summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/browser/browser_local_install.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/extensions/test/browser/browser_local_install.js')
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_local_install.js245
1 files changed, 245 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/browser/browser_local_install.js b/toolkit/mozapps/extensions/test/browser/browser_local_install.js
new file mode 100644
index 0000000000..5200b69e39
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/browser_local_install.js
@@ -0,0 +1,245 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+const { AddonTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/AddonTestUtils.sys.mjs"
+);
+
+AddonTestUtils.initMochitest(this);
+
+const XPI_INCOMPATIBLE_ID = "incompatible-xpi@tests.mozilla.org";
+// NOTE: we are using an HTTP url on purpose here, the test case fails
+// otherwise... We disable `AddonManager.checkUpdateSecurity` to allow
+// retrieving updates from HTTP (which is restored in a
+// `registerCleanupFunction()` or at the end of the task).
+//
+// eslint-disable-next-line @microsoft/sdl/no-insecure-url
+const BASE_URL = "http://fake-updates.example.com";
+
+const server = AddonTestUtils.createHttpServer({
+ hosts: ["fake-updates.example.com"],
+});
+
+const UPDATE_ENTRY_COMPATIBLE = {
+ // NOTE: this version must be the exact same one associated than the
+ // initially incompatible XPI, otherwise it won't override the initial
+ // compatibility range.
+ // See the check in `AddonUpdateChecker.getCompatibilityUpdate` here:
+ // https://searchfox.org/mozilla-central/rev/4044c340/toolkit/mozapps/extensions/internal/AddonUpdateChecker.sys.mjs#489
+ version: "4.0",
+ // An empty compatibility range will make this update to be overriding the
+ // incompatible range in the xpi and makes the xpi version to be considered
+ // compatible.
+ applications: { gecko: {} },
+};
+
+const UPDATE_ENTRY_INCOMPATIBLE = {
+ ...UPDATE_ENTRY_COMPATIBLE,
+ // This update entry instead is including a compatibility range that would
+ // makes the xpi version being installed to be considered still incompatible.
+ applications: {
+ gecko: {
+ strict_min_version: "41",
+ strict_max_version: "41.*",
+ },
+ },
+};
+
+AddonTestUtils.registerJSON(server, "/updates-still-incompatible.json", {
+ addons: {
+ [XPI_INCOMPATIBLE_ID]: {
+ updates: [UPDATE_ENTRY_INCOMPATIBLE],
+ },
+ },
+});
+
+AddonTestUtils.registerJSON(server, "/updates-now-compatible.json", {
+ addons: {
+ [XPI_INCOMPATIBLE_ID]: {
+ updates: [UPDATE_ENTRY_COMPATIBLE],
+ },
+ },
+});
+
+add_task(async function test_local_install_blocklisted() {
+ let id = "amosigned-xpi@tests.mozilla.org";
+ let version = "2.1";
+
+ await AddonTestUtils.loadBlocklistRawData({
+ extensionsMLBF: [
+ {
+ stash: { blocked: [`${id}:${version}`], unblocked: [] },
+ stash_time: 0,
+ },
+ ],
+ });
+ let needsCleanupBlocklist = true;
+ const cleanupBlocklist = async () => {
+ if (!needsCleanupBlocklist) {
+ return;
+ }
+ await AddonTestUtils.loadBlocklistRawData({
+ extensionsMLBF: [
+ {
+ stash: { blocked: [], unblocked: [] },
+ stash_time: 0,
+ },
+ ],
+ });
+ needsCleanupBlocklist = false;
+ };
+ registerCleanupFunction(cleanupBlocklist);
+
+ const xpiFilePath = getTestFilePath("../xpinstall/amosigned.xpi");
+ const xpiFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ xpiFile.initWithPath(xpiFilePath);
+ ok(xpiFile.exists(), "Expect the xpi file to exist");
+ const xpiFileURI = Services.io.newFileURI(xpiFile);
+
+ let install = await AddonManager.getInstallForURL(xpiFileURI.spec, {
+ telemetryInfo: { source: "file-url" },
+ });
+ const promiseInstallFailed = BrowserUtils.promiseObserved(
+ "addon-install-failed",
+ subject => {
+ return subject.wrappedJSObject.installs[0] == install;
+ }
+ );
+
+ AddonManager.installAddonFromWebpage(
+ "application/x-xpinstall",
+ gBrowser.selectedBrowser,
+ Services.scriptSecurityManager.getSystemPrincipal(),
+ install
+ );
+
+ info("Wait for addon-install-failed to be notified");
+ await promiseInstallFailed;
+ Assert.equal(
+ install.error,
+ AddonManager.ERROR_BLOCKLISTED,
+ "LocalInstall cancelled with the expected error"
+ );
+
+ await cleanupBlocklist();
+});
+
+add_task(async function test_local_install_incompatible() {
+ const xpiFilePath = getTestFilePath("../xpinstall/incompatible.xpi");
+ const xpiFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ xpiFile.initWithPath(xpiFilePath);
+ ok(xpiFile.exists(), "Expect the xpi file to exist");
+ const xpiFileURI = Services.io.newFileURI(xpiFile);
+
+ const installTestExtension = async ({ expectIncompatible }) => {
+ let install = await AddonManager.getInstallForURL(xpiFileURI.spec, {
+ telemetryInfo: { source: "file-url" },
+ });
+ const promiseInstallDone = expectIncompatible
+ ? BrowserUtils.promiseObserved(
+ "addon-install-failed",
+ subject => subject.wrappedJSObject.installs[0] == install
+ )
+ : BrowserUtils.promiseObserved(
+ "webextension-permission-prompt",
+ subject => subject.wrappedJSObject.info.addon == install.addon
+ );
+
+ AddonManager.installAddonFromWebpage(
+ "application/x-xpinstall",
+ gBrowser.selectedBrowser,
+ Services.scriptSecurityManager.getSystemPrincipal(),
+ install
+ );
+
+ if (expectIncompatible) {
+ info("Wait for addon-install-failed to be notified");
+ await promiseInstallDone;
+ Assert.equal(
+ install.error,
+ AddonManager.ERROR_INCOMPATIBLE,
+ "LocalInstall cancelled with the expected error"
+ );
+ } else {
+ info("Wait for webextension-permission-prompt to be notified");
+ await promiseInstallDone;
+ Assert.equal(
+ install.error,
+ 0,
+ "no error expected on the LocalInstall instance"
+ );
+ Assert.equal(
+ install.state,
+ AddonManager.STATE_DOWNLOADED,
+ "Got the expected LocalInstall state"
+ );
+ Assert.ok(
+ install.addon.isCompatible,
+ "updated Addon XPI is expected to be compatible"
+ );
+ Assert.equal(
+ install.addon.version,
+ "4.0",
+ "Addon version expected to match the updated xpi file"
+ );
+ // Cancel the installation, before exiting the test.
+ await install.cancel();
+ }
+ };
+
+ info("Test incompatible xpi without a compatibility override");
+ // Use a new tab to make sure the doorhanger will be gone when
+ // the test tab is being removed (same when repeating the
+ // test with expectIncompatible set to false).
+ await BrowserTestUtils.withNewTab("about:blank", async () => {
+ await installTestExtension({ expectIncompatible: true });
+ });
+
+ // Add the prefs to ignore signature checks for this test (allowed on all
+ // channels while running in automation).
+ SpecialPowers.pushPrefEnv({
+ set: [
+ ["extensions.update.url", `${BASE_URL}/updates.json`],
+ ["xpinstall.signatures.required", false],
+ ["extensions.ui.ignoreUnsigned", true],
+ ],
+ });
+ AddonManager.checkUpdateSecurity = false;
+ registerCleanupFunction(() => {
+ AddonManager.checkUpdateSecurity = true;
+ });
+
+ info(
+ "Test incompatible xpi with a compatibility override that is still incompatible"
+ );
+ // Add the prefs to provide a compatibility range override which is still
+ // incompatible.
+ SpecialPowers.pushPrefEnv({
+ set: [
+ ["extensions.update.url", `${BASE_URL}/updates-still-incompatible.json`],
+ ],
+ });
+ await BrowserTestUtils.withNewTab("about:blank", async () => {
+ await installTestExtension({ expectIncompatible: true });
+ });
+ SpecialPowers.popPrefEnv();
+
+ info(
+ "Test incompatible xpi with a compatibility override that makes it compatible"
+ );
+ // Add the prefs to provide a compatibility range override which is
+ // compatible.
+ SpecialPowers.pushPrefEnv({
+ set: [["extensions.update.url", `${BASE_URL}/updates-now-compatible.json`]],
+ });
+ await BrowserTestUtils.withNewTab("about:blank", async () => {
+ await installTestExtension({ expectIncompatible: false });
+ });
+ SpecialPowers.popPrefEnv();
+
+ SpecialPowers.popPrefEnv();
+ AddonManager.checkUpdateSecurity = true;
+});