Bug 1395332 - perform some post-profile-migration steps to ensure Sync works correctly in the new profile. r?Gijs
MozReview-Commit-ID: EcFdDeqzzCY
--- a/browser/components/migration/FirefoxProfileMigrator.js
+++ b/browser/components/migration/FirefoxProfileMigrator.js
@@ -121,23 +121,31 @@ FirefoxProfileMigrator.prototype._getRes
for (let file of files) {
file.copyTo(currentProfileDir, "");
}
aCallback(true);
}
};
};
+ function savePrefs() {
+ // If we've used the pref service to write prefs for the new profile, it's too
+ // early in startup for the service to have a profile directory, so we have to
+ // manually tell it where to save the prefs file.
+ let newPrefsFile = currentProfileDir.clone();
+ newPrefsFile.append("prefs.js");
+ Services.prefs.savePrefFile(newPrefsFile);
+ }
+
let types = MigrationUtils.resourceTypes;
let places = getFileResource(types.HISTORY, ["places.sqlite", "places.sqlite-wal"]);
let favicons = getFileResource(types.HISTORY, ["favicons.sqlite", "favicons.sqlite-wal"]);
let cookies = getFileResource(types.COOKIES, ["cookies.sqlite", "cookies.sqlite-wal"]);
let passwords = getFileResource(types.PASSWORDS,
- ["signons.sqlite", "logins.json", "key3.db", "key4.db",
- "signedInUser.json"]);
+ ["signons.sqlite", "logins.json", "key3.db", "key4.db"]);
let formData = getFileResource(types.FORMDATA, [
"formhistory.sqlite",
"autofill-profiles.json",
]);
let bookmarksBackups = getFileResource(types.OTHERDATA,
[PlacesBackups.profileRelativeFolderPath]);
let dictionary = getFileResource(types.OTHERDATA, ["persdict.dat"]);
@@ -163,30 +171,57 @@ FirefoxProfileMigrator.prototype._getRes
let buildID = Services.appinfo.platformBuildID;
let mstone = Services.appinfo.platformVersion;
// Force the browser to one-off resume the session that we give it:
Services.prefs.setBoolPref("browser.sessionstore.resume_session_once", true);
// Reset the homepage_override prefs so that the browser doesn't override our
// session with the "what's new" page:
Services.prefs.setCharPref("browser.startup.homepage_override.mstone", mstone);
Services.prefs.setCharPref("browser.startup.homepage_override.buildID", buildID);
- // It's too early in startup for the pref service to have a profile directory,
- // so we have to manually tell it where to save the prefs file.
- let newPrefsFile = currentProfileDir.clone();
- newPrefsFile.append("prefs.js");
- Services.prefs.savePrefFile(newPrefsFile);
+ savePrefs();
aCallback(true);
}, function() {
aCallback(false);
});
}
};
}
}
+ // Sync/FxA related data
+ let sync = {
+ name: "sync", // name is used only by tests.
+ type: types.OTHERDATA,
+ migrate: async aCallback => {
+ // Try and parse a signedInUser.json file from the source directory and
+ // if we can, copy it to the new profile and set sync's username pref
+ // (which acts as a de-facto flag to indicate if sync is configured)
+ try {
+ let oldPath = OS.Path.join(sourceProfileDir.path, "signedInUser.json");
+ let exists = await OS.File.exists(oldPath);
+ if (exists) {
+ let raw = await OS.File.read(oldPath, {encoding: "utf-8"});
+ let data = JSON.parse(raw);
+ if (data && data.accountData && data.accountData.email) {
+ let username = data.accountData.email;
+ // Write it to prefs.js and flush the file.
+ Services.prefs.setStringPref("services.sync.username", username);
+ savePrefs();
+ // and copy the file itself.
+ await OS.File.copy(oldPath, OS.Path.join(currentProfileDir.path, "signedInUser.json"));
+ }
+ }
+ } catch (ex) {
+ aCallback(false);
+ return;
+ }
+ aCallback(true);
+ }
+ };
+
// Telemetry related migrations.
let times = {
name: "times", // name is used only by tests.
type: types.OTHERDATA,
migrate: aCallback => {
let file = this._getFileObject(sourceProfileDir, "times.json");
if (file) {
file.copyTo(currentProfileDir, "");
@@ -247,17 +282,17 @@ FirefoxProfileMigrator.prototype._getRes
}
}
aCallback(true);
}
};
return [places, cookies, passwords, formData, dictionary, bookmarksBackups,
- session, times, telemetry, favicons].filter(r => r);
+ session, sync, times, telemetry, favicons].filter(r => r);
};
Object.defineProperty(FirefoxProfileMigrator.prototype, "startupOnlyMigrator", {
get: () => true
});
FirefoxProfileMigrator.prototype.classDescription = "Firefox Profile Migrator";
--- a/browser/components/migration/tests/marionette/test_refresh_firefox.py
+++ b/browser/components/migration/tests/marionette/test_refresh_firefox.py
@@ -166,32 +166,44 @@ class TestFirefoxRefresh(MarionetteTestC
let allTabs = Array.from(gBrowser.tabs);
for (let tab of allTabs) {
if (!expectedTabs.has(tab)) {
gBrowser.removeTab(tab);
}
}
""", script_args=(self._expectedURLs,))
+ def createSync(self):
+ # This script will write an entry to the login manager and create
+ # a signedInUser.json in the profile dir.
+ self.runAsyncCode("""
+ Cu.import("resource://gre/modules/FxAccountsStorage.jsm");
+ let storage = new FxAccountsStorageManager();
+ let data = {email: "test@test.com", uid: "uid", keyFetchToken: "top-secret"};
+ storage.initialize(data);
+ storage.finalize().then(marionetteScriptFinished);
+ """);
+
def checkPassword(self):
loginInfo = self.marionette.execute_script("""
let ary = Services.logins.findLogins({},
"test.marionette.mozilla.com",
"http://test.marionette.mozilla.com/some/form/",
null, {});
return ary.length ? ary : {username: "null", password: "null"};
""")
self.assertEqual(len(loginInfo), 1)
self.assertEqual(loginInfo[0]['username'], self._username)
self.assertEqual(loginInfo[0]['password'], self._password)
loginCount = self.marionette.execute_script("""
return Services.logins.getAllLogins().length;
""")
- self.assertEqual(loginCount, 1, "No other logins are present")
+ # Note that we expect 2 logins - one from us, one from sync.
+ self.assertEqual(loginCount, 2, "No other logins are present")
def checkBookmark(self):
titleInBookmarks = self.marionette.execute_script("""
let url = arguments[0];
let bookmarkIds = PlacesUtils.bookmarks.getBookmarkIdsForURI(makeURI(url), {}, {});
return bookmarkIds.length == 1 ? PlacesUtils.bookmarks.getItemTitle(bookmarkIds[0]) : "";
""", script_args=(self._bookmarkURL,))
self.assertEqual(titleInBookmarks, self._bookmarkText)
@@ -331,34 +343,64 @@ class TestFirefoxRefresh(MarionetteTestC
}, { once: true });
}
};
mm.loadFrameScript("data:application/javascript,(" + fs.toString() + ")()", true);
""")
self.assertSequenceEqual(tabURIs, self._expectedURLs)
+ def checkSync(self, hasMigrated):
+ result = self.runAsyncCode("""
+ Cu.import("resource://gre/modules/FxAccountsStorage.jsm");
+ let prefs = new global.Preferences("services.sync.");
+ let storage = new FxAccountsStorageManager();
+ let result = {};
+ storage.initialize();
+ storage.getAccountData().then(data => {
+ result.accountData = data;
+ return storage.finalize();
+ }).then(() => {
+ result.prefUsername = prefs.get("username");
+ marionetteScriptFinished(result);
+ }).catch(err => {
+ marionetteScriptFinished(err.toString());
+ });
+ """);
+ if type(result) != dict:
+ self.fail(result)
+ return
+ self.assertEqual(result["accountData"]["email"], "test@test.com");
+ self.assertEqual(result["accountData"]["uid"], "uid");
+ self.assertEqual(result["accountData"]["keyFetchToken"], "top-secret");
+ if hasMigrated:
+ # This test doesn't actually configure sync itself, so the username
+ # pref only exists after migration.
+ self.assertEqual(result["prefUsername"], "test@test.com");
+
def checkProfile(self, hasMigrated=False):
self.checkPassword()
self.checkBookmark()
self.checkHistory()
self.checkFormHistory()
self.checkFormAutofill()
self.checkCookie()
+ self.checkSync(hasMigrated);
if hasMigrated:
self.checkSession()
def createProfileData(self):
self.savePassword()
self.createBookmark()
self.createHistory()
self.createFormHistory()
self.createFormAutofill()
self.createCookie()
self.createSession()
+ self.createSync()
def setUpScriptData(self):
self.marionette.set_context(self.marionette.CONTEXT_CHROME)
self.runCode("""
window.global = {};
global.LoginInfo = Components.Constructor("@mozilla.org/login-manager/loginInfo;1", "nsILoginInfo", "init");
global.profSvc = Cc["@mozilla.org/toolkit/profile-service;1"].getService(Ci.nsIToolkitProfileService);
global.Preferences = Cu.import("resource://gre/modules/Preferences.jsm", {}).Preferences;