Backed out 3 changesets (bug 1252871) for test_ext_all_apis.html bustage a=backout CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Fri, 28 Oct 2016 14:24:13 -0700
changeset 320068 c2b23c06acfe4086c26e844ffb9bd94e01c6a252
parent 320067 c456c1797299e5dfc39187992e30c323f7d92ee1
child 320069 425c0602ccb486822c4974aa5f7d367597d2b259
push id20749
push userryanvm@gmail.com
push dateSat, 29 Oct 2016 13:21:21 +0000
treeherderfx-team@1b170b39ed6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1252871
milestone52.0a1
backs outb3a08a040c8a870eb9902998d7909918cff32e2a
c2a511511a72010f07159a768a268c53e3090389
9c2c3780aa4c599699b7bc87ef15566cadc8ccf0
Backed out 3 changesets (bug 1252871) for test_ext_all_apis.html bustage a=backout CLOSED TREE Backed out changeset b3a08a040c8a (bug 1252871) Backed out changeset c2a511511a72 (bug 1252871) Backed out changeset 9c2c3780aa4c (bug 1252871)
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionXPCShellUtils.jsm
toolkit/components/extensions/ext-backgroundPage.js
toolkit/components/extensions/ext-runtime.js
toolkit/components/extensions/schemas/runtime.json
toolkit/components/extensions/test/xpcshell/head.js
toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled.js
toolkit/components/extensions/test/xpcshell/xpcshell.ini
toolkit/mozapps/extensions/AddonManager.jsm
toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
toolkit/mozapps/extensions/internal/WebExtensionBootstrap.js
toolkit/mozapps/extensions/test/xpcshell/head_addons.js
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -1210,35 +1210,31 @@ class MockExtension {
   }
 
   cleanupGeneratedFile() {
     flushJarCache(this.file);
     return OS.File.remove(this.file.path);
   }
 }
 
