Backed out 5 changesets (bug 1316281, bug 1316810) for ASan failures in UsageTelemetry tests
authorPhil Ringnalda <philringnalda@gmail.com>
Thu, 01 Dec 2016 07:46:00 -0800
changeset 325028 dd01d903f823c089789b30c7f95d4da80e5e6162
parent 325027 9e5cd2bf4d66a602b934235f9071ff2247a66d94
child 325029 1464a199a2a568b8a9259dba6fe7933833254517
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
bugs1316281, 1316810
milestone53.0a1
backs out2c711bb8e3738cc21e509df3c9aaf66071a4712c
b3ea1334c33a48a50c21daf6150cf51651b1d16f
823e118b3fad7539b0fc64202535ed3cbde2c634
84e97301a8c94aaa7279c624576983f3f3cac60f
f98ddece4b12d3129bc8875830eb59f8452683a8
Backed out 5 changesets (bug 1316281, bug 1316810) for ASan failures in UsageTelemetry tests Backed out changeset 2c711bb8e373 (bug 1316281) Backed out changeset b3ea1334c33a (bug 1316281) Backed out changeset 823e118b3fad (bug 1316281) Backed out changeset 84e97301a8c9 (bug 1316810) Backed out changeset f98ddece4b12 (bug 1316810) MozReview-Commit-ID: 5tR2v8NWxQW
browser/modules/BrowserUsageTelemetry.jsm
browser/modules/test/browser_UsageTelemetry_content.js
browser/modules/test/browser_UsageTelemetry_content_aboutHome.js
browser/modules/test/browser_UsageTelemetry_searchbar.js
browser/modules/test/browser_UsageTelemetry_urlbar.js
browser/modules/test/head.js
toolkit/components/telemetry/Events.yaml
toolkit/components/telemetry/TelemetryEvent.cpp
toolkit/components/telemetry/TelemetrySession.jsm
toolkit/components/telemetry/parse_events.py
toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js
toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
--- a/browser/modules/BrowserUsageTelemetry.jsm
+++ b/browser/modules/BrowserUsageTelemetry.jsm
@@ -288,91 +288,88 @@ let BrowserUsageTelemetry = {
     } else {
       if (!KNOWN_SEARCH_SOURCES.includes(source)) {
         throw new Error("Unknown source for search: " + source);
       }
       Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").add(countId);
     }
 
     // Dispatch the search signal to other handlers.
-    this._handleSearchAction(engine, source, details);
+    this._handleSearchAction(source, details);
   },
 
