summaryrefslogtreecommitdiffstats
path: root/services/sync/tests/unit/test_addons_reconciler.js
diff options
context:
space:
mode:
Diffstat (limited to 'services/sync/tests/unit/test_addons_reconciler.js')
-rw-r--r--services/sync/tests/unit/test_addons_reconciler.js209
1 files changed, 209 insertions, 0 deletions
diff --git a/services/sync/tests/unit/test_addons_reconciler.js b/services/sync/tests/unit/test_addons_reconciler.js
new file mode 100644
index 0000000000..c72b18b00e
--- /dev/null
+++ b/services/sync/tests/unit/test_addons_reconciler.js
@@ -0,0 +1,209 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { AddonsReconciler, CHANGE_INSTALLED, CHANGE_UNINSTALLED } =
+ ChromeUtils.importESModule(
+ "resource://services-sync/addonsreconciler.sys.mjs"
+ );
+const { AddonsEngine } = ChromeUtils.importESModule(
+ "resource://services-sync/engines/addons.sys.mjs"
+);
+const { Service } = ChromeUtils.importESModule(
+ "resource://services-sync/service.sys.mjs"
+);
+
+AddonTestUtils.init(this);
+AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "1",
+ "1.9.2"
+);
+AddonTestUtils.overrideCertDB();
+
+const ADDON_ID = "addon1@tests.mozilla.org";
+const XPI = AddonTestUtils.createTempWebExtensionFile({
+ manifest: {
+ name: "Test 1",
+ description: "Test Description",
+ browser_specific_settings: { gecko: { id: ADDON_ID } },
+ },
+});
+
+function makeAddonsReconciler() {
+ const log = Service.engineManager.get("addons")._log;
+ const queueCaller = Async.asyncQueueCaller(log);
+ return new AddonsReconciler(queueCaller);
+}
+
+add_task(async function setup() {
+ await AddonTestUtils.promiseStartupManager();
+ Svc.PrefBranch.setBoolPref("engine.addons", true);
+ await Service.engineManager.register(AddonsEngine);
+});
+
+add_task(async function test_defaults() {
+ _("Ensure new objects have reasonable defaults.");
+
+ let reconciler = makeAddonsReconciler();
+ await reconciler.ensureStateLoaded();
+
+ Assert.ok(!reconciler._listening);
+ Assert.equal("object", typeof reconciler.addons);
+ Assert.equal(0, Object.keys(reconciler.addons).length);
+ Assert.equal(0, reconciler._changes.length);
+ Assert.equal(0, reconciler._listeners.length);
+});
+
+add_task(async function test_load_state_empty_file() {
+ _("Ensure loading from a missing file results in defaults being set.");
+
+ let reconciler = makeAddonsReconciler();
+ await reconciler.ensureStateLoaded();
+
+ let loaded = await reconciler.loadState();
+ Assert.ok(!loaded);
+
+ Assert.equal("object", typeof reconciler.addons);
+ Assert.equal(0, Object.keys(reconciler.addons).length);
+ Assert.equal(0, reconciler._changes.length);
+});
+
+add_task(async function test_install_detection() {
+ _("Ensure that add-on installation results in appropriate side-effects.");
+
+ let reconciler = makeAddonsReconciler();
+ await reconciler.ensureStateLoaded();
+ reconciler.startListening();
+
+ let before = new Date();
+ let addon = await installAddon(XPI);
+ let after = new Date();
+
+ Assert.equal(1, Object.keys(reconciler.addons).length);
+ Assert.ok(addon.id in reconciler.addons);
+ let record = reconciler.addons[ADDON_ID];
+
+ const KEYS = [
+ "id",
+ "guid",
+ "enabled",
+ "installed",
+ "modified",
+ "type",
+ "scope",
+ "foreignInstall",
+ ];
+ for (let key of KEYS) {
+ Assert.ok(key in record);
+ Assert.notEqual(null, record[key]);
+ }
+
+ Assert.equal(addon.id, record.id);
+ Assert.equal(addon.syncGUID, record.guid);
+ Assert.ok(record.enabled);
+ Assert.ok(record.installed);
+ Assert.ok(record.modified >= before && record.modified <= after);
+ Assert.equal("extension", record.type);
+ Assert.ok(!record.foreignInstall);
+
+ Assert.equal(1, reconciler._changes.length);
+ let change = reconciler._changes[0];
+ Assert.ok(change[0] >= before && change[1] <= after);
+ Assert.equal(CHANGE_INSTALLED, change[1]);
+ Assert.equal(addon.id, change[2]);
+
+ await uninstallAddon(addon);
+});
+
+add_task(async function test_uninstall_detection() {
+ _("Ensure that add-on uninstallation results in appropriate side-effects.");
+
+ let reconciler = makeAddonsReconciler();
+ await reconciler.ensureStateLoaded();
+ reconciler.startListening();
+
+ reconciler._addons = {};
+ reconciler._changes = [];
+
+ let addon = await installAddon(XPI);
+ let id = addon.id;
+
+ reconciler._changes = [];
+ await uninstallAddon(addon, reconciler);
+
+ Assert.equal(1, Object.keys(reconciler.addons).length);
+ Assert.ok(id in reconciler.addons);
+
+ let record = reconciler.addons[id];
+ Assert.ok(!record.installed);
+
+ Assert.equal(1, reconciler._changes.length);
+ let change = reconciler._changes[0];
+ Assert.equal(CHANGE_UNINSTALLED, change[1]);
+ Assert.equal(id, change[2]);
+});
+
+add_task(async function test_load_state_future_version() {
+ _("Ensure loading a file from a future version results in no data loaded.");
+
+ const FILENAME = "TEST_LOAD_STATE_FUTURE_VERSION";
+
+ let reconciler = makeAddonsReconciler();
+ await reconciler.ensureStateLoaded();
+
+ // First we populate our new file.
+ let state = { version: 100, addons: { foo: {} }, changes: [[1, 1, "foo"]] };
+
+ // jsonSave() expects an object with ._log, so we give it a reconciler
+ // instance.
+ await Utils.jsonSave(FILENAME, reconciler, state);
+
+ let loaded = await reconciler.loadState(FILENAME);
+ Assert.ok(!loaded);
+
+ Assert.equal("object", typeof reconciler.addons);
+ Assert.equal(0, Object.keys(reconciler.addons).length);
+ Assert.equal(0, reconciler._changes.length);
+});
+
+add_task(async function test_prune_changes_before_date() {
+ _("Ensure that old changes are pruned properly.");
+
+ let reconciler = makeAddonsReconciler();
+ await reconciler.ensureStateLoaded();
+ reconciler._changes = [];
+
+ let now = new Date();
+ const HOUR_MS = 1000 * 60 * 60;
+
+ _("Ensure pruning an empty changes array works.");
+ reconciler.pruneChangesBeforeDate(now);
+ Assert.equal(0, reconciler._changes.length);
+
+ let old = new Date(now.getTime() - HOUR_MS);
+ let young = new Date(now.getTime() - 1000);
+ reconciler._changes.push([old, CHANGE_INSTALLED, "foo"]);
+ reconciler._changes.push([young, CHANGE_INSTALLED, "bar"]);
+ Assert.equal(2, reconciler._changes.length);
+
+ _("Ensure pruning with an old time won't delete anything.");
+ let threshold = new Date(old.getTime() - 1);
+ reconciler.pruneChangesBeforeDate(threshold);
+ Assert.equal(2, reconciler._changes.length);
+
+ _("Ensure pruning a single item works.");
+ threshold = new Date(young.getTime() - 1000);
+ reconciler.pruneChangesBeforeDate(threshold);
+ Assert.equal(1, reconciler._changes.length);
+ Assert.notEqual(undefined, reconciler._changes[0]);
+ Assert.equal(young, reconciler._changes[0][0]);
+ Assert.equal("bar", reconciler._changes[0][2]);
+
+ _("Ensure pruning all changes works.");
+ reconciler._changes.push([old, CHANGE_INSTALLED, "foo"]);
+ reconciler.pruneChangesBeforeDate(now);
+ Assert.equal(0, reconciler._changes.length);
+});