bug 1232222 - provide telemetry environment data on which addons are system addons r=gfritzsche draft
authorRobert Helmer <rhelmer@mozilla.com>
Mon, 25 Jan 2016 14:19:52 -0800
changeset 330719 17ae87a1972ae66500764bd7fb0a0cb9e24fe2b4
parent 330718 94e0c85c346a7b9e1ddd7bd272775c4131b12741
child 514221 46f0f0a3b3a3a3331ae7da44b635437ac5b8df95
push id10809
push userrhelmer@mozilla.com
push dateFri, 12 Feb 2016 17:46:29 +0000
reviewersgfritzsche
bugs1232222
milestone47.0a1
bug 1232222 - provide telemetry environment data on which addons are system addons r=gfritzsche MozReview-Commit-ID: 89M0HnzfIrd
toolkit/components/telemetry/TelemetryEnvironment.jsm
toolkit/components/telemetry/docs/environment.rst
toolkit/components/telemetry/tests/unit/head.js
toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
toolkit/components/telemetry/tests/unit/xpcshell.ini
--- a/toolkit/components/telemetry/TelemetryEnvironment.jsm
+++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm
@@ -535,16 +535,17 @@ EnvironmentAddonBuilder.prototype = {
           version: limitStringToLength(addon.version, MAX_ADDON_STRING_LENGTH),
           scope: addon.scope,
           type: addon.type,
           foreignInstall: addon.foreignInstall,
           hasBinaryComponents: addon.hasBinaryComponents,
           installDay: Utils.millisecondsToDays(installDate.getTime()),
           updateDay: Utils.millisecondsToDays(updateDate.getTime()),
           signedState: addon.signedState,
+          isSystem: addon.isSystem,
         };
 
         if (addon.signedState !== undefined)
           activeAddons[addon.id].signedState = addon.signedState;
 
       } catch (ex) {
         this._environment._log.error("_getActiveAddons - An addon was discarded due to an error", ex);
         continue;
--- a/toolkit/components/telemetry/docs/environment.rst
+++ b/toolkit/components/telemetry/docs/environment.rst
@@ -190,16 +190,17 @@ Structure::
             version: <string>,
             scope: <integer>,
             type: <string>, // "extension", "service", ...
             foreignInstall: <bool>,
             hasBinaryComponents: <bool>
             installDay: <number>, // days since UNIX epoch, 0 on failure
             updateDay: <number>, // days since UNIX epoch, 0 on failure
             signedState: <integer>, // whether the add-on is signed by AMO, only present for extensions
+            isSystem: <bool>, // true if this is a System Add-on
           },
           ...
         },
         theme: { // the active theme
           id: <string>,
           blocklisted: <bool>,
           description: <string>,
           name: <string>,
--- a/toolkit/components/telemetry/tests/unit/head.js
+++ b/toolkit/components/telemetry/tests/unit/head.js
@@ -161,16 +161,20 @@ function wrapWithExceptionHandler(f) {
 function loadAddonManager(id, name, version, platformVersion) {
   let ns = {};
   Cu.import("resource://gre/modules/Services.jsm", ns);
   let head = "../../../../mozapps/extensions/test/xpcshell/head_addons.js";
   let file = do_get_file(head);
   let uri = ns.Services.io.newFileURI(file);
   ns.Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
   createAppInfo(id, name, version, platformVersion);
+  // As we're not running in application, we need to setup the features directory
+  // used by system add-ons.
+  const distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "app0"], true);
+  registerDirectory("XREAppFeat", distroDir);
   startupManager();
 }
 
 function createAppInfo(id, name, version, platformVersion) {
   const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
   const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
   let gAppInfo;
   if (!gOldAppInfo) {
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -4,16 +4,17 @@
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/TelemetryEnvironment.jsm", this);
 Cu.import("resource://gre/modules/Preferences.jsm", this);
 Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
 Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
 Cu.import("resource://testing-common/AddonManagerTesting.jsm");
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource://testing-common/MockRegistrar.jsm", this);
+Cu.import("resource://gre/modules/FileUtils.jsm");
 
 // Lazy load |LightweightThemeManager|, we won't be using it on Gonk.
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge",
                                   "resource://gre/modules/ProfileAge.jsm");
 
@@ -62,16 +63,19 @@ const PLUGIN2_VERSION = "2.3";
 const PERSONA_ID = "3785";
 // Defined by LightweightThemeManager, it is appended to the PERSONA_ID.
 const PERSONA_ID_SUFFIX = "@personas.mozilla.org";
 const PERSONA_NAME = "Test Theme";
 const PERSONA_DESCRIPTION = "A nice theme/persona description.";
 
 const PLUGIN_UPDATED_TOPIC     = "plugins-list-updated";
 
+// system add-ons are enabled at startup, so record date when the test starts
+const SYSTEM_ADDON_INSTALL_DATE = Date.now();
+
 /**
  * Used to mock plugin tags in our fake plugin host.
  */
 function PluginTag(aName, aDescription, aVersion, aEnabled) {
   this.name = aName;
   this.description = aDescription;
   this.version = aVersion;
   this.disabled = !aEnabled;
@@ -566,29 +570,35 @@ function checkSystemSection(data) {
 
     let features = gfxInfo.getFeatures();
     Assert.equal(features.compositor, gfxData.features.compositor);
   }
   catch (e) {}
 }
 
 function checkActiveAddon(data){
+  let signedState = mozinfo.addon_signing ? "number" : "undefined";
+  // system add-ons have an undefined signState
+  if (data.isSystem)
+    signedState = "undefined";
+
   const EXPECTED_ADDON_FIELDS_TYPES = {
     blocklisted: "boolean",
     name: "string",
     userDisabled: "boolean",
     appDisabled: "boolean",
     version: "string",
     scope: "number",
     type: "string",
     foreignInstall: "boolean",
     hasBinaryComponents: "boolean",
     installDay: "number",
     updateDay: "number",
-    signedState: mozinfo.addon_signing ? "number" : "undefined",
+    signedState: signedState,
+    isSystem: "boolean",
   };
 
   for (let f in EXPECTED_ADDON_FIELDS_TYPES) {
     Assert.ok(f in data, f + " must be available.");
     Assert.equal(typeof data[f], EXPECTED_ADDON_FIELDS_TYPES[f],
                  f + " must have the correct type.");
   }
 
@@ -710,16 +720,23 @@ function checkEnvironmentData(data, isIn
 }
 
 function run_test() {
   // Load a custom manifest to provide search engine loading from JAR files.
   do_load_manifest("chrome.manifest");
   do_test_pending();
   spoofGfxAdapter();
   do_get_profile();
+
+  // The system add-on must be installed before AddonManager is started.
+  const distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "app0"], true);
+  do_get_file("system.xpi").copyTo(distroDir, "tel-system-xpi@tests.mozilla.org.xpi");
+  let system_addon = FileUtils.File(distroDir.path);
+  system_addon.append("tel-system-xpi@tests.mozilla.org.xpi");
+  system_addon.lastModifiedTime = SYSTEM_ADDON_INSTALL_DATE;
   loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
 
   // Spoof the persona ID, but not on Gonk.
   if (!gIsGonk) {
     LightweightThemeManager.currentTheme =
       spoofTheme(PERSONA_ID, PERSONA_NAME, PERSONA_DESCRIPTION);
   }
   // Register a fake plugin host for consistent flash version data.
@@ -1011,16 +1028,34 @@ add_task(function* test_addonsAndPlugins
     version: "1.0",
     scope: 1,
     type: "extension",
     foreignInstall: false,
     hasBinaryComponents: false,
     installDay: ADDON_INSTALL_DATE,
     updateDay: ADDON_INSTALL_DATE,
     signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED,
+    isSystem: false,
+  };
+  const SYSTEM_ADDON_ID = "tel-system-xpi@tests.mozilla.org";
+  const EXPECTED_SYSTEM_ADDON_DATA = {
+    blocklisted: false,
+    description: "A system addon which is shipped with Firefox.",
+    name: "XPI Telemetry System Add-on Test",
+    userDisabled: false,
+    appDisabled: false,
+    version: "1.0",
+    scope: 1,
+    type: "extension",
+    foreignInstall: false,
+    hasBinaryComponents: false,
+    installDay: truncateToDays(SYSTEM_ADDON_INSTALL_DATE),
+    updateDay: truncateToDays(SYSTEM_ADDON_INSTALL_DATE),
+    signedState: undefined,
+    isSystem: true,
   };
 
   const EXPECTED_PLUGIN_DATA = {
     name: FLASH_PLUGIN_NAME,
     version: FLASH_PLUGIN_VERSION,
     description: FLASH_PLUGIN_DESC,
     blocklisted: false,
     disabled: false,
@@ -1035,16 +1070,23 @@ add_task(function* test_addonsAndPlugins
 
   // Check addon data.
   Assert.ok(ADDON_ID in data.addons.activeAddons, "We must have one active addon.");
   let targetAddon = data.addons.activeAddons[ADDON_ID];
   for (let f in EXPECTED_ADDON_DATA) {
     Assert.equal(targetAddon[f], EXPECTED_ADDON_DATA[f], f + " must have the correct value.");
   }
 
+  // Check system add-on data.
+  Assert.ok(SYSTEM_ADDON_ID in data.addons.activeAddons, "We must have one active system addon.");
+  let targetSystemAddon = data.addons.activeAddons[SYSTEM_ADDON_ID];
+  for (let f in EXPECTED_SYSTEM_ADDON_DATA) {
+    Assert.equal(targetSystemAddon[f], EXPECTED_SYSTEM_ADDON_DATA[f], f + " must have the correct value.");
+  }
+
   // Check theme data.
   let theme = data.addons.theme;
   Assert.equal(theme.id, (PERSONA_ID + PERSONA_ID_SUFFIX));
   Assert.equal(theme.name, PERSONA_NAME);
   Assert.equal(theme.description, PERSONA_DESCRIPTION);
 
   // Check plugin data.
   Assert.equal(data.addons.activePlugins.length, 1, "We must have only one active plugin.");
--- a/toolkit/components/telemetry/tests/unit/xpcshell.ini
+++ b/toolkit/components/telemetry/tests/unit/xpcshell.ini
@@ -7,23 +7,25 @@ skip-if = toolkit == 'gonk'
 # xpcshell fails to install tests if we move them under the test entry.
 support-files =
   ../search/chrome.manifest
   ../search/searchTest.jar
   dictionary.xpi
   experiment.xpi
   extension.xpi
   extension-2.xpi
+  system.xpi
   restartless.xpi
   theme.xpi
 generated-files =
   dictionary.xpi
   experiment.xpi
   extension.xpi
   extension-2.xpi
+  system.xpi
   restartless.xpi
   theme.xpi
 
 [test_nsITelemetry.js]
 [test_SubsessionChaining.js]
 tags = addons
 [test_TelemetryEnvironment.js]
 skip-if = os == "android"