Bug 1336501 - Sync shield-recipe-client from GitHub (ad0f45e). r=Gijs, a=lizzard
authorMythmon <mcooper@mozilla.com>
Wed, 08 Feb 2017 09:51:55 -0800
changeset 378354 6b063631a7d3ffd5dc2b621852e4d8ac8758ef99
parent 378353 787f2ba757298bed792e11662a341950cbb8cf7d
child 378355 920aa8178562a97bab18bd69775610a02515e5ab
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs, lizzard
bugs1336501
milestone53.0a2
Bug 1336501 - Sync shield-recipe-client from GitHub (ad0f45e). r=Gijs, a=lizzard MozReview-Commit-ID: KiDjjs2qpk5
browser/extensions/shield-recipe-client/bootstrap.js
browser/extensions/shield-recipe-client/lib/CleanupManager.jsm
browser/extensions/shield-recipe-client/lib/EnvExpressions.jsm
browser/extensions/shield-recipe-client/lib/LogManager.jsm
browser/extensions/shield-recipe-client/lib/NormandyDriver.jsm
browser/extensions/shield-recipe-client/test/browser/browser_EnvExpressions.js
browser/extensions/shield-recipe-client/test/browser/browser_NormandyDriver.js
--- a/browser/extensions/shield-recipe-client/bootstrap.js
+++ b/browser/extensions/shield-recipe-client/bootstrap.js
@@ -2,26 +2,34 @@
  * 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/. */
 "use strict";
 
 const {utils: Cu} = Components;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "LogManager",
