Bug 1454202: Part 5a - Remove callback-based variants of most AddonManager APIs. r=aswan
authorKris Maglione <maglione.k@gmail.com>
Sat, 21 Apr 2018 15:15:10 -0700
changeset 468495 ebacf44a86dc27644717e72a2a302d586d5d81a1
parent 468494 112ff1e321a11fac3895742f1f35fe12d2acf903
child 468496 81d9e69a3539603114d1b97f9700c14f45affd49
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1454202
milestone61.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 1454202: Part 5a - Remove callback-based variants of most AddonManager APIs. r=aswan MozReview-Commit-ID: BrUH8Gyx8kx
browser/extensions/formautofill/test/browser/browser_check_installed.js
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/browser/extensions/formautofill/test/browser/browser_check_installed.js
+++ b/browser/extensions/formautofill/test/browser/browser_check_installed.js
@@ -1,14 +1,12 @@
 "use strict";
 
 add_task(async function test_enabled() {
-  let addon = await new Promise(
-    resolve => AddonManager.getAddonByID("formautofill@mozilla.org", resolve)
-  );
+  let addon = await AddonManager.getAddonByID("formautofill@mozilla.org");
   isnot(addon, null, "Check addon exists");
   is(addon.version, "1.0", "Check version");
   is(addon.name, "Form Autofill", "Check name");
   ok(addon.isCompatible, "Check application compatibility");
   ok(!addon.appDisabled, "Check not app disabled");
   ok(addon.isActive, "Check addon is active");
   is(addon.type, "extension", "Check type is 'extension'");
 });
--- 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,52 @@ 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 addonId = this.syncGetAddonIDByInstanceID(aInstanceID);
+    if (!addonId) {
+      throw Error(`No addon matching instanceID: ${String(aInstanceID)}`);
+    }
+    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 addonId = this.syncGetAddonIDByInstanceID(aInstanceID);
+    if (!addonId) {
+      throw Error(`No addon for instanceID: ${aInstanceID}`);
+    }
+    if (this.upgradeListeners.has(addonId)) {
+      this.upgradeListeners.delete(addonId);
+    } else {
+      throw Error(`No upgrade listener registered for addon ID: ${addonId}`);
+    }
   },
 
   /**
    * 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,29 +2100,47 @@ 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);
 
      return AddonManagerInternal._getProviderByName("XPIProvider")
                                 .getAddonByInstanceID(aInstanceID);
    },
 
+   syncGetAddonIDByInstanceID(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);
+
+     return AddonManagerInternal._getProviderByName("XPIProvider")
+                                .getAddonIDByInstanceID(aInstanceID);
+   },
+
+
   /**
    * Gets an icon from the icon set provided by the add-on
    * that is closest to the specified size.
    *
    * The optional window parameter will be used to determine
    * the screen resolution and select a more appropriate icon.
    * Calling this method with 48px on retina screens will try to
    * match an icon of size 96px.
@@ -2953,20 +2968,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 +3409,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
@@ -3376,27 +3376,36 @@ var XPIProvider = {
    * @param aInstanceID
    *        An Addon Instance ID
    * @return {Promise}
    * @resolves The found Addon or null if no such add-on exists.
    * @rejects  Never
    * @throws if the aInstanceID argument is not specified
    */
    getAddonByInstanceID(aInstanceID) {
+     let id = this.getAddonIDByInstanceID(aInstanceID);
+     if (id) {
+       return this.syncGetAddonByID(id);
+     }
+
+     return null;
+   },
+
+   getAddonIDByInstanceID(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 id;
        }
      }
 
-     return Promise.resolve(null);
+     return null;
    },
 
   /**
    * Removes an AddonInstall from the list of active installs.
    *
    * @param  install
    *         The AddonInstall to remove
    */
@@ -3411,16 +3420,36 @@ var XPIProvider = {
    *         The ID of the add-on to retrieve
    */
   async getAddonByID(aId) {
     let aAddon = await XPIDatabase.getVisibleAddonForID(aId);
     return aAddon ? aAddon.wrapper : null;
   },
 
   /**
+   * Synchronously returns the Addon object for the add-on with the
+   * given ID.
+   *
+   * *DO NOT USE THIS IF YOU CAN AT ALL AVOID IT*
+   *
+   * This will always return null if the add-on database has not been
+   * loaded, and the resulting Addon object may not yet include a
+   * reference to its corresponding repository add-on object.
+   *
+   * @param {string} aId
+   *        The ID of the add-on to return.
+   * @returns {DBAddonInternal?}
+   *        The Addon object, if available.
+   */
+  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);
     if (typesToGet && !typesToGet.some(type => ALL_EXTERNAL_TYPES.has(type))) {
--- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
+++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
@@ -62,39 +62,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
@@ -618,113 +600,98 @@ 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 => 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
@@ -766,40 +733,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.