diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /toolkit/components/telemetry/tests/unit/test_HealthPing.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_HealthPing.js')
-rw-r--r-- | toolkit/components/telemetry/tests/unit/test_HealthPing.js | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_HealthPing.js b/toolkit/components/telemetry/tests/unit/test_HealthPing.js new file mode 100644 index 0000000000..b922a07f47 --- /dev/null +++ b/toolkit/components/telemetry/tests/unit/test_HealthPing.js @@ -0,0 +1,279 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// This tests the public Telemetry API for submitting Health pings. + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + TelemetryHealthPing: "resource://gre/modules/HealthPing.sys.mjs", +}); + +function checkHealthPingStructure(ping, expectedFailuresDict) { + let payload = ping.payload; + Assert.equal( + ping.type, + TelemetryHealthPing.HEALTH_PING_TYPE, + "Should have recorded a health ping." + ); + + for (let [key, value] of Object.entries(expectedFailuresDict)) { + Assert.deepEqual( + payload[key], + value, + "Should have recorded correct entry with key: " + key + ); + } +} + +function fakeHealthSchedulerTimer(set, clear) { + let { Policy } = ChromeUtils.importESModule( + "resource://gre/modules/HealthPing.sys.mjs" + ); + Policy.setSchedulerTickTimeout = set; + Policy.clearSchedulerTickTimeout = clear; +} + +add_setup(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(); + Preferences.set(TelemetryUtils.Preferences.HealthPingEnabled, true); + + await TelemetryController.testSetup(); + PingServer.start(); + TelemetrySend.setServer("http://localhost:" + PingServer.port); + Preferences.set( + TelemetryUtils.Preferences.Server, + "http://localhost:" + PingServer.port + ); +}); + +registerCleanupFunction(async function cleanup() { + await PingServer.stop(); +}); + +add_task(async function test_sendImmediately() { + PingServer.clearRequests(); + TelemetryHealthPing.testReset(); + + await TelemetryHealthPing.recordSendFailure("testProblem"); + let ping = await PingServer.promiseNextPing(); + checkHealthPingStructure(ping, { + [TelemetryHealthPing.FailureType.SEND_FAILURE]: { + testProblem: 1, + }, + os: TelemetryHealthPing.OsInfo, + reason: TelemetryHealthPing.Reason.IMMEDIATE, + }); +}); + +add_task(async function test_sendOnDelay() { + PingServer.clearRequests(); + TelemetryHealthPing.testReset(); + + // This first failure should immediately trigger a ping. After this, subsequent failures should be throttled. + await TelemetryHealthPing.recordSendFailure("testFailure"); + let testPing = await PingServer.promiseNextPing(); + Assert.equal( + testPing.type, + TelemetryHealthPing.HEALTH_PING_TYPE, + "Should have recorded a health ping." + ); + + // Retrieve delayed call back. + let pingSubmissionCallBack = null; + fakeHealthSchedulerTimer( + callBack => (pingSubmissionCallBack = callBack), + () => {} + ); + + // Record two failures, health ping must not be send now. + await TelemetryHealthPing.recordSendFailure("testFailure"); + await TelemetryHealthPing.recordSendFailure("testFailure"); + + // Wait for sending delayed health ping. + await pingSubmissionCallBack(); + + let ping = await PingServer.promiseNextPing(); + checkHealthPingStructure(ping, { + [TelemetryHealthPing.FailureType.SEND_FAILURE]: { + testFailure: 2, + }, + os: TelemetryHealthPing.OsInfo, + reason: TelemetryHealthPing.Reason.DELAYED, + }); +}); + +add_task(async function test_sendOverSizedPing() { + TelemetryHealthPing.testReset(); + PingServer.clearRequests(); + let OVER_SIZED_PING_TYPE = "over-sized-ping"; + let overSizedData = generateRandomString(2 * 1024 * 1024); + + await TelemetryController.submitExternalPing(OVER_SIZED_PING_TYPE, { + data: overSizedData, + }); + let ping = await PingServer.promiseNextPing(); + + checkHealthPingStructure(ping, { + [TelemetryHealthPing.FailureType.DISCARDED_FOR_SIZE]: { + [OVER_SIZED_PING_TYPE]: 1, + }, + os: TelemetryHealthPing.OsInfo, + reason: TelemetryHealthPing.Reason.IMMEDIATE, + }); +}); + +add_task(async function test_sendOnlyTopTenDiscardedPings() { + TelemetryHealthPing.testReset(); + await TelemetrySend.reset(); + PingServer.clearRequests(); + let PING_TYPE = "sort-discarded"; + + // This first failure should immediately trigger a ping. After this, subsequent failures should be throttled. + await TelemetryHealthPing.recordSendFailure("testFailure"); + let testPing = await PingServer.promiseNextPing(); + Assert.equal( + testPing.type, + TelemetryHealthPing.HEALTH_PING_TYPE, + "Should have recorded a health ping." + ); + + // Retrieve delayed call back. + let pingSubmissionCallBack = null; + fakeHealthSchedulerTimer( + callBack => (pingSubmissionCallBack = callBack), + () => {} + ); + + // Add failures + for (let i = 1; i < 12; i++) { + for (let j = 1; j < i; j++) { + TelemetryHealthPing.recordDiscardedPing(PING_TYPE + i); + } + } + + await TelemetrySend.reset(); + await pingSubmissionCallBack(); + let ping = await PingServer.promiseNextPing(); + + checkHealthPingStructure(ping, { + os: TelemetryHealthPing.OsInfo, + reason: TelemetryHealthPing.Reason.DELAYED, + [TelemetryHealthPing.FailureType.DISCARDED_FOR_SIZE]: { + [PING_TYPE + 11]: 10, + [PING_TYPE + 10]: 9, + [PING_TYPE + 9]: 8, + [PING_TYPE + 8]: 7, + [PING_TYPE + 7]: 6, + [PING_TYPE + 6]: 5, + [PING_TYPE + 5]: 4, + [PING_TYPE + 4]: 3, + [PING_TYPE + 3]: 2, + [PING_TYPE + 2]: 1, + }, + }); +}); + +add_task(async function test_discardedForSizePending() { + TelemetryHealthPing.testReset(); + PingServer.clearRequests(); + + const PING_TYPE = "discarded-for-size-pending"; + + const OVERSIZED_PING_ID = "9b21ec8f-f762-4d28-a2c1-44e1c4694f24"; + // Create a pending oversized ping. + let overSizedPayload = generateRandomString(2 * 1024 * 1024); + const OVERSIZED_PING = { + id: OVERSIZED_PING_ID, + type: PING_TYPE, + creationDate: new Date().toISOString(), + // Generate a 2MB string to use as the ping payload. + payload: overSizedPayload, + }; + + // Test loadPendingPing. + await TelemetryStorage.savePendingPing(OVERSIZED_PING); + // Try to manually load the oversized ping. + await Assert.rejects( + TelemetryStorage.loadPendingPing(OVERSIZED_PING_ID), + /loadPendingPing - exceeded the maximum ping size/, + "The oversized ping should have been pruned." + ); + + let ping = await PingServer.promiseNextPing(); + checkHealthPingStructure(ping, { + [TelemetryHealthPing.FailureType.DISCARDED_FOR_SIZE]: { + "<unknown>": 1, + }, + os: TelemetryHealthPing.OsInfo, + reason: TelemetryHealthPing.Reason.IMMEDIATE, + }); + + // Test _scanPendingPings. + TelemetryHealthPing.testReset(); + await TelemetryStorage.savePendingPing(OVERSIZED_PING); + await TelemetryStorage.loadPendingPingList(); + + ping = await PingServer.promiseNextPing(); + checkHealthPingStructure(ping, { + [TelemetryHealthPing.FailureType.DISCARDED_FOR_SIZE]: { + "<unknown>": 1, + }, + os: TelemetryHealthPing.OsInfo, + reason: TelemetryHealthPing.Reason.IMMEDIATE, + }); +}); + +add_task(async function test_usePingSenderOnShutdown() { + if ( + gIsAndroid || + (AppConstants.platform == "linux" && !Services.appinfo.is64Bit) + ) { + // We don't support the pingsender on Android, yet, see bug 1335917. + // We also don't support the pingsender testing on Treeherder for + // Linux 32 bit (due to missing libraries). So skip it there too. + // See bug 1310703 comment 78. + return; + } + + TelemetryHealthPing.testReset(); + await TelemetrySend.reset(); + PingServer.clearRequests(); + + // This first failure should immediately trigger a ping. + // After this, subsequent failures should be throttled. + await TelemetryHealthPing.recordSendFailure("testFailure"); + await PingServer.promiseNextPing(); + + TelemetryHealthPing.recordSendFailure("testFailure"); + let nextRequest = PingServer.promiseNextRequest(); + + await TelemetryController.testReset(); + await TelemetryController.testShutdown(); + let request = await nextRequest; + let ping = decodeRequestPayload(request); + + checkHealthPingStructure(ping, { + [TelemetryHealthPing.FailureType.SEND_FAILURE]: { + testFailure: 1, + }, + os: TelemetryHealthPing.OsInfo, + reason: TelemetryHealthPing.Reason.SHUT_DOWN, + }); + + // Check that the health ping is sent at shutdown using the pingsender. + Assert.equal( + request.getHeader("User-Agent"), + "pingsender/1.0", + "Should have received the correct user agent string." + ); + Assert.equal( + request.getHeader("X-PingSender-Version"), + "1.0", + "Should have received the correct PingSender version string." + ); +}); |