Bug 1261522 - Support reloading an add-on. r=Mossop
authorKumar McMillan <kumar.mcmillan@gmail.com>
Fri, 08 Apr 2016 10:13:50 -0500
changeset 316407 b98d8b88dfc702363e8974a230b590ce79bc920d
parent 316406 f8094c2a425476288246f9fbdfdf8240af1c4660
child 316408 88a5069742fee445e11923ad865f8a9bf88a25eb
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
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/addons/test_bug1261522_app_disabled/install.rdf
toolkit/mozapps/extensions/test/xpcshell/test_reload.js
toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -7288,16 +7288,38 @@ AddonWrapper.prototype = {
       addon._hasResourceCache.set(aPath, false);
       return false;
     }
     finally {
       zipReader.close();
     }
   },
 
+  reload: function() {
+    return new Promise(resolve => {
+      if (this.appDisabled) {
+        throw new Error(
+          "cannot reload add-on because it is disabled by the application");
+      }
+
+      const addon = addonFor(this);
+      const isReloadable = (!XPIProvider.enableRequiresRestart(addon) &&
+                            !XPIProvider.disableRequiresRestart(addon));
+      if (!isReloadable) {
+        throw new Error(
+          "cannot reload add-on because it requires a browser restart");
+      }
+
+      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/addons/test_bug1261522_app_disabled/install.rdf
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>bug1261522-app-disabled@tests.mozilla.org</em:id>
+    <em:version>1.0</em:version>
+
+    <em:targetApplication>
+      <Description>
+        <em:minVersion>1</em:minVersion>
+        <em:maxVersion>2</em:maxVersion>
+        <em:strictCompatibility>true</em:strictCompatibility>
+      </Description>
+    </em:targetApplication>
+
+    <em:name>An add-on that will be app-disabled when installed</em:name>
+
+  </Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_reload.js
@@ -0,0 +1,74 @@
+/* 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_cannot_reload_addon_requiring_restart() {
+  // This is 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,
+    "cannot reload add-on because it requires a browser restart");
+
+  tearDownAddon(addon);
+});
+
+add_task(function* test_cannot_reload_app_disabled_addon() {
+  // This add-on will be app disabled immediately.
+  const addon = yield getTestAddon(
+    "test_bug1261522_app_disabled",
+    "bug1261522-app-disabled@tests.mozilla.org");
+  do_check_eq(addon.appDisabled, true);
+
+  let caughtError = null;
+  try {
+    yield addon.reload();
+  } catch (error) {
+    caughtError = error;
+  }
+
+  do_check_eq(
+    caughtError && caughtError.message,
+    "cannot reload add-on because it is disabled by the application");
+
+  tearDownAddon(addon);
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
@@ -1,14 +1,15 @@
 # The file is shared between the two main xpcshell manifest files.
 [DEFAULT]
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 tags = addons
 
 [test_AddonRepository.js]
+[test_reload.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 [test_AddonRepository_cache.js]
 # Bug 676992: test consistently hangs on Android
 # Bug 1026805: frequent hangs on OSX 10.8
 skip-if = os == "android" || os == "mac"
 run-sequentially = Uses hardcoded ports in xpi files.
 [test_AddonRepository_compatmode.js]
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -31,9 +31,10 @@ skip-if = appname != "firefox"
 [test_system_reset.js]
 [test_XPIcancel.js]
 [test_XPIStates.js]
 [test_temporary.js]
 [test_proxies.js]
 [test_proxy.js]
 [test_pass_symbol.js]
 
+
 [include:xpcshell-shared.ini]