Bug 1494781 - Include install error when reporting add-on study enroll errors r=aswan
authorMichael Cooper <mcooper@mozilla.com>
Thu, 11 Oct 2018 16:39:28 +0000
changeset 499209 6f88d27fbe44c6107ca2c9f1a7ef020ccfd900f6
parent 499208 ac0fc3f030290176619301bc08e25694a3741464
child 499210 7381bd2bb8eb974217ed0843cb808381e2aabe67
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1494781
milestone64.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 1494781 - Include install error when reporting add-on study enroll errors r=aswan Differential Revision: https://phabricator.services.mozilla.com/D7141
toolkit/components/normandy/actions/AddonStudyAction.jsm
toolkit/components/normandy/lib/TelemetryEvents.jsm
toolkit/components/normandy/test/browser/browser_actions_AddonStudyAction.js
--- a/toolkit/components/normandy/actions/AddonStudyAction.jsm
+++ b/toolkit/components/normandy/actions/AddonStudyAction.jsm
@@ -22,34 +22,40 @@ XPCOMUtils.defineLazyModuleGetters(this,
   TelemetryEvents: "resource://normandy/lib/TelemetryEvents.jsm",
 });
 
 var EXPORTED_SYMBOLS = ["AddonStudyAction"];
 
 const OPT_OUT_STUDIES_ENABLED_PREF = "app.shield.optoutstudies.enabled";
 
 class AddonStudyEnrollError extends Error {
-  constructor(studyName, reason) {
+  /**
+   * @param {string} studyName
+   * @param {object} extra Extra details to include when reporting the error to telemetry.
+   * @param {string} extra.reason The specific reason for the failure.
+   */
+  constructor(studyName, extra) {
     let message;
+    let { reason } = extra;
     switch (reason) {
       case "conflicting-addon-id": {
         message = "an add-on with this ID is already installed";
         break;
       }
       case "download-failure": {
         message = "the add-on failed to download";
         break;
       }
       default: {
         throw new Error(`Unexpected AddonStudyEnrollError reason: ${reason}`);
       }
     }
     super(new Error(`Cannot install study add-on for ${studyName}: ${message}.`));
     this.studyName = studyName;
-    this.reason = reason;
+    this.extra = extra;
   }
 }
 
 class AddonStudyAction extends BaseAction {
   get schema() {
     return ActionSchemas["addon-study"];
   }
 
@@ -141,34 +147,40 @@ class AddonStudyAction extends BaseActio
     const installDeferred = PromiseUtils.defer();
 
     const install = await AddonManager.getInstallForURL(addonUrl, "application/x-xpinstall",
                                                         null, null, null, null, null,
                                                         {source: "internal"});
 
     const listener = {
       onDownloadFailed() {
-        downloadDeferred.reject(new AddonStudyEnrollError(name, "download-failure"));
+        downloadDeferred.reject(new AddonStudyEnrollError(name, {
+          reason: "download-failure",
+          detail: AddonManager.errorToString(install.error),
+        }));
       },
 
       onDownloadEnded() {
         downloadDeferred.resolve();
         return false; // temporarily pause installation for Normandy bookkeeping
       },
 
       onInstallStarted(cbInstall) {
         if (cbInstall.existingAddon) {
-          installDeferred.reject(new AddonStudyEnrollError(name, "conflicting-addon-id"));
+          installDeferred.reject(new AddonStudyEnrollError(name, {reason: "conflicting-addon-id"}));
           return false; // cancel the installation, no upgrades allowed
         }
         return true;
       },
 
       onInstallFailed() {
-        installDeferred.reject(new AddonStudyEnrollError(name, "failed-to-install"));
+        installDeferred.reject(new AddonStudyEnrollError(name, {
+          reason: "failed-to-install",
+          detail: AddonManager.errorToString(install.error),
+        }));
       },
 
       onInstallEnded() {
         installDeferred.resolve();
       },
     };
 
     install.addListener(listener);
@@ -223,17 +235,17 @@ class AddonStudyAction extends BaseActio
     });
 
     install.removeListener(listener);
   }
 
   reportEnrollError(error) {
     if (error instanceof AddonStudyEnrollError) {
       // One of our known errors. Report it nicely to telemetry
-      TelemetryEvents.sendEvent("enrollFailed", "addon_study", error.studyName, { reason: error.reason });
+      TelemetryEvents.sendEvent("enrollFailed", "addon_study", error.studyName, error.extra);
     } else {
       /*
         * Some unknown error. Add some helpful details, and report it to
         * telemetry. The actual stack trace and error message could possibly
         * contain PII, so we don't include them here. Instead include some
         * information that should still be helpful, and is less likely to be
         * unsafe.
         */
--- a/toolkit/components/normandy/lib/TelemetryEvents.jsm
+++ b/toolkit/components/normandy/lib/TelemetryEvents.jsm
@@ -16,17 +16,17 @@ const TelemetryEvents = {
       objects: ["preference_study", "addon_study", "preference_rollout"],
       extra_keys: ["experimentType", "branch", "addonId", "addonVersion"],
       record_on_release: true,
     },
 
     enroll_failed: {
       methods: ["enrollFailed"],
       objects: ["addon_study", "preference_rollout", "preference_study"],
-      extra_keys: ["reason", "preference"],
+      extra_keys: ["reason", "preference", "detail"],
       record_on_release: true,
     },
 
     update: {
       methods: ["update"],
       objects: ["preference_rollout"],
       extra_keys: ["previousState"],
       record_on_release: true,
--- a/toolkit/components/normandy/test/browser/browser_actions_AddonStudyAction.js
+++ b/toolkit/components/normandy/test/browser/browser_actions_AddonStudyAction.js
@@ -72,17 +72,17 @@ decorate_task(
     const action = new AddonStudyAction();
     await action.enroll(recipe);
 
     const studies = await AddonStudies.getAll();
     Assert.deepEqual(studies, [], "the study should not be in the database");
 
     Assert.deepEqual(
       sendEventStub.args,
-      [["enrollFailed", "addon_study", recipe.arguments.name, {reason: "download-failure"}]],
+      [["enrollFailed", "addon_study", recipe.arguments.name, {reason: "download-failure", detail: "ERROR_NETWORK_FAILURE"}]],
       "An enrollFailed event should be sent",
     );
   }
 );
 
 // Test that in the case of a study add-on conflicting with a non-study add-on, the study does not enroll
 decorate_task(
   ensureAddonCleanup,