summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/tests/unit/test_TelemetryEvents_buildFaster.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_TelemetryEvents_buildFaster.js')
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryEvents_buildFaster.js468
1 files changed, 468 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEvents_buildFaster.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEvents_buildFaster.js
new file mode 100644
index 0000000000..24554403e4
--- /dev/null
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEvents_buildFaster.js
@@ -0,0 +1,468 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/
+*/
+
+const { CommonUtils } = ChromeUtils.import(
+ "resource://services-common/utils.js"
+);
+
+/**
+ * Return the path to the definitions file for the events.
+ */
+function getDefinitionsPath() {
+ // Write the event definition to the spec file in the binary directory.
+ let definitionFile = Cc["@mozilla.org/file/local;1"].createInstance(
+ Ci.nsIFile
+ );
+ definitionFile = Services.dirsvc.get("GreD", Ci.nsIFile);
+ definitionFile.append("EventArtifactDefinitions.json");
+ return definitionFile.path;
+}
+
+add_task(async function test_setup() {
+ do_get_profile();
+});
+
+add_task(
+ {
+ // The test needs to write a file, and that fails in tests on Android.
+ // We don't really need the Android coverage, so skip on Android.
+ skip_if: () => AppConstants.platform == "android",
+ },
+ async function test_invalidJSON() {
+ const INVALID_JSON = "{ invalid,JSON { {1}";
+ const FILE_PATH = getDefinitionsPath();
+
+ // Write a corrupted JSON file.
+ await OS.File.writeAtomic(FILE_PATH, INVALID_JSON, {
+ encoding: "utf-8",
+ noOverwrite: false,
+ });
+
+ // Simulate Firefox startup. This should not throw!
+ await TelemetryController.testSetup();
+ await TelemetryController.testPromiseJsProbeRegistration();
+
+ // Cleanup.
+ await TelemetryController.testShutdown();
+ await OS.File.remove(FILE_PATH);
+ }
+);
+
+add_task(
+ {
+ // The test needs to write a file, and that fails in tests on Android.
+ // We don't really need the Android coverage, so skip on Android.
+ skip_if: () => AppConstants.platform == "android",
+ },
+ async function test_dynamicBuiltin() {
+ const DYNAMIC_EVENT_SPEC = {
+ "telemetry.test.builtin": {
+ test: {
+ objects: ["object1", "object2"],
+ expires: "never",
+ methods: ["test1", "test2"],
+ extra_keys: ["key2", "key1"],
+ record_on_release: false,
+ },
+ },
+ // Test a new, expired event
+ "telemetry.test.expired": {
+ expired: {
+ objects: ["object1"],
+ methods: ["method1"],
+ expires: AppConstants.MOZ_APP_VERSION,
+ record_on_release: false,
+ },
+ },
+ // Test overwriting static expiries
+ "telemetry.test": {
+ expired_version: {
+ objects: ["object1"],
+ methods: ["expired_version"],
+ expires: "never",
+ record_on_release: false,
+ },
+ not_expired_optout: {
+ objects: ["object1"],
+ methods: ["not_expired_optout"],
+ expires: AppConstants.MOZ_APP_VERSION,
+ record_on_release: true,
+ },
+ },
+ };
+
+ Telemetry.clearEvents();
+
+ // Let's write to the definition file to also cover the file
+ // loading part.
+ const FILE_PATH = getDefinitionsPath();
+ await CommonUtils.writeJSON(DYNAMIC_EVENT_SPEC, FILE_PATH);
+
+ // Start TelemetryController to trigger loading the specs.
+ await TelemetryController.testReset();
+ await TelemetryController.testPromiseJsProbeRegistration();
+
+ // Record the events
+ const TEST_EVENT_NAME = "telemetry.test.builtin";
+ const DYNAMIC_EVENT_CATEGORY = "telemetry.test.expired";
+ const STATIC_EVENT_CATEGORY = "telemetry.test";
+ Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true);
+ Telemetry.setEventRecordingEnabled(DYNAMIC_EVENT_CATEGORY, true);
+ Telemetry.setEventRecordingEnabled(STATIC_EVENT_CATEGORY, true);
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1");
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object1", null, {
+ key1: "foo",
+ key2: "bar",
+ });
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object2", null, {
+ key2: "bar",
+ });
+ Telemetry.recordEvent(DYNAMIC_EVENT_CATEGORY, "method1", "object1");
+ Telemetry.recordEvent(STATIC_EVENT_CATEGORY, "expired_version", "object1");
+ Telemetry.recordEvent(
+ STATIC_EVENT_CATEGORY,
+ "not_expired_optout",
+ "object1"
+ );
+
+ // Check the values we tried to store.
+ const snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ false
+ );
+ Assert.ok(
+ "parent" in snapshot,
+ "Should have parent events in the snapshot."
+ );
+
+ let expected = [
+ [TEST_EVENT_NAME, "test1", "object1"],
+ [TEST_EVENT_NAME, "test2", "object1", null, { key1: "foo", key2: "bar" }],
+ [TEST_EVENT_NAME, "test2", "object2", null, { key2: "bar" }],
+ [STATIC_EVENT_CATEGORY, "expired_version", "object1"],
+ ];
+ let events = snapshot.parent;
+ Assert.equal(
+ events.length,
+ expected.length,
+ "Should have recorded the right amount of events."
+ );
+ for (let i = 0; i < expected.length; ++i) {
+ Assert.deepEqual(
+ events[i].slice(1),
+ expected[i],
+ "Should have recorded the expected event data."
+ );
+ }
+
+ // Clean up.
+ await TelemetryController.testShutdown();
+ await OS.File.remove(FILE_PATH);
+ }
+);
+
+add_task(async function test_dynamicBuiltinEvents() {
+ Telemetry.clearEvents();
+ Telemetry.clearScalars();
+ Telemetry.canRecordExtended = true;
+
+ const TEST_EVENT_NAME = "telemetry.test.dynamicbuiltin";
+
+ // Register some dynamic builtin test events.
+ Telemetry.registerBuiltinEvents(TEST_EVENT_NAME, {
+ // Event with only required fields.
+ test1: {
+ methods: ["test1"],
+ objects: ["object1"],
+ },
+ // Event with extra_keys.
+ test2: {
+ methods: ["test2", "test2b"],
+ objects: ["object1", "object2"],
+ extra_keys: ["key1", "key2"],
+ },
+ });
+
+ // Record some events.
+ Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true);
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1");
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object1", null, {
+ key1: "foo",
+ key2: "bar",
+ });
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test2b", "object2", null, {
+ key2: "bar",
+ });
+ // Now check that the snapshot contains the expected data.
+ let snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ false
+ );
+ Assert.ok("parent" in snapshot, "Should have parent events in the snapshot.");
+
+ // For checking event summaries
+ const scalars = Telemetry.getSnapshotForKeyedScalars("main", true);
+ Assert.ok(
+ "parent" in scalars,
+ "Should have parent scalars in the main snapshot."
+ );
+
+ let expected = [
+ [TEST_EVENT_NAME, "test1", "object1"],
+ [TEST_EVENT_NAME, "test2", "object1", null, { key1: "foo", key2: "bar" }],
+ [TEST_EVENT_NAME, "test2b", "object2", null, { key2: "bar" }],
+ ];
+ let events = snapshot.parent;
+ Assert.equal(
+ events.length,
+ expected.length,
+ "Should have recorded the right amount of events."
+ );
+ for (let i = 0; i < expected.length; ++i) {
+ Assert.deepEqual(
+ events[i].slice(1),
+ expected[i],
+ "Should have recorded the expected event data."
+ );
+
+ const uniqueEventName = `${expected[i][0]}#${expected[i][1]}#${expected[i][2]}`;
+ const summaryCount =
+ scalars.parent["telemetry.event_counts"][uniqueEventName];
+ Assert.equal(1, summaryCount, `${uniqueEventName} had wrong summary count`);
+ }
+});
+
+add_task(async function test_dynamicBuiltinEventsDisabledByDefault() {
+ Telemetry.clearEvents();
+ Telemetry.canRecordExtended = true;
+
+ const TEST_EVENT_NAME = "telemetry.test.offbydefault";
+
+ // Register some dynamic builtin test events.
+ Telemetry.registerBuiltinEvents(TEST_EVENT_NAME, {
+ // Event with only required fields.
+ test1: {
+ methods: ["test1"],
+ objects: ["object1"],
+ },
+ });
+
+ // Record some events.
+ // Explicitely _don't_ enable the category
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1");
+
+ // Now check that the snapshot contains the expected data.
+ let snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ false
+ );
+ Assert.ok(
+ !("parent" in snapshot),
+ "Should not have parent events in the snapshot."
+ );
+
+ // Now enable the category and record again
+ Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true);
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1");
+
+ snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ false
+ );
+ Assert.ok("parent" in snapshot, "Should have parent events in the snapshot.");
+
+ let expected = [[TEST_EVENT_NAME, "test1", "object1"]];
+ let events = snapshot.parent;
+ Assert.equal(
+ events.length,
+ expected.length,
+ "Should have recorded the right amount of events."
+ );
+ for (let i = 0; i < expected.length; ++i) {
+ Assert.deepEqual(
+ events[i].slice(1),
+ expected[i],
+ "Should have recorded the expected event data."
+ );
+ }
+});
+
+add_task(async function test_dynamicBuiltinDontOverwriteStaticData() {
+ Telemetry.clearEvents();
+ Telemetry.canRecordExtended = true;
+
+ const TEST_STATIC_EVENT_NAME = "telemetry.test";
+ const TEST_EVENT_NAME = "telemetry.test.nooverwrite";
+
+ // Register some dynamic builtin test events.
+ Telemetry.registerBuiltinEvents(TEST_EVENT_NAME, {
+ dynamic: {
+ methods: ["dynamic"],
+ objects: ["builtin", "anotherone"],
+ },
+ });
+
+ // First enable the categories we're using
+ Telemetry.setEventRecordingEnabled(TEST_STATIC_EVENT_NAME, true);
+ Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true);
+
+ // Now record some dynamic-builtin and static events
+ Telemetry.recordEvent(TEST_EVENT_NAME, "dynamic", "builtin");
+ Telemetry.recordEvent(TEST_STATIC_EVENT_NAME, "test1", "object1");
+ Telemetry.recordEvent(TEST_EVENT_NAME, "dynamic", "anotherone");
+
+ let snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ false
+ );
+ Assert.ok("parent" in snapshot, "Should have parent events in the snapshot.");
+
+ // All events should now be recorded in the right order
+ let expected = [
+ [TEST_EVENT_NAME, "dynamic", "builtin"],
+ [TEST_STATIC_EVENT_NAME, "test1", "object1"],
+ [TEST_EVENT_NAME, "dynamic", "anotherone"],
+ ];
+ let events = snapshot.parent;
+ Assert.equal(
+ events.length,
+ expected.length,
+ "Should have recorded the right amount of events."
+ );
+ for (let i = 0; i < expected.length; ++i) {
+ Assert.deepEqual(
+ events[i].slice(1),
+ expected[i],
+ "Should have recorded the expected event data."
+ );
+ }
+});
+
+add_task(async function test_dynamicBuiltinEventsOverridingStatic() {
+ Telemetry.clearEvents();
+ Telemetry.canRecordExtended = true;
+
+ const TEST_EVENT_NAME = "telemetry.test";
+
+ // Register dynamic builtin test events, overwriting existing one.
+ Telemetry.registerBuiltinEvents(TEST_EVENT_NAME, {
+ // Event with only required fields.
+ test1: {
+ methods: ["test1"],
+ objects: ["object1", "object2"],
+ },
+ // Event with extra_keys.
+ test2: {
+ methods: ["test2"],
+ objects: ["object1", "object2", "object3"],
+ extra_keys: ["key1", "key2", "newdynamickey"],
+ },
+ });
+
+ // Record some events that should be available in the static event already .
+ Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true);
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1");
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object1", null, {
+ key1: "foo",
+ key2: "bar",
+ });
+ // Record events with newly added objects and keys.
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object2", null, {
+ newdynamickey: "foo",
+ });
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object3", null, {
+ key1: "foo",
+ });
+ // Now check that the snapshot contains the expected data.
+ let snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ false
+ );
+ Assert.ok("parent" in snapshot, "Should have parent events in the snapshot.");
+
+ let expected = [
+ [TEST_EVENT_NAME, "test1", "object1"],
+ [TEST_EVENT_NAME, "test2", "object1", null, { key1: "foo", key2: "bar" }],
+ [TEST_EVENT_NAME, "test2", "object2", null, { newdynamickey: "foo" }],
+ [TEST_EVENT_NAME, "test2", "object3", null, { key1: "foo" }],
+ ];
+ let events = snapshot.parent;
+ Assert.equal(
+ events.length,
+ expected.length,
+ "Should have recorded the right amount of events."
+ );
+ for (let i = 0; i < expected.length; ++i) {
+ Assert.deepEqual(
+ events[i].slice(1),
+ expected[i],
+ "Should have recorded the expected event data."
+ );
+ }
+});
+
+add_task(async function test_realDynamicDontOverwrite() {
+ // Real dynamic events follow similar code paths internally.
+ // Let's ensure they trigger the right code path and don't overwrite.
+
+ Telemetry.clearEvents();
+ Telemetry.canRecordExtended = true;
+
+ const TEST_EVENT_NAME = "telemetry.test";
+
+ // Register dynamic test events, this should not overwrite existing ones.
+ Telemetry.registerEvents(TEST_EVENT_NAME, {
+ // Event with only required fields.
+ test1: {
+ methods: ["test1"],
+ objects: ["object1", "object2"],
+ },
+ // Event with extra_keys.
+ test2: {
+ methods: ["test2"],
+ objects: ["object1", "object2", "object3"],
+ extra_keys: ["key1", "key2", "realdynamic"],
+ },
+ });
+
+ // Record some events that should be available in the static event already .
+ Telemetry.setEventRecordingEnabled(TEST_EVENT_NAME, true);
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test1", "object1");
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object1", null, {
+ key1: "foo",
+ key2: "bar",
+ });
+ // Record events with newly added objects and keys.
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object2", null, {
+ realdynamic: "foo",
+ });
+ Telemetry.recordEvent(TEST_EVENT_NAME, "test2", "object3", null, {
+ key1: "foo",
+ });
+ // Now check that the snapshot contains the expected data.
+ let snapshot = Telemetry.snapshotEvents(
+ Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
+ false
+ );
+ Assert.ok("parent" in snapshot, "Should have parent events in the snapshot.");
+
+ let expected = [
+ [TEST_EVENT_NAME, "test1", "object1"],
+ [TEST_EVENT_NAME, "test2", "object1", null, { key1: "foo", key2: "bar" }],
+ [TEST_EVENT_NAME, "test2", "object3", null, { key1: "foo" }],
+ ];
+ let events = snapshot.parent;
+ Assert.equal(
+ events.length,
+ expected.length,
+ "Should have recorded the right amount of events."
+ );
+ for (let i = 0; i < expected.length; ++i) {
+ Assert.deepEqual(
+ events[i].slice(1),
+ expected[i],
+ "Should have recorded the expected event data."
+ );
+ }
+});