gecko-dev/toolkit/components/telemetry/tests/unit/test_ChildEvents.js

164 lines
6.7 KiB
JavaScript

/* 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 > 0, "Main process section should have events.");
Assert.ok("content" in snapshot, "Should have child process section");
Assert.ok(snapshot.content.length > 0, "Child process section should have events.");
Assert.ok("dynamic" in snapshot, "Should have dynamic process section");
Assert.ok(snapshot.dynamic.length > 0, "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.");
});