--- a/browser/components/migration/360seProfileMigrator.js
+++ b/browser/components/migration/360seProfileMigrator.js
@@ -150,25 +150,25 @@ Bookmarks.prototype = {
parentGuid =
yield MigrationUtils.createImportedBookmarksFolder("360se", parentGuid);
}
idToGuid.set("fallback", parentGuid);
}
try {
if (is_folder == 1) {
- let newFolderGuid = (yield PlacesUtils.bookmarks.insert({
+ let newFolderGuid = (yield MigrationUtils.insertBookmarkWrapper({
parentGuid,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
title
})).guid;
idToGuid.set(id, newFolderGuid);
} else {
- yield PlacesUtils.bookmarks.insert({
+ yield MigrationUtils.insertBookmarkWrapper({
parentGuid,
url,
title
});
}
} catch (ex) {
Cu.reportError(ex);
}
--- a/browser/components/migration/ChromeProfileMigrator.js
+++ b/browser/components/migration/ChromeProfileMigrator.js
@@ -83,21 +83,21 @@ function* insertBookmarkItems(parentGuid
for (let item of items) {
try {
if (item.type == "url") {
if (item.url.trim().startsWith("chrome:")) {
// Skip invalid chrome URIs. Creating an actual URI always reports
// messages to the console, so we avoid doing that.
continue;
}
- yield PlacesUtils.bookmarks.insert({
+ yield MigrationUtils.insertBookmarkWrapper({
parentGuid, url: item.url, title: item.name
});
} else if (item.type == "folder") {
- let newFolderGuid = (yield PlacesUtils.bookmarks.insert({
+ let newFolderGuid = (yield MigrationUtils.insertBookmarkWrapper({
parentGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title: item.name
})).guid;
yield insertBookmarkItems(newFolderGuid, item.children, errorAccumulator);
}
} catch (e) {
Cu.reportError(e);
errorAccumulator(e);
@@ -334,17 +334,17 @@ function GetHistoryResource(aProfileFold
});
} catch (e) {
Cu.reportError(e);
}
}
if (places.length > 0) {
yield new Promise((resolve, reject) => {
- PlacesUtils.asyncHistory.updatePlaces(places, {
+ MigrationUtils.insertVisitsWrapper(places, {
_success: false,
handleResult: function() {
// Importing any entry is considered a successful import.
this._success = true;
},
handleError: function() {},
handleCompletion: function() {
if (this._success) {
@@ -442,17 +442,17 @@ function GetWindowsPasswordsResource(aPr
let crypto = new OSCrypto();
for (let row of rows) {
let loginInfo = {
username: row.getResultByName("username_value"),
password: crypto.
decryptData(crypto.arrayToString(row.getResultByName("password_value")),
null),
- hostName: NetUtil.newURI(row.getResultByName("origin_url")).prePath,
+ hostname: NetUtil.newURI(row.getResultByName("origin_url")).prePath,
submitURL: null,
httpRealm: null,
usernameElement: row.getResultByName("username_element"),
passwordElement: row.getResultByName("password_element"),
timeCreated: chromeTimeToDate(row.getResultByName("date_created") + 0).getTime(),
timesUsed: row.getResultByName("times_used") + 0,
};
@@ -460,42 +460,23 @@ function GetWindowsPasswordsResource(aPr
switch (row.getResultByName("scheme")) {
case AUTH_TYPE.SCHEME_HTML:
loginInfo.submitURL = NetUtil.newURI(row.getResultByName("action_url")).prePath;
break;
case AUTH_TYPE.SCHEME_BASIC:
case AUTH_TYPE.SCHEME_DIGEST:
// signon_realm format is URIrealm, so we need remove URI
loginInfo.httpRealm = row.getResultByName("signon_realm")
- .substring(loginInfo.hostName.length + 1);
+ .substring(loginInfo.hostname.length + 1);
break;
default:
throw new Error("Login data scheme type not supported: " +
row.getResultByName("scheme"));
}
- let login = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo);
-
- login.init(loginInfo.hostName, loginInfo.submitURL, loginInfo.httpRealm,
- loginInfo.username, loginInfo.password, loginInfo.usernameElement,
- loginInfo.passwordElement);
- login.QueryInterface(Ci.nsILoginMetaInfo);
- login.timeCreated = loginInfo.timeCreated;
- login.timeLastUsed = loginInfo.timeCreated;
- login.timePasswordChanged = loginInfo.timeCreated;
- login.timesUsed = loginInfo.timesUsed;
-
- // Add the login only if there's not an existing entry
- let logins = Services.logins.findLogins({}, login.hostname,
- login.formSubmitURL,
- login.httpRealm);
-
- // Bug 1187190: Password changes should be propagated depending on timestamps.
- if (!logins.some(l => login.matches(l, true))) {
- Services.logins.addLogin(login);
- }
+ MigrationUtils.insertLoginWrapper(loginInfo);
} catch (e) {
Cu.reportError(e);
}
}
crypto.finalize();
aCallback(true);
}),
};
--- a/browser/components/migration/EdgeProfileMigrator.js
+++ b/browser/components/migration/EdgeProfileMigrator.js
@@ -133,17 +133,17 @@ EdgeTypedURLMigrator.prototype = {
});
}
if (places.length == 0) {
aCallback(typedURLs.size == 0);
return;
}
- PlacesUtils.asyncHistory.updatePlaces(places, {
+ MigrationUtils.insertVisitsWrapper(places, {
_success: false,
handleResult: function() {
// Importing any entry is considered a successful import.
this._success = true;
},
handleError: function() {},
handleCompletion: function() {
aCallback(this._success);
@@ -196,17 +196,17 @@ EdgeReadingListMigrator.prototype = {
if (!readingListItems.length) {
return;
}
let destFolderGuid = yield this._ensureReadingListFolder(parentGuid);
let exceptionThrown;
for (let item of readingListItems) {
let dateAdded = item.AddedDate || new Date();
- yield PlacesUtils.bookmarks.insert({
+ yield MigrationUtils.insertBookmarkWrapper({
parentGuid: destFolderGuid, url: item.URL, title: item.Title, dateAdded
}).catch(ex => {
if (!exceptionThrown) {
exceptionThrown = ex;
}
Cu.reportError(ex);
});
}
@@ -214,17 +214,17 @@ EdgeReadingListMigrator.prototype = {
throw exceptionThrown;
}
}),
_ensureReadingListFolder: Task.async(function*(parentGuid) {
if (!this.__readingListFolderGuid) {
let folderTitle = MigrationUtils.getLocalizedString("importedEdgeReadingList");
let folderSpec = {type: PlacesUtils.bookmarks.TYPE_FOLDER, parentGuid, title: folderTitle};
- this.__readingListFolderGuid = (yield PlacesUtils.bookmarks.insert(folderSpec)).guid;
+ this.__readingListFolderGuid = (yield MigrationUtils.insertBookmarkWrapper(folderSpec)).guid;
}
return this.__readingListFolderGuid;
}),
};
function EdgeBookmarksMigrator(dbOverride) {
this.dbOverride = dbOverride;
}
@@ -317,17 +317,17 @@ EdgeBookmarksMigrator.prototype = {
}
let placesInfo = {
parentGuid,
url: bookmark.URL,
dateAdded: bookmark.DateUpdated || new Date(),
title: bookmark.Title,
};
- yield PlacesUtils.bookmarks.insert(placesInfo).catch(ex => {
+ yield MigrationUtils.insertBookmarkWrapper(placesInfo).catch(ex => {
if (!exceptionThrown) {
exceptionThrown = ex;
}
Cu.reportError(ex);
});
}
if (exceptionThrown) {
@@ -385,17 +385,17 @@ EdgeBookmarksMigrator.prototype = {
let parentGuid = yield this._getGuidForFolder(folder.ParentId, folderMap, rootGuid);
let folderInfo = {
title: folder.Title,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
dateAdded: folder.DateUpdated || new Date(),
parentGuid,
};
// and add ourselves as a kid, and return the guid we got.
- let parentBM = yield PlacesUtils.bookmarks.insert(folderInfo);
+ let parentBM = yield MigrationUtils.insertBookmarkWrapper(folderInfo);
folder._guid = parentBM.guid;
return folder._guid;
}),
};
function EdgeProfileMigrator() {
this.wrappedJSObject = this;
}
--- a/browser/components/migration/IEProfileMigrator.js
+++ b/browser/components/migration/IEProfileMigrator.js
@@ -14,17 +14,16 @@ const kMainKey = "Software\\Microsoft\\I
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/osfile.jsm"); /* globals OS */
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm"); /* globals MigratorPrototype */
Cu.import("resource:///modules/MSMigrationUtils.jsm");
-Cu.import("resource://gre/modules/LoginHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
"resource://gre/modules/ctypes.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OSCrypto",
"resource://gre/modules/OSCrypto.jsm");
@@ -88,17 +87,17 @@ History.prototype = {
}
// Check whether there is any history to import.
if (places.length == 0) {
aCallback(true);
return;
}
- PlacesUtils.asyncHistory.updatePlaces(places, {
+ MigrationUtils.insertVisitsWrapper(places, {
_success: false,
handleResult: function() {
// Importing any entry is considered a successful import.
this._success = true;
},
handleError: function() {},
handleCompletion: function() {
aCallback(this._success);
@@ -244,17 +243,17 @@ IE7FormPasswords.prototype = {
try {
// create a new login
let login = {
username: ieLogin.username,
password: ieLogin.password,
hostname: ieLogin.url,
timeCreated: ieLogin.creation,
};
- LoginHelper.maybeImportLogin(login);
+ MigrationUtils.insertLoginWrapper(login);
} catch (e) {
Cu.reportError(e);
}
}
},
/**
* Extract the details of one or more logins from the raw decrypted data.
--- a/browser/components/migration/MSMigrationUtils.jsm
+++ b/browser/components/migration/MSMigrationUtils.jsm
@@ -8,17 +8,16 @@ this.EXPORTED_SYMBOLS = ["MSMigrationUti
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/AppConstants.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm");
-Cu.import("resource://gre/modules/LoginHelper.jsm");
Cu.importGlobalProperties(["FileReader"]);
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
"resource://gre/modules/WindowsRegistry.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ctypes",
@@ -402,17 +401,17 @@ Bookmarks.prototype = {
folderGuid = PlacesUtils.bookmarks.toolbarGuid;
if (!MigrationUtils.isStartupMigration) {
folderGuid =
yield MigrationUtils.createImportedBookmarksFolder(this.importedAppLabel, folderGuid);
}
}
else {
// Import to a new folder.
- folderGuid = (yield PlacesUtils.bookmarks.insert({
+ folderGuid = (yield MigrationUtils.insertBookmarkWrapper({
type: PlacesUtils.bookmarks.TYPE_FOLDER,
parentGuid: aDestFolderGuid,
title: entry.leafName
})).guid;
}
if (entry.isReadable()) {
// Recursively import the folder.
@@ -424,17 +423,17 @@ Bookmarks.prototype = {
// and get the associated title.
let matches = entry.leafName.match(/(.+)\.url$/i);
if (matches) {
let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
getService(Ci.nsIFileProtocolHandler);
let uri = fileHandler.readURLFile(entry);
let title = matches[1];
- yield PlacesUtils.bookmarks.insert({
+ yield MigrationUtils.insertBookmarkWrapper({
parentGuid: aDestFolderGuid, url: uri, title
});
}
}
} catch (ex) {
Components.utils.reportError("Unable to import " + this.importedAppLabel + " favorite (" + entry.leafName + "): " + ex);
succeeded = false;
}
@@ -833,17 +832,17 @@ WindowsVaultFormPasswords.prototype = {
// Ignore exceptions in the dates and just create the login for right now.
}
// create a new login
let login = {
username, password,
hostname: realURL.prePath,
timeCreated: creation,
};
- LoginHelper.maybeImportLogin(login);
+ MigrationUtils.insertLoginWrapper(login);
// close current item
error = ctypesVaultHelpers._functions.VaultFree(credential);
if (error == FREE_CLOSE_FAILED) {
throw new Error("Unable to free item: " + error);
}
} catch (e) {
migrationSucceeded = false;
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -15,16 +15,18 @@ Cu.import("resource://gre/modules/AppCon
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AutoMigrate",
"resource:///modules/AutoMigrate.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils",
"resource://gre/modules/BookmarkHTMLUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
+ "resource://gre/modules/LoginHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PromiseUtils",
"resource://gre/modules/PromiseUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
"resource://gre/modules/Sqlite.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
"resource://gre/modules/TelemetryStopwatch.jsm");
@@ -249,16 +251,27 @@ this.MigratorPrototype = {
};
let maybeStopTelemetryStopwatch = (resourceType, resource) => {
let histogram = getHistogramForResourceType(resourceType);
if (histogram) {
TelemetryStopwatch.finishKeyed(histogram, this.getKey(), resource);
}
};
+ let collectQuantityTelemetry = () => {
+ try {
+ for (let resourceType of Object.keys(MigrationUtils._importQuantities)) {
+ let histogramId =
+ "FX_MIGRATION_" + resourceType.toUpperCase() + "_QUANTITY";
+ let histogram = Services.telemetry.getKeyedHistogram(histogramId);
+ histogram.add(this.getKey(), MigrationUtils._importQuantities[resourceType]);
+ }
+ } catch (ex) { /* Telemetry is exception-happy */ }
+ };
+
// Called either directly or through the bookmarks import callback.
let doMigrate = Task.async(function*() {
let resourcesGroupedByItems = new Map();
resources.forEach(function(resource) {
if (!resourcesGroupedByItems.has(resource.type)) {
resourcesGroupedByItems.set(resource.type, new Set());
}
resourcesGroupedByItems.get(resource.type).add(resource);
@@ -266,16 +279,19 @@ this.MigratorPrototype = {
if (resourcesGroupedByItems.size == 0)
throw new Error("No items to import");
let notify = function(aMsg, aItemType) {
Services.obs.notifyObservers(null, aMsg, aItemType);
};
+ for (let resourceType of Object.keys(MigrationUtils._importQuantities)) {
+ MigrationUtils._importQuantities[resourceType] = 0;
+ }
notify("Migration:Started");
for (let [key, value] of resourcesGroupedByItems) {
// Workaround bug 449811.
let migrationType = key, itemResources = value;
notify("Migration:ItemBeforeMigrate", migrationType);
let itemSuccess = false;
@@ -289,16 +305,17 @@ this.MigratorPrototype = {
itemResources.delete(resource);
itemSuccess |= aSuccess;
if (itemResources.size == 0) {
notify(itemSuccess ?
"Migration:ItemAfterMigrate" : "Migration:ItemError",
migrationType);
resourcesGroupedByItems.delete(migrationType);
if (resourcesGroupedByItems.size == 0) {
+ collectQuantityTelemetry();
notify("Migration:Ended");
}
}
completeDeferred.resolve();
};
// If migrate throws, an error occurred, and the callback
// (itemMayBeDone) might haven't been called.
@@ -902,16 +919,37 @@ this.MigrationUtils = Object.freeze({
migrator,
aProfileStartup,
skipSourcePage,
aProfileToMigrate,
];
this.showMigrationWizard(null, params);
},
+ _importQuantities: {
+ bookmarks: 0,
+ logins: 0,
+ history: 0,
+ },
+
+ insertBookmarkWrapper(bookmark) {
+ this._importQuantities.bookmarks++;
+ return PlacesUtils.bookmarks.insert(bookmark);
+ },
+
+ insertVisitsWrapper(places, options) {
+ this._importQuantities.history += places.length;
+ return PlacesUtils.asyncHistory.updatePlaces(places, options);
+ },
+
+ insertLoginWrapper(login) {
+ this._importQuantities.logins++;
+ return LoginHelper.maybeImportLogin(login);
+ },
+
/**
* Cleans up references to migrators and nsIProfileInstance instances.
*/
finishMigration: function MU_finishMigration() {
gMigrators = null;
gProfileStartup = null;
gMigrationBundle = null;
},
--- a/browser/components/migration/SafariProfileMigrator.js
+++ b/browser/components/migration/SafariProfileMigrator.js
@@ -126,17 +126,17 @@ Bookmarks.prototype = {
yield MigrationUtils.createImportedBookmarksFolder("Safari", folderGuid);
}
break;
}
case this.READING_LIST_COLLECTION: {
// Reading list items are imported as regular bookmarks.
// They are imported under their own folder, created either under the
// bookmarks menu (in the case of startup migration).
- folderGuid = (yield PlacesUtils.bookmarks.insert({
+ folderGuid = (yield MigrationUtils.insertBookmarkWrapper({
parentGuid: PlacesUtils.bookmarks.menuGuid,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
title: MigrationUtils.getLocalizedString("importedSafariReadingList"),
})).guid;
break;
}
default:
throw new Error("Unexpected value for aCollection!");
@@ -149,31 +149,31 @@ Bookmarks.prototype = {
// migrate the given array of safari bookmarks to the given places
// folder.
_migrateEntries: Task.async(function* (entries, parentGuid) {
for (let entry of entries) {
let type = entry.get("WebBookmarkType");
if (type == "WebBookmarkTypeList" && entry.has("Children")) {
let title = entry.get("Title");
- let newFolderGuid = (yield PlacesUtils.bookmarks.insert({
+ let newFolderGuid = (yield MigrationUtils.insertBookmarkWrapper({
parentGuid, type: PlacesUtils.bookmarks.TYPE_FOLDER, title
})).guid;
// Empty folders may not have a children array.
if (entry.has("Children"))
yield this._migrateEntries(entry.get("Children"), newFolderGuid, false);
}
else if (type == "WebBookmarkTypeLeaf" && entry.has("URLString")) {
let title;
if (entry.has("URIDictionary"))
title = entry.get("URIDictionary").get("title");
try {
- yield PlacesUtils.bookmarks.insert({
+ yield MigrationUtils.insertBookmarkWrapper({
parentGuid, url: entry.get("URLString"), title
});
} catch (ex) {
Cu.reportError("Invalid Safari bookmark: " + ex);
}
}
}
})
@@ -225,17 +225,17 @@ History.prototype = {
catch (ex) {
// Safari's History file may contain malformed URIs which
// will be ignored.
Cu.reportError(ex);
}
}
}
if (places.length > 0) {
- PlacesUtils.asyncHistory.updatePlaces(places, {
+ MigrationUtils.insertVisitsWrapper(places, {
_success: false,
handleResult: function() {
// Importing any entry is considered a successful import.
this._success = true;
},
handleError: function() {},
handleCompletion: function() {
aCallback(this._success);
--- a/browser/components/migration/tests/unit/test_Chrome_passwords.js
+++ b/browser/components/migration/tests/unit/test_Chrome_passwords.js
@@ -168,16 +168,18 @@ add_task(function* test_importIntoEmptyD
let logins = Services.logins.getAllLogins({});
Assert.equal(logins.length, 0, "There are no logins initially");
// Migrate the logins.
yield promiseMigration(migrator, MigrationUtils.resourceTypes.PASSWORDS, PROFILE);
logins = Services.logins.getAllLogins({});
Assert.equal(logins.length, TEST_LOGINS.length, "Check login count after importing the data");
+ Assert.equal(logins.length, MigrationUtils._importQuantities.logins,
+ "Check telemetry matches the actual import.");
for (let i = 0; i < TEST_LOGINS.length; i++) {
checkLoginsAreEqual(logins[i], TEST_LOGINS[i], i + 1);
}
});
// Test that existing logins for the same primary key don't get overwritten
add_task(function* test_importExistingLogins() {
@@ -203,13 +205,15 @@ add_task(function* test_importExistingLo
checkLoginsAreEqual(logins[i], newLogins[i], i + 1);
}
// Migrate the logins.
yield promiseMigration(migrator, MigrationUtils.resourceTypes.PASSWORDS, PROFILE);
logins = Services.logins.getAllLogins({});
Assert.equal(logins.length, TEST_LOGINS.length,
"Check there are still the same number of logins after re-importing the data");
+ Assert.equal(logins.length, MigrationUtils._importQuantities.logins,
+ "Check telemetry matches the actual import.");
for (let i = 0; i < newLogins.length; i++) {
checkLoginsAreEqual(logins[i], newLogins[i], i + 1);
}
});
--- a/browser/components/migration/tests/unit/test_Edge_db_migration.js
+++ b/browser/components/migration/tests/unit/test_Edge_db_migration.js
@@ -382,16 +382,19 @@ add_task(function*() {
{type: COLUMN_TYPES.JET_coltypGUID, name: "ParentId"},
], itemsInDB);
let migrator = Cc["@mozilla.org/profile/migrator;1?app=browser&type=edge"]
.createInstance(Ci.nsIBrowserProfileMigrator);
let bookmarksMigrator = migrator.wrappedJSObject.getESEMigratorForTesting(db);
Assert.ok(bookmarksMigrator.exists, "Should recognize table we just created");
+ let source = MigrationUtils.getLocalizedString("sourceNameEdge");
+ let sourceLabel = MigrationUtils.getLocalizedString("importedBookmarksFolder", [source]);
+
let seenBookmarks = [];
let bookmarkObserver = {
onItemAdded(itemId, parentId, index, itemType, url, title, dateAdded, itemGuid, parentGuid) {
if (title.startsWith("Deleted")) {
ok(false, "Should not see deleted items being bookmarked!");
}
seenBookmarks.push({itemId, parentId, index, itemType, url, title, dateAdded, itemGuid, parentGuid});
},
@@ -407,16 +410,19 @@ add_task(function*() {
let migrateResult = yield new Promise(resolve => bookmarksMigrator.migrate(resolve)).catch(ex => {
Cu.reportError(ex);
Assert.ok(false, "Got an exception trying to migrate data! " + ex);
return false;
});
PlacesUtils.bookmarks.removeObserver(bookmarkObserver);
Assert.ok(migrateResult, "Migration should succeed");
Assert.equal(seenBookmarks.length, 7, "Should have seen 7 items being bookmarked.");
+ Assert.equal(seenBookmarks.filter(bm => bm.title != sourceLabel).length,
+ MigrationUtils._importQuantities.bookmarks,
+ "Telemetry should have items except for 'From Microsoft Edge' folders");
let menuParents = seenBookmarks.filter(item => item.parentGuid == PlacesUtils.bookmarks.menuGuid);
Assert.equal(menuParents.length, 1, "Should have a single folder added to the menu");
let toolbarParents = seenBookmarks.filter(item => item.parentGuid == PlacesUtils.bookmarks.toolbarGuid);
Assert.equal(toolbarParents.length, 1, "Should have a single item added to the toolbar");
let menuParentGuid = menuParents[0].itemGuid;
let toolbarParentGuid = toolbarParents[0].itemGuid;
--- a/browser/components/migration/tests/unit/test_IE7_passwords.js
+++ b/browser/components/migration/tests/unit/test_IE7_passwords.js
@@ -373,16 +373,25 @@ add_task(function* test_passwordsAvailab
migrator._migrateURIs(uris);
logins = Services.logins.getAllLogins({});
// check that the number of logins in the password manager has increased as expected which means
// that all the values for the current website were imported
loginCount += website.logins.length;
Assert.equal(logins.length, loginCount,
"The number of logins has increased after the migration");
+ // NB: because telemetry records any login data passed to the login manager, it
+ // also gets told about logins that are duplicates or invalid (for one reason
+ // or another) and so its counts might exceed those of the login manager itself.
+ Assert.greaterOrEqual(MigrationUtils._importQuantities.logins, loginCount,
+ "Telemetry quantities equal or exceed the actual import.");
+ // Reset - this normally happens at the start of a new migration, but we're calling
+ // the migrator directly so can't rely on that:
+ MigrationUtils._importQuantities.logins = 0;
+
let startIndex = loginCount - website.logins.length;
// compares the imported password manager logins with their expected logins
for (let i = 0; i < website.logins.length; i++) {
checkLoginsAreEqual(logins[startIndex + i], website.logins[i],
" " + current + " - " + i + " ");
}
}
});
--- a/browser/components/migration/tests/unit/test_IE_bookmarks.js
+++ b/browser/components/migration/tests/unit/test_IE_bookmarks.js
@@ -8,31 +8,37 @@ add_task(function* () {
// Wait for the imported bookmarks. Check that "From Internet Explorer"
// folders are created in the menu and on the toolbar.
let source = MigrationUtils.getLocalizedString("sourceNameIE");
let label = MigrationUtils.getLocalizedString("importedBookmarksFolder", [source]);
let expectedParents = [ PlacesUtils.bookmarksMenuFolderId,
PlacesUtils.toolbarFolderId ];
- PlacesUtils.bookmarks.addObserver({
+ let itemCount = 0;
+ let bmObserver = {
onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle) {
- if (aTitle == label) {
+ if (aTitle != label) {
+ itemCount++;
+ }
+ if (expectedParents.length > 0 && aTitle == label) {
let index = expectedParents.indexOf(aParentId);
Assert.notEqual(index, -1);
expectedParents.splice(index, 1);
- if (expectedParents.length == 0)
- PlacesUtils.bookmarks.removeObserver(this);
}
},
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onItemRemoved() {},
onItemChanged() {},
onItemVisited() {},
onItemMoved() {},
- }, false);
+ };
+ PlacesUtils.bookmarks.addObserver(bmObserver, false);
yield promiseMigration(migrator, MigrationUtils.resourceTypes.BOOKMARKS);
+ PlacesUtils.bookmarks.removeObserver(bmObserver);
+ Assert.equal(MigrationUtils._importQuantities.bookmarks, itemCount,
+ "Ensure telemetry matches actual number of imported items.");
// Check the bookmarks have been imported to all the expected parents.
- Assert.equal(expectedParents.length, 0);
+ Assert.equal(expectedParents.length, 0, "Got all the expected parents");
});
--- a/browser/components/migration/tests/unit/test_Safari_bookmarks.js
+++ b/browser/components/migration/tests/unit/test_Safari_bookmarks.js
@@ -8,32 +8,39 @@ add_task(function* () {
Assert.ok(migrator.sourceExists);
// Wait for the imported bookmarks. Check that "From Safari"
// folders are created on the toolbar.
let source = MigrationUtils.getLocalizedString("sourceNameSafari");
let label = MigrationUtils.getLocalizedString("importedBookmarksFolder", [source]);
let expectedParents = [ PlacesUtils.toolbarFolderId ];
+ let itemCount = 0;
- PlacesUtils.bookmarks.addObserver({
+ let bmObserver = {
onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle) {
- if (aTitle == label) {
+ if (aTitle != label) {
+ itemCount++;
+ }
+ if (expectedParents.length > 0 && aTitle == label) {
let index = expectedParents.indexOf(aParentId);
- Assert.notEqual(index, -1);
+ Assert.ok(index != -1, "Found expected parent");
expectedParents.splice(index, 1);
- if (expectedParents.length == 0)
- PlacesUtils.bookmarks.removeObserver(this);
}
},
onBeginUpdateBatch() {},
onEndUpdateBatch() {},
onItemRemoved() {},
onItemChanged() {},
onItemVisited() {},
onItemMoved() {},
- }, false);
+ };
+ PlacesUtils.bookmarks.addObserver(bmObserver, false);
yield promiseMigration(migrator, MigrationUtils.resourceTypes.BOOKMARKS);
+ PlacesUtils.bookmarks.removeObserver(bmObserver);
// Check the bookmarks have been imported to all the expected parents.
- Assert.equal(expectedParents.length, 0);
+ Assert.ok(!expectedParents.length, "No more expected parents");
+ Assert.equal(itemCount, 13, "Should import all 13 items.");
+ // Check that the telemetry matches:
+ Assert.equal(MigrationUtils._importQuantities.bookmarks, itemCount, "Telemetry reporting correct.");
});
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -4828,16 +4828,49 @@
"expires_in_version": "54",
"kind": "exponential",
"n_buckets": 70,
"high": 100000,
"releaseChannelCollection": "opt-out",
"keyed": true,
"description": "How long it took to import logins (passwords) from another browser, keyed by the name of the browser."
},
+ "FX_MIGRATION_BOOKMARKS_QUANTITY": {
+ "bug_numbers": [1279501],
+ "alert_emails": ["gijs@mozilla.com"],
+ "expires_in_version": "56",
+ "kind": "exponential",
+ "n_buckets": 20,
+ "high": 1000,
+ "releaseChannelCollection": "opt-out",
+ "keyed": true,
+ "description": "How many bookmarks we imported from another browser, keyed by the name of the browser."
+ },
+ "FX_MIGRATION_HISTORY_QUANTITY": {
+ "bug_numbers": [1279501],
+ "alert_emails": ["gijs@mozilla.com"],
+ "expires_in_version": "56",
+ "kind": "exponential",
+ "n_buckets": 40,
+ "high": 10000,
+ "releaseChannelCollection": "opt-out",
+ "keyed": true,
+ "description": "How many history visits we imported from another browser, keyed by the name of the browser."
+ },
+ "FX_MIGRATION_LOGINS_QUANTITY": {
+ "bug_numbers": [1279501],
+ "alert_emails": ["gijs@mozilla.com"],
+ "expires_in_version": "56",
+ "kind": "exponential",
+ "n_buckets": 20,
+ "high": 1000,
+ "releaseChannelCollection": "opt-out",
+ "keyed": true,
+ "description": "How many logins (passwords) we imported from another browser, keyed by the name of the browser."
+ },
"FX_STARTUP_MIGRATION_BROWSER_COUNT": {
"bug_numbers": [1275114],
"alert_emails": ["gijs@mozilla.com"],
"expires_in_version": "53",
"kind": "enumerated",
"n_values": 15,
"releaseChannelCollection": "opt-out",
"description": "Number of browsers from which the user could migrate on initial profile migration. Only available on release builds during firstrun."