bug 1460595 - Test "event" ping event storage r?Dexter draft
authorChris H-C <chutten@mozilla.com>
Fri, 11 May 2018 16:13:18 -0400
changeset 798708 b3f8f6342a3c10ab0205be7d87c551c3953773e1
parent 798707 f499c1f9dc02b871e63e239191b25e85c22a34e8
child 798709 f3d1cb5e5c907c2a285a48b5ef713466b0c11784
push id110834
push userbmo:chutten@mozilla.com
push dateWed, 23 May 2018 12:25:06 +0000
reviewersDexter
bugs1460595
milestone62.0a1
bug 1460595 - Test "event" ping event storage r?Dexter This does not bother testing all aspects of Telemetry Events against storage two, but contents itself with checking basic functionality and the areas where the two behave differently: clearing, and limits. For clearing, I was careful to test the clearing independently. For limits, I added checks that the new topic was appropriately notified and that storage two doesn't truncate upon hitting the limit, also covering the case when there is a specified event limit for return. MozReview-Commit-ID: FoSVvi7XSeM
toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js
@@ -1,12 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/
 */
 
+ChromeUtils.defineModuleGetter(this, "TestUtils", "resource://testing-common/TestUtils.jsm");
+
 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.");
@@ -99,44 +101,59 @@ add_task(async function test_recording_s
     ["telemetry.test", "test1", "object1"],
     ["telemetry.test.second", "test", "object1"],
   ];
 
   // Both test categories should be off by default.
   events.forEach(e => Telemetry.recordEvent(...e));
   let snapshot = Telemetry.snapshotEvents(OPTIN, true);
   Assert.equal(Object.keys(snapshot).length, 0, "Should not have recorded any events.");
+  snapshot = Telemetry.snapshotEvents(OPTIN, true, true);
+  Assert.equal(Object.keys(snapshot).length, 0, "Should not have recorded any events in storage two.");
   checkEventSummary(events.map(e => (["parent", e, 1])), true);
 
   // Enable one test category and see that we record correctly.
   Telemetry.setEventRecordingEnabled("telemetry.test", true);
   events.forEach(e => Telemetry.recordEvent(...e));
   snapshot = Telemetry.snapshotEvents(OPTIN, true);
   Assert.ok(("parent" in snapshot), "Should have entry for main process.");
   Assert.equal(snapshot.parent.length, 1, "Should have recorded one event.");
   Assert.equal(snapshot.parent[0][1], "telemetry.test", "Should have recorded one event in telemetry.test");
+  snapshot = Telemetry.snapshotEvents(OPTIN, true, true);
+  Assert.ok(("parent" in snapshot), "Should have entry for main process from storage two.");
+  Assert.equal(snapshot.parent.length, 1, "Should have recorded one event in storage two.");
+  Assert.equal(snapshot.parent[0][1], "telemetry.test", "Should have recorded one event in telemetry.test (storage two)");
   checkEventSummary(events.map(e => (["parent", e, 1])), true);
 
   // Also enable the other test category and see that we record correctly.
   Telemetry.setEventRecordingEnabled("telemetry.test.second", true);
   events.forEach(e => Telemetry.recordEvent(...e));
   snapshot = Telemetry.snapshotEvents(OPTIN, true);
   Assert.ok(("parent" in snapshot), "Should have entry for main process.");
   Assert.equal(snapshot.parent.length, 2, "Should have recorded two events.");
   Assert.equal(snapshot.parent[0][1], "telemetry.test", "Should have recorded one event in telemetry.test");
   Assert.equal(snapshot.parent[1][1], "telemetry.test.second", "Should have recorded one event in telemetry.test.second");
