Bug 1579936 - WebExt API: Add browser.experiments.urlbar.isBrowserUpdateReadyToInstall. r=adw,mixedpuppy
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 14 Nov 2019 10:20:40 +0000
changeset 501912 0cc270168d0844f4e252575dfa04ad588c2f31c7
parent 501911 1b8819d514f8a3a9e9f7b214f5474f84fa59a56c
child 501913 b8a5f2a349bc8429c935dd0af40dbc360bead67c
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersadw, mixedpuppy
bugs1579936
milestone72.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 1579936 - WebExt API: Add browser.experiments.urlbar.isBrowserUpdateReadyToInstall. r=adw,mixedpuppy Differential Revision: https://phabricator.services.mozilla.com/D52884
browser/components/urlbar/tests/ext/api.js
browser/components/urlbar/tests/ext/browser/browser.ini
browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_isBrowserShowingNotification.js
browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_isBrowserUpdateReadyToInstall.js
browser/components/urlbar/tests/ext/schema.json
--- a/browser/components/urlbar/tests/ext/api.js
+++ b/browser/components/urlbar/tests/ext/api.js
@@ -3,18 +3,37 @@
 "use strict";
 
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 XPCOMUtils.defineLazyModuleGetters(this, {
   AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.jsm",
   BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
+  Services: "resource://gre/modules/Services.jsm",
 });
 
+XPCOMUtils.defineLazyServiceGetter(
+  this,
+  "updateService",
+  "@mozilla.org/updates/update-service;1",
+  "nsIApplicationUpdateService"
+);
+XPCOMUtils.defineLazyServiceGetter(
+  this,
+  "updateManager",
+  "@mozilla.org/updates/update-manager;1",
+  "nsIUpdateManager"
+);
+
+function updateStateIs(prefix) {
+  let update = updateManager.activeUpdate;
+  return !!(update && update.state.startsWith(prefix));
+}
+
 this.experiments_urlbar = class extends ExtensionAPI {
   getAPI() {
     return {
       experiments: {
         urlbar: {
           isBrowserShowingNotification() {
             let window = BrowserWindowTracker.getTopWindow();
 
@@ -65,13 +84,30 @@ this.experiments_urlbar = class extends 
             for (let node of navbar.querySelectorAll("toolbarbutton")) {
               if (node.getAttribute("open") == "true") {
                 return true;
               }
             }
 
             return false;
           },
+
+          isBrowserUpdateReadyToInstall() {
+            if (
+              !updateService.canStageUpdates ||
+              !Services.policies.isAllowed("appUpdate")
+            ) {
+              return updateStateIs("pending");
+            }
+            if (updateStateIs("applied")) {
+              return true;
+            }
+            // If the state is pending and there is an error, staging failed and
+            // Firefox can be restarted to apply the update without staging.
+            let update = updateManager.activeUpdate;
+            let errorCode = update ? update.errorCode : 0;
+            return updateStateIs("pending") && errorCode != 0;
+          },
         },
       },
     };
   }
 };
--- a/browser/components/urlbar/tests/ext/browser/browser.ini
+++ b/browser/components/urlbar/tests/ext/browser/browser.ini
@@ -5,8 +5,9 @@
 [DEFAULT]
 support-files =
   ../../browser/head-common.js
   ../api.js
   ../schema.json
   head.js
 
 [browser_ext_urlbar_isBrowserShowingNotification.js]
+[browser_ext_urlbar_isBrowserUpdateReadyToInstall.js]
--- a/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_isBrowserShowingNotification.js
+++ b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_isBrowserShowingNotification.js
@@ -1,14 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /* global browser */
 
-// This tests the browser.urlbarExperiments.isBrowserShowingNotification
+// This tests the browser.experiments.urlbar.isBrowserShowingNotification
 // WebExtension Experiment API.
 
 "use strict";
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.jsm",
 });
 
