Bug 1451532 Remove unneeded bootstrapped extensions in addon manager xpcshell tests r=kmag
authorAndrew Swan <aswan@mozilla.com>
Sun, 18 Nov 2018 16:35:51 -0800
changeset 503586 c1d4918380adbf58e0fb231fb8de6940fce5f7c3
parent 503585 77e400a477280361e26b3b2d2c72416e0861eb95
child 503587 edff28b27f207b3d6e592b131bd0f7bf94da9982
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1451532
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1451532 Remove unneeded bootstrapped extensions in addon manager xpcshell tests r=kmag In most case this involves switching to webextensions. Some old or redundant tests are removed, other tets are cleaned up and modernized along the way.
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionTestCommon.jsm
toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.json
toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/hotfix_badid.xpi
toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/hotfix_broken.xpi
toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/hotfix_good.xpi
toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_metadata_filters_1.xml
toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_regexp_1.xml
toolkit/mozapps/extensions/test/xpcshell/data/test_dictionary.json
toolkit/mozapps/extensions/test/xpcshell/head_addons.js
toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository.js
toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js
toolkit/mozapps/extensions/test/xpcshell/test_XPIStates.js
toolkit/mozapps/extensions/test/xpcshell/test_backgroundupdate.js
toolkit/mozapps/extensions/test/xpcshell/test_bad_json.js
toolkit/mozapps/extensions/test/xpcshell/test_badschema.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_appversion.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_osabi.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_severities.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
toolkit/mozapps/extensions/test/xpcshell/test_corrupt.js
toolkit/mozapps/extensions/test/xpcshell/test_corruptfile.js
toolkit/mozapps/extensions/test/xpcshell/test_crash_annotation_quoting.js
toolkit/mozapps/extensions/test/xpcshell/test_delay_update.js
toolkit/mozapps/extensions/test/xpcshell/test_dependencies.js
toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js
toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js
toolkit/mozapps/extensions/test/xpcshell/test_distribution.js
toolkit/mozapps/extensions/test/xpcshell/test_error.js
toolkit/mozapps/extensions/test/xpcshell/test_filepointer.js
toolkit/mozapps/extensions/test/xpcshell/test_getresource.js
toolkit/mozapps/extensions/test/xpcshell/test_install.js
toolkit/mozapps/extensions/test/xpcshell/test_isDebuggable.js
toolkit/mozapps/extensions/test/xpcshell/test_locale.js
toolkit/mozapps/extensions/test/xpcshell/test_nodisable_hidden.js
toolkit/mozapps/extensions/test/xpcshell/test_proxies.js
toolkit/mozapps/extensions/test/xpcshell/test_proxy.js
toolkit/mozapps/extensions/test/xpcshell/test_reload.js
toolkit/mozapps/extensions/test/xpcshell/test_safemode.js
toolkit/mozapps/extensions/test/xpcshell/test_schema_change.js
toolkit/mozapps/extensions/test/xpcshell/test_seen.js
toolkit/mozapps/extensions/test/xpcshell/test_sideloads.js
toolkit/mozapps/extensions/test/xpcshell/test_softblocked.js
toolkit/mozapps/extensions/test/xpcshell/test_sourceURI.js
toolkit/mozapps/extensions/test/xpcshell/test_startup.js
toolkit/mozapps/extensions/test/xpcshell/test_switch_os.js
toolkit/mozapps/extensions/test/xpcshell/test_syncGUID.js
toolkit/mozapps/extensions/test/xpcshell/test_temporary.js
toolkit/mozapps/extensions/test/xpcshell/test_undouninstall.js
toolkit/mozapps/extensions/test/xpcshell/test_update.js
toolkit/mozapps/extensions/test/xpcshell/test_updateCancel.js
toolkit/mozapps/extensions/test/xpcshell/test_update_strictcompat.js
toolkit/mozapps/extensions/test/xpcshell/test_update_webextensions.js
toolkit/mozapps/extensions/test/xpcshell/test_updatecheck_errors.js
toolkit/mozapps/extensions/test/xpcshell/test_updateid.js
toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -887,17 +887,21 @@ class ExtensionData {
   }
 
   getAPIManager() {
     let apiManagers = [Management];
 
     for (let id of this.dependencies) {
       let policy = WebExtensionPolicy.getByID(id);
       if (policy) {
-        apiManagers.push(policy.extension.experimentAPIManager);
+        if (policy.extension.experimentAPIManager) {
+          apiManagers.push(policy.extension.experimentAPIManager);
+        } else if (AppConstants.DEBUG) {
+          Cu.reportError(`Cannot find experimental API exported from ${id}`);
+        }
       }
     }
 
     if (this.modules) {
       this.experimentAPIManager =
         new ExtensionCommon.LazyAPIManager("main", this.modules.parent, this.schemaURLs);
 
       apiManagers.push(this.experimentAPIManager);
--- a/toolkit/components/extensions/ExtensionTestCommon.jsm
+++ b/toolkit/components/extensions/ExtensionTestCommon.jsm
@@ -167,27 +167,20 @@ function provide(obj, keys, value, overr
     if (!(keys[0] in obj)) {
       obj[keys[0]] = {};
     }
     provide(obj[keys[0]], keys.slice(1), value, override);
   }
 }
 
 var ExtensionTestCommon = class ExtensionTestCommon {
-  static generateManifest(manifest) {
-    provide(manifest, ["name"], "Generated extension");
-    provide(manifest, ["manifest_version"], 2);
-    provide(manifest, ["version"], "1.0");
-    return manifest;
-  }
-
   /**
    * 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.
+   * single JS object.
    *
    * Properties:
    *   "background": "<JS code>"
    *     A script to be loaded as the background script.
    *     The "background" section of the "manifest" property is overwritten
    *     if this is provided.
    *   "manifest": {...}
    *     Contents of manifest.json
@@ -196,43 +189,64 @@ var ExtensionTestCommon = class Extensio
    *     If a manifest file is provided here, it takes precedence over
    *     a generated one. Always use "/" as a directory separator.
    *     Directories should appear here only implicitly (as a prefix
    *     to file names)
    *
    * To make things easier, the value of "background" and "files"[] can
    * be a function, which is converted to source that is run.
    *
-   * The generated extension is stored in the system temporary directory,
-   * and an nsIFile object pointing to it is returned.
-   *
    * @param {object} data
-   * @returns {nsIFile}
+   * @returns {object}
    */
-  static generateXPI(data) {
+  static generateFiles(data) {
+    let files = {};
+
+    Object.assign(files, data.files);
+
     let manifest = data.manifest;
     if (!manifest) {
       manifest = {};
     }
 
-    let files = Object.assign({}, data.files);
-
     provide(manifest, ["name"], "Generated extension");
     provide(manifest, ["manifest_version"], 2);
     provide(manifest, ["version"], "1.0");
 
     if (data.background) {
       let bgScript = uuidGen.generateUUID().number + ".js";
 
       provide(manifest, ["background", "scripts"], [bgScript], true);
       files[bgScript] = data.background;
     }
 
-    provide(files, ["manifest.json"], manifest);
+    provide(files, ["manifest.json"], JSON.stringify(manifest));
+
+    for (let filename in files) {
+      let contents = files[filename];
+      if (typeof contents == "function") {
+        files[filename] = this.serializeScript(contents);
+      } else if (typeof contents != "string" && !instanceOf(contents, "ArrayBuffer")) {
+        files[filename] = JSON.stringify(contents);
+      }
+    }
 
+    return files;
+  }
+
+  /**
+   * Write an xpi file to disk for a webextension.
+   * The generated extension is stored in the system temporary directory,
+   * and an nsIFile object pointing to it is returned.
+   *
+   * @param {object} data In the format handled by generateFiles.
+   * @returns {nsIFile}
+   */
+  static generateXPI(data) {
+    let files = this.generateFiles(data);
     return this.generateZipFile(files);
   }
 
   static generateZipFile(files, baseName = "generated-extension.xpi") {
     let ZipWriter = Components.Constructor("@mozilla.org/zipwriter;1", "nsIZipWriter");
     let zipW = new ZipWriter();
 
     let file = FileUtils.getFile("TmpD", [baseName]);
@@ -253,22 +267,16 @@ var ExtensionTestCommon = class Extensio
         if (!zipW.hasEntry(path)) {
           zipW.addEntryDirectory(path, time, false);
         }
       }
     }
 
     for (let filename in files) {
       let script = files[filename];
-      if (typeof(script) == "function") {
-        script = this.serializeScript(script);
-      } else if (instanceOf(script, "Object") || instanceOf(script, "Array")) {
-        script = JSON.stringify(script);
-      }
-
       if (!instanceOf(script, "ArrayBuffer")) {
         script = new TextEncoder("utf-8").encode(script).buffer;
       }
 
       let stream = Cc["@mozilla.org/io/arraybuffer-input-stream;1"].createInstance(Ci.nsIArrayBufferInputStream);
       stream.setData(script, 0, script.byteLength);
 
       generateFile(filename);
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -542,16 +542,23 @@ var AddonTestUtils = {
       return new Promise(resolve => {
         server.stop(resolve);
       });
     });
 
     return server;
   },
 
+  registerJSON(server, path, obj) {
+    server.registerPathHandler(path, (request, response) => {
+      response.setHeader("content-type", "application/json", true);
+      response.write(JSON.stringify(obj));
+    });
+  },
+
   info(msg) {
     // info() for mochitests, do_print for xpcshell.
     let print = this.testScope.info || this.testScope.do_print;
     print(msg);
   },
 
   cleanupTempXPIs() {
     for (let file of this.tempXPIs.splice(0)) {
@@ -1080,31 +1087,37 @@ var AddonTestUtils = {
     }
 
     let xpi = OS.Path.join(dir, `${id}.xpi`);
 
     return this.promiseWriteFilesToZip(xpi, files);
   },
 
   tempXPIs: [],
+
+  allocTempXPIFile() {
+    let file = this.tempDir.clone();
+    let uuid = uuidGen.generateUUID().number.slice(1, -1);
+    file.append(`${uuid}.xpi`);
+
+    this.tempXPIs.push(file);
+
+    return file;
+  },
+
   /**
    * 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 {object} files
    *          The object holding data about the add-on
    * @return {nsIFile} A file pointing to the created XPI file
    */
   createTempXPIFile(files) {
-    var file = this.tempDir.clone();
-    let uuid = uuidGen.generateUUID().number.slice(1, -1);
-    file.append(`${uuid}.xpi`);
-
-    this.tempXPIs.push(file);
-
+    let file = this.allocTempXPIFile();
     if (typeof files["install.rdf"] === "object")
       files["install.rdf"] = this.createInstallRDF(files["install.rdf"]);
 
     this.writeFilesToZip(file.path, files);
     return file;
   },
 
   /**
@@ -1335,16 +1348,29 @@ var AddonTestUtils = {
           resolve(args);
         },
       };
 
       AddonManager.addAddonListener(listener);
     });
   },
 
+  promiseInstallEvent(event) {
+    return new Promise(resolve => {
+      let listener = {
+        [event](...args) {
+          AddonManager.removeInstallListener(listener);
+          resolve(args);
+        },
+      };
+
+      AddonManager.addInstallListener(listener);
+    });
+  },
+
   /**
    * A helper method to install AddonInstall and wait for completion.
    *
    * @param {AddonInstall} install
    *        The add-on to install.
    * @returns {Promise<AddonInstall>}
    *        Resolves when the install completes, either successfully or
    *        in failure.
--- a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.json
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.json
@@ -5,31 +5,31 @@
         {
           "applications": {
             "gecko": {
               "strict_min_version": "0",
               "advisory_max_version": "*"
             }
           },
           "version": "4",
-          "update_link": "http://example.com/addons/blocklist_regexp1_1.xpi"
+          "update_link": "http://example.com/addons/blocklist_regexp_1.xpi"
         }
       ]
     },
     "hardblock@tests.mozilla.org": {
       "updates": [
         {
           "applications": {
             "gecko": {
               "strict_min_version": "0",
               "advisory_max_version": "*"
             }
           },
           "version": "4",
-          "update_link": "http://example.com/addons/blocklist_hard1_1.xpi"
+          "update_link": "http://example.com/addons/blocklist_hard_1.xpi"
         }
       ]
     },
     "softblock5@tests.mozilla.org": {
       "updates": [
         {
           "applications": {
             "gecko": {
deleted file mode 100644
index 9d6f0c708116c3217680a4409efba106a0fd2239..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 4496a90cf8807414f13c1b82e62c78e356fb789e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index e61e3c721bcd0319199a85fe1c2aadeecd455a4d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_metadata_filters_1.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_metadata_filters_1.xml
@@ -4,17 +4,17 @@
   <emItems>
     <emItem name="/^Mozilla Corp\.$/">
       <versionRange severity="1">
         <targetApplication id="xpcshell@tests.mozilla.org">
           <versionRange minVersion="1" maxVersion="2.*"/>
         </targetApplication>
       </versionRange>
     </emItem>
-    <emItem id="/block2/" name="/^Moz/" creator="Dangerous"
+    <emItem id="/block2/" name="/^Moz/"
       homepageURL="/\.dangerous\.com/" updateURL="/\.dangerous\.com/">
       <versionRange severity="3">
         <targetApplication id="xpcshell@tests.mozilla.org">
           <versionRange minVersion="1" maxVersion="2.*"/>
         </targetApplication>
       </versionRange>
     </emItem>
   </emItems>
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_regexp_1.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
-  <emItems>
-    <emItem id="/block1/">
-      <versionRange severity="1">
-        <targetApplication id="xpcshell@tests.mozilla.org">
-          <versionRange minVersion="1" maxVersion="2.*"/>
-        </targetApplication>
-      </versionRange>
-    </emItem>
-    <emItem id="/block1/">
-      <versionRange severity="2">
-        <targetApplication id="xpcshell@tests.mozilla.org">
-          <versionRange minVersion="1" maxVersion="2.*"/>
-        </targetApplication>
-      </versionRange>
-    </emItem>
-  </emItems>
-</blocklist>
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_dictionary.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
-  "addons": {
-    "ab-CD@dictionaries.addons.mozilla.org": {
-      "updates": [
-        {
-          "applications": {
-            "gecko": {
-              "strict_min_version": "1",
-              "advisory_max_version": "1"
-            }
-          },
-          "version": "2.0",
-          "update_link": "http://example.com/addons/test_dictionary_3.xpi"
-        }
-      ]
-    },
-    "gh@dictionaries.addons.mozilla.org": {
-      "updates": [
-        {
-          "applications": {
-            "gecko": {
-              "strict_min_version": "1",
-              "advisory_max_version": "1"
-            }
-          },
-          "version": "2.0",
-          "update_link": "http://example.com/addons/test_dictionary_5.xpi"
-        }
-      ]
-    },
-    "ef@dictionaries.addons.mozilla.org": {
-      "updates": [
-        {
-          "applications": {
-            "gecko": {
-              "strict_min_version": "1",
-              "advisory_max_version": "1"
-            }
-          },
-          "version": "2.0",
-          "update_link": "http://example.com/addons/test_dictionary_4.xpi"
-        }
-      ]
-    }
-  }
-}
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -196,24 +196,16 @@ function isManifestRegistered(file) {
   }
   return false;
 }
 
 const BOOTSTRAP_MONITOR_BOOTSTRAP_JS = `
   ChromeUtils.import("resource://xpcshell-data/BootstrapMonitor.jsm").monitor(this);
 `;
 
-
-const EMPTY_BOOTSTRAP_JS = `
-  function startup() {}
-  function shutdown() {}
-  function install() {}
-  function uninstall() {}
-`;
-
 // Listens to messages from bootstrap.js telling us what add-ons were started
 // and stopped etc. and performs some sanity checks that only installed add-ons
 // are started etc.
 this.BootstrapMonitor = {
   inited: false,
 
   // Contain the current state of add-ons in the system
   installed: new Map(),
@@ -568,17 +560,17 @@ function checkAddon(id, addon, expected)
  *         The version of the add-on
  */
 function do_check_in_crash_annotation(aId, aVersion) {
   if (!AppConstants.MOZ_CRASHREPORTER) {
     return;
   }
 
   if (!("Add-ons" in gAppInfo.annotations)) {
-    Assert.equal(false, true);
+    Assert.ok(false, "Cannot find Add-ons entry in crash annotations");
     return;
   }
 
   let addons = gAppInfo.annotations["Add-ons"].split(",");
   Assert.ok(addons.includes(`${encodeURIComponent(aId)}:${encodeURIComponent(aVersion)}`));
 }
 
 /**
@@ -698,18 +690,16 @@ function do_check_addon(aActualAddon, aE
     }
 
     switch (aProperty) {
       case "creator":
         do_check_author(actualValue, expectedValue);
         break;
 
       case "developers":
-      case "translators":
-      case "contributors":
         Assert.equal(actualValue.length, expectedValue.length);
         for (let i = 0; i < actualValue.length; i++)
           do_check_author(actualValue[i], expectedValue[i]);
         break;
 
       case "screenshots":
         Assert.equal(actualValue.length, expectedValue.length);
         for (let i = 0; i < actualValue.length; i++)
@@ -802,26 +792,16 @@ function do_check_icons(aActual, aExpect
 function isThemeInAddonsList(aDir, aId) {
   return AddonTestUtils.addonsList.hasTheme(aDir, aId);
 }
 
 function isExtensionInBootstrappedList(aDir, aId) {
   return AddonTestUtils.addonsList.hasExtension(aDir, aId);
 }
 
-function check_startup_changes(aType, aIds) {
-  var ids = aIds.slice(0);
-  ids.sort();
-  var changes = AddonManager.getStartupChanges(aType);
-  changes = changes.filter(aEl => /@tests.mozilla.org$/.test(aEl));
-  changes.sort();
-
-  Assert.equal(JSON.stringify(ids), JSON.stringify(changes));
-}
-
 /**
  * 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
@@ -1166,21 +1146,25 @@ function prepare_test(aExpectedEvents, a
   AddonManager.addAddonListener(AddonListener);
   AddonManager.addInstallListener(InstallListener);
 
   gExpectedInstalls = aExpectedInstalls;
   gExpectedEvents = aExpectedEvents;
   gNext = aNext;
 }
 
-function end_test() {
+function clearListeners() {
   AddonManager.removeAddonListener(AddonListener);
   AddonManager.removeInstallListener(InstallListener);
 }
 
+function end_test() {
+  clearListeners();
+}
+
 // Checks if all expected events have been seen and if so calls the callback
 function check_test_completed(aArgs) {
   if (!gNext)
     return undefined;
 
   if (gExpectedInstalls instanceof Array &&
       gExpectedInstalls.length > 0)
     return undefined;
--- a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository.js
@@ -1,80 +1,50 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests AddonRepository.jsm
 
 ChromeUtils.import("resource://gre/modules/addons/AddonRepository.jsm");
 
-var gServer = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
+var gServer = createHttpServer({hosts: ["example.com"]});
 
 const PREF_GETADDONS_BROWSEADDONS        = "extensions.getAddons.browseAddons";
 const PREF_GETADDONS_BROWSESEARCHRESULTS = "extensions.getAddons.search.browseURL";
 
-const PORT          = gServer.identity.primaryPort;
 const BASE_URL      = "http://example.com";
 const DEFAULT_URL   = "about:blank";
 
 const ADDONS = [
   {
-    id: "test_AddonRepository_1@tests.mozilla.org",
-    version: "1.1",
-    bootstrap: true,
-
-    name: "XPI Add-on 1",
-    description: "XPI Add-on 1 - Description",
-    creator: "XPI Add-on 1 - Creator",
-    developer: ["XPI Add-on 1 - First Developer",
-                "XPI Add-on 1 - Second Developer"],
-    translator: ["XPI Add-on 1 - First Translator",
-                 "XPI Add-on 1 - Second Translator"],
-    contributor: ["XPI Add-on 1 - First Contributor",
-                  "XPI Add-on 1 - Second Contributor"],
-    homepageURL: "http://example.com/xpi/1/homepage.html",
-    optionsURL: "http://example.com/xpi/1/options.html",
-    aboutURL: "http://example.com/xpi/1/about.html",
-    iconURL: "http://example.com/xpi/1/icon.png",
-
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1"}],
+    manifest: {
+      name: "XPI Add-on 1",
+      version: "1.1",
+      applications: {gecko: {id: "test_AddonRepository_1@tests.mozilla.org" }},
+    },
   },
   {
-    id: "test_AddonRepository_2@tests.mozilla.org",
-    type: 4,
-    internalName: "test2/1.0",
-    version: "1.2",
-    bootstrap: true,
-    name: "XPI Add-on 2",
-
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1"}],
+    manifest: {
+      name: "XPI Add-on 2",
+      version: "1.2",
+      theme: { },
+      applications: {gecko: {id: "test_AddonRepository_2@tests.mozilla.org"}},
+    },
   },
   {
-    id: "test_AddonRepository_3@tests.mozilla.org",
-    type: "4",
-    internalName: "test3/1.0",
-    version: "1.3",
-    bootstrap: true,
-    name: "XPI Add-on 3",
-
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1"}],
+    manifest: {
+      name: "XPI Add-on 3",
+      version: "1.3",
+      theme: { },
+      applications: {gecko: {id: "test_AddonRepository_3@tests.mozilla.org"}},
+    },
   },
 ];
 
-gPort = PORT;
-
 // Path to source URI of installing add-on
 const INSTALL_URL2  = "/addons/test_AddonRepository_2.xpi";
 // Path to source URI of non-active add-on (state = STATE_AVAILABLE)
 const INSTALL_URL3  = "/addons/test_AddonRepository_3.xpi";
 
 // Properties of an individual add-on that should be checked
 // Note: name is checked separately
 var ADDON_PROPERTIES = ["id", "type", "version", "creator", "developers",
@@ -166,17 +136,17 @@ function check_results(aActualAddons, aE
 
   });
 }
 
 add_task(async function setup() {
   // Setup for test
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
 
-  let xpis = ADDONS.map(addon => createTempXPIFile(addon));
+  let xpis = ADDONS.map(addon => createTempWebExtensionFile(addon));
 
   // Register other add-on XPI files
   gServer.registerFile(INSTALL_URL2, xpis[1]);
   gServer.registerFile(INSTALL_URL3, xpis[2]);
 
   // Register files used to test search failure
   gServer.registerFile(GET_TEST.failedURL,
                        do_get_file("data/test_AddonRepository_fail.json"));
--- a/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js
@@ -70,22 +70,20 @@ const ADDONS = [
 const ADDON_IDS = ADDONS.map(addon => addon.manifest.applications.gecko.id);
 const ADDON_FILES = ADDONS.map(addon => AddonTestUtils.createTempWebExtensionFile(addon));
 
 const PREF_ADDON0_CACHE_ENABLED = "extensions." + ADDON_IDS[0] + ".getAddons.cache.enabled";
 const PREF_ADDON1_CACHE_ENABLED = "extensions." + ADDON_IDS[1] + ".getAddons.cache.enabled";
 
 // Properties of an individual add-on that should be checked
 // Note: updateDate is checked separately
-const ADDON_PROPERTIES = ["id", "type", "name", "version", "creator",
-                          "developers", "translators", "contributors",
-                          "description", "fullDescription",
-                          "iconURL", "icons",
-                          "screenshots", "homepageURL", "supportURL",
-                          "optionsURL", "aboutURL", "contributionURL",
+const ADDON_PROPERTIES = ["id", "type", "name", "version",
+                          "developers", "description", "fullDescription",
+                          "icons", "screenshots", "homepageURL", "supportURL",
+                          "optionsURL",
                           "averageRating", "reviewCount",
                           "reviewURL", "weeklyDownloads", "sourceURI"];
 
 // The updateDate property is annoying to test for XPI add-ons.
 // However, since we only care about whether the repository value vs. the
 // XPI value is used, we can just test if the property value matches
 // the repository value
 const REPOSITORY_UPDATEDATE = 9;
@@ -100,215 +98,180 @@ function get_subfile_uri(aId, aFilename)
 
 
 // Expected repository add-ons
 const REPOSITORY_ADDONS = [{
   id:                     ADDON_IDS[0],
   type:                   "extension",
   name:                   "Repo Add-on 1",
   version:                "2.1",
-  creator:                {
-                            name: "Repo Add-on 1 - Creator",
-                            url:  BASE_URL + "/repo/1/creator.html",
-                          },
   developers:             [{
                             name: "Repo Add-on 1 - First Developer",
                             url:  BASE_URL + "/repo/1/firstDeveloper.html",
                           }, {
                             name: "Repo Add-on 1 - Second Developer",
                             url:  BASE_URL + "/repo/1/secondDeveloper.html",
                           }],
   description:            "Repo Add-on 1 - Description\nSecond line",
   fullDescription:        "Repo Add-on 1 - Full Description & some extra",
-  iconURL:                BASE_URL + "/repo/1/icon.png",
   icons:                  { "32": BASE_URL + "/repo/1/icon.png" },
   homepageURL:            BASE_URL + "/repo/1/homepage.html",
   supportURL:             BASE_URL + "/repo/1/support.html",
-  contributionURL:        BASE_URL + "/repo/1/meetDevelopers.html",
   averageRating:          1,
   reviewCount:            1111,
   reviewURL:              BASE_URL + "/repo/1/review.html",
   weeklyDownloads:        3331,
   sourceURI:              BASE_URL + "/repo/1/install.xpi",
 }, {
   id:                     ADDON_IDS[1],
   type:                   "theme",
   name:                   "Repo Add-on 2",
   version:                "2.2",
-  creator:                {
-                            name: "Repo Add-on 2 - Creator",
-                            url:  BASE_URL + "/repo/2/creator.html",
-                          },
   developers:             [{
                             name: "Repo Add-on 2 - First Developer",
                             url:  BASE_URL + "/repo/2/firstDeveloper.html",
                           }, {
                             name: "Repo Add-on 2 - Second Developer",
                             url:  BASE_URL + "/repo/2/secondDeveloper.html",
                           }],
   description:            "Repo Add-on 2 - Description",
   fullDescription:        "Repo Add-on 2 - Full Description",
-  iconURL:                BASE_URL + "/repo/2/icon.png",
   icons:                  { "32": BASE_URL + "/repo/2/icon.png" },
   screenshots:            [{
                             url:          BASE_URL + "/repo/2/firstFull.png",
                             thumbnailURL: BASE_URL + "/repo/2/firstThumbnail.png",
                             caption:      "Repo Add-on 2 - First Caption",
                           }, {
                             url:          BASE_URL + "/repo/2/secondFull.png",
                             thumbnailURL: BASE_URL + "/repo/2/secondThumbnail.png",
                             caption:      "Repo Add-on 2 - Second Caption",
                           }],
   homepageURL:            BASE_URL + "/repo/2/homepage.html",
   supportURL:             BASE_URL + "/repo/2/support.html",
-  contributionURL:        BASE_URL + "/repo/2/meetDevelopers.html",
   averageRating:          2,
   reviewCount:            1112,
   reviewURL:              BASE_URL + "/repo/2/review.html",
   weeklyDownloads:        3332,
   sourceURI:              BASE_URL + "/repo/2/install.xpi",
 }, {
   id:                     ADDON_IDS[2],
   type:                   "theme",
   name:                   "Repo Add-on 3",
   version:                "2.3",
-  iconURL:                BASE_URL + "/repo/3/icon.png",
   icons:                  { "32": BASE_URL + "/repo/3/icon.png" },
   screenshots:            [{
                             url:          BASE_URL + "/repo/3/firstFull.png",
                             thumbnailURL: BASE_URL + "/repo/3/firstThumbnail.png",
                             caption:      "Repo Add-on 3 - First Caption",
                           }, {
                             url:          BASE_URL + "/repo/3/secondFull.png",
                             thumbnailURL: BASE_URL + "/repo/3/secondThumbnail.png",
                             caption:      "Repo Add-on 3 - Second Caption",
                           }],
 }];
 
+function extensionURL(id, path) {
+  return WebExtensionPolicy.getByID(id).getURL(path);
+}
 
 // Expected add-ons when not using cache
 const WITHOUT_CACHE = [{
   id:                     ADDON_IDS[0],
   type:                   "extension",
   name:                   "XPI Add-on 1",
   version:                "1.1",
-  creator:                { name: "XPI Add-on 1 - Creator" },
-  developers:             [{ name: "XPI Add-on 1 - First Developer" },
-                           { name: "XPI Add-on 1 - Second Developer" }],
-  translators:            [{ name: "XPI Add-on 1 - First Translator" },
-                           { name: "XPI Add-on 1 - Second Translator" }],
-  contributors:           [{ name: "XPI Add-on 1 - First Contributor" },
-                           { name: "XPI Add-on 1 - Second Contributor" }],
+  authors:                [{ name: "XPI Add-on 1 - Author" }],
   description:            "XPI Add-on 1 - Description",
-  iconURL:                BASE_URL + "/xpi/1/icon.png",
-  icons:                  { "32": BASE_URL + "/xpi/1/icon.png" },
-  homepageURL:            BASE_URL + "/xpi/1/homepage.html",
-  optionsURL:             BASE_URL + "/xpi/1/options.html",
-  aboutURL:               BASE_URL + "/xpi/1/about.html",
+  get icons() {
+    return { "32": get_subfile_uri(ADDON_IDS[0], "icon.png") };
+  },
+  homepageURL:            `${BASE_URL}/xpi/1/homepage.html`,
+  get optionsURL() {
+    return extensionURL(ADDON_IDS[0], "options.html");
+  },
   sourceURI:              NetUtil.newURI(ADDON_FILES[0]).spec,
 }, {
   id:                     ADDON_IDS[1],
   type:                   "theme",
   name:                   "XPI Add-on 2",
   version:                "1.2",
   sourceURI:              NetUtil.newURI(ADDON_FILES[1]).spec,
   icons:                  {},
 }, {
   id:                     ADDON_IDS[2],
   type:                   "theme",
   name:                   "XPI Add-on 3",
   version:                "1.3",
-  get iconURL() {
-    return get_subfile_uri(ADDON_IDS[2], "icon.png");
-  },
   get icons() {
     return { "32": get_subfile_uri(ADDON_IDS[2], "icon.png") };
   },
   screenshots:            [{ get url() { return get_subfile_uri(ADDON_IDS[2], "preview.png"); } }],
   sourceURI:              NetUtil.newURI(ADDON_FILES[2]).spec,
 }];
 
 
 // Expected add-ons when using cache
 const WITH_CACHE = [{
   id:                     ADDON_IDS[0],
   type:                   "extension",
   name:                   "XPI Add-on 1",
   version:                "1.1",
-  creator:                {
-                            name: "Repo Add-on 1 - Creator",
-                            url:  BASE_URL + "/repo/1/creator.html",
-                          },
-  developers:             [{ name: "XPI Add-on 1 - First Developer" },
-                           { name: "XPI Add-on 1 - Second Developer" }],
-  translators:            [{ name: "XPI Add-on 1 - First Translator" },
-                           { name: "XPI Add-on 1 - Second Translator" }],
-  contributors:           [{ name: "XPI Add-on 1 - First Contributor" },
-                           { name: "XPI Add-on 1 - Second Contributor" }],
+  developers:             [{
+                            name: "Repo Add-on 1 - First Developer",
+                            url:  BASE_URL + "/repo/1/firstDeveloper.html",
+                          }, {
+                            name: "Repo Add-on 1 - Second Developer",
+                            url:  BASE_URL + "/repo/1/secondDeveloper.html",
+                          }],
   description:            "XPI Add-on 1 - Description",
   fullDescription:        "Repo Add-on 1 - Full Description & some extra",
-  eula:                   "Repo Add-on 1 - EULA",
-  iconURL:                BASE_URL + "/xpi/1/icon.png",
-  icons:                  { "32": BASE_URL + "/xpi/1/icon.png" },
+  get icons() {
+    return { "32": get_subfile_uri(ADDON_IDS[0], "icon.png") };
+  },
   homepageURL:            BASE_URL + "/xpi/1/homepage.html",
   supportURL:             BASE_URL + "/repo/1/support.html",
-  optionsURL:             BASE_URL + "/xpi/1/options.html",
-  aboutURL:               BASE_URL + "/xpi/1/about.html",
-  contributionURL:        BASE_URL + "/repo/1/meetDevelopers.html",
-  contributionAmount:     "$11.11",
+  get optionsURL() {
+    return extensionURL(ADDON_IDS[0], "options.html");
+  },
   averageRating:          1,
   reviewCount:            1111,
   reviewURL:              BASE_URL + "/repo/1/review.html",
-  totalDownloads:         2221,
   weeklyDownloads:        3331,
-  dailyUsers:             4441,
   sourceURI:              NetUtil.newURI(ADDON_FILES[0]).spec,
-  repositoryStatus:       4,
 }, {
   id:                     ADDON_IDS[1],
   type:                   "theme",
   name:                   "XPI Add-on 2",
   version:                "1.2",
-  creator:                {
-                            name: "Repo Add-on 2 - Creator",
-                            url:  BASE_URL + "/repo/2/creator.html",
-                          },
   developers:             [{
                             name: "Repo Add-on 2 - First Developer",
                             url:  BASE_URL + "/repo/2/firstDeveloper.html",
                           }, {
                             name: "Repo Add-on 2 - Second Developer",
                             url:  BASE_URL + "/repo/2/secondDeveloper.html",
                           }],
   description:            "Repo Add-on 2 - Description",
   fullDescription:        "Repo Add-on 2 - Full Description",
-  eula:                   "Repo Add-on 2 - EULA",
-  iconURL:                BASE_URL + "/repo/2/icon.png",
   icons:                  { "32": BASE_URL + "/repo/2/icon.png" },
   screenshots:            [{
                             url:          BASE_URL + "/repo/2/firstFull.png",
                             thumbnailURL: BASE_URL + "/repo/2/firstThumbnail.png",
                             caption:      "Repo Add-on 2 - First Caption",
                           }, {
                             url:          BASE_URL + "/repo/2/secondFull.png",
                             thumbnailURL: BASE_URL + "/repo/2/secondThumbnail.png",
                             caption:      "Repo Add-on 2 - Second Caption",
                           }],
   homepageURL:            BASE_URL + "/repo/2/homepage.html",
   supportURL:             BASE_URL + "/repo/2/support.html",
-  contributionURL:        BASE_URL + "/repo/2/meetDevelopers.html",
-  contributionAmount:     null,
   averageRating:          2,
   reviewCount:            1112,
   reviewURL:              BASE_URL + "/repo/2/review.html",
-  totalDownloads:         2222,
   weeklyDownloads:        3332,
-  dailyUsers:             4442,
   sourceURI:              NetUtil.newURI(ADDON_FILES[1]).spec,
-  repositoryStatus:       9,
 }, {
   id:                     ADDON_IDS[2],
   type:                   "theme",
   name:                   "XPI Add-on 3",
   version:                "1.3",
   get iconURL() {
     return get_subfile_uri(ADDON_IDS[2], "icon.png");
   },
@@ -328,45 +291,38 @@ const WITH_CACHE = [{
 }];
 
 // Expected add-ons when using cache
 const WITH_EXTENSION_CACHE = [{
   id:                     ADDON_IDS[0],
   type:                   "extension",
   name:                   "XPI Add-on 1",
   version:                "1.1",
-  creator:                {
-                            name: "Repo Add-on 1 - Creator",
-                            url:  BASE_URL + "/repo/1/creator.html",
-                          },
-  developers:             [{ name: "XPI Add-on 1 - First Developer" },
-                           { name: "XPI Add-on 1 - Second Developer" }],
-  translators:            [{ name: "XPI Add-on 1 - First Translator" },
-                           { name: "XPI Add-on 1 - Second Translator" }],
-  contributors:           [{ name: "XPI Add-on 1 - First Contributor" },
-                           { name: "XPI Add-on 1 - Second Contributor" }],
+  developers:             [{
+                            name: "Repo Add-on 1 - First Developer",
+                            url:  BASE_URL + "/repo/1/firstDeveloper.html",
+                          }, {
+                            name: "Repo Add-on 1 - Second Developer",
+                            url:  BASE_URL + "/repo/1/secondDeveloper.html",
+                          }],
   description:            "XPI Add-on 1 - Description",
   fullDescription:        "Repo Add-on 1 - Full Description & some extra",
-  eula:                   "Repo Add-on 1 - EULA",
-  iconURL:                BASE_URL + "/xpi/1/icon.png",
-  icons:                  { "32": BASE_URL + "/xpi/1/icon.png" },
+  get icons() {
+    return { "32": get_subfile_uri(ADDON_IDS[0], "icon.png") };
+  },
   homepageURL:            BASE_URL + "/xpi/1/homepage.html",
   supportURL:             BASE_URL + "/repo/1/support.html",
-  optionsURL:             BASE_URL + "/xpi/1/options.html",
-  aboutURL:               BASE_URL + "/xpi/1/about.html",
-  contributionURL:        BASE_URL + "/repo/1/meetDevelopers.html",
-  contributionAmount:     "$11.11",
+  get optionsURL() {
+    return extensionURL(ADDON_IDS[0], "options.html");
+  },
   averageRating:          1,
   reviewCount:            1111,
   reviewURL:              BASE_URL + "/repo/1/review.html",
-  totalDownloads:         2221,
   weeklyDownloads:        3331,
-  dailyUsers:             4441,
   sourceURI:              NetUtil.newURI(ADDON_FILES[0]).spec,
-  repositoryStatus:       4,
 }, {
   id:                     ADDON_IDS[1],
   type:                   "theme",
   name:                   "XPI Add-on 2",
   version:                "1.2",
   sourceURI:              NetUtil.newURI(ADDON_FILES[1]).spec,
   icons:                  {},
 }, {
@@ -611,18 +567,18 @@ add_task(async function run_test_11() {
 
 // Tests that XPI add-ons do not use any of the repository properties if
 // caching is disabled, even if there are repository properties available
 add_task(async function run_test_12() {
   Assert.ok(gDBFile.exists());
   Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
   Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, GETADDONS_RESULTS);
 
-  let aAddons = await promiseAddonsByIDs(ADDON_IDS);
-  check_results(aAddons, WITHOUT_CACHE);
+  let addons = await promiseAddonsByIDs(ADDON_IDS);
+  check_results(addons, WITHOUT_CACHE);
 });
 
 // Tests that a background update with caching disabled deletes the add-ons
 // database, and that XPI add-ons still do not use any of repository properties
 add_task(async function run_test_13() {
   Assert.ok(gDBFile.exists());
   Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, EMPTY_RESULT);
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_XPIStates.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_XPIStates.js
@@ -5,49 +5,34 @@
 // Test that we only check manifest age for disabled extensions
 
 
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
-const ADDONS = {
-  test_bootstrap1_1: {
-    "install.rdf": {
-      "id": "bootstrap1@tests.mozilla.org",
-      "name": "Test Bootstrap 1",
-    },
-    "bootstrap.js": BOOTSTRAP_MONITOR_BOOTSTRAP_JS,
-  },
-};
-
-/* We want one add-on installed packed, and one installed unpacked
- */
-
-function run_test() {
-  // Shut down the add-on manager after all tests run.
+add_task(async function setup() {
+  await promiseStartupManager();
   registerCleanupFunction(promiseShutdownManager);
-  // Kick off the task-based tests...
-  run_next_test();
-}
 
-// Use bootstrap extensions so the changes will be immediate.
-// A packed extension, to be enabled
-add_task(async function setup() {
-  await promiseWriteInstallRDFToXPI({
-    id: "packed-enabled@tests.mozilla.org",
-    name: "Packed, Enabled",
-  }, profileDir);
+  await promiseInstallWebExtension({
+    manifest: {
+      applications: {gecko: {id: "enabled@tests.mozilla.org"}},
+    },
+  });
+  await promiseInstallWebExtension({
+    manifest: {
+      applications: {gecko: {id: "disabled@tests.mozilla.org"}},
+    },
+  });
 
-  // Packed, will be disabled
-  await promiseWriteInstallRDFToXPI({
-    id: "packed-disabled@tests.mozilla.org",
-    name: "Packed, Disabled",
-  }, profileDir);
+  let addon = await promiseAddonByID("disabled@tests.mozilla.org");
+  notEqual(addon, null);
+  await addon.disable();
 });
 
 // Keep track of the last time stamp we've used, so that we can keep moving
 // it forward (if we touch two different files in the same add-on with the same
 // timestamp we may not consider the change significant)
 var lastTimestamp = Date.now();
 
 /*
@@ -74,70 +59,69 @@ function getXS() {
 
 async function getXSJSON() {
   await AddonTestUtils.loadAddonsList(true);
 
   return aomStartup.readStartupData();
 }
 
 add_task(async function detect_touches() {
-  await promiseStartupManager();
-  let [/* pe */, pd] = await promiseAddonsByIDs([
-         "packed-enabled@tests.mozilla.org",
-         "packed-disabled@tests.mozilla.org",
-         ]);
-
-  info("Disable test add-ons");
-  await pd.disable();
-
   let XS = getXS();
 
   // Should be no changes detected here, because everything should start out up-to-date.
   Assert.ok(!XS.scanForChanges());
 
   let states = XS.getLocation("app-profile");
 
   // State should correctly reflect enabled/disabled
-  Assert.ok(states.get("packed-enabled@tests.mozilla.org").enabled);
-  Assert.ok(!states.get("packed-disabled@tests.mozilla.org").enabled);
+
+  let state = states.get("enabled@tests.mozilla.org");
+  Assert.notEqual(state, null, "Found xpi state for enabled extension");
+  Assert.ok(state.enabled, "enabled extension has correct xpi state");
+
+  state = states.get("disabled@tests.mozilla.org");
+  Assert.notEqual(state, null, "Found xpi state for disabled extension");
+  Assert.ok(!state.enabled, "disabled extension has correct xpi state");
 
   // Touch various files and make sure the change is detected.
 
   // We notice that a packed XPI is touched for an enabled add-on.
   let peFile = profileDir.clone();
-  peFile.append("packed-enabled@tests.mozilla.org.xpi");
+  peFile.append("enabled@tests.mozilla.org.xpi");
   checkChange(XS, peFile, true);
 
   // We should notice the packed XPI change for a disabled add-on too.
   let pdFile = profileDir.clone();
-  pdFile.append("packed-disabled@tests.mozilla.org.xpi");
+  pdFile.append("disabled@tests.mozilla.org.xpi");
   checkChange(XS, pdFile, true);
 });
 
 /*
- * Uninstalling bootstrap add-ons should immediately remove them from the
- * extensions.xpiState preference.
+ * Uninstalling extensions should immediately remove them from XPIStates.
  */
 add_task(async function uninstall_bootstrap() {
-  let [pe /* pd */] = await promiseAddonsByIDs([
-         "packed-enabled@tests.mozilla.org",
-         "packed-disabled@tests.mozilla.org",
-         ]);
+  let pe = await promiseAddonByID("enabled@tests.mozilla.org");
   await pe.uninstall();
 
   let xpiState = await getXSJSON();
-  Assert.equal(false, "packed-enabled@tests.mozilla.org" in xpiState["app-profile"].addons);
+  Assert.equal(false, "enabled@tests.mozilla.org" in xpiState["app-profile"].addons);
 });
 
 /*
- * Installing a restartless add-on should immediately add it to XPIState
+ * Installing an extension should immediately add it to XPIState
  */
 add_task(async function install_bootstrap() {
+  const ID = "addon@tests.mozilla.org";
   let XS = getXS();
 
-  let {addon} = await AddonTestUtils.promiseInstallXPI(ADDONS.test_bootstrap1_1);
+  await promiseInstallWebExtension({
+    manifest: {
+      applications: {gecko: {id: ID}},
+    },
+  });
+  let addon = await promiseAddonByID(ID);
 
-  let xState = XS.getAddon("app-profile", addon.id);
+  let xState = XS.getAddon("app-profile", ID);
   Assert.ok(!!xState);
   Assert.ok(xState.enabled);
   Assert.equal(xState.mtime, addon.updateDate.getTime());
   await addon.uninstall();
 });
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_backgroundupdate.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// This verifies that background updates & notifications work as expected
-
-// The test extension uses an insecure update url.
-Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
-
-var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
-add_task(async function setup() {
-  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
-
-  testserver.registerDirectory("/data/", do_get_file("data"));
-
-  await promiseStartupManager();
-
-  do_test_pending();
-  run_test_1();
-});
-
-function end_test() {
-  do_test_finished();
-}
-
-// Verify that with no add-ons installed the background update notifications get
-// called
-async function run_test_1() {
-  let aAddons = await AddonManager.getAddonsByTypes(["extension", "theme", "locale"]);
-  Assert.equal(aAddons.length, 1);
-
-  Services.obs.addObserver(function observer() {
-    Services.obs.removeObserver(observer, "addons-background-update-complete");
-
-    executeSoon(run_test_2);
-  }, "addons-background-update-complete");
-
-  // Trigger the background update timer handler
-  gInternalManager.notify(null);
-}
-
-// Verify that with two add-ons installed both of which claim to have updates
-// available we get the notification after both updates attempted to start
-async function run_test_2() {
-  await promiseWriteInstallRDFForExtension({
-    id: "addon1@tests.mozilla.org",
-    version: "1.0",
-    updateURL: "http://example.com/data/test_backgroundupdate.json",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test Addon 1",
-  }, profileDir);
-
-  await promiseWriteInstallRDFForExtension({
-    id: "addon2@tests.mozilla.org",
-    version: "1.0",
-    updateURL: "http://example.com/data/test_backgroundupdate.json",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test Addon 2",
-  }, profileDir);
-
-  await promiseWriteInstallRDFForExtension({
-    id: "addon3@tests.mozilla.org",
-    version: "1.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test Addon 3",
-  }, profileDir);
-
-  // Disable rcwn to make cache behavior deterministic.
-  Services.prefs.setBoolPref("network.http.rcwn.enabled", false);
-
-  // Background update uses a different pref, if set
-  Services.prefs.setCharPref("extensions.update.background.url",
-                             "http://example.com/data/test_backgroundupdate.json");
-
-  await promiseRestartManager();
-
-  let installCount = 0;
-  let completeCount = 0;
-  let sawCompleteNotification = false;
-
-  Services.obs.addObserver(function observer() {
-    Services.obs.removeObserver(observer, "addons-background-update-complete");
-
-    Assert.equal(installCount, 3);
-    sawCompleteNotification = true;
-  }, "addons-background-update-complete");
-
-  AddonManager.addInstallListener({
-    onNewInstall(aInstall) {
-      installCount++;
-    },
-
-    onDownloadFailed(aInstall) {
-      completeCount++;
-      if (completeCount == 3) {
-        Assert.ok(sawCompleteNotification);
-        end_test();
-      }
-    },
-  });
-
-  // Trigger the background update timer handler
-  gInternalManager.notify(null);
-}
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bad_json.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bad_json.js
@@ -1,48 +1,39 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests that we rebuild the database correctly if it contains
 // JSON data that parses correctly but doesn't contain required fields
 
-var addon1 = {
-  id: "addon1@tests.mozilla.org",
-  version: "2.0",
-  name: "Test 1",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
-
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
 add_task(async function() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
-  // This addon will be auto-installed at startup
-  await promiseWriteInstallRDFForExtension(addon1, profileDir);
+  await promiseStartupManager();
 
-  await promiseStartupManager();
+  const ID = "addon@tests.mozilla.org";
+  await promiseInstallWebExtension({
+    manifest: {
+      version: "2.0",
+      applications: {gecko: {id: ID}},
+    },
+  });
+
   await promiseShutdownManager();
 
   // First startup/shutdown finished
   // Replace the JSON store with something bogus
   await saveJSON({not: "what we expect to find"}, gExtensionsJSON.path);
 
   await promiseStartupManager();
   // Retrieve an addon to force the database to rebuild
-  let a1 = await AddonManager.getAddonByID(addon1.id);
+  let addon = await AddonManager.getAddonByID(ID);
 
-  Assert.equal(a1.id, addon1.id);
+  Assert.equal(addon.id, ID);
 
   await promiseShutdownManager();
 
   // Make sure our JSON database has schemaVersion and our installed extension
   let data = await loadJSON(gExtensionsJSON.path);
   Assert.ok("schemaVersion" in data);
-  Assert.equal(data.addons[0].id, addon1.id);
+  Assert.equal(data.addons[0].id, ID);
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_badschema.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_badschema.js
@@ -6,184 +6,123 @@
 
 var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 
 // register files with server
 testserver.registerDirectory("/data/", do_get_file("data"));
 
 // The test extension uses an insecure update url.
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
-Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, false);
 
 const ADDONS = {
   "addon1@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon1@tests.mozilla.org",
-      version: "1.0",
+    manifest: {
       name: "Test 1",
-      bootstrap: true,
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "2",
-        maxVersion: "2",
-      }],
+      applications: {
+        gecko: {
+          id: "addon1@tests.mozilla.org",
+          strict_min_version: "2",
+          strict_max_version: "2",
+        },
+      },
     },
     desiredValues: {
       isActive: true,
       userDisabled: false,
       appDisabled: false,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
   "addon2@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon2@tests.mozilla.org",
-      version: "1.0",
+    manifest: {
       name: "Test 2",
-      bootstrap: true,
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "2",
-        maxVersion: "2",
-      }],
+      version: "1.0",
+      applications: {
+        gecko: {
+          id: "addon2@tests.mozilla.org",
+        },
+      },
     },
     initialState: {
       userDisabled: true,
     },
     desiredValues: {
       isActive: false,
       userDisabled: true,
       appDisabled: false,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
   "addon3@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon3@tests.mozilla.org",
-      version: "1.0",
+    manifest: {
       name: "Test 3",
-      bootstrap: true,
-      updateURL: "http://example.com/data/test_corrupt.json",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "1",
-      }],
+      version: "1.0",
+      applications: {
+        gecko: {
+          id: "addon3@tests.mozilla.org",
+          update_url: "http://example.com/data/test_corrupt.json",
+          strict_min_version: "1",
+          strict_max_version: "1",
+        },
+      },
     },
     findUpdates: true,
     desiredValues: {
       isActive: true,
       userDisabled: false,
       appDisabled: false,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
   "addon4@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon4@tests.mozilla.org",
-      version: "1.0",
+    manifest: {
       name: "Test 4",
-      bootstrap: true,
-      updateURL: "http://example.com/data/test_corrupt.json",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "1",
-      }],
+      version: "1.0",
+      applications: {
+        gecko: {
+          id: "addon4@tests.mozilla.org",
+          update_url: "http://example.com/data/test_corrupt.json",
+          strict_min_version: "1",
+          strict_max_version: "1",
+        },
+      },
     },
     initialState: {
       userDisabled: true,
     },
     findUpdates: true,
     desiredValues: {
       isActive: false,
       userDisabled: true,
       appDisabled: false,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
   "addon5@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon5@tests.mozilla.org",
-      version: "1.0",
+    manifest: {
       name: "Test 5",
-      bootstrap: true,
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "1",
-      }],
-    },
-    desiredValues: {
-      isActive: true,
-      userDisabled: false,
-      appDisabled: false,
-      pendingOperations: 0,
-    },
-    afterCorruption: {},
-    afterSecondRestart: {},
-  },
-
-  "addon6@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon6@tests.mozilla.org",
       version: "1.0",
