Files
sousa-gecko/services/sync/tests/unit/test_rust_password_tracker.js
T
Johannes Salas Schmidt 1e136a29d5 Bug 2050064 - Add Rust-backed logins Sync engine r=sync-reviewers,credential-management-reviewers,dimi,markh
Introduce RustPasswordEngine, a BridgedEngine backed by the Rust logins
component, used instead of the legacy JS PasswordEngine when the pref
signon.storage.rust.active is set.

Note: lastSync is not migrated from the legacy "<engine>.lastSync" pref
into the Rust meta table, so the first sync after switching backends does
a full re-download. This is a one-time, reset-like behavior.

Differential Revision: https://phabricator.services.mozilla.com/D308535
2026-06-30 09:54:47 +00:00

94 lines
2.9 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Unit tests for RustPasswordTracker.observe().
*
* observe() is pure scoring logic with no dependency on the Rust store, so it is
* exercised on a minimal fake object rather than a fully initialized engine.
*/
"use strict";
const { RustPasswordEngine } = ChromeUtils.importESModule(
"resource://services-sync/engines/passwords.sys.mjs"
);
// RustPasswordTracker is not exported directly; reach it through the engine.
const RustPasswordTracker = RustPasswordEngine.prototype._trackerObj;
function makeTracker({ ignoreAll = false } = {}) {
return {
score: 0,
ignoreAll,
observe: RustPasswordTracker.prototype.observe,
};
}
// Stands in for the nsIArray subject passed for "removeAllLogins".
function fakeLoginArray(count) {
const array = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
for (let i = 0; i < count; i++) {
array.appendElement(
Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString)
);
}
return array;
}
add_task(async function test_single_change_topics_bump_score() {
for (let data of ["modifyLogin", "addLogin", "removeLogin", "importLogins"]) {
let tracker = makeTracker();
await tracker.observe(null, "passwordmgr-storage-changed", data);
Assert.equal(
tracker.score,
SCORE_INCREMENT_XLARGE,
`${data} bumps the score by SCORE_INCREMENT_XLARGE`
);
}
});
add_task(async function test_modifyLogin_ignores_syncCounter() {
// The legacy PasswordTracker only scores "modifyLogin" when the subject's
// syncCounter is > 0. The Rust tracker must not look at the subject at all,
// so passing a null subject still bumps the score.
let tracker = makeTracker();
await tracker.observe(null, "passwordmgr-storage-changed", "modifyLogin");
Assert.equal(
tracker.score,
SCORE_INCREMENT_XLARGE,
"modifyLogin scores without inspecting the subject's syncCounter"
);
});
add_task(async function test_removeAllLogins_scales_with_count() {
let tracker = makeTracker();
await tracker.observe(
fakeLoginArray(3),
"passwordmgr-storage-changed",
"removeAllLogins"
);
Assert.equal(
tracker.score,
SCORE_INCREMENT_XLARGE * 4,
"removeAllLogins bumps the score by SCORE_INCREMENT_XLARGE * (count + 1)"
);
});
add_task(async function test_unknown_topic_does_nothing() {
let tracker = makeTracker();
await tracker.observe(null, "passwordmgr-storage-changed", "somethingElse");
Assert.equal(tracker.score, 0, "an unrelated notification leaves the score");
});
add_task(async function test_ignoreAll_suppresses_scoring() {
let tracker = makeTracker({ ignoreAll: true });
await tracker.observe(null, "passwordmgr-storage-changed", "addLogin");
await tracker.observe(
fakeLoginArray(5),
"passwordmgr-storage-changed",
"removeAllLogins"
);
Assert.equal(tracker.score, 0, "ignoreAll suppresses all scoring");
});