Bug 1454202: Part 4a - Remove callback-based variants of most AddonManager APIs. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 15 Apr 2018 14:17:28 -0700
changeset 782446 56fe71ba7939aac6b24e38bd63d94bd1f9ff57fe
parent 782445 17d554bae08bfdc92173e25b69bca2fb658e24fd
child 782447 b88ea5a05b7e40523b8f257ab149ae6184cb2f19
push id106537
push usermaglione.k@gmail.com
push dateMon, 16 Apr 2018 03:19:09 +0000
reviewersaswan
bugs1454202
milestone61.0a1
Bug 1454202: Part 4a - Remove callback-based variants of most AddonManager APIs. r?aswan MozReview-Commit-ID: BrUH8Gyx8kx
toolkit/mozapps/extensions/AddonManager.jsm
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/internal/XPIProviderUtils.js
toolkit/mozapps/extensions/test/browser/browser_CTP_plugins.js
toolkit/mozapps/extensions/test/browser/browser_manualupdates.js
toolkit/mozapps/extensions/test/browser/head.js
toolkit/mozapps/extensions/test/xpcshell/head_addons.js
toolkit/mozapps/extensions/test/xpcshell/test_bad_json.js
toolkit/mozapps/extensions/test/xpcshell/test_delay_update_webextension.js
toolkit/mozapps/extensions/test/xpcshell/test_no_addons.js
toolkit/mozapps/extensions/test/xpcshell/test_pass_symbol.js
toolkit/mozapps/extensions/test/xpcshell/test_syncGUID.js
toolkit/mozapps/extensions/test/xpcshell/test_system_delay_update.js
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -1610,17 +1610,17 @@ var AddonManagerInternal = {
    *         Optional placeholder icons while the add-on is being downloaded
    * @param  aVersion
    *         An optional placeholder version while the add-on is being downloaded
    * @param  aBrowser
    *         An optional <browser> element for download permissions prompts.
    * @throws if the aUrl, aCallback or aMimetype arguments are not specified
    */
   getInstallForURL(aUrl, aMimetype, aHash, aName,
-                             aIcons, aVersion, aBrowser) {
+                   aIcons, aVersion, aBrowser) {
     if (!gStarted)
       throw Components.Exception("AddonManager is not initialized",
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     if (!aUrl || typeof aUrl != "string")
       throw Components.Exception("aURL must be a non-empty string",
                                  Cr.NS_ERROR_INVALID_ARG);
 
@@ -2017,55 +2017,53 @@ var AddonManagerInternal = {
    *
    * @param  aInstanceID
    *         The instance ID of an addon to register a listener for.
    * @param  aCallback
    *         The callback to invoke when updates are available for this addon.
    * @throws if there is no addon matching the instanceID
    */
   addUpgradeListener(aInstanceID, aCallback) {
-   if (!aInstanceID || typeof aInstanceID != "symbol")
-     throw Components.Exception("aInstanceID must be a symbol",
-                                Cr.NS_ERROR_INVALID_ARG);
-
-  if (!aCallback || typeof aCallback != "function")
-    throw Components.Exception("aCallback must be a function",
-                               Cr.NS_ERROR_INVALID_ARG);
-
-   this.getAddonByInstanceID(aInstanceID).then(wrapper => {
-     if (!wrapper) {
-       throw Error(`No addon matching instanceID: ${String(aInstanceID)}`);
-     }
-     let addonId = wrapper.id;
-     logger.debug(`Registering upgrade listener for ${addonId}`);
-     this.upgradeListeners.set(addonId, aCallback);
-   });
+    if (!aInstanceID || typeof aInstanceID != "symbol")
+      throw Components.Exception("aInstanceID must be a symbol",
+                                 Cr.NS_ERROR_INVALID_ARG);
+
+    if (!aCallback || typeof aCallback != "function")
+      throw Components.Exception("aCallback must be a function",
+                                 Cr.NS_ERROR_INVALID_ARG);
+
+    let wrapper = this.syncGetAddonByInstanceID(aInstanceID);
+    if (!wrapper) {
+      throw Error(`No addon matching instanceID: ${String(aInstanceID)}`);
+    }
+    let addonId = wrapper.id;
+    logger.debug(`Registering upgrade listener for ${addonId}`);
+    this.upgradeListeners.set(addonId, aCallback);
   },
 
   /**
    * Removes an UpgradeListener if the listener is registered.
    *
    * @param  aInstanceID
    *         The instance ID of the addon to remove
    */
   removeUpgradeListener(aInstanceID) {
     if (!aInstanceID || typeof aInstanceID != "symbol")
       throw Components.Exception("aInstanceID must be a symbol",
                                  Cr.NS_ERROR_INVALID_ARG);
 
-    return this.getAddonByInstanceID(aInstanceID).then(addon => {
-      if (!addon) {
-        throw Error(`No addon for instanceID: ${aInstanceID}`);
-      }
-      if (this.upgradeListeners.has(addon.id)) {
-        this.upgradeListeners.delete(addon.id);
-      } else {
-        throw Error(`No upgrade listener registered for addon ID: ${addon.id}`);
-      }
-    });
+    let addon = this.syncGetAddonByInstanceID(aInstanceID);
+    if (!addon) {
+      throw Error(`No addon for instanceID: ${aInstanceID}`);
+    }
+    if (this.upgradeListeners.has(addon.id)) {
+      this.upgradeListeners.delete(addon.id);
+    } else {
+      throw Error(`No upgrade listener registered for addon ID: ${addon.id}`);
+    }
   },
 
   /**
    * Installs a temporary add-on from a local file or directory.
    *
    * @param  aFile
    *         An nsIFile for the file or directory of the add-on to be
    *         temporarily installed.
@@ -2103,17 +2101,21 @@ var AddonManagerInternal = {
    * @param aInstanceID
    *        An Addon Instance ID symbol
    * @return {Promise}
    * @resolves The found Addon or null if no such add-on exists.
    * @rejects  Never
    * @throws if the aInstanceID argument is not specified
    *         or the AddonManager is not initialized
    */
-   getAddonByInstanceID(aInstanceID) {
+   async getAddonByInstanceID(aInstanceID) {
+     return this.syncGetAddonByInstanceID(aInstanceID);
+   },
+
+   syncGetAddonByInstanceID(aInstanceID) {
      if (!gStarted)
        throw Components.Exception("AddonManager is not initialized",
                                   Cr.NS_ERROR_NOT_INITIALIZED);
 
      if (!aInstanceID || typeof aInstanceID != "symbol")
        throw Components.Exception("aInstanceID must be a Symbol()",
                                   Cr.NS_ERROR_INVALID_ARG);
 
@@ -2953,20 +2955,18 @@ var AddonManagerPrivate = {
   notifyAddonChanged(aID, aType, aPendingRestart) {
     AddonManagerInternal.notifyAddonChanged(aID, aType, aPendingRestart);
   },
 
   updateAddonAppDisabledStates() {
     AddonManagerInternal.updateAddonAppDisabledStates();
   },
 
-  updateAddonRepositoryData(aCallback) {
-    return promiseOrCallback(
-      AddonManagerInternal.updateAddonRepositoryData(),
-      aCallback);
+  updateAddonRepositoryData() {
+    return AddonManagerInternal.updateAddonRepositoryData();
   },
 
   callInstallListeners(...aArgs) {
     return AddonManagerInternal.callInstallListeners.apply(AddonManagerInternal,
                                                            aArgs);
   },
 
   callAddonListeners(...aArgs) {
@@ -3396,68 +3396,50 @@ var AddonManager = {
    * @return An array of add-on IDs
    */
   getStartupChanges(aType) {
     if (!(aType in AddonManagerInternal.startupChanges))
       return [];
     return AddonManagerInternal.startupChanges[aType].slice(0);
   },
 
-  getAddonByID(aID, aCallback) {
-    return promiseOrCallback(
-      AddonManagerInternal.getAddonByID(aID),
-      aCallback);
+  getAddonByID(aID) {
+    return AddonManagerInternal.getAddonByID(aID);
   },
 
-  getAddonBySyncGUID(aGUID, aCallback) {
-    return promiseOrCallback(
-      AddonManagerInternal.getAddonBySyncGUID(aGUID),
-      aCallback);
+  getAddonBySyncGUID(aGUID) {
+    return AddonManagerInternal.getAddonBySyncGUID(aGUID);
   },
 
-  getAddonsByIDs(aIDs, aCallback) {
-    return promiseOrCallback(
-      AddonManagerInternal.getAddonsByIDs(aIDs),
-      aCallback);
+  getAddonsByIDs(aIDs) {
+    return AddonManagerInternal.getAddonsByIDs(aIDs);
   },
 
-  getAddonsWithOperationsByTypes(aTypes, aCallback) {
-    return promiseOrCallback(
-      AddonManagerInternal.getAddonsWithOperationsByTypes(aTypes),
-      aCallback);
+  getAddonsWithOperationsByTypes(aTypes) {
+    return AddonManagerInternal.getAddonsWithOperationsByTypes(aTypes);
   },
 
-  getAddonsByTypes(aTypes, aCallback) {
-    return promiseOrCallback(
-      AddonManagerInternal.getAddonsByTypes(aTypes),
-      aCallback);
+  getAddonsByTypes(aTypes) {
+    return AddonManagerInternal.getAddonsByTypes(aTypes);
   },
 
-  getActiveAddons(aTypes, aCallback) {
-    return promiseOrCallback(
-      AddonManagerInternal.getActiveAddons(aTypes),
-      aCallback);
+  getActiveAddons(aTypes) {
+    return AddonManagerInternal.getActiveAddons(aTypes);
   },
 
-  getAllAddons(aCallback) {
-    return promiseOrCallback(
-      AddonManagerInternal.getAllAddons(),
-      aCallback);
+  getAllAddons() {
+    return AddonManagerInternal.getAllAddons();
   },
 
-  getInstallsByTypes(aTypes, aCallback) {
-    return promiseOrCallback(
-      AddonManagerInternal.getInstallsByTypes(aTypes),
-      aCallback);
+  getInstallsByTypes(aTypes) {
+    return AddonManagerInternal.getInstallsByTypes(aTypes);
   },
 
-  getAllInstalls(aCallback) {
-    return promiseOrCallback(
-      AddonManagerInternal.getAllInstalls(),
-      aCallback);
+  getAllInstalls() {
+    return AddonManagerInternal.getAllInstalls();
   },
 
   isInstallEnabled(aType) {
     return AddonManagerInternal.isInstallEnabled(aType);
   },
 
   isInstallAllowed(aType, aInstallingPrincipal) {
     return AddonManagerInternal.isInstallAllowed(aType, aInstallingPrincipal);
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -3378,21 +3378,21 @@ var XPIProvider = {
    */
    getAddonByInstanceID(aInstanceID) {
      if (!aInstanceID || typeof aInstanceID != "symbol")
        throw Components.Exception("aInstanceID must be a Symbol()",
                                   Cr.NS_ERROR_INVALID_ARG);
 
      for (let [id, val] of this.activeAddons) {
        if (aInstanceID == val.instanceID) {
-         return this.getAddonByID(id);
+         return this.syncGetAddonByID(id);
        }
      }
 
-     return Promise.resolve(null);
+     return null;
    },
 
   /**
    * Removes an AddonInstall from the list of active installs.
    *
    * @param  install
    *         The AddonInstall to remove
    */
@@ -3406,16 +3406,21 @@ var XPIProvider = {
    * @param  aId
    *         The ID of the add-on to retrieve
    */
   async getAddonByID(aId) {
     let aAddon = await XPIDatabase.getVisibleAddonForID(aId);
     return aAddon ? aAddon.wrapper : null;
   },
 
+  syncGetAddonByID(aId) {
+    let aAddon = XPIDatabase.syncGetVisibleAddonForID(aId);
+    return aAddon ? aAddon.wrapper : null;
+  },
+
   /**
    * Called to get Addons of a particular type.
    *
    * @param  aTypes
    *         An array of types to fetch. Can be null to get all types.
    */
   async getAddonsByTypes(aTypes) {
     let typesToGet = getAllAliasesForTypes(aTypes);
--- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
+++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
@@ -66,39 +66,21 @@ const PROP_JSON_FIELDS = ["id", "syncGUI
                           "blocklistState", "blocklistURL", "startupData"];
 
 // Time to wait before async save of XPI JSON database, in milliseconds
 const ASYNC_SAVE_DELAY_MS = 20;
 
 /**
  * Asynchronously fill in the _repositoryAddon field for one addon
  */
-async function getRepositoryAddon(aAddon, aCallback) {
-  let addon;
+async function getRepositoryAddon(aAddon) {
   if (aAddon) {
-    addon = await AddonRepository.getCachedAddonByID(aAddon.id);
-    aAddon._repositoryAddon = addon;
-  }
-  if (aCallback) {
-    aCallback(addon);
+    aAddon._repositoryAddon = await AddonRepository.getCachedAddonByID(aAddon.id);
   }
-  return addon;
-}
-
-/**
- * Wrap an API-supplied function in an exception handler to make it safe to call
- */
-function makeSafe(aCallback) {
-  return function(...aArgs) {
-    try {
-      aCallback(...aArgs);
-    } catch (ex) {
-      logger.warn("XPI Database callback failed", ex);
-    }
-  };
+  return aAddon;
 }
 
 /**
  * Copies properties from one object to another. If no target object is passed
  * a new object will be created and returned.
  *
  * @param  aObject
  *         An object to copy from
@@ -622,115 +604,100 @@ this.XPIDatabase = {
     }
   },
 
   /**
    * Asynchronously list all addons that match the filter function
    * @param  aFilter
    *         Function that takes an addon instance and returns
    *         true if that addon should be included in the selected array
-   * @param  aCallback
-   *         Optional and will be called with an array of addons matching
-   *         aFilter or an empty array if none match.
    * @return a Promise that resolves to the list of add-ons matching aFilter or
    *         an empty array if none match
    */
-  async getAddonList(aFilter, aCallback) {
+  async getAddonList(aFilter) {
     try {
       let addonDB = await this.asyncLoadDB();
       let addonList = _filterDB(addonDB, aFilter);
       let addons = await Promise.all(addonList.map(addon => getRepositoryAddon(addon)));
-      if (aCallback) {
-        makeSafe(aCallback)(addons);
-      }
       return addons;
     } catch (error) {
       logger.error("getAddonList failed", error);
-      if (aCallback) {
-        makeSafe(aCallback)([]);
-      }
       return [];
     }
   },
 
   /**
    * (Possibly asynchronously) get the first addon that matches the filter function
    * @param  aFilter
    *         Function that takes an addon instance and returns
    *         true if that addon should be selected
-   * @param  aCallback
-   *         Called back with the addon, or null if no matching addon is found
    */
-  getAddon(aFilter, aCallback) {
+  getAddon(aFilter) {
     return this.asyncLoadDB().then(
       addonDB => {
         return getRepositoryAddon(_findAddon(addonDB, aFilter));
       })
     .catch(
         error => {
           logger.error("getAddon failed", error);
-          makeSafe(aCallback)(null);
         });
   },
 
+  syncGetAddon(aFilter) {
+    return _findAddon(this.addonDB, aFilter);
+  },
+
   /**
    * Asynchronously gets an add-on with a particular ID in a particular
    * install location.
    *
    * @param  aId
    *         The ID of the add-on to retrieve
    * @param  aLocation
    *         The name of the install location
-   * @param  aCallback
-   *         A callback to pass the DBAddonInternal to
    */
-  getAddonInLocation(aId, aLocation, aCallback) {
+  getAddonInLocation(aId, aLocation) {
     return this.asyncLoadDB().then(
-        addonDB => getRepositoryAddon(addonDB.get(aLocation + ":" + aId),
-                                      makeSafe(aCallback)));
+        addonDB => getRepositoryAddon(addonDB.get(aLocation + ":" + aId)));
   },
 
   /**
    * Asynchronously get all the add-ons in a particular install location.
    *
    * @param  aLocation
    *         The name of the install location
-   * @param  aCallback
-   *         A callback to pass the array of DBAddonInternals to
    */
-  getAddonsInLocation(aLocation, aCallback) {
-    return this.getAddonList(aAddon => aAddon._installLocation.name == aLocation, aCallback);
+  getAddonsInLocation(aLocation) {
+    return this.getAddonList(aAddon => aAddon._installLocation.name == aLocation);
   },
 
   /**
    * Asynchronously gets the add-on with the specified ID that is visible.
    *
    * @param  aId
    *         The ID of the add-on to retrieve
-   * @param  aCallback
-   *         A callback to pass the DBAddonInternal to
    */
-  getVisibleAddonForID(aId, aCallback) {
-    return this.getAddon(aAddon => ((aAddon.id == aId) && aAddon.visible),
-                         aCallback);
+  getVisibleAddonForID(aId) {
+    return this.getAddon(aAddon => ((aAddon.id == aId) && aAddon.visible));
+  },
+
+  syncGetVisibleAddonForID(aId) {
+    return this.syncGetAddon(aAddon => ((aAddon.id == aId) && aAddon.visible));
   },
 
   /**
    * Asynchronously gets the visible add-ons, optionally restricting by type.
    *
    * @param  aTypes
    *         An array of types to include or null to include all types
-   * @param  aCallback
-   *         A callback to pass the array of DBAddonInternals to
    */
-  getVisibleAddons(aTypes, aCallback) {
+  getVisibleAddons(aTypes) {
     return this.getAddonList(aAddon => (aAddon.visible &&
                                         (!aTypes || (aTypes.length == 0) ||
-                                         (aTypes.indexOf(aAddon.type) > -1))),
-                             aCallback);
+                                         (aTypes.indexOf(aAddon.type) > -1))));
   },
 
   /**
    * Synchronously gets all add-ons of a particular type(s).
    *
    * @param  aType, aType2, ...
    *         The type(s) of add-on to retrieve
    * @return an array of DBAddonInternals
@@ -772,40 +739,32 @@ this.XPIDatabase = {
                                 (aAddon.internalName == aInternalName));
   },
 
   /**
    * Asynchronously gets all add-ons with pending operations.
    *
    * @param  aTypes
    *         The types of add-ons to retrieve or null to get all types
-   * @param  aCallback
-   *         A callback to pass the array of DBAddonInternal to
    */
-  getVisibleAddonsWithPendingOperations(aTypes, aCallback) {
+  getVisibleAddonsWithPendingOperations(aTypes) {
     return this.getAddonList(
         aAddon => (aAddon.visible &&
                    aAddon.pendingUninstall &&
-                   (!aTypes || (aTypes.length == 0) || (aTypes.indexOf(aAddon.type) > -1))),
-        aCallback);
+                   (!aTypes || (aTypes.length == 0) || (aTypes.indexOf(aAddon.type) > -1))));
   },
 
   /**
    * Asynchronously get an add-on by its Sync GUID.
    *
    * @param  aGUID
    *         Sync GUID of add-on to fetch
-   * @param  aCallback
-   *         A callback to pass the DBAddonInternal record to. Receives null
-   *         if no add-on with that GUID is found.
-   *
    */
-  getAddonBySyncGUID(aGUID, aCallback) {
-    return this.getAddon(aAddon => aAddon.syncGUID == aGUID,
-                         aCallback);
+  getAddonBySyncGUID(aGUID) {
+    return this.getAddon(aAddon => aAddon.syncGUID == aGUID);
   },
 
   /**
    * Synchronously gets all add-ons in the database.
    * This is only called from the preference observer for the default
    * compatibility version preference, so we can return an empty list if
    * we haven't loaded the database yet.
    *
--- a/toolkit/mozapps/extensions/test/browser/browser_CTP_plugins.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_CTP_plugins.js
@@ -35,30 +35,30 @@ add_task(async function() {
     await new Promise(resolve => {
       setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml", resolve);
     });
     resetBlocklist();
   });
 
   let pluginTag = getTestPluginTag();
   pluginTag.enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
-  let managerWindow = await new Promise(resolve => open_manager("addons://list/plugin", resolve));
+  let managerWindow = await open_manager("addons://list/plugin");
 
-  let plugins = await new Promise(resolve => AddonManager.getAddonsByTypes(["plugin"], resolve));
+  let plugins = await AddonManager.getAddonsByTypes(["plugin"]);
 
   let testPluginId;
   for (let plugin of plugins) {
     if (plugin.name == "Test Plug-in") {
       testPluginId = plugin.id;
       break;
     }
   }
   ok(testPluginId, "part2: Test Plug-in should exist");
 
-  let testPlugin = await new Promise(resolve => AddonManager.getAddonByID(testPluginId, resolve));
+  let testPlugin = await AddonManager.getAddonByID(testPluginId);
   isnot(testPlugin, null, "part2.1: Test Plug-in should exist");
 
   let pluginEl = get_addon_element(managerWindow, testPluginId);
   pluginEl.parentNode.ensureElementIsVisible(pluginEl);
   let enableButton = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "enable-btn");
   is_element_hidden(enableButton, "part3: enable button should not be visible");
   let disableButton = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "disable-btn");
   is_element_hidden(disableButton, "part3: disable button should not be visible");
--- a/toolkit/mozapps/extensions/test/browser/browser_manualupdates.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_manualupdates.js
@@ -88,26 +88,27 @@ add_test(async function() {
   });
   await wait_for_view_load(gManagerWindow, null, true);
   is(gManagerWindow.document.getElementById("categories").selectedItem.value, "addons://updates/available", "Available Updates category should now be selected");
   is(gManagerWindow.gViewController.currentViewId, "addons://updates/available", "Available Updates view should be the current view");
   run_next_test();
 });
 
 
-add_test(function() {
+add_test(async function() {
   var list = gManagerWindow.document.getElementById("updates-list");
   is(list.itemCount, 1, "Should be 1 available update listed");
   var item = list.firstChild;
   is(item.mAddon.id, "addon2@tests.mozilla.org", "Update item should be for the manually updating addon");
 
   // The item in the list will be checking for update information asynchronously
   // so we have to wait for it to complete. Doing the same async request should
   // make our callback be called later.
-  AddonManager.getAllInstalls(run_next_test);
+  await AddonManager.getAllInstalls();
+  run_next_test();
 });
 
 add_test(function() {
   var list = gManagerWindow.document.getElementById("updates-list");
   var item = list.firstChild;
   get_tooltip_info(item).then(({ version }) => {
     is(version, "1.1", "Update item should have version number of the update");
     var postfix = gManagerWindow.document.getAnonymousElementByAttribute(item, "class", "update-postfix");
--- a/toolkit/mozapps/extensions/test/browser/head.js
+++ b/toolkit/mozapps/extensions/test/browser/head.js
@@ -506,25 +506,21 @@ function is_element_visible(aElement, aM
 }
 
 function is_element_hidden(aElement, aMsg) {
   isnot(aElement, null, "Element should not be null, when checking visibility");
   ok(is_hidden(aElement), aMsg || (aElement + " should be hidden"));
 }
 
 function promiseAddonByID(aId) {
-  return new Promise(resolve => {
-    AddonManager.getAddonByID(aId, resolve);
-  });
+  return AddonManager.getAddonByID(aId);
 }
 
 function promiseAddonsByIDs(aIDs) {
-  return new Promise(resolve => {
-    AddonManager.getAddonsByIDs(aIDs, resolve);
-  });
+  return AddonManager.getAddonsByIDs(aIDs);
 }
 /**
  * Install an add-on and call a callback when complete.
  *
  * The callback will receive the Addon for the installed add-on.
  */
 function install_addon(path, cb, pathPrefix = TESTROOT) {
   let p = new Promise(async (resolve, reject) => {
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -55,16 +55,18 @@ ChromeUtils.defineModuleGetter(this, "Ex
 ChromeUtils.defineModuleGetter(this, "HttpServer",
                                "resource://testing-common/httpd.js");
 ChromeUtils.defineModuleGetter(this, "MockAsyncShutdown",
                                "resource://testing-common/AddonTestUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "MockRegistrar",
                                "resource://testing-common/MockRegistrar.jsm");
 ChromeUtils.defineModuleGetter(this, "MockRegistry",
                                "resource://testing-common/MockRegistry.jsm");
+ChromeUtils.defineModuleGetter(this, "PromiseTestUtils",
+                               "resource://testing-common/PromiseTestUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "TestUtils",
                                "resource://testing-common/TestUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
                                    "@mozilla.org/addons/addon-manager-startup;1",
                                    "amIAddonManagerStartup");
 
 const {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bad_json.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bad_json.js
@@ -15,41 +15,34 @@ var addon1 = {
     minVersion: "1",
     maxVersion: "1"
   }]
 };
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 
-async function run_test() {
-  do_test_pending("Bad JSON");
-
+add_task(async function() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
 
   // This addon will be auto-installed at startup
   writeInstallRDFForExtension(addon1, profileDir);
 
-  startupManager();
-
-  shutdownManager();
+  await promiseStartupManager();
+  await promiseShutdownManager();
 
   // First startup/shutdown finished
   // Replace the JSON store with something bogus
   await saveJSON({not: "what we expect to find"}, gExtensionsJSON.path);
 
-  startupManager(false);
+  await promiseStartupManager(false);
   // Retrieve an addon to force the database to rebuild
-  AddonManager.getAddonsByIDs([addon1.id], callback_soon(after_db_rebuild));
-}
+  let a1 = await AddonManager.getAddonByID(addon1.id);
 
-async function after_db_rebuild([a1]) {
   Assert.equal(a1.id, addon1.id);
 
-  shutdownManager();
+  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);
-
-  do_test_finished("Bad JSON");
-}
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_delay_update_webextension.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_delay_update_webextension.js
@@ -11,18 +11,16 @@ ChromeUtils.import("resource://gre/modul
 
 if (AppConstants.platform == "win" && AppConstants.DEBUG) {
   // Shutdown timing is flaky in this test, and remote extensions
   // sometimes wind up leaving the XPI locked at the point when we try
   // to remove it.
   Services.prefs.setBoolPref("extensions.webextensions.remote", false);
 }
 
-ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm");
-
 PromiseTestUtils.expectUncaughtRejection(/Message manager disconnected/);
 
 /* globals browser*/
 
 const profileDir = gProfD.clone();
 profileDir.append("extensions");
 const stageDir = profileDir.clone();
 stageDir.append("staged");
--- a/toolkit/mozapps/extensions/test/xpcshell/test_no_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_no_addons.js
@@ -37,19 +37,17 @@ function check_empty_state() {
 add_task(async function first_run() {
   startupManager();
   check_empty_state();
   await true;
 });
 
 // Now do something that causes a DB load, and re-check
 async function trigger_db_load() {
-  let addonList = await new Promise(resolve => {
-    AddonManager.getAddonsByTypes(["extension"], resolve);
-  });
+  let addonList = await AddonManager.getAddonsByTypes(["extension"]);
 
   Assert.equal(addonList.length, 0);
   check_empty_state();
 
   await true;
 }
 add_task(trigger_db_load);
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_pass_symbol.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_pass_symbol.js
@@ -9,16 +9,18 @@ const ADDON_ID = "test_symbol@tests.mozi
 
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
 startupManager();
 
 BootstrapMonitor.init();
 
 // symbol is passed when add-on is installed
 add_task(async function() {
+  PromiseTestUtils.expectUncaughtRejection(/no addon found for symbol/);
+
   for (let pref of [PASS_PREF, FAIL_BOGUS_PREF, FAIL_ID_PREF])
     Services.prefs.clearUserPref(pref);
 
   await promiseInstallAllFiles([do_get_addon("test_symbol")], true);
 
   let addon = await promiseAddonByID(ADDON_ID);
 
   Assert.notEqual(addon, null);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_syncGUID.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_syncGUID.js
@@ -83,21 +83,20 @@ add_test(async function test_getter_and_
   };
 
   AddonManager.addInstallListener(listener);
 
   let install = await AddonManager.getInstallForFile(XPIS[0]);
   install.install();
 });
 
-add_test(function test_fetch_by_guid_unknown_guid() {
-  XPIProvider.getAddonBySyncGUID("XXXX", function(addon) {
-    Assert.equal(null, addon);
-    run_next_test();
-  });
+add_test(async function test_fetch_by_guid_unknown_guid() {
+  let addon = await XPIProvider.getAddonBySyncGUID("XXXX");
+  Assert.equal(null, addon);
+  run_next_test();
 });
 
 // Ensure setting an extension to an existing syncGUID results in error.
 add_test(function test_error_on_duplicate_syncguid_insert() {
   const installNames = ["test_install1", "test_install2_1"];
   const installIDs = ["addon1@tests.mozilla.org", "addon2@tests.mozilla.org"];
 
   let installCount = 0;
@@ -140,22 +139,21 @@ add_test(function test_error_on_duplicat
 
 add_test(async function test_fetch_by_guid_known_guid() {
   let addon = await AddonManager.getAddonByID(addonId);
   Assert.notEqual(null, addon);
   Assert.notEqual(null, addon.syncGUID);
 
   let syncGUID = addon.syncGUID;
 
-  XPIProvider.getAddonBySyncGUID(syncGUID, function(newAddon) {
-    Assert.notEqual(null, newAddon);
-    Assert.equal(syncGUID, newAddon.syncGUID);
+  let newAddon = await XPIProvider.getAddonBySyncGUID(syncGUID);
+  Assert.notEqual(null, newAddon);
+  Assert.equal(syncGUID, newAddon.syncGUID);
 
-    run_next_test();
-  });
+  run_next_test();
 });
 
 add_test(async function test_addon_manager_get_by_sync_guid() {
   let addon = await AddonManager.getAddonByID(addonId);
   Assert.notEqual(null, addon.syncGUID);
 
   let syncGUID = addon.syncGUID;
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_system_delay_update.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_delay_update.js
@@ -93,20 +93,16 @@ function promiseInstallDeferred(addonID1
       },
       onInstallEnded: (install) => {
         seenEnded.push(install.addon.id);
         if (seenEnded.includes(addonID1) && seenEnded.includes(addonID2)) {
           AddonManager.removeInstallListener(listener);
           resolve();
         }
       },
-      onInstallPostponed: (install) => {
-        AddonManager.removeInstallListener(listener);
-        reject(`extension installation should not have been postponed for ${install.addon.id}`);
-      }
     };
 
     AddonManager.addInstallListener(listener);
   });
 }
 
 
 // add-on registers upgrade listener, and ignores update.