-let _browserUpdated = false;
-
 // We create one instance of this class per extension. |addonData|
 // comes directly from bootstrap.js when initializing.
 this.Extension = class extends ExtensionData {
-  constructor(addonData, startupReason) {
+  constructor(addonData) {
     super(addonData.resourceURI);
 
     this.uuid = UUIDMap.get(addonData.id);
 
     if (addonData.cleanupFile) {
       Services.obs.addObserver(this, "xpcom-shutdown", false);
       this.cleanupFile = addonData.cleanupFile || null;
       delete addonData.cleanupFile;
     }
 
     this.addonData = addonData;
-    this.startupReason = startupReason;
-
     this.id = addonData.id;
     this.baseURI = NetUtil.newURI(this.getURL("")).QueryInterface(Ci.nsIURL);
     this.principal = this.createPrincipal();
 
     this.onStartup = null;
 
     this.hasShutdown = false;
     this.onShutdown = new Set();
@@ -1247,24 +1243,16 @@ this.Extension = class extends Extension
 
     this.apis = [];
     this.whiteListedHosts = null;
     this.webAccessibleResources = null;
 
     this.emitter = new EventEmitter();
   }
 
-  static set browserUpdated(updated) {
-    _browserUpdated = updated;
-  }
-
-  static get browserUpdated() {
-    return _browserUpdated;
-  }
-
   /**
    * This code is designed to make it easy to test a WebExtension
    * without creating a bunch of files. Everything is contained in a
    * single JSON blob.
    *
    * Properties:
    *   "background": "<JS code>"
    *     A script to be loaded as the background script.
--- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
+++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
@@ -15,21 +15,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
                                   "resource://gre/modules/Schemas.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "Management", () => {
-  const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
-  return Management;
-});
-
 /* exported ExtensionTestUtils */
 
 let BASE_MANIFEST = Object.freeze({
   "applications": Object.freeze({
     "gecko": Object.freeze({
       "id": "test@web.ext",
     }),
   }),
@@ -50,69 +45,65 @@ class ExtensionWrapper {
     this.testResolve = null;
     this.testDone = new Promise(resolve => { this.testResolve = resolve; });
 
     this.messageHandler = new Map();
     this.messageAwaiter = new Map();
 
     this.messageQueue = new Set();
 
-    this.attachListeners();
-
     this.testScope.do_register_cleanup(() => {
       if (this.messageQueue.size) {
         let names = Array.from(this.messageQueue, ([msg]) => msg);
         this.testScope.equal(JSON.stringify(names), "[]", "message queue is empty");
       }
       if (this.messageAwaiter.size) {
         let names = Array.from(this.messageAwaiter.keys());
         this.testScope.equal(JSON.stringify(names), "[]", "no tasks awaiting on messages");
       }
     });
 
+    /* eslint-disable mozilla/balanced-listeners */
+    extension.on("test-eq", (kind, pass, msg, expected, actual) => {
+      this.testScope.ok(pass, `${msg} - Expected: ${expected}, Actual: ${actual}`);
+    });
+    extension.on("test-log", (kind, pass, msg) => {
+      this.testScope.do_print(msg);
+    });
+    extension.on("test-result", (kind, pass, msg) => {
+      this.testScope.ok(pass, msg);
+    });
+    extension.on("test-done", (kind, pass, msg, expected, actual) => {
+      this.testScope.ok(pass, msg);
+      this.testResolve(msg);
+    });
+
+    extension.on("test-message", (kind, msg, ...args) => {
+      let handler = this.messageHandler.get(msg);
+      if (handler) {
+        handler(...args);
+      } else {
+        this.messageQueue.add([msg, ...args]);
+        this.checkMessages();
+      }
+    });
+    /* eslint-enable mozilla/balanced-listeners */
+
     this.testScope.do_register_cleanup(() => {
       if (this.state == "pending" || this.state == "running") {
         this.testScope.equal(this.state, "unloaded", "Extension left running at test shutdown");
         return this.unload();
       } else if (extension.state == "unloading") {
         this.testScope.equal(this.state, "unloaded", "Extension not fully unloaded at test shutdown");
       }
     });
 
     this.testScope.do_print(`Extension loaded`);
   }
 
-  attachListeners() {
-    /* eslint-disable mozilla/balanced-listeners */
-    this.extension.on("test-eq", (kind, pass, msg, expected, actual) => {
-      this.testScope.ok(pass, `${msg} - Expected: ${expected}, Actual: ${actual}`);
-    });
-    this.extension.on("test-log", (kind, pass, msg) => {
-      this.testScope.do_print(msg);
-    });
-    this.extension.on("test-result", (kind, pass, msg) => {
-      this.testScope.ok(pass, msg);
-    });
-    this.extension.on("test-done", (kind, pass, msg, expected, actual) => {
-      this.testScope.ok(pass, msg);
-      this.testResolve(msg);
-    });
-
-    this.extension.on("test-message", (kind, msg, ...args) => {
-      let handler = this.messageHandler.get(msg);
-      if (handler) {
-        handler(...args);
-      } else {
-        this.messageQueue.add([msg, ...args]);
-        this.checkMessages();
-      }
-    });
-    /* eslint-enable mozilla/balanced-listeners */
-  }
-
   startup() {
     if (this.state != "uninitialized") {
       throw new Error("Extension already started");
     }
     this.state = "pending";
 
     return this.extension.startup().then(
       result => {
@@ -204,16 +195,18 @@ class ExtensionWrapper {
     this.messageHandler.set(msg, callback);
   }
 }
 
 var ExtensionTestUtils = {
   BASE_MANIFEST,
 
   normalizeManifest: Task.async(function* (manifest, baseManifest = BASE_MANIFEST) {
+    const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
+
     yield Management.lazyInit();
 
     let errors = [];
     let context = {
       url: null,
 
       logError: error => {
         errors.push(error);
--- a/toolkit/components/extensions/ext-backgroundPage.js
+++ b/toolkit/components/extensions/ext-backgroundPage.js
@@ -96,17 +96,21 @@ BackgroundPage.prototype = {
 
     // Set the add-on's main debugger global, for use in the debugger
     // console.
     if (this.extension.addonData.instanceID) {
       AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID)
                   .then(addon => addon.setDebugGlobal(window));
     }
 
-    this.extension.emit("startup");
+    // TODO(robwu): This implementation of onStartup is wrong, see
+    // https://bugzil.la/1247435#c1
+    if (this.extension.onStartup) {
+      this.extension.onStartup();
+    }
   }),
 
   shutdown() {
     if (this.extension.addonData.instanceID) {
       AddonManager.getAddonByInstanceID(this.extension.addonData.instanceID)
                   .then(addon => addon.setDebugGlobal(null));
     }
 
--- a/toolkit/components/extensions/ext-runtime.js
+++ b/toolkit/components/extensions/ext-runtime.js
@@ -3,54 +3,38 @@
 var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Extension",
-                                  "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
                                   "resource://gre/modules/ExtensionManagement.jsm");
 
 var {
+  EventManager,
+  SingletonEventManager,
   ignoreEvent,
-  SingletonEventManager,
 } = ExtensionUtils;
 
 extensions.registerSchemaAPI("runtime", "addon_parent", context => {
   let {extension} = context;
   return {
     runtime: {
-      onStartup: ignoreEvent(context, "runtime.onStartup"),
-
-      onInstalled: new SingletonEventManager(context, "runtime.onInstalled", fire => {
-        let listener = () => {
-          switch (extension.startupReason) {
-            case "APP_STARTUP":
-              if (Extension.browserUpdated) {
-                fire({reason: "browser_update"});
-              }
-              break;
-            case "ADDON_INSTALL":
-              fire({reason: "install"});
-              break;
-            case "ADDON_UPGRADE":
-              fire({reason: "update"});
-              break;
-          }
-        };
-        extension.on("startup", listener);
+      onStartup: new EventManager(context, "runtime.onStartup", fire => {
+        extension.onStartup = fire;
         return () => {
-          extension.off("startup", listener);
+          extension.onStartup = null;
         };
       }).api(),
 
+      onInstalled: ignoreEvent(context, "runtime.onInstalled"),
+
       onUpdateAvailable: new SingletonEventManager(context, "runtime.onUpdateAvailable", fire => {
         let instanceID = extension.addonData.instanceID;
         AddonManager.addUpgradeListener(instanceID, upgrade => {
           extension.upgrade = upgrade;
           let details = {
             version: upgrade.version,
           };
           context.runSafe(fire, details);
--- a/toolkit/components/extensions/schemas/runtime.json
+++ b/toolkit/components/extensions/schemas/runtime.json
@@ -117,17 +117,17 @@
         "type": "string",
         "enum": ["throttled", "no_update", "update_available"],
         "allowedContexts": ["content"],
         "description": "Result of the update check."
       },
       {
         "id": "OnInstalledReason",
         "type": "string",
-        "enum": ["install", "update", "browser_update"],
+        "enum": ["install", "update", "chrome_update", "shared_module_update"],
         "allowedContexts": ["content"],
         "description": "The reason that this event is being dispatched."
       },
       {
         "id": "OnRestartRequiredReason",
         "type": "string",
         "allowedContexts": ["content"],
         "description": "The reason that the event is being dispatched. 'app_update' is used when the restart is needed because the application is updated to a newer version. 'os_update' is used when the restart is needed because the browser/OS is updated to a newer version. 'periodic' is used when the system runs for more than the permitted uptime set in the enterprise policy.",
@@ -454,37 +454,36 @@
       {
         "name": "onStartup",
         "unsupported": true,
         "type": "function",
         "description": "Fired when a profile that has this extension installed first starts up. This event is not fired when an incognito profile is started, even if this extension is operating in 'split' incognito mode."
       },
       {
         "name": "onInstalled",
+        "unsupported": true,
         "type": "function",
         "description": "Fired when the extension is first installed, when the extension is updated to a new version, and when the browser is updated to a new version.",
         "parameters": [
           {
             "type": "object",
             "name": "details",
             "properties": {
               "reason": {
                 "$ref": "OnInstalledReason",
                 "description": "The reason that this event is being dispatched."
               },
               "previousVersion": {
                 "type": "string",
                 "optional": true,
-                "unsupported": true,
                 "description": "Indicates the previous version of the extension, which has just been updated. This is present only if 'reason' is 'update'."
               },
               "id": {
                 "type": "string",
                 "optional": true,
-                "unsupported": true,
                 "description": "Indicates the ID of the imported shared module extension which updated. This is present only if 'reason' is 'shared_module_update'."
               }
             }
           }
         ]
       },
       {
         "name": "onSuspend",
--- a/toolkit/components/extensions/test/xpcshell/head.js
+++ b/toolkit/components/extensions/test/xpcshell/head.js
@@ -2,17 +2,16 @@
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 /* exported createHttpServer, promiseConsoleOutput, cleanupDir */
 
 Components.utils.import("resource://gre/modules/Task.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Timer.jsm");
-Components.utils.import("resource://testing-common/AddonTestUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Extension",
                                   "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData",
                                   "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
deleted file mode 100644
--- a/toolkit/components/extensions/test/xpcshell/test_ext_runtime_onInstalled.js
+++ /dev/null
@@ -1,324 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-XPCOMUtils.defineLazyGetter(this, "Management", () => {
-  const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
-  return Management;
-});
-
-const {
-  createAppInfo,
-  createTempWebExtensionFile,
-  promiseAddonByID,
-  promiseAddonEvent,
-  promiseCompleteAllInstalls,
-  promiseFindAddonUpdates,
-  promiseRestartManager,
-  promiseShutdownManager,
-  promiseStartupManager,
-} = AddonTestUtils;
-
-AddonTestUtils.init(this);
-
-// Allow for unsigned addons.
-AddonTestUtils.overrideCertDB();
-
-createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
-
-function awaitEvent(eventName) {
-  return new Promise(resolve => {
-    let listener = (_eventName, extension) => {
-      if (_eventName === eventName) {
-        Management.off(eventName, listener);
-        resolve(extension);
-      }
-    };
-
-    Management.on(eventName, listener);
-  });
-}
-
-add_task(function* test_should_fire_on_addon_update() {
-  const EXTENSION_ID = "test_runtime_on_installed_addon_update@tests.mozilla.org";
-
-  const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity";
-
-  // The test extension uses an insecure update url.
-  Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
-
-  const testServer = createHttpServer();
-  const port = testServer.identity.primaryPort;
-
-  let extension = ExtensionTestUtils.loadExtension({
-    useAddonManager: "permanent",
-    manifest: {
-      "version": "1.0",
-      "applications": {
-        "gecko": {
-          "id": EXTENSION_ID,
-          "update_url": `http://localhost:${port}/test_update.json`,
-        },
-      },
-    },
-    background() {
-      browser.runtime.onUpdateAvailable.addListener(details => {
-        browser.test.sendMessage("reloading");
-        browser.runtime.reload();
-      });
-
-      browser.runtime.onInstalled.addListener(details => {
-        browser.test.sendMessage("installed", details);
-      });
-    },
-  });
-
-  testServer.registerPathHandler("/test_update.json", (request, response) => {
-    response.write(`{
-      "addons": {
-        "${EXTENSION_ID}": {
-          "updates": [
-            {
-              "version": "2.0",
-              "update_link": "http://localhost:${port}/addons/test_runtime_on_installed-2.0.xpi"
-            }
-          ]
-        }
-      }
-    }`);
-  });
-
-  let webExtensionFile = createTempWebExtensionFile({
-    manifest: {
-      version: "2.0",
-      applications: {
-        gecko: {
-          id: EXTENSION_ID,
-        },
-      },
-    },
-    background() {
-      browser.runtime.onInstalled.addListener(details => {
-        browser.test.sendMessage("installed", details);
-      });
-    },
-  });
-
-  testServer.registerFile("/addons/test_runtime_on_installed-2.0.xpi", webExtensionFile);
-
-  yield promiseStartupManager();
-
-  yield extension.startup();
-  let details = yield extension.awaitMessage("installed");
-  equal(details.reason, "install", "runtime.onInstalled fired with the correct reason");
-
-  let addon = yield promiseAddonByID(EXTENSION_ID);
-  equal(addon.version, "1.0", "The installed addon has the correct version");
-
-  let update = yield promiseFindAddonUpdates(addon);
-  let install = update.updateAvailable;
-
-  let promiseInstalled = promiseAddonEvent("onInstalled");
-  yield promiseCompleteAllInstalls([install]);
-
-  yield extension.awaitMessage("reloading");
-
-  let startupPromise = awaitEvent("ready");
-
-  let [updated_addon] = yield promiseInstalled;
-  equal(updated_addon.version, "2.0", "The updated addon has the correct version");
-
-  extension.extension = yield startupPromise;
-  extension.attachListeners();
-
-  details = yield extension.awaitMessage("installed");
-  equal(details.reason, "update", "runtime.onInstalled fired with the correct reason");
-
-  yield extension.unload();
-
-  yield updated_addon.uninstall();
-  yield promiseShutdownManager();
-});
-
-add_task(function* test_should_fire_on_browser_update() {
-  const EXTENSION_ID = "test_runtime_on_installed_browser_update@tests.mozilla.org";
-
-  yield promiseStartupManager();
-
-  let extension = ExtensionTestUtils.loadExtension({
-    useAddonManager: "permanent",
-    manifest: {
-      "version": "1.0",
-      "applications": {
-        "gecko": {
-          "id": EXTENSION_ID,
-        },
-      },
-    },
-    background() {
-      let onInstalledDetails = null;
-
-      browser.runtime.onInstalled.addListener(details => {
-        onInstalledDetails = details;
-      });
-
-      browser.test.onMessage.addListener(message => {
-        if (message == "get-on-installed-details") {
-          browser.test.sendMessage("on-installed-details", onInstalledDetails);
-        }
-      });
-    },
-  });
-
-  yield extension.startup();
-
-  extension.sendMessage("get-on-installed-details");
-  let details = yield extension.awaitMessage("on-installed-details");
-  equal(details.reason, "install", "runtime.onInstalled fired with the correct reason");
-
-  let startupPromise = awaitEvent("ready");
-  yield promiseRestartManager("1");
-  extension.extension = yield startupPromise;
-  extension.attachListeners();
-
-  extension.sendMessage("get-on-installed-details");
-  details = yield extension.awaitMessage("on-installed-details");
-  equal(details, null, "runtime.onInstalled should not have fired");
-
-  // Update the browser.
-  startupPromise = awaitEvent("ready");
-  yield promiseRestartManager("2");
-  extension.extension = yield startupPromise;
-  extension.attachListeners();
-
-  extension.sendMessage("get-on-installed-details");
-  details = yield extension.awaitMessage("on-installed-details");
-  equal(details.reason, "browser_update", "runtime.onInstalled fired with the correct reason");
-
-  // Restart the browser.
-  startupPromise = awaitEvent("ready");
-  yield promiseRestartManager("2");
-  extension.extension = yield startupPromise;
-  extension.attachListeners();
-
-  extension.sendMessage("get-on-installed-details");
-  details = yield extension.awaitMessage("on-installed-details");
-  equal(details, null, "runtime.onInstalled should not have fired");
-
-  // Update the browser again.
-  startupPromise = awaitEvent("ready");
-  yield promiseRestartManager("3");
-  extension.extension = yield startupPromise;
-  extension.attachListeners();
-
-  extension.sendMessage("get-on-installed-details");
-  details = yield extension.awaitMessage("on-installed-details");
-  equal(details.reason, "browser_update", "runtime.onInstalled fired with the correct reason");
-
-  yield extension.unload();
-
-  yield promiseShutdownManager();
-});
-
-add_task(function* test_should_not_fire_on_reload() {
-  const EXTENSION_ID = "test_runtime_on_installed_reload@tests.mozilla.org";
-
-  yield promiseStartupManager();
-
-  let extension = ExtensionTestUtils.loadExtension({
-    useAddonManager: "permanent",
-    manifest: {
-      "version": "1.0",
-      "applications": {
-        "gecko": {
-          "id": EXTENSION_ID,
-        },
-      },
-    },
-    background() {
-      let onInstalledDetails = null;
-
-      browser.runtime.onInstalled.addListener(details => {
-        onInstalledDetails = details;
-      });
-
-      browser.test.onMessage.addListener(message => {
-        if (message == "reload-extension") {
-          browser.runtime.reload();
-        } else if (message == "get-on-installed-details") {
-          browser.test.sendMessage("on-installed-details", onInstalledDetails);
-        }
-      });
-    },
-  });
-
-  yield extension.startup();
-
-  extension.sendMessage("get-on-installed-details");
-  let details = yield extension.awaitMessage("on-installed-details");
-  equal(details.reason, "install", "runtime.onInstalled fired with the correct reason");
-
-  let startupPromise = awaitEvent("ready");
-  extension.sendMessage("reload-extension");
-  extension.extension = yield startupPromise;
-  extension.attachListeners();
-
-  extension.sendMessage("get-on-installed-details");
-  details = yield extension.awaitMessage("on-installed-details");
-  equal(details, null, "runtime.onInstalled should not have fired");
-
-  yield extension.unload();
-  yield promiseShutdownManager();
-});
-
-add_task(function* test_should_not_fire_on_restart() {
-  const EXTENSION_ID = "test_runtime_on_installed_restart@tests.mozilla.org";
-
-  yield promiseStartupManager();
-
-  let extension = ExtensionTestUtils.loadExtension({
-    useAddonManager: "permanent",
-    manifest: {
-      "version": "1.0",
-      "applications": {
-        "gecko": {
-          "id": EXTENSION_ID,
-        },
-      },
-    },
-    background() {
-      let onInstalledDetails = null;
-
-      browser.runtime.onInstalled.addListener(details => {
-        onInstalledDetails = details;
-      });
-
-      browser.test.onMessage.addListener(message => {
-        if (message == "get-on-installed-details") {
-          browser.test.sendMessage("on-installed-details", onInstalledDetails);
-        }
-      });
-    },
-  });
-
-  yield extension.startup();
-
-  extension.sendMessage("get-on-installed-details");
-  let details = yield extension.awaitMessage("on-installed-details");
-  equal(details.reason, "install", "runtime.onInstalled fired with the correct reason");
-
-  let addon = yield promiseAddonByID(EXTENSION_ID);
-  addon.userDisabled = true;
-
-  let startupPromise = awaitEvent("ready");
-  addon.userDisabled = false;
-  extension.extension = yield startupPromise;
-  extension.attachListeners();
-
-  extension.sendMessage("get-on-installed-details");
-  details = yield extension.awaitMessage("on-installed-details");
-  equal(details, null, "runtime.onInstalled should not have fired");
-
-  yield extension.markUnloaded();
-  yield promiseShutdownManager();
-});
--- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini
@@ -41,17 +41,16 @@ skip-if = release_or_beta
 [test_ext_management_uninstall_self.js]
 [test_ext_manifest_content_security_policy.js]
 [test_ext_manifest_incognito.js]
 [test_ext_manifest_minimum_chrome_version.js]
 [test_ext_onmessage_removelistener.js]
 [test_ext_runtime_connect_no_receiver.js]
 [test_ext_runtime_getBrowserInfo.js]
 [test_ext_runtime_getPlatformInfo.js]
-[test_ext_runtime_onInstalled.js]
 [test_ext_runtime_sendMessage.js]
 [test_ext_runtime_sendMessage_errors.js]
 [test_ext_runtime_sendMessage_no_receiver.js]
 [test_ext_runtime_sendMessage_self.js]
 [test_ext_schemas.js]
 [test_ext_schemas_api_injection.js]
 [test_ext_schemas_async.js]
 [test_ext_schemas_allowed_contexts.js]
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -80,18 +80,16 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/AsyncShutdown.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
                                   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
                                   "resource://gre/modules/addons/AddonRepository.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Extension",
-                                  "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "CertUtils", function() {
   let certUtils = {};
   Components.utils.import("resource://gre/modules/CertUtils.jsm", certUtils);
   return certUtils;
 });
@@ -847,18 +845,16 @@ var AddonManagerInternal = {
 
       let oldAppVersion = null;
       try {
         oldAppVersion = Services.prefs.getCharPref(PREF_EM_LAST_APP_VERSION);
         appChanged = Services.appinfo.version != oldAppVersion;
       }
       catch (e) { }
 
-      Extension.browserUpdated = appChanged;
-
       let oldPlatformVersion = null;
       try {
         oldPlatformVersion = Services.prefs.getCharPref(PREF_EM_LAST_PLATFORM_VERSION);
       }
       catch (e) { }
 
       if (appChanged !== false) {
         logger.debug("Application has been upgraded");
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -1083,75 +1083,16 @@ var AddonTestUtils = {
    * @return {Promise<Addon>}
    *        Resolves to the add-on with the given ID.
    */
   promiseAddonByID(id) {
     return new Promise(resolve => AddonManager.getAddonByID(id, resolve));
   },
 
   /**
-   * Returns a promise that will be resolved when an add-on update check is
-   * complete. The value resolved will be an AddonInstall if a new version was
-   * found.
-   *
-   * @param {object} addon The add-on to find updates for.
-   * @param {integer} reason The type of update to find.
-   * @return {Promise<object>} an object containing information about the update.
-   */
-  promiseFindAddonUpdates(addon, reason = AddonManager.UPDATE_WHEN_PERIODIC_UPDATE) {
-    let equal = this.testScope.equal;
-    return new Promise((resolve, reject) => {
-      let result = {};
-      addon.findUpdates({
-        onNoCompatibilityUpdateAvailable: function(addon2) {
-          if ("compatibilityUpdate" in result) {
-            throw new Error("Saw multiple compatibility update events");
-          }
-          equal(addon, addon2, "onNoCompatibilityUpdateAvailable");
-          result.compatibilityUpdate = false;
-        },
-
-        onCompatibilityUpdateAvailable: function(addon2) {
-          if ("compatibilityUpdate" in result) {
-            throw new Error("Saw multiple compatibility update events");
-          }
-          equal(addon, addon2, "onCompatibilityUpdateAvailable");
-          result.compatibilityUpdate = true;
-        },
-
-        onNoUpdateAvailable: function(addon2) {
-          if ("updateAvailable" in result) {
-            throw new Error("Saw multiple update available events");
-          }
-          equal(addon, addon2, "onNoUpdateAvailable");
-          result.updateAvailable = false;
-        },
-
-        onUpdateAvailable: function(addon2, install) {
-          if ("updateAvailable" in result) {
-            throw new Error("Saw multiple update available events");
-          }
-          equal(addon, addon2, "onUpdateAvailable");
-          result.updateAvailable = install;
-        },
-
-        onUpdateFinished: function(addon2, error) {
-          equal(addon, addon2, "onUpdateFinished");
-          if (error == AddonManager.UPDATE_STATUS_NO_ERROR) {
-            resolve(result);
-          } else {
-            result.error = error;
-            reject(result);
-          }
-        }
-      }, reason);
-    });
-  },
-
-  /**
    * A promise-based variant of AddonManager.getAddonsWithOperationsByTypes
    *
    * @param {Array<string>} types
    *        The first argument to AddonManager.getAddonsWithOperationsByTypes
    * @return {Promise<Array<Addon>>}
    *        Resolves to an array of add-ons with the given operations
    *        pending.
    */
--- a/toolkit/mozapps/extensions/internal/WebExtensionBootstrap.js
+++ b/toolkit/mozapps/extensions/internal/WebExtensionBootstrap.js
@@ -3,34 +3,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 Components.utils.import("resource://gre/modules/Extension.jsm");
 
 var extension;
 
-const BOOTSTRAP_REASON_TO_STRING_MAP = {
-  1: "APP_STARTUP",
-  2: "APP_SHUTDOWN",
-  3: "ADDON_ENABLE",
-  4: "ADDON_DISABLE",
-  5: "ADDON_INSTALL",
-  6: "ADDON_UNINSTALL",
-  7: "ADDON_UPGRADE",
-  8: "ADDON_DOWNGRADE",
-}
-
 function install(data, reason)
 {
 }
 
 function startup(data, reason)
 {
-  extension = new Extension(data, BOOTSTRAP_REASON_TO_STRING_MAP[reason]);
+  extension = new Extension(data);
   extension.startup();
 }
 
 function shutdown(data, reason)
 {
   extension.shutdown();
 }
 
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -51,44 +51,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://testing-common/httpd.js");
 XPCOMUtils.defineLazyModuleGetter(this, "MockAsyncShutdown",
                                   "resource://testing-common/AddonTestUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MockRegistrar",
                                   "resource://testing-common/MockRegistrar.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MockRegistry",
                                   "resource://testing-common/MockRegistry.jsm");
 
-const {
-  awaitPromise,
-  createAppInfo,
-  createInstallRDF,
-  createTempWebExtensionFile,
-  createUpdateRDF,
-  getFileForAddon,
-  manuallyInstall,
-  manuallyUninstall,
-  promiseAddonByID,
-  promiseAddonEvent,
-  promiseAddonsByIDs,
-  promiseAddonsWithOperationsByTypes,
-  promiseCompleteAllInstalls,
-  promiseConsoleOutput,
-  promiseFindAddonUpdates,
-  promiseInstallAllFiles,
-  promiseInstallFile,
-  promiseRestartManager,
-  promiseSetExtensionModifiedTime,
-  promiseShutdownManager,
-  promiseStartupManager,
-  promiseWriteProxyFileToDir,
-  registerDirectory,
-  setExtensionModifiedTime,
-  writeFilesToZip
-} = AddonTestUtils;
-
 // WebExtension wrapper for ease of testing
 ExtensionTestUtils.init(this);
 
 AddonTestUtils.init(this);
 AddonTestUtils.overrideCertDB();
 
 Object.defineProperty(this, "gAppInfo", {
   get() {
@@ -339,16 +311,18 @@ function isNightlyChannel() {
   try {
     channel = Services.prefs.getCharPref("app.update.channel");
   }
   catch (e) { }
 
   return channel != "aurora" && channel != "beta" && channel != "release" && channel != "esr";
 }
 
+var {createAppInfo} = AddonTestUtils;
+
 /**
  * Tests that an add-on does appear in the crash report annotations, if
  * crash reporting is enabled. The test will fail if the add-on is not in the
  * annotation.
  * @param  aId
  *         The ID of the add-on
  * @param  aVersion
  *         The version of the add-on
@@ -597,16 +571,21 @@ function do_check_compatibilityoverride(
 }
 
 function do_check_icons(aActual, aExpected) {
   for (var size in aExpected) {
     do_check_eq(remove_port(aActual[size]), remove_port(aExpected[size]));
   }
 }
 
+var {promiseStartupManager} = AddonTestUtils;
+var {promiseRestartManager} = AddonTestUtils;
+var {promiseShutdownManager} = AddonTestUtils;
+var {awaitPromise} = AddonTestUtils;
+
 function startupManager(aAppChanged) {
   promiseStartupManager(aAppChanged);
 }
 
 /**
  * Restarts the add-on manager as if the host application was restarted.
  *
  * @param  aNewVersion
@@ -639,16 +618,19 @@ function check_startup_changes(aType, aI
   ids.sort();
   var changes = AddonManager.getStartupChanges(aType);
   changes = changes.filter(aEl => /@tests.mozilla.org$/.test(aEl));
   changes.sort();
 
   do_check_eq(JSON.stringify(ids), JSON.stringify(changes));
 }
 
+var {createUpdateRDF} = AddonTestUtils;
+var {createInstallRDF} = AddonTestUtils;
+
 /**
  * Writes an install.rdf manifest into a directory using the properties passed
  * in a JS object. The objects should contain a property for each property to
  * appear in the RDF. The object may contain an array of objects with id,
  * minVersion and maxVersion in the targetApplications property to give target
  * application compatibility.
  *
  * @param   aData
@@ -748,16 +730,18 @@ function writeInstallRDFForExtension(aDa
  */
 function promiseWriteWebManifestForExtension(aData, aDir, aId = aData.applications.gecko.id) {
   let files = {
     "manifest.json": JSON.stringify(aData),
   }
   return AddonTestUtils.promiseWriteFilesToExtension(aDir.path, aId, files);
 }
 
+var {writeFilesToZip} = AddonTestUtils;
+
 /**
  * Creates an XPI file for some manifest data in the temporary directory and
  * returns the nsIFile for it. The file will be deleted when the test completes.
  *
  * @param   aData
  *          The object holding data about the add-on
  * @return  A file pointing to the created XPI file
  */
@@ -768,16 +752,28 @@ function createTempXPIFile(aData, aExtra
   if (typeof aExtraFile == "object")
     Object.assign(files, aExtraFile);
   else if (aExtraFile)
     files[aExtraFile] = "";
 
   return AddonTestUtils.createTempXPIFile(files);
 }
 
+var {createTempWebExtensionFile} = AddonTestUtils;
+
+var {setExtensionModifiedTime} = AddonTestUtils;
+var {promiseSetExtensionModifiedTime} = AddonTestUtils;
+
+var {manuallyInstall} = AddonTestUtils;
+var {manuallyUninstall} = AddonTestUtils;
+
+var {getFileForAddon} = AddonTestUtils;
+
+var {registerDirectory} = AddonTestUtils;
+
 var gExpectedEvents = {};
 var gExpectedInstalls = [];
 var gNext = null;
 
 function getExpectedEvent(aId) {
   if (!(aId in gExpectedEvents))
     do_throw("Wasn't expecting events for " + aId);
   if (gExpectedEvents[aId].length == 0)
@@ -1018,29 +1014,35 @@ function ensure_test_completed() {
     if (gExpectedEvents[i].length > 0)
       do_throw("Didn't see all the expected events for " + i);
   }
   gExpectedEvents = {};
   if (gExpectedInstalls)
     do_check_eq(gExpectedInstalls.length, 0);
 }
 
+var {promiseAddonEvent} = AddonTestUtils;
+
+var {promiseCompleteAllInstalls} = AddonTestUtils;
+
 /**
  * A helper method to install an array of AddonInstall to completion and then
  * call a provided callback.
  *
  * @param   aInstalls
  *          The array of AddonInstalls to install
  * @param   aCallback
  *          The callback to call when all installs have finished
  */
 function completeAllInstalls(aInstalls, aCallback) {
   promiseCompleteAllInstalls(aInstalls).then(aCallback);
 }
 
+var {promiseInstallFile, promiseInstallAllFiles} = AddonTestUtils;
+
 /**
  * A helper method to install an array of files and call a callback after the
  * installs are completed.
  *
  * @param   aFiles
  *          The array of files to install
  * @param   aCallback
  *          The callback to call when all installs have finished
@@ -1267,15 +1269,79 @@ function saveJSON(aData, aFile) {
 function callback_soon(aFunction) {
   return function(...args) {
     do_execute_soon(function() {
       aFunction.apply(null, args);
     }, aFunction.name ? "delayed callback " + aFunction.name : "delayed callback");
   }
 }
 
+var {promiseAddonsByIDs} = AddonTestUtils;
+
+var {promiseAddonByID} = AddonTestUtils;
+
+var {promiseAddonsWithOperationsByTypes} = AddonTestUtils;
+
+/**
+ * Returns a promise that will be resolved when an add-on update check is
+ * complete. The value resolved will be an AddonInstall if a new version was
+ * found.
+ */
+function promiseFindAddonUpdates(addon, reason = AddonManager.UPDATE_WHEN_PERIODIC_UPDATE) {
+  return new Promise((resolve, reject) => {
+    let result = {};
+    addon.findUpdates({
+      onNoCompatibilityUpdateAvailable: function(addon2) {
+        if ("compatibilityUpdate" in result) {
+          do_throw("Saw multiple compatibility update events");
+        }
+        equal(addon, addon2, "onNoCompatibilityUpdateAvailable");
+        result.compatibilityUpdate = false;
+      },
+
+      onCompatibilityUpdateAvailable: function(addon2) {
+        if ("compatibilityUpdate" in result) {
+          do_throw("Saw multiple compatibility update events");
+        }
+        equal(addon, addon2, "onCompatibilityUpdateAvailable");
+        result.compatibilityUpdate = true;
+      },
+
+      onNoUpdateAvailable: function(addon2) {
+        if ("updateAvailable" in result) {
+          do_throw("Saw multiple update available events");
+        }
+        equal(addon, addon2, "onNoUpdateAvailable");
+        result.updateAvailable = false;
+      },
+
+      onUpdateAvailable: function(addon2, install) {
+        if ("updateAvailable" in result) {
+          do_throw("Saw multiple update available events");
+        }
+        equal(addon, addon2, "onUpdateAvailable");
+        result.updateAvailable = install;
+      },
+
+      onUpdateFinished: function(addon2, error) {
+        equal(addon, addon2, "onUpdateFinished");
+        if (error == AddonManager.UPDATE_STATUS_NO_ERROR) {
+          resolve(result);
+        } else {
+          result.error = error;
+          reject(result);
+        }
+      }
+    }, reason);
+  });
+}
+
+var {promiseConsoleOutput} = AddonTestUtils;
+
+var {promiseWriteProxyFileToDir} = AddonTestUtils;
+
 function writeProxyFileToDir(aDir, aAddon, aId) {
   awaitPromise(promiseWriteProxyFileToDir(aDir, aAddon, aId));
 
   let file = aDir.clone();
   file.append(aId);
   return file
 }