summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/tests/unit/test_ChildEvents.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_ChildEvents.js')
-rw-r--r--toolkit/components/telemetry/tests/unit/test_ChildEvents.js226
1 files changed, 226 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_ChildEvents.js b/toolkit/components/telemetry/tests/unit/test_ChildEvents.js
new file mode 100644
index 0000000000..ff3da1954c
--- /dev/null
+++ b/toolkit/components/telemetry/tests/unit/test_ChildEvents.js
@@ -0,0 +1,226 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+*/
+
+ChromeUtils.import("resource://gre/modules/Services.jsm", this);
+ChromeUtils.import("resource://gre/modules/TelemetryController.jsm", this);
+ChromeUtils.import("resource://gre/modules/TelemetrySession.jsm", this);
+ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm", this);
+ChromeUtils.import("resource://testing-common/ContentTaskUtils.jsm", this);
+
+const MESSAGE_CHILD_TEST_DONE = "ChildTest:Done";
+
+const PLATFORM_VERSION = "1.9.2";
+const APP_VERSION = "1";
+const APP_ID = "xpcshell@tests.mozilla.org";
+const APP_NAME = "XPCShell";
+
+const RECORDED_CONTENT_EVENTS = [
+ ["telemetry.test", "content_only", "object1"],
+ ["telemetry.test", "main_and_content", "object1"],
+ ["telemetry.test", "content_only", "object1", "some value"],
+ ["telemetry.test", "content_only", "object1", null, { foo: "x", bar: "y" }],
+ [
+ "telemetry.test",
+ "content_only",
+ "object1",
+ "some value",
+ { foo: "x", bar: "y" },
+ ],
+];
+
+const UNRECORDED_CONTENT_EVENTS = [["telemetry.test", "main_only", "object1"]];
+
+const RECORDED_PARENT_EVENTS = [
+ ["telemetry.test", "main_and_content", "object1"],
+ ["telemetry.test", "main_only", "object1"],
+];
+
+const UNRECORDED_PARENT_EVENTS = [
+ ["telemetry.test", "content_only", "object1"],
+];
+
+const RECORDED_DYNAMIC_EVENTS = [
+ ["telemetry.test.dynamic", "test1", "object1"],
+ ["telemetry.test.dynamic", "test2", "object1"],
+];
+
+function run_child_test() {
+ // Record some events in the "content" process.
+ RECORDED_CONTENT_EVENTS.forEach(e => Telemetry.recordEvent(...e));
+ // These events should not be recorded for the content process.
+ UNRECORDED_CONTENT_EVENTS.forEach(e => Telemetry.recordEvent(...e));
+ // Record some dynamic events from the content process.
+ RECORDED_DYNAMIC_EVENTS.forEach(e => Telemetry.recordEvent(...e));
+}
+
+/**
+ * This function waits until content events are reported into the
+ * events snapshot.
+ */
+async function waitForContentEvents() {
+ await ContentTaskUtils.waitForCondition(() => {
+ const snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ false
+ );
+ return (
+ Object.keys(snapshot).includes("content") &&
+ Object.keys(snapshot).includes("dynamic")
+ );
+ });
+}
+
+add_task(async function() {
+ if (!runningInParent) {
+ TelemetryController.testSetupContent();
+ run_child_test();
+ do_send_remote_message(MESSAGE_CHILD_TEST_DONE);
+ return;
+ }
+
+ // Setup.
+ do_get_profile(true);
+ loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
+ finishAddonManagerStartup();
+ fakeIntlReady();
+ await TelemetryController.testSetup();
+ // Make sure we don't generate unexpected pings due to pref changes.
+ await setEmptyPrefWatchlist();
+ // Enable recording for the test event category.
+ Telemetry.setEventRecordingEnabled("telemetry.test", true);
+
+ // Register dynamic test events.
+ Telemetry.registerEvents("telemetry.test.dynamic", {
+ // Event with only required fields.
+ test1: {
+ methods: ["test1"],
+ objects: ["object1"],
+ },
+ // Event with extra_keys.
+ test2: {
+ methods: ["test2", "test2b"],
+ objects: ["object1"],
+ extra_keys: ["key1", "key2"],
+ },
+ });
+
+ // Run test in child, don't wait for it to finish: just wait for the
+ // MESSAGE_CHILD_TEST_DONE.
+ const timestampBeforeChildEvents = Telemetry.msSinceProcessStart();
+ run_test_in_child("test_ChildEvents.js");
+ await do_await_remote_message(MESSAGE_CHILD_TEST_DONE);
+
+ // Once events are set by the content process, they don't immediately get
+ // sent to the parent process. Wait for the Telemetry IPC Timer to trigger
+ // and batch send the data back to the parent process.
+ await waitForContentEvents();
+ const timestampAfterChildEvents = Telemetry.msSinceProcessStart();
+
+ // Also record some events in the parent.
+ RECORDED_PARENT_EVENTS.forEach(e => Telemetry.recordEvent(...e));
+ UNRECORDED_PARENT_EVENTS.forEach(e => Telemetry.recordEvent(...e));
+
+ let snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ false
+ );
+
+ Assert.ok("parent" in snapshot, "Should have main process section");
+ Assert.ok(
+ !!snapshot.parent.length,
+ "Main process section should have events."
+ );
+ Assert.ok("content" in snapshot, "Should have child process section");
+ Assert.ok(
+ !!snapshot.content.length,
+ "Child process section should have events."
+ );
+ Assert.ok("dynamic" in snapshot, "Should have dynamic process section");
+ Assert.ok(
+ !!snapshot.dynamic.length,
+ "Dynamic process section should have events."
+ );
+
+ // Check that the expected events are present from the content process.
+ let contentEvents = snapshot.content.map(e => e.slice(1));
+ Assert.equal(
+ contentEvents.length,
+ RECORDED_CONTENT_EVENTS.length,
+ "Should match expected event count."
+ );
+ for (let i = 0; i < RECORDED_CONTENT_EVENTS.length; ++i) {
+ Assert.deepEqual(
+ contentEvents[i],
+ RECORDED_CONTENT_EVENTS[i],
+ "Should have recorded expected event."
+ );
+ }
+
+ // Check that the expected events are present from the parent process.
+ let parentEvents = snapshot.parent.map(e => e.slice(1));
+ Assert.equal(
+ parentEvents.length,
+ RECORDED_PARENT_EVENTS.length,
+ "Should match expected event count."
+ );
+ for (let i = 0; i < RECORDED_PARENT_EVENTS.length; ++i) {
+ Assert.deepEqual(
+ parentEvents[i],
+ RECORDED_PARENT_EVENTS[i],
+ "Should have recorded expected event."
+ );
+ }
+
+ // Check that the expected dynamic events are present.
+ let dynamicEvents = snapshot.dynamic.map(e => e.slice(1));
+ Assert.equal(
+ dynamicEvents.length,
+ RECORDED_DYNAMIC_EVENTS.length,
+ "Should match expected event count."
+ );
+ for (let i = 0; i < RECORDED_DYNAMIC_EVENTS.length; ++i) {
+ Assert.deepEqual(
+ dynamicEvents[i],
+ RECORDED_DYNAMIC_EVENTS[i],
+ "Should have recorded expected event."
+ );
+ }
+
+ // Check that the event timestamps are in the expected ranges.
+ let contentTimestamps = snapshot.content.map(e => e[0]);
+ let parentTimestamps = snapshot.parent.map(e => e[0]);
+
+ Assert.ok(
+ contentTimestamps.every(
+ ts =>
+ ts > Math.floor(timestampBeforeChildEvents) &&
+ ts < timestampAfterChildEvents
+ ),
+ "All content event timestamps should be in the expected time range."
+ );
+ Assert.ok(
+ parentTimestamps.every(ts => ts >= Math.floor(timestampAfterChildEvents)),
+ "All parent event timestamps should be in the expected time range."
+ );
+
+ // Make sure all events are cleared from storage properly.
+ snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ true
+ );
+ Assert.greaterOrEqual(
+ Object.keys(snapshot).length,
+ 2,
+ "Should have events from at least two processes."
+ );
+ snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ true
+ );
+ Assert.equal(
+ Object.keys(snapshot).length,
+ 0,
+ "Should have cleared all events from storage."
+ );
+});