Bug 841028: Add last build ID to telemetry system info if build ID has changed. r=froydnj
authorIrving Reid <irving@mozilla.com>
Mon, 18 Mar 2013 07:29:43 -0400
changeset 136422 13ddefe3068a9263384578c5c0e2931b80b16e57
parent 136421 4b69df3f802d4df7ab19f3b2cc506dab9555242c
child 136423 83cb7a59803fe38c23a3eb8fc88db9be3e49ab16
push id336
push userakeybl@mozilla.com
push dateMon, 17 Jun 2013 22:53:19 +0000
treeherdermozilla-release@574a39cdf657 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs841028
milestone22.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 841028: Add last build ID to telemetry system info if build ID has changed. r=froydnj
toolkit/components/telemetry/TelemetryPing.js
toolkit/components/telemetry/tests/unit/test_TelemetryPingBuildID.js
toolkit/components/telemetry/tests/unit/xpcshell.ini
--- a/toolkit/components/telemetry/TelemetryPing.js
+++ b/toolkit/components/telemetry/TelemetryPing.js
@@ -18,22 +18,25 @@ Cu.import("resource://gre/modules/ctypes
 
 // When modifying the payload in incompatible ways, please bump this version number
 const PAYLOAD_VERSION = 1;
 
 // This is the HG changeset of the Histogram.json file, used to associate
 // submitted ping data with its histogram definition (bug 832007)
 #expand const HISTOGRAMS_FILE_VERSION = "__HISTOGRAMS_FILE_VERSION__";
 
-const PREF_SERVER = "toolkit.telemetry.server";
+const PREF_BRANCH = "toolkit.telemetry.";
+const PREF_SERVER = PREF_BRANCH + "server";
 #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
-const PREF_ENABLED = "toolkit.telemetry.enabledPreRelease";
+const PREF_ENABLED = PREF_BRANCH + "enabledPreRelease";
 #else
-const PREF_ENABLED = "toolkit.telemetry.enabled";
+const PREF_ENABLED = PREF_BRANCH + "enabled";
 #endif
+const PREF_PREVIOUS_BUILDID = PREF_BRANCH + "previousBuildID";
+
 // Do not gather data more than once a minute
 const TELEMETRY_INTERVAL = 60000;
 // Delay before intializing telemetry (ms)
 const TELEMETRY_DELAY = 60000;
 // Delete ping files that have been lying around for longer than this.
 const MAX_PING_FILE_AGE = 7 * 24 * 60 * 60 * 1000; // 1 week
 // Constants from prio.h for nsIFileOutputStream.init
 const PR_WRONLY = 0x2;
@@ -177,16 +180,19 @@ TelemetryPing.prototype = {
   _pingLoadsCompleted: 0,
   _savedProfileDirectory: null,
   // Saving pings for later consumption is done in two parts: one part
   // saves a minimal amount of information in these variables.  Said
   // information will not be available later on.  The second part
   // handles retrieving histograms and writing the data to disk.
   _savedSimpleMeasurements: null,
   _savedInfo: null,
+  // The previous build ID, if this is the first run with a new build.
+  // Undefined if this is not the first run, or the previous build ID is unknown.
+  _previousBuildID: undefined,
 
   /**
    * Gets a series of simple measurements (counters). At the moment, this
    * only returns startup data from nsIAppStartup.getStartupInfo().
    * 
    * @return simple measurements as a dictionary.
    */
   getSimpleMeasurements: function getSimpleMeasurements(forSavedSession) {
@@ -380,16 +386,19 @@ TelemetryPing.prototype = {
       appVersion: ai.version,
       appName: ai.name,
       appBuildID: ai.appBuildID,
       appUpdateChannel: UpdateChannel.get(),
       platformBuildID: ai.platformBuildID,
       revision: HISTOGRAMS_FILE_VERSION,
       locale: getLocale()
     };
+    if (this._previousBuildID) {
+      ret.previousBuildID = this._previousBuildID;
+    }
 
     // sysinfo fields are not always available, get what we can.
     let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
     let fields = ["cpucount", "memsize", "arch", "version", "kernel_version",
                   "device", "manufacturer", "hardware",
                   "hasMMX", "hasSSE", "hasSSE2", "hasSSE3",
                   "hasSSSE3", "hasSSE4A", "hasSSE4_1", "hasSSE4_2",
                   "hasEDSP", "hasARMv6", "hasARMv7", "hasNEON", "isWow64"];
@@ -748,16 +757,32 @@ TelemetryPing.prototype = {
       this._isIdleObserver = false;
     }
   },
 
   /**
    * Initializes telemetry within a timer. If there is no PREF_SERVER set, don't turn on telemetry.
    */
   setup: function setup() {
+    // Record old value and update build ID preference if this is the first
+    // run with a new build ID.
+    let previousBuildID = undefined;
+    try {
+      previousBuildID = Services.prefs.getCharPref(PREF_PREVIOUS_BUILDID);
+    } catch (e) {
+      // Preference was not set.
+    }
+    let thisBuildID = Services.appinfo.appBuildID;
+    // If there is no previousBuildID preference, this._previousBuildID remains
+    // undefined so no value is sent in the telemetry metadata.
+    if (previousBuildID != thisBuildID) {
+      this._previousBuildID = previousBuildID;
+      Services.prefs.setCharPref(PREF_PREVIOUS_BUILDID, thisBuildID);
+    }
+
 #ifdef MOZILLA_OFFICIAL
     if (!Telemetry.canSend) {
       // We can't send data; no point in initializing observers etc.
       // Only do this for official builds so that e.g. developer builds
       // still enable Telemetry based on prefs.
       Telemetry.canRecord = false;
       return;
     }
new file mode 100644
--- /dev/null
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryPingBuildID.js
@@ -0,0 +1,73 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/
+*/
+/* Test inclusion of previous build ID in telemetry pings when build ID changes.
+ * bug 841028
+ *
+ * Cases to cover:
+ * 1) Run with no "previousBuildID" stored in prefs:
+ *     -> no previousBuildID in telemetry system info, new value set in prefs.
+ * 2) previousBuildID in prefs, equal to current build ID:
+ *     -> no previousBuildID in telemetry, prefs not updated.
+ * 3) previousBuildID in prefs, not equal to current build ID:
+ *     -> previousBuildID in telemetry, new value set in prefs.
+ */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+// Get the TelemetryPing definitions directly so we can test it without going through xpcom.
+Services.scriptloader.loadSubScript("resource://gre/components/TelemetryPing.js");
+
+// Force the Telemetry enabled preference so that TelemetryPing.setup() doesn't exit early.
+Services.prefs.setBoolPref(PREF_ENABLED, true);
+
+// Set up our dummy AppInfo object so we can control the appBuildID.
+Cu.import("resource://testing-common/AppInfo.jsm");
+updateAppInfo();
+
+// Check that when run with no previous build ID stored, we update the pref but do not
+// put anything into the metadata.
+function testFirstRun() {
+  let ping = new TelemetryPing();
+  ping.setup();
+  let metadata = ping.getMetadata();
+  do_check_false("previousBuildID" in metadata);
+  let appBuildID = getAppInfo().appBuildID;
+  let buildIDPref = Services.prefs.getCharPref(PREF_PREVIOUS_BUILDID);
+  do_check_eq(appBuildID, buildIDPref);
+}
+
+// Check that a subsequent run with the same build ID does not put prev build ID in
+// metadata. Assumes testFirstRun() has already been called to set the previousBuildID pref.
+function testSecondRun() {
+  let ping = new TelemetryPing();
+  ping.setup();
+  let metadata = ping.getMetadata();
+  do_check_false("previousBuildID" in metadata);
+}
+
+
+// Set up telemetry with a different app build ID and check that the old build ID
+// is returned in the metadata and the pref is updated to the new build ID.
+// Assumes testFirstRun() has been called to set the previousBuildID pref.
+const NEW_BUILD_ID = "20130314";
+function testNewBuild() {
+  let info = getAppInfo();
+  let oldBuildID = info.appBuildID;
+  info.appBuildID = NEW_BUILD_ID;
+  let ping = new TelemetryPing();
+  ping.setup();
+  let metadata = ping.getMetadata();
+  do_check_eq(metadata.previousBuildID, oldBuildID);
+  let buildIDPref = Services.prefs.getCharPref(PREF_PREVIOUS_BUILDID);
+  do_check_eq(NEW_BUILD_ID, buildIDPref);
+}
+
+
+function run_test() {
+  // Make sure we have a profile directory.
+  do_get_profile();
+  testFirstRun();
+  testSecondRun();
+  testNewBuild();
+}
--- a/toolkit/components/telemetry/tests/unit/xpcshell.ini
+++ b/toolkit/components/telemetry/tests/unit/xpcshell.ini
@@ -3,8 +3,9 @@ head =
 tail = 
 
 [test_nsITelemetry.js]
 [test_TelemetryPing.js]
 # Bug 676989: test fails consistently on Android
 # fail-if = os == "android"
 [test_TelemetryPing_idle.js]
 [test_TelemetryStopwatch.js]
+[test_TelemetryPingBuildID.js]