277 lines
7.8 KiB
JavaScript
277 lines
7.8 KiB
JavaScript
/* 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"
|
|
);
|
|
|
|
Services.prefs.setStringPref(
|
|
"extensions.getAddons.get.url",
|
|
"http://localhost:8888/search/guid:%IDS%"
|
|
);
|
|
Services.prefs.setBoolPref("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 = Services.prefs.getBoolPref(
|
|
"privacy.reduceTimerPrecision"
|
|
);
|
|
Services.prefs.setBoolPref("privacy.reduceTimerPrecision", false);
|
|
|
|
registerCleanupFunction(function () {
|
|
Services.prefs.setBoolPref("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();
|
|
});
|