+  snapshot = Telemetry.snapshotEvents(OPTIN, true, true);
+  Assert.ok(("parent" in snapshot), "Should have entry for main process from storage two.");
+  Assert.equal(snapshot.parent.length, 2, "Should have recorded two events in storage two.");
+  Assert.equal(snapshot.parent[0][1], "telemetry.test", "Should have recorded one event in telemetry.test (storage two)");
+  Assert.equal(snapshot.parent[1][1], "telemetry.test.second", "Should have recorded one event in telemetry.test.second (storage two)");
   checkEventSummary(events.map(e => (["parent", e, 1])), true);
 
   // Now turn of one category again and check that this works as expected.
   Telemetry.setEventRecordingEnabled("telemetry.test", false);
   events.forEach(e => Telemetry.recordEvent(...e));
   snapshot = Telemetry.snapshotEvents(OPTIN, true);
   Assert.ok(("parent" in snapshot), "Should have entry for main process.");
   Assert.equal(snapshot.parent.length, 1, "Should have recorded one event.");
   Assert.equal(snapshot.parent[0][1], "telemetry.test.second", "Should have recorded one event in telemetry.test.second");
+  snapshot = Telemetry.snapshotEvents(OPTIN, true, true);
+  Assert.ok(("parent" in snapshot), "Should have entry for main process from storage two.");
+  Assert.equal(snapshot.parent.length, 1, "Should have recorded one event in storage two.");
+  Assert.equal(snapshot.parent[0][1], "telemetry.test.second", "Should have recorded one event in telemetry.test.second (storage two)");
   checkEventSummary(events.map(e => (["parent", e, 1])), true);
 });
 
 add_task(async function recording_setup() {
   // Make sure both test categories are enabled for the remaining tests.
   // Otherwise their event recording won't work.
   Telemetry.setEventRecordingEnabled("telemetry.test", true);
   Telemetry.setEventRecordingEnabled("telemetry.test.second", true);
@@ -219,57 +236,85 @@ add_task(async function test_recording()
       Assert.deepEqual(recordedData, expectedData, "The recorded event data should match.");
     }
   };
 
   // Check that the expected events were recorded.
   let snapshot = Telemetry.snapshotEvents(OPTIN, false);
   Assert.ok(("parent" in snapshot), "Should have entry for main process.");
   checkEvents(snapshot.parent, expected);
+  snapshot = Telemetry.snapshotEvents(OPTIN, false, true);
+  Assert.ok(("parent" in snapshot), "Should have entry for main process from storage two.");
+  checkEvents(snapshot.parent, expected);
 
   // Check serializing only opt-out events.
   snapshot = Telemetry.snapshotEvents(OPTOUT, false);
   Assert.ok(("parent" in snapshot), "Should have entry for main process.");
   let filtered = expected.filter(e => !!e.optout);
   checkEvents(snapshot.parent, filtered);
+  snapshot = Telemetry.snapshotEvents(OPTOUT, false, true);
+  Assert.ok(("parent" in snapshot), "Should have entry for main process from storage two.");
+  checkEvents(snapshot.parent, filtered);
 });
 
 add_task(async function test_clear() {
   Telemetry.clearEvents();
 
   const COUNT = 10;
   for (let i = 0; i < COUNT; ++i) {
     Telemetry.recordEvent("telemetry.test", "test1", "object1");
     Telemetry.recordEvent("telemetry.test.second", "test", "object1");
   }
 
   // Check that events were recorded.
   // The events are cleared by passing the respective flag.
   let snapshot = Telemetry.snapshotEvents(OPTIN, true);
   Assert.ok(("parent" in snapshot), "Should have entry for main process.");
   Assert.equal(snapshot.parent.length, 2 * COUNT, `Should have recorded ${2 * COUNT} events.`);
+  snapshot = Telemetry.snapshotEvents(OPTIN, true, true);
+  Assert.ok(("parent" in snapshot), "Should have entry for main process from storage two.");
+  Assert.equal(snapshot.parent.length, 2 * COUNT, `Should have recorded ${2 * COUNT} events in storage two.`);
 
   // Now the events should be cleared.
   snapshot = Telemetry.snapshotEvents(OPTIN, false);
   Assert.equal(Object.keys(snapshot).length, 0, `Should have cleared the events.`);
+  snapshot = Telemetry.snapshotEvents(OPTIN, false, false);
+  Assert.equal(Object.keys(snapshot).length, 0, `Should have cleared the events from storage two.`);
+
+  for (let i = 0; i < COUNT; ++i) {
+    Telemetry.recordEvent("telemetry.test", "test1", "object1");
+    Telemetry.recordEvent("telemetry.test.second", "test", "object1");
+  }
+  snapshot = Telemetry.snapshotEvents(OPTIN, true, true, 5);
+  Assert.ok(("parent" in snapshot), "Should have entry for main process.");
+  Assert.equal(snapshot.parent.length, 5, "Should have returned 5 events");
+  snapshot = Telemetry.snapshotEvents(OPTIN, true, true);
+  Assert.ok(("parent" in snapshot), "Should have entry for main process.");
+  Assert.equal(snapshot.parent.length, (2 * COUNT) - 5, `Should have returned ${(2 * COUNT) - 5} events`);
+
 });
 
 add_task(async function test_expiry() {
   Telemetry.clearEvents();
 
   // Recording call with event that is expired by version.
   Telemetry.recordEvent("telemetry.test", "expired_version", "object1");
   let snapshot = Telemetry.snapshotEvents(OPTIN, true);
   Assert.equal(Object.keys(snapshot).length, 0, "Should not record event with expired version.");
+  snapshot = Telemetry.snapshotEvents(OPTIN, true, true);
+  Assert.equal(Object.keys(snapshot).length, 0, "Should not record event with expired version in storage two.");
 
   // Recording call with event that has expiry_version set into the future.
   Telemetry.recordEvent("telemetry.test", "not_expired_optout", "object1");
   snapshot = Telemetry.snapshotEvents(OPTOUT, true);
   Assert.ok(("parent" in snapshot), "Should have entry for main process.");
   Assert.equal(snapshot.parent.length, 1, "Should record event when version is not expired.");
+  snapshot = Telemetry.snapshotEvents(OPTOUT, true, true);
+  Assert.ok(("parent" in snapshot), "Should have entry for main process from storage two.");
+  Assert.equal(snapshot.parent.length, 1, "Should record event when version is not expired in storage two.");
 });
 
 add_task(async function test_invalidParams() {
   Telemetry.clearEvents();
 
   // Recording call with wrong type for value argument.
   Telemetry.recordEvent("telemetry.test", "test1", "object1", 1);
   let snapshot = Telemetry.snapshotEvents(OPTIN, true);
@@ -289,30 +334,40 @@ add_task(async function test_invalidPara
   Telemetry.recordEvent("telemetry.test", "test1", "object1", null, {"key3": 1});
   snapshot = Telemetry.snapshotEvents(OPTIN, true);
   Assert.equal(Object.keys(snapshot).length, 0, "Should not record event when extra argument with invalid value type is passed.");
 });
 
 add_task(async function test_storageLimit() {
   Telemetry.clearEvents();
 
+  let limitReached = TestUtils.topicObserved("event-telemetry-storage-limit-reached");
   // Record more events than the storage limit allows.
   let LIMIT = 1000;
   let COUNT = LIMIT + 10;
   for (let i = 0; i < COUNT; ++i) {
     Telemetry.recordEvent("telemetry.test", "test1", "object1", String(i));
   }
 
+  await limitReached;
+  Assert.ok(true, "Topic was notified when event limit was reached");
+
   // Check that the right events were recorded.
   let snapshot = Telemetry.snapshotEvents(OPTIN, true);
   Assert.ok(("parent" in snapshot), "Should have entry for main process.");
   let events = snapshot.parent;
   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.");
+  snapshot = Telemetry.snapshotEvents(OPTIN, true, true);
+  Assert.ok(("parent" in snapshot), "Should have entry for main process from storage two.");
+  events = snapshot.parent;
+  Assert.equal(events.length, COUNT, `Should have recorded all ${COUNT} events in storage two`);
+  Assert.ok(events.every((e, idx) => e[4] === String(idx)),
+            "Should have recorded all events in storage two.");
 });
 
 add_task(async function test_valueLimits() {
   Telemetry.clearEvents();
 
   // Record values that are at or over the limits for string lengths.
   let LIMIT = 80;
   let expected = [