Bug 1261522 - Support reloading an add-on. r?Mossop draft
authorKumar McMillan <kumar.mcmillan@gmail.com>
Tue, 05 Apr 2016 15:11:56 -0500
changeset 347791 6589ade8cbaef38baa28fabe48ec027aaec2be93
parent 346007 e14db462d31d566570e3bece66d5380f7b1ad400
child 347792 7f68c50e3676222a29cc9fee37f244b2d6ca0cdf
push id14658
push userbmo:kumar.mcmillan@gmail.com
push dateTue, 05 Apr 2016 20:13:07 +0000
reviewersMossop
bugs1261522
milestone48.0a1
Bug 1261522 - Support reloading an add-on. r?Mossop MozReview-Commit-ID: W8z1J4QzjE
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/test/xpcshell/test_isReloadable.js
toolkit/mozapps/extensions/test/xpcshell/test_reload.js
toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -7269,16 +7269,34 @@ AddonWrapper.prototype = {
       addon._hasResourceCache.set(aPath, false);
       return false;
     }
     finally {
       zipReader.close();
     }
   },
 
+  get isReloadable() {
+    let addon = addonFor(this);
+    return (!XPIProvider.enableRequiresRestart(addon) &&
+            !XPIProvider.disableRequiresRestart(addon));
+  },
+
+  reload: function() {
+    return new Promise(resolve => {
+      if (!this.isReloadable) {
+        throw new Error("this add-on cannot be reloaded");
+      }
+      this.userDisabled = true;
+      flushStartupCache();
+      this.userDisabled = false;
+      resolve();
+    });
+  },
+
   /**
    * Returns a URI to the selected resource or to the add-on bundle if aPath
    * is null. URIs to the bundle will always be file: URIs. URIs to resources
    * will be file: URIs if the add-on is unpacked or jar: URIs if the add-on is
    * still an XPI file.
    *
    * @param  aPath
    *         The path in the add-on to get the URI for or null to get a URI to
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_isReloadable.js
@@ -0,0 +1,41 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "2");
+startupManager();
+
+function* getAllTestAddons() {
+  yield promiseInstallAllFiles([
+    "test_install1", // plain old install.rdf
+    "test_jetpack",
+    "webextension_1"
+  ].map(do_get_addon));
+
+  restartManager();
+
+  return promiseAddonsByIDs([
+    "addon1@tests.mozilla.org",
+    "jetpack@tests.mozilla.org",
+    "webextension1@tests.mozilla.org"
+  ]);
+}
+
+function* tearDownAddons(addons) {
+  for (const addon of addons) {
+    addon.uninstall();
+  }
+  yield promiseShutdownManager();
+}
+
+add_task(function* test_reloadable_addons() {
+  const addons = yield getAllTestAddons();
+  const [oldInstallRDF, jetpack, webExt] = addons;
+
+  do_check_eq(oldInstallRDF.isReloadable, false);
+  do_check_eq(jetpack.isReloadable, true);
+  do_check_eq(webExt.isReloadable, true);
+
+  tearDownAddons(addons);
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_reload.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
+startupManager();
+
+function* getTestAddon(fixtureName, addonID) {
+  yield promiseInstallAllFiles([do_get_addon(fixtureName)]);
+  restartManager();
+  return promiseAddonByID(addonID);
+}
+
+function* tearDownAddon(addon) {
+  addon.uninstall();
+  yield promiseShutdownManager();
+}
+
+add_task(function* test_reloading_an_addon() {
+  const addonId = "webextension1@tests.mozilla.org";
+  const addon = yield getTestAddon("webextension_1", addonId);
+
+  const onDisabled = promiseAddonEvent("onDisabled");
+  const onEnabled = promiseAddonEvent("onEnabled");
+
+  yield addon.reload();
+
+  const [disabledAddon] = yield onDisabled;
+  do_check_eq(disabledAddon.id, addonId);
+
+  const [enabledAddon] = yield onEnabled;
+  do_check_eq(enabledAddon.id, addonId);
+
+  tearDownAddon(addon);
+});
+
+add_task(function* test_addon_that_cannot_be_reloaded() {
+  // Try reloading a plain install.rdf add-on without a bootstrap script.
+  const addon = yield getTestAddon("test_install1", "addon1@tests.mozilla.org");
+
+  let caughtError = null;
+  try {
+    yield addon.reload();
+  } catch (error) {
+    caughtError = error;
+  }
+
+  do_check_eq(caughtError && caughtError.message,
+              "this add-on cannot be reloaded");
+
+  tearDownAddon(addon);
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -12,25 +12,27 @@ support-files =
 [test_addon_path_service.js]
 [test_asyncBlocklistLoad.js]
 [test_cache_certdb.js]
 run-if = addon_signing
 [test_cacheflush.js]
 [test_DeferredSave.js]
 [test_gmpProvider.js]
 skip-if = appname != "firefox"
+[test_isReloadable.js]
 [test_hotfix_cert.js]
 [test_isReady.js]
 [test_metadata_update.js]
 [test_pluginInfoURL.js]
 [test_provider_markSafe.js]
 [test_provider_shutdown.js]
 [test_provider_unsafe_access_shutdown.js]
 [test_provider_unsafe_access_startup.js]
 [test_ProductAddonChecker.js]
+[test_reload.js]
 [test_shutdown.js]
 [test_system_update.js]
 [test_system_reset.js]
 [test_XPIcancel.js]
 [test_XPIStates.js]
 [test_temporary.js]
 [test_proxies.js]
 [test_proxy.js]