diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /services/sync/tests/unit/test_addons_engine.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'services/sync/tests/unit/test_addons_engine.js')
-rw-r--r-- | services/sync/tests/unit/test_addons_engine.js | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/services/sync/tests/unit/test_addons_engine.js b/services/sync/tests/unit/test_addons_engine.js new file mode 100644 index 0000000000..7e1997b25b --- /dev/null +++ b/services/sync/tests/unit/test_addons_engine.js @@ -0,0 +1,279 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { AddonManager } = ChromeUtils.importESModule( + "resource://gre/modules/AddonManager.sys.mjs" +); +const { CHANGE_INSTALLED } = 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" +); +const { Preferences } = ChromeUtils.importESModule( + "resource://gre/modules/Preferences.sys.mjs" +); + +const prefs = new Preferences(); +prefs.set( + "extensions.getAddons.get.url", + "http://localhost:8888/search/guid:%IDS%" +); +prefs.set("extensions.install.requireSecureOrigin", false); + +let engine; +let syncID; +let reconciler; +let tracker; + +AddonTestUtils.init(this); + +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 } }, + }, +}); + +async function resetReconciler() { + reconciler._addons = {}; + reconciler._changes = []; + + await reconciler.saveState(); + + await tracker.clearChangedIDs(); +} + +add_task(async function setup() { + AddonTestUtils.createAppInfo( + "xpcshell@tests.mozilla.org", + "XPCShell", + "1", + "1.9.2" + ); + AddonTestUtils.overrideCertDB(); + await AddonTestUtils.promiseStartupManager(); + + await Service.engineManager.register(AddonsEngine); + engine = Service.engineManager.get("addons"); + syncID = await engine.resetLocalSyncID(); + reconciler = engine._reconciler; + tracker = engine._tracker; + + reconciler.startListening(); + + // Don't flush to disk in the middle of an event listener! + // This causes test hangs on WinXP. + reconciler._shouldPersist = false; + + await resetReconciler(); +}); + +// This is a basic sanity test for the unit test itself. If this breaks, the +// add-ons API likely changed upstream. +add_task(async function test_addon_install() { + _("Ensure basic add-on APIs work as expected."); + + let install = await AddonManager.getInstallForFile(XPI); + Assert.notEqual(install, null); + Assert.equal(install.type, "extension"); + Assert.equal(install.name, "Test 1"); + + await resetReconciler(); +}); + +add_task(async function test_find_dupe() { + _("Ensure the _findDupe() implementation is sane."); + + // This gets invoked at the top of sync, which is bypassed by this + // test, so we do it manually. + await engine._refreshReconcilerState(); + + let addon = await installAddon(XPI, reconciler); + + let record = { + id: Utils.makeGUID(), + addonID: ADDON_ID, + enabled: true, + applicationID: Services.appinfo.ID, + source: "amo", + }; + + let dupe = await engine._findDupe(record); + Assert.equal(addon.syncGUID, dupe); + + record.id = addon.syncGUID; + dupe = await engine._findDupe(record); + Assert.equal(null, dupe); + + await uninstallAddon(addon, reconciler); + await resetReconciler(); +}); + +add_task(async function test_get_changed_ids() { + let timerPrecision = Preferences.get("privacy.reduceTimerPrecision"); + Preferences.set("privacy.reduceTimerPrecision", false); + + registerCleanupFunction(function () { + Preferences.set("privacy.reduceTimerPrecision", timerPrecision); + }); + + _("Ensure getChangedIDs() has the appropriate behavior."); + + _("Ensure getChangedIDs() returns an empty object by default."); + let changes = await engine.getChangedIDs(); + Assert.equal("object", typeof changes); + Assert.equal(0, Object.keys(changes).length); + + _("Ensure tracker changes are populated."); + let now = new Date(); + let changeTime = now.getTime() / 1000; + let guid1 = Utils.makeGUID(); + await tracker.addChangedID(guid1, changeTime); + + changes = await engine.getChangedIDs(); + Assert.equal("object", typeof changes); + Assert.equal(1, Object.keys(changes).length); + Assert.ok(guid1 in changes); + Assert.equal(changeTime, changes[guid1]); + + await tracker.clearChangedIDs(); + + _("Ensure reconciler changes are populated."); + let addon = await installAddon(XPI, reconciler); + await tracker.clearChangedIDs(); // Just in case. + changes = await engine.getChangedIDs(); + Assert.equal("object", typeof changes); + Assert.equal(1, Object.keys(changes).length); + Assert.ok(addon.syncGUID in changes); + _( + "Change time: " + changeTime + ", addon change: " + changes[addon.syncGUID] + ); + Assert.ok(changes[addon.syncGUID] >= changeTime); + + let oldTime = changes[addon.syncGUID]; + let guid2 = addon.syncGUID; + await uninstallAddon(addon, reconciler); + changes = await engine.getChangedIDs(); + Assert.equal(1, Object.keys(changes).length); + Assert.ok(guid2 in changes); + Assert.ok(changes[guid2] > oldTime); + + _("Ensure non-syncable add-ons aren't picked up by reconciler changes."); + reconciler._addons = {}; + reconciler._changes = []; + let record = { + id: "DUMMY", + guid: Utils.makeGUID(), + enabled: true, + installed: true, + modified: new Date(), + type: "UNSUPPORTED", + scope: 0, + foreignInstall: false, + }; + reconciler.addons.DUMMY = record; + await reconciler._addChange(record.modified, CHANGE_INSTALLED, record); + + changes = await engine.getChangedIDs(); + _(JSON.stringify(changes)); + Assert.equal(0, Object.keys(changes).length); + + await resetReconciler(); +}); + +add_task(async function test_disabled_install_semantics() { + _("Ensure that syncing a disabled add-on preserves proper state."); + + // This is essentially a test for bug 712542, which snuck into the original + // add-on sync drop. It ensures that when an add-on is installed that the + // disabled state and incoming syncGUID is preserved, even on the next sync. + const USER = "foo"; + const PASSWORD = "password"; + + let server = new SyncServer(); + server.start(); + await SyncTestingInfrastructure(server, USER, PASSWORD); + + await generateNewKeys(Service.collectionKeys); + + let contents = { + meta: { + global: { engines: { addons: { version: engine.version, syncID } } }, + }, + crypto: {}, + addons: {}, + }; + + server.registerUser(USER, "password"); + server.createContents(USER, contents); + + let amoServer = new HttpServer(); + amoServer.registerFile( + "/search/guid:addon1%40tests.mozilla.org", + do_get_file("addon1-search.json") + ); + + amoServer.registerFile("/addon1.xpi", XPI); + amoServer.start(8888); + + // Insert an existing record into the server. + let id = Utils.makeGUID(); + let now = Date.now() / 1000; + + let record = encryptPayload({ + id, + applicationID: Services.appinfo.ID, + addonID: ADDON_ID, + enabled: false, + deleted: false, + source: "amo", + }); + let wbo = new ServerWBO(id, record, now - 2); + server.insertWBO(USER, "addons", wbo); + + _("Performing sync of add-ons engine."); + await engine._sync(); + + // At this point the non-restartless extension should be staged for install. + + // Don't need this server any more. + await promiseStopServer(amoServer); + + // We ensure the reconciler has recorded the proper ID and enabled state. + let addon = reconciler.getAddonStateFromSyncGUID(id); + Assert.notEqual(null, addon); + Assert.equal(false, addon.enabled); + + // We fake an app restart and perform another sync, just to make sure things + // are sane. + await AddonTestUtils.promiseRestartManager(); + + let collection = server.getCollection(USER, "addons"); + engine.lastModified = collection.timestamp; + await engine._sync(); + + // The client should not upload a new record. The old record should be + // retained and unmodified. + Assert.equal(1, collection.count()); + + let payload = collection.payloads()[0]; + Assert.notEqual(null, collection.wbo(id)); + Assert.equal(ADDON_ID, payload.addonID); + Assert.ok(!payload.enabled); + + await promiseStopServer(server); +}); + +add_test(function cleanup() { + // There's an xpcom-shutdown hook for this, but let's give this a shot. + reconciler.stopListening(); + run_next_test(); +}); |