-  _recordSearch(engine, source, action = null) {
-    let scalarKey = action ? "search_" + action : "search";
-    Services.telemetry.keyedScalarAdd("browser.engagement.navigation." + source,
-                                      scalarKey, 1);
-    Services.telemetry.recordEvent("navigation", "search", source, action,
-                                   { engine: getSearchEngineId(engine) });
-  },
-
-  _handleSearchAction(engine, source, details) {
+  _handleSearchAction(source, details) {
     switch (source) {
       case "urlbar":
       case "oneoff-urlbar":
       case "searchbar":
       case "oneoff-searchbar":
       case "unknown": // Edge case: this is the searchbar (see bug 1195733 comment 7).
-        this._handleSearchAndUrlbar(engine, source, details);
+        this._handleSearchAndUrlbar(source, details);
         break;
       case "abouthome":
-        this._recordSearch(engine, "about_home", "enter");
+        Services.telemetry.keyedScalarAdd("browser.engagement.navigation.about_home",
+                                          "search_enter", 1);
         break;
       case "newtab":
-        this._recordSearch(engine, "about_newtab", "enter");
+        Services.telemetry.keyedScalarAdd("browser.engagement.navigation.about_newtab",
+                                          "search_enter", 1);
         break;
       case "contextmenu":
-        this._recordSearch(engine, "contextmenu");
+        Services.telemetry.keyedScalarAdd("browser.engagement.navigation.contextmenu",
+                                          "search", 1);
         break;
     }
   },
 
   /**
    * This function handles the "urlbar", "urlbar-oneoff", "searchbar" and
    * "searchbar-oneoff" sources.
    */
-  _handleSearchAndUrlbar(engine, source, details) {
+  _handleSearchAndUrlbar(source, details) {
     // We want "urlbar" and "urlbar-oneoff" (and similar cases) to go in the same
     // scalar, but in a different key.
 
     // When using one-offs in the searchbar we get an "unknown" source. See bug
     // 1195733 comment 7 for the context. Fix-up the label here.
-    const sourceName =
+    const plainSourceName =
       (source === "unknown") ? "searchbar" : source.replace("oneoff-", "");
+    const scalarName = "browser.engagement.navigation." + plainSourceName;
 
     const isOneOff = !!details.isOneOff;
     if (isOneOff) {
       // We will receive a signal from the "urlbar"/"searchbar" even when the
       // search came from "oneoff-urlbar". That's because both signals
       // are propagated from search.xml. Skip it if that's the case.
       // Moreover, we skip the "unknown" source that comes from the searchbar
       // when performing searches from the default search engine. See bug 1195733
       // comment 7 for context.
       if (["urlbar", "searchbar", "unknown"].includes(source)) {
         return;
       }
 
-      // If that's a legit one-off search signal, record it using the relative key.
-      this._recordSearch(engine, sourceName, "oneoff");
+      // If that's a legit one-off search signal, increment the scalar using the
+      // relative key.
+      Services.telemetry.keyedScalarAdd(scalarName, "search_oneoff", 1);
       return;
     }
 
     // The search was not a one-off. It was a search with the default search engine.
     if (details.isSuggestion) {
       // It came from a suggested search, so count it as such.
-      this._recordSearch(engine, sourceName, "suggestion");
+      Services.telemetry.keyedScalarAdd(scalarName, "search_suggestion", 1);
       return;
     } else if (details.isAlias) {
       // This one came from a search that used an alias.
-      this._recordSearch(engine, sourceName, "alias");
+      Services.telemetry.keyedScalarAdd(scalarName, "search_alias", 1);
       return;
     }
 
     // The search signal was generated by typing something and pressing enter.
-    this._recordSearch(engine, sourceName, "enter");
+    Services.telemetry.keyedScalarAdd(scalarName, "search_enter", 1);
   },
 
   /**
    * This gets called shortly after the SessionStore has finished restoring
    * windows and tabs. It counts the open tabs and adds listeners to all the
    * windows.
    */
   _setupAfterRestore() {
--- a/browser/modules/test/browser_UsageTelemetry_content.js
+++ b/browser/modules/test/browser_UsageTelemetry_content.js
@@ -32,19 +32,18 @@ add_task(function* setup() {
   registerCleanupFunction(function* () {
     Services.search.currentEngine = originalEngine;
     Services.search.removeEngine(engineDefault);
     Services.search.removeEngine(engineOneOff);
   });
 });
 
 add_task(function* test_context_menu() {
-  // Let's reset the Telemetry data.
+  // Let's reset the counts.
   Services.telemetry.clearScalars();
-  Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
 
   // Open a new tab with a page containing some text.
   let tab =
     yield BrowserTestUtils.openNewForegroundTab(gBrowser, "data:text/plain;charset=utf8,test%20search");
 
   info("Select all the text in the page.");
   yield ContentTask.spawn(tab.linkedBrowser, "", function*() {
@@ -60,40 +59,34 @@ add_task(function* test_context_menu() {
   BrowserTestUtils.synthesizeMouseAtCenter("body", { type: "contextmenu", button: 2 },
                                            gBrowser.selectedBrowser);
   yield popupPromise;
 
   info("Click on search.");
   let searchItem = contextMenu.getElementsByAttribute("id", "context-searchselect")[0];
   searchItem.click();
 
-  info("Validate the search metrics.");
+  info("Validate the search counts.");
   const scalars =
     Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
   checkKeyedScalar(scalars, SCALAR_CONTEXT_MENU, "search", 1);
   Assert.equal(Object.keys(scalars[SCALAR_CONTEXT_MENU]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   checkKeyedHistogram(search_hist, 'other-MozSearch.contextmenu', 1);
 
-  // Also check events.
-  let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = events.filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "contextmenu", null, {engine: "other-MozSearch"}]]);
-
   contextMenu.hidePopup();
   yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
   yield BrowserTestUtils.removeTab(tab);
 });
 
 add_task(function* test_about_newtab() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
-  Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
 
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:newtab", false);
   yield ContentTask.spawn(tab.linkedBrowser, null, function* () {
     yield ContentTaskUtils.waitForCondition(() => !content.document.hidden);
   });
 
   info("Trigger a simple serch, just text + enter.");
@@ -107,15 +100,10 @@ add_task(function* test_about_newtab() {
     Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
   checkKeyedScalar(scalars, SCALAR_ABOUT_NEWTAB, "search_enter", 1);
   Assert.equal(Object.keys(scalars[SCALAR_ABOUT_NEWTAB]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   checkKeyedHistogram(search_hist, 'other-MozSearch.newtab', 1);
 
-  // Also check events.
-  let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = events.filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "about_newtab", "enter", {engine: "other-MozSearch"}]]);
-
   yield BrowserTestUtils.removeTab(tab);
 });
--- a/browser/modules/test/browser_UsageTelemetry_content_aboutHome.js
+++ b/browser/modules/test/browser_UsageTelemetry_content_aboutHome.js
@@ -36,17 +36,16 @@ add_task(function* setup() {
     Services.search.removeEngine(engineDefault);
     Services.search.removeEngine(engineOneOff);
   });
 });
 
 add_task(function* test_abouthome_simpleQuery() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
-  Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
 
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
 
   info("Setup waiting for AboutHomeLoadSnippetsCompleted.");
   let promiseAboutHomeLoaded = new Promise(resolve => {
     tab.linkedBrowser.addEventListener("AboutHomeLoadSnippetsCompleted", function loadListener(event) {
       tab.linkedBrowser.removeEventListener("AboutHomeLoadSnippetsCompleted", loadListener, true);
@@ -70,15 +69,10 @@ add_task(function* test_abouthome_simple
     Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
   checkKeyedScalar(scalars, SCALAR_ABOUT_HOME, "search_enter", 1);
   Assert.equal(Object.keys(scalars[SCALAR_ABOUT_HOME]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   checkKeyedHistogram(search_hist, 'other-MozSearch.abouthome', 1);
 
-  // Also check events.
-  let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = events.filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "about_home", "enter", {engine: "other-MozSearch"}]]);
-
   yield BrowserTestUtils.removeTab(tab);
 });
--- a/browser/modules/test/browser_UsageTelemetry_searchbar.js
+++ b/browser/modules/test/browser_UsageTelemetry_searchbar.js
@@ -76,17 +76,16 @@ add_task(function* setup() {
     Services.search.removeEngine(engineDefault);
     Services.search.removeEngine(engineOneOff);
   });
 });
 
 add_task(function* test_plainQuery() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
-  Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
 
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
   info("Simulate entering a simple search.");
   let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   yield searchInSearchbar("simple query");
   EventUtils.sendKey("return");
@@ -97,28 +96,22 @@ add_task(function* test_plainQuery() {
     Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
   checkKeyedScalar(scalars, SCALAR_SEARCHBAR, "search_enter", 1);
   Assert.equal(Object.keys(scalars[SCALAR_SEARCHBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   checkKeyedHistogram(search_hist, 'other-MozSearch.searchbar', 1);
 
-  // Also check events.
-  let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = events.filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "searchbar", "enter", {engine: "other-MozSearch"}]]);
-
   yield BrowserTestUtils.removeTab(tab);
 });
 
 add_task(function* test_oneOff() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
-  Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
 
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
   info("Perform a one-off search using the first engine.");
   let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   yield searchInSearchbar("query");
 
@@ -132,28 +125,22 @@ add_task(function* test_oneOff() {
     Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
   checkKeyedScalar(scalars, SCALAR_SEARCHBAR, "search_oneoff", 1);
   Assert.equal(Object.keys(scalars[SCALAR_SEARCHBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   checkKeyedHistogram(search_hist, 'other-MozSearch2.searchbar', 1);
 
-  // Also check events.
-  let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = events.filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "searchbar", "oneoff", {engine: "other-MozSearch2"}]]);
-
   yield BrowserTestUtils.removeTab(tab);
 });
 
 add_task(function* test_suggestion() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
-  Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
 
   // Create an engine to generate search suggestions and add it as default
   // for this test.
   const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml";
   let suggestionEngine = yield new Promise((resolve, reject) => {
     Services.search.addEngine(url, null, "", false, {
       onSuccess(engine) { resolve(engine) },
@@ -176,20 +163,14 @@ add_task(function* test_suggestion() {
   // Check if the scalars contain the expected values.
   const scalars =
     Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
   checkKeyedScalar(scalars, SCALAR_SEARCHBAR, "search_suggestion", 1);
   Assert.equal(Object.keys(scalars[SCALAR_SEARCHBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
-  let searchEngineId = 'other-' + suggestionEngine.name;
-  checkKeyedHistogram(search_hist, searchEngineId + '.searchbar', 1);
-
-  // Also check events.
-  let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = events.filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "searchbar", "suggestion", {engine: searchEngineId}]]);
+  checkKeyedHistogram(search_hist, 'other-' + suggestionEngine.name + '.searchbar', 1);
 
   Services.search.currentEngine = previousEngine;
   Services.search.removeEngine(suggestionEngine);
   yield BrowserTestUtils.removeTab(tab);
 });
--- a/browser/modules/test/browser_UsageTelemetry_urlbar.js
+++ b/browser/modules/test/browser_UsageTelemetry_urlbar.js
@@ -69,17 +69,16 @@ add_task(function* setup() {
     Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF, true);
     Services.prefs.clearUserPref(ONEOFF_URLBAR_PREF);
   });
 });
 
 add_task(function* test_simpleQuery() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
-  Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
 
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
   info("Simulate entering a simple search.");
   let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   yield searchInAwesomebar("simple query");
   EventUtils.sendKey("return");
@@ -90,28 +89,22 @@ add_task(function* test_simpleQuery() {
     Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
   checkKeyedScalar(scalars, SCALAR_URLBAR, "search_enter", 1);
   Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   checkKeyedHistogram(search_hist, 'other-MozSearch.urlbar', 1);
 
-  // Also check events.
-  let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = events.filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "urlbar", "enter", {engine: "other-MozSearch"}]]);
-
   yield BrowserTestUtils.removeTab(tab);
 });
 
 add_task(function* test_searchAlias() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
-  Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
 
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
   info("Search using a search alias.");
   let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   yield searchInAwesomebar("mozalias query");
   EventUtils.sendKey("return");
@@ -122,28 +115,22 @@ add_task(function* test_searchAlias() {
     Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
   checkKeyedScalar(scalars, SCALAR_URLBAR, "search_alias", 1);
   Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   checkKeyedHistogram(search_hist, 'other-MozSearch.urlbar', 1);
 
-  // Also check events.
-  let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = events.filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "urlbar", "alias", {engine: "other-MozSearch"}]]);
-
   yield BrowserTestUtils.removeTab(tab);
 });
 
 add_task(function* test_oneOff() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
-  Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
 
   let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
 
   info("Perform a one-off search using the first engine.");
   let p = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   yield searchInAwesomebar("query");
 
@@ -157,28 +144,22 @@ add_task(function* test_oneOff() {
     Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
   checkKeyedScalar(scalars, SCALAR_URLBAR, "search_oneoff", 1);
   Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
   checkKeyedHistogram(search_hist, 'other-MozSearch.urlbar', 1);
 
-  // Also check events.
-  let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = events.filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "urlbar", "oneoff", {engine: "other-MozSearch"}]]);
-
   yield BrowserTestUtils.removeTab(tab);
 });
 
 add_task(function* test_suggestion() {
   // Let's reset the counts.
   Services.telemetry.clearScalars();
-  Services.telemetry.clearEvents();
   let search_hist = getSearchCountsHistogram();
 
   // Create an engine to generate search suggestions and add it as default
   // for this test.
   const url = getRootDirectory(gTestPath) + "usageTelemetrySearchSuggestions.xml";
   let suggestionEngine = yield new Promise((resolve, reject) => {
     Services.search.addEngine(url, null, "", false, {
       onSuccess(engine) { resolve(engine) },
@@ -201,20 +182,14 @@ add_task(function* test_suggestion() {
   // Check if the scalars contain the expected values.
   const scalars =
     Services.telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
   checkKeyedScalar(scalars, SCALAR_URLBAR, "search_suggestion", 1);
   Assert.equal(Object.keys(scalars[SCALAR_URLBAR]).length, 1,
                "This search must only increment one entry in the scalar.");
 
   // Make sure SEARCH_COUNTS contains identical values.
-  let searchEngineId = 'other-' + suggestionEngine.name;
-  checkKeyedHistogram(search_hist, searchEngineId + '.urlbar', 1);
-
-  // Also check events.
-  let events = Services.telemetry.snapshotBuiltinEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
-  events = events.filter(e => e[1] == "navigation" && e[2] == "search");
-  checkEvents(events, [["navigation", "search", "urlbar", "suggestion", {engine: searchEngineId}]]);
+  checkKeyedHistogram(search_hist, 'other-' + suggestionEngine.name + '.urlbar', 1);
 
   Services.search.currentEngine = previousEngine;
   Services.search.removeEngine(suggestionEngine);
   yield BrowserTestUtils.removeTab(tab);
 });
--- a/browser/modules/test/head.js
+++ b/browser/modules/test/head.js
@@ -90,19 +90,8 @@ function getSearchCountsHistogram() {
 /**
  * Check that the keyed histogram contains the right value.
  */
 function checkKeyedHistogram(h, key, expectedValue) {
   const snapshot = h.snapshot();
   Assert.ok(key in snapshot, `The histogram must contain ${key}.`);
   Assert.equal(snapshot[key].sum, expectedValue, `The key ${key} must contain ${expectedValue}.`);
 }
-
-function checkEvents(events, expectedEvents) {
-  Assert.equal(events.length, expectedEvents.length, "Should have matching amount of events.");
-
-  // Strip timestamps from the events for easier comparison.
-  events = events.map(e => e.slice(1));
-
-  for (let i = 0; i < events.length; ++i) {
-    Assert.deepEqual(events[i], expectedEvents[i], "Events should match.");
-  }
-}
--- a/toolkit/components/telemetry/Events.yaml
+++ b/toolkit/components/telemetry/Events.yaml
@@ -1,57 +1,42 @@
-navigation:
-- methods: ["search"]
-  objects: ["about_home", "about_newtab", "contextmenu", "oneoff",
-            "suggestion", "alias", "enter", "searchbar", "urlbar"]
-  release_channel_collection: opt-in
-  description: >
-    This is recorded on each search navigation.
-    The value field records the action used to trigger the search:
-      "enter", "oneoff", "suggestion", "alias", null (for contextmenu)
-  bug_numbers: [1316281]
-  notification_emails: ["past@mozilla.com"]
-  expiry_version: "58.0"
-  extra_keys:
-    engine: The id of the search engine used.
-
 # This category contains event entries used for Telemetry tests.
 # They will not be sent out with any pings.
 telemetry.test:
 - methods: ["test1", "test2"]
   objects: ["object1", "object2"]
   bug_numbers: [1286606]
   notification_emails: ["telemetry-client-dev@mozilla.com"]
   description: This is a test entry for Telemetry.
   expiry_date: never
   extra_keys:
     key1: This is just a test description.
     key2: This is another test description.
-- methods: ["optout"]
+- methods: ["test_optout"]
   objects: ["object1", "object2"]
   bug_numbers: [1286606]
   notification_emails: ["telemetry-client-dev@mozilla.com"]
   description: This is an opt-out test entry.
   expiry_date: never
   release_channel_collection: opt-out
   extra_keys:
     key1: This is just a test description.
-- methods: ["expired_version"]
+- methods: ["test_expired_version"]
   objects: ["object1", "object2"]
   bug_numbers: [1286606]
   notification_emails: ["telemetry-client-dev@mozilla.com"]
   description: This is a test entry with an expired version.
   expiry_version: "3.6"
-- methods: ["expired_date"]
+- methods: ["test_expired_date"]
   objects: ["object1", "object2"]
   bug_numbers: [1286606]
   notification_emails: ["telemetry-client-dev@mozilla.com"]
   description: This is a test entry with an expired date.
   expiry_date: 2014-01-28
-- methods: ["not_expired_optout"]
+- methods: ["test_not_expired_optout"]
   objects: ["object1"]
   bug_numbers: [1286606]
   notification_emails: ["telemetry-client-dev@mozilla.com"]
   description: This is an opt-out test entry with unexpired date and version.
   release_channel_collection: opt-out
   expiry_date: 2099-01-01
   expiry_version: "999.0"
 
--- a/toolkit/components/telemetry/TelemetryEvent.cpp
+++ b/toolkit/components/telemetry/TelemetryEvent.cpp
@@ -82,21 +82,21 @@ const uint32_t kEventCount = mozilla::Te
 // This is a special event id used to mark expired events, to make expiry checks
 // faster at runtime.
 const uint32_t kExpiredEventId = kEventCount + 1;
 static_assert(kEventCount < kExpiredEventId, "Should not overflow.");
 
 // This is the hard upper limit on the number of event records we keep in storage.
 // If we cross this limit, we will drop any further event recording until elements
 // are removed from storage.
-const uint32_t kMaxEventRecords = 1000;
+const uint32_t kMaxEventRecords = 10000;
 // Maximum length of any passed value string, in UTF8 byte sequence length.
-const uint32_t kMaxValueByteLength = 80;
+const uint32_t kMaxValueByteLength = 100;
 // Maximum length of any string value in the extra dictionary, in UTF8 byte sequence length.
-const uint32_t kMaxExtraValueByteLength = 80;
+const uint32_t kMaxExtraValueByteLength = 100;
 
 typedef nsDataHashtable<nsCStringHashKey, uint32_t> EventMapType;
 typedef nsClassHashtable<nsCStringHashKey, nsCString> StringMap;
 
 enum class RecordEventResult {
   Ok,
   UnknownEvent,
   InvalidExtraKey,
@@ -514,23 +514,19 @@ TelemetryEvent::RecordEvent(const nsACSt
       return NS_ERROR_FAILURE;
     }
 
     res = ::RecordEvent(lock, timestamp, aCategory, aMethod, aObject, value, extra);
   }
 
   // Trigger warnings or errors where needed.
   switch (res) {
-    case RecordEventResult::UnknownEvent: {
-      JS_ReportErrorASCII(cx, R"(Unknown event: ["%s", "%s", "%s"])",
-                          PromiseFlatCString(aCategory).get(),
-                          PromiseFlatCString(aMethod).get(),
-                          PromiseFlatCString(aObject).get());
+    case RecordEventResult::UnknownEvent:
+      JS_ReportErrorASCII(cx, "Unknown event.");
       return NS_ERROR_INVALID_ARG;
-    }
     case RecordEventResult::InvalidExtraKey:
       LogToBrowserConsole(nsIScriptError::warningFlag,
                           NS_LITERAL_STRING("Invalid extra key for event."));
       return NS_OK;
     case RecordEventResult::StorageLimitReached:
       LogToBrowserConsole(nsIScriptError::warningFlag,
                           NS_LITERAL_STRING("Event storage limit reached."));
       return NS_OK;
@@ -572,82 +568,82 @@ TelemetryEvent::CreateSnapshots(uint32_t
   if (!eventsArray) {
     return NS_ERROR_FAILURE;
   }
 
   for (uint32_t i = 0; i < events.Length(); ++i) {
     const EventRecord& record = events[i];
     const EventInfo& info = gEventInfo[record.EventId()];
 
-    // Each entry is an array of one of the forms:
-    // [timestamp, category, method, object, value]
-    // [timestamp, category, method, object, null, extra]
+    // Each entry is an array of the form:
     // [timestamp, category, method, object, value, extra]
-    JS::AutoValueVector items(cx);
+    JS::RootedObject itemsArray(cx, JS_NewArrayObject(cx, 6));
+    if (!itemsArray) {
+      return NS_ERROR_FAILURE;
+    }
 
     // Add timestamp.
     JS::Rooted<JS::Value> val(cx);
-    if (!items.append(JS::NumberValue(floor(record.Timestamp())))) {
+    uint32_t itemIndex = 0;
+    val.setDouble(floor(record.Timestamp()));
+    if (!JS_DefineElement(cx, itemsArray, itemIndex++, val, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
     // Add category, method, object.
     const char* strings[] = {
       info.common_info.category(),
       info.method(),
       info.object(),
     };
-    for (const char* s : strings) {
-      const NS_ConvertUTF8toUTF16 wide(s);
-      if (!items.append(JS::StringValue(JS_NewUCStringCopyN(cx, wide.Data(), wide.Length())))) {
+    for (uint32_t s = 0; s < ArrayLength(strings); ++s) {
+      const NS_ConvertUTF8toUTF16 wide(strings[s]);
+      val.setString(JS_NewUCStringCopyN(cx, wide.Data(), wide.Length()));
+      if (!JS_DefineElement(cx, itemsArray, itemIndex++, val, JSPROP_ENUMERATE)) {
         return NS_ERROR_FAILURE;
       }
     }
 
-    // Add the optional string value only when needed.
-    // When extra is empty and this has no value, we can save a little space.
-    if (record.Value()) {
+    // Add the optional string value.
+    if (!record.Value()) {
+      val.setNull();
+    } else {
       const NS_ConvertUTF8toUTF16 wide(record.Value().value());
-      if (!items.append(JS::StringValue(JS_NewUCStringCopyN(cx, wide.Data(), wide.Length())))) {
-        return NS_ERROR_FAILURE;
-      }
-    } else if (!record.Extra().IsEmpty()) {
-      if (!items.append(JS::NullValue())) {
-        return NS_ERROR_FAILURE;
-      }
+      val.setString(JS_NewUCStringCopyN(cx, wide.Data(), wide.Length()));
+    }
+    if (!JS_DefineElement(cx, itemsArray, itemIndex++, val, JSPROP_ENUMERATE)) {
+      return NS_ERROR_FAILURE;
     }
 
     // Add the optional extra dictionary.
-    // To save a little space, only add it when it is not empty.
-    if (!record.Extra().IsEmpty()) {
+    if (record.Extra().IsEmpty()) {
+      val.setNull();
+    } else {
       JS::RootedObject obj(cx, JS_NewPlainObject(cx));
       if (!obj) {
         return NS_ERROR_FAILURE;
       }
 
-      // Add extra key & value entries.
       const ExtraArray& extra = record.Extra();
       for (uint32_t i = 0; i < extra.Length(); ++i) {
         const NS_ConvertUTF8toUTF16 wide(extra[i].value);
         JS::Rooted<JS::Value> value(cx);
         value.setString(JS_NewUCStringCopyN(cx, wide.Data(), wide.Length()));
 
         if (!JS_DefineProperty(cx, obj, extra[i].key.get(), value, JSPROP_ENUMERATE)) {
           return NS_ERROR_FAILURE;
         }
       }
       val.setObject(*obj);
-
-      if (!items.append(val)) {
-        return NS_ERROR_FAILURE;
-      }
+    }
+    if (!JS_DefineElement(cx, itemsArray, itemIndex++, val, JSPROP_ENUMERATE)) {
+      return NS_ERROR_FAILURE;
     }
 
     // Add the record to the events array.
-    JS::RootedObject itemsArray(cx, JS_NewArrayObject(cx, items));
     if (!JS_DefineElement(cx, eventsArray, i, itemsArray, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   aResult.setObject(*eventsArray);
   return NS_OK;
 }
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -1015,17 +1015,17 @@ var Impl = {
       return [];
     }
 
     let events = Telemetry.snapshotBuiltinEvents(this.getDatasetType(),
                                                  clearSubsession);
 
     // Don't return the test events outside of test environments.
     if (!this._testing) {
-      events = events.filter(e => !e[1].startsWith("telemetry.test"));
+      events = events.filter(e => e[1].startsWith("telemetry.test"));
     }
 
     return events;
   },
 
   getThreadHangStats: function getThreadHangStats(stats) {
     this._log.trace("getThreadHangStats");
 
--- a/toolkit/components/telemetry/parse_events.py
+++ b/toolkit/components/telemetry/parse_events.py
@@ -4,21 +4,21 @@
 
 import re
 import yaml
 import itertools
 import datetime
 import string
 from shared_telemetry_utils import add_expiration_postfix
 
-MAX_CATEGORY_NAME_LENGTH = 30
-MAX_METHOD_NAME_LENGTH = 20
-MAX_OBJECT_NAME_LENGTH = 20
-MAX_EXTRA_KEYS_COUNT = 10
-MAX_EXTRA_KEY_NAME_LENGTH = 15
+MAX_CATEGORY_NAME_LENGTH = 100
+MAX_METHOD_NAME_LENGTH = 40
+MAX_OBJECT_NAME_LENGTH = 40
+MAX_EXTRA_KEYS_COUNT = 20
+MAX_EXTRA_KEY_NAME_LENGTH = 20
 
 IDENTIFIER_PATTERN = r'^[a-zA-Z][a-zA-Z0-9_.]+[a-zA-Z0-9]$'
 DATE_PATTERN = r'^[0-9]{4}-[0-9]{2}-[0-9]{2}$'
 
 def nice_type_name(t):
     if isinstance(t, basestring):
         return "string"
     return t.__name__
@@ -121,18 +121,18 @@ def type_check_event_fields(category, de
 
     # Type-check fields.
     for k,v in definition.iteritems():
         ALL_FIELDS[k].check(k, v)
 
 def string_check(category, field_name, value, min_length, max_length, regex=None):
     # Length check.
     if len(value) > max_length:
-        raise ValueError("Value '%s' for %s in %s exceeds maximum length of %d" %\
-                         (value, field_name, category, max_length))
+        raise ValueError("Value for %s in %s exceeds maximum length of %d" %\
+                         (field_name, category, max_length))
     # Regex check.
     if regex and not re.match(regex, value):
         raise ValueError, 'String value for %s in %s is not matching pattern "%s": %s' % \
                           (field_name, category, regex, value)
 
 class EventData:
     """A class representing one event."""
 
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js
@@ -4,32 +4,27 @@
 
 const OPTIN = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN;
 const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
 
 function checkEventFormat(events) {
   Assert.ok(Array.isArray(events), "Events should be serialized to an array.");
   for (let e of events) {
     Assert.ok(Array.isArray(e), "Event should be an array.");
-    Assert.greaterOrEqual(e.length, 4, "Event should have at least 4 elements.");
-    Assert.lessOrEqual(e.length, 6, "Event should have at most 6 elements.");
+    Assert.equal(e.length, 6, "Event should have 6 elements.");
 
     Assert.equal(typeof(e[0]), "number", "Element 0 should be a number.");
     Assert.equal(typeof(e[1]), "string", "Element 1 should be a string.");
     Assert.equal(typeof(e[2]), "string", "Element 2 should be a string.");
     Assert.equal(typeof(e[3]), "string", "Element 3 should be a string.");
 
-    if (e.length > 4) {
-      Assert.ok(e[4] === null || typeof(e[4]) == "string",
-                "Event element 4 should be null or a string.");
-    }
-    if (e.length > 5) {
-      Assert.ok(e[5] === null || typeof(e[5]) == "object",
-                "Event element 5 should be null or an object.");
-    }
+    Assert.ok(e[4] === null || typeof(e[4]) == "string",
+              "Event element 4 should be null or a string.");
+    Assert.ok(e[5] === null || typeof(e[5]) == "object",
+              "Event element 4 should be null or an object.");
 
     let extra = e[5];
     if (extra) {
       Assert.ok(Object.keys(extra).every(k => typeof(k) == "string"),
                 "All extra keys should be strings.");
       Assert.ok(Object.values(extra).every(v => typeof(v) == "string"),
                 "All extra values should be strings.");
     }
@@ -44,63 +39,58 @@ add_task(function* test_recording() {
     {optout: false, event: ["telemetry.test", "test1", "object1"]},
     {optout: false, event: ["telemetry.test", "test2", "object2"]},
 
     {optout: false, event: ["telemetry.test", "test1", "object1", "value"]},
     {optout: false, event: ["telemetry.test", "test1", "object1", "value", null]},
     {optout: false, event: ["telemetry.test", "test1", "object1", null, {"key1": "value1"}]},
     {optout: false, event: ["telemetry.test", "test1", "object1", "value", {"key1": "value1", "key2": "value2"}]},
 
-    {optout: true,  event: ["telemetry.test", "optout", "object1"]},
+    {optout: true,  event: ["telemetry.test", "test_optout", "object1"]},
     {optout: false, event: ["telemetry.test.second", "test", "object1"]},
     {optout: false, event: ["telemetry.test.second", "test", "object1", null, {"key1": "value1"}]},
   ];
 
   for (let entry of expected) {
     entry.tsBefore = Math.floor(Telemetry.msSinceProcessStart());
     try {
       Telemetry.recordEvent(...entry.event);
     } catch (ex) {
       Assert.ok(false, `Failed to record event ${JSON.stringify(entry.event)}: ${ex}`);
     }
     entry.tsAfter = Math.floor(Telemetry.msSinceProcessStart());
   }
 
-  // Strip off trailing null values to match the serialized events.
-  for (let entry of expected) {
-    let e = entry.event;
-    while ((e.length >= 3) && (e[e.length - 1] === null)) {
-      e.pop();
-    }
-  }
-
   // The following should not result in any recorded events.
   Assert.throws(() => Telemetry.recordEvent("unknown.category", "test1", "object1"),
-                /Error: Unknown event: \["unknown.category", "test1", "object1"\]/,
+                /Error: Unknown event\./,
                 "Should throw on unknown category.");
   Assert.throws(() => Telemetry.recordEvent("telemetry.test", "unknown", "object1"),
-                /Error: Unknown event: \["telemetry.test", "unknown", "object1"\]/,
+                /Error: Unknown event\./,
                 "Should throw on unknown method.");
   Assert.throws(() => Telemetry.recordEvent("telemetry.test", "test1", "unknown"),
-                /Error: Unknown event: \["telemetry.test", "test1", "unknown"\]/,
+                /Error: Unknown event\./,
                 "Should throw on unknown object.");
 
   let checkEvents = (events, expectedEvents) => {
     checkEventFormat(events);
     Assert.equal(events.length, expectedEvents.length,
                  "Snapshot should have the right number of events.");
 
     for (let i = 0; i < events.length; ++i) {
       let {tsBefore, tsAfter} = expectedEvents[i];
       let ts = events[i][0];
       Assert.greaterOrEqual(ts, tsBefore, "The recorded timestamp should be greater than the one before recording.");
       Assert.lessOrEqual(ts, tsAfter, "The recorded timestamp should be less than the one after recording.");
 
       let recordedData = events[i].slice(1);
       let expectedData = expectedEvents[i].event.slice();
+      for (let j = expectedData.length; j < 5; ++j) {
+        expectedData.push(null);
+      }
       Assert.deepEqual(recordedData, expectedData, "The recorded event data should match.");
     }
   };
 
   // Check that the expected events were recorded.
   let events = Telemetry.snapshotBuiltinEvents(OPTIN, false);
   checkEvents(events, expected);
 
@@ -128,27 +118,27 @@ add_task(function* test_clear() {
   events = Telemetry.snapshotBuiltinEvents(OPTIN, false);
   Assert.equal(events.length, 0, `Should have cleared the events.`);
 });
 
 add_task(function* test_expiry() {
   Telemetry.clearEvents();
 
   // Recording call with event that is expired by version.
-  Telemetry.recordEvent("telemetry.test", "expired_version", "object1");
+  Telemetry.recordEvent("telemetry.test", "test_expired_version", "object1");
   let events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
   Assert.equal(events.length, 0, "Should not record event with expired version.");
 
   // Recording call with event that is expired by date.
-  Telemetry.recordEvent("telemetry.test", "expired_date", "object1");
+  Telemetry.recordEvent("telemetry.test", "test_expired_date", "object1");
   events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
   Assert.equal(events.length, 0, "Should not record event with expired date.");
 
   // Recording call with event that has expiry_version and expiry_date in the future.
-  Telemetry.recordEvent("telemetry.test", "not_expired_optout", "object1");
+  Telemetry.recordEvent("telemetry.test", "test_not_expired_optout", "object1");
   events = Telemetry.snapshotBuiltinEvents(OPTOUT, true);
   Assert.equal(events.length, 1, "Should record event when date and version are not expired.");
 });
 
 add_task(function* test_invalidParams() {
   Telemetry.clearEvents();
 
   // Recording call with wrong type for value argument.
@@ -171,60 +161,53 @@ add_task(function* test_invalidParams() 
   events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
   Assert.equal(events.length, 0, "Should not record event when extra argument with invalid value type is passed.");
 });
 
 add_task(function* test_storageLimit() {
   Telemetry.clearEvents();
 
   // Record more events than the storage limit allows.
-  let LIMIT = 1000;
+  let LIMIT = 10000;
   let COUNT = LIMIT + 10;
   for (let i = 0; i < COUNT; ++i) {
     Telemetry.recordEvent("telemetry.test", "test1", "object1", String(i));
   }
 
   // Check that the right events were recorded.
   let events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
   Assert.equal(events.length, LIMIT, `Should have only recorded ${LIMIT} events`);
   Assert.ok(events.every((e, idx) => e[4] === String(idx)),
             "Should have recorded all events from before hitting the limit.");
 });
 
 add_task(function* test_valueLimits() {
   Telemetry.clearEvents();
 
   // Record values that are at or over the limits for string lengths.
-  let LIMIT = 80;
+  let LIMIT = 100;
   let expected = [
     ["telemetry.test", "test1", "object1", "a".repeat(LIMIT - 10), null],
     ["telemetry.test", "test1", "object1", "a".repeat(LIMIT     ), null],
     ["telemetry.test", "test1", "object1", "a".repeat(LIMIT +  1), null],
     ["telemetry.test", "test1", "object1", "a".repeat(LIMIT + 10), null],
 
     ["telemetry.test", "test1", "object1", null, {key1: "a".repeat(LIMIT - 10)}],
     ["telemetry.test", "test1", "object1", null, {key1: "a".repeat(LIMIT     )}],
     ["telemetry.test", "test1", "object1", null, {key1: "a".repeat(LIMIT +  1)}],
     ["telemetry.test", "test1", "object1", null, {key1: "a".repeat(LIMIT + 10)}],
   ];
 
   for (let event of expected) {
     Telemetry.recordEvent(...event);
     if (event[3]) {
-      event[3] = event[3].substr(0, LIMIT);
+      event[3] = event[3].substr(0, 100);
     }
     if (event[4]) {
-      event[4].key1 = event[4].key1.substr(0, LIMIT);
-    }
-  }
-
-  // Strip off trailing null values to match the serialized events.
-  for (let e of expected) {
-    while ((e.length >= 3) && (e[e.length - 1] === null)) {
-      e.pop();
+      event[4].key1 = event[4].key1.substr(0, 100);
     }
   }
 
   // Check that the right events were recorded.
   let events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
   Assert.equal(events.length, expected.length,
                "Should have recorded the expected number of events");
   for (let i = 0; i < expected.length; ++i) {
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -720,23 +720,16 @@ add_task(function* test_checkSubsessionE
   let expected = [
     ["telemetry.test", "test1", "object1", "a", null],
     ["telemetry.test", "test1", "object1", null, {key1: "value"}],
   ];
   for (let event of expected) {
     Telemetry.recordEvent(...event);
   }
 
-  // Strip off trailing null values to match the serialized events.
-  for (let e of expected) {
-    while ((e.length >= 3) && (e[e.length - 1] === null)) {
-      e.pop();
-    }
-  }
-
   // Check that events are not available in classic pings but are in subsession
   // pings. Also clear the subsession.
   let classic = TelemetrySession.getPayload();
   let subsession = TelemetrySession.getPayload("environment-change", true);
 
   Assert.ok("events" in classic.processes.parent, "Should have an events field in classic payload.");
   Assert.ok("events" in subsession.processes.parent, "Should have an events field in subsession payload.");