diff options
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_EventPing.js')
-rw-r--r-- | toolkit/components/telemetry/tests/unit/test_EventPing.js | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_EventPing.js b/toolkit/components/telemetry/tests/unit/test_EventPing.js new file mode 100644 index 0000000000..450e88a846 --- /dev/null +++ b/toolkit/components/telemetry/tests/unit/test_EventPing.js @@ -0,0 +1,280 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ + */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + TelemetryEventPing: "resource://gre/modules/EventPing.sys.mjs", +}); + +function checkPingStructure(type, payload, options) { + Assert.equal( + type, + TelemetryEventPing.EVENT_PING_TYPE, + "Should be an event ping." + ); + // Check the payload for required fields. + Assert.ok("reason" in payload, "Payload must have reason."); + Assert.ok( + "processStartTimestamp" in payload, + "Payload must have processStartTimestamp." + ); + Assert.ok("sessionId" in payload, "Payload must have sessionId."); + Assert.ok("subsessionId" in payload, "Payload must have subsessionId."); + Assert.ok("lostEventsCount" in payload, "Payload must have lostEventsCount."); + Assert.ok("events" in payload, "Payload must have events."); +} + +function fakePolicy(set, clear, send) { + let { Policy } = ChromeUtils.importESModule( + "resource://gre/modules/EventPing.sys.mjs" + ); + Policy.setTimeout = set; + Policy.clearTimeout = clear; + Policy.sendPing = send; +} + +function pass() { + /* intentionally empty */ +} +function fail() { + Assert.ok(false, "Not allowed"); +} + +function recordEvents(howMany) { + for (let i = 0; i < howMany; i++) { + Telemetry.recordEvent("telemetry.test", "test1", "object1"); + } +} + +add_task(async function setup() { + // Trigger a proper telemetry init. + do_get_profile(true); + // Make sure we don't generate unexpected pings due to pref changes. + await setEmptyPrefWatchlist(); + + await TelemetryController.testSetup(); + TelemetryEventPing.testReset(); + Telemetry.setEventRecordingEnabled("telemetry.test", true); +}); + +// Tests often take the form of faking policy within faked policy. +// This is to allow us to record events in addition to any that were +// recorded to trigger the submit in the first place. +// This works because we start the timer at the top of _submitPing, giving us +// this opportunity. +// This results in things looking this way: +/* +fakePolicy((callback, delay) => { + // Code that runs at the top of _submitPing + fakePolicy(pass, pass, (type, payload, options) => { + // Code that runs at the bottom of _submitPing + }); +}, pass, fail); +// Code that triggers _submitPing to run +*/ + +add_task(async function test_eventLimitReached() { + Telemetry.clearEvents(); + TelemetryEventPing.testReset(); + + let pingCount = 0; + + fakePolicy(pass, pass, fail); + recordEvents(999); + fakePolicy( + (callback, delay) => { + Telemetry.recordEvent("telemetry.test", "test2", "object1"); + fakePolicy(pass, pass, (type, payload, options) => { + checkPingStructure(type, payload, options); + Assert.ok(options.addClientId, "Adds the client id."); + Assert.ok(options.addEnvironment, "Adds the environment."); + Assert.ok(!options.usePingSender, "Doesn't require pingsender."); + Assert.equal( + payload.reason, + TelemetryEventPing.Reason.MAX, + "Sending because we hit max" + ); + Assert.equal( + payload.events.parent.length, + 1000, + "Has one thousand events" + ); + Assert.equal(payload.lostEventsCount, 0, "Lost no events"); + Assert.ok( + !payload.events.parent.some(ev => ev[1] === "test2"), + "Should not have included the final event (yet)." + ); + pingCount++; + }); + }, + pass, + fail + ); + // Now trigger the submit. + Telemetry.recordEvent("telemetry.test", "test1", "object1"); + Assert.equal(pingCount, 1, "Should have sent a ping"); + + // With a recent MAX ping sent, record another max amount of events (and then two extras). + fakePolicy(fail, fail, fail); + recordEvents(998); + fakePolicy( + (callback, delay) => { + Telemetry.recordEvent("telemetry.test", "test2", "object2"); + Telemetry.recordEvent("telemetry.test", "test2", "object2"); + fakePolicy(pass, pass, (type, payload, options) => { + checkPingStructure(type, payload, options); + Assert.ok(options.addClientId, "Adds the client id."); + Assert.ok(options.addEnvironment, "Adds the environment."); + Assert.ok(!options.usePingSender, "Doesn't require pingsender."); + Assert.equal( + payload.reason, + TelemetryEventPing.Reason.MAX, + "Sending because we hit max" + ); + Assert.equal( + payload.events.parent.length, + 1000, + "Has one thousand events" + ); + Assert.equal(payload.lostEventsCount, 2, "Lost two events"); + Assert.equal( + payload.events.parent[0][2], + "test2", + "The first event of the second bunch should be the leftover event of the first bunch." + ); + Assert.ok( + !payload.events.parent.some(ev => ev[3] === "object2"), + "Should not have included any of the lost two events." + ); + pingCount++; + }); + callback(); // Trigger the send immediately. + }, + pass, + fail + ); + recordEvents(1); + Assert.equal(pingCount, 2, "Should have sent a second ping"); + + // Ensure we send a subsequent MAX ping exactly on 1000 events, and without + // the two events we lost. + fakePolicy(fail, fail, fail); + recordEvents(999); + fakePolicy((callback, delay) => { + fakePolicy(pass, pass, (type, payload, options) => { + checkPingStructure(type, payload, options); + Assert.ok(options.addClientId, "Adds the client id."); + Assert.ok(options.addEnvironment, "Adds the environment."); + Assert.ok(!options.usePingSender, "Doesn't require pingsender."); + Assert.equal( + payload.reason, + TelemetryEventPing.Reason.MAX, + "Sending because we hit max" + ); + Assert.equal( + payload.events.parent.length, + 1000, + "Has one thousand events" + ); + Assert.equal(payload.lostEventsCount, 0, "Lost no events"); + Assert.ok( + !payload.events.parent.some(ev => ev[3] === "object2"), + "Should not have included any of the lost two events from the previous bunch." + ); + pingCount++; + }); + callback(); // Trigger the send immediately + }); + recordEvents(1); + Assert.equal(pingCount, 3, "Should have sent a third ping"); +}); + +add_task(async function test_timers() { + Telemetry.clearEvents(); + TelemetryEventPing.testReset(); + + // Immediately after submitting a MAX ping, we should set the timer for the + // next interval. + recordEvents(999); + fakePolicy( + (callback, delay) => { + Assert.equal( + delay, + TelemetryEventPing.minFrequency, + "Timer should be started with the min frequency" + ); + }, + pass, + pass + ); + recordEvents(1); + + fakePolicy( + (callback, delay) => { + Assert.ok( + delay <= TelemetryEventPing.maxFrequency, + "Timer should be at most the max frequency for a subsequent MAX ping." + ); + }, + pass, + pass + ); + recordEvents(1000); +}); + +add_task(async function test_periodic() { + Telemetry.clearEvents(); + TelemetryEventPing.testReset(); + + fakePolicy( + (callback, delay) => { + Assert.equal( + delay, + TelemetryEventPing.minFrequency, + "Timer should default to the min frequency" + ); + fakePolicy(pass, pass, (type, payload, options) => { + checkPingStructure(type, payload, options); + Assert.ok(options.addClientId, "Adds the client id."); + Assert.ok(options.addEnvironment, "Adds the environment."); + Assert.ok(!options.usePingSender, "Doesn't require pingsender."); + Assert.equal( + payload.reason, + TelemetryEventPing.Reason.PERIODIC, + "Sending because we hit a timer" + ); + Assert.equal(payload.events.parent.length, 1, "Has one event"); + Assert.equal(payload.lostEventsCount, 0, "Lost no events"); + }); + callback(); + }, + pass, + fail + ); + + recordEvents(1); + TelemetryEventPing._startTimer(); +}); + +// Ensure this is the final test in the suite, as it shuts things down. +add_task(async function test_shutdown() { + Telemetry.clearEvents(); + TelemetryEventPing.testReset(); + + recordEvents(999); + fakePolicy(pass, pass, (type, payload, options) => { + Assert.ok(options.addClientId, "Adds the client id."); + Assert.ok(options.addEnvironment, "Adds the environment."); + Assert.ok(options.usePingSender, "Asks for pingsender."); + Assert.equal( + payload.reason, + TelemetryEventPing.Reason.SHUTDOWN, + "Sending because we are shutting down" + ); + Assert.equal(payload.events.parent.length, 999, "Has 999 events"); + Assert.equal(payload.lostEventsCount, 0, "No lost events"); + }); + TelemetryEventPing.shutdown(); +}); |