+  "resource://shield-recipe-client/lib/LogManager.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "RecipeRunner",
+  "resource://shield-recipe-client/lib/RecipeRunner.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "CleanupManager",
+  "resource://shield-recipe-client/lib/CleanupManager.jsm");
 
 const REASONS = {
   APP_STARTUP: 1,      // The application is starting up.
   APP_SHUTDOWN: 2,     // The application is shutting down.
   ADDON_ENABLE: 3,     // The add-on is being enabled.
   ADDON_DISABLE: 4,    // The add-on is being disabled. (Also sent during uninstallation)
   ADDON_INSTALL: 5,    // The add-on is being installed.
   ADDON_UNINSTALL: 6,  // The add-on is being uninstalled.
   ADDON_UPGRADE: 7,    // The add-on is being upgraded.
-  ADDON_DOWNGRADE: 8,  //The add-on is being downgraded.
+  ADDON_DOWNGRADE: 8,  // The add-on is being downgraded.
 };
 
 const PREF_BRANCH = "extensions.shield-recipe-client.";
 const DEFAULT_PREFS = {
   api_url: "https://self-repair.mozilla.org/api/v1",
   dev_mode: false,
   enabled: true,
   startup_delay_seconds: 300,
@@ -48,29 +56,25 @@ this.install = function() {
 this.startup = function() {
   setDefaultPrefs();
 
   if (!shouldRun) {
     return;
   }
 
   // Setup logging and listen for changes to logging prefs
-  Cu.import("resource://shield-recipe-client/lib/LogManager.jsm");
   LogManager.configure(Services.prefs.getIntPref(PREF_LOGGING_LEVEL));
   Preferences.observe(PREF_LOGGING_LEVEL, LogManager.configure);
+  CleanupManager.addCleanupHandler(
+    () => Preferences.ignore(PREF_LOGGING_LEVEL, LogManager.configure));
 
-  Cu.import("resource://shield-recipe-client/lib/RecipeRunner.jsm");
   RecipeRunner.init();
 };
 
 this.shutdown = function(data, reason) {
-  Preferences.ignore(PREF_LOGGING_LEVEL, LogManager.configure);
-
-  Cu.import("resource://shield-recipe-client/lib/CleanupManager.jsm");
-
   CleanupManager.cleanup();
 
   if (reason === REASONS.ADDON_DISABLE || reason === REASONS.ADDON_UNINSTALL) {
     Services.prefs.setBoolPref(PREF_SELF_SUPPORT_ENABLED, true);
   }
 
   const modules = [
     "lib/CleanupManager.jsm",
old mode 100644
new mode 100755
--- a/browser/extensions/shield-recipe-client/lib/CleanupManager.jsm
+++ b/browser/extensions/shield-recipe-client/lib/CleanupManager.jsm
@@ -1,14 +1,15 @@
 /* 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/. */
 
 "use strict";
 
+const {utils: Cu} = Components;
 this.EXPORTED_SYMBOLS = ["CleanupManager"];
 
 const cleanupHandlers = new Set();
 
 this.CleanupManager = {
   addCleanupHandler(handler) {
     cleanupHandlers.add(handler);
   },
--- a/browser/extensions/shield-recipe-client/lib/EnvExpressions.jsm
+++ b/browser/extensions/shield-recipe-client/lib/EnvExpressions.jsm
@@ -1,16 +1,17 @@
 /* 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/. */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/TelemetryArchive.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://shield-recipe-client/lib/Sampling.jsm");
 
 const {generateUUID} = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
 
 this.EXPORTED_SYMBOLS = ["EnvExpressions"];
@@ -69,19 +70,21 @@ this.EnvExpressions = {
       id = generateUUID().toString().slice(1, -1);
       prefs.setCharPref("user_id", id);
     }
     return id;
   },
 
   eval(expr, extraContext = {}) {
     // First clone the extra context
-    const context = Object.assign({}, extraContext);
+    const context = Object.assign({normandy: {}}, extraContext);
     // jexl handles promises, so it is fine to include them in this data.
     context.telemetry = EnvExpressions.getLatestTelemetry();
-    context.normandy = context.normandy || {};
-    context.normandy.userId = EnvExpressions.getUserId();
+
+    context.normandy = Object.assign(context.normandy, {
+      userId: EnvExpressions.getUserId(),
+      distribution: Preferences.get("distribution.id", "default"),
+    });
 
     const onelineExpr = expr.replace(/[\t\n\r]/g, " ");
-
     return jexl.eval(onelineExpr, context);
   },
 };
--- a/browser/extensions/shield-recipe-client/lib/LogManager.jsm
+++ b/browser/extensions/shield-recipe-client/lib/LogManager.jsm
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const {utils: Cu} = Components;
 Cu.import("resource://gre/modules/Log.jsm");
 
 this.EXPORTED_SYMBOLS = ["LogManager"];
 
-const ROOT_LOGGER_NAME = "extensions.shield-recipe-client"
+const ROOT_LOGGER_NAME = "extensions.shield-recipe-client";
 let rootLogger = null;
 
 this.LogManager = {
   /**
    * Configure the root logger for the Recipe Client. Must be called at
    * least once before using any loggers created via getLogger.
    * @param {Number} loggingLevel
    *        Logging level to use as defined in Log.jsm
--- a/browser/extensions/shield-recipe-client/lib/NormandyDriver.jsm
+++ b/browser/extensions/shield-recipe-client/lib/NormandyDriver.jsm
@@ -70,18 +70,22 @@ this.NormandyDriver = function(sandboxMa
 
     client() {
       const appinfo = {
         version: Services.appinfo.version,
         channel: Services.appinfo.defaultUpdateChannel,
         isDefaultBrowser: ShellService.isDefaultBrowser() || null,
         searchEngine: null,
         syncSetup: Preferences.isSet("services.sync.username"),
+        syncDesktopDevices: Preferences.get("services.sync.clients.devices.desktop", 0),
+        syncMobileDevices: Preferences.get("services.sync.clients.devices.mobile", 0),
+        syncTotalDevices: Preferences.get("services.sync.numClients", 0),
         plugins: {},
         doNotTrack: Preferences.get("privacy.donottrackheader.enabled", false),
+        distribution: Preferences.get("distribution.id", "default"),
       };
 
       const searchEnginePromise = new Promise(resolve => {
         Services.search.init(rv => {
           if (Components.isSuccessCode(rv)) {
             appinfo.searchEngine = Services.search.defaultEngine.identifier;
           }
           resolve();
--- a/browser/extensions/shield-recipe-client/test/browser/browser_EnvExpressions.js
+++ b/browser/extensions/shield-recipe-client/test/browser/browser_EnvExpressions.js
@@ -77,9 +77,18 @@ add_task(function* () {
   Assert.equal(val, "fake id", "userId is pulled from preferences");
 
   // test that it merges context correctly, `userId` comes from the default context, and
   // `injectedValue` comes from us. Expect both to be on the final `normandy` object.
   val = yield EnvExpressions.eval(
     "[normandy.userId, normandy.injectedValue]",
     {normandy: {injectedValue: "injected"}});
   Assert.deepEqual(val, ["fake id", "injected"], "context is correctly merged");
+
+  // distribution id defaults to "default"
+  val = yield EnvExpressions.eval("normandy.distribution");
+  Assert.equal(val, "default", "distribution has a default value");
+
+  // distribution id is in the context
+  yield SpecialPowers.pushPrefEnv({set: [["distribution.id", "funnelcake"]]});
+  val = yield EnvExpressions.eval("normandy.distribution");
+  Assert.equal(val, "funnelcake", "distribution is read from preferences");
 });
--- a/browser/extensions/shield-recipe-client/test/browser/browser_NormandyDriver.js
+++ b/browser/extensions/shield-recipe-client/test/browser/browser_NormandyDriver.js
@@ -13,8 +13,37 @@ add_task(Utils.withDriver(Assert, functi
   const uuid2 = driver.uuid();
   isnot(uuid1, uuid2, "uuids are unique");
 }));
 
 add_task(Utils.withDriver(Assert, function* userId(driver) {
   // Test that userId is a UUID
   ok(Utils.UUID_REGEX.test(driver.userId), "userId is a uuid");
 }));
+
+add_task(Utils.withDriver(Assert, function* syncDeviceCounts(driver) {
+  let client = yield driver.client();
+  is(client.syncMobileDevices, 0, "syncMobileDevices defaults to zero");
+  is(client.syncDesktopDevices, 0, "syncDesktopDevices defaults to zero");
+  is(client.syncTotalDevices, 0, "syncTotalDevices defaults to zero");
+
+  yield SpecialPowers.pushPrefEnv({
+    set: [
+      ["services.sync.numClients", 9],
+      ["services.sync.clients.devices.mobile", 5],
+      ["services.sync.clients.devices.desktop", 4],
+    ],
+  });
+
+  client = yield driver.client();
+  is(client.syncMobileDevices, 5, "syncMobileDevices is read when set");
+  is(client.syncDesktopDevices, 4, "syncDesktopDevices is read when set");
+  is(client.syncTotalDevices, 9, "syncTotalDevices is read when set");
+}));
+
+add_task(Utils.withDriver(Assert, function* distribution(driver) {
+  let client = yield driver.client();
+  is(client.distribution, "default", "distribution has a default value");
+
+  yield SpecialPowers.pushPrefEnv({set: [["distribution.id", "funnelcake"]]});
+  client = yield driver.client();
+  is(client.distribution, "funnelcake", "distribution is read from preferences");
+}));