commit adcc104bc7d8afb196df6b3b3adf76bbe8d4c6f6
parent b65113ed0849854fbc6833c0c9619e27bd89b890
Author: Johannes Schmidt <joschmidt@mozilla.com>
Date: Tue, 21 Oct 2025 14:30:20 +0000
Bug 1993218 - emit rust mirror events and harden tests - r=dimi
Differential Revision: https://phabricator.services.mozilla.com/D269383
Diffstat:
2 files changed, 59 insertions(+), 48 deletions(-)
diff --git a/toolkit/components/passwordmgr/LoginManagerRustMirror.sys.mjs b/toolkit/components/passwordmgr/LoginManagerRustMirror.sys.mjs
@@ -259,6 +259,11 @@ export class LoginManagerRustMirror {
this.#logger.error(`error: received unhandled event "${eventName}"`);
break;
}
+
+ Services.obs.notifyObservers(
+ null,
+ `rust-mirror.event.${eventName}.finished`
+ );
}
async #maybeRunMigration() {
@@ -339,6 +344,9 @@ export class LoginManagerRustMirror {
numberOfLoginsMigrated
);
this.#migrationInProgress = false;
+
+ // Notify about the finished migration. This is used in tests.
+ Services.obs.notifyObservers(null, "rust-mirror.migration.finished");
}
}
}
diff --git a/toolkit/components/passwordmgr/test/browser/browser_rust_mirror.js b/toolkit/components/passwordmgr/test/browser/browser_rust_mirror.js
@@ -27,12 +27,15 @@ add_task(async function test_mirror_addLogin() {
username: "username",
password: "password",
});
+ const addLoginFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.event.addLogin.finished"
+ );
await Services.logins.addLoginAsync(loginInfo);
+ await addLoginFinishedPromise;
// note LoginManagerRustStorage is a singleton and already initialized when
// Services.logins gets initialized.
const rustStorage = new LoginManagerRustStorage();
-
const storedLoginInfos = await Services.logins.getAllLogins();
const rustStoredLoginInfos = await rustStorage.getAllLogins();
LoginTestUtils.assertLoginListsEqual(storedLoginInfos, rustStoredLoginInfos);
@@ -54,9 +57,11 @@ add_task(async function test_mirror_modifyLogin() {
username: "username",
password: "password",
});
+ const addLoginFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.event.addLogin.finished"
+ );
await Services.logins.addLoginAsync(loginInfo);
-
- const rustStorage = new LoginManagerRustStorage();
+ await addLoginFinishedPromise;
const [storedLoginInfo] = await Services.logins.getAllLogins();
@@ -66,13 +71,17 @@ add_task(async function test_mirror_modifyLogin() {
usernameField: "new_form_field_username",
passwordField: "new_form_field_password",
});
+ const modifyLoginFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.event.modifyLogin.finished"
+ );
Services.logins.modifyLogin(storedLoginInfo, modifiedLoginInfo);
+ await modifyLoginFinishedPromise;
+ const rustStorage = new LoginManagerRustStorage();
const [storedModifiedLoginInfo] = await Services.logins.getAllLogins();
const [rustStoredModifiedLoginInfo] = await rustStorage.searchLoginsAsync({
guid: storedLoginInfo.guid,
});
-
LoginTestUtils.assertLoginListsEqual(
[storedModifiedLoginInfo],
[rustStoredModifiedLoginInfo]
@@ -95,14 +104,20 @@ add_task(async function test_mirror_removeLogin() {
username: "username",
password: "password",
});
+ const addLoginFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.event.addLogin.finished"
+ );
await Services.logins.addLoginAsync(loginInfo);
-
- const rustStorage = new LoginManagerRustStorage();
+ await addLoginFinishedPromise;
const [storedLoginInfo] = await Services.logins.getAllLogins();
-
+ const removeLoginFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.event.removeLogin.finished"
+ );
Services.logins.removeLogin(storedLoginInfo);
+ await removeLoginFinishedPromise;
+ const rustStorage = new LoginManagerRustStorage();
const allLogins = await rustStorage.getAllLogins();
Assert.equal(allLogins.length, 0);
@@ -116,27 +131,21 @@ add_task(async function test_mirror_removeLogin() {
*/
add_task(async function test_mirror_csv_import_add() {
await SpecialPowers.pushPrefEnv({
- set: [
- ["signon.rustMirror.enabled", true],
- ["signon.rustMirror.migrationNeeded", true],
- ],
+ set: [["signon.rustMirror.enabled", true]],
});
let csvFile = await LoginTestUtils.file.setupCsvFileWithLines([
"url,username,password,httpRealm,formActionOrigin,guid,timeCreated,timeLastUsed,timePasswordChanged",
`https://example.com,joe@example.com,qwerty,My realm,,{5ec0d12f-e194-4279-ae1b-d7d281bb46f0},1589617814635,1589710449871,1589617846802`,
]);
- const prefChangePromise = TestUtils.waitForPrefChange(
- "signon.rustMirror.migrationNeeded"
+ const importLoginsFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.event.importLogins.finished"
);
await LoginCSVImport.importFromCSV(csvFile.path);
// wait for the mirror to complete
- await prefChangePromise;
+ await importLoginsFinishedPromise;
- // note LoginManagerRustStorage is a singleton and already initialized when
- // Services.logins gets initialized.
const rustStorage = new LoginManagerRustStorage();
-
const storedLoginInfos = await Services.logins.getAllLogins();
const rustStoredLoginInfos = await rustStorage.getAllLogins();
LoginTestUtils.assertLoginListsEqual(storedLoginInfos, rustStoredLoginInfos);
@@ -151,10 +160,7 @@ add_task(async function test_mirror_csv_import_add() {
*/
add_task(async function test_mirror_csv_import_modify() {
await SpecialPowers.pushPrefEnv({
- set: [
- ["signon.rustMirror.enabled", true],
- ["signon.rustMirror.migrationNeeded", true],
- ],
+ set: [["signon.rustMirror.enabled", true]],
});
// create a login
@@ -163,26 +169,27 @@ add_task(async function test_mirror_csv_import_modify() {
username: "username",
password: "password",
});
- const login = await Services.logins.addLoginAsync(loginInfo);
- const prefChangePromise = TestUtils.waitForPrefChange(
- "signon.rustMirror.migrationNeeded"
+ const addLoginFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.event.addLogin.finished"
);
+ const login = await Services.logins.addLoginAsync(loginInfo);
+ await addLoginFinishedPromise;
+
// and import it, so we update
let csvFile = await LoginTestUtils.file.setupCsvFileWithLines([
"url,username,password,httpRealm,formActionOrigin,guid,timeCreated,timeLastUsed,timePasswordChanged",
`https://example.com,username,qwerty,My realm,,${login.guid},1589617814635,1589710449871,1589617846802`,
]);
+ const importLoginsFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.event.importLogins.finished"
+ );
await LoginCSVImport.importFromCSV(csvFile.path);
// wait for the mirror to complete
- await prefChangePromise;
+ await importLoginsFinishedPromise;
- // note LoginManagerRustStorage is a singleton and already initialized when
- // Services.logins gets initialized.
const rustStorage = new LoginManagerRustStorage();
-
const [storedLoginInfo] = await Services.logins.getAllLogins();
const [rustStoredLoginInfo] = await rustStorage.getAllLogins();
-
Assert.equal(
storedLoginInfo.password,
rustStoredLoginInfo.password,
@@ -242,10 +249,13 @@ add_task(async function test_migration_is_idempotent() {
username: "test-user",
password: "secure-password",
});
+ const addLoginFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.event.addLogin.finished"
+ );
await Services.logins.addLoginAsync(login);
+ await addLoginFinishedPromise;
const rustStorage = new LoginManagerRustStorage();
-
let rustLogins = await rustStorage.getAllLogins();
Assert.equal(
rustLogins.length,
@@ -257,14 +267,13 @@ add_task(async function test_migration_is_idempotent() {
await SpecialPowers.pushPrefEnv({
set: [["signon.rustMirror.enabled", false]],
});
- // using the migrationNeeded pref change as an indicator that the migration did run
- const prefChangePromise = TestUtils.waitForPrefChange(
- "signon.rustMirror.migrationNeeded"
+ const migrationFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.migration.finished"
);
await SpecialPowers.pushPrefEnv({
set: [["signon.rustMirror.enabled", true]],
});
- await prefChangePromise;
+ await migrationFinishedPromise;
rustLogins = await rustStorage.getAllLogins();
Assert.equal(rustLogins.length, 1, "No duplicate after second migration");
@@ -307,16 +316,13 @@ add_task(async function test_migration_partial_failure() {
await Services.logins.addLoginAsync(login_bad);
// trigger again
- await SpecialPowers.pushPrefEnv({
- set: [["signon.rustMirror.enabled", false]],
- });
+ const migrationFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.migration.finished"
+ );
await SpecialPowers.pushPrefEnv({
set: [["signon.rustMirror.enabled", true]],
});
-
- // and wait a little, due to the lack of a migration-complete event.
- // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
- await new Promise(resolve => setTimeout(resolve, 200));
+ await migrationFinishedPromise;
const rustLogins = await rustStorage.getAllLogins();
Assert.equal(rustLogins.length, 1, "only valid login migrated");
@@ -348,16 +354,13 @@ add_task(async function test_migration_rejects_when_bulk_add_rejects() {
await Services.logins.addLoginAsync(login);
// trigger again
- await SpecialPowers.pushPrefEnv({
- set: [["signon.rustMirror.enabled", false]],
- });
+ const migrationFinishedPromise = TestUtils.topicObserved(
+ "rust-mirror.migration.finished"
+ );
await SpecialPowers.pushPrefEnv({
set: [["signon.rustMirror.enabled", true]],
});
-
- // and wait a little, due to the lack of a migration-complete event.
- // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
- await new Promise(resolve => setTimeout(resolve, 200));
+ await migrationFinishedPromise;
const rustLogins = await rustStorage.getAllLogins();
Assert.equal(rustLogins.length, 0, "zero logins migrated");