summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpcshell/test_webextension_langpack.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/extensions/test/xpcshell/test_webextension_langpack.js')
-rw-r--r--toolkit/mozapps/extensions/test/xpcshell/test_webextension_langpack.js573
1 files changed, 573 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_langpack.js b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_langpack.js
new file mode 100644
index 0000000000..9e4aeadf4e
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_langpack.js
@@ -0,0 +1,573 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+"use strict";
+
+const { L10nRegistry } = ChromeUtils.import(
+ "resource://gre/modules/L10nRegistry.jsm"
+);
+
+const { ExtensionUtils } = ChromeUtils.import(
+ "resource://gre/modules/ExtensionUtils.jsm"
+);
+
+XPCOMUtils.defineLazyGetter(this, "resourceProtocol", () =>
+ Services.io
+ .getProtocolHandler("resource")
+ .QueryInterface(Ci.nsIResProtocolHandler)
+);
+
+Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
+
+const ID = "langpack-und@test.mozilla.org";
+
+const profileDir = gProfD.clone();
+profileDir.append("extensions");
+
+var server = AddonTestUtils.createHttpServer({ hosts: ["example.com"] });
+AddonTestUtils.registerJSON(server, "/test_update_langpack.json", {
+ addons: {
+ "langpack-und@test.mozilla.org": {
+ updates: [
+ {
+ version: "1.0",
+ applications: {
+ gecko: {
+ strict_min_version: "58.0",
+ strict_max_version: "58.*",
+ },
+ },
+ },
+ {
+ version: "2.0",
+ update_link:
+ "http://example.com/addons/langpack-und@test.mozilla.org.xpi",
+ applications: {
+ gecko: {
+ strict_min_version: "60.0",
+ strict_max_version: "60.*",
+ },
+ },
+ },
+ ],
+ },
+ },
+});
+
+function promisePostponeInstall(install) {
+ return new Promise((resolve, reject) => {
+ let listener = {
+ onDownloadEnded: () => {
+ install.postpone();
+ },
+ onInstallFailed: () => {
+ install.removeListener(listener);
+ reject(new Error("extension installation should not have failed"));
+ },
+ onInstallEnded: () => {
+ install.removeListener(listener);
+ reject(
+ new Error(
+ `extension installation should not have ended for ${install.addon.id}`
+ )
+ );
+ },
+ onInstallPostponed: () => {
+ install.removeListener(listener);
+ resolve();
+ },
+ };
+
+ install.addListener(listener);
+ });
+}
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "58");
+
+const ADDONS = {
+ langpack_1: {
+ "browser/localization/und/browser.ftl":
+ "message-browser = Value from Browser\n",
+ "localization/und/toolkit_test.ftl": "message-id1 = Value 1\n",
+ "chrome/und/locale/und/global/test.properties":
+ "message = Value from .properties\n",
+ "manifest.json": {
+ name: "und Language Pack",
+ version: "1.0",
+ manifest_version: 2,
+ applications: {
+ gecko: {
+ id: ID,
+ strict_min_version: "58.0",
+ strict_max_version: "58.*",
+ update_url: "http://example.com/test_update_langpack.json",
+ },
+ },
+ sources: {
+ browser: {
+ base_path: "browser/",
+ },
+ },
+ langpack_id: "und",
+ languages: {
+ und: {
+ chrome_resources: {
+ global: "chrome/und/locale/und/global/",
+ },
+ version: "20171001190118",
+ },
+ },
+ author: "Mozilla Localization Task Force",
+ description: "Language pack for Testy for und",
+ },
+ },
+};
+
+// clone the extension so we can create an update.
+const langpack_update = JSON.parse(JSON.stringify(ADDONS.langpack_1));
+langpack_update["manifest.json"].version = "2.0";
+langpack_update["manifest.json"].applications.gecko = {
+ id: ID,
+ strict_min_version: "60.0",
+ strict_max_version: "60.*",
+};
+
+let xpi = AddonTestUtils.createTempXPIFile(langpack_update);
+server.registerFile(`/addons/${ID}.xpi`, xpi);
+
+function promiseLangpackStartup() {
+ return new Promise(resolve => {
+ const EVENT = "webextension-langpack-startup";
+ Services.obs.addObserver(function observer() {
+ Services.obs.removeObserver(observer, EVENT);
+ resolve();
+ }, EVENT);
+ });
+}
+
+add_task(async function setup() {
+ Services.prefs.clearUserPref("extensions.startupScanScopes");
+});
+
+/**
+ * This is a basic life-cycle test which verifies that
+ * the language pack registers and unregisters correct
+ * languages at various stages.
+ */
+add_task(async function test_basic_lifecycle() {
+ await promiseStartupManager();
+
+ // Make sure that `und` locale is not installed.
+ equal(
+ L10nRegistry.getAvailableLocales().includes("und"),
+ false,
+ "und not installed"
+ );
+ equal(
+ Services.locale.availableLocales.includes("und"),
+ false,
+ "und not available"
+ );
+
+ let [, { addon }] = await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+
+ // Now make sure that `und` locale is available.
+ equal(
+ L10nRegistry.getAvailableLocales().includes("und"),
+ true,
+ "und is installed"
+ );
+ equal(
+ Services.locale.availableLocales.includes("und"),
+ true,
+ "und is available"
+ );
+
+ await addon.disable();
+
+ // It is not available after the langpack has been disabled.
+ equal(
+ L10nRegistry.getAvailableLocales().includes("und"),
+ false,
+ "und not installed"
+ );
+ equal(
+ Services.locale.availableLocales.includes("und"),
+ false,
+ "und not available"
+ );
+
+ // This quirky code here allows us to handle a scenario where enabling the
+ // addon is synchronous or asynchronous.
+ await Promise.all([promiseLangpackStartup(), addon.enable()]);
+
+ // After re-enabling it, the `und` locale is available again.
+ equal(
+ L10nRegistry.getAvailableLocales().includes("und"),
+ true,
+ "und is installed"
+ );
+ equal(
+ Services.locale.availableLocales.includes("und"),
+ true,
+ "und is available"
+ );
+
+ await addon.uninstall();
+
+ // After the langpack has been uninstalled, no more `und` in locales.
+ equal(
+ L10nRegistry.getAvailableLocales().includes("und"),
+ false,
+ "und not installed"
+ );
+ equal(
+ Services.locale.availableLocales.includes("und"),
+ false,
+ "und not available"
+ );
+});
+
+/**
+ * This test verifies that registries are able to load and synchronously return
+ * correct strings available in the language pack.
+ */
+add_task(async function test_locale_registries() {
+ let [, { addon }] = await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+
+ {
+ // Toolkit string
+ let bundles = L10nRegistry.generateBundlesSync(
+ ["und"],
+ ["toolkit_test.ftl"]
+ );
+ let bundle0 = bundles.next().value;
+ ok(bundle0);
+ equal(bundle0.hasMessage("message-id1"), true);
+ }
+
+ {
+ // Browser string
+ let bundles = L10nRegistry.generateBundlesSync(["und"], ["browser.ftl"]);
+ let bundle0 = bundles.next().value;
+ ok(bundle0);
+ equal(bundle0.hasMessage("message-browser"), true);
+ }
+
+ {
+ // Test chrome package
+ let reqLocs = Services.locale.requestedLocales;
+ Services.locale.requestedLocales = ["und"];
+
+ let bundle = Services.strings.createBundle(
+ "chrome://global/locale/test.properties"
+ );
+ let entry = bundle.GetStringFromName("message");
+ equal(entry, "Value from .properties");
+
+ Services.locale.requestedLocales = reqLocs;
+ }
+
+ await addon.uninstall();
+});
+
+/**
+ * This test verifies that registries are able to load and asynchronously return
+ * correct strings available in the language pack.
+ */
+add_task(async function test_locale_registries_async() {
+ let [, { addon }] = await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+
+ {
+ // Toolkit string
+ let bundles = L10nRegistry.generateBundles(["und"], ["toolkit_test.ftl"]);
+ let bundle0 = (await bundles.next()).value;
+ equal(bundle0.hasMessage("message-id1"), true);
+ }
+
+ {
+ // Browser string
+ let bundles = L10nRegistry.generateBundles(["und"], ["browser.ftl"]);
+ let bundle0 = (await bundles.next()).value;
+ equal(bundle0.hasMessage("message-browser"), true);
+ }
+
+ await addon.uninstall();
+ await promiseShutdownManager();
+});
+
+add_task(async function test_langpack_app_shutdown() {
+ let langpackId = `langpack-und-${AppConstants.MOZ_BUILD_APP.replace(
+ "/",
+ "-"
+ )}`;
+ let check = (yes, msg) => {
+ equal(resourceProtocol.hasSubstitution(langpackId), yes, msg);
+ };
+
+ await promiseStartupManager();
+
+ check(false, "no initial resource substitution");
+
+ await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+
+ check(true, "langpack resource available after startup");
+
+ await promiseShutdownManager();
+
+ check(true, "langpack resource available after app shutdown");
+
+ await promiseStartupManager();
+
+ let addon = await AddonManager.getAddonByID(ID);
+ await addon.uninstall();
+
+ check(false, "langpack resource removed during shutdown for uninstall");
+
+ await promiseShutdownManager();
+});
+
+add_task(async function test_amazing_disappearing_langpacks() {
+ let check = yes => {
+ equal(
+ L10nRegistry.getAvailableLocales().includes("und"),
+ yes,
+ "check L10nRegistry"
+ );
+ equal(
+ Services.locale.availableLocales.includes("und"),
+ yes,
+ "check availableLocales"
+ );
+ };
+
+ await promiseStartupManager();
+
+ check(false);
+
+ await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+
+ check(true);
+
+ await promiseShutdownManager();
+
+ check(false);
+
+ await AddonTestUtils.manuallyUninstall(AddonTestUtils.profileExtensions, ID);
+
+ await promiseStartupManager();
+
+ check(false);
+});
+
+/**
+ * This test verifies that language pack will get disabled after app
+ * gets upgraded.
+ */
+add_task(async function test_disable_after_app_update() {
+ let [, { addon }] = await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+ Assert.ok(addon.isActive);
+
+ await promiseRestartManager("59");
+
+ addon = await promiseAddonByID(ID);
+ Assert.ok(!addon.isActive);
+ Assert.ok(addon.appDisabled);
+
+ await addon.uninstall();
+ await promiseShutdownManager();
+});
+
+/**
+ * This test verifies that a postponed language pack update will be
+ * applied after a restart.
+ */
+add_task(async function test_after_app_update() {
+ await promiseStartupManager("58");
+ let [, { addon }] = await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+ Assert.ok(addon.isActive);
+
+ await promiseRestartManager("60");
+
+ addon = await promiseAddonByID(ID);
+ Assert.ok(!addon.isActive);
+ Assert.ok(addon.appDisabled);
+ Assert.equal(addon.version, "1.0");
+
+ let update = await promiseFindAddonUpdates(addon);
+ Assert.ok(update.updateAvailable, "update is available");
+ let install = update.updateAvailable;
+ let postponed = promisePostponeInstall(install);
+ install.install();
+ await postponed;
+ Assert.equal(
+ install.state,
+ AddonManager.STATE_POSTPONED,
+ "install postponed"
+ );
+
+ await promiseRestartManager();
+
+ addon = await promiseAddonByID(ID);
+ Assert.ok(addon.isActive);
+ Assert.equal(addon.version, "2.0");
+
+ await addon.uninstall();
+ await promiseShutdownManager();
+});
+
+// Support setting the request locale.
+function promiseLocaleChanged(requestedLocales) {
+ let changed = ExtensionUtils.promiseObserved(
+ "intl:requested-locales-changed"
+ );
+ Services.locale.requestedLocales = requestedLocales;
+ return changed;
+}
+
+/**
+ * This test verifies that an addon update for the next version can be
+ * retrieved and staged for restart.
+ */
+add_task(async function test_staged_langpack_for_app_update() {
+ let originalLocales = Services.locale.requestedLocales;
+
+ await promiseStartupManager("58");
+ let [, { addon }] = await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+ Assert.ok(addon.isActive);
+ await promiseLocaleChanged(["und"]);
+
+ await AddonManager.stageLangpacksForAppUpdate("60");
+ await promiseRestartManager("60");
+
+ addon = await promiseAddonByID(ID);
+ Assert.ok(addon.isActive);
+ Assert.equal(addon.version, "2.0");
+
+ await addon.uninstall();
+ await promiseShutdownManager();
+
+ Services.locale.requestedLocales = originalLocales;
+});
+
+/**
+ * This test verifies that an addon update for the next version can be
+ * retrieved and staged for restart, but a restart failure falls back.
+ */
+add_task(async function test_staged_langpack_for_app_update_fail() {
+ let originalLocales = Services.locale.requestedLocales;
+
+ await promiseStartupManager("58");
+ let [, { addon }] = await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+ Assert.ok(addon.isActive);
+ await promiseLocaleChanged(["und"]);
+
+ await AddonManager.stageLangpacksForAppUpdate("60");
+ await promiseRestartManager();
+
+ addon = await promiseAddonByID(ID);
+ Assert.ok(addon.isActive);
+ Assert.equal(addon.version, "1.0");
+
+ await addon.uninstall();
+ await promiseShutdownManager();
+ Services.locale.requestedLocales = originalLocales;
+});
+
+/**
+ * This test verifies that an update restart works when the langpack
+ * cannot be updated.
+ */
+add_task(async function test_staged_langpack_for_app_update_not_found() {
+ let originalLocales = Services.locale.requestedLocales;
+
+ await promiseStartupManager("58");
+ let [, { addon }] = await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+ Assert.ok(addon.isActive);
+ await promiseLocaleChanged(["und"]);
+
+ await AddonManager.stageLangpacksForAppUpdate("59");
+ await promiseRestartManager("59");
+
+ addon = await promiseAddonByID(ID);
+ Assert.ok(!addon.isActive);
+ Assert.equal(addon.version, "1.0");
+
+ await addon.uninstall();
+ await promiseShutdownManager();
+ Services.locale.requestedLocales = originalLocales;
+});
+
+/**
+ * This test verifies that a compat update with an invalid max_version
+ * will be disabled, at least allowing Firefox to startup without failures.
+ */
+add_task(async function test_staged_langpack_compat_startup() {
+ let originalLocales = Services.locale.requestedLocales;
+
+ await promiseStartupManager("58");
+ let [, { addon }] = await Promise.all([
+ promiseLangpackStartup(),
+ AddonTestUtils.promiseInstallXPI(ADDONS.langpack_1),
+ ]);
+ Assert.ok(addon.isActive);
+ await promiseLocaleChanged(["und"]);
+
+ // Mimick a compatibility update
+ let compatUpdate = {
+ targetApplications: [
+ {
+ id: "toolkit@mozilla.org",
+ minVersion: "58",
+ maxVersion: "*",
+ },
+ ],
+ };
+ addon.__AddonInternal__.applyCompatibilityUpdate(compatUpdate);
+
+ await promiseRestartManager("59");
+
+ addon = await promiseAddonByID(ID);
+ Assert.ok(!addon.isActive, "addon is not active after upgrade");
+ ok(!addon.isCompatible, "compatibility update fixed");
+
+ await promiseRestartManager("58");
+
+ addon = await promiseAddonByID(ID);
+ Assert.ok(addon.isActive, "addon is active after downgrade");
+ ok(addon.isCompatible, "compatibility update fixed");
+
+ await addon.uninstall();
+ await promiseShutdownManager();
+ Services.locale.requestedLocales = originalLocales;
+});