Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
authorAndreea Pavel <apavel@mozilla.com>
Sat, 21 Apr 2018 18:26:31 +0300
changeset 1491732 69fa028293fbd2b2c55f5c1289a539866635b0f8
parent 1491627 fde4d35d666ad9f261f02e520fcfc675f45fe929 (current diff)
parent 1491637 e2b0e792967f878029cb9e2fbb538821cc9b0baa (diff)
child 1491733 0f113bac293a677b74c6fc2ce9ecc2a7af09e0e2
push id266529
push useropettay@mozilla.com
push dateSat, 21 Apr 2018 20:56:30 +0000
treeherdertry@514ff6e1dc4e [default view] [failures only]
reviewersmerge
milestone61.0a1
Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
--- a/browser/base/content/test/plugins/blocklist_proxy.js
+++ b/browser/base/content/test/plugins/blocklist_proxy.js
@@ -1,15 +1,16 @@
 var Cm = Components.manager;
 
 const kBlocklistServiceUUID = "{66354bc9-7ed1-4692-ae1d-8da97d6b205e}";
 const kBlocklistServiceContractID = "@mozilla.org/extensions/blocklist;1";
 const kBlocklistServiceFactory = Cm.getClassObject(Cc[kBlocklistServiceContractID], Ci.nsIFactory);
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/Timer.jsm");
 
 /*
  * A lightweight blocklist proxy for the testing purposes.
  */
 var BlocklistProxy = {
   _uuid: null,
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
@@ -39,17 +40,18 @@ var BlocklistProxy = {
   },
 
   notify(aTimer) {
   },
 
   observe(aSubject, aTopic, aData) {
   },
 
-  getAddonBlocklistState(aAddon, aAppVersion, aToolkitVersion) {
+  async getAddonBlocklistState(aAddon, aAppVersion, aToolkitVersion) {
+    await new Promise(r => setTimeout(r, 0));
     return 0; // STATE_NOT_BLOCKED
   },
 
   getPluginBlocklistState(aPluginTag, aAppVersion, aToolkitVersion) {
     return 0; // STATE_NOT_BLOCKED
   },
 
   getPluginBlocklistURL(aPluginTag) {
--- a/devtools/.eslintrc.js
+++ b/devtools/.eslintrc.js
@@ -11,31 +11,29 @@ module.exports = {
     "module": true,
     "reportError": true,
     "require": true,
   },
   "overrides": [{
     // XXX Bug 1230193. We're still working on enabling no-undef for these test
     // directories.
     "files": [
-      "client/framework/test/**",
       "client/scratchpad/**",
       "server/tests/mochitest/**",
       "shared/tests/unit/**",
     ],
     "rules": {
       "no-undef": "off",
     }
   }, {
     "files": [
       "client/framework/**",
     ],
     "rules": {
       "no-return-assign": "off",
-      "no-unused-vars": "off",
     }
   }, {
     "files": [
       "client/scratchpad/scratchpad-manager.jsm",
       "client/scratchpad/scratchpad.js",
       "client/shared/*.jsm",
     ],
     "rules": {
--- a/devtools/client/framework/attach-thread.js
+++ b/devtools/client/framework/attach-thread.js
@@ -1,15 +1,14 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 
-const {Cc, Ci, Cu} = require("chrome");
 const Services = require("Services");
 const defer = require("devtools/shared/defer");
 
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
 
 function handleThreadState(toolbox, event, packet) {
   // Suppress interrupted events by default because the thread is
--- a/devtools/client/framework/components/toolbox-toolbar.js
+++ b/devtools/client/framework/components/toolbox-toolbar.js
@@ -6,17 +6,16 @@
 const { Component, createFactory } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const {div, button} = dom;
 const {openWebLink} = require("devtools/client/shared/link");
 
 const Menu = require("devtools/client/framework/menu");
 const MenuItem = require("devtools/client/framework/menu-item");
-const ToolboxTab = createFactory(require("devtools/client/framework/components/toolbox-tab"));
 const ToolboxTabs = createFactory(require("devtools/client/framework/components/toolbox-tabs"));
 
 /**
  * This is the overall component for the toolbox toolbar. It is designed to not know how
  * the state is being managed, and attempts to be as pure as possible. The
  * ToolboxController component controls the changing state, and passes in everything as
  * props.
  */
--- a/devtools/client/framework/connect/connect.js
+++ b/devtools/client/framework/connect/connect.js
@@ -42,16 +42,17 @@ window.addEventListener("DOMContentLoade
       showError("unexpected");
     });
   });
 }, {capture: true, once: true});
 
 /**
  * Called when the "connect" button is clicked.
  */
+/* exported submit */
 var submit = async function() {
   // Show the "connecting" screen
   document.body.classList.add("connecting");
 
   let host = document.getElementById("host").value;
   let port = document.getElementById("port").value;
 
   // Save the host/port values
--- a/devtools/client/framework/gDevTools.jsm
+++ b/devtools/client/framework/gDevTools.jsm
@@ -10,18 +10,16 @@
  * This JSM is here to keep some compatibility with existing add-ons.
  * Please now use the modules:
  * - devtools/client/framework/devtools for gDevTools
  * - devtools/client/framework/devtools-browser for gDevToolsBrowser
  */
 
 this.EXPORTED_SYMBOLS = [ "gDevTools", "gDevToolsBrowser" ];
 
-const { loader } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-
 /**
  * Do not directly map to the commonjs modules so that callsites of
  * gDevTools.jsm do not have to do anything to access to the very last version
  * of the module. The `devtools` and `browser` getter are always going to
  * retrieve the very last version of the modules.
  */
 Object.defineProperty(this, "require", {
   get() {
--- a/devtools/client/framework/test/browser_browser_toolbox.js
+++ b/devtools/client/framework/test/browser_browser_toolbox.js
@@ -33,16 +33,17 @@ add_task(async function() {
       Services.obs.removeObserver(listener, "browser-toolbox-console-works");
       done(data === "true");
     }, "browser-toolbox-console-works");
   });
 
   // Be careful, this JS function is going to be executed in the addon toolbox,
   // which lives in another process. So do not try to use any scope variable!
   let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
+  /* global toolbox */
   let testScript = function() {
     toolbox.selectTool("webconsole")
       .then(console => {
         // This is for checking Browser Toolbox doesn't have a close button.
         let hasCloseButton = !!toolbox.doc.getElementById("toolbox-close");
         let { jsterm } = console.hud;
         let js = "Services.obs.notifyObservers(null, 'browser-toolbox-console-works', " +
             hasCloseButton + ");";
--- a/devtools/client/framework/test/browser_browser_toolbox_debugger.js
+++ b/devtools/client/framework/test/browser_browser_toolbox_debugger.js
@@ -58,16 +58,17 @@ add_task(async function runTest() {
   let interval = setInterval(s.plop, 1000);
 
   // Be careful, this JS function is going to be executed in the browser toolbox,
   // which lives in another process. So do not try to use any scope variable!
   let env = Cc["@mozilla.org/process/environment;1"]
               .getService(Ci.nsIEnvironment);
   // First inject a very minimal head, with simplest assertion methods
   // and very common globals
+  /* eslint-disable no-unused-vars */
   let testHead = (function() {
     const info = msg => dump(msg + "\n");
     const is = (a, b, description) => {
       let msg = "'" + JSON.stringify(a) + "' is equal to '" + JSON.stringify(b) + "'";
       if (description) {
         msg += " - " + description;
       }
       if (a !== b) {
@@ -111,19 +112,19 @@ add_task(async function runTest() {
         // TODO: fixme.
         // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
         setTimeout(function() {
           waitUntil(predicate, interval).then(() => resolve(true));
         }, interval);
       });
     }
   }).toSource().replace(/^\(function\(\) \{|\}\)$/g, "");
+  /* eslint-enable no-unused-vars */
   // Stringify testHead's function and remove `(function {` prefix and `})` suffix
   // to ensure inner symbols gets exposed to next pieces of code
-
   // Then inject new debugger head file
   let { content } = await fetch(debuggerHeadURL);
   let debuggerHead = content;
   // We remove its import of shared-head, which isn't available in browser toolbox process
   // And isn't needed thanks to testHead's symbols
   debuggerHead = debuggerHead.replace(/Services.scriptloader.loadSubScript[^\)]*\);/, "");
 
   // Finally, fetch the debugger test script that is going to be execute in the browser
--- a/devtools/client/framework/test/browser_ignore_toolbox_network_requests.js
+++ b/devtools/client/framework/test/browser_ignore_toolbox_network_requests.js
@@ -17,16 +17,16 @@ add_task(async function() {
   let tab = await addTab(URL_ROOT + "doc_viewsource.html");
   let target = TargetFactory.forTab(tab);
   let toolbox = await gDevTools.showToolbox(target, "styleeditor");
   let panel = toolbox.getPanel("styleeditor");
 
   is(panel.UI.editors.length, 1, "correct number of editors opened");
 
   let monitor = await toolbox.selectTool("netmonitor");
-  let { store, windowRequire } = monitor.panelWin;
+  let { store } = monitor.panelWin;
 
   is(store.getState().requests.requests.size, 0, "No network requests appear in the network panel");
 
   await gDevTools.closeToolbox(target);
   tab = target = toolbox = panel = null;
   gBrowser.removeCurrentTab();
 });
--- a/devtools/client/framework/test/browser_new_activation_workflow.js
+++ b/devtools/client/framework/test/browser_new_activation_workflow.js
@@ -2,18 +2,16 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests devtools API
 
 var toolbox, target;
 
-var tempScope = {};
-
 function test() {
   addTab("about:blank").then(function(aTab) {
     target = TargetFactory.forTab(gBrowser.selectedTab);
     loadWebConsole(aTab).then(function() {
       console.log("loaded");
     });
   });
 }
--- a/devtools/client/framework/test/browser_target_support.js
+++ b/devtools/client/framework/test/browser_target_support.js
@@ -11,17 +11,17 @@ var { WebAudioFront } =
 
 async function testTarget(client, target) {
   await target.makeRemote();
 
   is(target.hasActor("timeline"), true, "target.hasActor() true when actor exists.");
   is(target.hasActor("webaudio"), true, "target.hasActor() true when actor exists.");
   is(target.hasActor("notreal"), false, "target.hasActor() false when actor does not exist.");
   // Create a front to ensure the actor is loaded
-  let front = new WebAudioFront(target.client, target.form);
+  new WebAudioFront(target.client, target.form);
 
   let desc = await target.getActorDescription("webaudio");
   is(desc.typeName, "webaudio",
     "target.getActorDescription() returns definition data for corresponding actor");
   is(desc.events["start-context"].type, "startContext",
     "target.getActorDescription() returns event data for corresponding actor");
 
   desc = await target.getActorDescription("nope");
--- a/devtools/client/framework/test/browser_toolbox_options_disable_cache-01.js
+++ b/devtools/client/framework/test/browser_toolbox_options_disable_cache-01.js
@@ -4,16 +4,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Tests that disabling the cache for a tab works as it should when toolboxes
 // are not toggled.
+/* import-globals-from helper_disable_cache.js */
 loadHelperScript("helper_disable_cache.js");
 
 add_task(async function() {
   // Disable rcwn to make cache behavior deterministic.
   await pushPref("network.http.rcwn.enabled", false);
 
   // Ensure that the setting is cleared after the test.
   registerCleanupFunction(() => {
--- a/devtools/client/framework/test/browser_toolbox_options_disable_cache-02.js
+++ b/devtools/client/framework/test/browser_toolbox_options_disable_cache-02.js
@@ -4,16 +4,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Tests that disabling the cache for a tab works as it should when toolboxes
 // are toggled.
+/* import-globals-from helper_disable_cache.js */
 loadHelperScript("helper_disable_cache.js");
 
 add_task(async function() {
   // Disable rcwn to make cache behavior deterministic.
   await pushPref("network.http.rcwn.enabled", false);
 
   // Ensure that the setting is cleared after the test.
   registerCleanupFunction(() => {
--- a/devtools/client/framework/test/browser_toolbox_options_disable_js.html
+++ b/devtools/client/framework/test/browser_toolbox_options_disable_js.html
@@ -16,16 +16,17 @@
         border: 1px solid #000;
       }
 
       h1 {
         font-size: 20px
       }
     </style>
     <script type="application/javascript">
+      /* exported log */
       function log(msg) {
         let output = document.getElementById("output");
 
         // eslint-disable-next-line no-unsanitized/property
         output.innerHTML = msg;
       }
     </script>
   </head>
--- a/devtools/client/framework/test/browser_toolbox_options_disable_js_iframe.html
+++ b/devtools/client/framework/test/browser_toolbox_options_disable_js_iframe.html
@@ -6,16 +6,17 @@
       div {
         width: 260px;
         height: 24px;
         border: 1px solid #000;
         margin-top: 10px;
       }
     </style>
     <script type="application/javascript">
+      /* exported log */
       function log(msg) {
         let output = document.getElementById("output");
 
         // eslint-disable-next-line no-unsanitized/property
         output.innerHTML = msg;
       }
     </script>
   </head>
--- a/devtools/client/framework/test/browser_toolbox_options_enable_serviceworkers_testing_frame_script.js
+++ b/devtools/client/framework/test/browser_toolbox_options_enable_serviceworkers_testing_frame_script.js
@@ -1,15 +1,17 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // A helper frame-script for devtools/client/framework service worker tests.
 
+/* eslint-env mozilla/frame-script */
+
 "use strict";
 
 addMessageListener("devtools:sw-test:register", function(msg) {
   content.navigator.serviceWorker.register("serviceworker.js")
     .then(swr => {
       sendAsyncMessage("devtools:sw-test:register", {success: true});
     }, error => {
       sendAsyncMessage("devtools:sw-test:register", {success: false});
--- a/devtools/client/framework/test/browser_toolbox_races.js
+++ b/devtools/client/framework/test/browser_toolbox_races.js
@@ -13,17 +13,17 @@ requestLongerTimeout(2);
 const URL = "data:text/html;charset=utf-8,Toggling devtools quickly";
 const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
 
 add_task(async function() {
   // Make sure this test starts with the selectedTool pref cleared. Previous
   // tests select various tools, and that sets this pref.
   Services.prefs.clearUserPref("devtools.toolbox.selectedTool");
 
-  let tab = await addTab(URL);
+  await addTab(URL);
 
   let created = 0, ready = 0, destroy = 0, destroyed = 0;
   let onCreated = () => {
     created++;
   };
   let onReady = () => {
     ready++;
   };
--- a/devtools/client/framework/test/browser_toolbox_remoteness_change.js
+++ b/devtools/client/framework/test/browser_toolbox_remoteness_change.js
@@ -1,13 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-var {Toolbox} = require("devtools/client/framework/toolbox");
-
 const URL_1 = "about:robots";
 const URL_2 = "data:text/html;charset=UTF-8," +
   encodeURIComponent("<div id=\"remote-page\">foo</div>");
 
 add_task(async function() {
   info("Open a tab on a URL supporting only running in parent process");
   let tab = await addTab(URL_1);
   is(tab.linkedBrowser.currentURI.spec, URL_1, "We really are on the expected document");
--- a/devtools/client/framework/test/browser_toolbox_sidebar.js
+++ b/devtools/client/framework/test/browser_toolbox_sidebar.js
@@ -5,17 +5,16 @@
 
 function test() {
   let {ToolSidebar} = require("devtools/client/framework/sidebar");
 
   const tab1URL = "data:text/html;charset=utf8,<title>1</title><p>1</p>";
   const tab2URL = "data:text/html;charset=utf8,<title>2</title><p>2</p>";
   const tab3URL = "data:text/html;charset=utf8,<title>3</title><p>3</p>";
 
-  let panelDoc;
   let tab1Selected = false;
   let registeredTabs = {};
   let readyTabs = {};
 
   let toolDefinition = {
     id: "fakeTool4242",
     visibilityswitch: "devtools.fakeTool4242.enabled",
     url: CHROME_URL_ROOT + "browser_toolbox_sidebar_toolURL.xul",
--- a/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
+++ b/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
@@ -56,18 +56,16 @@ function runTools(target) {
       ok(panel.isReady, toolId + " panel should be ready");
     }
 
     await toolbox.destroy();
   })();
 }
 
 function getClient() {
-  let deferred = defer();
-
   DebuggerServer.init();
   DebuggerServer.registerAllActors();
 
   let transport = DebuggerServer.connectPipe();
   let client = new DebuggerClient(transport);
 
   return client.connect().then(() => client);
 }
--- a/devtools/client/framework/test/browser_toolbox_toolbar_reorder_by_width.js
+++ b/devtools/client/framework/test/browser_toolbox_toolbar_reorder_by_width.js
@@ -18,17 +18,17 @@ let { Toolbox } = require("devtools/clie
 
 add_task(async function() {
   let tab = await addTab("about:blank");
 
   info("Open devtools on the Storage in a sidebar.");
   let toolbox = await openToolboxForTab(tab, "storage", Toolbox.HostType.BOTTOM);
 
   info("Waiting for the window to be resized");
-  let {hostWin, originalWidth, originalHeight} = await resizeWindow(toolbox, 800);
+  let {originalWidth, originalHeight} = await resizeWindow(toolbox, 800);
 
   info("Wait until the tools menu button is available");
   await waitUntil(() => toolbox.doc.querySelector(".tools-chevron-menu"));
 
   let toolsMenuButton = toolbox.doc.querySelector(".tools-chevron-menu");
   ok(toolsMenuButton, "The tools menu button is displayed");
 
   info("Confirm that selected tab is not hidden.");
@@ -40,17 +40,17 @@ add_task(async function() {
 
 add_task(async function() {
   let tab = await addTab("about:blank");
 
   info("Open devtools on the Storage in a sidebar.");
   let toolbox = await openToolboxForTab(tab, "storage", Toolbox.HostType.BOTTOM);
 
   info("Resize devtools window to a width that should trigger an overflow");
-  let {hostWin, originalWidth, originalHeight} = await resizeWindow(toolbox, 800);
+  let {originalWidth, originalHeight} = await resizeWindow(toolbox, 800);
 
   info("Regist a new tab");
   let onRegistered = toolbox.once("tool-registered");
   gDevTools.registerTool({
     id: "test-tools",
     label: "Test Tools",
     isMenu: true,
     isTargetSupported: () => true,
--- a/devtools/client/framework/test/browser_toolbox_tools_per_toolbox_registration.js
+++ b/devtools/client/framework/test/browser_toolbox_tools_per_toolbox_registration.js
@@ -35,18 +35,16 @@ var waitForToolInstanceBuild = new Promi
 var resolveToolInstanceDestroyed;
 var waitForToolInstanceDestroyed = new Promise((resolve) => {
   resolveToolInstanceDestroyed = resolve;
 });
 
 function toolboxRegister(aToolbox) {
   toolbox = aToolbox;
 
-  var resolveToolInstanceBuild;
-
   waitForToolInstanceBuild = new Promise((resolve) => {
     resolveToolInstanceBuild = resolve;
   });
 
   info("add per-toolbox tool in the opened toolbox.");
 
   toolbox.addAdditionalTool({
     id: TOOL_ID,
--- a/devtools/client/framework/test/helper_disable_cache.js
+++ b/devtools/client/framework/test/helper_disable_cache.js
@@ -1,15 +1,21 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+// This file assumes we have head.js globals for the scope where this is loaded.
+/* import-globals-from head.js */
+
+/* exported initTab, checkCacheStateForAllTabs, setDisableCacheCheckboxChecked,
+            finishUp */
+
 // Common code shared by browser_toolbox_options_disable_cache-*.js
 const TEST_URI = URL_ROOT + "browser_toolbox_options_disable_cache.sjs";
 var tabs = [
   {
     title: "Tab 0",
     desc: "Toggles cache on.",
     startToolbox: true
   },
--- a/devtools/client/framework/test/test_browser_toolbox_debugger.js
+++ b/devtools/client/framework/test/test_browser_toolbox_debugger.js
@@ -1,9 +1,11 @@
-/* global toolbox */
+/* global toolbox, createDebuggerContext, waitForSources, testUrl,
+          waitForPaused, addBreakpoint, assertPausedLocation, stepIn,
+          findSource, removeBreakpoint, resume */
 
 info(`START: ${new Error().lineNumber}`);
 
 (async function() {
   Services.prefs.clearUserPref("devtools.debugger.tabs");
   Services.prefs.clearUserPref("devtools.debugger.pending-selected-location");
 
   info("Waiting for debugger load");
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -202,23 +202,24 @@ BuildHandlerChain(nsIContent* aContent, 
       continue;
     }
 
     Element* keyElement = key->AsElement();
     // Check whether the key element has empty value at key/char attribute.
     // Such element is used by localizers for alternative shortcut key
     // definition on the locale. See bug 426501.
     nsAutoString valKey, valCharCode, valKeyCode;
-    bool attrExists =
-      keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::key, valKey) ||
+    // Hopefully at least one of the attributes is set:
+    keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::key, valKey) ||
       keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::charcode, valCharCode) ||
       keyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::keycode, valKeyCode);
-    if (attrExists &&
-        valKey.IsEmpty() && valCharCode.IsEmpty() && valKeyCode.IsEmpty())
+    // If not, ignore this key element.
+    if (valKey.IsEmpty() && valCharCode.IsEmpty() && valKeyCode.IsEmpty()) {
       continue;
+    }
 
     // reserved="pref" is the default for <key> elements.
     XBLReservedKey reserved = XBLReservedKey_Unset;
     if (keyElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::reserved,
                                 nsGkAtoms::_true, eCaseMatters)) {
       reserved = XBLReservedKey_True;
     } else if (keyElement->AttrValueIs(kNameSpaceID_None,
                                        nsGkAtoms::reserved,
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -12,16 +12,17 @@ var EXPORTED_SYMBOLS = ["AddonTestUtils"
 const CERTDB_CONTRACTID = "@mozilla.org/security/x509certdb;1";
 
 Cu.importGlobalProperties(["fetch", "TextEncoder"]);
 
 ChromeUtils.import("resource://gre/modules/AsyncShutdown.jsm");
 ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
 ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://gre/modules/Timer.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm", {});
 const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm", {});
 
 ChromeUtils.defineModuleGetter(this, "Extension",
                                "resource://gre/modules/Extension.jsm");
 XPCOMUtils.defineLazyGetter(this, "Management", () => {
@@ -131,23 +132,23 @@ class MockBlocklist {
     this._reLazifyService();
   }
 
   unregister() {
     MockRegistrar.unregister(this.originalCID);
     this._reLazifyService();
   }
 
-  getAddonBlocklistState(addon, appVersion, toolkitVersion) {
+  async getAddonBlocklistState(addon, appVersion, toolkitVersion) {
+    await new Promise(r => setTimeout(r, 0));
     return this.addons.get(addon.id) || Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
   }
 
   async getAddonBlocklistEntry(addon, appVersion, toolkitVersion) {
-    await Promise.resolve();
-    let state = this.getAddonBlocklistState(addon, appVersion, toolkitVersion);
+    let state = await this.getAddonBlocklistState(addon, appVersion, toolkitVersion);
     if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
       return {
         state,
         url: "http://example.com/",
       };
     }
     return null;
   }
--- a/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm
@@ -475,45 +475,45 @@ var AddonUpdateChecker = {
           return update;
         }
       }
     }
     return null;
   },
 
   /**
-   * Returns the newest available update from a list of update objects.
+   * Asynchronously returns the newest available update from a list of update objects.
    *
    * @param  aUpdates
    *         An array of update objects
    * @param  aAppVersion
    *         The version of the application or null to use the current version
    * @param  aPlatformVersion
    *         The version of the platform or null to use the current version
    * @param  aIgnoreMaxVersion
    *         When determining compatible updates, ignore maxVersion. Optional.
    * @param  aIgnoreStrictCompat
    *         When determining compatible updates, ignore strictCompatibility. Optional.
    * @param  aCompatOverrides
    *         Array of AddonCompatibilityOverride to take into account. Optional.
    * @return an update object if one matches or null if not
    */
-  getNewestCompatibleUpdate(aUpdates, aAppVersion, aPlatformVersion,
-                                      aIgnoreMaxVersion, aIgnoreStrictCompat,
-                                      aCompatOverrides) {
+  async getNewestCompatibleUpdate(aUpdates, aAppVersion, aPlatformVersion,
+                                  aIgnoreMaxVersion, aIgnoreStrictCompat,
+                                  aCompatOverrides) {
     if (!aAppVersion)
       aAppVersion = Services.appinfo.version;
     if (!aPlatformVersion)
       aPlatformVersion = Services.appinfo.platformVersion;
 
     let newest = null;
     for (let update of aUpdates) {
       if (!update.updateURL)
         continue;
-      let state = Services.blocklist.getAddonBlocklistState(update, aAppVersion, aPlatformVersion);
+      let state = await Services.blocklist.getAddonBlocklistState(update, aAppVersion, aPlatformVersion);
       if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED)
         continue;
       if ((newest == null || (Services.vc.compare(newest.version, update.version) < 0)) &&
           matchesVersions(update, aAppVersion, aPlatformVersion,
                           aIgnoreMaxVersion, aIgnoreStrictCompat,
                           aCompatOverrides)) {
         newest = update;
       }
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm
@@ -2590,22 +2590,19 @@ UpdateChecker.prototype = {
       aSelf.callListener("onUpdateFinished", aSelf.addon.wrapper,
                          AddonManager.UPDATE_STATUS_NO_ERROR);
     }
 
     let compatOverrides = AddonManager.strictCompatibility ?
                           null :
                           await AddonRepository.getCompatibilityOverrides(this.addon.id);
 
-    let update = AUC.getNewestCompatibleUpdate(aUpdates,
-                                           this.appVersion,
-                                           this.platformVersion,
-                                           ignoreMaxVersion,
-                                           ignoreStrictCompat,
-                                           compatOverrides);
+    let update = await AUC.getNewestCompatibleUpdate(
+      aUpdates, this.appVersion, this.platformVersion,
+      ignoreMaxVersion, ignoreStrictCompat, compatOverrides);
 
     if (update && Services.vc.compare(this.addon.version, update.version) < 0
         && !this.addon._installLocation.locked) {
       for (let currentInstall of XPIProvider.installs) {
         // Skip installs that don't match the available update
         if (currentInstall.existingAddon != this.addon ||
             currentInstall.version != update.version)
           continue;
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -339,19 +339,18 @@ Blocklist.prototype = {
    *        If this parameter is null, the version of the running application
    *        is used.
    * @param {string?} toolkitVersion
    *        The version of the toolkit we are checking in the blocklist.
    *        If this parameter is null, the version of the running toolkit
    *        is used.
    * @returns {integer} The STATE constant.
    */
-  getAddonBlocklistState(addon, appVersion, toolkitVersion) {
-    if (!this.isLoaded)
-      this._loadBlocklist();
+  async getAddonBlocklistState(addon, appVersion, toolkitVersion) {
+    await this.loadBlocklistAsync();
     return this._getAddonBlocklistState(addon, this._addonEntries,
                                         appVersion, toolkitVersion);
   },
 
   /**
    * Returns a matching blocklist entry for the given add-on, if one
    * exists.
    *
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_osabi.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_osabi.js
@@ -281,22 +281,23 @@ add_task(async function setup() {
           `Add-on ${id} should not initially be blocked`);
   }
 });
 
 add_task(async function test_1() {
   await loadBlocklist("test_bug393285.xml");
 
   let addons = await getAddons(ADDON_IDS);
-  function isBlocklisted(addon, appVer, toolkitVer) {
-    return Services.blocklist.getAddonBlocklistState(addon, appVer, toolkitVer) != Services.blocklist.STATE_NOT_BLOCKED;
+  async function isBlocklisted(addon, appVer, toolkitVer) {
+    let state = await Services.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 || []) {
-      ok(isBlocklisted(addons.get(id), ...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 || []) {
-      ok(!isBlocklisted(addons.get(id), ...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_overrideblocklist.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_overrideblocklist.js
@@ -79,119 +79,120 @@ function run_test() {
       clearBlocklists();
       appBlocklist.moveTo(gAppDir, FILE_BLOCKLIST);
     });
   }
 
   run_next_test();
 }
 
-function isBlocklisted(addon, appVer, toolkitVer) {
-  return Services.blocklist.getAddonBlocklistState(addon, appVer, toolkitVer) != Services.blocklist.STATE_NOT_BLOCKED;
+async function isBlocklisted(addon, appVer, toolkitVer) {
+  let state = await Services.blocklist.getAddonBlocklistState(addon, appVer, toolkitVer);
+  return state != Services.blocklist.STATE_NOT_BLOCKED;
 }
 
 // On first run whataver is in the app dir should get copied to the profile
-add_test(function test_copy() {
+add_test(async function test_copy() {
   clearBlocklists();
   copyToApp(OLD);
 
   incrementAppVersion();
   startupManager();
 
   reloadBlocklist();
-  Assert.ok(!isBlocklisted(invalidAddon));
-  Assert.ok(!isBlocklisted(ancientAddon));
-  Assert.ok(isBlocklisted(oldAddon));
-  Assert.ok(!isBlocklisted(newAddon));
+  Assert.ok(!(await isBlocklisted(invalidAddon)));
+  Assert.ok(!(await isBlocklisted(ancientAddon)));
+  Assert.ok(await isBlocklisted(oldAddon));
+  Assert.ok(!(await isBlocklisted(newAddon)));
 
   shutdownManager();
 
   run_next_test();
 });
 
 // An ancient blocklist should be ignored
-add_test(function test_ancient() {
+add_test(async function test_ancient() {
   clearBlocklists();
   copyToApp(ANCIENT);
   copyToProfile(OLD, OLD_TSTAMP);
 
   incrementAppVersion();
   startupManager();
 
   reloadBlocklist();
 
-  Assert.ok(!isBlocklisted(invalidAddon));
-  Assert.ok(!isBlocklisted(ancientAddon));
-  Assert.ok(isBlocklisted(oldAddon));
-  Assert.ok(!isBlocklisted(newAddon));
+  Assert.ok(!(await isBlocklisted(invalidAddon)));
+  Assert.ok(!(await isBlocklisted(ancientAddon)));
+  Assert.ok(await isBlocklisted(oldAddon));
+  Assert.ok(!(await isBlocklisted(newAddon)));
 
   shutdownManager();
 
   run_next_test();
 });
 
 // A new blocklist should override an old blocklist
-add_test(function test_override() {
+add_test(async function test_override() {
   clearBlocklists();
   copyToApp(NEW);
   copyToProfile(OLD, OLD_TSTAMP);
 
   incrementAppVersion();
   startupManager();
 
   reloadBlocklist();
 
-  Assert.ok(!isBlocklisted(invalidAddon));
-  Assert.ok(!isBlocklisted(ancientAddon));
-  Assert.ok(!isBlocklisted(oldAddon));
-  Assert.ok(isBlocklisted(newAddon));
+  Assert.ok(!(await isBlocklisted(invalidAddon)));
+  Assert.ok(!(await isBlocklisted(ancientAddon)));
+  Assert.ok(!(await isBlocklisted(oldAddon)));
+  Assert.ok(await isBlocklisted(newAddon));
 
   shutdownManager();
 
   run_next_test();
 });
 
 // An old blocklist shouldn't override a new blocklist
-add_test(function test_retain() {
+add_test(async function test_retain() {
   clearBlocklists();
   copyToApp(OLD);
   copyToProfile(NEW, NEW_TSTAMP);
 
   incrementAppVersion();
   startupManager();
 
   reloadBlocklist();
 
-  Assert.ok(!isBlocklisted(invalidAddon));
-  Assert.ok(!isBlocklisted(ancientAddon));
-  Assert.ok(!isBlocklisted(oldAddon));
-  Assert.ok(isBlocklisted(newAddon));
+  Assert.ok(!(await isBlocklisted(invalidAddon)));
+  Assert.ok(!(await isBlocklisted(ancientAddon)));
+  Assert.ok(!(await isBlocklisted(oldAddon)));
+  Assert.ok(await isBlocklisted(newAddon));
 
   shutdownManager();
 
   run_next_test();
 });
 
 // A missing blocklist in the profile should still load an app-shipped blocklist
-add_test(function test_missing() {
+add_test(async function test_missing() {
   clearBlocklists();
   copyToApp(OLD);
   copyToProfile(NEW, NEW_TSTAMP);
 
   incrementAppVersion();
   startupManager();
   shutdownManager();
 
   let blocklist = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
   blocklist.remove(true);
   startupManager(false);
 
   reloadBlocklist();
 
-  Assert.ok(!isBlocklisted(invalidAddon));
-  Assert.ok(!isBlocklisted(ancientAddon));
-  Assert.ok(isBlocklisted(oldAddon));
-  Assert.ok(!isBlocklisted(newAddon));
+  Assert.ok(!(await isBlocklisted(invalidAddon)));
+  Assert.ok(!(await isBlocklisted(ancientAddon)));
+  Assert.ok(await isBlocklisted(oldAddon));
+  Assert.ok(!(await isBlocklisted(newAddon)));
 
   shutdownManager();
 
   run_next_test();
 });
--- a/toolkit/mozapps/extensions/test/xpcshell/test_update_rdf.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_update_rdf.js
@@ -60,17 +60,17 @@ add_task(async function test_update_rdf_
   }
 });
 
 add_task(async function test_update_check() {
   for (let file of ["test_updatecheck.rdf", "test_updatecheck.json"]) {
     let updates = await checkUpdates("updatecheck1@tests.mozilla.org", file);
 
     equal(updates.length, 5);
-    let update = AddonUpdateChecker.getNewestCompatibleUpdate(updates);
+    let update = await AddonUpdateChecker.getNewestCompatibleUpdate(updates);
     notEqual(update, null);
     equal(update.version, "3.0");
     update = AddonUpdateChecker.getCompatibilityUpdate(updates, "2");
     notEqual(update, null);
     equal(update.version, "2.0");
     equal(update.targetApplications[0].minVersion, "1");
     equal(update.targetApplications[0].maxVersion, "2");
   }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_updatecheck.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_updatecheck.js
@@ -34,17 +34,17 @@ function run_test() {
 
 const UPDATE_FILE = "test_updatecheck.json";
 
 // Test that a basic update check returns the expected available updates
 add_task(async function() {
   let updates = await checkUpdates("updatecheck1@tests.mozilla.org", UPDATE_FILE);
 
   equal(updates.length, 5);
-  let update = AddonUpdateChecker.getNewestCompatibleUpdate(updates);
+  let update = await AddonUpdateChecker.getNewestCompatibleUpdate(updates);
   notEqual(update, null);
   equal(update.version, "3.0");
   update = AddonUpdateChecker.getCompatibilityUpdate(updates, "2");
   notEqual(update, null);
   equal(update.version, "2.0");
   equal(update.targetApplications[0].minVersion, "1");
   equal(update.targetApplications[0].maxVersion, "2");
 });
@@ -154,17 +154,17 @@ add_task(async function() {
     equal(e.status, AddonManager.ERROR_PARSE_ERROR);
   }
 });
 
 add_task(async function() {
   let updates = await checkUpdates("ignore-compat@tests.mozilla.org",
                                    UPDATE_FILE);
   equal(updates.length, 3);
-  let update = AddonUpdateChecker.getNewestCompatibleUpdate(
+  let update = await AddonUpdateChecker.getNewestCompatibleUpdate(
     updates, null, null, true);
   notEqual(update, null);
   equal(update.version, 2);
 });
 
 add_task(async function() {
   let updates = await checkUpdates("compat-override@tests.mozilla.org",
                                    UPDATE_FILE);
@@ -179,22 +179,22 @@ add_task(async function() {
   }, {
     type: "incompatible",
     minVersion: 2,
     maxVersion: 2,
     appID: "xpcshell@tests.mozilla.org",
     appMinVersion: 1,
     appMaxVersion: 2
   }];
-  let update = AddonUpdateChecker.getNewestCompatibleUpdate(
+  let update = await AddonUpdateChecker.getNewestCompatibleUpdate(
     updates, null, null, true, false, overrides);
   notEqual(update, null);
   equal(update.version, 1);
 });
 
 add_task(async function() {
   let updates = await checkUpdates("compat-strict-optin@tests.mozilla.org",
                                    UPDATE_FILE);
   equal(updates.length, 1);
-  let update = AddonUpdateChecker.getNewestCompatibleUpdate(
+  let update = await AddonUpdateChecker.getNewestCompatibleUpdate(
     updates, null, null, true, false);
   equal(update, null);
 });