gecko/mobile/android/base/tests/testMigration.java.in

358 lines
14 KiB
Java
Raw Normal View History

#filter substitution
package @ANDROID_PACKAGE_NAME@.tests;
import @ANDROID_PACKAGE_NAME@.*;
import android.app.Activity;
import android.content.ContentValues;
import android.content.ContentResolver;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.content.Context;
import android.net.Uri;
import android.provider.Browser;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ClassLoader;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* Tests the profile migration. Unpacks an old database, moves
* it to the profile, then call the BrowserProvider Control URI
* to launch a migration and check the results.
*/
public class testMigration extends ContentProviderTest {
// Big files are zipped to allow us to manually extract them,
// the APK extractor will fail >1Mb.
private static final String ASSET_SUFFIX = ".zip";
private static final String DB_NAME = "places.sqlite";
@Override
protected int getTestType() {
return TEST_MOCHITEST;
}
private File extractAsset(String dbName) {
File oldDbLocation = null;
boolean foundFile = false;
String fullAssetName = dbName + ASSET_SUFFIX;
AssetManager assets = getAssetManager();
try {
String[] assetList = assets.list("");
String assetString = "";
for (String file: assetList) {
assetString = assetString.concat(file);
assetString = assetString.concat(" ");
if (file.equals(fullAssetName)) {
foundFile = true;
}
}
mAsserter.is(foundFile, true, fullAssetName + " found in assets: " + assetString);
} catch (IOException e) {
String stackTrace = Log.getStackTraceString(e);
mAsserter.is(false, true, "Error getting asset dir: " + stackTrace);
}
// Extract the old places database from assets
// and write it out in the profile directory
try {
InputStream profData = assets.open(fullAssetName);
File profile = new File(mProfile);
oldDbLocation = new File(profile, dbName);
OutputStream out = new FileOutputStream(oldDbLocation);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(profData));
try {
ZipEntry ze;
while ((ze = zis.getNextEntry()) != null) {
byte[] buffer = new byte[1024];
int count;
while ((count = zis.read(buffer)) != -1) {
out.write(buffer, 0, count);
}
String fileName = ze.getName();
mAsserter.is(fileName, DB_NAME, "Filename match: " + fileName);
}
} finally {
zis.close();
}
profData.close();
out.flush();
out.close();
} catch (IOException e) {
String stackTrace = Log.getStackTraceString(e);
mAsserter.is(false, true, "Error getting profile data: " + stackTrace);
}
return oldDbLocation;
}
public void testMigration() {
Context context = (Context)getActivity();
File oldDbLocation = extractAsset(DB_NAME);
mAsserter.is(oldDbLocation.exists(), true, "OK old file exists: "
+ oldDbLocation.toString());
// Set up BrowserDB
try {
Class browserDBClass =
mClassLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
Method initializeMethod =
browserDBClass.getDeclaredMethod("initialize", String.class);
initializeMethod.invoke(null, "default");
} catch (Exception ex) {
mAsserter.is(true, false, "Error setting up BrowserDB: "
+ ex.getMessage());
return;
}
// Use reflection to look up the ProfileMigrator things we need
// access to (constructor, launch), as well as BrowserContract.Control.
Method launchPlacesTest;
Constructor constructor;
Class pmClass;
try {
pmClass = mClassLoader.loadClass("org.mozilla.gecko.ProfileMigrator");
launchPlacesTest = pmClass.getMethod("launchPlacesTest", File.class);
constructor = pmClass.getConstructor(Context.class, ContentResolver.class);
} catch(ClassNotFoundException ex) {
mAsserter.is(false, true, "Error getting class: " + ex.getMessage());
return;
} catch (java.lang.NoSuchMethodException ex) {
mAsserter.is(true, false, "Unable to find method: " + ex.getMessage());
return;
}
Object pm = null;
try {
// Construct ProfileMigrator object
pm = constructor.newInstance(context, mResolver);
} catch (Exception ex) {
mAsserter.is(true, false, "Error instantiating ProfileMigrator instance: "
+ ex.getMessage());
return;
}
// Reset history entries from previous tests
clearHistory();
// Launch the Profile Migration
try {
launchPlacesTest.invoke(pm, new File(mProfile));
} catch (Exception ex) {
String stackTrace = Log.getStackTraceString(ex);
mAsserter.is(true, false, "Unable to invoke launchPlacesTest:" + stackTrace);
return;
}
// Run the tests to see if that worked
runTestViaContentProvider();
runTestViaBrowserDB();
mAsserter.is(oldDbLocation.exists(), false, "OK old file gone now");
}
private void clearHistory() {
Method clearHistory = null;
try {
Class browserDB =
mClassLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
clearHistory =
browserDB.getMethod("clearHistory", ContentResolver.class);
} catch (java.lang.ClassNotFoundException ex) {
mAsserter.is(true, false, "Unable to find class");
return;
} catch (java.lang.NoSuchMethodException ex) {
mAsserter.is(true, false, "Unable to find method");
return;
}
try {
clearHistory.invoke(null, mResolver);
} catch (Exception ex) {
String stackTrace = Log.getStackTraceString(ex);
mAsserter.is(true, false, "Exception clearing history:" + stackTrace);
}
}
// stolen from testBookmarks
private void runTestViaBrowserDB() {
Method isBookmarked = null;
Method getAllVisitedHistory = null;
Constructor constructor = null;
try {
Class localBrowserDB =
mClassLoader.loadClass("org.mozilla.gecko.db.LocalBrowserDB");
isBookmarked =
localBrowserDB.getMethod("isBookmark", ContentResolver.class, String.class);
getAllVisitedHistory =
localBrowserDB.getMethod("getAllVisitedHistory", ContentResolver.class);
constructor = localBrowserDB.getConstructor(String.class);
} catch (java.lang.ClassNotFoundException ex) {
mAsserter.is(true, false, "Unable to find class");
return;
} catch (java.lang.NoSuchMethodException ex) {
mAsserter.is(true, false, "Unable to find method:" + ex.getMessage());
return;
}
Object db = null;
try {
String defaultProfile = "default";
db = constructor.newInstance(defaultProfile);
} catch (Exception ex) {
mAsserter.is(true, false, "Error instantiating LocalBrowserDB instance: "
+ ex.getMessage());
return;
}
final String[] knownBookmarks = new String[] {
"http://www.androidpolice.com/",
"https://developer.mozilla.org/En/Mozilla_Coding_Style_Guide",
"http://planet.mozilla.org/",
"http://www.crockford.com/",
"https://wiki.mozilla.org/Mobile/Fennec/Android"
};
final String ABOUT_HOME_URL = "about:home";
for (String url: knownBookmarks) {
try {
// Check for some bookmarks we know must exist
boolean isbookmark =
(Boolean)isBookmarked.invoke(db,
mResolver,
url);
mAsserter.is(isbookmark, true, "Expected page is bookmarked: " + url);
} catch (Exception ex) {
mAsserter.is(true, false, "Exception checking bookmark existence");
ex.printStackTrace();
return;
}
}
// Check the amount of history, this should match the following on the
// database in assets:
// SELECT COUNT(DISTINCT(url)) FROM moz_historyvisits
// JOIN moz_places ON moz_historyvisits.place_id = moz_places.id
final int PLACES_KNOWN_HISTORY_URLS = 184;
try {
Cursor cursor =
(Cursor)getAllVisitedHistory.invoke(db,
mResolver);
int historyCount = cursor.getCount();
cursor.close();
mAsserter.is(historyCount, PLACES_KNOWN_HISTORY_URLS,
"History count " + historyCount +
", expected was " + PLACES_KNOWN_HISTORY_URLS);
} catch (Exception ex) {
mAsserter.is(true, false, "Exception checking history count");
ex.printStackTrace();
}
}
private void runTestViaContentProvider() {
String ensureHistory;
String ensureBookmarks;
String urlField;
String visitsField;
Uri controlUri;
Uri historyUri;
try {
Class browserContract =
mClassLoader.loadClass("org.mozilla.gecko.db.BrowserContract");
Class browserContractControl =
mClassLoader.loadClass("org.mozilla.gecko.db.BrowserContract$Control");
Class browserContractHistory =
mClassLoader.loadClass("org.mozilla.gecko.db.BrowserContract$History");
Class browserContractUrl =
mClassLoader.loadClass("org.mozilla.gecko.db.BrowserContract$URLColumns");
Class browserContractHistoryColumns =
mClassLoader.loadClass("org.mozilla.gecko.db.BrowserContract$HistoryColumns");
controlUri = (Uri)browserContractControl.getField("CONTENT_URI").get(null);
historyUri = (Uri)browserContractHistory.getField("CONTENT_URI").get(null);
urlField = (String)browserContractUrl.getField("URL").get(null);
visitsField = (String)browserContractHistoryColumns.getField("VISITS").get(null);
String profilePath = (String)browserContract.getField("PARAM_PROFILE_PATH").get(null);
Uri.Builder builder = controlUri.buildUpon();
controlUri = builder.build();
ensureHistory =
(String)browserContractControl.getField("ENSURE_HISTORY_MIGRATED").get(null);
ensureBookmarks =
(String)browserContractControl.getField("ENSURE_BOOKMARKS_MIGRATED").get(null);
} catch (Exception ex) {
mAsserter.is(true, false, "Reflection error getting BrowserContract classes and Uri's");
ex.printStackTrace();
return;
}
Cursor c = mResolver.query(controlUri,
new String[] { ensureHistory,
ensureBookmarks },
null,
null,
null);
int historyMigrated = 0;
int bookmarksMigrated = 0;
if (c.moveToFirst()) {
historyMigrated = c.getInt(0);
bookmarksMigrated = c.getInt(1);
}
c.close();
mAsserter.is(historyMigrated, 1, "History migrated");
mAsserter.is(bookmarksMigrated, 1, "Bookmarks migrated");
// Check whether visit counts are as expected. The test profile
// has visited reddit 4 times so we expect to find that in our
// own database too now.
c = mResolver.query(historyUri,
new String[] { visitsField },
urlField + " = ?",
new String[] { "http://www.reddit.com/" },
null);
mAsserter.is(c.moveToFirst(), true, "Expected URL found");
int visits = c.getInt(0);
c.close();
mAsserter.is(visits, 4, "Visit count of " + visits + " equals expected 4");
}
@Override
public void setUp() throws Exception {
super.setUp("@ANDROID_PACKAGE_NAME@.db.BrowserProvider", "AUTHORITY");
}
public void tearDown() throws Exception {
// remove the database file
File profile = new File(mProfile);
File db = new File(profile, DB_NAME);
if (db.delete()) {
mAsserter.dumpLog("tearDown deleted "+db.toString());
} else {
mAsserter.dumpLog("tearDown did not delete "+db.toString());
}
super.tearDown();
}
}