/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ const { TelemetryController } = ChromeUtils.importESModule( "resource://gre/modules/TelemetryController.sys.mjs" ); const { ContentTaskUtils } = ChromeUtils.importESModule( "resource://testing-common/ContentTaskUtils.sys.mjs" ); const MESSAGE_CHILD_TEST_DONE = "ChildTest:Done"; 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); await 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." ); });