Bug 1497365 - send Prio-encoded data for subsessions r=janerik
authorRobert Helmer <rhelmer@mozilla.com>
Mon, 15 Oct 2018 16:52:49 +0000
changeset 489677 45a7ec8b70219b47b26eec692b17b6f7e73fc098
parent 489676 f6e9edf3db436e5dbaf2ff199f43c571e231515b
child 489678 4ccf0f4b0ef23fc71f5593ca269e625c0cca5d56
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjanerik
bugs1497365
milestone64.0a1
Bug 1497365 - send Prio-encoded data for subsessions r=janerik Differential Revision: https://phabricator.services.mozilla.com/D8300
toolkit/components/telemetry/pings/TelemetrySession.jsm
toolkit/components/telemetry/tests/unit/head.js
toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
--- a/toolkit/components/telemetry/pings/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/pings/TelemetrySession.jsm
@@ -103,16 +103,17 @@ function getMsSinceProcessStart() {
  */
 var Policy = {
   now: () => new Date(),
   monotonicNow: getMsSinceProcessStart,
   generateSessionUUID: () => generateUUID(),
   generateSubsessionUUID: () => generateUUID(),
   setSchedulerTickTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
   clearSchedulerTickTimeout: id => clearTimeout(id),
+  prioEncode: (batchID, prioParams) => PrioEncoder.encode(batchID, prioParams),
 };
 
 /**
  * Get the ping type based on the payload.
  * @param {Object} aPayload The ping payload.
  * @return {String} A string representing the ping type.
  */
 function getPingType(aPayload) {
@@ -978,17 +979,17 @@ var Impl = {
       // Add process measurements to payload.
       payloadObj.processes[processType] = processPayload;
     }
 
     payloadObj.info = info;
 
     // Collect Prio-encoded measurements.
     if (Services.prefs.getBoolPref(PRIO_ENABLED_PREF, false)) {
-      payloadObj.prio = protect(() => this._prioEncode());
+      payloadObj.prio = protect(() => this._prioEncode(payloadObj));
     }
 
     // Add extended set measurements for chrome process.
     if (Telemetry.canRecordExtended) {
       payloadObj.slowSQL = protect(() => Telemetry.slowSQL);
       payloadObj.fileIOReports = protect(() => Telemetry.fileIOReports);
       payloadObj.lateWrites = protect(() => Telemetry.lateWrites);
 
@@ -1602,45 +1603,50 @@ var Impl = {
     this._log.trace("markNewProfilePingSent");
     this._newProfilePingSent = true;
     return TelemetryStorage.saveSessionData(this._getSessionDataObject());
   },
 
   /**
    * Encodes data for experimental Prio pilot project.
    *
+   * @param {Object} measurements - measurements taken until now. Histograms will have been cleared if
+   *                 this is a subsession, so use this to get the correct values.
    * @return {Object} An object containing Prio-encoded data.
    */
-  _prioEncode() {
-    // First, map the Telemetry histogram names to the params PrioEncoder.encode() expects.
+  _prioEncode(payloadObj) {
+    // First, map the Telemetry histogram names to the params PrioEncoder expects.
     const prioEncodedHistograms = {
       "BROWSER_IS_USER_DEFAULT": "browserIsUserDefault",
       "NEWTAB_PAGE_ENABLED": "newTabPageEnabled",
       "PDF_VIEWER_USED": "pdfViewerUsed",
     };
 
     // Build list of Prio parameters, using the first value recorded in each histogram.
     let prioParams = {};
     for (const [histogramName, prioName] of Object.entries(prioEncodedHistograms)) {
       try {
-        const histogram = Telemetry.getHistogramById(histogramName);
-        const firstCount = Boolean(histogram.snapshot().sum);
-        prioParams[prioName] = firstCount;
+        if (histogramName in payloadObj.histograms) {
+          const histogram = payloadObj.histograms[histogramName];
+          prioParams[prioName] = Boolean(histogram.sum);
+        } else {
+          prioParams[prioName] = false;
+        }
 
       } catch (ex) {
         this._log.error(ex);
       }
     }
 
     // Prio encode the data and add to payload.
     const batchID = Services.appinfo.appBuildID;
 
     let prioEncodedData;
 
     try {
-      prioEncodedData = PrioEncoder.encode(batchID, prioParams);
+      prioEncodedData = Policy.prioEncode(batchID, prioParams);
     } catch (ex) {
       this._log.error(ex);
     }
 
     return prioEncodedData;
   },
 };
--- a/toolkit/components/telemetry/tests/unit/head.js
+++ b/toolkit/components/telemetry/tests/unit/head.js
@@ -284,16 +284,21 @@ function fakeGzipCompressStringForNextPi
   let send = ChromeUtils.import("resource://gre/modules/TelemetrySend.jsm", {});
   let largePayload = generateString(length);
   send.Policy.gzipCompressString = (data) => {
     send.Policy.gzipCompressString = send.gzipCompressString;
     return largePayload;
   };
 }
 
+function fakePrioEncode() {
+  const m = ChromeUtils.import("resource://gre/modules/TelemetrySession.jsm", {});
+  m.Policy.prioEncode = (batchID, prioParams) => prioParams;
+}
+
 // Return a date that is |offset| ms in the future from |date|.
 function futureDate(date, offset) {
   return new Date(date.getTime() + offset);
 }
 
 function truncateToDays(aMsec) {
   return Math.floor(aMsec / MILLISECONDS_PER_DAY);
 }
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -925,16 +925,47 @@ add_task(async function test_environment
   Assert.equal(ping.environment.settings.userPrefs[PREF_TEST], 1);
   Assert.equal(ping.payload.info.reason, REASON_ENVIRONMENT_CHANGE);
   subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
   Assert.equal(subsessionStartDate.toISOString(), startHour.toISOString());
 
   Assert.ok(!(COUNT_ID in ping.payload.histograms));
   Assert.ok(!(KEYED_ID in ping.payload.keyedHistograms));
 
+  // Trigger and collect another ping. The histograms should be reset.
+  startHour = TelemetryUtils.truncateToHours(now);
+  gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
+  now = fakeNow(futureDate(now, 10 * MILLISECONDS_PER_MINUTE));
+
+  fakePrioEncode();
+
+  // Set histograms to expected state.
+  let prioMeasures = [
+    "BROWSER_IS_USER_DEFAULT",
+    "NEWTAB_PAGE_ENABLED",
+  ];
+
+  for (let measure of prioMeasures) {
+    const value = Telemetry.getHistogramById(measure);
+    value.clear();
+    value.add(1);
+  }
+
+  let expectedPrioResult = {
+    "browserIsUserDefault": true,
+    "newTabPageEnabled": true,
+    "pdfViewerUsed": false,
+  };
+
+  Preferences.set(PREF_TEST, 3);
+  ping = await PingServer.promiseNextPing();
+  Assert.ok(!!ping);
+
+  Assert.deepEqual(ping.payload.prio, expectedPrioResult);
+
   await TelemetryController.testShutdown();
 });
 
 add_task(async function test_experimentAnnotations_subsession() {
   if (gIsAndroid) {
     // We don't split subsessions on environment changes yet on Android.
     return;
   }