summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklistchange.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklistchange.js')
-rw-r--r--toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklistchange.js1410
1 files changed, 1410 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklistchange.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklistchange.js
new file mode 100644
index 0000000000..cd80b34ac0
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklistchange.js
@@ -0,0 +1,1410 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Checks that changes that cause an add-on to become unblocked or blocked have
+// the right effect
+
+// The tests follow a mostly common pattern. First they start with the add-ons
+// unblocked, then they make a change that causes the add-ons to become blocked
+// then they make a similar change that keeps the add-ons blocked then they make
+// a change that unblocks the add-ons. Some tests skip the initial part and
+// start with add-ons detected as blocked.
+
+// softblock1 is enabled/disabled by the blocklist changes so its softDisabled
+// property should always match its userDisabled property
+
+// softblock2 gets manually enabled then disabled after it becomes blocked so
+// its softDisabled property should never become true after that
+
+// softblock3 does the same as softblock2 however it remains disabled
+
+// softblock4 is disabled while unblocked and so should never have softDisabled
+// set to true and stay userDisabled. This add-on is not used in tests that
+// start with add-ons blocked as it would be identical to softblock3
+
+const URI_EXTENSION_BLOCKLIST_DIALOG =
+ "chrome://mozapps/content/extensions/blocklist.xhtml";
+
+// Allow insecure updates
+Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
+
+const IS_ANDROID_WITH_BLOCKLIST_V2 =
+ AppConstants.platform == "android" && !AppConstants.NIGHTLY_BUILD;
+
+// This is the initial value of Blocklist.allowDeprecatedBlocklistV2.
+if (IS_ANDROID_WITH_BLOCKLIST_V2) {
+ // test_blocklistchange_v2.js tests blocklist v2, so we should flip the pref
+ // to enable the v3 blocklist on Android.
+ Assert.ok(
+ _TEST_NAME.includes("test_blocklistchange"),
+ `Expected _TEST_NAME to be test_blocklistchange{,_v2}.js`
+ );
+ if (_TEST_NAME.includes("test_blocklistchange.js")) {
+ Assert.equal(
+ Services.prefs.getBoolPref("extensions.blocklist.useMLBF"),
+ false,
+ "Blocklist v3 disabled by default on Android"
+ );
+ Services.prefs.setBoolPref("extensions.blocklist.useMLBF", true);
+ }
+}
+
+// TODO bug 1649906: strip blocklist v2-specific parts of this test.
+// All specific logic is already covered by other test files, but the tests
+// here trigger the logic via higher-level methods, so it may make sense to
+// keep this file even after the removal of blocklist v2.
+const useMLBF = Services.prefs.getBoolPref(
+ "extensions.blocklist.useMLBF",
+ true
+);
+
+var testserver = createHttpServer({ hosts: ["example.com"] });
+
+function permissionPromptHandler(subject, topic, data) {
+ ok(
+ subject?.wrappedJSObject?.info?.resolve,
+ "Got a permission prompt notification as expected"
+ );
+ subject.wrappedJSObject.info.resolve();
+}
+
+Services.obs.addObserver(
+ permissionPromptHandler,
+ "webextension-permission-prompt"
+);
+
+registerCleanupFunction(() => {
+ Services.obs.removeObserver(
+ permissionPromptHandler,
+ "webextension-permission-prompt"
+ );
+});
+
+const XPIS = {};
+
+const ADDON_IDS = [
+ "softblock1@tests.mozilla.org",
+ "softblock2@tests.mozilla.org",
+ "softblock3@tests.mozilla.org",
+ "softblock4@tests.mozilla.org",
+ "hardblock@tests.mozilla.org",
+ "regexpblock@tests.mozilla.org",
+];
+
+const BLOCK_APP = [
+ {
+ guid: "xpcshell@tests.mozilla.org",
+ maxVersion: "2.*",
+ minVersion: "2",
+ },
+];
+// JEXL filter expression that matches BLOCK_APP.
+const BLOCK_APP_FILTER_EXPRESSION = `env.appinfo.ID == "xpcshell@tests.mozilla.org" && env.appinfo.version >= "2" && env.appinfo.version < "3"`;
+
+function softBlockApp(id) {
+ return {
+ guid: `${id}@tests.mozilla.org`,
+ versionRange: [
+ {
+ severity: "1",
+ targetApplication: BLOCK_APP,
+ },
+ ],
+ };
+}
+
+function softBlockAddonChange(id) {
+ return {
+ guid: `${id}@tests.mozilla.org`,
+ versionRange: [
+ {
+ severity: "1",
+ minVersion: "2",
+ maxVersion: "3",
+ },
+ ],
+ };
+}
+
+function softBlockUpdate2(id) {
+ return {
+ guid: `${id}@tests.mozilla.org`,
+ versionRange: [{ severity: "1" }],
+ };
+}
+
+function softBlockManual(id) {
+ return {
+ guid: `${id}@tests.mozilla.org`,
+ versionRange: [
+ {
+ maxVersion: "2",
+ minVersion: "1",
+ severity: "1",
+ },
+ ],
+ };
+}
+
+const BLOCKLIST_DATA = {
+ empty_blocklist: [],
+ app_update: [
+ softBlockApp("softblock1"),
+ softBlockApp("softblock2"),
+ softBlockApp("softblock3"),
+ softBlockApp("softblock4"),
+ {
+ guid: "hardblock@tests.mozilla.org",
+ versionRange: [
+ {
+ targetApplication: BLOCK_APP,
+ },
+ ],
+ },
+ {
+ guid: "/^RegExp/",
+ versionRange: [
+ {
+ severity: "1",
+ targetApplication: BLOCK_APP,
+ },
+ ],
+ },
+ {
+ guid: "/^RegExp/i",
+ versionRange: [
+ {
+ targetApplication: BLOCK_APP,
+ },
+ ],
+ },
+ ],
+ addon_change: [
+ softBlockAddonChange("softblock1"),
+ softBlockAddonChange("softblock2"),
+ softBlockAddonChange("softblock3"),
+ softBlockAddonChange("softblock4"),
+ {
+ guid: "hardblock@tests.mozilla.org",
+ versionRange: [
+ {
+ maxVersion: "3",
+ minVersion: "2",
+ },
+ ],
+ },
+ {
+ _comment:
+ "Two RegExp matches, so test flags work - first shouldn't match.",
+ guid: "/^RegExp/",
+ versionRange: [
+ {
+ maxVersion: "3",
+ minVersion: "2",
+ severity: "1",
+ },
+ ],
+ },
+ {
+ guid: "/^RegExp/i",
+ versionRange: [
+ {
+ maxVersion: "3",
+ minVersion: "2",
+ severity: "2",
+ },
+ ],
+ },
+ ],
+ blocklist_update2: [
+ softBlockUpdate2("softblock1"),
+ softBlockUpdate2("softblock2"),
+ softBlockUpdate2("softblock3"),
+ softBlockUpdate2("softblock4"),
+ {
+ guid: "hardblock@tests.mozilla.org",
+ versionRange: [],
+ },
+ {
+ guid: "/^RegExp/",
+ versionRange: [{ severity: "1" }],
+ },
+ {
+ guid: "/^RegExp/i",
+ versionRange: [],
+ },
+ ],
+ manual_update: [
+ softBlockManual("softblock1"),
+ softBlockManual("softblock2"),
+ softBlockManual("softblock3"),
+ softBlockManual("softblock4"),
+ {
+ guid: "hardblock@tests.mozilla.org",
+ versionRange: [
+ {
+ maxVersion: "2",
+ minVersion: "1",
+ },
+ ],
+ },
+ {
+ guid: "/^RegExp/i",
+ versionRange: [
+ {
+ maxVersion: "2",
+ minVersion: "1",
+ },
+ ],
+ },
+ ],
+};
+
+// Blocklist v3 (useMLBF) only supports hard blocks by guid+version. Version
+// ranges, regexps and soft blocks are not supported. So adjust expectations to
+// ensure that the test passes even if useMLBF=true, by:
+// - soft blocks are converted to hard blocks.
+// - hard blocks are accepted as-is.
+// - regexps blocks are converted to hard blocks.
+// - Version ranges are expanded to cover all known versions.
+if (useMLBF) {
+ for (let [key, blocks] of Object.entries(BLOCKLIST_DATA)) {
+ BLOCKLIST_DATA[key] = [];
+ for (let block of blocks) {
+ let { guid } = block;
+ if (guid.includes("RegExp")) {
+ guid = "regexpblock@tests.mozilla.org";
+ } else if (!guid.startsWith("soft") && !guid.startsWith("hard")) {
+ throw new Error(`Unexpected mock addon ID: ${guid}`);
+ }
+
+ const {
+ minVersion = "1",
+ maxVersion = "3",
+ targetApplication,
+ } = block.versionRange?.[0] || {};
+
+ for (let v = minVersion; v <= maxVersion; ++v) {
+ BLOCKLIST_DATA[key].push({
+ // Assume that IF targetApplication is set, that it is BLOCK_APP.
+ filter_expression: targetApplication && BLOCK_APP_FILTER_EXPRESSION,
+ stash: {
+ // XPI files use version `${v}.0`, update manifests use `${v}`.
+ blocked: [`${guid}:${v}.0`, `${guid}:${v}`],
+ unblocked: [],
+ },
+ });
+ }
+ }
+ }
+}
+
+// XXXgijs: according to https://bugzilla.mozilla.org/show_bug.cgi?id=1257565#c111
+// this code and the related code in Blocklist.jsm (specific to XML blocklist) is
+// dead code and can be removed. See https://bugzilla.mozilla.org/show_bug.cgi?id=1549550 .
+//
+// Don't need the full interface, attempts to call other methods will just
+// throw which is just fine
+var WindowWatcher = {
+ openWindow(parent, url, name, features, openArgs) {
+ // Should be called to list the newly blocklisted items
+ Assert.equal(url, URI_EXTENSION_BLOCKLIST_DIALOG);
+
+ // Simulate auto-disabling any softblocks
+ var list = openArgs.wrappedJSObject.list;
+ list.forEach(function (aItem) {
+ if (!aItem.blocked) {
+ aItem.disable = true;
+ }
+ });
+
+ // run the code after the blocklist is closed
+ Services.obs.notifyObservers(null, "addon-blocklist-closed");
+ },
+
+ QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"]),
+};
+
+MockRegistrar.register(
+ "@mozilla.org/embedcomp/window-watcher;1",
+ WindowWatcher
+);
+
+var InstallConfirm = {
+ confirm(aWindow, aUrl, aInstalls) {
+ aInstalls.forEach(function (aInstall) {
+ aInstall.install();
+ });
+ },
+
+ QueryInterface: ChromeUtils.generateQI(["amIWebInstallPrompt"]),
+};
+
+var InstallConfirmFactory = {
+ createInstance: function createInstance(iid) {
+ return InstallConfirm.QueryInterface(iid);
+ },
+};
+
+var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+registrar.registerFactory(
+ Components.ID("{f0863905-4dde-42e2-991c-2dc8209bc9ca}"),
+ "Fake Install Prompt",
+ "@mozilla.org/addons/web-install-prompt;1",
+ InstallConfirmFactory
+);
+
+function Pload_blocklist(aId) {
+ return AddonTestUtils.loadBlocklistRawData({
+ [useMLBF ? "extensionsMLBF" : "extensions"]: BLOCKLIST_DATA[aId],
+ });
+}
+
+// Does a background update check for add-ons and returns a promise that
+// resolves when any started installs complete
+function Pbackground_update() {
+ return new Promise((resolve, reject) => {
+ let installCount = 0;
+ let backgroundCheckCompleted = false;
+
+ AddonManager.addInstallListener({
+ onNewInstall(aInstall) {
+ installCount++;
+ },
+
+ onInstallEnded(aInstall) {
+ installCount--;
+ // Wait until all started installs have completed
+ if (installCount) {
+ return;
+ }
+
+ AddonManager.removeInstallListener(this);
+
+ // If the background check hasn't yet completed then let that call the
+ // callback when it is done
+ if (!backgroundCheckCompleted) {
+ return;
+ }
+
+ resolve();
+ },
+ });
+
+ Services.obs.addObserver(function observer() {
+ Services.obs.removeObserver(
+ observer,
+ "addons-background-update-complete"
+ );
+ backgroundCheckCompleted = true;
+
+ // If any new installs have started then we'll call the callback once they
+ // are completed
+ if (installCount) {
+ return;
+ }
+
+ resolve();
+ }, "addons-background-update-complete");
+
+ AddonManagerPrivate.backgroundUpdateCheck();
+ });
+}
+
+// Manually updates the test add-ons to the given version
+function Pmanual_update(aVersion) {
+ const names = ["soft1", "soft2", "soft3", "soft4", "hard", "regexp"];
+ return Promise.all(
+ names.map(async name => {
+ let url = `http://example.com/addons/blocklist_${name}_${aVersion}.xpi`;
+ let install = await AddonManager.getInstallForURL(url);
+
+ // installAddonFromAOM() does more checking than install.install().
+ // In particular, it will refuse to install an incompatible addon.
+
+ return new Promise(resolve => {
+ install.addListener({
+ onDownloadCancelled: resolve,
+ onInstallEnded: resolve,
+ });
+
+ AddonManager.installAddonFromAOM(null, null, install);
+ });
+ })
+ );
+}
+
+// Checks that an add-ons properties match expected values
+function check_addon(
+ aAddon,
+ aExpectedVersion,
+ aExpectedUserDisabled,
+ aExpectedSoftDisabled,
+ aExpectedState
+) {
+ if (useMLBF) {
+ if (aAddon.id.startsWith("soft")) {
+ if (aExpectedState === Ci.nsIBlocklistService.STATE_SOFTBLOCKED) {
+ // The whole test file assumes that an add-on is "user-disabled" after
+ // an explicit disable(), or after a soft block (without enable()).
+ // With useMLBF, soft blocks are not supported, so the "user-disabled"
+ // state matches the usual behavior of "userDisabled" (=disable()).
+ aExpectedUserDisabled = aAddon.userDisabled;
+ aExpectedSoftDisabled = false;
+ aExpectedState = Ci.nsIBlocklistService.STATE_BLOCKED;
+ }
+ }
+ }
+
+ Assert.notEqual(aAddon, null);
+ info(
+ "Testing " +
+ aAddon.id +
+ " version " +
+ aAddon.version +
+ " user " +
+ aAddon.userDisabled +
+ " soft " +
+ aAddon.softDisabled +
+ " perms " +
+ aAddon.permissions
+ );
+
+ Assert.equal(aAddon.version, aExpectedVersion);
+ Assert.equal(aAddon.blocklistState, aExpectedState);
+ Assert.equal(aAddon.userDisabled, aExpectedUserDisabled);
+ Assert.equal(aAddon.softDisabled, aExpectedSoftDisabled);
+ if (aAddon.softDisabled) {
+ Assert.ok(aAddon.userDisabled);
+ }
+
+ if (aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED) {
+ info("blocked, PERM_CAN_ENABLE " + aAddon.id);
+ Assert.ok(!hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE));
+ info("blocked, PERM_CAN_DISABLE " + aAddon.id);
+ Assert.ok(!hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE));
+ } else if (aAddon.userDisabled) {
+ info("userDisabled, PERM_CAN_ENABLE " + aAddon.id);
+ Assert.ok(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE));
+ info("userDisabled, PERM_CAN_DISABLE " + aAddon.id);
+ Assert.ok(!hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE));
+ } else {
+ info("other, PERM_CAN_ENABLE " + aAddon.id);
+ Assert.ok(!hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE));
+ if (aAddon.type != "theme") {
+ info("other, PERM_CAN_DISABLE " + aAddon.id);
+ Assert.ok(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE));
+ }
+ }
+ Assert.equal(
+ aAddon.appDisabled,
+ aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED
+ );
+
+ let willBeActive = aAddon.isActive;
+ if (hasFlag(aAddon.pendingOperations, AddonManager.PENDING_DISABLE)) {
+ willBeActive = false;
+ } else if (hasFlag(aAddon.pendingOperations, AddonManager.PENDING_ENABLE)) {
+ willBeActive = true;
+ }
+
+ if (
+ aExpectedUserDisabled ||
+ aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED
+ ) {
+ Assert.ok(!willBeActive);
+ } else {
+ Assert.ok(willBeActive);
+ }
+}
+
+async function promiseRestartManagerWithAppChange(version) {
+ await promiseShutdownManager();
+ await promiseStartupManagerWithAppChange(version);
+}
+
+async function promiseStartupManagerWithAppChange(version) {
+ if (version) {
+ AddonTestUtils.appInfo.version = version;
+ }
+ if (useMLBF) {
+ // The old ExtensionBlocklist enforced the app version/ID part of the block
+ // when the blocklist entry is checked.
+ // The new ExtensionBlocklist (with useMLBF=true) does not separately check
+ // the app version/ID, but the underlying data source (Remote Settings)
+ // does offer the ability to filter entries with `filter_expression`.
+ // Force a reload to ensure that the BLOCK_APP_FILTER_EXPRESSION filter in
+ // this test file is checked again against the new version.
+ await Blocklist.ExtensionBlocklist._updateMLBF();
+ }
+ await promiseStartupManager();
+}
+
+add_task(async function setup() {
+ createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
+ if (useMLBF) {
+ const { ClientEnvironmentBase } = ChromeUtils.importESModule(
+ "resource://gre/modules/components-utils/ClientEnvironment.sys.mjs"
+ );
+ Object.defineProperty(ClientEnvironmentBase, "appinfo", {
+ configurable: true,
+ get() {
+ return gAppInfo;
+ },
+ });
+ }
+
+ function getxpibasename(id, version) {
+ // pattern used to map ids like softblock1 to soft1
+ let pattern = /^(soft|hard|regexp)block([1-9]*)@/;
+ let match = id.match(pattern);
+ return `blocklist_${match[1]}${match[2]}_${version}`;
+ }
+ for (let id of ADDON_IDS) {
+ for (let version of [1, 2, 3, 4]) {
+ let name = getxpibasename(id, version);
+
+ let xpi = createTempWebExtensionFile({
+ manifest: {
+ name: "Test",
+ version: `${version}.0`,
+ browser_specific_settings: {
+ gecko: {
+ id,
+ // This file is generated below, as updateJson.
+ update_url: `http://example.com/addon_update${version}.json`,
+ },
+ },
+ },
+ });
+
+ // To test updates, individual tasks in this test file start the test by
+ // installing a set of add-ons with version |version| and trigger an
+ // update check, from XPIS.${nameprefix}${version} (version = 1, 2, 3)
+ if (version != 4) {
+ XPIS[name] = xpi;
+ }
+
+ // update_url above points to a test manifest that references the next
+ // version. The xpi is made available on the server, so that the test
+ // can verify that the blocklist works as intended (i.e. update to newer
+ // version is blocked).
+ // There is nothing that updates to version 1, only to versions 2, 3, 4.
+ if (version != 1) {
+ testserver.registerFile(`/addons/${name}.xpi`, xpi);
+ }
+ }
+ }
+
+ // For each version that this test file uses, create a test manifest that
+ // references the next version for each id in ADDON_IDS.
+ for (let version of [1, 2, 3]) {
+ let updateJson = { addons: {} };
+ for (let id of ADDON_IDS) {
+ let nextversion = version + 1;
+ let name = getxpibasename(id, nextversion);
+ updateJson.addons[id] = {
+ updates: [
+ {
+ applications: {
+ gecko: {
+ strict_min_version: "0",
+ advisory_max_version: "*",
+ },
+ },
+ version: `${nextversion}.0`,
+ update_link: `http://example.com/addons/${name}.xpi`,
+ },
+ ],
+ };
+ }
+ AddonTestUtils.registerJSON(
+ testserver,
+ `/addon_update${version}.json`,
+ updateJson
+ );
+ }
+
+ await promiseStartupManager();
+
+ await promiseInstallFile(XPIS.blocklist_soft1_1);
+ await promiseInstallFile(XPIS.blocklist_soft2_1);
+ await promiseInstallFile(XPIS.blocklist_soft3_1);
+ await promiseInstallFile(XPIS.blocklist_soft4_1);
+ await promiseInstallFile(XPIS.blocklist_hard_1);
+ await promiseInstallFile(XPIS.blocklist_regexp_1);
+
+ let s4 = await promiseAddonByID("softblock4@tests.mozilla.org");
+ await s4.disable();
+});
+
+// Starts with add-ons unblocked and then switches application versions to
+// change add-ons to blocked and back
+add_task(async function run_app_update_test() {
+ await Pload_blocklist("app_update");
+ await promiseRestartManager();
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s2,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+});
+
+add_task(async function app_update_step_2() {
+ await promiseRestartManagerWithAppChange("2");
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+
+ await s2.enable();
+ await s2.disable();
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ await s3.enable();
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+});
+
+add_task(async function app_update_step_3() {
+ await promiseRestartManager();
+
+ await promiseRestartManagerWithAppChange("2.5");
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+});
+
+add_task(async function app_update_step_4() {
+ await promiseRestartManagerWithAppChange("1");
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+
+ await s1.enable();
+ await s2.enable();
+});
+
+// Starts with add-ons unblocked and then switches application versions to
+// change add-ons to blocked and back. A DB schema change is faked to force a
+// rebuild when the application version changes
+add_task(async function run_app_update_schema_test() {
+ await promiseRestartManager();
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s2,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+});
+
+add_task(async function update_schema_2() {
+ await promiseShutdownManager();
+
+ await changeXPIDBVersion(100);
+ gAppInfo.version = "2";
+ await promiseStartupManagerWithAppChange();
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+
+ await s2.enable();
+ await s2.disable();
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ await s3.enable();
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+});
+
+add_task(async function update_schema_3() {
+ await promiseRestartManager();
+
+ await promiseShutdownManager();
+ await changeXPIDBVersion(100);
+ gAppInfo.version = "2.5";
+ await promiseStartupManagerWithAppChange();
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+});
+
+add_task(async function update_schema_4() {
+ await promiseShutdownManager();
+
+ await changeXPIDBVersion(100);
+ await promiseStartupManager();
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+});
+
+add_task(async function update_schema_5() {
+ await promiseShutdownManager();
+
+ await changeXPIDBVersion(100);
+ gAppInfo.version = "1";
+ await promiseStartupManagerWithAppChange();
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+
+ await s1.enable();
+ await s2.enable();
+});
+
+// Starts with add-ons unblocked and then loads new blocklists to change add-ons
+// to blocked and back again.
+add_task(async function run_blocklist_update_test() {
+ await Pload_blocklist("empty_blocklist");
+ await promiseRestartManager();
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s2,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+
+ await Pload_blocklist("blocklist_update2");
+ await promiseRestartManager();
+
+ [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+
+ await s2.enable();
+ await s2.disable();
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ await s3.enable();
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+
+ await promiseRestartManager();
+
+ await Pload_blocklist("blocklist_update2");
+ await promiseRestartManager();
+
+ [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+
+ await Pload_blocklist("empty_blocklist");
+ await promiseRestartManager();
+
+ [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+
+ await s1.enable();
+ await s2.enable();
+});
+
+// Starts with add-ons unblocked and then new versions are installed outside of
+// the app to change them to blocked and back again.
+add_task(async function run_addon_change_test() {
+ await Pload_blocklist("addon_change");
+ await promiseRestartManager();
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s2,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+});
+
+add_task(async function run_addon_change_2() {
+ await promiseInstallFile(XPIS.blocklist_soft1_2);
+ await promiseInstallFile(XPIS.blocklist_soft2_2);
+ await promiseInstallFile(XPIS.blocklist_soft3_2);
+ await promiseInstallFile(XPIS.blocklist_soft4_2);
+ await promiseInstallFile(XPIS.blocklist_hard_2);
+ await promiseInstallFile(XPIS.blocklist_regexp_2);
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s3, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s4, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+
+ await s2.enable();
+ await s2.disable();
+ check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ await s3.enable();
+ check_addon(
+ s3,
+ "2.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+});
+
+add_task(async function run_addon_change_3() {
+ await promiseInstallFile(XPIS.blocklist_soft1_3);
+ await promiseInstallFile(XPIS.blocklist_soft2_3);
+ await promiseInstallFile(XPIS.blocklist_soft3_3);
+ await promiseInstallFile(XPIS.blocklist_soft4_3);
+ await promiseInstallFile(XPIS.blocklist_hard_3);
+ await promiseInstallFile(XPIS.blocklist_regexp_3);
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(
+ s3,
+ "3.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+ check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+});
+
+add_task(async function run_addon_change_4() {
+ await promiseInstallFile(XPIS.blocklist_soft1_1);
+ await promiseInstallFile(XPIS.blocklist_soft2_1);
+ await promiseInstallFile(XPIS.blocklist_soft3_1);
+ await promiseInstallFile(XPIS.blocklist_soft4_1);
+ await promiseInstallFile(XPIS.blocklist_hard_1);
+ await promiseInstallFile(XPIS.blocklist_regexp_1);
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+
+ await s1.enable();
+ await s2.enable();
+});
+
+// Add-ons are initially unblocked then attempts to upgrade to blocked versions
+// in the background which should fail
+add_task(async function run_background_update_test() {
+ await promiseRestartManager();
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s2,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+
+ await Pbackground_update();
+ await promiseRestartManager();
+
+ [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s2,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+});
+
+// Starts with add-ons blocked and then new versions are detected and installed
+// automatically for unblocked versions.
+add_task(async function run_background_update_2_test() {
+ await promiseInstallFile(XPIS.blocklist_soft1_3);
+ await promiseInstallFile(XPIS.blocklist_soft2_3);
+ await promiseInstallFile(XPIS.blocklist_soft3_3);
+ await promiseInstallFile(XPIS.blocklist_soft4_3);
+ await promiseInstallFile(XPIS.blocklist_hard_3);
+ await promiseInstallFile(XPIS.blocklist_regexp_3);
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s3, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+
+ await s2.enable();
+ await s2.disable();
+ check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ await s3.enable();
+ check_addon(
+ s3,
+ "3.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+
+ await Pbackground_update();
+
+ [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "4.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s2, "4.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(
+ s3,
+ "4.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(h, "4.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "4.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+
+ await s1.enable();
+ await s2.enable();
+ await s4.disable();
+});
+
+// The next test task (run_manual_update_test) was written to expect version 1,
+// but after the previous test, version 4 of the add-ons were installed.
+add_task(async function reset_addons_to_version_1_instead_of_4() {
+ await promiseInstallFile(XPIS.blocklist_soft1_1);
+ await promiseInstallFile(XPIS.blocklist_soft2_1);
+ await promiseInstallFile(XPIS.blocklist_soft3_1);
+ await promiseInstallFile(XPIS.blocklist_soft4_1);
+ await promiseInstallFile(XPIS.blocklist_hard_1);
+ await promiseInstallFile(XPIS.blocklist_regexp_1);
+});
+
+// Starts with add-ons blocked and then simulates the user upgrading them to
+// unblocked versions.
+add_task(async function run_manual_update_test() {
+ await Pload_blocklist("manual_update");
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+
+ await s2.enable();
+ await s2.disable();
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ await s3.enable();
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+
+ await Pmanual_update("2");
+
+ [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ // With useMLBF, s1/s2/s3 are hard blocks, so they cannot update.
+ const sv2 = useMLBF ? "1.0" : "2.0";
+ check_addon(s1, sv2, true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, sv2, true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s3, sv2, false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s4, sv2, true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ // Can't manually update to a hardblocked add-on
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+
+ await Pmanual_update("3");
+
+ [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "3.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(
+ s3,
+ "3.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+});
+
+// Starts with add-ons blocked and then new versions are installed outside of
+// the app to change them to unblocked.
+add_task(async function run_manual_update_2_test() {
+ let addons = await promiseAddonsByIDs(ADDON_IDS);
+ await Promise.all(addons.map(addon => addon.uninstall()));
+
+ await promiseInstallFile(XPIS.blocklist_soft1_1);
+ await promiseInstallFile(XPIS.blocklist_soft2_1);
+ await promiseInstallFile(XPIS.blocklist_soft3_1);
+ await promiseInstallFile(XPIS.blocklist_soft4_1);
+ await promiseInstallFile(XPIS.blocklist_hard_1);
+ await promiseInstallFile(XPIS.blocklist_regexp_1);
+
+ let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+
+ await s2.enable();
+ await s2.disable();
+ check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ await s3.enable();
+ check_addon(
+ s3,
+ "1.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ );
+
+ await Pmanual_update("2");
+
+ [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ // With useMLBF, s1/s2/s3 are hard blocks, so they cannot update.
+ const sv2 = useMLBF ? "1.0" : "2.0";
+ check_addon(s1, sv2, true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, sv2, true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s3, sv2, false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ // Can't manually update to a hardblocked add-on
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+
+ await Pmanual_update("3");
+
+ [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(
+ s1,
+ "3.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(
+ s3,
+ "3.0",
+ false,
+ false,
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED
+ );
+ check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+
+ await s1.enable();
+ await s2.enable();
+ await s4.disable();
+});
+
+// Uses the API to install blocked add-ons from the local filesystem
+add_task(async function run_local_install_test() {
+ let addons = await promiseAddonsByIDs(ADDON_IDS);
+ await Promise.all(addons.map(addon => addon.uninstall()));
+
+ await promiseInstallAllFiles([
+ XPIS.blocklist_soft1_1,
+ XPIS.blocklist_soft2_1,
+ XPIS.blocklist_soft3_1,
+ XPIS.blocklist_soft4_1,
+ XPIS.blocklist_hard_1,
+ XPIS.blocklist_regexp_1,
+ ]);
+
+ let installs = await AddonManager.getAllInstalls();
+ // Should have finished all installs without needing to restart
+ Assert.equal(installs.length, 0);
+
+ let [s1, s2, s3 /* s4 */, , h, r] = await promiseAddonsByIDs(ADDON_IDS);
+
+ check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+ check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+ check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
+});