-      name: "Test 6",
-      bootstrap: "true",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "2",
-        maxVersion: "2",
-      }],
-    },
-    desiredValues: {
-      isActive: true,
-      userDisabled: false,
-      appDisabled: false,
-      pendingOperations: 0,
-    },
-    afterCorruption: {},
-    afterSecondRestart: {},
-  },
-
-  "addon7@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon7@tests.mozilla.org",
-      version: "1.0",
-      name: "Test 7",
-      bootstrap: "true",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "2",
-        maxVersion: "2",
-      }],
-    },
-    initialState: {
-      userDisabled: true,
+      applications: {
+        gecko: {
+          id: "addon5@tests.mozilla.org",
+          strict_min_version: "1",
+          strict_max_version: "1",
+        },
+      },
     },
     desiredValues: {
       isActive: false,
-      userDisabled: true,
-      appDisabled: false,
+      userDisabled: false,
+      appDisabled: true,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
   "theme1@tests.mozilla.org": {
     manifest: {
       manifest_version: 2,
       name: "Theme 1",
       version: "1.0",
       theme: { images: { headerURL: "example.png" } },
@@ -194,18 +133,16 @@ const ADDONS = {
       },
     },
     desiredValues: {
       isActive: false,
       userDisabled: true,
       appDisabled: false,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
   "theme2@tests.mozilla.org": {
     manifest: {
       manifest_version: 2,
       name: "Theme 2",
       version: "1.0",
       theme: { images: { headerURL: "example.png" } },
@@ -219,43 +156,34 @@ const ADDONS = {
       userDisabled: false,
     },
     desiredValues: {
       isActive: true,
       userDisabled: false,
       appDisabled: false,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 };
 
 const IDS = Object.keys(ADDONS);
 
 function promiseUpdates(addon) {
   return new Promise(resolve => {
     addon.findUpdates({onUpdateFinished: resolve},
                       AddonManager.UPDATE_WHEN_PERIODIC_UPDATE);
   });
 }
 
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
 add_task(async function setup() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "2");
 
   for (let addon of Object.values(ADDONS)) {
-    if (addon["install.rdf"]) {
-      await promiseWriteInstallRDFForExtension(addon["install.rdf"], profileDir);
-    } else {
-      let webext = createTempWebExtensionFile({manifest: addon.manifest});
-      await AddonTestUtils.manuallyInstall(webext);
-    }
+    let webext = createTempWebExtensionFile({manifest: addon.manifest});
+    await AddonTestUtils.manuallyInstall(webext);
   }
 
   await promiseStartupManager();
 
   let addons = await getAddons(IDS);
   for (let [id, addon] of Object.entries(ADDONS)) {
     if (addon.initialState) {
       await setInitialState(addons.get(id), addon.initialState);
@@ -283,27 +211,25 @@ add_task(async function test_after_schem
   // the schema
   await changeXPIDBVersion(100);
 
   await promiseStartupManager();
 
   info("Test add-on state after schema version change");
   let addons = await getAddons(IDS);
   for (let [id, addon] of Object.entries(ADDONS)) {
-    checkAddon(id, addons.get(id),
-               Object.assign({}, addon.desiredValues, addon.afterCorruption));
+    checkAddon(id, addons.get(id), addon.desiredValues);
   }
 
   await promiseShutdownManager();
 });
 
 add_task(async function test_after_second_restart() {
   await promiseStartupManager();
 
   info("Test add-on state after second restart");
   let addons = await getAddons(IDS);
   for (let [id, addon] of Object.entries(ADDONS)) {
-    checkAddon(id, addons.get(id),
-               Object.assign({}, addon.desiredValues, addon.afterSecondRestart));
+    checkAddon(id, addons.get(id), addon.desiredValues);
   }
 
   await promiseShutdownManager();
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_appversion.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_appversion.js
@@ -248,25 +248,22 @@ async function loadBlocklist(file) {
 }
 
 let factory = XPCOMUtils.generateSingletonFactory(function() { return BlocklistPrompt; });
 Cm.registerFactory(Components.ID("{26d32654-30c7-485d-b983-b4d2568aebba}"),
                    "Blocklist Prompt",
                    "@mozilla.org/addons/blocklist-prompt;1", factory);
 
 function createAddon(addon) {
-  return promiseInstallXPI({
-    name: addon.name,
-    id: addon.id,
-    version: addon.version,
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "3",
-      maxVersion: "3"}],
+  return promiseInstallWebExtension({
+    manifest: {
+      name: addon.name,
+      version: addon.version,
+      applications: {gecko: {id: addon.id}},
+    },
   });
 }
 
 /**
  * Checks that items are blocklisted correctly according to the current test.
  * If a lastTest is provided checks that the notification dialog got passed
  * the newly blocked items compared to the previous test.
  */
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
@@ -35,103 +35,88 @@ var WindowWatcher = {
 
   },
 
   QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"]),
 };
 
 MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
 
-function load_blocklist(aFile, aCallback) {
-  Services.obs.addObserver(function observer() {
-    Services.obs.removeObserver(observer, "blocklist-updated");
+function load_blocklist(aFile) {
+  return new Promise(resolve => {
+    Services.obs.addObserver(function observer() {
+      Services.obs.removeObserver(observer, "blocklist-updated");
 
-    executeSoon(aCallback);
-  }, "blocklist-updated");
+      resolve();
+    }, "blocklist-updated");
 
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + aFile);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
+    Services.prefs.setCharPref("extensions.blocklist.url",
+                               `http://localhost:${gPort}/data/${aFile}`);
+    var blocklist = Cc["@mozilla.org/extensions/blocklist;1"]
+                      .getService(Ci.nsITimerCallback);
+    blocklist.notify(null);
+  });
 }
 
 
-function end_test() {
-  do_test_finished();
-}
+add_task(async function setup() {
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
 
-async function run_test() {
-  do_test_pending();
-
-  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
+  await promiseStartupManager();
 
   // Should get blocked by name
-  await promiseWriteInstallRDFForExtension({
-    id: "block1@tests.mozilla.org",
-    version: "1.0",
-    name: "Mozilla Corp.",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3",
-    }],
-  }, profileDir);
+  await promiseInstallWebExtension({
+    manifest: {
+      name: "Mozilla Corp.",
+      version: "1.0",
+      applications: {gecko: {id: "block1@tests.mozilla.org"}},
+    },
+  });
 
   // Should get blocked by all the attributes.
-  await promiseWriteInstallRDFForExtension({
-    id: "block2@tests.mozilla.org",
-    version: "1.0",
-    name: "Moz-addon",
-    bootstrap: true,
-    creator: "Dangerous",
-    homepageURL: "www.extension.dangerous.com",
-    updateURL: "www.extension.dangerous.com/update.rdf",
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3",
-    }],
-  }, profileDir);
+  await promiseInstallWebExtension({
+    manifest: {
+      name: "Moz-addon",
+      version: "1.0",
+      homepage_url: "https://www.extension.dangerous.com/",
+      applications: {
+        gecko: {
+          id: "block2@tests.mozilla.org",
+          update_url: "https://www.extension.dangerous.com/update.json",
+        },
+      },
+    },
+  });
 
   // Fails to get blocked because of a different ID even though other
   // attributes match against a blocklist entry.
-  await promiseWriteInstallRDFForExtension({
-    id: "block3@tests.mozilla.org",
-    version: "1.0",
-    name: "Moz-addon",
-    bootstrap: true,
-    creator: "Dangerous",
-    homepageURL: "www.extensions.dangerous.com",
-    updateURL: "www.extension.dangerous.com/update.rdf",
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3",
-    }],
-  }, profileDir);
-
-  await promiseStartupManager();
+  await promiseInstallWebExtension({
+    manifest: {
+      name: "Moz-addon",
+      version: "1.0",
+      homepage_url: "https://www.extension.dangerous.com/",
+      applications: {
+        gecko: {
+          id: "block3@tests.mozilla.org",
+          update_url: "https://www.extension.dangerous.com/update.json",
+        },
+      },
+    },
+  });
 
   let [a1, a2, a3] = await AddonManager.getAddonsByIDs(["block1@tests.mozilla.org",
                                                         "block2@tests.mozilla.org",
                                                         "block3@tests.mozilla.org"]);
   Assert.equal(a1.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   Assert.equal(a2.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   Assert.equal(a3.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
-
-  run_test_1();
-}
+});
 
-function run_test_1() {
-  load_blocklist("test_blocklist_metadata_filters_1.xml", async function() {
-    await promiseRestartManager();
+add_task(async function test_blocks() {
+  await load_blocklist("test_blocklist_metadata_filters_1.xml");
 
-    let [a1, a2, a3] = await AddonManager.getAddonsByIDs(["block1@tests.mozilla.org",
-                                                          "block2@tests.mozilla.org",
-                                                          "block3@tests.mozilla.org"]);
-    Assert.equal(a1.blocklistState, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-    Assert.equal(a2.blocklistState, Ci.nsIBlocklistService.STATE_BLOCKED);
-    Assert.equal(a3.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
-    end_test();
-  });
-}
+  let [a1, a2, a3] = await AddonManager.getAddonsByIDs(["block1@tests.mozilla.org",
+                                                        "block2@tests.mozilla.org",
+                                                        "block3@tests.mozilla.org"]);
+  Assert.equal(a1.blocklistState, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+  Assert.equal(a2.blocklistState, Ci.nsIBlocklistService.STATE_BLOCKED);
+  Assert.equal(a3.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_osabi.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_osabi.js
@@ -6,278 +6,165 @@
 var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
 gPort = testserver.identity.primaryPort;
 
 testserver.registerDirectory("/data/", do_get_file("data"));
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
-const ADDONS = {
-  "test_bug393285_1@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_1@tests.mozilla.org",
-      name: "extension 1",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
+const ADDONS = [
+  {
+    id: "test_bug393285_1@tests.mozilla.org",
+    name: "extension 1",
+    version: "1.0",
+
     // No info in blocklist, shouldn't be blocked
     notBlocklisted: [["1", "1.9"], [null, null]],
   },
+  {
+    id: "test_bug393285_2@tests.mozilla.org",
+    name: "extension 2",
+    version: "1.0",
 
-  "test_bug393285_2@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_2@tests.mozilla.org",
-      name: "extension 2",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Should always be blocked
     blocklisted: [["1", "1.9"], [null, null]],
   },
+  {
+    id: "test_bug393285_3a@tests.mozilla.org",
+    name: "extension 3a",
+    version: "1.0",
 
-  "test_bug393285_3a@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_3a@tests.mozilla.org",
-      name: "extension 3a",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Only version 1 should be blocked
     blocklisted: [["1", "1.9"], [null, null]],
   },
+  {
+    id: "test_bug393285_3b@tests.mozilla.org",
+    name: "extension 3b",
+    version: "2.0",
 
-  "test_bug393285_3b@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_3b@tests.mozilla.org",
-      name: "extension 3b",
-      bootstrap: true,
-      version: "2.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Only version 1 should be blocked
     notBlocklisted: [["1", "1.9"]],
   },
+  {
+    id: "test_bug393285_4@tests.mozilla.org",
+    name: "extension 4",
+    version: "1.0",
 
-  "test_bug393285_4@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_4@tests.mozilla.org",
-      name: "extension 4",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Should be blocked for app version 1
     blocklisted: [["1", "1.9"], [null, null]],
     notBlocklisted: [["2", "1.9"]],
   },
-
-  "test_bug393285_5@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_5@tests.mozilla.org",
-      name: "extension 5",
-      bootstrap: true,
+  {
+    id: "test_bug393285_5@tests.mozilla.org",
+    name: "extension 5",
       version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
+
     // Not blocklisted because we are a different OS
     notBlocklisted: [["2", "1.9"]],
   },
+  {
+    id: "test_bug393285_6@tests.mozilla.org",
+    name: "extension 6",
+    version: "1.0",
 
-  "test_bug393285_6@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_6@tests.mozilla.org",
-      name: "extension 6",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Blocklisted based on OS
     blocklisted: [["2", "1.9"]],
   },
+  {
+    id: "test_bug393285_7@tests.mozilla.org",
+    name: "extension 7",
+    version: "1.0",
 
-  "test_bug393285_7@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_7@tests.mozilla.org",
-      name: "extension 7",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Blocklisted based on OS
     blocklisted: [["2", "1.9"]],
   },
+  {
+    id: "test_bug393285_8@tests.mozilla.org",
+    name: "extension 8",
+    version: "1.0",
 
-  "test_bug393285_8@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_8@tests.mozilla.org",
-      name: "extension 8",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Not blocklisted because we are a different ABI
     notBlocklisted: [["2", "1.9"]],
   },
+  {
+    id: "test_bug393285_9@tests.mozilla.org",
+    name: "extension 9",
+    version: "1.0",
 
-  "test_bug393285_9@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_9@tests.mozilla.org",
-      name: "extension 9",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Blocklisted based on ABI
     blocklisted: [["2", "1.9"]],
   },
+  {
+    id: "test_bug393285_10@tests.mozilla.org",
+    name: "extension 10",
+    version: "1.0",
 
-  "test_bug393285_10@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_10@tests.mozilla.org",
-      name: "extension 10",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Blocklisted based on ABI
     blocklisted: [["2", "1.9"]],
   },
+  {
+    id: "test_bug393285_11@tests.mozilla.org",
+    name: "extension 11",
+    version: "1.0",
 
-  "test_bug393285_11@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_11@tests.mozilla.org",
-      name: "extension 11",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Doesn't match both os and abi so not blocked
     notBlocklisted: [["2", "1.9"]],
   },
+  {
+    id: "test_bug393285_12@tests.mozilla.org",
+    name: "extension 12",
+    version: "1.0",
 
-  "test_bug393285_12@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_12@tests.mozilla.org",
-      name: "extension 12",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Doesn't match both os and abi so not blocked
     notBlocklisted: [["2", "1.9"]],
   },
+  {
+    id: "test_bug393285_13@tests.mozilla.org",
+    name: "extension 13",
+    version: "1.0",
 
-  "test_bug393285_13@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_13@tests.mozilla.org",
-      name: "extension 13",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Doesn't match both os and abi so not blocked
     notBlocklisted: [["2", "1.9"]],
   },
+  {
+    id: "test_bug393285_14@tests.mozilla.org",
+    name: "extension 14",
+    version: "1.0",
 
-  "test_bug393285_14@tests.mozilla.org": {
-    "install.rdf": {
-      id: "test_bug393285_14@tests.mozilla.org",
-      name: "extension 14",
-      bootstrap: true,
-      version: "1.0",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "3",
-      }],
-    },
     // Matches both os and abi so blocked
     blocklisted: [["2", "1.9"]],
   },
-};
+];
 
-const ADDON_IDS = Object.keys(ADDONS);
+const ADDON_IDS = ADDONS.map(a => a.id);
 
 async function loadBlocklist(file) {
   let blocklistUpdated = TestUtils.topicObserved("blocklist-updated");
 
   Services.prefs.setCharPref("extensions.blocklist.url",
                              "http://example.com/data/" + file);
   Blocklist.notify();
 
   return blocklistUpdated;
 }
 
 
 add_task(async function setup() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
   await promiseStartupManager();
 
-  for (let addon of Object.values(ADDONS)) {
-    await promiseInstallXPI(addon["install.rdf"]);
+  for (let addon of ADDONS) {
+    await promiseInstallWebExtension({
+      manifest: {
+        name: addon.name,
+        version: addon.version,
+        applications: {gecko: {id: addon.id}},
+      },
+    });
   }
 
   let addons = await getAddons(ADDON_IDS);
   for (let id of ADDON_IDS) {
     equal(addons.get(id).blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED,
           `Add-on ${id} should not initially be blocked`);
   }
 });
@@ -285,19 +172,20 @@ add_task(async function setup() {
 add_task(async function test_1() {
   await loadBlocklist("test_bug393285.xml");
 
   let addons = await getAddons(ADDON_IDS);
   async function isBlocklisted(addon, appVer, toolkitVer) {
     let state = await Blocklist.getAddonBlocklistState(addon, appVer, toolkitVer);
     return state != Services.blocklist.STATE_NOT_BLOCKED;
   }
-  for (let [id, options] of Object.entries(ADDONS)) {
-    for (let blocklisted of options.blocklisted || []) {
+  for (let addon of ADDONS) {
+    let {id} = addon;
+    for (let blocklisted of addon.blocklisted || []) {
       ok(await isBlocklisted(addons.get(id), ...blocklisted),
          `Add-on ${id} should be blocklisted in app/platform version ${blocklisted}`);
     }
-    for (let notBlocklisted of options.notBlocklisted || []) {
+    for (let notBlocklisted of addon.notBlocklisted || []) {
       ok(!(await isBlocklisted(addons.get(id), ...notBlocklisted)),
          `Add-on ${id} should not be blocklisted in app/platform version ${notBlocklisted}`);
     }
   }
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
@@ -3,24 +3,21 @@
  */
 
 // Tests resetting of preferences in blocklist entry when an add-on is blocked.
 // See bug 802434.
 
 const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
 
 ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
-var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
+var testserver = createHttpServer({hosts: ["example.com"]});
 gPort = testserver.identity.primaryPort;
 
 testserver.registerDirectory("/data/", do_get_file("data"));
 
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
 // A window watcher to handle the blocklist UI.
 // Don't need the full interface, attempts to call other methods will just
 // throw which is just fine
 var WindowWatcher = {
   openWindow(parent, url, name, features, args) {
     // Should be called to list the newly blocklisted items
     Assert.equal(url, URI_EXTENSION_BLOCKLIST_DIALOG);
 
@@ -36,97 +33,81 @@ var WindowWatcher = {
 
   },
 
   QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"]),
 };
 
 MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
 
-function load_blocklist(aFile, aCallback) {
-  Services.obs.addObserver(function observer() {
-    Services.obs.removeObserver(observer, "blocklist-updated");
+function load_blocklist(aFile) {
+  return new Promise(resolve => {
+    Services.obs.addObserver(function observer() {
+      Services.obs.removeObserver(observer, "blocklist-updated");
+      resolve();
+    }, "blocklist-updated");
 
-    executeSoon(aCallback);
-  }, "blocklist-updated");
-
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + aFile);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
+    Services.prefs.setCharPref("extensions.blocklist.url",
+                               `http://localhost:${gPort}/data/${aFile}`);
+    var blocklist = Cc["@mozilla.org/extensions/blocklist;1"]
+                      .getService(Ci.nsITimerCallback);
+    blocklist.notify(null);
+  });
 }
 
-function end_test() {
-  do_test_finished();
-}
+add_task(async function setup() {
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
 
-async function run_test() {
-  do_test_pending();
-
-  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
+  await promiseStartupManager();
 
   // Add 2 extensions
-  await promiseWriteInstallRDFForExtension({
-    id: "block1@tests.mozilla.org",
-    version: "1.0",
-    name: "Blocked add-on-1 with to-be-reset prefs",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3",
-    }],
-  }, profileDir);
-
-  await promiseWriteInstallRDFForExtension({
-    id: "block2@tests.mozilla.org",
-    version: "1.0",
-    name: "Blocked add-on-2 with to-be-reset prefs",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3",
-    }],
-  }, profileDir);
+  await promiseInstallWebExtension({
+    manifest: {
+      name: "Blocked add-on-1 with to-be-reset prefs",
+      version: "1.0",
+      applications: {gecko: {id: "block1@tests.mozilla.org"}},
+    },
+  });
+  await promiseInstallWebExtension({
+    manifest: {
+      name: "Blocked add-on-2 with to-be-reset prefs",
+      version: "1.0",
+      applications: {gecko: {id: "block2@tests.mozilla.org"}},
+    },
+  });
 
   // Pre-set the preferences that we expect to get reset.
   Services.prefs.setIntPref("test.blocklist.pref1", 15);
   Services.prefs.setIntPref("test.blocklist.pref2", 15);
   Services.prefs.setBoolPref("test.blocklist.pref3", true);
   Services.prefs.setBoolPref("test.blocklist.pref4", true);
 
-  await promiseStartupManager();
 
   // Before blocklist is loaded.
   let [a1, a2] = await AddonManager.getAddonsByIDs(["block1@tests.mozilla.org",
                                                     "block2@tests.mozilla.org"]);
   Assert.equal(a1.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   Assert.equal(a2.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 
   Assert.equal(Services.prefs.getIntPref("test.blocklist.pref1"), 15);
   Assert.equal(Services.prefs.getIntPref("test.blocklist.pref2"), 15);
   Assert.equal(Services.prefs.getBoolPref("test.blocklist.pref3"), true);
   Assert.equal(Services.prefs.getBoolPref("test.blocklist.pref4"), true);
-  run_test_1();
-}
+});
+
 
-function run_test_1() {
-  load_blocklist("test_blocklist_prefs_1.xml", async function() {
-    await promiseRestartManager();
+add_task(async function test_blocks() {
+  await load_blocklist("test_blocklist_prefs_1.xml");
 
-    // Blocklist changes should have applied and the prefs must be reset.
-    let [a1, a2] = await AddonManager.getAddonsByIDs(["block1@tests.mozilla.org",
-                                                      "block2@tests.mozilla.org"]);
-    Assert.notEqual(a1, null);
-    Assert.equal(a1.blocklistState, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-    Assert.notEqual(a2, null);
-    Assert.equal(a2.blocklistState, Ci.nsIBlocklistService.STATE_BLOCKED);
+  // Blocklist changes should have applied and the prefs must be reset.
+  let [a1, a2] = await AddonManager.getAddonsByIDs(["block1@tests.mozilla.org",
+                                                    "block2@tests.mozilla.org"]);
+  Assert.notEqual(a1, null);
+  Assert.equal(a1.blocklistState, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
+  Assert.notEqual(a2, null);
+  Assert.equal(a2.blocklistState, Ci.nsIBlocklistService.STATE_BLOCKED);
 
-    // All these prefs must be reset to defaults.
-    Assert.equal(Services.prefs.prefHasUserValue("test.blocklist.pref1"), false);
-    Assert.equal(Services.prefs.prefHasUserValue("test.blocklist.pref2"), false);
-    Assert.equal(Services.prefs.prefHasUserValue("test.blocklist.pref3"), false);
-    Assert.equal(Services.prefs.prefHasUserValue("test.blocklist.pref4"), false);
-    end_test();
-  });
-}
+  // All these prefs must be reset to defaults.
+  Assert.equal(Services.prefs.prefHasUserValue("test.blocklist.pref1"), false);
+  Assert.equal(Services.prefs.prefHasUserValue("test.blocklist.pref2"), false);
+  Assert.equal(Services.prefs.prefHasUserValue("test.blocklist.pref3"), false);
+  Assert.equal(Services.prefs.prefHasUserValue("test.blocklist.pref4"), false);
+});
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// Checks that blocklist entries using RegExp work as expected. This only covers
-// behavior specific to RegExp entries - general behavior is already tested
-// in test_blocklistchange.js.
-
-const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
-
-ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
-var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
-gPort = testserver.identity.primaryPort;
-
-testserver.registerDirectory("/data/", do_get_file("data"));
-
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
-// Don't need the full interface, attempts to call other methods will just
-// throw which is just fine
-var WindowWatcher = {
-  openWindow(parent, url, name, features, args) {
-    // Should be called to list the newly blocklisted items
-    Assert.equal(url, URI_EXTENSION_BLOCKLIST_DIALOG);
-
-    // Simulate auto-disabling any softblocks
-    var list = args.wrappedJSObject.list;
-    list.forEach(function(aItem) {
-      if (!aItem.blocked)
-        aItem.disable = true;
-    });
-
-    // run the code after the blocklist is closed
-    Services.obs.notifyObservers(null, "addon-blocklist-closed");
-
-  },
-
-  QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"]),
-};
-
-MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
-
-
-function load_blocklist(aFile, aCallback) {
-  Services.obs.addObserver(function observer() {
-    Services.obs.removeObserver(observer, "blocklist-updated");
-
-    executeSoon(aCallback);
-  }, "blocklist-updated");
-
-  Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
-                             gPort + "/data/" + aFile);
-  var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
-                  getService(Ci.nsITimerCallback);
-  blocklist.notify(null);
-}
-
-
-function end_test() {
-  do_test_finished();
-}
-
-
-async function run_test() {
-  do_test_pending();
-
-  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
-
-  await promiseWriteInstallRDFForExtension({
-    id: "block1@tests.mozilla.org",
-    version: "1.0",
-    name: "RegExp blocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3",
-    }],
-  }, profileDir);
-
-  await promiseStartupManager();
-
-  let [a1] = await AddonManager.getAddonsByIDs(["block1@tests.mozilla.org"]);
-  Assert.equal(a1.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
-
-  run_test_1();
-}
-
-function run_test_1() {
-  load_blocklist("test_blocklist_regexp_1.xml", async function() {
-    await promiseRestartManager();
-
-    let [a1] = await AddonManager.getAddonsByIDs(["block1@tests.mozilla.org"]);
-    Assert.notEqual(a1, null);
-    Assert.equal(a1.blocklistState, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-
-    end_test();
-  });
-}
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_severities.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_severities.js
@@ -116,25 +116,28 @@ var WindowWatcher = {
   },
 
   QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"]),
 };
 
 MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
 
 function createAddon(addon) {
-  return promiseInstallXPI({
-    name: addon.name,
-    id: addon.id,
-    version: addon.version,
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: addon.appVersion,
-      maxVersion: addon.appVersion}],
+  return promiseInstallWebExtension({
+    manifest: {
+      name: addon.name,
+      version: addon.version,
+      applications: {
+        gecko: {
+          id: addon.id,
+          strict_min_version: addon.appVersion,
+          strict_max_version: addon.appVersion,
+        },
+      },
+    },
   });
 }
 
 async function loadBlocklist(file, callback) {
   let blocklistUpdated = TestUtils.topicObserved("blocklist-updated");
 
   gNotificationCheck = callback;
 
@@ -176,17 +179,17 @@ async function checkInitialState() {
   equal(await check_plugin_state(PLUGINS[5]), "false,true");
 }
 
 function checkAddonState(addon, state) {
   return checkAddon(addon.id, addon, state);
 }
 
 add_task(async function setup() {
-  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "3", "8");
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "3", "3");
   await promiseStartupManager();
 
   for (let addon of ADDONS)
     await createAddon(addon);
 });
 
 add_task(async function test_1() {
   // Tests the add-ons were installed and the initial blocklist applied as expected
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
@@ -25,477 +25,24 @@
 
 const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
 
 ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
 
 // Allow insecure updates
 Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
 
-var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
+Services.prefs.setBoolPref("extensions.webextPermissionPrompts", false);
+
+var testserver = createHttpServer({hosts: ["example.com"]});
 
 testserver.registerDirectory("/data/", do_get_file("data"));
 
-const ADDONS = {
-  "blocklist_hard1_1": {
-    id: "hardblock@tests.mozilla.org",
-    version: "1.0",
-    name: "Hardblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_hard1_2": {
-    id: "hardblock@tests.mozilla.org",
-    version: "2.0",
-    name: "Hardblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_hard1_3": {
-    id: "hardblock@tests.mozilla.org",
-    version: "3.0",
-    name: "Hardblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_regexp1_1": {
-    id: "regexpblock@tests.mozilla.org",
-    version: "1.0",
-    name: "RegExp-blocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_regexp1_2": {
-    id: "regexpblock@tests.mozilla.org",
-    version: "2.0",
-    name: "RegExp-blocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_regexp1_3": {
-    id: "regexpblock@tests.mozilla.org",
-    version: "3.0",
-    name: "RegExp-blocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft1_1": {
-    id: "softblock1@tests.mozilla.org",
-    version: "1.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft1_2": {
-    id: "softblock1@tests.mozilla.org",
-    version: "2.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft1_3": {
-    id: "softblock1@tests.mozilla.org",
-    version: "3.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft2_1": {
-    id: "softblock2@tests.mozilla.org",
-    version: "1.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft2_2": {
-    id: "softblock2@tests.mozilla.org",
-    version: "2.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft2_3": {
-    id: "softblock2@tests.mozilla.org",
-    version: "3.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft3_1": {
-    id: "softblock3@tests.mozilla.org",
-    version: "1.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft3_2": {
-    id: "softblock3@tests.mozilla.org",
-    version: "2.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft3_3": {
-    id: "softblock3@tests.mozilla.org",
-    version: "3.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft4_1": {
-    id: "softblock4@tests.mozilla.org",
-    version: "1.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft4_2": {
-    id: "softblock4@tests.mozilla.org",
-    version: "2.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft4_3": {
-    id: "softblock4@tests.mozilla.org",
-    version: "3.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft5_1": {
-    id: "softblock5@tests.mozilla.org",
-    version: "1.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    internalName: "test/1.0",
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft5_2": {
-    id: "softblock5@tests.mozilla.org",
-    version: "2.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    internalName: "test/1.0",
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-  "blocklist_soft5_3": {
-    id: "softblock5@tests.mozilla.org",
-    version: "3.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    internalName: "test/1.0",
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3"}],
-  },
-};
-
 const XPIS = {};
 
-for (let [name, manifest] of Object.entries(ADDONS)) {
-  XPIS[name] = createTempXPIFile(manifest);
-  testserver.registerFile(`/addons/${name}.xpi`, XPIS[name]);
-}
-
-var softblock1_1 = {
-  id: "softblock1@tests.mozilla.org",
-  version: "1.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update1.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock1_2 = {
-  id: "softblock1@tests.mozilla.org",
-  version: "2.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update2.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock1_3 = {
-  id: "softblock1@tests.mozilla.org",
-  version: "3.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update3.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock2_1 = {
-  id: "softblock2@tests.mozilla.org",
-  version: "1.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update1.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock2_2 = {
-  id: "softblock2@tests.mozilla.org",
-  version: "2.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update2.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock2_3 = {
-  id: "softblock2@tests.mozilla.org",
-  version: "3.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update3.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock3_1 = {
-  id: "softblock3@tests.mozilla.org",
-  version: "1.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update1.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock3_2 = {
-  id: "softblock3@tests.mozilla.org",
-  version: "2.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update2.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock3_3 = {
-  id: "softblock3@tests.mozilla.org",
-  version: "3.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update3.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock4_1 = {
-  id: "softblock4@tests.mozilla.org",
-  version: "1.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update1.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock4_2 = {
-  id: "softblock4@tests.mozilla.org",
-  version: "2.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update2.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var softblock4_3 = {
-  id: "softblock4@tests.mozilla.org",
-  version: "3.0",
-  name: "Softblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update3.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var hardblock_1 = {
-  id: "hardblock@tests.mozilla.org",
-  version: "1.0",
-  name: "Hardblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update1.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var hardblock_2 = {
-  id: "hardblock@tests.mozilla.org",
-  version: "2.0",
-  name: "Hardblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update2.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var hardblock_3 = {
-  id: "hardblock@tests.mozilla.org",
-  version: "3.0",
-  name: "Hardblocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update3.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var regexpblock_1 = {
-  id: "regexpblock@tests.mozilla.org",
-  version: "1.0",
-  name: "RegExp-blocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update1.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var regexpblock_2 = {
-  id: "regexpblock@tests.mozilla.org",
-  version: "2.0",
-  name: "RegExp-blocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update2.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
-var regexpblock_3 = {
-  id: "regexpblock@tests.mozilla.org",
-  version: "3.0",
-  name: "RegExp-blocked add-on",
-  bootstrap: true,
-  updateURL: "http://example.com/data/blocklistchange/addon_update3.json",
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "3",
-  }],
-};
-
 const ADDON_IDS = ["softblock1@tests.mozilla.org",
                    "softblock2@tests.mozilla.org",
                    "softblock3@tests.mozilla.org",
                    "softblock4@tests.mozilla.org",
                    "hardblock@tests.mozilla.org",
                    "regexpblock@tests.mozilla.org"];
 
 // Don't need the full interface, attempts to call other methods will just
@@ -562,20 +109,20 @@ function Pload_blocklist(aFile) {
                   getService(Ci.nsITimerCallback);
   blocklist.notify(null);
   return blocklist_updated;
 }
 
 // Does a background update check for add-ons and returns a promise that
 // resolves when any started installs complete
 function Pbackground_update() {
-  var installCount = 0;
-  var backgroundCheckCompleted = false;
+  return new Promise((resolve, reject) => {
+    let installCount = 0;
+    let backgroundCheckCompleted = false;
 
-  let updated = new Promise((resolve, reject) => {
     AddonManager.addInstallListener({
       onNewInstall(aInstall) {
         installCount++;
       },
 
       onInstallEnded(aInstall) {
         installCount--;
         // Wait until all started installs have completed
@@ -599,46 +146,40 @@ function Pbackground_update() {
 
       // If any new installs have started then we'll call the callback once they
       // are completed
       if (installCount)
         return;
 
       resolve();
     }, "addons-background-update-complete");
+
+    AddonManagerPrivate.backgroundUpdateCheck();
   });
-
-  AddonManagerPrivate.backgroundUpdateCheck();
-  return updated;
 }
 
 // Manually updates the test add-ons to the given version
 function Pmanual_update(aVersion) {
-  let Pinstalls = [];
-  for (let name of ["soft1", "soft2", "soft3", "soft4", "hard1", "regexp1"]) {
-    Pinstalls.push(
-      AddonManager.getInstallForURL(
-        `http://example.com/addons/blocklist_${name}_${aVersion}.xpi`, "application/x-xpinstall"));
-  }
+  const names = ["soft1", "soft2", "soft3", "soft4", "hard", "regexp"];
+  return Promise.all(names.map(async name => {
+    let url = `http://example.com/addons/blocklist_${name}_${aVersion}.xpi`;
+    let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
 
-  return Promise.all(Pinstalls).then(installs => {
-    let completePromises = [];
-    for (let install of installs) {
-      completePromises.push(new Promise(resolve => {
-        install.addListener({
-          onDownloadCancelled: resolve,
-          onInstallEnded: resolve,
-        });
-      }));
+    // installAddonFromAOM() does more checking than install.install().
+    // In particular, it will refuse to install an incompatible addon.
+
+    return new Promise(resolve => {
+      install.addListener({
+        onDownloadCancelled: resolve,
+        onInstallEnded: resolve,
+      });
 
       AddonManager.installAddonFromAOM(null, null, install);
-    }
-
-    return Promise.all(completePromises);
-  });
+    });
+  }));
 }
 
 // Checks that an add-ons properties match expected values
 function check_addon(aAddon, aExpectedVersion, aExpectedUserDisabled,
                      aExpectedSoftDisabled, aExpectedState) {
   Assert.notEqual(aAddon, null);
   info("Testing " + aAddon.id + " version " + aAddon.version + " user "
        + aAddon.userDisabled + " soft " + aAddon.softDisabled
@@ -679,38 +220,59 @@ function check_addon(aAddon, aExpectedVe
 
   if (aExpectedUserDisabled || aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED) {
     Assert.ok(!willBeActive);
   } else {
     Assert.ok(willBeActive);
   }
 }
 
-function run_test() {
+add_task(async function setup() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
-  run_next_test();
-}
+
+  // pattern used to map ids like softblock1 to soft1
+  let pattern = /^(soft|hard|regexp)block([1-9]*)@/;
+  for (let id of ADDON_IDS) {
+    for (let version of [1, 2, 3]) {
+      let match = id.match(pattern);
+      let name = `blocklist_${match[1]}${match[2]}_${version}`;
 
-add_task(async function init() {
-  await promiseWriteInstallRDFForExtension(softblock1_1, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock2_1, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock3_1, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock4_1, profileDir);
-  await promiseWriteInstallRDFForExtension(hardblock_1, profileDir);
-  await promiseWriteInstallRDFForExtension(regexpblock_1, profileDir);
+      XPIS[name] = createTempWebExtensionFile({
+        manifest: {
+          name: "Test",
+          version: `${version}.0`,
+          applications: {
+            gecko: {
+              id,
+              update_url: `http://example.com/data/blocklistchange/addon_update${version}.json`,
+            },
+          },
+        },
+      });
+
+      testserver.registerFile(`/addons/${name}.xpi`, XPIS[name]);
+    }
+  }
+
   await promiseStartupManager();
 
-  let [/* s1 */, /* s2 */, /* s3 */, s4 /* h, r */] = await promiseAddonsByIDs(ADDON_IDS);
+  await promiseInstallFile(XPIS.blocklist_soft1_1);
+  await promiseInstallFile(XPIS.blocklist_soft2_1);
+  await promiseInstallFile(XPIS.blocklist_soft3_1);
+  await promiseInstallFile(XPIS.blocklist_soft4_1);
+  await promiseInstallFile(XPIS.blocklist_hard_1);
+  await promiseInstallFile(XPIS.blocklist_regexp_1);
+
+  let s4 = await promiseAddonByID("softblock4@tests.mozilla.org");
   await s4.disable();
 });
 
 // Starts with add-ons unblocked and then switches application versions to
 // change add-ons to blocked and back
 add_task(async function run_app_update_test() {
-  await promiseRestartManager();
   await Pload_blocklist("app_update.xml");
   await promiseRestartManager();
 
   let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@@ -943,32 +505,22 @@ add_task(async function run_addon_change
   check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 });
 
 add_task(async function run_addon_change_2() {
-  await promiseShutdownManager();
-
-  await promiseWriteInstallRDFForExtension(softblock1_2, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_2.id), Date.now() + 10000);
-  await promiseWriteInstallRDFForExtension(softblock2_2, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_2.id), Date.now() + 10000);
-  await promiseWriteInstallRDFForExtension(softblock3_2, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_2.id), Date.now() + 10000);
-  await promiseWriteInstallRDFForExtension(softblock4_2, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_2.id), Date.now() + 10000);
-  await promiseWriteInstallRDFForExtension(hardblock_2, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_2.id), Date.now() + 10000);
-  await promiseWriteInstallRDFForExtension(regexpblock_2, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_2.id), Date.now() + 10000);
-
-  await promiseStartupManager();
+  await promiseInstallFile(XPIS.blocklist_soft1_2);
+  await promiseInstallFile(XPIS.blocklist_soft2_2);
+  await promiseInstallFile(XPIS.blocklist_soft3_2);
+  await promiseInstallFile(XPIS.blocklist_soft4_2);
+  await promiseInstallFile(XPIS.blocklist_hard_2);
+  await promiseInstallFile(XPIS.blocklist_regexp_2);
 
   let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s2, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s3, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s4, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(h, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
@@ -977,175 +529,54 @@ add_task(async function run_addon_change
   await s2.enable();
   await s2.disable();
   check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   await s3.enable();
   check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
 });
 
 add_task(async function run_addon_change_3() {
-  await promiseRestartManager();
-
-  await promiseShutdownManager();
-
-  await promiseWriteInstallRDFForExtension(softblock1_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_3.id), Date.now() + 20000);
-  await promiseWriteInstallRDFForExtension(softblock2_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_3.id), Date.now() + 20000);
-  await promiseWriteInstallRDFForExtension(softblock3_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_3.id), Date.now() + 20000);
-  await promiseWriteInstallRDFForExtension(softblock4_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_3.id), Date.now() + 20000);
-  await promiseWriteInstallRDFForExtension(hardblock_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_3.id), Date.now() + 20000);
-  await promiseWriteInstallRDFForExtension(regexpblock_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_3.id), Date.now() + 20000);
-
-  await promiseStartupManager();
+  await promiseInstallFile(XPIS.blocklist_soft1_3);
+  await promiseInstallFile(XPIS.blocklist_soft2_3);
+  await promiseInstallFile(XPIS.blocklist_soft3_3);
+  await promiseInstallFile(XPIS.blocklist_soft4_3);
+  await promiseInstallFile(XPIS.blocklist_hard_3);
+  await promiseInstallFile(XPIS.blocklist_regexp_3);
 
   let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
   check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 });
 
 add_task(async function run_addon_change_4() {
-  await promiseShutdownManager();
-
-  await promiseWriteInstallRDFForExtension(softblock1_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_1.id), Date.now() + 30000);
-  await promiseWriteInstallRDFForExtension(softblock2_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_1.id), Date.now() + 30000);
-  await promiseWriteInstallRDFForExtension(softblock3_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_1.id), Date.now() + 30000);
-  await promiseWriteInstallRDFForExtension(softblock4_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_1.id), Date.now() + 30000);
-  await promiseWriteInstallRDFForExtension(hardblock_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_1.id), Date.now() + 30000);
-  await promiseWriteInstallRDFForExtension(regexpblock_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_1.id), Date.now() + 30000);
-
-  await promiseStartupManager();
+  await promiseInstallFile(XPIS.blocklist_soft1_1);
+  await promiseInstallFile(XPIS.blocklist_soft2_1);
+  await promiseInstallFile(XPIS.blocklist_soft3_1);
+  await promiseInstallFile(XPIS.blocklist_soft4_1);
+  await promiseInstallFile(XPIS.blocklist_hard_1);
+  await promiseInstallFile(XPIS.blocklist_regexp_1);
 
   let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 
   await s1.enable();
   await s2.enable();
 });
 
-// Starts with add-ons blocked and then new versions are installed outside of
-// the app to change them to unblocked.
-add_task(async function run_addon_change_2_test() {
-  await promiseShutdownManager();
-
-  getFileForAddon(profileDir, softblock1_1.id).remove(true);
-  getFileForAddon(profileDir, softblock2_1.id).remove(true);
-  getFileForAddon(profileDir, softblock3_1.id).remove(true);
-  getFileForAddon(profileDir, softblock4_1.id).remove(true);
-  getFileForAddon(profileDir, hardblock_1.id).remove(true);
-  getFileForAddon(profileDir, regexpblock_1.id).remove(true);
-
-  await promiseStartupManager();
-  await promiseShutdownManager();
-
-  await promiseWriteInstallRDFForExtension(softblock1_2, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock2_2, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock3_2, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock4_2, profileDir);
-  await promiseWriteInstallRDFForExtension(hardblock_2, profileDir);
-  await promiseWriteInstallRDFForExtension(regexpblock_2, profileDir);
-
-  await promiseStartupManager();
-
-  let [s1, s2, s3, /* s4 */, h, r] = await promiseAddonsByIDs(ADDON_IDS);
-
-  check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-  check_addon(s2, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-  check_addon(s3, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-  check_addon(h, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
-  check_addon(r, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
-
-  await s2.enable();
-  await s2.disable();
-  check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-  await s3.enable();
-  check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-});
-
-add_task(async function addon_change_2_test_2() {
-  await promiseRestartManager();
-
-  await promiseShutdownManager();
-
-  await promiseWriteInstallRDFForExtension(softblock1_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_3.id), Date.now() + 10000);
-  await promiseWriteInstallRDFForExtension(softblock2_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_3.id), Date.now() + 10000);
-  await promiseWriteInstallRDFForExtension(softblock3_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_3.id), Date.now() + 10000);
-  await promiseWriteInstallRDFForExtension(softblock4_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_3.id), Date.now() + 10000);
-  await promiseWriteInstallRDFForExtension(hardblock_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_3.id), Date.now() + 10000);
-  await promiseWriteInstallRDFForExtension(regexpblock_3, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_3.id), Date.now() + 10000);
-
-  await promiseStartupManager();
-
-  let [s1, s2, s3, /* s4 */, h, r] = await promiseAddonsByIDs(ADDON_IDS);
-
-  check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-  check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-  check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-  check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
-  check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
-});
-
-add_task(async function addon_change_2_test_3() {
-  await promiseShutdownManager();
-
-  await promiseWriteInstallRDFForExtension(softblock1_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_1.id), Date.now() + 20000);
-  await promiseWriteInstallRDFForExtension(softblock2_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_1.id), Date.now() + 20000);
-  await promiseWriteInstallRDFForExtension(softblock3_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_1.id), Date.now() + 20000);
-  await promiseWriteInstallRDFForExtension(softblock4_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_1.id), Date.now() + 20000);
-  await promiseWriteInstallRDFForExtension(hardblock_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_1.id), Date.now() + 20000);
-  await promiseWriteInstallRDFForExtension(regexpblock_1, profileDir);
-  setExtensionModifiedTime(getFileForAddon(profileDir, regexpblock_1.id), Date.now() + 20000);
-
-  await promiseStartupManager();
-
-  let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
-
-  check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
-  check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
-  check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
-  check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
-  check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
-
-  await s1.enable();
-  await s2.enable();
-  await s4.disable();
-});
-
 // Add-ons are initially unblocked then attempts to upgrade to blocked versions
 // in the background which should fail
 add_task(async function run_background_update_test() {
   await promiseRestartManager();
 
   let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@@ -1166,55 +597,38 @@ add_task(async function run_background_u
   check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 });
 
 // Starts with add-ons blocked and then new versions are detected and installed
 // automatically for unblocked versions.
 add_task(async function run_background_update_2_test() {
-  await promiseShutdownManager();
-
-  getFileForAddon(profileDir, softblock1_1.id).remove(true);
-  getFileForAddon(profileDir, softblock2_1.id).remove(true);
-  getFileForAddon(profileDir, softblock3_1.id).remove(true);
-  getFileForAddon(profileDir, softblock4_1.id).remove(true);
-  getFileForAddon(profileDir, hardblock_1.id).remove(true);
-  getFileForAddon(profileDir, regexpblock_1.id).remove(true);
-
-  await promiseStartupManager();
-  await promiseShutdownManager();
-
-  await promiseWriteInstallRDFForExtension(softblock1_3, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock2_3, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock3_3, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock4_3, profileDir);
-  await promiseWriteInstallRDFForExtension(hardblock_3, profileDir);
-  await promiseWriteInstallRDFForExtension(regexpblock_3, profileDir);
-
-  await promiseStartupManager();
+  await promiseInstallFile(XPIS.blocklist_soft1_3);
+  await promiseInstallFile(XPIS.blocklist_soft2_3);
+  await promiseInstallFile(XPIS.blocklist_soft3_3);
+  await promiseInstallFile(XPIS.blocklist_soft4_3);
+  await promiseInstallFile(XPIS.blocklist_hard_3);
+  await promiseInstallFile(XPIS.blocklist_regexp_3);
 
   let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s2, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s3, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
   check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
   await s2.enable();
   await s2.disable();
   check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   await s3.enable();
   check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
 
-  await promiseRestartManager();
-
   await Pbackground_update();
-  await promiseRestartManager();
 
   [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
@@ -1222,157 +636,128 @@ add_task(async function run_background_u
   await s1.enable();
   await s2.enable();
   await s4.disable();
 });
 
 // Starts with add-ons blocked and then simulates the user upgrading them to
 // unblocked versions.
 add_task(async function run_manual_update_test() {
-  await promiseRestartManager();
   await Pload_blocklist("manual_update.xml");
-  await promiseRestartManager();
 
   let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
   check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
   await s2.enable();
   await s2.disable();
   check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   await s3.enable();
   check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
 
-  await promiseRestartManager();
-
   await Pmanual_update("2");
-  await promiseRestartManager();
 
   [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s4, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   // Can't manually update to a hardblocked add-on
   check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
   check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
   await Pmanual_update("3");
-  await promiseRestartManager();
 
   [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 });
 
 // Starts with add-ons blocked and then new versions are installed outside of
 // the app to change them to unblocked.
 add_task(async function run_manual_update_2_test() {
-  await promiseShutdownManager();
-
-  getFileForAddon(profileDir, softblock1_1.id).remove(true);
-  getFileForAddon(profileDir, softblock2_1.id).remove(true);
-  getFileForAddon(profileDir, softblock3_1.id).remove(true);
-  getFileForAddon(profileDir, softblock4_1.id).remove(true);
-  getFileForAddon(profileDir, hardblock_1.id).remove(true);
-  getFileForAddon(profileDir, regexpblock_1.id).remove(true);
+  let addons = await promiseAddonsByIDs(ADDON_IDS);
+  await Promise.all(addons.map(addon => addon.uninstall()));
 
-  await promiseStartupManager();
-  await promiseShutdownManager();
-
-  await promiseWriteInstallRDFForExtension(softblock1_1, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock2_1, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock3_1, profileDir);
-  await promiseWriteInstallRDFForExtension(softblock4_1, profileDir);
-  await promiseWriteInstallRDFForExtension(hardblock_1, profileDir);
-  await promiseWriteInstallRDFForExtension(regexpblock_1, profileDir);
-
-  await promiseStartupManager();
+  await promiseInstallFile(XPIS.blocklist_soft1_1);
+  await promiseInstallFile(XPIS.blocklist_soft2_1);
+  await promiseInstallFile(XPIS.blocklist_soft3_1);
+  await promiseInstallFile(XPIS.blocklist_soft4_1);
+  await promiseInstallFile(XPIS.blocklist_hard_1);
+  await promiseInstallFile(XPIS.blocklist_regexp_1);
 
   let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
   check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
   await s2.enable();
   await s2.disable();
   check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   await s3.enable();
   check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
-  await promiseRestartManager();
 
   await Pmanual_update("2");
-  await promiseRestartManager();
 
   [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   // Can't manually update to a hardblocked add-on
   check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
   check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
 
-  await promiseRestartManager();
 
   await Pmanual_update("3");
-  await promiseRestartManager();
 
   [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
   check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
 
   await s1.enable();
   await s2.enable();
   await s4.disable();
 });
 
 // Uses the API to install blocked add-ons from the local filesystem
 add_task(async function run_local_install_test() {
-  await promiseShutdownManager();
-
-  getFileForAddon(profileDir, softblock1_1.id).remove(true);
-  getFileForAddon(profileDir, softblock2_1.id).remove(true);
-  getFileForAddon(profileDir, softblock3_1.id).remove(true);
-  getFileForAddon(profileDir, softblock4_1.id).remove(true);
-  getFileForAddon(profileDir, hardblock_1.id).remove(true);
-  getFileForAddon(profileDir, regexpblock_1.id).remove(true);
-
-  await promiseStartupManager();
+  let addons = await promiseAddonsByIDs(ADDON_IDS);
+  await Promise.all(addons.map(addon => addon.uninstall()));
 
   await promiseInstallAllFiles([
     XPIS.blocklist_soft1_1,
     XPIS.blocklist_soft2_1,
     XPIS.blocklist_soft3_1,
     XPIS.blocklist_soft4_1,
-    XPIS.blocklist_hard1_1,
-    XPIS.blocklist_regexp1_1,
+    XPIS.blocklist_hard_1,
+    XPIS.blocklist_regexp_1,
   ]);
 
-  let aInstalls = await AddonManager.getAllInstalls();
+  let installs = await AddonManager.getAllInstalls();
   // Should have finished all installs without needing to restart
-  Assert.equal(aInstalls.length, 0);
+  Assert.equal(installs.length, 0);
 
   let [s1, s2, s3, /* s4 */, h, r] = await promiseAddonsByIDs(ADDON_IDS);
 
   check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
   check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
   check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
@@ -6,50 +6,49 @@
 
 var gExpectedFile = null;
 var gCacheFlushCount = 0;
 
 var CacheFlushObserver = {
   observe(aSubject, aTopic, aData) {
     if (aTopic != "flush-cache-entry")
       return;
-    // Ignore flushes triggered by the fake cert DB
-    if (aData == "cert-override")
+
+    // Ignore flushes from the fake cert DB or extension-process-script
+    if (aData == "cert-override" || aSubject == null)
       return;
 
+
     if (!gExpectedFile) {
       return;
     }
     ok(aSubject instanceof Ci.nsIFile);
     equal(aSubject.path, gExpectedFile.path);
     gCacheFlushCount++;
   },
 };
 
-const ADDONS = [
-  {
-    id: "addon2@tests.mozilla.org",
-    version: "2.0",
-
-    name: "Cache Flush Test",
-  },
-];
-
-const XPIS = ADDONS.map(addon => createTempXPIFile(addon));
-
 add_task(async function setup() {
   Services.obs.addObserver(CacheFlushObserver, "flush-cache-entry");
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "2");
 
   await promiseStartupManager();
 });
 
 // Tests that the cache is flushed when installing a restartless add-on
 add_task(async function test_flush_restartless_install() {
-  let install = await AddonManager.getInstallForFile(XPIS[0]);
+  let xpi = await createTempWebExtensionFile({
+    manifest: {
+      name: "Cache Flush Test",
+      version: "2.0",
+      applications: {gecko: {id: "addon2@tests.mozilla.org"}},
+    },
+  });
+
+  let install = await AddonManager.getInstallForFile(xpi);
 
   await new Promise(resolve => {
     install.addListener({
       onInstallStarted() {
         // We should flush the staged XPI when completing the install
         gExpectedFile = gProfD.clone();
         gExpectedFile.append("extensions");
         gExpectedFile.append("staged");
--- a/toolkit/mozapps/extensions/test/xpcshell/test_corrupt.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_corrupt.js
@@ -1,130 +1,95 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Checks that we rebuild something sensible from a corrupt database
 
 
 // Create and configure the HTTP server.
-var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
+var testserver = createHttpServer({hosts: ["example.com"]});
 
 // register files with server
 testserver.registerDirectory("/data/", do_get_file("data"));
 
 // The test extension uses an insecure update url.
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
-Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, false);
 
 const ADDONS = {
   // Will get a compatibility update and stay enabled
   "addon3@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon3@tests.mozilla.org",
+    manifest: {
       name: "Test 3",
-      updateURL: "http://example.com/data/test_corrupt.json",
+      applications: {
+        gecko: {
+          id: "addon3@tests.mozilla.org",
+          update_url: "http://example.com/data/test_corrupt.json",
+        },
+      },
     },
     findUpdates: true,
     desiredState: {
       isActive: true,
       userDisabled: false,
       appDisabled: false,
       pendingOperations: 0,
     },
-    // The compatibility update won't be recovered but it should still be
-    // active for this session
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
   // Will get a compatibility update and be enabled
   "addon4@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon4@tests.mozilla.org",
+    manifest: {
       name: "Test 4",
-      updateURL: "http://example.com/data/test_corrupt.json",
+      applications: {
+        gecko: {
+          id: "addon4@tests.mozilla.org",
+          update_url: "http://example.com/data/test_corrupt.json",
+        },
+      },
     },
     initialState: {
       userDisabled: true,
     },
     findUpdates: true,
     desiredState: {
       isActive: false,
       userDisabled: true,
       appDisabled: false,
       pendingOperations: 0,
     },
-    // The compatibility update won't be recovered and with strict
-    // compatibility it would not have been able to tell that it was
-    // previously userDisabled. However, without strict compat, it wasn't
-    // appDisabled, so it knows it must have been userDisabled.
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
-  // Would stay incompatible with strict compat
   "addon5@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon5@tests.mozilla.org",
+    manifest: {
       name: "Test 5",
+      applications: {gecko: {id: "addon5@tests.mozilla.org"}},
     },
     desiredState: {
       isActive: true,
       userDisabled: false,
       appDisabled: false,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
-  // Enabled bootstrapped
-  "addon6@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon6@tests.mozilla.org",
-      name: "Test 6",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "2",
-        maxVersion: "2",
-      }],
-    },
-    desiredState: {
-      isActive: true,
-      userDisabled: false,
-      appDisabled: false,
-      pendingOperations: 0,
-    },
-    afterCorruption: {},
-    afterSecondRestart: {},
-  },
-
-  // Disabled bootstrapped
   "addon7@tests.mozilla.org": {
-    "install.rdf": {
-      id: "addon7@tests.mozilla.org",
+    manifest: {
       name: "Test 7",
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "2",
-        maxVersion: "2",
-      }],
+      applications: { gecko: {id: "addon7@tests.mozilla.org"}},
     },
     initialState: {
       userDisabled: true,
     },
     desiredState: {
       isActive: false,
       userDisabled: true,
       appDisabled: false,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
   // The default theme
   "theme1@tests.mozilla.org": {
     manifest: {
       manifest_version: 2,
       name: "Theme 1",
       version: "1.0",
@@ -136,18 +101,16 @@ const ADDONS = {
       },
     },
     desiredState: {
       isActive: false,
       userDisabled: true,
       appDisabled: false,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 
   "theme2@tests.mozilla.org": {
     manifest: {
       manifest_version: 2,
       name: "Theme 2",
       version: "1.0",
       theme: { images: { headerURL: "example.png" } },
@@ -161,43 +124,34 @@ const ADDONS = {
       userDisabled: false,
     },
     desiredState: {
       isActive: true,
       userDisabled: false,
       appDisabled: false,
       pendingOperations: 0,
     },
-    afterCorruption: {},
-    afterSecondRestart: {},
   },
 };
 
 const IDS = Object.keys(ADDONS);
 
 function promiseUpdates(addon) {
   return new Promise(resolve => {
     addon.findUpdates({onUpdateFinished: resolve},
                       AddonManager.UPDATE_WHEN_PERIODIC_UPDATE);
   });
 }
 
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
 add_task(async function setup() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "2");
 
   for (let addon of Object.values(ADDONS)) {
-    if (addon["install.rdf"]) {
-      await promiseWriteInstallRDFForExtension(addon["install.rdf"], profileDir);
-    } else {
-      let webext = createTempWebExtensionFile({manifest: addon.manifest});
-      await AddonTestUtils.manuallyInstall(webext);
-    }
+    let webext = createTempWebExtensionFile({manifest: addon.manifest});
+    await AddonTestUtils.manuallyInstall(webext);
   }
 
   await promiseStartupManager();
 
   let addons = await getAddons(IDS);
   for (let [id, addon] of Object.entries(ADDONS)) {
     if (addon.initialState) {
       await setInitialState(addons.get(id), addon.initialState);
@@ -236,27 +190,25 @@ add_task(async function test_after_corru
     }, "xpi-database-loaded");
     Services.obs.notifyObservers(null, "sessionstore-windows-restored");
   });
 
   // Accessing the add-ons should open and recover the database
   info("Test add-on state after corruption");
   let addons = await getAddons(IDS);
   for (let [id, addon] of Object.entries(ADDONS)) {
-    checkAddon(id, addons.get(id),
-               Object.assign({}, addon.desiredState, addon.afterCorruption));
+    checkAddon(id, addons.get(id), addon.desiredState);
   }
 
   await Assert.rejects(promiseShutdownManager(), OS.File.Error);
 });
 
 add_task(async function test_after_second_restart() {
   await promiseStartupManager();
 
   info("Test add-on state after second restart");
   let addons = await getAddons(IDS);
   for (let [id, addon] of Object.entries(ADDONS)) {
-    checkAddon(id, addons.get(id),
-               Object.assign({}, addon.desiredState, addon.afterSecondRestart));
+    checkAddon(id, addons.get(id), addon.desiredState);
   }
 
   await Assert.rejects(promiseShutdownManager(), OS.File.Error);
 });
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_corruptfile.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// Tests that attempting to install a corrupt XPI file doesn't break the universe
-
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
-add_task(async function setup() {
-  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
-
-  await promiseStartupManager();
-
-  if (TEST_UNPACKED)
-    return run_test_unpacked();
-  return run_test_packed();
-});
-
-// When installing packed we won't detect corruption in the XPI until we attempt
-// to load bootstrap.js so everything will look normal from the outside.
-async function run_test_packed() {
-  prepare_test({
-    "corrupt@tests.mozilla.org": [
-      ["onInstalling", false],
-      ["onInstalled", false],
-    ],
-  }, [
-    "onNewInstall",
-    "onInstallStarted",
-    "onInstallEnded",
-  ]);
-
-  await promiseInstallAllFiles([do_get_file("data/corruptfile.xpi")]);
-  ensure_test_completed();
-
-  let addon = await AddonManager.getAddonByID("corrupt@tests.mozilla.org");
-  Assert.notEqual(addon, null);
-}
-
-// When extracting the corruption will be detected and the add-on fails to
-// install
-async function run_test_unpacked() {
-  prepare_test({
-    "corrupt@tests.mozilla.org": [
-      ["onInstalling", false],
-      "onOperationCancelled",
-    ],
-  }, [
-    "onNewInstall",
-    "onInstallStarted",
-    "onInstallFailed",
-  ]);
-
-  await promiseInstallAllFiles([do_get_file("data/corruptfile.xpi")]);
-  ensure_test_completed();
-
-  // Check the add-on directory isn't left over
-  var addonDir = profileDir.clone();
-  addonDir.append("corrupt@tests.mozilla.org");
-  pathShouldntExist(addonDir);
-
-  // Check the staging directory isn't left over
-  var stageDir = profileDir.clone();
-  stageDir.append("staged");
-  pathShouldntExist(stageDir);
-
-  let addon = await AddonManager.getAddonByID("corrupt@tests.mozilla.org");
-  Assert.equal(addon, null);
-}
--- a/toolkit/mozapps/extensions/test/xpcshell/test_crash_annotation_quoting.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_crash_annotation_quoting.js
@@ -1,48 +1,25 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This verifies that strange characters in an add-on version don't break the
 // crash annotation.
 
-var addon3 = {
-  id: "addon3@tests.mozilla.org",
-  version: "1,0",
-  name: "Test 3",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
-
-var addon4 = {
-  id: "addon4@tests.mozilla.org",
-  version: "1:0",
-  name: "Test 4",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
-
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
 add_task(async function run_test() {
   await promiseStartupManager();
 
-  await promiseInstallXPI(addon3);
-  await promiseInstallXPI(addon4);
-
-  let [a3, a4] = await AddonManager.getAddonsByIDs(["addon3@tests.mozilla.org",
-                                                    "addon4@tests.mozilla.org"]);
+  let n = 1;
+  for (let version in [ "1,0", "1:0" ]) {
+    let id = `addon${n++}@tests.mozilla.org`;
+    await promiseInstallWebExtension({
+      manifest: {
+        version,
+        applications: {gecko: {id}},
+      },
+    });
 
-  Assert.notEqual(a3, null);
-  do_check_in_crash_annotation(addon3.id, addon3.version);
-
-  Assert.notEqual(a4, null);
-  do_check_in_crash_annotation(addon4.id, addon4.version);
+    do_check_in_crash_annotation(id, version);
+  }
 });
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_delay_update.js
+++ /dev/null
@@ -1,363 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// This verifies that delaying an update works
-
-// The test extension uses an insecure update url.
-Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
-
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
-const IGNORE_ID = "test_delay_update_ignore@tests.mozilla.org";
-const COMPLETE_ID = "test_delay_update_complete@tests.mozilla.org";
-const DEFER_ID = "test_delay_update_defer@tests.mozilla.org";
-
-const TEST_IGNORE_PREF = "delaytest.ignore";
-
-// Note that we would normally use BootstrapMonitor but it currently requires
-// the objects in `data` to be serializable, and we need a real reference to the
-// `instanceID` symbol to test.
-
-createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
-
-// Create and configure the HTTP server.
-var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
-testserver.registerDirectory("/data/", do_get_file("data"));
-
-
-const ADDONS = {
-  test_delay_update_complete_v2: {
-    "install.rdf": {
-      "id": "test_delay_update_complete@tests.mozilla.org",
-      "version": "2.0",
-      "name": "Test Delay Update Complete",
-    },
-  },
-  test_delay_update_defer_v2: {
-    "install.rdf": {
-      "id": "test_delay_update_defer@tests.mozilla.org",
-      "version": "2.0",
-      "name": "Test Delay Update Defer",
-    },
-  },
-  test_delay_update_ignore_v2: {
-    "install.rdf": {
-      "id": "test_delay_update_ignore@tests.mozilla.org",
-      "version": "2.0",
-      "name": "Test Delay Update Ignore",
-    },
-  },
-};
-
-const XPIS = {};
-for (let [name, files] of Object.entries(ADDONS)) {
-  XPIS[name] = AddonTestUtils.createTempXPIFile(files);
-  testserver.registerFile(`/addons/${name}.xpi`, XPIS[name]);
-}
-
-async function createIgnoreAddon() {
-  await promiseWriteInstallRDFToXPI({
-    id: IGNORE_ID,
-    version: "1.0",
-    bootstrap: true,
-    unpack: true,
-    updateURL: `http://example.com/data/test_delay_updates_ignore_legacy.json`,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test Delay Update Ignore",
-  }, profileDir, IGNORE_ID, {
-    "bootstrap.js": String.raw`
-      ChromeUtils.import("resource://gre/modules/Services.jsm");
-      ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
-
-      const ADDON_ID = "test_delay_update_ignore@tests.mozilla.org";
-      const TEST_IGNORE_PREF = "delaytest.ignore";
-
-      function install(data, reason) {}
-
-      // normally we would use BootstrapMonitor here, but we need a reference to
-      // the symbol inside XPIProvider.jsm.
-      function startup(data, reason) {
-        Services.prefs.setBoolPref(TEST_IGNORE_PREF, false);
-
-        // explicitly ignore update, will be queued for next restart
-        if (data.hasOwnProperty("instanceID") && data.instanceID) {
-          AddonManager.addUpgradeListener(data.instanceID, (upgrade) => {
-            Services.prefs.setBoolPref(TEST_IGNORE_PREF, true);
-          });
-        } else {
-          throw Error("no instanceID passed to bootstrap startup");
-        }
-      }
-
-      function shutdown(data, reason) {}
-
-      function uninstall(data, reason) {}
-    `,
-  });
-}
-
-async function createCompleteAddon() {
-  await promiseWriteInstallRDFToXPI({
-    id: COMPLETE_ID,
-    version: "1.0",
-    bootstrap: true,
-    unpack: true,
-    updateURL: `http://example.com/data/test_delay_updates_complete_legacy.json`,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test Delay Update Complete",
-  }, profileDir, COMPLETE_ID, {
-    "bootstrap.js": String.raw`
-      ChromeUtils.import("resource://gre/modules/Services.jsm");
-      ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
-
-      const ADDON_ID = "test_delay_update_complete@tests.mozilla.org";
-      const INSTALL_COMPLETE_PREF = "bootstraptest.install_complete_done";
-
-      function install(data, reason) {}
-
-      // normally we would use BootstrapMonitor here, but we need a reference to
-      // the symbol inside XPIProvider.jsm.
-      function startup(data, reason) {
-        // apply update immediately
-        if (data.hasOwnProperty("instanceID") && data.instanceID) {
-          AddonManager.addUpgradeListener(data.instanceID, (upgrade) => {
-            upgrade.install();
-          });
-        } else {
-          throw Error("no instanceID passed to bootstrap startup");
-        }
-      }
-
-      function shutdown(data, reason) {}
-
-      function uninstall(data, reason) {}
-    `,
-  });
-}
-
-async function createDeferAddon() {
-  await promiseWriteInstallRDFToXPI({
-    id: DEFER_ID,
-    version: "1.0",
-    bootstrap: true,
-    unpack: true,
-    updateURL: `http://example.com/data/test_delay_updates_defer_legacy.json`,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test Delay Update Defer",
-  }, profileDir, DEFER_ID, {
-    "bootstrap.js": String.raw`
-      ChromeUtils.import("resource://gre/modules/Services.jsm");
-      ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
-
-      const ADDON_ID = "test_delay_update_complete@tests.mozilla.org";
-      const INSTALL_COMPLETE_PREF = "bootstraptest.install_complete_done";
-
-      // global reference to hold upgrade object
-      let gUpgrade;
-
-      function install(data, reason) {}
-
-      // normally we would use BootstrapMonitor here, but we need a reference to
-      // the symbol inside XPIProvider.jsm.
-      function startup(data, reason) {
-        // do not apply update immediately, hold on to for later
-        if (data.hasOwnProperty("instanceID") && data.instanceID) {
-          AddonManager.addUpgradeListener(data.instanceID, (upgrade) => {
-            gUpgrade = upgrade;
-          });
-        } else {
-          throw Error("no instanceID passed to bootstrap startup");
-        }
-
-        // add a listener so the test can pass control back
-        AddonManager.addAddonListener({
-          onFakeEvent: () => {
-            gUpgrade.install();
-          }
-        });
-      }
-
-      function shutdown(data, reason) {}
-
-      function uninstall(data, reason) {}
-    `,
-  });
-}
-
-// add-on registers upgrade listener, and ignores update.
-add_task(async function() {
-
-  await createIgnoreAddon();
-
-  await promiseStartupManager();
-
-  let addon = await promiseAddonByID(IGNORE_ID);
-  Assert.notEqual(addon, null);
-  Assert.equal(addon.version, "1.0");
-  Assert.equal(addon.name, "Test Delay Update Ignore");
-  Assert.ok(addon.isCompatible);
-  Assert.ok(!addon.appDisabled);
-  Assert.ok(addon.isActive);
-  Assert.equal(addon.type, "extension");
-
-  let update = await promiseFindAddonUpdates(addon);
-  let install = update.updateAvailable;
-
-  await promiseCompleteAllInstalls([install]);
-
-  Assert.equal(install.state, AddonManager.STATE_POSTPONED);
-
-  // addon upgrade has been delayed
-  let addon_postponed = await promiseAddonByID(IGNORE_ID);
-  Assert.notEqual(addon_postponed, null);
-  Assert.equal(addon_postponed.version, "1.0");
-  Assert.equal(addon_postponed.name, "Test Delay Update Ignore");
-  Assert.ok(addon_postponed.isCompatible);
-  Assert.ok(!addon_postponed.appDisabled);
-  Assert.ok(addon_postponed.isActive);
-  Assert.equal(addon_postponed.type, "extension");
-  Assert.ok(Services.prefs.getBoolPref(TEST_IGNORE_PREF));
-
-  // restarting allows upgrade to proceed
-  await promiseRestartManager();
-
-  let addon_upgraded = await promiseAddonByID(IGNORE_ID);
-  Assert.notEqual(addon_upgraded, null);
-  Assert.equal(addon_upgraded.version, "2.0");
-  Assert.equal(addon_upgraded.name, "Test Delay Update Ignore");
-  Assert.ok(addon_upgraded.isCompatible);
-  Assert.ok(!addon_upgraded.appDisabled);
-  Assert.ok(addon_upgraded.isActive);
-  Assert.equal(addon_upgraded.type, "extension");
-
-  await promiseShutdownManager();
-});
-
-// add-on registers upgrade listener, and allows update.
-add_task(async function() {
-
-  await createCompleteAddon();
-
-  await promiseStartupManager();
-
-  let addon = await promiseAddonByID(COMPLETE_ID);
-  Assert.notEqual(addon, null);
-  Assert.equal(addon.version, "1.0");
-  Assert.equal(addon.name, "Test Delay Update Complete");
-  Assert.ok(addon.isCompatible);
-  Assert.ok(!addon.appDisabled);
-  Assert.ok(addon.isActive);
-  Assert.equal(addon.type, "extension");
-
-  let update = await promiseFindAddonUpdates(addon);
-  let install = update.updateAvailable;
-
-  await promiseCompleteAllInstalls([install]);
-
-  // upgrade is initially postponed
-  let addon_postponed = await promiseAddonByID(COMPLETE_ID);
-  Assert.notEqual(addon_postponed, null);
-  Assert.equal(addon_postponed.version, "1.0");
-  Assert.equal(addon_postponed.name, "Test Delay Update Complete");
-  Assert.ok(addon_postponed.isCompatible);
-  Assert.ok(!addon_postponed.appDisabled);
-  Assert.ok(addon_postponed.isActive);
-  Assert.equal(addon_postponed.type, "extension");
-
-  // addon upgrade has been allowed
-  let [addon_allowed] = await promiseAddonEvent("onInstalled");
-  Assert.notEqual(addon_allowed, null);
-  Assert.equal(addon_allowed.version, "2.0");
-  Assert.equal(addon_allowed.name, "Test Delay Update Complete");
-  Assert.ok(addon_allowed.isCompatible);
-  Assert.ok(!addon_allowed.appDisabled);
-  Assert.ok(addon_allowed.isActive);
-  Assert.equal(addon_allowed.type, "extension");
-
-  // restarting changes nothing
-  await promiseRestartManager();
-
-  let addon_upgraded = await promiseAddonByID(COMPLETE_ID);
-  Assert.notEqual(addon_upgraded, null);
-  Assert.equal(addon_upgraded.version, "2.0");
-  Assert.equal(addon_upgraded.name, "Test Delay Update Complete");
-  Assert.ok(addon_upgraded.isCompatible);
-  Assert.ok(!addon_upgraded.appDisabled);
-  Assert.ok(addon_upgraded.isActive);
-  Assert.equal(addon_upgraded.type, "extension");
-
-  await promiseShutdownManager();
-});
-
-// add-on registers upgrade listener, initially defers update then allows upgrade
-add_task(async function() {
-
-  await createDeferAddon();
-
-  await promiseStartupManager();
-
-  let addon = await promiseAddonByID(DEFER_ID);
-  Assert.notEqual(addon, null);
-  Assert.equal(addon.version, "1.0");
-  Assert.equal(addon.name, "Test Delay Update Defer");
-  Assert.ok(addon.isCompatible);
-  Assert.ok(!addon.appDisabled);
-  Assert.ok(addon.isActive);
-  Assert.equal(addon.type, "extension");
-
-  let update = await promiseFindAddonUpdates(addon);
-  let install = update.updateAvailable;
-
-  await promiseCompleteAllInstalls([install]);
-
-  // upgrade is initially postponed
-  let addon_postponed = await promiseAddonByID(DEFER_ID);
-  Assert.notEqual(addon_postponed, null);
-  Assert.equal(addon_postponed.version, "1.0");
-  Assert.equal(addon_postponed.name, "Test Delay Update Defer");
-  Assert.ok(addon_postponed.isCompatible);
-  Assert.ok(!addon_postponed.appDisabled);
-  Assert.ok(addon_postponed.isActive);
-  Assert.equal(addon_postponed.type, "extension");
-
-  // add-on will not allow upgrade until fake event fires
-  AddonManagerPrivate.callAddonListeners("onFakeEvent");
-
-  // addon upgrade has been allowed
-  let [addon_allowed] = await promiseAddonEvent("onInstalled");
-  Assert.notEqual(addon_allowed, null);
-  Assert.equal(addon_allowed.version, "2.0");
-  Assert.equal(addon_allowed.name, "Test Delay Update Defer");
-  Assert.ok(addon_allowed.isCompatible);
-  Assert.ok(!addon_allowed.appDisabled);
-  Assert.ok(addon_allowed.isActive);
-  Assert.equal(addon_allowed.type, "extension");
-
-  // restarting changes nothing
-  await promiseRestartManager();
-
-  let addon_upgraded = await promiseAddonByID(DEFER_ID);
-  Assert.notEqual(addon_upgraded, null);
-  Assert.equal(addon_upgraded.version, "2.0");
-  Assert.equal(addon_upgraded.name, "Test Delay Update Defer");
-  Assert.ok(addon_upgraded.isCompatible);
-  Assert.ok(!addon_upgraded.appDisabled);
-  Assert.ok(addon_upgraded.isActive);
-  Assert.equal(addon_upgraded.type, "extension");
-
-  await promiseShutdownManager();
-});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_dependencies.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_dependencies.js
@@ -2,128 +2,107 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
 
-const BOOTSTRAP = String.raw`
-  Components.utils.import("resource://gre/modules/Services.jsm");
-
-  function startup(data) {
-    Services.obs.notifyObservers(null, "test-addon-bootstrap-startup", data.id);
-  }
-  function shutdown(data) {
-    Services.obs.notifyObservers(null, "test-addon-bootstrap-shutdown", data.id);
-  }
-  function install() {}
-  function uninstall() {}
-`;
-
 const ADDONS = [
   {
-    id: "addon1@dependency-test.mozilla.org",
-    dependencies: ["addon2@dependency-test.mozilla.org"],
+    id: "addon1@experiments.addons.mozilla.org",
+    dependencies: ["experiments.addon2"],
   },
   {
-    id: "addon2@dependency-test.mozilla.org",
-    dependencies: ["addon3@dependency-test.mozilla.org"],
+    id: "addon2@experiments.addons.mozilla.org",
+    dependencies: ["experiments.addon3"],
   },
   {
-    id: "addon3@dependency-test.mozilla.org",
+    id: "addon3@experiments.addons.mozilla.org",
   },
   {
-    id: "addon4@dependency-test.mozilla.org",
+    id: "addon4@experiments.addons.mozilla.org",
   },
   {
-    id: "addon5@dependency-test.mozilla.org",
-    dependencies: ["addon2@dependency-test.mozilla.org"],
+    id: "addon5@experiments.addons.mozilla.org",
+    dependencies: ["experiments.addon2"],
   },
 ];
 
 let addonFiles = [];
 
 let events = [];
+
 add_task(async function setup() {
   await promiseStartupManager();
 
-  let startupObserver = (subject, topic, data) => {
-    events.push(["startup", data]);
-  };
-  let shutdownObserver = (subject, topic, data) => {
-    events.push(["shutdown", data]);
+  const onBootstrapMethod = (event, {method, params}) => {
+    if (method == "startup" || method == "shutdown") {
+      events.push([method, params.id]);
+    }
   };
 
-  Services.obs.addObserver(startupObserver, "test-addon-bootstrap-startup");
-  Services.obs.addObserver(shutdownObserver, "test-addon-bootstrap-shutdown");
+  AddonTestUtils.on("bootstrap-method", onBootstrapMethod);
   registerCleanupFunction(() => {
-    Services.obs.removeObserver(startupObserver, "test-addon-bootstrap-startup");
-    Services.obs.removeObserver(shutdownObserver, "test-addon-bootstrap-shutdown");
+    AddonTestUtils.off("bootstrap-method", onBootstrapMethod);
   });
 
   for (let addon of ADDONS) {
-    Object.assign(addon, {
-      targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "1",
-        maxVersion: "1",
-      }],
-      version: "1.0",
-      name: addon.id,
-      bootstrap: true,
-    });
+    let manifest = {
+      applications: {gecko: {id: addon.id}},
+      permissions: addon.dependencies,
+    };
 
-    addonFiles.push(createTempXPIFile(addon, {"bootstrap.js": BOOTSTRAP}));
+    addonFiles.push(await createTempWebExtensionFile({manifest}));
   }
 });
 
 add_task(async function() {
   deepEqual(events, [], "Should have no events");
 
-  await promiseInstallAllFiles([addonFiles[3]]);
+  await promiseInstallFile(addonFiles[3]);
 
   deepEqual(events, [
     ["startup", ADDONS[3].id],
   ]);
 
   events.length = 0;
 
-  await promiseInstallAllFiles([addonFiles[0]]);
+  await promiseInstallFile(addonFiles[0]);
   deepEqual(events, [], "Should have no events");
 
-  await promiseInstallAllFiles([addonFiles[1]]);
+  await promiseInstallFile(addonFiles[1]);
   deepEqual(events, [], "Should have no events");
 
-  await promiseInstallAllFiles([addonFiles[2]]);
+  await promiseInstallFile(addonFiles[2]);
 
   deepEqual(events, [
     ["startup", ADDONS[2].id],
     ["startup", ADDONS[1].id],
     ["startup", ADDONS[0].id],
   ]);
 
   events.length = 0;
 
-  await promiseInstallAllFiles([addonFiles[2]]);
+  await promiseInstallFile(addonFiles[2]);
 
   deepEqual(events, [
     ["shutdown", ADDONS[0].id],
     ["shutdown", ADDONS[1].id],
     ["shutdown", ADDONS[2].id],
 
     ["startup", ADDONS[2].id],
     ["startup", ADDONS[1].id],
     ["startup", ADDONS[0].id],
   ]);
 
   events.length = 0;
 
-  await promiseInstallAllFiles([addonFiles[4]]);
+  await promiseInstallFile(addonFiles[4]);
 
   deepEqual(events, [
     ["startup", ADDONS[4].id],
   ]);
 
   events.length = 0;
 
   await promiseRestartManager();
@@ -136,10 +115,12 @@ add_task(async function() {
     ["shutdown", ADDONS[2].id],
 
     ["startup", ADDONS[2].id],
     ["startup", ADDONS[1].id],
     ["startup", ADDONS[0].id],
     ["startup", ADDONS[3].id],
     ["startup", ADDONS[4].id],
   ]);
+
+  await promiseShutdownManager();
 });
 
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js
+++ /dev/null
@@ -1,590 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// This verifies that bootstrappable add-ons can be used without restarts.
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-Cu.importGlobalProperties(["XMLHttpRequest"]);
-
-// Our stub hunspell engine makes things a bit flaky.
-PromiseTestUtils.whitelistRejectionsGlobally(/spellCheck is undefined/);
-
-// Enable loading extensions from the user scopes
-Services.prefs.setIntPref("extensions.enabledScopes",
-                          AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_USER);
-
-// The test extension uses an insecure update url.
-Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
-
-createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
-
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
-const userExtDir = gProfD.clone();
-userExtDir.append("extensions2");
-userExtDir.append(gAppInfo.ID);
-
-registerDirectory("XREUSysExt", userExtDir.parent);
-
-// Create and configure the HTTP server.
-var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
-
-// register files with server
-testserver.registerDirectory("/data/", do_get_file("data"));
-
-const ADDONS = {
-  test_dictionary: {
-    "install.rdf": {
-      "id": "ab-CD@dictionaries.addons.mozilla.org",
-      "type": "64",
-      "name": "Test Dictionary",
-    },
-    "dictionaries/ab-CD.dic": "1\ntest1\n",
-    "chrome.manifest": "content dict ./\n",
-  },
-  test_dictionary_3: {
-    "install.rdf": {
-      "id": "ab-CD@dictionaries.addons.mozilla.org",
-      "version": "2.0",
-      "type": "64",
-      "name": "Test Dictionary",
-    },
-  },
-  test_dictionary_4: {
-    "install.rdf": {
-      "id": "ef@dictionaries.addons.mozilla.org",
-      "version": "2.0",
-      "name": "Test Dictionary ef",
-    },
-  },
-  test_dictionary_5: {
-    "install.rdf": {
-      "id": "gh@dictionaries.addons.mozilla.org",
-      "version": "2.0",
-      "type": "64",
-      "name": "Test Dictionary gh",
-    },
-  },
-};
-
-const ID_DICT = "ab-CD@dictionaries.addons.mozilla.org";
-const XPI_DICT = AddonTestUtils.createTempXPIFile(ADDONS.test_dictionary);
-
-const XPIS = {};
-for (let [name, files] of Object.entries(ADDONS)) {
-  XPIS[name] = AddonTestUtils.createTempXPIFile(files);
-  testserver.registerFile(`/addons/${name}.xpi`, XPIS[name]);
-}
-
-/**
- * This object is both a factory and an mozISpellCheckingEngine implementation (so, it
- * is de-facto a service). It's also an interface requestor that gives out
- * itself when asked for mozISpellCheckingEngine.
- */
-var HunspellEngine = {
-  dictionaryURIs: new Map(),
-  listener: null,
-
-  QueryInterface: ChromeUtils.generateQI(["nsIFactory", "mozISpellCheckingEngine"]),
-  createInstance: function hunspell_ci(outer, iid) {
-    if (outer)
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    return this.QueryInterface(iid);
-  },
-  lockFactory: function hunspell_lockf(lock) {
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-  },
-
-  addDictionary(lang, uri) {
-    this.dictionaryURIs.set(lang, uri);
-    if (this.listener)
-      this.listener("addDictionary");
-  },
-
-  removeDictionary(lang, uri) {
-    this.dictionaryURIs.delete(lang);
-    if (this.listener)
-      this.listener("removeDictionary");
-  },
-
-  getInterface: function hunspell_gi(iid) {
-    if (iid.equals(Ci.mozISpellCheckingEngine))
-      return this;
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
-
-  contractID: "@mozilla.org/spellchecker/engine;1",
-  classID: Components.ID("{6f3c63bc-a4fd-449b-9a58-a2d9bd972cce}"),
-
-  activate: function hunspell_activate() {
-    this.origClassID = Components.manager.nsIComponentRegistrar
-      .contractIDToCID(this.contractID);
-    this.origFactory = Components.manager
-      .getClassObject(Cc[this.contractID],
-                      Ci.nsIFactory);
-
-    Components.manager.nsIComponentRegistrar
-      .unregisterFactory(this.origClassID, this.origFactory);
-    Components.manager.nsIComponentRegistrar.registerFactory(this.classID,
-      "Test hunspell", this.contractID, this);
-  },
-
-  deactivate: function hunspell_deactivate() {
-    Components.manager.nsIComponentRegistrar.unregisterFactory(this.classID, this);
-    Components.manager.nsIComponentRegistrar.registerFactory(this.origClassID,
-      "Hunspell", this.contractID, this.origFactory);
-  },
-
-  isDictionaryEnabled: function hunspell_isDictionaryEnabled(name) {
-    let uri = this.dictionaryURIs.get(name.replace(/\.dic$/, ""));
-    if (!uri) {
-      return false;
-    }
-    try {
-      let xhr = new XMLHttpRequest();
-      xhr.open("GET", uri.spec.replace(/\.aff$/, ".dic"), false);
-      xhr.send();
-      return true;
-    } catch (e) {
-      Cu.reportError(e);
-    }
-    return false;
-  },
-};
-
-add_task(async function setup() {
-  await promiseStartupManager();
-
-  // Starts collecting the Addon Manager Telemetry events.
-  AddonTestUtils.hookAMTelemetryEvents();
-});
-
-// Tests that installing doesn't require a restart
-add_task(async function test_1() {
-  prepare_test({ }, [
-    "onNewInstall",
-  ]);
-
-  HunspellEngine.activate();
-
-  let install = await AddonManager.getInstallForFile(XPI_DICT);
-  ensure_test_completed();
-
-  notEqual(install, null);
-  equal(install.type, "dictionary");
-  equal(install.version, "1.0");
-  equal(install.name, "Test Dictionary");
-  equal(install.state, AddonManager.STATE_DOWNLOADED);
-  equal(install.addon.operationsRequiringRestart &
-               AddonManager.OP_NEEDS_RESTART_INSTALL, 0);
-  do_check_not_in_crash_annotation(ID_DICT, "1.0");
-
-  await new Promise(resolve => {
-    prepare_test({
-      [ID_DICT]: [
-        ["onInstalling", false],
-        "onInstalled",
-      ],
-    }, [
-      "onInstallStarted",
-      "onInstallEnded",
-    ], function() {
-      HunspellEngine.listener = function(aEvent) {
-        HunspellEngine.listener = null;
-        equal(aEvent, "addDictionary");
-        resolve();
-      };
-    });
-    install.install();
-  });
-
-  let installs = await AddonManager.getAllInstalls();
-  // There should be no active installs now since the install completed and
-  // doesn't require a restart.
-  equal(installs.length, 0);
-
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(!addon.appDisabled);
-  ok(!addon.userDisabled);
-  ok(addon.isActive);
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  do_check_in_crash_annotation(ID_DICT, "1.0");
-
-  let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
-                  getService(Ci.nsIChromeRegistry);
-  try {
-    chromeReg.convertChromeURL(NetUtil.newURI("chrome://dict/content/dict.xul"));
-    do_throw("Chrome manifest should not have been registered");
-  } catch (e) {
-    // Expected the chrome url to not be registered
-  }
-
-  // Test the collected telemetry events.
-  let amEvents = AddonTestUtils.getAMTelemetryEvents().filter(evt => {
-    return evt.method === "install" && evt.object === "dictionary";
-  }).map(evt => {
-    // collect only the remaining event properties (just the extra vars) to run assertions on them.
-    return evt.extra;
-  });
-
-  Assert.deepEqual(amEvents, [
-    {step: "started", addon_id: addon.id},
-    {step: "completed", addon_id: addon.id},
-  ], "Got the expected telemetry events");
-});
-
-// Tests that disabling doesn't require a restart
-add_task(async function test_2() {
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  prepare_test({
-    [ID_DICT]: [
-      ["onDisabling", false],
-      "onDisabled",
-    ],
-  });
-
-  equal(addon.operationsRequiringRestart &
-               AddonManager.OP_NEEDS_RESTART_DISABLE, 0);
-  await addon.disable();
-  ensure_test_completed();
-
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(!addon.appDisabled);
-  ok(addon.userDisabled);
-  ok(!addon.isActive);
-  ok(!HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  do_check_not_in_crash_annotation(ID_DICT, "1.0");
-
-  addon = await AddonManager.getAddonByID(ID_DICT);
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(!addon.appDisabled);
-  ok(addon.userDisabled);
-  ok(!addon.isActive);
-
-  // Test the collected telemetry events.
-  let amEvents = AddonTestUtils.getAMTelemetryEvents().filter(evt => {
-    return evt.object === "dictionary";
-  });
-
-  Assert.deepEqual(amEvents, [
-    {method: "disable", object: "dictionary", value: addon.id, extra: null},
-  ], "Got the expected telemetry events");
-});
-
-// Test that restarting doesn't accidentally re-enable
-add_task(async function test_3() {
-  await promiseShutdownManager();
-  ok(!HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  await promiseStartupManager();
-
-  ok(!HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  do_check_not_in_crash_annotation(ID_DICT, "1.0");
-
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(!addon.appDisabled);
-  ok(addon.userDisabled);
-  ok(!addon.isActive);
-});
-
-// Tests that enabling doesn't require a restart
-add_task(async function test_4() {
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  prepare_test({
-    [ID_DICT]: [
-      ["onEnabling", false],
-      "onEnabled",
-    ],
-  });
-
-  equal(addon.operationsRequiringRestart &
-               AddonManager.OP_NEEDS_RESTART_ENABLE, 0);
-  await addon.enable();
-  ensure_test_completed();
-
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(!addon.appDisabled);
-  ok(!addon.userDisabled);
-  ok(addon.isActive);
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  do_check_in_crash_annotation(ID_DICT, "1.0");
-
-  addon = await AddonManager.getAddonByID(ID_DICT);
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(!addon.appDisabled);
-  ok(!addon.userDisabled);
-  ok(addon.isActive);
-});
-
-// Tests that a restart shuts down and restarts the add-on
-add_task(async function test_5() {
-  await promiseShutdownManager();
-
-  // We don't unregister dictionaries at app shutdown, so the dictionary
-  // will still be registered at this point.
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  do_check_not_in_crash_annotation(ID_DICT, "1.0");
-
-  await promiseStartupManager();
-
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  do_check_in_crash_annotation(ID_DICT, "1.0");
-
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(!addon.appDisabled);
-  ok(!addon.userDisabled);
-  ok(addon.isActive);
-});
-
-// Tests that uninstalling doesn't require a restart
-add_task(async function test_7() {
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  prepare_test({
-    [ID_DICT]: [
-      ["onUninstalling", false],
-      "onUninstalled",
-    ],
-  });
-
-  equal(addon.operationsRequiringRestart &
-               AddonManager.OP_NEEDS_RESTART_UNINSTALL, 0);
-  await addon.uninstall();
-
-  ensure_test_completed();
-
-  ok(!HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  do_check_not_in_crash_annotation(ID_DICT, "1.0");
-
-  addon = await AddonManager.getAddonByID(ID_DICT);
-  equal(addon, null);
-
-  await promiseRestartManager();
-
-  addon = await AddonManager.getAddonByID(ID_DICT);
-  equal(addon, null);
-});
-
-// Test that a bootstrapped extension dropped into the profile loads properly
-// on startup and doesn't cause an EM restart
-add_task(async function test_8() {
-  await promiseShutdownManager();
-  await AddonTestUtils.manuallyInstall(XPI_DICT);
-  await promiseStartupManager();
-
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(!addon.appDisabled);
-  ok(!addon.userDisabled);
-  ok(addon.isActive);
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  do_check_in_crash_annotation(ID_DICT, "1.0");
-});
-
-// Test that items detected as removed during startup get removed properly
-add_task(async function test_9() {
-  await promiseShutdownManager();
-  await AddonTestUtils.manuallyUninstall(profileDir, ID_DICT);
-  await promiseStartupManager();
-
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  equal(addon, null);
-  do_check_not_in_crash_annotation(ID_DICT, "1.0");
-});
-
-
-// Tests that bootstrapped extensions are correctly loaded even if the app is
-// upgraded at the same time
-add_task(async function test_12() {
-  await promiseShutdownManager();
-  await AddonTestUtils.manuallyInstall(XPI_DICT);
-  await promiseStartupManager();
-
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(!addon.appDisabled);
-  ok(!addon.userDisabled);
-  ok(addon.isActive);
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  do_check_in_crash_annotation(ID_DICT, "1.0");
-
-  await addon.uninstall();
-});
-
-
-// Tests that bootstrapped extensions don't get loaded when in safe mode
-add_task(async function test_16() {
-  await promiseRestartManager();
-  await promiseInstallFile(XPI_DICT);
-
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  // Should have installed and started
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-
-  await promiseShutdownManager();
-
-  // We don't unregister dictionaries at app shutdown, so the dictionary
-  // will still be registered at this point.
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-
-  HunspellEngine.dictionaryURIs.delete("ab-CD");
-
-  gAppInfo.inSafeMode = true;
-  await promiseStartupManager();
-
-  addon = await AddonManager.getAddonByID(ID_DICT);
-  // Should still be stopped
-  ok(!HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  ok(!addon.isActive);
-
-  await promiseShutdownManager();
-  gAppInfo.inSafeMode = false;
-  await promiseStartupManager();
-
-  // Should have started
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-
-  addon = await AddonManager.getAddonByID(ID_DICT);
-  await addon.uninstall();
-});
-
-// Check that a bootstrapped extension in a non-profile location is loaded
-add_task(async function test_17() {
-  await promiseShutdownManager();
-  await AddonTestUtils.manuallyInstall(XPI_DICT, userExtDir);
-  await promiseStartupManager();
-
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  // Should have installed and started
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(addon.isActive);
-
-  await AddonTestUtils.manuallyUninstall(userExtDir, ID_DICT);
-  await promiseRestartManager();
-});
-
-// Tests that installing from a URL doesn't require a restart
-add_task(async function test_23() {
-  prepare_test({ }, [
-    "onNewInstall",
-  ]);
-
-  let url = "http://example.com/addons/test_dictionary.xpi";
-  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  ensure_test_completed();
-
-  notEqual(install, null);
-
-  await new Promise(resolve => {
-    prepare_test({ }, [
-      "onDownloadStarted",
-      "onDownloadEnded",
-    ], function() {
-      equal(install.type, "dictionary");
-      equal(install.version, "1.0");
-      equal(install.name, "Test Dictionary");
-      equal(install.state, AddonManager.STATE_DOWNLOADED);
-      equal(install.addon.operationsRequiringRestart &
-                   AddonManager.OP_NEEDS_RESTART_INSTALL, 0);
-      do_check_not_in_crash_annotation(ID_DICT, "1.0");
-
-      prepare_test({
-        [ID_DICT]: [
-          ["onInstalling", false],
-          "onInstalled",
-        ],
-      }, [
-        "onInstallStarted",
-        "onInstallEnded",
-      ], resolve);
-    });
-    install.install();
-  });
-
-  let installs = await AddonManager.getAllInstalls();
-  // There should be no active installs now since the install completed and
-  // doesn't require a restart.
-  equal(installs.length, 0);
-
-  let addon = await AddonManager.getAddonByID(ID_DICT);
-  notEqual(addon, null);
-  equal(addon.version, "1.0");
-  ok(!addon.appDisabled);
-  ok(!addon.userDisabled);
-  ok(addon.isActive);
-  ok(HunspellEngine.isDictionaryEnabled("ab-CD.dic"));
-  do_check_in_crash_annotation(ID_DICT, "1.0");
-
-  await promiseRestartManager();
-
-  addon = await AddonManager.getAddonByID(ID_DICT);
-  await addon.uninstall();
-});
-
-// Tests that an update check from a bootstrappable add-on to a bootstrappable add-on works
-add_task(async function test_29() {
-  await promiseRestartManager();
-
-  await promiseWriteInstallRDFForExtension({
-    id: "gh@dictionaries.addons.mozilla.org",
-    version: "1.0",
-    type: "64",
-    updateURL: "http://example.com/data/test_dictionary.json",
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test Dictionary gh",
-  }, profileDir);
-
-  await promiseRestartManager();
-
-  await new Promise(resolve => {
-    prepare_test({
-      "gh@dictionaries.addons.mozilla.org": [
-        ["onInstalling", false /* = no restart */],
-        ["onInstalled", false],
-      ],
-    }, [
-      "onNewInstall",
-      "onDownloadStarted",
-      "onDownloadEnded",
-      "onInstallStarted",
-      "onInstallEnded",
-    ], resolve);
-
-    AddonManagerPrivate.backgroundUpdateCheck();
-  });
-
-  let addon = await AddonManager.getAddonByID("gh@dictionaries.addons.mozilla.org");
-  notEqual(addon, null);
-  equal(addon.version, "2.0");
-  equal(addon.type, "dictionary");
-
-  await new Promise(resolve => {
-    prepare_test({
-      "gh@dictionaries.addons.mozilla.org": [
-        ["onUninstalling", false],
-        ["onUninstalled", false],
-      ],
-    }, [
-    ], resolve);
-
-    addon.uninstall();
-  });
-});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js
@@ -139,69 +139,12 @@ SFX A   0       en         [^elr]
 
   await addon.uninstall();
 
   await new Promise(executeSoon);
 
   ok(!spellCheck.check(WORD), "Word should not pass check after add-on unloads");
 });
 
-// Tests that existing unpacked dictionaries are migrated to
-// WebExtension dictionaries on schema bump.
-add_task(async function test_migration() {
-  let profileDir = gProfD.clone();
-  profileDir.append("extensions");
-
-  await promiseShutdownManager();
-
-  const ID = "en-US@dictionaries.mozilla.org";
-  await promiseWriteInstallRDFToDir({
-    id: ID,
-    type: "64",
-    version: "1.0",
-    targetApplications: [{
-        id: "xpcshell@tests.mozilla.org",
-        minVersion: "61",
-        maxVersion: "61.*"}],
-  }, profileDir, ID, {
-    "dictionaries/en-US.dic": `1\n${WORD}\n`,
-    "dictionaries/en-US.aff": "",
-  });
-
-  await promiseStartupManager();
-
-  ok(spellCheck.check(WORD), "Word should pass check after initial load");
-
-  var {XPIDatabase, XPIProvider, XPIStates} = ChromeUtils.import("resource://gre/modules/addons/XPIProvider.jsm", null);
-
-  let addon = await XPIDatabase.getVisibleAddonForID(ID);
-  let state = XPIStates.findAddon(ID);
-
-  // Mangle the add-on state to match what an unpacked dictionary looked
-  // like in older versions.
-  XPIDatabase.setAddonProperties(addon, {
-    startupData: null,
-    type: "dictionary",
-  });
-
-  state.type = "dictionary";
-  state.startupData = null;
-  XPIStates.save();
-
-  // Dictionary add-ons usually do not unregister dictionaries at app
-  // shutdown, so force them to here.
-  XPIProvider.activeAddons.get(ID).scope.shutdown(0);
-  await promiseShutdownManager();
-
-  ok(!spellCheck.check(WORD), "Word should not pass check while add-on manager is shut down");
-
-  // Drop the schema version to the last one that supported legacy
-  // dictionaries.
-  Services.prefs.setIntPref("extensions.databaseSchema", 25);
-  await promiseStartupManager();
-
-  ok(spellCheck.check(WORD), "Word should pass check while add-on load is loaded");
-});
-
 add_task(function teardown_telemetry_events() {
   // Ignore any additional telemetry events collected in this file.
   AddonTestUtils.getAMTelemetryEvents();
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_distribution.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_distribution.js
@@ -12,208 +12,104 @@ createAppInfo("xpcshell@tests.mozilla.or
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 const distroDir = gProfD.clone();
 distroDir.append("distribution");
 distroDir.append("extensions");
 registerDirectory("XREAppDist", distroDir.parent);
 
-const ADDONS = {
-  test_distribution1_2: {
-    "install.rdf": {
-      "id": "addon1@tests.mozilla.org",
-      "version": "2.0",
-      "name": "Distributed add-ons test",
-    },
-  },
-};
-
-var addon1_1 = {
-  id: "addon1@tests.mozilla.org",
-  version: "1.0",
-  name: "Test version 1",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "5",
-  }],
-};
-
-var addon1_2 = {
-  id: "addon1@tests.mozilla.org",
-  version: "2.0",
-  name: "Test version 2",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "5",
-  }],
-};
-
-var addon1_3 = {
-  id: "addon1@tests.mozilla.org",
-  version: "3.0",
-  name: "Test version 3",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "5",
-  }],
-};
-
 async function setOldModificationTime() {
   // Make sure the installed extension has an old modification time so any
   // changes will be detected
   await promiseShutdownManager();
   let extension = gProfD.clone();
   extension.append("extensions");
-  extension.append("addon1@tests.mozilla.org.xpi");
+  extension.append(`${ID}.xpi`);
   setExtensionModifiedTime(extension, Date.now() - MAKE_FILE_OLD_DIFFERENCE);
   await promiseStartupManager();
 }
 
-function run_test() {
-  do_test_pending();
+const ID = "addon@tests.mozilla.org";
 
-  run_test_1();
+async function writeDistroAddon(version) {
+  let xpi = await createTempWebExtensionFile({
+    manifest: {
+      version,
+      applications: {gecko: {id: ID}},
+    },
+  });
+  xpi.copyTo(distroDir, `${ID}.xpi`);
 }
 
-// Tests that on the first startup the add-on gets installed, with now as the
-// profile modifiedTime.
-async function run_test_1() {
-  let extension = await promiseWriteInstallRDFForExtension(addon1_1, distroDir);
-  setExtensionModifiedTime(extension, Date.now() - MAKE_FILE_OLD_DIFFERENCE);
-
+// Tests that on the first startup the add-on gets installed
+add_task(async function run_test_1() {
+  await writeDistroAddon("1.0");
   await promiseStartupManager();
 
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let a1 = await AddonManager.getAddonByID(ID);
   Assert.notEqual(a1, null);
   Assert.equal(a1.version, "1.0");
   Assert.ok(a1.isActive);
   Assert.equal(a1.scope, AddonManager.SCOPE_PROFILE);
   Assert.ok(!a1.foreignInstall);
-
-  // Modification time should be updated when the addon is copied to the
-  // profile.
-  let testURI = a1.getResourceURI(TEST_UNPACKED ? "install.rdf" : "");
-  let testFile = testURI.QueryInterface(Ci.nsIFileURL).file;
-
-  Assert.ok(testFile.exists());
-  let difference = testFile.lastModifiedTime - Date.now();
-  Assert.ok(Math.abs(difference) < MAX_TIME_DIFFERENCE);
-
-  executeSoon(run_test_2);
-}
+});
 
 // Tests that starting with a newer version in the distribution dir doesn't
 // install it yet
-async function run_test_2() {
+add_task(async function run_test_2() {
   await setOldModificationTime();
 
-  await promiseWriteInstallRDFForExtension(addon1_2, distroDir);
-
+  await writeDistroAddon("2.0");
   await promiseRestartManager();
 
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let a1 = await AddonManager.getAddonByID(ID);
   Assert.notEqual(a1, null);
   Assert.equal(a1.version, "1.0");
   Assert.ok(a1.isActive);
   Assert.equal(a1.scope, AddonManager.SCOPE_PROFILE);
-
-  executeSoon(run_test_3);
-}
+});
 
 // Test that an app upgrade installs the newer version
-async function run_test_3() {
+add_task(async function run_test_3() {
   await promiseRestartManager("2");
 
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let a1 = await AddonManager.getAddonByID(ID);
   Assert.notEqual(a1, null);
   Assert.equal(a1.version, "2.0");
   Assert.ok(a1.isActive);
   Assert.equal(a1.scope, AddonManager.SCOPE_PROFILE);
   Assert.ok(!a1.foreignInstall);
-
-  executeSoon(run_test_4);
-}
+});
 
 // Test that an app upgrade doesn't downgrade the extension
-async function run_test_4() {
+add_task(async function run_test_4() {
   await setOldModificationTime();
 
-  await promiseWriteInstallRDFForExtension(addon1_1, distroDir);
-
+  await writeDistroAddon("1.0");
   await promiseRestartManager("3");
 
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let a1 = await AddonManager.getAddonByID(ID);
   Assert.notEqual(a1, null);
   Assert.equal(a1.version, "2.0");
   Assert.ok(a1.isActive);
   Assert.equal(a1.scope, AddonManager.SCOPE_PROFILE);
-
-  executeSoon(run_test_5);
-}
+});
 
 // Tests that after uninstalling a restart doesn't re-install the extension
-async function run_test_5() {
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+add_task(async function run_test_5() {
+  let a1 = await AddonManager.getAddonByID(ID);
   await a1.uninstall();
 
   await promiseRestartManager();
 
-  let a1_2 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let a1_2 = await AddonManager.getAddonByID(ID);
   Assert.equal(a1_2, null);
-
-  executeSoon(run_test_6);
-}
+});
 
 // Tests that upgrading the application still doesn't re-install the uninstalled
 // extension
-async function run_test_6() {
+add_task(async function run_test_6() {
   await promiseRestartManager("4");
 
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let a1 = await AddonManager.getAddonByID(ID);
   Assert.equal(a1, null);
-
-  executeSoon(run_test_7);
-}
-
-// Tests that a pending install of a newer version of a distributed add-on
-// at app change still gets applied
-async function run_test_7() {
-  Services.prefs.clearUserPref("extensions.installedDistroAddon.addon1@tests.mozilla.org");
-
-  await AddonTestUtils.promiseInstallXPI(ADDONS.test_distribution1_2);
-  await promiseRestartManager(2);
-
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
-  Assert.notEqual(a1, null);
-  Assert.equal(a1.version, "2.0");
-  Assert.ok(a1.isActive);
-  Assert.equal(a1.scope, AddonManager.SCOPE_PROFILE);
-
-  await a1.uninstall();
-  executeSoon(run_test_8);
-}
-
-// Tests that a pending install of a older version of a distributed add-on
-// at app change gets replaced by the distributed version
-async function run_test_8() {
-  await promiseRestartManager();
-
-  await promiseWriteInstallRDFForExtension(addon1_3, distroDir);
-
-  await AddonTestUtils.promiseInstallXPI(ADDONS.test_distribution1_2);
-  await promiseRestartManager(3);
-
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
-  Assert.notEqual(a1, null);
-  Assert.equal(a1.version, "3.0");
-  Assert.ok(a1.isActive);
-  Assert.equal(a1.scope, AddonManager.SCOPE_PROFILE);
-
-  await a1.uninstall();
-  executeSoon(do_test_finished);
-}
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_error.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_error.js
@@ -1,93 +1,76 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests that various error conditions are handled correctly
 
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
-const ADDONS = {
-  test_bug567173: {
-    "install.rdf": {
-      "id": "bug567173",
-    },
-  },
-};
-
-async function run_test() {
-  do_test_pending();
+add_task(async function setup() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
   await promiseStartupManager();
-
-  run_test_1();
-}
+});
 
 // Checks that a local file validates ok
-async function run_test_1() {
-  let install = await AddonManager.getInstallForFile(do_get_file("data/unsigned.xpi"));
+add_task(async function run_test_1() {
+  let xpi = await createTempWebExtensionFile({});
+  let install = await AddonManager.getInstallForFile(xpi);
   Assert.notEqual(install, null);
   Assert.equal(install.state, AddonManager.STATE_DOWNLOADED);
   Assert.equal(install.error, 0);
 
   install.cancel();
+});
 
-  run_test_2();
-}
 
 // Checks that a corrupt file shows an error
-async function run_test_2() {
-  let install = await AddonManager.getInstallForFile(do_get_file("data/corrupt.xpi"));
+add_task(async function run_test_2() {
+  let xpi = AddonTestUtils.allocTempXPIFile();
+  await OS.File.writeAtomic(xpi.path, new TextEncoder().encode("this is not a zip file"));
+
+  let install = await AddonManager.getInstallForFile(xpi);
   Assert.notEqual(install, null);
   Assert.equal(install.state, AddonManager.STATE_DOWNLOAD_FAILED);
   Assert.equal(install.error, AddonManager.ERROR_CORRUPT_FILE);
-
-  run_test_3();
-}
+});
 
 // Checks that an empty file shows an error
-async function run_test_3() {
-  let install = await AddonManager.getInstallForFile(do_get_file("data/empty.xpi"));
+add_task(async function run_test_3() {
+  let xpi = await createTempXPIFile({});
+  let install = await AddonManager.getInstallForFile(xpi);
   Assert.notEqual(install, null);
   Assert.equal(install.state, AddonManager.STATE_DOWNLOAD_FAILED);
   Assert.equal(install.error, AddonManager.ERROR_CORRUPT_FILE);
-
-  run_test_4();
-}
+});
 
 // Checks that a file that doesn't match its hash shows an error
-async function run_test_4() {
-  let url = Services.io.newFileURI(do_get_file("data/unsigned.xpi")).spec;
+add_task(async function run_test_4() {
+  let xpi = await createTempWebExtensionFile({});
+  let url = Services.io.newFileURI(xpi).spec;
   let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", "sha1:foo");
   Assert.notEqual(install, null);
   Assert.equal(install.state, AddonManager.STATE_DOWNLOAD_FAILED);
   Assert.equal(install.error, AddonManager.ERROR_INCORRECT_HASH);
-
-  run_test_5();
-}
+});
 
 // Checks that a file that doesn't exist shows an error
-async function run_test_5() {
+add_task(async function run_test_5() {
   let file = do_get_file("data");
   file.append("missing.xpi");
   let install = await AddonManager.getInstallForFile(file);
   Assert.notEqual(install, null);
   Assert.equal(install.state, AddonManager.STATE_DOWNLOAD_FAILED);
   Assert.equal(install.error, AddonManager.ERROR_NETWORK_FAILURE);
-
-  run_test_6();
-}
+});
 
 // Checks that an add-on with an illegal ID shows an error
-async function run_test_6() {
-  let xpi = await AddonTestUtils.createTempXPIFile(ADDONS.test_bug567173);
+add_task(async function run_test_6() {
+  let xpi = await createTempWebExtensionFile({
+    manifest: {
+      applications: {gecko: {id: "invalid"}},
+    },
+  });
   let install = await AddonManager.getInstallForFile(xpi);
   Assert.notEqual(install, null);
   Assert.equal(install.state, AddonManager.STATE_DOWNLOAD_FAILED);
   Assert.equal(install.error, AddonManager.ERROR_CORRUPT_FILE);
-
-  executeSoon(do_test_finished);
-}
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_filepointer.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_filepointer.js
@@ -1,61 +1,29 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests that various operations with file pointers work and do not affect the
 // source files
 
-var addon1 = {
-  id: "addon1@tests.mozilla.org",
-  version: "1.0",
-  name: "Test 1",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
-
-var addon1_2 = {
-  id: "addon1@tests.mozilla.org",
-  version: "2.0",
-  name: "Test 1",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
-
-var addon2 = {
-  id: "addon2@tests.mozilla.org",
-  version: "1.0",
-  name: "Test 2",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
+const ID1 = "addon1@tests.mozilla.org";
+const ID2 = "addon2@tests.mozilla.org";
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 profileDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
 
 const sourceDir = gProfD.clone();
 sourceDir.append("source");
 
-var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
-testserver.registerDirectory("/data/", do_get_file("data"));
-gPort = testserver.identity.primaryPort;
+function promiseWriteWebExtension(path, data) {
+  let files = ExtensionTestCommon.generateFiles(data);
+  return AddonTestUtils.promiseWriteFilesToDir(path, files);
+}
 
 function promiseWritePointer(aId, aName) {
   let path = OS.Path.join(profileDir.path, aName || aId);
 
   let target = OS.Path.join(sourceDir.path,
                             do_get_expected_addon_name(aId));
 
   return OS.File.writeAtomic(path, new TextEncoder().encode(target));
@@ -79,279 +47,276 @@ add_task(async function setup() {
   // signature checks disabled.
   Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, false);
 
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
 });
 
 // Tests that installing a new add-on by pointer works
 add_task(async function test_new_pointer_install() {
-  await promiseWriteInstallRDFForExtension(addon1, sourceDir);
-  await promiseWritePointer(addon1.id);
+  let target = OS.Path.join(sourceDir.path, ID1);
+  await promiseWriteWebExtension(target, {
+    manifest: {
+      version: "1.0",
+      applications: {gecko: {id: ID1}},
+    },
+  });
+  await promiseWritePointer(ID1);
   await promiseStartupManager();
 
-  let addon = await AddonManager.getAddonByID(addon1.id);
+  let addon = await AddonManager.getAddonByID(ID1);
   notEqual(addon, null);
   equal(addon.version, "1.0");
 
   let file = addon.getResourceURI().QueryInterface(Ci.nsIFileURL).file;
   equal(file.parent.path, sourceDir.path);
 
-  let rootUri = do_get_addon_root_uri(sourceDir, addon1.id);
+  let rootUri = do_get_addon_root_uri(sourceDir, ID1);
   let uri = addon.getResourceURI("/");
   equal(uri.spec, rootUri);
-  uri = addon.getResourceURI("install.rdf");
-  equal(uri.spec, rootUri + "install.rdf");
 
   // Check that upgrade is disabled for addons installed by file-pointers.
   equal(addon.permissions & AddonManager.PERM_CAN_UPGRADE, 0);
 });
 
 // Tests that installing the addon from some other source doesn't clobber
 // the original sources
 add_task(async function test_addon_over_pointer() {
-  prepare_test({}, [
-    "onNewInstall",
-  ]);
-
-  let xpi = AddonTestUtils.createTempXPIFile({
-    "install.rdf": {
-      id: "addon1@tests.mozilla.org",
+  let xpi = AddonTestUtils.createTempWebExtensionFile({
+    manifest: {
       version: "2.0",
-      name: "File Pointer Test",
-      bootstrap: true,
-
-      targetApplications: [{
-          id: "xpcshell@tests.mozilla.org",
-          minVersion: "1",
-          maxVersion: "1"}],
+      applications: {gecko: {id: ID1}},
     },
   });
 
-  testserver.registerFile("/addons/test_filepointer.xpi", xpi);
-
-  let url = "http://example.com/addons/test_filepointer.xpi";
-  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  await new Promise(resolve => {
-    ensure_test_completed();
+  let install = await AddonManager.getInstallForFile(xpi, "application/x-xpinstall");
+  await install.install();
 
-    prepare_test({
-      "addon1@tests.mozilla.org": [
-        ["onInstalling", false],
-        ["onInstalled", false],
-      ],
-    }, [
-      "onDownloadStarted",
-      "onDownloadEnded",
-      "onInstallStarted",
-      "onInstallEnded",
-    ], callback_soon(resolve));
-
-    install.install();
-  });
-
-  await promiseRestartManager();
-
-  let addon = await AddonManager.getAddonByID(addon1.id);
+  let addon = await AddonManager.getAddonByID(ID1);
   notEqual(addon, null);
   equal(addon.version, "2.0");
 
   let file = addon.getResourceURI().QueryInterface(Ci.nsIFileURL).file;
   equal(file.parent.path, profileDir.path);
 
-  let rootUri = do_get_addon_root_uri(profileDir, addon1.id);
+  let rootUri = do_get_addon_root_uri(profileDir, ID1);
   let uri = addon.getResourceURI("/");
   equal(uri.spec, rootUri);
-  uri = addon.getResourceURI("install.rdf");
-  equal(uri.spec, rootUri + "install.rdf");
 
   let source = sourceDir.clone();
-  source.append(addon1.id);
+  source.append(ID1);
   ok(source.exists());
 
   await addon.uninstall();
 });
 
 // Tests that uninstalling doesn't clobber the original sources
 add_task(async function test_uninstall_pointer() {
-  await promiseRestartManager();
-  await promiseWritePointer(addon1.id);
+  await promiseWritePointer(ID1);
   await promiseRestartManager();
 
-  let addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let addon = await AddonManager.getAddonByID(ID1);
   notEqual(addon, null);
   equal(addon.version, "1.0");
 
   await addon.uninstall();
 
-  await promiseRestartManager();
-
   let source = sourceDir.clone();
-  source.append(addon1.id);
+  source.append(ID1);
   ok(source.exists());
 });
 
 // Tests that misnaming a pointer doesn't clobber the sources
 add_task(async function test_bad_pointer() {
-  await promiseWritePointer("addon2@tests.mozilla.org", addon1.id);
-
-  await promiseRestartManager();
+  await promiseWritePointer(ID2, ID1);
 
-  let [a1, a2] = await AddonManager.getAddonsByIDs(
-    ["addon1@tests.mozilla.org", "addon2@tests.mozilla.org"]);
-
+  let [a1, a2] = await AddonManager.getAddonsByIDs([ID1, ID2]);
   equal(a1, null);
   equal(a2, null);
 
   let source = sourceDir.clone();
-  source.append(addon1.id);
+  source.append(ID1);
   ok(source.exists());
 
   let pointer = profileDir.clone();
-  pointer.append("addon2@tests.mozilla.org");
+  pointer.append(ID2);
   ok(!pointer.exists());
 });
 
 // Tests that changing the ID of an existing add-on doesn't clobber the sources
 add_task(async function test_bad_pointer_id() {
-  var dest = await promiseWriteInstallRDFForExtension(addon1, sourceDir);
+  let dir = sourceDir.clone();
+  dir.append(ID1);
+
   // Make sure the modification time changes enough to be detected.
-  setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
-  await promiseWritePointer(addon1.id);
+  setExtensionModifiedTime(dir, dir.lastModifiedTime - 5000);
+  await promiseWritePointer(ID1);
   await promiseRestartManager();
 
-  let addon = await AddonManager.getAddonByID(addon1.id);
+  let addon = await AddonManager.getAddonByID(ID1);
   notEqual(addon, null);
   equal(addon.version, "1.0");
 
-  await promiseWriteInstallRDFForExtension(addon2, sourceDir, addon1.id);
-  setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
+  await promiseWriteWebExtension(dir.path, {
+    manifest: {
+      version: "1.0",
+      applications: {gecko: {id: ID2}},
+    },
+  });
+  setExtensionModifiedTime(dir, dir.lastModifiedTime - 5000);
 
   await promiseRestartManager();
 
-  let [a1, a2] = await AddonManager.getAddonsByIDs(
-    ["addon1@tests.mozilla.org", "addon2@tests.mozilla.org"]);
-
+  let [a1, a2] = await AddonManager.getAddonsByIDs([ID1, ID2]);
   equal(a1, null);
   equal(a2, null);
 
   let source = sourceDir.clone();
-  source.append(addon1.id);
+  source.append(ID1);
   ok(source.exists());
 
   let pointer = profileDir.clone();
-  pointer.append(addon1.id);
+  pointer.append(ID1);
   ok(!pointer.exists());
 });
 
 // Removing the pointer file should uninstall the add-on
 add_task(async function test_remove_pointer() {
-  var dest = await promiseWriteInstallRDFForExtension(addon1, sourceDir);
-  // Make sure the modification time changes enough to be detected in run_test_8.
-  setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
-  await promiseWritePointer(addon1.id);
+  let dir = sourceDir.clone();
+  dir.append(ID1);
+
+  await promiseWriteWebExtension(dir.path, {
+    manifest: {
+      version: "1.0",
+      applications: {gecko: {id: ID1}},
+    },
+  });
+
+  setExtensionModifiedTime(dir, dir.lastModifiedTime - 5000);
+  await promiseWritePointer(ID1);
 
   await promiseRestartManager();
 
-  let addon = await AddonManager.getAddonByID(addon1.id);
+  let addon = await AddonManager.getAddonByID(ID1);
   notEqual(addon, null);
   equal(addon.version, "1.0");
 
   let pointer = profileDir.clone();
-  pointer.append(addon1.id);
+  pointer.append(ID1);
   pointer.remove(false);
 
   await promiseRestartManager();
 
-  addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  addon = await AddonManager.getAddonByID(ID1);
   equal(addon, null);
 });
 
 // Removing the pointer file and replacing it with a directory should work
 add_task(async function test_replace_pointer() {
-  await promiseWritePointer(addon1.id);
+  await promiseWritePointer(ID1);
   await promiseRestartManager();
 
-  let addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let addon = await AddonManager.getAddonByID(ID1);
   notEqual(addon, null);
   equal(addon.version, "1.0");
 
   let pointer = profileDir.clone();
-  pointer.append(addon1.id);
+  pointer.append(ID1);
   pointer.remove(false);
 
-  await promiseWriteInstallRDFForExtension(addon1_2, profileDir);
+  await promiseWriteWebExtension(OS.Path.join(profileDir.path, ID1), {
+    manifest: {
+      version: "2.0",
+      applications: {gecko: {id: ID1}},
+    },
+  });
 
   await promiseRestartManager();
 
-  addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  addon = await AddonManager.getAddonByID(ID1);
   notEqual(addon, null);
   equal(addon.version, "2.0");
 
   await addon.uninstall();
 });
 
 // Changes to the source files should be detected
 add_task(async function test_change_pointer_sources() {
-  await promiseRestartManager();
-  await promiseWritePointer(addon1.id);
+  await promiseWritePointer(ID1);
   await promiseRestartManager();
 
-  let addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let addon = await AddonManager.getAddonByID(ID1);
   notEqual(addon, null);
   equal(addon.version, "1.0");
 
-  let dest = await promiseWriteInstallRDFForExtension(addon1_2, sourceDir);
-  setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
+  let dir = sourceDir.clone();
+  dir.append(ID1);
+  await promiseWriteWebExtension(dir.path, {
+    manifest: {
+      version: "2.0",
+      applications: {gecko: {id: ID1}},
+    },
+  });
+  setExtensionModifiedTime(dir, dir.lastModifiedTime - 5000);
 
   await promiseRestartManager();
 
-  addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  addon = await AddonManager.getAddonByID(ID1);
   notEqual(addon, null);
   equal(addon.version, "2.0");
 
   await addon.uninstall();
 });
 
 // Removing the add-on the pointer file points at should uninstall the add-on
 add_task(async function test_remove_pointer_target() {
-  await promiseRestartManager();
-  var dest = await promiseWriteInstallRDFForExtension(addon1, sourceDir);
-  await promiseWritePointer(addon1.id);
+  let target = OS.Path.join(sourceDir.path, ID1);
+  await promiseWriteWebExtension(target, {
+    manifest: {
+      version: "1.0",
+      applications: {gecko: {id: ID1}},
+    },
+  });
+  await promiseWritePointer(ID1);
   await promiseRestartManager();
 
-  let addon = await AddonManager.getAddonByID(addon1.id);
+  let addon = await AddonManager.getAddonByID(ID1);
   notEqual(addon, null);
   equal(addon.version, "1.0");
 
-  dest.remove(true);
+  await OS.File.removeDir(target);
 
   await promiseRestartManager();
 
-  addon = await AddonManager.getAddonByID(addon1.id);
+  addon = await AddonManager.getAddonByID(ID1);
   equal(addon, null);
 
   let pointer = profileDir.clone();
-  pointer.append(addon1.id);
+  pointer.append(ID1);
   ok(!pointer.exists());
 });
 
+
 // Tests that installing a new add-on by pointer with a relative path works
 add_task(async function test_new_relative_pointer() {
-  await promiseWriteInstallRDFForExtension(addon1, sourceDir);
-  await promiseWriteRelativePointer(addon1.id);
+  let target = OS.Path.join(sourceDir.path, ID1);
+  await promiseWriteWebExtension(target, {
+    manifest: {
+      version: "1.0",
+      applications: {gecko: {id: ID1}},
+    },
+  });
+  await promiseWriteRelativePointer(ID1);
   await promiseRestartManager();
 
-  let addon = await AddonManager.getAddonByID(addon1.id);
+  let addon = await AddonManager.getAddonByID(ID1);
   equal(addon.version, "1.0");
 
   let file = addon.getResourceURI().QueryInterface(Ci.nsIFileURL).file;
   equal(file.parent.path, sourceDir.path);
 
-  let rootUri = do_get_addon_root_uri(sourceDir, addon1.id);
+  let rootUri = do_get_addon_root_uri(sourceDir, ID1);
   let uri = addon.getResourceURI("/");
   equal(uri.spec, rootUri);
-  uri = addon.getResourceURI("install.rdf");
-  equal(uri.spec, rootUri + "install.rdf");
 
   // Check that upgrade is disabled for addons installed by file-pointers.
   equal(addon.permissions & AddonManager.PERM_CAN_UPGRADE, 0);
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_getresource.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_getresource.js
@@ -1,68 +1,57 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This verifies the functionality of getResourceURI
 // There are two cases - with a filename it returns an nsIFileURL to the filename
 // and with no parameters, it returns an nsIFileURL to the root of the addon
 
-const ADDONS = {
-  test_getresource: {
-    "install.rdf": {
-      "id": "addon1@tests.mozilla.org",
-      "name": "Test 1",
-    },
-    "icon.png": "Dummy icon file",
-    "subdir/subfile.txt": "Dummy file in subdirectory",
-  },
-};
-
-async function run_test() {
-  do_test_pending();
+add_task(async function run_test() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
 
   await promiseStartupManager();
 
-  let xpi = AddonTestUtils.createTempXPIFile(ADDONS.test_getresource);
-  let aInstall = await AddonManager.getInstallForFile(xpi);
-  Assert.equal(aInstall.addon.getResourceURI().spec, aInstall.sourceURI.spec);
-
-  Assert.equal(aInstall.addon.getResourceURI("icon.png").spec,
-               "jar:" + aInstall.sourceURI.spec + "!/icon.png");
+  const ID = "addon@tests.mozilla.org";
+  let xpi = AddonTestUtils.createTempWebExtensionFile({
+    manifest: { applications: {gecko: {id: ID}}},
+    files: {
+      "icon.png": "Dummy icon file",
+      "subdir/subfile.txt": "Dummy file in subdirectory",
+    },
+  });
 
-  Assert.equal(aInstall.addon.getResourceURI("subdir/subfile.txt").spec,
-               "jar:" + aInstall.sourceURI.spec + "!/subdir/subfile.txt");
+  let install = await AddonManager.getInstallForFile(xpi);
+  Assert.equal(install.addon.getResourceURI().spec, install.sourceURI.spec);
+
+  Assert.equal(install.addon.getResourceURI("icon.png").spec,
+               `jar:${install.sourceURI.spec}!/icon.png`);
 
-  await promiseCompleteAllInstalls([aInstall]);
+  Assert.equal(install.addon.getResourceURI("subdir/subfile.txt").spec,
+               `jar:${install.sourceURI.spec}!/subdir/subfile.txt`);
+
+  await promiseCompleteInstall(install);
   await promiseRestartManager();
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let a1 = await AddonManager.getAddonByID(ID);
   Assert.notEqual(a1, null);
 
   let addonDir = gProfD.clone();
   addonDir.append("extensions");
-  let rootUri = do_get_addon_root_uri(addonDir, "addon1@tests.mozilla.org");
+  let rootUri = do_get_addon_root_uri(addonDir, ID);
 
   let uri = a1.getResourceURI("/");
   Assert.equal(uri.spec, rootUri);
 
-  let file = rootUri + "install.rdf";
-  uri = a1.getResourceURI("install.rdf");
+  let file = rootUri + "manifest.json";
+  uri = a1.getResourceURI("manifest.json");
   Assert.equal(uri.spec, file);
 
   file = rootUri + "icon.png";
   uri = a1.getResourceURI("icon.png");
   Assert.equal(uri.spec, file);
 
   file = rootUri + "subdir/subfile.txt";
   uri = a1.getResourceURI("subdir/subfile.txt");
   Assert.equal(uri.spec, file);
 
   await a1.uninstall();
-
-  await promiseRestartManager();
-
-  let newa1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
-  Assert.equal(newa1, null);
-
-  executeSoon(do_test_finished);
-}
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_install.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_install.js
@@ -1,214 +1,222 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
-ChromeUtils.import("resource://testing-common/httpd.js");
-
-var testserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
+var testserver = createHttpServer({hosts: ["example.com"]});
 var gInstallDate;
 
 const ADDONS = {
   test_install1: {
-    "install.rdf": {
-      id: "addon1@tests.mozilla.org",
-      version: "1.0",
+    manifest: {
       name: "Test 1",
+      version: "1.0",
+      applications: {gecko: {id: "addon1@tests.mozilla.org"}},
     },
-    "icon.png": "Fake icon image",
-    "icon64.png": "Fake icon image",
   },
   test_install2_1: {
-    "install.rdf": {
-      id: "addon2@tests.mozilla.org",
+    manifest: {
+      name: "Test 2",
       version: "2.0",
-      name: "Real Test 2",
+      applications: {gecko: {id: "addon2@tests.mozilla.org"}},
     },
-    "icon.png": "Fake icon image",
   },
   test_install2_2: {
-    "install.rdf": {
-      id: "addon2@tests.mozilla.org",
+    manifest: {
+      name: "Test 2",
       version: "3.0",
-      name: "Real Test 3",
+      applications: {gecko: {id: "addon2@tests.mozilla.org"}},
     },
   },
   test_install3: {
-    "install.rdf": {
-      id: "addon3@tests.mozilla.org",
+    manifest: {
+      name: "Test 3",
       version: "1.0",
-      name: "Real Test 4",
-
-      updateURL: "http://example.com/data/test_install.rdf",
-
-      targetApplications: [{
-          id: "xpcshell@tests.mozilla.org",
-          minVersion: "0",
-          maxVersion: "0"}],
-    },
-  },
-  test_install6: {
-    "install.rdf": {
-      id: "addon6@tests.mozilla.org",
-      version: "1.0",
-      name: "Addon Test 6",
-    },
-  },
-  test_install7: {
-    "install.rdf": {
-      type: "32",
+      applications: {
+        gecko: {
+          id: "addon3@tests.mozilla.org",
+          strict_min_version: "0",
+          strict_max_version: "0",
+          update_url: "http://example.com/update.json",
+        },
+      },
     },
   },
 };
 
 const XPIS = {};
 
-for (let [name, files] of Object.entries(ADDONS)) {
-  XPIS[name] = AddonTestUtils.createTempXPIFile(files);
-  testserver.registerFile(`/addons/${name}.xpi`, XPIS[name]);
-}
-
-const ZipReader = Components.Constructor(
-  "@mozilla.org/libjar/zip-reader;1", "nsIZipReader",
-  "open");
-
 // The test extension uses an insecure update url.
 Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
 Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, false);
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
+const UPDATE_JSON = {
+  addons: {
+    "addon3@tests.mozilla.org": {
+      updates: [
+        {
+          version: "1.0",
+          applications: {
+            gecko: {
+              strict_min_version: "0",
+              strict_max_version: "2",
+            },
+          },
+        },
+      ],
+    },
+  },
+};
+
+const GETADDONS_JSON = {
+  page_size: 25,
+  page_count: 1,
+  count: 1,
+  next: null,
+  previous: null,
+  results: [
+    {
+      name: "Test 2",
+      type: "extension",
+      guid: "addon2@tests.mozilla.org",
+      current_version: {
+        version: "1.0",
+        files: [
+          {
+            size: 2,
+            url: "http://example.com/test_install2_1.xpi",
+          },
+        ],
+      },
+      authors: [
+        {
+          name: "Test Creator",
+          url: "http://example.com/creator.html",
+        },
+      ],
+      summary: "Repository summary",
+      description: "Repository description",
+    },
+  ],
+};
+
+const COMPAT_JSON = {
+  page_size: 25,
+  page_count: 1,
+  count: 0,
+  next: null,
+  previous: null,
+  results: [ ],
+};
+
 function checkInstall(install, expected) {
   for (let [key, value] of Object.entries(expected)) {
     if (value instanceof Ci.nsIURI) {
       equal(install[key] && install[key].spec, value.spec, `Expected value of install.${key}`);
     } else {
       deepEqual(install[key], value, `Expected value of install.${key}`);
     }
   }
 }
 
 add_task(async function setup() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
+  for (let [name, data] of Object.entries(ADDONS)) {
+    XPIS[name] = AddonTestUtils.createTempWebExtensionFile(data);
+    testserver.registerFile(`/addons/${name}.xpi`, XPIS[name]);
+  }
+
   await promiseStartupManager();
 
-  // Make sure we only register once despite multiple calls
-  AddonManager.addInstallListener(InstallListener);
-  AddonManager.addAddonListener(AddonListener);
-  AddonManager.addInstallListener(InstallListener);
-  AddonManager.addAddonListener(AddonListener);
-
   // Create and configure the HTTP server.
+  AddonTestUtils.registerJSON(testserver, "/update.json", UPDATE_JSON);
   testserver.registerDirectory("/data/", do_get_file("data"));
   testserver.registerPathHandler("/redirect", function(aRequest, aResponse) {
     aResponse.setStatusLine(null, 301, "Moved Permanently");
     let url = aRequest.host + ":" + aRequest.port + aRequest.queryString;
     aResponse.setHeader("Location", "http://" + url);
   });
   gPort = testserver.identity.primaryPort;
 });
 
 // Checks that an install from a local file proceeds as expected
-add_task(async function test_1() {
-  prepare_test({ }, [
-    "onNewInstall",
+add_task(async function test_install_file() {
+  let [, install] = await Promise.all([
+    AddonTestUtils.promiseInstallEvent("onNewInstall"),
+    AddonManager.getInstallForFile(XPIS.test_install1),
   ]);
 
-  let install = await AddonManager.getInstallForFile(XPIS.test_install1);
-  ensure_test_completed();
-
   let uri = Services.io.newFileURI(XPIS.test_install1);
   checkInstall(install, {
     type: "extension",
     version: "1.0",
     name: "Test 1",
     state: AddonManager.STATE_DOWNLOADED,
-    iconURL: null,
     sourceURI: uri,
   });
 
   let {addon} = install;
   checkAddon("addon1@tests.mozilla.org", addon, {
     install,
-    iconURL: `jar:${uri.spec}!/icon.png`,
     sourceURI: uri,
   });
   notEqual(addon.syncGUID, null);
-  equal(addon.getResourceURI("install.rdf").spec, `jar:${uri.spec}!/install.rdf`);
+  equal(addon.getResourceURI("manifest.json").spec, `jar:${uri.spec}!/manifest.json`);
 
   let activeInstalls = await AddonManager.getAllInstalls();
   equal(activeInstalls.length, 1);
   equal(activeInstalls[0], install);
 
   let fooInstalls = await AddonManager.getInstallsByTypes(["foo"]);
   equal(fooInstalls.length, 0);
 
   let extensionInstalls = await AddonManager.getInstallsByTypes(["extension"]);
   equal(extensionInstalls.length, 1);
   equal(extensionInstalls[0], install);
 
-  let installSyncGUID = await new Promise(resolve => {
-    prepare_test({
-      "addon1@tests.mozilla.org": [
-        ["onInstalling", false],
-        "onInstalled",
-      ],
-    }, [
-      "onInstallStarted",
-      "onInstallEnded",
-    ], () => {
-      resolve(install.addon.syncGUID);
-    });
-    install.install();
-  });
+  prepare_test({
+    "addon1@tests.mozilla.org": [
+      ["onInstalling", false],
+      "onInstalled",
+    ],
+  }, [
+    "onInstallStarted",
+    "onInstallEnded",
+  ]);
+
+  await install.install();
 
   ensure_test_completed();
 
   addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
   ok(addon);
 
-  uri = NetUtil.newURI(addon.iconURL);
-  if (uri instanceof Ci.nsIJARURI) {
-    let {file} = uri.JARFile.QueryInterface(Ci.nsIFileURL);
-    let zipReader = new ZipReader(file);
-    try {
-      ok(zipReader.hasEntry(uri.JAREntry));
-    } finally {
-      zipReader.close();
-    }
-  } else {
-    let {file} = uri.QueryInterface(Ci.nsIFileURL);
-    ok(file.exists());
-  }
+  ok(!hasFlag(addon.permissions, AddonManager.PERM_CAN_ENABLE));
+  ok(hasFlag(addon.permissions, AddonManager.PERM_CAN_DISABLE));
 
   let updateDate = Date.now();
 
-  ok(!hasFlag(addon.permissions, AddonManager.PERM_CAN_ENABLE));
-  ok(hasFlag(addon.permissions, AddonManager.PERM_CAN_DISABLE));
-
   await promiseRestartManager();
 
   activeInstalls = await AddonManager.getAllInstalls();
   equal(activeInstalls, 0);
 
   let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
   let uri2 = do_get_addon_root_uri(profileDir, "addon1@tests.mozilla.org");
 
   checkAddon("addon1@tests.mozilla.org", a1, {
-    syncGUID: installSyncGUID,
     type: "extension",
     version: "1.0",
     name: "Test 1",
     foreignInstall: false,
-    iconURL: uri2 + "icon.png",
     sourceURI: Services.io.newFileURI(XPIS.test_install1),
   });
 
   notEqual(a1.syncGUID, null);
   ok(a1.syncGUID.length >= 9);
 
   ok(isExtensionInBootstrappedList(profileDir, a1.id));
   ok(XPIS.test_install1.exists());
@@ -217,439 +225,396 @@ add_task(async function test_1() {
   let difference = a1.installDate.getTime() - updateDate;
   if (Math.abs(difference) > MAX_TIME_DIFFERENCE)
     do_throw("Add-on install time was out by " + difference + "ms");
 
   difference = a1.updateDate.getTime() - updateDate;
   if (Math.abs(difference) > MAX_TIME_DIFFERENCE)
     do_throw("Add-on update time was out by " + difference + "ms");
 
-  equal(a1.getResourceURI("install.rdf").spec, uri2 + "install.rdf");
+  equal(a1.getResourceURI("manifest.json").spec, uri2 + "manifest.json");
 
   // Ensure that extension bundle (or icon if unpacked) has updated
   // lastModifiedDate.
-  let testURI = a1.getResourceURI(TEST_UNPACKED ? "icon.png" : "");
+  let testURI = a1.getResourceURI("");
   let testFile = testURI.QueryInterface(Ci.nsIFileURL).file;
   ok(testFile.exists());
   difference = testFile.lastModifiedTime - Date.now();
   ok(Math.abs(difference) < MAX_TIME_DIFFERENCE);
 
   await a1.uninstall();
   let { id, version } = a1;
   await promiseRestartManager();
   do_check_not_in_crash_annotation(id, version);
 });
 
 // Tests that an install from a url downloads.
-add_task(async function test_2() {
+add_task(async function test_install_url() {
   let url = "http://example.com/addons/test_install2_1.xpi";
   let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", null, "Test 2", null, "1.0");
   checkInstall(install, {
     version: "1.0",
     name: "Test 2",
     state: AddonManager.STATE_AVAILABLE,
-    iconURL: null,
     sourceURI: Services.io.newURI(url),
   });
 
   let activeInstalls = await AddonManager.getAllInstalls();
   equal(activeInstalls.length, 1);
   equal(activeInstalls[0], install);
 
-  install = await new Promise(resolve => {
+  await new Promise(resolve => {
     prepare_test({}, [
       "onDownloadStarted",
       "onDownloadEnded",
-    ], install1 => {
-      resolve(install1);
+    ], () => {
+      resolve();
       return false;
     });
-
-    install.addListener({
-      onDownloadProgress() {
-        executeSoon(function() {
-          Cu.forceGC();
-        });
-      },
-    });
-
     install.install();
   });
 
   ensure_test_completed();
+
   checkInstall(install, {
     version: "2.0",
-    name: "Real Test 2",
+    name: "Test 2",
     state: AddonManager.STATE_DOWNLOADED,
-    iconURL: null,
   });
   equal(install.addon.install, install);
 
-  install = await new Promise(resolve => {
-    prepare_test({
-      "addon2@tests.mozilla.org": [
-        ["onInstalling", false],
-        "onInstalled",
-      ],
-    }, [
-      "onInstallStarted",
-      "onInstallEnded",
-    ], resolve);
-    install.install();
-  });
+  prepare_test({
+    "addon2@tests.mozilla.org": [
+      ["onInstalling", false],
+      "onInstalled",
+    ],
+  }, [
+    "onInstallStarted",
+    "onInstallEnded",
+  ]);
+
+  await install.install();
+  ensure_test_completed();
 
   let updateDate = Date.now();
 
-  ensure_test_completed();
-
   await promiseRestartManager();
 
   let installs = await AddonManager.getAllInstalls();
   equal(installs, 0);
 
   let a2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
   checkAddon("addon2@tests.mozilla.org", a2, {
     type: "extension",
     version: "2.0",
-    name: "Real Test 2",
+    name: "Test 2",
     sourceURI: Services.io.newURI(url),
   });
   notEqual(a2.syncGUID, null);
 
   ok(isExtensionInBootstrappedList(profileDir, a2.id));
   ok(XPIS.test_install2_1.exists());
-
   do_check_in_crash_annotation(a2.id, a2.version);
 
   let difference = a2.installDate.getTime() - updateDate;
-  if (Math.abs(difference) > MAX_TIME_DIFFERENCE)
-    do_throw("Add-on install time was out by " + difference + "ms");
+  Assert.lessOrEqual(Math.abs(difference), MAX_TIME_DIFFERENCE,
+                     "Add-on install time was correct");
 
   difference = a2.updateDate.getTime() - updateDate;
-  if (Math.abs(difference) > MAX_TIME_DIFFERENCE)
-    do_throw("Add-on update time was out by " + difference + "ms");
+  Assert.lessOrEqual(Math.abs(difference), MAX_TIME_DIFFERENCE,
+                     "Add-on update time was correct");
 
   gInstallDate = a2.installDate;
 });
 
 // Tests that installing a new version of an existing add-on works
-add_task(async function test_4() {
-  prepare_test({ }, [
-    "onNewInstall",
+add_task(async function test_install_new_version() {
+  let url = "http://example.com/addons/test_install2_2.xpi";
+  let [, install] = await Promise.all([
+    AddonTestUtils.promiseInstallEvent("onNewInstall"),
+    AddonManager.getInstallForURL(url, "application/x-xpinstall", null, "Test 2", null, "3.0"),
   ]);
 
-  let url = "http://example.com/addons/test_install2_2.xpi";
-  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", null, "Test 3", null, "3.0");
-  ensure_test_completed();
-
   checkInstall(install, {
     version: "3.0",
-    name: "Test 3",
+    name: "Test 2",
     state: AddonManager.STATE_AVAILABLE,
     existingAddon: null,
   });
 
   let activeInstalls = await AddonManager.getAllInstalls();
   equal(activeInstalls.length, 1);
   equal(activeInstalls[0], install);
 
-  install = await new Promise(resolve => {
+  await new Promise(resolve => {
     prepare_test({}, [
       "onDownloadStarted",
       "onDownloadEnded",
-    ], install1 => {
-      resolve(install1);
+    ], () => {
+      resolve();
       return false;
     });
     install.install();
   });
 
   ensure_test_completed();
 
   checkInstall(install, {
     version: "3.0",
-    name: "Real Test 3",
+    name: "Test 2",
     state: AddonManager.STATE_DOWNLOADED,
     existingAddon: await AddonManager.getAddonByID("addon2@tests.mozilla.org"),
   });
 
   equal(install.addon.install, install);
 
   // Installation will continue when there is nothing returned.
-  install = await new Promise(resolve => {
-    prepare_test({
-      "addon2@tests.mozilla.org": [
-        ["onInstalling", false],
-        "onInstalled",
-      ],
-    }, [
-      "onInstallStarted",
-      "onInstallEnded",
-    ], resolve);
-    install.install();
-  });
+  prepare_test({
+    "addon2@tests.mozilla.org": [
+      ["onInstalling", false],
+      "onInstalled",
+    ],
+  }, [
+    "onInstallStarted",
+    "onInstallEnded",
+  ]);
+
+  await install.install();
 
   ensure_test_completed();
 
   await promiseRestartManager();
 
   let installs2 = await AddonManager.getInstallsByTypes(null);
   equal(installs2.length, 0);
 
   let a2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
   checkAddon("addon2@tests.mozilla.org", a2, {
     type: "extension",
     version: "3.0",
-    name: "Real Test 3",
+    name: "Test 2",
     isActive: true,
     foreignInstall: false,
     sourceURI: Services.io.newURI(url),
     installDate: gInstallDate,
   });
 
   ok(isExtensionInBootstrappedList(profileDir, a2.id));
   ok(XPIS.test_install2_2.exists());
-
   do_check_in_crash_annotation(a2.id, a2.version);
 
   // Update date should be later (or the same if this test is too fast)
   ok(a2.installDate <= a2.updateDate);
 
   await a2.uninstall();
 });
 
 // Tests that an install that requires a compatibility update works
-add_task(async function test_6() {
-  await promiseRestartManager();
-
-  prepare_test({ }, [
-    "onNewInstall",
+add_task(async function test_install_compat_update() {
+  let url = "http://example.com/addons/test_install3.xpi";
+  let [, install] = await Promise.all([
+    AddonTestUtils.promiseInstallEvent("onNewInstall"),
+    await AddonManager.getInstallForURL(url, "application/x-xpinstall", null, "Test 3", null, "1.0"),
   ]);
 
-  let url = "http://example.com/addons/test_install3.xpi";
-  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", null, "Real Test 4", null, "1.0");
-  ensure_test_completed();
-
   checkInstall(install, {
     version: "1.0",
-    name: "Real Test 4",
+    name: "Test 3",
     state: AddonManager.STATE_AVAILABLE,
   });
 
   let activeInstalls = await AddonManager.getInstallsByTypes(null);
   equal(activeInstalls.length, 1);
   equal(activeInstalls[0], install);
 
-  install = await new Promise(resolve => {
+  await new Promise(resolve => {
     prepare_test({}, [
       "onDownloadStarted",
       "onDownloadEnded",
-    ], install1 => {
-      resolve(install1);
+    ], () => {
+      resolve();
       return false;
     });
     install.install();
   });
+  ensure_test_completed();
 
-  ensure_test_completed();
   checkInstall(install, {
     version: "1.0",
-    name: "Real Test 4",
+    name: "Test 3",
     state: AddonManager.STATE_DOWNLOADED,
     existingAddon: null,
   });
   checkAddon("addon3@tests.mozilla.org", install.addon, {
     appDisabled: false,
   });
 
   // Continue the install
-  await new Promise(resolve => {
-    prepare_test({
-      "addon3@tests.mozilla.org": [
-        ["onInstalling", false],
-        "onInstalled",
-      ],
-    }, [
-      "onInstallStarted",
-      "onInstallEnded",
-    ], resolve);
-    install.install();
-  });
+  prepare_test({
+    "addon3@tests.mozilla.org": [
+      ["onInstalling", false],
+      "onInstalled",
+    ],
+  }, [
+    "onInstallStarted",
+    "onInstallEnded",
+  ]);
 
+  await install.install();
   ensure_test_completed();
 
   await promiseRestartManager();
 
   let installs = await AddonManager.getAllInstalls();
   equal(installs, 0);
 
   let a3 = await AddonManager.getAddonByID("addon3@tests.mozilla.org");
   checkAddon("addon3@tests.mozilla.org", a3, {
     type: "extension",
     version: "1.0",
-    name: "Real Test 4",
+    name: "Test 3",
     isActive: true,
     appDisabled: false,
   });
   notEqual(a3.syncGUID, null);
 
   ok(isExtensionInBootstrappedList(profileDir, a3.id));
 
   ok(XPIS.test_install3.exists());
   await a3.uninstall();
 });
 
-add_task(async function test_8() {
-  await promiseRestartManager();
-
-  AddonManager.addInstallListener(InstallListener);
-  AddonManager.addAddonListener(AddonListener);
-
-  prepare_test({ }, [
-    "onNewInstall",
+add_task(async function test_compat_update_local() {
+  let [, install] = await Promise.all([
+    AddonTestUtils.promiseInstallEvent("onNewInstall"),
+    AddonManager.getInstallForFile(XPIS.test_install3),
   ]);
-
-  let install = await AddonManager.getInstallForFile(XPIS.test_install3);
   ok(install.addon.isCompatible);
 
-  await new Promise(resolve => {
-    prepare_test({
-      "addon3@tests.mozilla.org": [
-        ["onInstalling", false],
-        "onInstalled",
-      ],
-    }, [
-      "onInstallStarted",
-      "onInstallEnded",
-    ], resolve);
-    install.install();
-  });
+  prepare_test({
+    "addon3@tests.mozilla.org": [
+      ["onInstalling", false],
+      "onInstalled",
+    ],
+  }, [
+    "onInstallStarted",
+    "onInstallEnded",
+  ]);
+
+  await install.install();
+  ensure_test_completed();
 
   await promiseRestartManager();
 
   let a3 = await AddonManager.getAddonByID("addon3@tests.mozilla.org");
   checkAddon("addon3@tests.mozilla.org", a3, {
     type: "extension",
     version: "1.0",
-    name: "Real Test 4",
+    name: "Test 3",
     isActive: true,
     appDisabled: false,
   });
   notEqual(a3.syncGUID, null);
 
   ok(isExtensionInBootstrappedList(profileDir, a3.id));
 
   ok(XPIS.test_install3.exists());
   await a3.uninstall();
 });
 
 // Test that after cancelling a download it is removed from the active installs
-add_task(async function test_9() {
-  await promiseRestartManager();
-
-  prepare_test({ }, [
-    "onNewInstall",
+add_task(async function test_cancel() {
+  let url = "http://example.com/addons/test_install3.xpi";
+  let [, install] = await Promise.all([
+    AddonTestUtils.promiseInstallEvent("onNewInstall"),
+    AddonManager.getInstallForURL(url, "application/x-xpinstall", null, "Test 3", null, "1.0"),
   ]);
 
-  let url = "http://example.com/addons/test_install3.xpi";
-  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", null, "Real Test 4", null, "1.0");
-  ensure_test_completed();
-
   checkInstall(install, {
     version: "1.0",
-    name: "Real Test 4",
+    name: "Test 3",
     state: AddonManager.STATE_AVAILABLE,
   });
 
   let activeInstalls = await AddonManager.getInstallsByTypes(null);
   equal(activeInstalls.length, 1);
   equal(activeInstalls[0], install);
 
-  install = await new Promise(resolve => {
+  await new Promise(resolve => {
     prepare_test({}, [
       "onDownloadStarted",
       "onDownloadEnded",
     ], () => {
       prepare_test({}, [
         "onDownloadCancelled",
       ], resolve);
 
       install.cancel();
     });
 
     install.install();
   });
+  ensure_test_completed();
 
   let file = install.file;
 
   // Allow the file removal to complete
   activeInstalls = await AddonManager.getAllInstalls();
   equal(activeInstalls.length, 0);
   ok(!file.exists());
 });
 
 // Check that cancelling the install from onDownloadStarted actually cancels it
-add_task(async function test_14() {
-  await promiseRestartManager();
-
-  prepare_test({ }, [
-    "onNewInstall",
+add_task(async function test_cancel_onDownloadStarted() {
+  clearListeners();
+  let url = "http://example.com/addons/test_install2_1.xpi";
+  let [, install] = await Promise.all([
+    AddonTestUtils.promiseInstallEvent("onNewInstall"),
+    AddonManager.getInstallForURL(url, "application/x-xpinstall"),
   ]);
 
-  let url = "http://example.com/addons/test_install2_1.xpi";
-  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  ensure_test_completed();
-
   equal(install.file, null);
 
-  install = await new Promise(resolve => {
-    prepare_test({ }, [
-      "onDownloadStarted",
-    ], resolve);
-    install.install();
+  install.addListener({
+    onDownloadStarted() {
+      install.removeListener(this);
+      executeSoon(() => install.cancel());
+    },
   });
 
-  // Wait for the channel to be ready to cancel
-  executeSoon(function() {
-    install.cancel();
-  });
 
-  await new Promise(resolve => {
-    prepare_test({ }, [
-      "onDownloadCancelled",
-    ], resolve);
-  });
+  let promise = AddonTestUtils.promiseInstallEvent("onDownloadCancelled");
+  install.install();
+  await promise;
 
-  let file = install.file;
-
+  // Wait another tick to see if it continues downloading.
+  // The listener only really tests if we give it time to see progress, the
+  // file check isn't ideal either
   install.addListener({
     onDownloadProgress() {
       do_throw("Download should not have continued");
     },
     onDownloadEnded() {
       do_throw("Download should not have continued");
     },
   });
 
-  // Allow the listener to return to see if it continues downloading. The
-  // The listener only really tests if we give it time to see progress, the
-  // file check isn't ideal either
+  let file = install.file;
+  await Promise.resolve();
   ok(!file.exists());
 });
 
 // Checks that cancelling the install from onDownloadEnded actually cancels it
-add_task(async function test_15() {
-  prepare_test({ }, [
-    "onNewInstall",
+add_task(async function test_cancel_onDownloadEnded() {
+  let url = "http://example.com/addons/test_install2_1.xpi";
+  let [, install] = await Promise.all([
+    AddonTestUtils.promiseInstallEvent("onNewInstall"),
+    AddonManager.getInstallForURL(url, "application/x-xpinstall"),
   ]);
 
-  let url = "http://example.com/addons/test_install2_1.xpi";
-  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  ensure_test_completed();
-
   equal(install.file, null);
 
   await new Promise(resolve => {
     prepare_test({ }, [
       "onDownloadStarted",
       "onDownloadEnded",
     ], () => {
       prepare_test({ }, [
@@ -667,586 +632,343 @@ add_task(async function test_15() {
   install.addListener({
     onInstallStarted() {
       do_throw("Install should not have continued");
     },
   });
 });
 
 // Verify that the userDisabled value carries over to the upgrade by default
-add_task(async function test_16() {
-  await promiseRestartManager();
-
+add_task(async function test_userDisabled_update() {
+  clearListeners();
   let url = "http://example.com/addons/test_install2_1.xpi";
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  await new Promise(resolve => {
-    aInstall.addListener({
-      onInstallStarted() {
-        ok(!aInstall.addon.userDisabled);
-        aInstall.addon.disable();
-      },
+  let [, install] = await Promise.all([
+    AddonTestUtils.promiseInstallEvent("onNewInstall"),
+    AddonManager.getInstallForURL(url, "application/x-xpinstall"),
+  ]);
 
-      onInstallEnded() {
-        resolve();
-      },
-    });
-    aInstall.install();
-  });
+  await install.install();
 
-  await promiseRestartManager();
+  ok(!install.addon.userDisabled);
+  await install.addon.disable();
 
-  let a2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  checkAddon("addon2@tests.mozilla.org", a2, {
+  let addon = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
+  checkAddon("addon2@tests.mozilla.org", addon, {
     userDisabled: true,
     isActive: false,
   });
 
-  let url_2 = "http://example.com/addons/test_install2_2.xpi";
-  let aInstall_2 = await AddonManager.getInstallForURL(url_2, "application/x-xpinstall");
-  await new Promise(resolve => {
-    aInstall_2.addListener({
-      onInstallEnded() {
-        resolve();
-      },
-    });
-    aInstall_2.install();
-  });
+  url = "http://example.com/addons/test_install2_2.xpi";
+  install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
+  await install.install();
 
-  checkAddon("addon2@tests.mozilla.org", aInstall_2.addon, {
+  checkAddon("addon2@tests.mozilla.org", install.addon, {
     userDisabled: true,
     isActive: false,
   });
 
   await promiseRestartManager();
 
-  let a2_2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  checkAddon("addon2@tests.mozilla.org", a2_2, {
+  addon = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
+  checkAddon("addon2@tests.mozilla.org", addon, {
     userDisabled: true,
     isActive: false,
   });
 
-  await a2_2.uninstall();
+  await addon.uninstall();
 });
 
 // Verify that changing the userDisabled value before onInstallEnded works
-add_task(async function test_17() {
-  await promiseRestartManager();
-
+add_task(async function test_userDisabled() {
   let url = "http://example.com/addons/test_install2_1.xpi";
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  await new Promise(resolve => {
-    aInstall.addListener({
-      onInstallEnded() {
-        resolve();
-      },
-    });
-    aInstall.install();
-  });
+  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
+  await install.install();
 
-  ok(!aInstall.addon.userDisabled);
+  ok(!install.addon.userDisabled);
 
-  await promiseRestartManager();
-
-  let a2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  checkAddon("addon2@tests.mozilla.org", a2, {
+  let addon = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
+  checkAddon("addon2@tests.mozilla.org", addon, {
     userDisabled: false,
     isActive: true,
   });
 
-  let url_2 = "http://example.com/addons/test_install2_2.xpi";
-  let aInstall_2 = await AddonManager.getInstallForURL(url_2, "application/x-xpinstall");
-
-  await new Promise(resolve => {
-    aInstall_2.addListener({
-      onInstallStarted() {
-        ok(!aInstall_2.addon.userDisabled);
-        aInstall_2.addon.disable();
-      },
+  url = "http://example.com/addons/test_install2_2.xpi";
+  install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
 
-      onInstallEnded() {
-        resolve();
-      },
-    });
-    aInstall_2.install();
-  });
-  await promiseRestartManager();
-
-  let a2_2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  checkAddon("addon2@tests.mozilla.org", a2_2, {
-    userDisabled: true,
-    isActive: false,
+  install.addListener({
+    onInstallStarted() {
+      ok(!install.addon.userDisabled);
+      install.addon.disable();
+    },
   });
 
-  await a2_2.uninstall();
-});
-
-// Verify that changing the userDisabled value before onInstallEnded works
-add_task(async function test_18() {
-  await promiseRestartManager();
+  await install.install();
 
-  let url = "http://example.com/addons/test_install2_1.xpi";
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  await new Promise(resolve => {
-    aInstall.addListener({
-      onInstallStarted() {
-        ok(!aInstall.addon.userDisabled);
-        aInstall.addon.disable();
-      },
-
-      onInstallEnded() {
-        resolve();
-      },
-    });
-    aInstall.install();
-  });
-
-  await promiseRestartManager();
-
-  let a2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  checkAddon("addon2@tests.mozilla.org", a2, {
+  addon = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
+  checkAddon("addon2@tests.mozilla.org", addon, {
     userDisabled: true,
     isActive: false,
   });
 
-  let url_2 = "http://example.com/addons/test_install2_2.xpi";
-  let aInstall_2 = await AddonManager.getInstallForURL(url_2, "application/x-xpinstall");
-  await new Promise(resolve => {
-    aInstall_2.addListener({
-      onInstallStarted() {
-        ok(aInstall_2.addon.userDisabled);
-        aInstall_2.addon.enable();
-      },
-
-      onInstallEnded() {
-        resolve();
-      },
-    });
-    aInstall_2.install();
-  });
-
-  await promiseRestartManager();
-
-  let a2_2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  checkAddon("addon2@tests.mozilla.org", a2_2, {
-    isActive: true,
-    userDisabled: false,
-  });
-
-  await a2_2.uninstall();
+  await addon.uninstall();
 });
 
-
 // Checks that metadata is not stored if the pref is set to false
 add_task(async function test_18_1() {
-  await promiseRestartManager();
+  AddonTestUtils.registerJSON(testserver, "/getaddons.json", GETADDONS_JSON);
+  Services.prefs.setCharPref(PREF_GETADDONS_BYIDS,
+                             "http://example.com/getaddons.json");
+
+  AddonTestUtils.registerJSON(testserver, "/compat.json", COMPAT_JSON);
+  Services.prefs.setCharPref(PREF_COMPAT_OVERRIDES,
+                             "http://example.com/compat.json");
 
   Services.prefs.setBoolPref("extensions.getAddons.cache.enabled", true);
-  Services.prefs.setCharPref(PREF_GETADDONS_BYIDS,
-                             "http://example.com/data/test_install_addons.json");
-  Services.prefs.setCharPref(PREF_COMPAT_OVERRIDES,
-                             "http://example.com/data/test_install_compat.json");
-
   Services.prefs.setBoolPref("extensions.addon2@tests.mozilla.org.getAddons.cache.enabled", false);
 
   let url = "http://example.com/addons/test_install2_1.xpi";
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
+  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
+  await install.install();
 
-  let addon = await new Promise(resolve => {
-    aInstall.addListener({
-      onInstallEnded(unused, aAddon) {
-        resolve(aAddon);
-      },
-    });
-    aInstall.install();
-  });
-
-  notEqual(addon.fullDescription, "Repository description");
+  notEqual(install.addon.fullDescription, "Repository description");
 
   await promiseRestartManager();
 
-  let a2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  notEqual(a2.fullDescription, "Repository description");
+  let addon = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
+  notEqual(addon.fullDescription, "Repository description");
 
-  await a2.uninstall();
+  await addon.uninstall();
 });
 
 // Checks that metadata is downloaded for new installs and is visible before and
 // after restart
-add_task(async function test_19() {
-  await promiseRestartManager();
+add_task(async function test_metadata() {
   Services.prefs.setBoolPref("extensions.addon2@tests.mozilla.org.getAddons.cache.enabled", true);
 
   let url = "http://example.com/addons/test_install2_1.xpi";
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  await new Promise(resolve => {
-    aInstall.addListener({
-      onInstallEnded(unused, aAddon) {
-        resolve(aAddon);
-      },
-    });
-    aInstall.install();
-  });
+  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
+  await install.install();
 
-  let a1 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  equal(a1.fullDescription, "Repository description");
+  equal(install.addon.fullDescription, "Repository description");
 
   await promiseRestartManager();
 
-  let a2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  equal(a2.fullDescription, "Repository description");
+  let addon = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
+  equal(addon.fullDescription, "Repository description");
 
-  await a2.uninstall();
+  await addon.uninstall();
 });
 
 // Do the same again to make sure it works when the data is already in the cache
-add_task(async function test_20() {
-  await promiseRestartManager();
-
+add_task(async function test_metadata_again() {
   let url = "http://example.com/addons/test_install2_1.xpi";
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  await new Promise(resolve => {
-    aInstall.addListener({
-      onInstallEnded(unused, aAddon) {
-        resolve(aAddon);
-      },
-    });
-    aInstall.install();
-  });
+  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
+  await install.install();
 
-  let a1 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  equal(a1.fullDescription, "Repository description");
+  equal(install.addon.fullDescription, "Repository description");
 
   await promiseRestartManager();
 
-  let a2 = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
-  equal(a2.fullDescription, "Repository description");
+  let addon = await AddonManager.getAddonByID("addon2@tests.mozilla.org");
+  equal(addon.fullDescription, "Repository description");
 
-  await a2.uninstall();
+  await addon.uninstall();
 });
 
 // Tests that an install can be restarted after being cancelled
-add_task(async function test_22() {
-  prepare_test({ }, [
-    "onNewInstall",
-  ]);
+add_task(async function test_restart() {
+  let url = "http://example.com/addons/test_install1.xpi";
+  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
+  equal(install.state, AddonManager.STATE_AVAILABLE);
 
-  let url = "http://example.com/addons/test_install3.xpi";
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  ensure_test_completed();
-
-  checkInstall(aInstall, {
-    state: AddonManager.STATE_AVAILABLE,
+  install.addListener({
+    onDownloadEnded() {
+      install.removeListener(this);
+      install.cancel();
+    },
   });
 
-  let install = await new Promise(resolve => {
-    prepare_test({}, [
-      "onDownloadStarted",
-      "onDownloadEnded",
-    ], install1 => {
-      prepare_test({}, [
-        "onDownloadCancelled",
-      ]);
-      aInstall.cancel();
-      resolve(install1);
-    });
-    aInstall.install();
-  });
+  try {
+    await install.install();
+    ok(false, "Install should not have succeeded");
+  } catch (err) { }
 
-  ensure_test_completed();
-
-  await new Promise(resolve => {
+  let promise = new Promise(resolve => {
     prepare_test({
-      "addon3@tests.mozilla.org": [
+      "addon1@tests.mozilla.org": [
         ["onInstalling", false],
         "onInstalled",
       ],
     }, [
       "onDownloadStarted",
       "onDownloadEnded",
       "onInstallStarted",
       "onInstallEnded",
     ], resolve);
-
     install.install();
   });
 
+  await Promise.all([
+    promise,
+    promiseWebExtensionStartup("addon1@tests.mozilla.org"),
+  ]);
   ensure_test_completed();
 
-  AddonManager.removeAddonListener(AddonListener);
+  clearListeners();
+
   await install.addon.uninstall();
 });
 
 // Tests that an install can be restarted after being cancelled when a hash
 // was provided
-add_task(async function test_23() {
-  prepare_test({ }, [
-    "onNewInstall",
-  ]);
+add_task(async function test_restart_hash() {
+  let url = "http://example.com/addons/test_install1.xpi";
+  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", do_get_file_hash(XPIS.test_install1));
+  equal(install.state, AddonManager.STATE_AVAILABLE);
 
-  let url = "http://example.com/addons/test_install3.xpi";
-  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", do_get_file_hash(XPIS.test_install3));
-
-  ensure_test_completed();
-
-  checkInstall(install, {
-    state: AddonManager.STATE_AVAILABLE,
+  install.addListener({
+    onDownloadEnded() {
+      install.removeListener(this);
+      install.cancel();
+    },
   });
 
-  await new Promise(resolve => {
-    prepare_test({}, [
-      "onDownloadStarted",
-      "onDownloadEnded",
-    ], () => {
-      prepare_test({}, [
-        "onDownloadCancelled",
-      ]);
+  try {
+    await install.install();
+    ok(false, "Install should not have succeeded");
+  } catch (err) { }
 
-      install.cancel();
-      resolve();
-    });
-    install.install();
-  });
-
-  ensure_test_completed();
-
-  await new Promise(resolve => {
+  let promise = new Promise(resolve => {
     prepare_test({
-      "addon3@tests.mozilla.org": [
+      "addon1@tests.mozilla.org": [
         ["onInstalling", false],
         "onInstalled",
       ],
     }, [
       "onDownloadStarted",
       "onDownloadEnded",
       "onInstallStarted",
       "onInstallEnded",
     ], resolve);
-
     install.install();
   });
 
+  await Promise.all([
+    promise,
+    promiseWebExtensionStartup("addon1@tests.mozilla.org"),
+  ]);
   ensure_test_completed();
 
-  AddonManager.removeAddonListener(AddonListener);
+  clearListeners();
+
   await install.addon.uninstall();
+
 });
 
 // Tests that an install with a bad hash can be restarted after it fails, though
 // it will only fail again
-add_task(async function test_24() {
-  prepare_test({ }, [
-    "onNewInstall",
-  ]);
+add_task(async function test_restart_badhash() {
+  let url = "http://example.com/addons/test_install1.xpi";
+  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", "sha1:foo");
+  equal(install.state, AddonManager.STATE_AVAILABLE);
 
-  let url = "http://example.com/addons/test_install3.xpi";
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall", "sha1:foo");
-  ensure_test_completed();
-
-  checkInstall(aInstall, {
-    state: AddonManager.STATE_AVAILABLE,
+  install.addListener({
+    onDownloadEnded() {
+      install.removeListener(this);
+      install.cancel();
+    },
   });
 
-  let install = await new Promise(resolve => {
-    prepare_test({}, [
-      "onDownloadStarted",
-      "onDownloadFailed",
-    ], resolve);
-    aInstall.install();
-  });
+  try {
+    await install.install();
+    ok(false, "Install should not have succeeded");
+  } catch (err) { }
 
-  await new Promise(resolve => {
-    prepare_test({ }, [
-      "onDownloadStarted",
-      "onDownloadFailed",
-    ], resolve);
-
-    install.install();
-  });
+  try {
+    await install.install();
+    ok(false, "Install should not have succeeded");
+  } catch (err) {
+    ok(true, "Resumed install should have failed");
+  }
 });
 
 // Tests that installs with a hash for a local file work
-add_task(async function test_25() {
-  prepare_test({ }, [
-    "onNewInstall",
-  ]);
+add_task(async function test_local_hash() {
+  let url = Services.io.newFileURI(XPIS.test_install1).spec;
+  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", do_get_file_hash(XPIS.test_install1));
 
-  let url = Services.io.newFileURI(XPIS.test_install3).spec;
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall", do_get_file_hash(XPIS.test_install3));
-  ensure_test_completed();
-
-  checkInstall(aInstall, {
+  checkInstall(install, {
     state: AddonManager.STATE_DOWNLOADED,
     error: 0,
   });
 
-  prepare_test({ }, [
-    "onDownloadCancelled",
-  ]);
-
-  aInstall.cancel();
-
-  ensure_test_completed();
+  install.cancel();
 });
 
-add_task(async function test_26() {
-  prepare_test({ }, [
-    "onNewInstall",
-    "onDownloadStarted",
-    "onDownloadCancelled",
-  ]);
-
+// Test that an install may be canceled after a redirect.
+add_task(async function test_cancel_redirect() {
   let url = "http://example.com/redirect?/addons/test_install1.xpi";
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
+  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
 
-  await new Promise(resolve => {
-    let observerService = Cc["@mozilla.org/network/http-activity-distributor;1"].
-                          getService(Ci.nsIHttpActivityDistributor);
-    observerService.addObserver({
-      observeActivity(aChannel, aType, aSubtype, aTimestamp, aSizeData,
-                                aStringData) {
-        aChannel.QueryInterface(Ci.nsIChannel);
-        // Wait for the final event for the redirected URL
-        if (aChannel.URI.spec != "http://example.com/addons/test_install1.xpi" ||
-            aType != Ci.nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION ||
-            aSubtype != Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE)
-          return;
-
-        // Request should have been cancelled
-        equal(aChannel.status, Cr.NS_BINDING_ABORTED);
+  install.addListener({
+    onDownloadProgress() {
+      install.cancel();
+    },
+  });
 
-        observerService.removeObserver(this);
-
-        resolve();
-      },
-    });
+  let promise = AddonTestUtils.promiseInstallEvent("onDownloadCancelled");
 
-    aInstall.addListener({
-      onDownloadProgress(aDownloadProgressInstall) {
-        aDownloadProgressInstall.cancel();
-      },
-    });
+  install.install();
+  await promise;
 
-    aInstall.install();
-  });
+  equal(install.state, AddonManager.STATE_CANCELLED);
 });
 
-
 // Tests that an install can be restarted during onDownloadCancelled after being
 // cancelled in mid-download
-add_task(async function test_27() {
-  prepare_test({ }, [
-    "onNewInstall",
-  ]);
-
-  let url = "http://example.com/addons/test_install3.xpi";
-  let aInstall = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
-  ensure_test_completed();
+add_task(async function test_restart2() {
+  let url = "http://example.com/addons/test_install1.xpi";
+  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
 
-  checkInstall(aInstall, {
-    state: AddonManager.STATE_AVAILABLE,
-  });
+  equal(install.state, AddonManager.STATE_AVAILABLE);
 
-  aInstall.addListener({
+  install.addListener({
     onDownloadProgress() {
-      aInstall.removeListener(this);
-      aInstall.cancel();
+      install.removeListener(this);
+      install.cancel();
     },
   });
 
-  let install = await new Promise(resolve => {
-    prepare_test({}, [
-      "onDownloadStarted",
-      "onDownloadCancelled",
-    ], resolve);
-    aInstall.install();
-  });
+  let promise = AddonTestUtils.promiseInstallEvent("onDownloadCancelled");
+  install.install();
+  await promise;
 
-  install = await new Promise(resolve => {
+  equal(install.state, AddonManager.STATE_CANCELLED);
+
+  promise = new Promise(resolve => {
     prepare_test({
-      "addon3@tests.mozilla.org": [
+      "addon1@tests.mozilla.org": [
         ["onInstalling", false],
         "onInstalled",
       ],
     }, [
       "onDownloadStarted",
       "onDownloadEnded",
       "onInstallStarted",
       "onInstallEnded",
     ], resolve);
 
     let file = install.file;
     install.install();
     notEqual(file.path, install.file.path);
     ok(!file.exists());
   });
 
-  ensure_test_completed();
-
-  AddonManager.removeAddonListener(AddonListener);
-  await install.addon.uninstall();
-});
-
-// Tests that an install with a matching compatibility override has appDisabled
-// set correctly.
-add_task(async function test_29() {
-  Services.prefs.setBoolPref("extensions.getAddons.cache.enabled", true);
-
-  prepare_test({ }, [
-    "onNewInstall",
+  await Promise.all([
+    promise,
+    promiseWebExtensionStartup("addon1@tests.mozilla.org"),
   ]);
 
-  let url = "http://example.com/addons/test_install6.xpi";
-  let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", null, "Addon Test 6", null, "1.0");
   ensure_test_completed();
 
-  checkInstall(install, {
-    version: "1.0",
-    name: "Addon Test 6",
-    state: AddonManager.STATE_AVAILABLE,
-  });
-
-  let activeInstalls = await AddonManager.getInstallsByTypes(null);
-  equal(activeInstalls.length, 1);
-  equal(activeInstalls[0], install);
-
-  install = await new Promise(resolve => {
-    prepare_test({}, [
-      "onDownloadStarted",
-      "onDownloadEnded",
-    ], install2 => {
-      resolve(install2);
-      return false;
-    });
-    install.install();
-  });
-
-  // ensure_test_completed();
-  checkInstall(install, {
-    state: AddonManager.STATE_DOWNLOADED,
-  });
-  checkAddon("addon6@tests.mozilla.org", install.addon, {
-    isCompatible: false,
-    appDisabled: true,
-  });
-
-  await new Promise(resolve => {
-    prepare_test({}, [
-      "onDownloadCancelled",
-    ], resolve);
-    install.cancel();
-  });
+  clearListeners();
+  await install.addon.uninstall();
 });
-
-// Tests that a multi-package XPI with no add-ons inside shows up as a
-// corrupt file
-add_task(async function test_30() {
-  prepare_test({ }, [
-    "onNewInstall",
-  ]);
-
-  let install = await AddonManager.getInstallForFile(XPIS.test_install7);
-  ensure_test_completed();
-
-  checkInstall(install, {
-    state: AddonManager.STATE_DOWNLOAD_FAILED,
-    error: AddonManager.ERROR_CORRUPT_FILE,
-  });
-});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_isDebuggable.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_isDebuggable.js
@@ -1,37 +1,21 @@
 /* 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/.
  */
 
-var ID = "bootstrap2@tests.mozilla.org";
-
-const ADDON = {
-  id: ID,
-  version: "1.0",
-  bootstrap: "true",
-  multiprocessCompatible: "true",
-
-  name: "Test Bootstrap 2",
-  description: "Test Description",
-
-  iconURL: "chrome://foo/skin/icon.png",
-  aboutURL: "chrome://foo/content/about.xul",
-  optionsURL: "chrome://foo/content/options.xul",
-
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1"}],
-};
+var ID = "debuggable@tests.mozilla.org";
 
 add_task(async function() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "2");
 
   await promiseStartupManager();
-  AddonManager.checkCompatibility = false;
 
-  await promiseInstallXPI(ADDON);
+  await promiseInstallWebExtension({
+    manifest: {
+      applications: {gecko: {id: ID}},
+    },
+  });
 
   let addon = await AddonManager.getAddonByID(ID);
   Assert.equal(addon.isDebuggable, true);
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_locale.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_locale.js
@@ -1,132 +1,97 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
-
-const ADDONS = {
-  test_locale: {
-    "install.rdf": {
-      "id": "addon1@tests.mozilla.org",
-      "name": "Fallback Name",
-      "description": "Fallback Description",
-      "localized": [
-        {
-          "name": "fr-FR Name",
-          "description": "fr-FR Description",
-          "locale": [
-            "fr-FR",
-            "",
-          ],
-          "contributor": [
-            "Fr Contributor 1",
-            "Fr Contributor 2",
-            "Fr Contributor 3",
-          ],
-        },
-        {
-          "name": "de-DE Name",
-          "locale": [
-            "de-DE",
-          ],
-        },
-        {
-          "name": "es-ES Name",
-          "description": "es-ES Description",
-          "locale": [
-            "es-ES",
-          ],
-        },
-        {
-          "name": "Repeated locale",
-          "locale": [
-            "fr-FR",
-          ],
-        },
-        {
-          "name": "Missing locale",
-        },
-      ],
-    },
-  },
-};
-
 add_task(async function setup() {
   // Setup for test
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
   await promiseStartupManager();
 });
 
 // Tests that the localized properties are visible before installation
 add_task(async function test_1() {
   await restartWithLocales(["fr-FR"]);
 
-  let xpi = AddonTestUtils.createTempXPIFile(ADDONS.test_locale);
+  let xpi = AddonTestUtils.createTempWebExtensionFile({
+    manifest: {
+      "name": "__MSG_name__",
+      "description": "__MSG_description__",
+      default_locale: "en",
+
+      applications: {
+        gecko: {
+          "id": "addon1@tests.mozilla.org",
+        },
+      },
+    },
+
+    files: {
+      "_locales/en/messages.json": {
+        name: {
+          message: "Fallback Name",
+          description: "name",
+        },
+        description: {
+          message: "Fallback Description",
+          description: "description",
+        },
+      },
+      "_locales/fr_FR/messages.json": {
+        name: {
+          message: "fr-FR Name",
+          description: "name",
+        },
+        description: {
+          message: "fr-FR Description",
+          description: "description",
+        },
+      },
+      "_locales/de-DE/messages.json": {
+        name: {
+          message: "de-DE Name",
+          description: "name",
+        },
+      },
+    },
+  });
+
   let install = await AddonManager.getInstallForFile(xpi);
   Assert.equal(install.addon.name, "fr-FR Name");
   Assert.equal(install.addon.description, "fr-FR Description");
-
-  await new Promise(resolve => {
-    prepare_test({
-      "addon1@tests.mozilla.org": [
-        ["onInstalling", false],
-        ["onInstalled", false],
-      ],
-    }, [
-      "onInstallStarted",
-      "onInstallEnded",
-    ], resolve);
-    install.install();
-  });
+  await install.install();
 });
 
 // Tests that the localized properties are visible after installation
 add_task(async function test_2() {
-  await promiseRestartManager();
-
   let addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
   Assert.notEqual(addon, null);
 
   Assert.equal(addon.name, "fr-FR Name");
   Assert.equal(addon.description, "fr-FR Description");
 
   await addon.disable();
 });
 
 // Test that the localized properties are still there when disabled.
 add_task(async function test_3() {
-  await promiseRestartManager();
-
   let addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
   Assert.notEqual(addon, null);
   Assert.equal(addon.name, "fr-FR Name");
 });
 
-add_task(async function test_4() {
-  await promiseRestartManager();
-
-  let addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
-  Assert.notEqual(addon, null);
-  Assert.equal(addon.name, "fr-FR Name");
-  let contributors = addon.contributors;
-  Assert.equal(contributors.length, 3);
-  Assert.equal(contributors[0], "Fr Contributor 1");
-  Assert.equal(contributors[1], "Fr Contributor 2");
-  Assert.equal(contributors[2], "Fr Contributor 3");
-});
-
 // Test that changing locale works
 add_task(async function test_5() {
   await restartWithLocales(["de-DE"]);
 
   let addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
   Assert.notEqual(addon, null);
 
   Assert.equal(addon.name, "de-DE Name");
-  Assert.equal(addon.description, null);
+  Assert.equal(addon.description, "Fallback Description");
 });
 
 // Test that missing locales use the fallbacks
 add_task(async function test_6() {
   await restartWithLocales(["nl-NL"]);
 
   let addon = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
   Assert.notEqual(addon, null);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_nodisable_hidden.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_nodisable_hidden.js
@@ -1,41 +1,34 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // This test verifies that hidden add-ons cannot be user disabled.
 
-// for normal add-ons
-const profileDir = FileUtils.getDir("ProfD", ["extensions"]);
 // for system add-ons
 const distroDir = FileUtils.getDir("ProfD", ["sysfeatures"], true);
 registerDirectory("XREAppFeat", distroDir);
 
 const NORMAL_ID = "normal@tests.mozilla.org";
 const SYSTEM_ID = "system@tests.mozilla.org";
 
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
 
 // normal add-ons can be user disabled.
 add_task(async function() {
+  await promiseStartupManager();
 
-  await promiseWriteInstallRDFToXPI({
-    id: NORMAL_ID,
-    version: "1.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test disabling hidden add-ons, non-hidden add-on case.",
-  }, profileDir, NORMAL_ID);
-
-  await promiseStartupManager();
+  await promiseInstallWebExtension({
+    manifest: {
+      name: "Test disabling hidden add-ons, non-hidden add-on case.",
+      version: "1.0",
+      applications: {gecko: {id: NORMAL_ID}},
+    },
+  });
 
   let addon = await promiseAddonByID(NORMAL_ID);
   Assert.notEqual(addon, null);
   Assert.equal(addon.version, "1.0");
   Assert.equal(addon.name, "Test disabling hidden add-ons, non-hidden add-on case.");
   Assert.ok(addon.isCompatible);
   Assert.ok(!addon.appDisabled);
   Assert.ok(!addon.userDisabled);
@@ -56,54 +49,40 @@ add_task(async function() {
 
   await addon.uninstall();
 
   await promiseShutdownManager();
 });
 
 // system add-ons can never be user disabled.
 add_task(async function() {
-
-  await promiseWriteInstallRDFToXPI({
-    id: SYSTEM_ID,
-    version: "1.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test disabling hidden add-ons, hidden system add-on case.",
-  }, distroDir, SYSTEM_ID);
-
+  let xpi = createTempWebExtensionFile({
+    manifest: {
+      name: "Test disabling hidden add-ons, hidden system add-on case.",
+      version: "1.0",
+      applications: {gecko: {id: SYSTEM_ID}},
+    },
+  });
+  xpi.copyTo(distroDir, `${SYSTEM_ID}.xpi`);
   await overrideBuiltIns({ "system": [SYSTEM_ID] });
 
   await promiseStartupManager();
 
   let addon = await promiseAddonByID(SYSTEM_ID);
   Assert.notEqual(addon, null);
   Assert.equal(addon.version, "1.0");
   Assert.equal(addon.name, "Test disabling hidden add-ons, hidden system add-on case.");
   Assert.ok(addon.isCompatible);
   Assert.ok(!addon.appDisabled);
   Assert.ok(!addon.userDisabled);
   Assert.ok(addon.isActive);
   Assert.equal(addon.type, "extension");
 
   // system add-ons cannot be disabled by the user.
-  try {
-    await addon.disable();
-    do_throw("Expected addon.userDisabled on a hidden add-on to throw!");
-  } catch (e) {
-    Assert.equal(e.message, `Cannot disable system add-on ${SYSTEM_ID}`);
-  }
+  await Assert.rejects(addon.disable(),
+                       err => err.message == `Cannot disable system add-on ${SYSTEM_ID}`,
+                       "disable() on a hidden add-on should fail");
 
-  Assert.notEqual(addon, null);
-  Assert.equal(addon.version, "1.0");
-  Assert.equal(addon.name, "Test disabling hidden add-ons, hidden system add-on case.");
-  Assert.ok(addon.isCompatible);
-  Assert.ok(!addon.appDisabled);
   Assert.ok(!addon.userDisabled);
   Assert.ok(addon.isActive);
-  Assert.equal(addon.type, "extension");
 
   await promiseShutdownManager();
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_proxies.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_proxies.js
@@ -23,26 +23,16 @@ var ADDONS = [
     type: "symlink",
   },
   {
     id: "symlink2@tests.mozilla.org",
     type: "symlink",
   },
 ];
 
-var METADATA = {
-  version: "2.0",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "2",
-    maxVersion: "2",
-  }],
-};
-
 const gHaveSymlinks = AppConstants.platform != "win";
 
 
 function createSymlink(aSource, aDest) {
   if (aSource instanceof Ci.nsIFile)
     aSource = aSource.path;
   if (aDest instanceof Ci.nsIFile)
     aDest = aDest.path;
@@ -55,17 +45,17 @@ function promiseWriteFile(aFile, aData) 
     aFile.parent.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
 
   return OS.File.writeAtomic(aFile.path, new TextEncoder().encode(aData));
 }
 
 function checkAddonsExist() {
   for (let addon of ADDONS) {
     let file = addon.directory.clone();
-    file.append("install.rdf");
+    file.append("manifest.json");
     Assert.ok(file.exists());
   }
 }
 
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
@@ -92,19 +82,24 @@ async function run_proxy_tests() {
 
   for (let addon of ADDONS) {
     addon.directory = gTmpD.clone();
     addon.directory.append(addon.id);
 
     addon.proxyFile = profileDir.clone();
     addon.proxyFile.append(addon.dirId || addon.id);
 
-    METADATA.id = addon.id;
-    METADATA.name = addon.id;
-    await promiseWriteInstallRDFToDir(METADATA, gTmpD);
+    let files = ExtensionTestCommon.generateFiles({
+      manifest: {
+        name: addon.id,
+        applications: {gecko: {id: addon.id}},
+      },
+    });
+    let path = OS.Path.join(gTmpD.path, addon.id);
+    await AddonTestUtils.promiseWriteFilesToDir(path, files);
 
     if (addon.type == "proxy") {
       await promiseWriteFile(addon.proxyFile, addon.directory.path);
     } else if (addon.type == "symlink") {
       await createSymlink(addon.directory, addon.proxyFile);
     }
   }
 
@@ -168,49 +163,49 @@ async function run_proxy_tests() {
         addon.proxyFile.remove(false);
       } catch (e) {}
     }
   } catch (e) {
     do_throw(e);
   }
 }
 
+// Check that symlinks are not followed out of a directory tree
+// when deleting an add-on.
 async function run_symlink_tests() {
-  // Check that symlinks are not followed out of a directory tree
-  // when deleting an add-on.
-
-  METADATA.id = "unpacked@test.mozilla.org";
-  METADATA.name = METADATA.id;
-  METADATA.unpack = "true";
+  const ID = "unpacked@test.mozilla.org";
 
   let tempDirectory = gTmpD.clone();
-  tempDirectory.append(METADATA.id);
+  tempDirectory.append(ID);
 
   let tempFile = tempDirectory.clone();
   tempFile.append("test.txt");
   tempFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
 
   let addonDirectory = profileDir.clone();
-  addonDirectory.append(METADATA.id);
+  addonDirectory.append(ID);
 
-  await promiseWriteInstallRDFToDir(METADATA, profileDir);
+  let files = ExtensionTestCommon.generateFiles({
+    manifest: {applications: {gecko: {id: ID}}},
+  });
+  await AddonTestUtils.promiseWriteFilesToDir(addonDirectory.path, files);
 
   let symlink = addonDirectory.clone();
   symlink.append(tempDirectory.leafName);
   await createSymlink(tempDirectory, symlink);
 
   // Make sure that the symlink was created properly.
   let file = symlink.clone();
   file.append(tempFile.leafName);
   file.normalize();
   Assert.equal(file.path.replace(/^\/private\//, "/"), tempFile.path);
 
   await promiseStartupManager();
 
-  let addon = await AddonManager.getAddonByID(METADATA.id);
+  let addon = await AddonManager.getAddonByID(ID);
   Assert.notEqual(addon, null);
 
   await addon.uninstall();
 
   await promiseRestartManager();
   await promiseShutdownManager();
 
   // Check that the install directory is gone.
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_proxy.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-const ID = "proxy1@tests.mozilla.org";
-
-createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
-
-BootstrapMonitor.init();
-
-// Ensure that a proxy file to an add-on with a valid manifest works.
-add_task(async function() {
-  Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, false);
-
-  await promiseStartupManager();
-
-  let tempdir = gTmpD.clone();
-  let unpackedAddon = await promiseWriteInstallRDFToDir({
-    id: ID,
-    version: "1.0",
-    bootstrap: true,
-    unpack: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test Bootstrap 1 (proxy)",
-  }, tempdir, ID, {
-    "bootstrap.js": BOOTSTRAP_MONITOR_BOOTSTRAP_JS,
-  });
-
-  // create proxy file in profile/extensions dir
-  let extensionsDir = gProfD.clone();
-  extensionsDir.append("extensions");
-  let proxyFile = await promiseWriteProxyFileToDir(extensionsDir, unpackedAddon, ID);
-
-  await promiseRestartManager();
-
-  let addon = await promiseAddonByID(ID);
-
-  if (AppConstants.MOZ_REQUIRE_SIGNING) {
-    BootstrapMonitor.checkAddonNotInstalled(ID, "1.0");
-    BootstrapMonitor.checkAddonNotStarted(ID, "1.0");
-
-    Assert.equal(addon, null);
-  } else {
-    BootstrapMonitor.checkAddonInstalled(ID, "1.0");
-    BootstrapMonitor.checkAddonStarted(ID, "1.0");
-
-    Assert.notEqual(addon, null);
-    Assert.equal(addon.version, "1.0");
-    Assert.equal(addon.name, "Test Bootstrap 1 (proxy)");
-    Assert.ok(addon.isCompatible);
-    Assert.ok(!addon.appDisabled);
-    Assert.ok(addon.isActive);
-    Assert.equal(addon.type, "extension");
-    Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_UNKNOWN);
-
-    Assert.ok(proxyFile.exists());
-
-    await addon.uninstall();
-  }
-  unpackedAddon.remove(true);
-
-  await promiseRestartManager();
-});
-
-
-// Ensure that a proxy file to an add-on is not removed even
-// if the manifest file is invalid. See bug 1195353.
-add_task(async function() {
-  let tempdir = gTmpD.clone();
-
-  // use a mismatched ID to make this install.rdf invalid
-  let unpackedAddon = await promiseWriteInstallRDFToDir({
-    id: "bad-proxy1@tests.mozilla.org",
-    version: "1.0",
-    bootstrap: true,
-    unpack: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1",
-    }],
-    name: "Test Bootstrap 1 (proxy)",
-  }, tempdir, ID, {
-    "bootstrap.js": BOOTSTRAP_MONITOR_BOOTSTRAP_JS,
-  });
-
-  // create proxy file in profile/extensions dir
-  let extensionsDir = gProfD.clone();
-  extensionsDir.append("extensions");
-  let proxyFile = await promiseWriteProxyFileToDir(extensionsDir, unpackedAddon, ID);
-
-  await promiseRestartManager();
-
-  BootstrapMonitor.checkAddonNotInstalled(ID, "1.0");
-  BootstrapMonitor.checkAddonNotStarted(ID, "1.0");
-
-  let addon = await promiseAddonByID(ID);
-  Assert.equal(addon, null);
-
-  Assert.ok(proxyFile.exists());
-
-  unpackedAddon.remove(true);
-  proxyFile.remove(true);
-
-  await promiseRestartManager();
-});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_reload.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_reload.js
@@ -1,12 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
-ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
 
 const ID = "webextension1@tests.mozilla.org";
 
 const ADDONS = {
   webextension_1: {
     "manifest.json": {
@@ -22,27 +21,16 @@ const ADDONS = {
         "48": "icon48.png",
         "64": "icon64.png",
       },
     },
     "chrome.manifest": "content webex ./\n",
   },
 };
 
-const manifestSample = {
-  id: "bootstrap1@tests.mozilla.org",
-  version: "1.0",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
-
 async function tearDownAddon(addon) {
   await addon.uninstall();
   await promiseShutdownManager();
 }
 
 add_task(async function test_reloading_a_temp_addon() {
   await promiseRestartManager();
   let xpi = AddonTestUtils.createTempXPIFile(ADDONS.webextension_1);
@@ -170,71 +158,8 @@ add_task(async function test_reload_to_i
   equal(reloadedAddon.id, addonId);
   equal(reloadedAddon.version, "1.0");
   equal(reloadedAddon.appDisabled, false);
   equal(reloadedAddon.userDisabled, false);
 
   await tearDownAddon(reloadedAddon);
   addonDir.remove(true);
 });
-
-add_task(async function test_manifest_changes_are_refreshed() {
-  if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
-    return;
-  }
-  await promiseRestartManager();
-  let tempdir = gTmpD.clone();
-
-  const unpackedAddon = await promiseWriteInstallRDFToDir(
-    Object.assign({}, manifestSample, {
-      name: "Test Bootstrap 1",
-    }), tempdir, manifestSample.id, "bootstrap.js");
-
-  await AddonManager.installTemporaryAddon(unpackedAddon);
-  const addon = await promiseAddonByID(manifestSample.id);
-  notEqual(addon, null);
-  equal(addon.name, "Test Bootstrap 1");
-
-  await promiseWriteInstallRDFToDir(Object.assign({}, manifestSample, {
-    name: "Test Bootstrap 1 (reloaded)",
-  }), tempdir, manifestSample.id);
-
-  await addon.reload();
-
-  const reloadedAddon = await promiseAddonByID(manifestSample.id);
-  notEqual(reloadedAddon, null);
-  equal(reloadedAddon.name, "Test Bootstrap 1 (reloaded)");
-
-  await tearDownAddon(reloadedAddon);
-  unpackedAddon.remove(true);
-});
-
-add_task(async function test_reload_fails_on_installation_errors() {
-  if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
-    return;
-  }
-  await promiseRestartManager();
-  let tempdir = gTmpD.clone();
-
-  const unpackedAddon = await promiseWriteInstallRDFToDir(
-    Object.assign({}, manifestSample, {
-      name: "Test Bootstrap 1",
-    }), tempdir, manifestSample.id, "bootstrap.js");
-
-  await AddonManager.installTemporaryAddon(unpackedAddon);
-  const addon = await promiseAddonByID(manifestSample.id);
-  notEqual(addon, null);
-
-  // Trigger an installation error with an empty manifest.
-  await promiseWriteInstallRDFToDir({}, tempdir, manifestSample.id);
-
-  await Assert.rejects(addon.reload(), /No ID in install manifest/);
-
-  // The old add-on should be active. I.E. the broken reload will not
-  // disturb it.
-  const oldAddon = await promiseAddonByID(manifestSample.id);
-  notEqual(oldAddon, null);
-  equal(oldAddon.isActive, true);
-  equal(oldAddon.name, "Test Bootstrap 1");
-
-  await tearDownAddon(addon);
-  unpackedAddon.remove(true);
-});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_safemode.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_safemode.js
@@ -1,110 +1,65 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Tests that extensions behave correctly in safe mode
 
-var addon1 = {
-  id: "addon1@tests.mozilla.org",
-  version: "1.0",
-  name: "Test 1",
-  optionsURL: "chrome://foo/content/options.xul",
-  aboutURL: "chrome://foo/content/about.xul",
-  iconURL: "chrome://foo/content/icon.png",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
-
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
-var gIconURL = null;
+const ID = "addon1@tests.mozilla.org";
+const VERSION = "1.0";
 
 // Sets up the profile by installing an add-on.
-async function run_test() {
-  do_test_pending();
+add_task(async function setup() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
   gAppInfo.inSafeMode = true;
 
   await promiseStartupManager();
 
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+  let a1 = await AddonManager.getAddonByID(ID);
   Assert.equal(a1, null);
-  do_check_not_in_crash_annotation(addon1.id, addon1.version);
+  do_check_not_in_crash_annotation(ID, VERSION);
 
-  await promiseWriteInstallRDFForExtension(addon1, profileDir, addon1.id, "icon.png");
-  gIconURL = do_get_addon_root_uri(profileDir.clone(), addon1.id) + "icon.png";
+  await promiseInstallWebExtension({
+    manifest: {
+      name: "Test 1",
+      version: VERSION,
+      applications: {gecko: {id: ID}},
+    },
+  });
 
   await promiseRestartManager();
 
-  let newa1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
-  Assert.notEqual(newa1, null);
-  Assert.ok(!newa1.isActive);
-  Assert.ok(!newa1.userDisabled);
-  Assert.equal(newa1.aboutURL, null);
-  Assert.equal(newa1.optionsURL, null);
-  Assert.equal(newa1.iconURL, gIconURL);
-  Assert.ok(isExtensionInBootstrappedList(profileDir, newa1.id));
-  Assert.ok(hasFlag(newa1.permissions, AddonManager.PERM_CAN_DISABLE));
-  Assert.ok(!hasFlag(newa1.permissions, AddonManager.PERM_CAN_ENABLE));
-  Assert.equal(newa1.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_NONE);
-  do_check_not_in_crash_annotation(addon1.id, addon1.version);
-
-  run_test_1();
-}
+  a1 = await AddonManager.getAddonByID(ID);
+  Assert.notEqual(a1, null);
+  Assert.ok(!a1.isActive);
+  Assert.ok(!a1.userDisabled);
+  Assert.ok(isExtensionInBootstrappedList(profileDir, ID));
+  Assert.ok(hasFlag(a1.permissions, AddonManager.PERM_CAN_DISABLE));
+  Assert.ok(!hasFlag(a1.permissions, AddonManager.PERM_CAN_ENABLE));
+  do_check_not_in_crash_annotation(ID, VERSION);
+});
 
 // Disabling an add-on should work
-async function run_test_1() {
-  prepare_test({
-    "addon1@tests.mozilla.org": [
-      ["onDisabling", false],
-      "onDisabled",
-    ],
-  });
-
-  let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
+add_task(async function test_disable() {
+  let a1 = await AddonManager.getAddonByID(ID);
   Assert.ok(!hasFlag(a1.operationsRequiringRestart,
                      AddonManager.OP_NEEDS_RESTART_DISABLE));
   await a1.disable();
   Assert.ok(!a1.isActive);
-  Assert.equal(a1.aboutURL, null);
-  Assert.equal(a1.optionsURL, null);
-  Assert.equal(a1.iconURL, gIconURL);
   Assert.ok(!hasFlag(a1.permissions, AddonManager.PERM_CAN_DISABLE));
   Assert.ok(hasFlag(a1.permissions, AddonManager.PERM_CAN_ENABLE));
-  Assert.equal(a1.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_NONE);
-  do_check_not_in_crash_annotation(addon1.id, addon1.version);
-
-  ensure_test_completed();
-
-  run_test_2();
-}
+  do_check_not_in_crash_annotation(ID, VERSION);
+});
 
-// Enabling an add-on should happen without restart but not become active.
-async function run_test_2() {
-  prepare_test({
-    "addon1@tests.mozilla.org": [
-      ["onEnabling", false],
-      "onEnabled",
-    ],
-  });
-
+// Enabling an add-on should happen but not become active.
+add_task(async function test_enable() {
   let a1 = await AddonManager.getAddonByID("addon1@tests.mozilla.org");
   await a1.enable();
   Assert.ok(!a1.isActive);
-  Assert.equal(a1.aboutURL, null);
-  Assert.equal(a1.optionsURL, null);
-  Assert.equal(a1.iconURL, gIconURL);
   Assert.ok(hasFlag(a1.permissions, AddonManager.PERM_CAN_DISABLE));
   Assert.ok(!hasFlag(a1.permissions, AddonManager.PERM_CAN_ENABLE));
-  Assert.equal(a1.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_NONE);
-  do_check_not_in_crash_annotation(addon1.id, addon1.version);
 
-  ensure_test_completed();
-
-  executeSoon(do_test_finished);
-}
+  do_check_not_in_crash_annotation(ID, VERSION);
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_schema_change.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_schema_change.js
@@ -1,318 +1,101 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-BootstrapMonitor.init();
-
 const PREF_DB_SCHEMA = "extensions.databaseSchema";
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "49");
 
-/**
- *  Schema change with no application update reloads metadata.
- */
-add_task(async function schema_change() {
-  await promiseStartupManager();
-
+add_task(async function run_tests() {
   const ID = "schema-change@tests.mozilla.org";
 
-  let xpiFile = createTempXPIFile({
-    id: ID,
-    name: "Test Add-on",
-    version: "1.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1.9.2",
-    }],
+  const xpi1 = createTempWebExtensionFile({
+    manifest: {
+      name: "Test Add-on",
+      version: "1.0",
+      applications: {gecko: {id: ID}},
+    },
   });
 
-  await promiseInstallFile(xpiFile);
-
-  let addon = await promiseAddonByID(ID);
-
-  notEqual(addon, null, "Got an addon object as expected");
-  equal(addon.version, "1.0", "Got the expected version");
-
-  await promiseShutdownManager();
-
-  xpiFile = createTempXPIFile({
-    id: ID,
-    name: "Test Add-on 2",
-    version: "2.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1.9.2",
-    }],
+  const xpi2 = createTempWebExtensionFile({
+    manifest: {
+      name: "Test Add-on 2",
+      version: "2.0",
+      applications: {gecko: {id: ID}},
+    },
   });
 
-  Services.prefs.setIntPref(PREF_DB_SCHEMA, 0);
-
-  let file = profileDir.clone();
-  file.append(`${ID}.xpi`);
-
-  // Make sure the timestamp is unchanged, so it is not re-scanned for that reason.
-  let timestamp = file.lastModifiedTime;
-  xpiFile.moveTo(profileDir, `${ID}.xpi`);
-
-  file.lastModifiedTime = timestamp;
-
-  await promiseStartupManager();
-
-  addon = await promiseAddonByID(ID);
-  notEqual(addon, null, "Got an addon object as expected");
-  equal(addon.version, "2.0", "Got the expected version");
-
-  let waitUninstall = promiseAddonEvent("onUninstalled");
-  await addon.uninstall();
-  await waitUninstall;
-});
-
-/**
- *  Application update with no schema change does not reload metadata.
- */
-add_task(async function schema_change() {
-  const ID = "schema-change@tests.mozilla.org";
+  let xpiPath = OS.Path.join(profileDir.path, `${ID}.xpi`);
 
-  let xpiFile = createTempXPIFile({
-    id: ID,
-    name: "Test Add-on",
-    version: "1.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "2",
-    }],
-  });
-
-  await promiseInstallFile(xpiFile);
-
-  let addon = await promiseAddonByID(ID);
-
-  notEqual(addon, null, "Got an addon object as expected");
-  equal(addon.version, "1.0", "Got the expected version");
-
-  await promiseShutdownManager();
-
-  xpiFile = createTempXPIFile({
-    id: ID,
-    name: "Test Add-on 2",
-    version: "2.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "2",
-    }],
-  });
-
-  gAppInfo.version = "2";
-  let file = profileDir.clone();
-  file.append(`${ID}.xpi`);
-
-  // Make sure the timestamp is unchanged, so it is not re-scanned for that reason.
-  let timestamp = file.lastModifiedTime;
-  xpiFile.moveTo(profileDir, `${ID}.xpi`);
-
-  file.lastModifiedTime = timestamp;
+  const TESTS = [
+    {
+      what: "Schema change with no application update reloads metadata.",
+      expectedVersion: "2.0",
+      action() {
+        Services.prefs.setIntPref(PREF_DB_SCHEMA, 0);
+      },
+    },
+    {
+      what: "Application update with no schema change does not reload metadata.",
+      expectedVersion: "1.0",
+      action() {
+        gAppInfo.version = "2";
+      },
+    },
+    {
+      what: "App update and a schema change causes a reload of the manifest.",
+      expectedVersion: "2.0",
+      action() {
+        gAppInfo.version = "3";
+        Services.prefs.setIntPref(PREF_DB_SCHEMA, 0);
+      },
+    },
+    {
+      what: "No schema change, no manifest reload.",
+      expectedVersion: "1.0",
+      action() {},
+    },
+    {
+      what: "Modified timestamp on the XPI causes a reload of the manifest.",
+      expectedVersion: "2.0",
+      async action() {
+        let stat = await OS.File.stat(xpiPath);
+        await OS.File.setDates(xpiPath, stat.lastAccessDate,
+                               stat.lastModificationDate.valueOf() + 60 * 1000);
+      },
+    },
+  ];
 
   await promiseStartupManager();
 
-  addon = await promiseAddonByID(ID);
-  notEqual(addon, null, "Got an addon object as expected");
-  equal(addon.version, "1.0", "Got the expected version");
-
-  let waitUninstall = promiseAddonEvent("onUninstalled");
-  await addon.uninstall();
-  await waitUninstall;
-});
-
-/**
- *  App update and a schema change causes a reload of the manifest.
- */
-add_task(async function schema_change_app_update() {
-  const ID = "schema-change@tests.mozilla.org";
-
-  let xpiFile = createTempXPIFile({
-    id: ID,
-    name: "Test Add-on",
-    version: "1.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3",
-    }],
-  });
-
-  await promiseInstallFile(xpiFile);
-
-  let addon = await promiseAddonByID(ID);
-
-  notEqual(addon, null, "Got an addon object as expected");
-  equal(addon.version, "1.0", "Got the expected version");
-
-  await promiseShutdownManager();
+  for (let test of TESTS) {
+    info(test.what);
+    await promiseInstallFile(xpi1);
 
-  xpiFile = createTempXPIFile({
-    id: ID,
-    name: "Test Add-on 2",
-    version: "2.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "3",
-    }],
-  });
-
-  gAppInfo.version = "3";
-  Services.prefs.setIntPref(PREF_DB_SCHEMA, 0);
-
-  let file = profileDir.clone();
-  file.append(`${ID}.xpi`);
-
-  // Make sure the timestamp is unchanged, so it is not re-scanned for that reason.
-  let timestamp = file.lastModifiedTime;
-  xpiFile.moveTo(profileDir, `${ID}.xpi`);
-
-  file.lastModifiedTime = timestamp;
-
-  await promiseStartupManager();
+    let addon = await promiseAddonByID(ID);
+    notEqual(addon, null, "Got an addon object as expected");
+    equal(addon.version, "1.0", "Got the expected version");
 
-  addon = await promiseAddonByID(ID);
-  notEqual(addon, null, "Got an addon object as expected");
-  equal(addon.appDisabled, false);
-  equal(addon.version, "2.0", "Got the expected version");
-
-  let waitUninstall = promiseAddonEvent("onUninstalled");
-  await addon.uninstall();
-  await waitUninstall;
-});
-
-/**
- *  No schema change, no manifest reload.
- */
-add_task(async function schema_change() {
-  const ID = "schema-change@tests.mozilla.org";
+    await promiseShutdownManager();
 
-  let xpiFile = createTempXPIFile({
-    id: ID,
-    name: "Test Add-on",
-    version: "1.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1.9.2",
-    }],
-  });
+    let orig = await OS.File.stat(xpiPath);
 
-  await promiseInstallFile(xpiFile);
-
-  let addon = await promiseAddonByID(ID);
+    xpi2.copyTo(profileDir, `${ID}.xpi`);
 
-  notEqual(addon, null, "Got an addon object as expected");
-  equal(addon.version, "1.0", "Got the expected version");
-
-  await promiseShutdownManager();
-
-  xpiFile = createTempXPIFile({
-    id: ID,
-    name: "Test Add-on 2",
-    version: "2.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1.9.2",
-    }],
-  });
-
-  let file = profileDir.clone();
-  file.append(`${ID}.xpi`);
+    // Make sure the timestamp is unchanged, so it is not re-scanned for that reason.
+    await OS.File.setDates(xpiPath, orig.lastAccessDate, orig.lastModificationDate);
 
-  // Make sure the timestamp is unchanged, so it is not re-scanned for that reason.
-  let timestamp = file.lastModifiedTime;
-  xpiFile.moveTo(profileDir, `${ID}.xpi`);
-
-  file.lastModifiedTime = timestamp;
-
-  await promiseStartupManager();
+    await test.action();
 
-  addon = await promiseAddonByID(ID);
-  notEqual(addon, null, "Got an addon object as expected");
-  equal(addon.version, "1.0", "Got the expected version");
-
-  let waitUninstall = promiseAddonEvent("onUninstalled");
-  await addon.uninstall();
-  await waitUninstall;
-});
-
-/**
- *  Modified timestamp on the XPI causes a reload of the manifest.
- */
-add_task(async function schema_change() {
-  const ID = "schema-change@tests.mozilla.org";
+    await promiseStartupManager();
 
-  let xpiFile = createTempXPIFile({
-    id: ID,
-    name: "Test Add-on",
-    version: "1.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1.9.2",
-    }],
-  });
-
-  await promiseInstallFile(xpiFile);
-
-  let addon = await promiseAddonByID(ID);
-
-  notEqual(addon, null, "Got an addon object as expected");
-  equal(addon.version, "1.0", "Got the expected version");
-
-  await promiseShutdownManager();
+    addon = await promiseAddonByID(ID);
+    notEqual(addon, null, "Got an addon object as expected");
+    equal(addon.version, test.expectedVersion, "Got the expected version");
 
-  xpiFile = createTempXPIFile({
-    id: ID,
-    name: "Test Add-on 2",
-    version: "2.0",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "1",
-      maxVersion: "1.9.2",
-    }],
-  });
-
-  xpiFile.moveTo(profileDir, `${ID}.xpi`);
-
-  let file = profileDir.clone();
-  file.append(`${ID}.xpi`);
-
-  // Set timestamp in the future so manifest is re-scanned.
-  let timestamp = new Date(Date.now() + 60000);
-  xpiFile.moveTo(profileDir, `${ID}.xpi`);
-
-  file.lastModifiedTime = timestamp;
-
-  await promiseStartupManager();
-
-  addon = await promiseAddonByID(ID);
-  notEqual(addon, null, "Got an addon object as expected");
-  equal(addon.version, "2.0", "Got the expected version");
-
-  let waitUninstall = promiseAddonEvent("onUninstalled");
-  await addon.uninstall();
-  await waitUninstall;
+    await addon.uninstall();
+  }
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_seen.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_seen.js
@@ -1,73 +1,57 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-const ID = "bootstrap1@tests.mozilla.org";
+const ID = "addon@tests.mozilla.org";
 
 let profileDir = gProfD.clone();
 profileDir.append("extensions");
 
 // By default disable add-ons from the profile and the system-wide scope
 const SCOPES = AddonManager.SCOPE_PROFILE | AddonManager.SCOPE_SYSTEM;
 Services.prefs.setIntPref("extensions.enabledScopes", SCOPES);
 Services.prefs.setIntPref("extensions.autoDisableScopes", SCOPES);
 
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
-const ADDONS = {
-  test_bootstrap1_1: {
-    "install.rdf": {
-      "id": "bootstrap1@tests.mozilla.org",
-      "name": "Test Bootstrap 1",
-    },
-    "bootstrap.js": BOOTSTRAP_MONITOR_BOOTSTRAP_JS,
-  },
-  test_bootstrap1_2: {
-    "install.rdf": {
-      "id": "bootstrap1@tests.mozilla.org",
-      "version": "2.0",
-      "name": "Test Bootstrap 1",
-    },
-    "bootstrap.js": BOOTSTRAP_MONITOR_BOOTSTRAP_JS,
-  },
-};
-
 const XPIS = {};
-for (let [name, files] of Object.entries(ADDONS)) {
-  XPIS[name] = AddonTestUtils.createTempXPIFile(files);
-}
-
 
 // Installing an add-on through the API should mark it as seen
 add_task(async function() {
   await promiseStartupManager();
 
-  let install = await AddonTestUtils.promiseInstallXPI(ADDONS.test_bootstrap1_1);
-  Assert.equal(install.state, AddonManager.STATE_INSTALLED);
-  Assert.ok(!hasFlag(install.addon.pendingOperations, AddonManager.PENDING_INSTALL));
+  for (let n of [1, 2]) {
+    XPIS[n] = await createTempWebExtensionFile({
+      manifest: {
+        name: "Test",
+        version: `${n}.0`,
+        applications: {gecko: {id: ID}},
+      },
+    });
+  }
 
-  let addon = install.addon;
+  await promiseInstallFile(XPIS[1]);
+
+  let addon = await promiseAddonByID(ID);
   Assert.equal(addon.version, "1.0");
   Assert.ok(!addon.foreignInstall);
   Assert.ok(addon.seen);
 
   await promiseRestartManager();
 
   addon = await promiseAddonByID(ID);
   Assert.ok(!addon.foreignInstall);
   Assert.ok(addon.seen);
 
   // Installing an update should retain that
-  install = await AddonTestUtils.promiseInstallXPI(ADDONS.test_bootstrap1_2);
-  Assert.equal(install.state, AddonManager.STATE_INSTALLED);
-  Assert.ok(!hasFlag(install.addon.pendingOperations, AddonManager.PENDING_INSTALL));
+  await promiseInstallFile(XPIS[2]);
 
-  addon = install.addon;
+  addon = await promiseAddonByID(ID);
   Assert.equal(addon.version, "2.0");
   Assert.ok(!addon.foreignInstall);
   Assert.ok(addon.seen);
 
   await promiseRestartManager();
 
   addon = await promiseAddonByID(ID);
   Assert.ok(!addon.foreignInstall);
@@ -88,17 +72,17 @@ add_task(async function() {
   registerDirectory("XRESysSExtPD", systemParentDir.clone());
   registerCleanupFunction(() => {
     systemParentDir.remove(true);
   });
 
   let systemDir = systemParentDir.clone();
   systemDir.append(Services.appinfo.ID);
 
-  let path = await manuallyInstall(XPIS.test_bootstrap1_1, systemDir, ID);
+  let path = await manuallyInstall(XPIS[1], systemDir, ID);
   // Make sure the startup code will detect sideloaded updates
   setExtensionModifiedTime(path, Date.now() - 10000);
 
   await promiseStartupManager();
   await AddonManagerPrivate.getNewSideloads();
 
   let addon = await promiseAddonByID(ID);
   Assert.equal(addon.version, "1.0");
@@ -116,17 +100,17 @@ add_task(async function() {
   path.remove(true);
 
   Services.prefs.setIntPref("extensions.startupScanScopes", savedStartupScanScopes);
 });
 
 // Sideloading an add-on in the profile should mark it as unseen and it should
 // remain unseen after an update is sideloaded.
 add_task(async function() {
-  let path = await manuallyInstall(XPIS.test_bootstrap1_1, profileDir, ID);
+  let path = await manuallyInstall(XPIS[1], profileDir, ID);
   // Make sure the startup code will detect sideloaded updates
   setExtensionModifiedTime(path, Date.now() - 10000);
 
   await promiseStartupManager();
 
   let addon = await promiseAddonByID(ID);
   Assert.equal(addon.version, "1.0");
   Assert.ok(addon.foreignInstall);
@@ -137,34 +121,34 @@ add_task(async function() {
   addon = await promiseAddonByID(ID);
   Assert.ok(addon.foreignInstall);
   Assert.ok(!addon.seen);
 
   await promiseShutdownManager();
 
   // Sideloading an update shouldn't change the state
   manuallyUninstall(profileDir, ID);
-  await manuallyInstall(XPIS.test_bootstrap1_2, profileDir, ID);
+  await manuallyInstall(XPIS[2], profileDir, ID);
   setExtensionModifiedTime(path, Date.now());
 
   await promiseStartupManager();
 
   addon = await promiseAddonByID(ID);
   Assert.equal(addon.version, "2.0");
   Assert.ok(addon.foreignInstall);
   Assert.ok(!addon.seen);
 
   await addon.uninstall();
   await promiseShutdownManager();
 });
 
 // Sideloading an add-on in the profile should mark it as unseen and it should
 // remain unseen after a regular update.
 add_task(async function() {
-  let path = await manuallyInstall(XPIS.test_bootstrap1_1, profileDir, ID);
+  let path = await manuallyInstall(XPIS[1], profileDir, ID);
   // Make sure the startup code will detect sideloaded updates
   setExtensionModifiedTime(path, Date.now() - 10000);
 
   await promiseStartupManager();
 
   let addon = await promiseAddonByID(ID);
   Assert.equal(addon.version, "1.0");
   Assert.ok(addon.foreignInstall);
@@ -172,17 +156,17 @@ add_task(async function() {
 
   await promiseRestartManager();
 
   addon = await promiseAddonByID(ID);
   Assert.ok(addon.foreignInstall);
   Assert.ok(!addon.seen);
 
   // Updating through the API shouldn't change the state
-  let install = await AddonTestUtils.promiseInstallXPI(ADDONS.test_bootstrap1_2);
+  let install = await promiseInstallFile(XPIS[2]);
   Assert.equal(install.state, AddonManager.STATE_INSTALLED);
   Assert.ok(!hasFlag(install.addon.pendingOperations, AddonManager.PENDING_INSTALL));
 
   addon = install.addon;
   Assert.ok(addon.foreignInstall);
   Assert.ok(!addon.seen);
 
   await promiseRestartManager();
@@ -194,17 +178,17 @@ add_task(async function() {
 
   await addon.uninstall();
   await promiseShutdownManager();
 });
 
 // After a sideloaded addon has been seen, sideloading an update should
 // not reset it to unseen.
 add_task(async function() {
-  let path = await manuallyInstall(XPIS.test_bootstrap1_1, profileDir, ID);
+  let path = await manuallyInstall(XPIS[1], profileDir, ID);
   // Make sure the startup code will detect sideloaded updates
   setExtensionModifiedTime(path, Date.now() - 10000);
 
   await promiseStartupManager();
 
   let addon = await promiseAddonByID(ID);
   Assert.equal(addon.version, "1.0");
   Assert.ok(addon.foreignInstall);
@@ -217,34 +201,34 @@ add_task(async function() {
   addon = await promiseAddonByID(ID);
   Assert.ok(addon.foreignInstall);
   Assert.ok(addon.seen);
 
   await promiseShutdownManager();
 
   // Sideloading an update shouldn't change the state
   manuallyUninstall(profileDir, ID);
-  await manuallyInstall(XPIS.test_bootstrap1_2, profileDir, ID);
+  await manuallyInstall(XPIS[2], profileDir, ID);
   setExtensionModifiedTime(path, Date.now());
 
   await promiseStartupManager();
 
   addon = await promiseAddonByID(ID);
   Assert.equal(addon.version, "2.0");
   Assert.ok(addon.foreignInstall);
   Assert.ok(addon.seen);
 
   await addon.uninstall();
   await promiseShutdownManager();
 });
 
 // After a sideloaded addon has been seen, manually applying an update should
 // not reset it to unseen.
 add_task(async function() {
-  let path = await manuallyInstall(XPIS.test_bootstrap1_1, profileDir, ID);
+  let path = await manuallyInstall(XPIS[1], profileDir, ID);
   // Make sure the startup code will detect sideloaded updates
   setExtensionModifiedTime(path, Date.now() - 10000);
 
   await promiseStartupManager();
 
   let addon = await promiseAddonByID(ID);
   Assert.equal(addon.version, "1.0");
   Assert.ok(addon.foreignInstall);
@@ -254,17 +238,17 @@ add_task(async function() {
 
   await promiseRestartManager();
 
   addon = await promiseAddonByID(ID);
   Assert.ok(addon.foreignInstall);
   Assert.ok(addon.seen);
 
   // Updating through the API shouldn't change the state
-  let install = await AddonTestUtils.promiseInstallXPI(ADDONS.test_bootstrap1_2);
+  let install = await promiseInstallFile(XPIS[2]);
   Assert.equal(install.state, AddonManager.STATE_INSTALLED);
   Assert.ok(!hasFlag(install.addon.pendingOperations, AddonManager.PENDING_INSTALL));
 
   addon = install.addon;
   Assert.ok(addon.foreignInstall);
   Assert.ok(addon.seen);
 
   await promiseRestartManager();
@@ -272,8 +256,9 @@ add_task(async function() {
   addon = await promiseAddonByID(ID);
   Assert.equal(addon.version, "2.0");
   Assert.ok(addon.foreignInstall);
   Assert.ok(addon.seen);
 
   await addon.uninstall();
   await promiseShutdownManager();
 });
+
--- a/toolkit/mozapps/extensions/test/xpcshell/test_sideloads.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_sideloads.js
@@ -19,73 +19,49 @@ async function createWebExtension(detail
     options.manifest.icons = {"64": details.iconURL};
   }
 
   let xpi = AddonTestUtils.createTempWebExtensionFile(options);
 
   await AddonTestUtils.manuallyInstall(xpi);
 }
 
-async function createXULExtension(details) {
-  let xpi = AddonTestUtils.createTempXPIFile({
-    "install.rdf": {
-      id: details.id,
-      name: details.name,
-      bootstrap: true,
-      version: "0.1",
-      targetApplications: [{
-        id: "toolkit@mozilla.org",
-        minVersion: "0",
-        maxVersion: "*",
-      }],
-    },
-  });
-
-  await AddonTestUtils.manuallyInstall(xpi);
-}
-
 add_task(async function test_sideloading() {
   Services.prefs.setIntPref("extensions.autoDisableScopes", 15);
   Services.prefs.setIntPref("extensions.startupScanScopes", 0);
 
   const ID1 = "addon1@tests.mozilla.org";
   await createWebExtension({
     id: ID1,
     name: "Test 1",
     userDisabled: true,
     permissions: ["history", "https://*/*"],
     iconURL: "foo-icon.png",
   });
 
   const ID2 = "addon2@tests.mozilla.org";
-  await createXULExtension({
+  await createWebExtension({
     id: ID2,
     name: "Test 2",
+    permissions: ["<all_urls>"],
   });
 
   const ID3 = "addon3@tests.mozilla.org";
   await createWebExtension({
     id: ID3,
     name: "Test 3",
     permissions: ["<all_urls>"],
   });
 
-  const ID4 = "addon4@tests.mozilla.org";
-  await createWebExtension({
-    id: ID4,
-    name: "Test 4",
-    permissions: ["<all_urls>"],
-  });
-
   await promiseStartupManager();
 
   let sideloaded = await AddonManagerPrivate.getNewSideloads();
 
   sideloaded.sort((a, b) => a.id.localeCompare(b.id));
 
   deepEqual(sideloaded.map(a => a.id),
-            [ID1, ID2, ID3, ID4],
+            [ID1, ID2, ID3],
             "Got the correct sideload add-ons");
 
   deepEqual(sideloaded.map(a => a.userDisabled),
-            [true, true, true, true],
+            [true, true, true],
             "All sideloaded add-ons are disabled");
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_softblocked.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_softblocked.js
@@ -1,101 +1,66 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
-
-ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
-
-// Allow insecure updates
-Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
-
 const testserver = createHttpServer();
 gPort = testserver.identity.primaryPort;
 testserver.registerDirectory("/data/", do_get_file("data"));
 
-// Don't need the full interface, attempts to call other methods will just
-// throw which is just fine
-var WindowWatcher = {
-  openWindow(parent, url, name, features, openArgs) {
-    // Should be called to list the newly blocklisted items
-    Assert.equal(url, URI_EXTENSION_BLOCKLIST_DIALOG);
-
-    // Simulate auto-disabling any softblocks
-    var list = openArgs.wrappedJSObject.list;
-    list.forEach(function(aItem) {
-      if (!aItem.blocked)
-        aItem.disable = true;
-    });
-
-    // run the code after the blocklist is closed
-    Services.obs.notifyObservers(null, "addon-blocklist-closed");
-  },
-
-  QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"]),
-};
-
-MockRegistrar.register("@mozilla.org/embedcomp/window-watcher;1", WindowWatcher);
-
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
 
 function load_blocklist(aFile) {
   return new Promise((resolve, reject) => {
     Services.obs.addObserver(function observer() {
       Services.obs.removeObserver(observer, "blocklist-updated");
 
       resolve();
     }, "blocklist-updated");
 
     Services.prefs.setCharPref("extensions.blocklist.url", `http://localhost:${gPort}/data/${aFile}`);
     var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
                     getService(Ci.nsITimerCallback);
     blocklist.notify(null);
   });
 }
 
-function run_test() {
-  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
-  run_next_test();
-}
-
 // Tests that an appDisabled add-on that becomes softBlocked remains disabled
 // when becoming appEnabled
-add_task(async function() {
-  await promiseWriteInstallRDFForExtension({
-    id: "softblock1@tests.mozilla.org",
-    version: "1.0",
-    name: "Softblocked add-on",
-    bootstrap: true,
-    targetApplications: [{
-      id: "xpcshell@tests.mozilla.org",
-      minVersion: "2",
-      maxVersion: "3",
-    }],
-  }, profileDir);
-
+add_task(async function test_softblock() {
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
   await promiseStartupManager();
 
+  await promiseInstallWebExtension({
+    manifest: {
+      name: "Softblocked add-on",
+      version: "1.0",
+      applications: {
+        gecko: {
+          id: "softblock1@tests.mozilla.org",
+          strict_min_version: "2",
+          strict_max_version: "3",
+        }},
+    },
+  });
   let s1 = await promiseAddonByID("softblock1@tests.mozilla.org");
 
   // Make sure to mark it as previously enabled.
   await s1.enable();
 
   Assert.ok(!s1.softDisabled);
   Assert.ok(s1.appDisabled);
   Assert.ok(!s1.isActive);
 
   await load_blocklist("test_softblocked1.xml");
 
   Assert.ok(s1.softDisabled);
   Assert.ok(s1.appDisabled);
   Assert.ok(!s1.isActive);
 
+  AddonTestUtils.appInfo.platformVersion = "2";
   await promiseRestartManager("2");
 
   s1 = await promiseAddonByID("softblock1@tests.mozilla.org");
 
   Assert.ok(s1.softDisabled);
   Assert.ok(!s1.appDisabled);
   Assert.ok(!s1.isActive);
 });
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_sourceURI.js
+++ /dev/null
@@ -1,98 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-ChromeUtils.import("resource://testing-common/httpd.js");
-var gServer = new HttpServer();
-gServer.start(-1);
-
-const PREF_GETADDONS_CACHE_ENABLED       = "extensions.getAddons.cache.enabled";
-
-const PORT          = gServer.identity.primaryPort;
-const BASE_URL      = "http://localhost:" + PORT;
-
-var addon = {
-  id: "addon@tests.mozilla.org",
-  version: "1.0",
-  name: "Test",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
-
-const profileDir = gProfD.clone();
-profileDir.append("extensions");
-
-function backgroundUpdate(aCallback) {
-  Services.obs.addObserver(function observer() {
-    Services.obs.removeObserver(observer, "addons-background-update-complete");
-    aCallback();
-  }, "addons-background-update-complete");
-
-  AddonManagerPrivate.backgroundUpdateCheck();
-}
-
-async function run_test() {
-  do_test_pending();
-
-  const GETADDONS_RESPONSE = {
-    page_size: 25,
-    next: null,
-    previous: null,
-    results: [
-      {
-        name: "Test",
-        type: "extension",
-        guid: "addon@tests.mozilla.org",
-        current_version: {
-          version: "1",
-          files: [
-            {
-              platform: "all",
-              url: "http://www.example.com/testaddon.xpi",
-            },
-          ],
-        },
-      },
-    ],
-  };
-  gServer.registerPathHandler("/addons.json", (request, response) => {
-    response.setHeader("content-type", "application/json");
-    response.write(JSON.stringify(GETADDONS_RESPONSE));
-  });
-
-  const COMPAT_RESPONSE = {
-    next: null,
-    results: [],
-  };
-  gServer.registerPathHandler("/compat.json", (request, response) => {
-    response.setHeader("content-type", "application/json");
-    response.write(JSON.stringify(COMPAT_RESPONSE));
-  });
-
-  Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, `${BASE_URL}/addons.json`);
-  Services.prefs.setCharPref(PREF_COMPAT_OVERRIDES, `${BASE_URL}/compat.json`);
-  Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
-
-  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
-  await promiseWriteInstallRDFForExtension(addon, profileDir);
-  await promiseStartupManager();
-
-  let a = await AddonManager.getAddonByID("addon@tests.mozilla.org");
-  Assert.notEqual(a, null);
-  Assert.equal(a.sourceURI, null);
-
-  backgroundUpdate(async function() {
-    await promiseRestartManager();
-
-    let a2 = await AddonManager.getAddonByID("addon@tests.mozilla.org");
-    Assert.notEqual(a2, null);
-    Assert.notEqual(a2.sourceURI, null);
-    Assert.equal(a2.sourceURI.spec, "http://www.example.com/testaddon.xpi");
-
-    do_test_finished();
-  });
-}
--- a/toolkit/mozapps/extensions/test/xpcshell/test_startup.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_startup.js
@@ -5,810 +5,616 @@
 // This verifies startup detection of added/removed/changed items and install
 // location priorities
 
 // Enable loading extensions from the user and system scopes
 Services.prefs.setIntPref("extensions.enabledScopes",
                           AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_USER +
                           AddonManager.SCOPE_SYSTEM);
 
-var addon1 = {
-  id: "addon1@tests.mozilla.org",
-  version: "1.0",
-  name: "Test 1",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }, {                 // Repeated target application entries should be ignored
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "2",
-    maxVersion: "2",
-  }],
-};
-
-var addon2 = {
-  id: "addon2@tests.mozilla.org",
-  version: "2.0",
-  name: "Test 2",
-  bootstrap: true,
-  targetApplications: [{  // Bad target application entries should be ignored
-    minVersion: "3",
-    maxVersion: "4",
-  }, {
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "2",
-  }],
-};
-
-var addon3 = {
-  id: "addon3@tests.mozilla.org",
-  version: "3.0",
-  name: "Test 3",
-  bootstrap: true,
-  targetApplications: [{
-    id: "toolkit@mozilla.org",
-    minVersion: "1.9.2",
-    maxVersion: "1.9.2.*",
-  }],
-};
+function getID(n) { return `addon${n}@tests.mozilla.org`; }
+function initialVersion(n) { return `${n}.0`; }
 
-// Should be ignored because it has no ID
-var addon4 = {
-  version: "4.0",
-  name: "Test 4",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
-
-// Should be ignored because it has no version
-var addon5 = {
-  id: "addon5@tests.mozilla.org",
-  version: undefined,
-  name: "Test 5",
-  bootstrap: true,
-  targetApplications: [{
-    id: "xpcshell@tests.mozilla.org",
-    minVersion: "1",
-    maxVersion: "1",
-  }],
-};
-
-// Should be ignored because it has an invalid type
-var addon6 = {
-  id: "addon6@tests.mozilla.org",
-  version: "3.0",
-  name: "Test 6",
-  bootstrap: true,
-  type: 5,
-  targetApplications: [{
-    id: "toolkit@mozilla.org",
-    minVersion: "1.9.2",
-    maxVersion: "1.9.2.*",
-  }],
-};
-
-// Should be ignored because it has an invalid type
-var addon7 = {
-  id: "addon7@tests.mozilla.org",
-  version: "3.0",
-  name: "Test 3",
-  bootstrap: true,
-  type: "extension",
-  targetApplications: [{
-    id: "toolkit@mozilla.org",
-    minVersion: "1.9.2",
-    maxVersion: "1.9.2.*",
-  }],
-};
+const ID1 = getID(1);
+const ID2 = getID(2);
+const ID3 = getID(3);
+const ID4 = getID(4);
 
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
 const globalDir = gProfD.clone();
 globalDir.append("extensions2");
 globalDir.append(gAppInfo.ID);
 registerDirectory("XRESysSExtPD", globalDir.parent);
 
 const userDir = gProfD.clone();
 userDir.append("extensions3");
 userDir.append(gAppInfo.ID);
 registerDirectory("XREUSysExt", userDir.parent);
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
-var gCachePurged = false;
+function check_startup_changes(aType, aIds) {
+  var ids = aIds.slice(0);
+  ids.sort();
+  var changes = AddonManager.getStartupChanges(aType);
+  changes = changes.filter(aEl => /@tests.mozilla.org$/.test(aEl));
+  changes.sort();
+
+  Assert.equal(JSON.stringify(ids), JSON.stringify(changes));
+}
+
+function promiseCacheInvalidated() {
+  return new Promise(resolve => {
+    let observer = () => {
+      Services.obs.removeObserver(observer, "startupcache-invalidate");
+      resolve();
+    };
+    Services.obs.addObserver(observer, "startupcache-invalidate");
+  });
+}
+
+function createWebExtension(id, version) {
+  return createTempWebExtensionFile({
+    manifest: {
+      version,
+      applications: {gecko: {id}},
+    },
+  });
+}
 
 // Set up the profile
-async function run_test() {
-  do_test_pending("test_startup main");
-
-  Services.obs.addObserver({
-    observe(aSubject, aTopic, aData) {
-      gCachePurged = true;
-    },
-  }, "startupcache-invalidate");
-
+add_task(async function setup() {
   await promiseStartupManager();
   check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_DISABLED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
 
   Assert.ok(!gExtensionsJSON.exists());
 
-  let [a1, a2, a3, a4, a5] = await AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
-                                                                "addon2@tests.mozilla.org",
-                                                                "addon3@tests.mozilla.org",
-                                                                "addon4@tests.mozilla.org",
-                                                                "addon5@tests.mozilla.org"]);
-  Assert.equal(a1, null);
-  do_check_not_in_crash_annotation(addon1.id, addon1.version);
-  Assert.equal(a2, null);
-  do_check_not_in_crash_annotation(addon2.id, addon2.version);
-  Assert.equal(a3, null);
-  do_check_not_in_crash_annotation(addon3.id, addon3.version);
-  Assert.equal(a4, null);
-  Assert.equal(a5, null);
-
-  executeSoon(run_test_1);
-}
-
-function end_test() {
-  do_test_finished("test_startup main");
-}
+  for (let n of [1, 2, 3]) {
+    let addon = await promiseAddonByID(getID(n));
+    Assert.equal(addon, null);
+    do_check_not_in_crash_annotation(getID(n), initialVersion(n));
+  }
+});
 
 // Try to install all the items into the profile
-async function run_test_1() {
-  await promiseWriteInstallRDFForExtension(addon1, profileDir);
-  var dest = await promiseWriteInstallRDFForExtension(addon2, profileDir);
-  // Attempt to make this look like it was added some time in the past so
-  // the change in run_test_2 makes the last modified time change.
-  setExtensionModifiedTime(dest, dest.lastModifiedTime - 5000);
+add_task(async function test_scan_profile() {
+  let ids = [];
+  for (let n of [1, 2, 3]) {
+    let id = getID(n);
+    ids.push(id);
+    let xpi = await createWebExtension(id, initialVersion(n));
+    xpi.copyTo(profileDir, `${id}.xpi`);
+  }
 
-  await promiseWriteInstallRDFForExtension(addon3, profileDir);
-  await promiseWriteInstallRDFForExtension(addon4, profileDir, "addon4@tests.mozilla.org");
-  await promiseWriteInstallRDFForExtension(addon5, profileDir);
-  await promiseWriteInstallRDFForExtension(addon6, profileDir);
-  await promiseWriteInstallRDFForExtension(addon7, profileDir);
+  await Promise.all([
+    promiseCacheInvalidated(),
+    promiseRestartManager(),
+  ]);
 
-  gCachePurged = false;
-  await promiseRestartManager();
-  check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ["addon1@tests.mozilla.org",
-                                      "addon2@tests.mozilla.org",
-                                      "addon3@tests.mozilla.org"]);
+  check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, ids);
   check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_DISABLED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
-  Assert.ok(gCachePurged);
 
   info("Checking for " + gAddonStartup.path);
   Assert.ok(gAddonStartup.exists());
 
-  let [a1, a2, a3, a4, a5, a6, a7] = await AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
-                                                                        "addon2@tests.mozilla.org",
-                                                                        "addon3@tests.mozilla.org",
-                                                                        "addon4@tests.mozilla.org",
-                                                                        "addon5@tests.mozilla.org",
-                                                                        "addon6@tests.mozilla.o