new file mode 100644
--- /dev/null
+++ b/browser/components/urlbar/tests/ext/browser/browser_ext_urlbar_isBrowserUpdateReadyToInstall.js
@@ -0,0 +1,120 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/* global browser */
+
+// This tests the browser.experiments.urlbar.isBrowserUpdateReadyToInstall
+// WebExtension Experiment API.
+
+"use strict";
+
+const mockUpdateManager = {
+  contractId: "@mozilla.org/updates/update-manager;1",
+
+  _mockClassId: Cc["@mozilla.org/uuid-generator;1"]
+    .getService(Ci.nsIUUIDGenerator)
+    .generateUUID(),
+  _originalClassId: "",
+
+  QueryInterface: ChromeUtils.generateQI([Ci.nsIUpdateManager]),
+
+  createInstance(outer, iiD) {
+    if (outer) {
+      throw Cr.NS_ERROR_NO_AGGREGATION;
+    }
+    return this.QueryInterface(iiD);
+  },
+
+  register() {
+    let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+    if (!registrar.isCIDRegistered(this._mockClassId)) {
+      this._originalClassId = registrar.contractIDToCID(this.contractId);
+      registrar.registerFactory(
+        this._mockClassId,
+        "Unregister after testing",
+        this.contractId,
+        this
+      );
+    }
+  },
+
+  unregister() {
+    let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+    registrar.unregisterFactory(this._mockClassId, this);
+    registrar.registerFactory(this._originalClassId, "", this.contractId, null);
+  },
+
+  setUpdateState(state, errorCode = 0) {
+    this._state = state;
+    this._errorCode = errorCode;
+  },
+
+  get activeUpdate() {
+    return {
+      type: "major",
+      name: "Firefox Developer Edition 49.0a2",
+      state: this._state,
+      errorCode: this._errorCode,
+    };
+  },
+};
+
+add_task(async function noUpdate() {
+  info("should return false when there are no updates");
+  await checkExtension(false);
+});
+
+add_task(async function hasUpdate() {
+  mockUpdateManager.register();
+  registerCleanupFunction(() => {
+    mockUpdateManager.unregister();
+  });
+
+  await SpecialPowers.pushPrefEnv({
+    set: [["app.update.staging.enabled", true]],
+  });
+
+  info("Should return false when an update is not ready");
+  for (let state of [
+    "downloading",
+    "applying",
+    "succeeded",
+    "download-failed",
+    "failed",
+  ]) {
+    mockUpdateManager.setUpdateState(state);
+    await checkExtension(false);
+  }
+
+  info("Should return false when an update is pending with no error");
+  mockUpdateManager.setUpdateState("pending");
+  await checkExtension(false);
+
+  info("Should return true when an update is pending with error");
+  mockUpdateManager.setUpdateState("pending", 1);
+  await checkExtension(true);
+
+  info("Should return true when an update was applied");
+  for (let state of ["applied", "applied-service"]) {
+    mockUpdateManager.setUpdateState(state);
+    await checkExtension(true);
+  }
+
+  await SpecialPowers.pushPrefEnv({
+    set: [["app.update.staging.enabled", false]],
+  });
+
+  info("Should return true when an update is pending and staging is disabled");
+  mockUpdateManager.setUpdateState("pending");
+  await checkExtension(true);
+});
+
+async function checkExtension(expectedReady) {
+  let ext = await loadExtension(async () => {
+    let ready = await browser.experiments.urlbar.isBrowserUpdateReadyToInstall();
+    browser.test.sendMessage("ready", ready);
+  });
+  let ready = await ext.awaitMessage("ready");
+  Assert.equal(ready, expectedReady);
+  await ext.unload();
+}
--- a/browser/components/urlbar/tests/ext/schema.json
+++ b/browser/components/urlbar/tests/ext/schema.json
@@ -4,12 +4,19 @@
     "description": "APIs supporting urlbar experiments",
     "functions": [
       {
         "name": "isBrowserShowingNotification",
         "type": "function",
         "async": true,
         "description": "Returns true if the browser is showing any kind of notification.",
         "parameters": []
+      },
+      {
+        "name": "isBrowserUpdateReadyToInstall",
+        "type": "function",
+        "async": true,
+        "description": "Returns true if there is an update ready to install.",
+        "parameters": []
       }
     ]
   }
 ]