diff options
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js')
-rw-r--r-- | toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js | 547 |
1 files changed, 0 insertions, 547 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js b/toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js deleted file mode 100644 index 221b6bcab..000000000 --- a/toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js +++ /dev/null @@ -1,547 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ - -/** - * This test case populates the profile with some fake stored - * pings, and checks that pending pings are immediatlely sent - * after delayed init. - */ - -"use strict" - -Cu.import("resource://gre/modules/osfile.jsm", this); -Cu.import("resource://gre/modules/Services.jsm", this); -Cu.import("resource://gre/modules/Promise.jsm", this); -Cu.import("resource://gre/modules/TelemetryStorage.jsm", this); -Cu.import("resource://gre/modules/TelemetryController.jsm", this); -Cu.import("resource://gre/modules/TelemetrySend.jsm", this); -Cu.import("resource://gre/modules/Task.jsm", this); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -var {OS: {File, Path, Constants}} = Cu.import("resource://gre/modules/osfile.jsm", {}); - -// We increment TelemetryStorage's MAX_PING_FILE_AGE and -// OVERDUE_PING_FILE_AGE by 1 minute so that our test pings exceed -// those points in time, even taking into account file system imprecision. -const ONE_MINUTE_MS = 60 * 1000; -const OVERDUE_PING_FILE_AGE = TelemetrySend.OVERDUE_PING_FILE_AGE + ONE_MINUTE_MS; - -const PING_SAVE_FOLDER = "saved-telemetry-pings"; -const PING_TIMEOUT_LENGTH = 5000; -const OVERDUE_PINGS = 6; -const OLD_FORMAT_PINGS = 4; -const RECENT_PINGS = 4; - -const TOTAL_EXPECTED_PINGS = OVERDUE_PINGS + RECENT_PINGS + OLD_FORMAT_PINGS; - -const PREF_FHR_UPLOAD = "datareporting.healthreport.uploadEnabled"; - -var gCreatedPings = 0; -var gSeenPings = 0; - -/** - * Creates some Telemetry pings for the and saves them to disk. Each ping gets a - * unique ID based on an incrementor. - * - * @param {Array} aPingInfos An array of ping type objects. Each entry must be an - * object containing a "num" field for the number of pings to create and - * an "age" field. The latter representing the age in milliseconds to offset - * from now. A value of 10 would make the ping 10ms older than now, for - * example. - * @returns Promise - * @resolve an Array with the created pings ids. - */ -var createSavedPings = Task.async(function* (aPingInfos) { - let pingIds = []; - let now = Date.now(); - - for (let type in aPingInfos) { - let num = aPingInfos[type].num; - let age = now - (aPingInfos[type].age || 0); - for (let i = 0; i < num; ++i) { - let pingId = yield TelemetryController.addPendingPing("test-ping", {}, { overwrite: true }); - if (aPingInfos[type].age) { - // savePing writes to the file synchronously, so we're good to - // modify the lastModifedTime now. - let filePath = getSavePathForPingId(pingId); - yield File.setDates(filePath, null, age); - } - gCreatedPings++; - pingIds.push(pingId); - } - } - - return pingIds; -}); - -/** - * Deletes locally saved pings if they exist. - * - * @param aPingIds an Array of ping ids to delete. - * @returns Promise - */ -var clearPings = Task.async(function* (aPingIds) { - for (let pingId of aPingIds) { - yield TelemetryStorage.removePendingPing(pingId); - } -}); - -/** - * Fakes the pending pings storage quota. - * @param {Integer} aPendingQuota The new quota, in bytes. - */ -function fakePendingPingsQuota(aPendingQuota) { - let storage = Cu.import("resource://gre/modules/TelemetryStorage.jsm"); - storage.Policy.getPendingPingsQuota = () => aPendingQuota; -} - -/** - * Returns a handle for the file that a ping should be - * stored in locally. - * - * @returns path - */ -function getSavePathForPingId(aPingId) { - return Path.join(Constants.Path.profileDir, PING_SAVE_FOLDER, aPingId); -} - -/** - * Check if the number of Telemetry pings received by the HttpServer is not equal - * to aExpectedNum. - * - * @param aExpectedNum the number of pings we expect to receive. - */ -function assertReceivedPings(aExpectedNum) { - do_check_eq(gSeenPings, aExpectedNum); -} - -/** - * Throws if any pings with the id in aPingIds is saved locally. - * - * @param aPingIds an Array of pings ids to check. - * @returns Promise - */ -var assertNotSaved = Task.async(function* (aPingIds) { - let saved = 0; - for (let id of aPingIds) { - let filePath = getSavePathForPingId(id); - if (yield File.exists(filePath)) { - saved++; - } - } - if (saved > 0) { - do_throw("Found " + saved + " unexpected saved pings."); - } -}); - -/** - * Our handler function for the HttpServer that simply - * increments the gSeenPings global when it successfully - * receives and decodes a Telemetry payload. - * - * @param aRequest the HTTP request sent from HttpServer. - */ -function pingHandler(aRequest) { - gSeenPings++; -} - -add_task(function* test_setup() { - PingServer.start(); - PingServer.registerPingHandler(pingHandler); - do_get_profile(); - loadAddonManager("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); - // Make sure we don't generate unexpected pings due to pref changes. - yield setEmptyPrefWatchlist(); - - Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true); - Services.prefs.setCharPref(TelemetryController.Constants.PREF_SERVER, - "http://localhost:" + PingServer.port); -}); - -/** - * Setup the tests by making sure the ping storage directory is available, otherwise - * |TelemetryController.testSaveDirectoryToFile| could fail. - */ -add_task(function* setupEnvironment() { - // The following tests assume this pref to be true by default. - Services.prefs.setBoolPref(PREF_FHR_UPLOAD, true); - - yield TelemetryController.testSetup(); - - let directory = TelemetryStorage.pingDirectoryPath; - yield File.makeDir(directory, { ignoreExisting: true, unixMode: OS.Constants.S_IRWXU }); - - yield TelemetryStorage.testClearPendingPings(); -}); - -/** - * Test that really recent pings are sent on Telemetry initialization. - */ -add_task(function* test_recent_pings_sent() { - let pingTypes = [{ num: RECENT_PINGS }]; - yield createSavedPings(pingTypes); - - yield TelemetryController.testReset(); - yield TelemetrySend.testWaitOnOutgoingPings(); - assertReceivedPings(RECENT_PINGS); - - yield TelemetryStorage.testClearPendingPings(); -}); - -/** - * Create an overdue ping in the old format and try to send it. - */ -add_task(function* test_overdue_old_format() { - // A test ping in the old, standard format. - const PING_OLD_FORMAT = { - slug: "1234567abcd", - reason: "test-ping", - payload: { - info: { - reason: "test-ping", - OS: "XPCShell", - appID: "SomeId", - appVersion: "1.0", - appName: "XPCShell", - appBuildID: "123456789", - appUpdateChannel: "Test", - platformBuildID: "987654321", - }, - }, - }; - - // A ping with no info section, but with a slug. - const PING_NO_INFO = { - slug: "1234-no-info-ping", - reason: "test-ping", - payload: {} - }; - - // A ping with no payload. - const PING_NO_PAYLOAD = { - slug: "5678-no-payload", - reason: "test-ping", - }; - - // A ping with no info and no slug. - const PING_NO_SLUG = { - reason: "test-ping", - payload: {} - }; - - const PING_FILES_PATHS = [ - getSavePathForPingId(PING_OLD_FORMAT.slug), - getSavePathForPingId(PING_NO_INFO.slug), - getSavePathForPingId(PING_NO_PAYLOAD.slug), - getSavePathForPingId("no-slug-file"), - ]; - - // Write the ping to file and make it overdue. - yield TelemetryStorage.savePing(PING_OLD_FORMAT, true); - yield TelemetryStorage.savePing(PING_NO_INFO, true); - yield TelemetryStorage.savePing(PING_NO_PAYLOAD, true); - yield TelemetryStorage.savePingToFile(PING_NO_SLUG, PING_FILES_PATHS[3], true); - - for (let f in PING_FILES_PATHS) { - yield File.setDates(PING_FILES_PATHS[f], null, Date.now() - OVERDUE_PING_FILE_AGE); - } - - gSeenPings = 0; - yield TelemetryController.testReset(); - yield TelemetrySend.testWaitOnOutgoingPings(); - assertReceivedPings(OLD_FORMAT_PINGS); - - // |TelemetryStorage.cleanup| doesn't know how to remove a ping with no slug or id, - // so remove it manually so that the next test doesn't fail. - yield OS.File.remove(PING_FILES_PATHS[3]); - - yield TelemetryStorage.testClearPendingPings(); -}); - -add_task(function* test_corrupted_pending_pings() { - const TEST_TYPE = "test_corrupted"; - - Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_READ").clear(); - Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_PARSE").clear(); - - // Save a pending ping and get its id. - let pendingPingId = yield TelemetryController.addPendingPing(TEST_TYPE, {}, {}); - - // Try to load it: there should be no error. - yield TelemetryStorage.loadPendingPing(pendingPingId); - - let h = Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_READ").snapshot(); - Assert.equal(h.sum, 0, "Telemetry must not report a pending ping load failure"); - h = Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_PARSE").snapshot(); - Assert.equal(h.sum, 0, "Telemetry must not report a pending ping parse failure"); - - // Delete it from the disk, so that its id will be kept in the cache but it will - // fail loading the file. - yield OS.File.remove(getSavePathForPingId(pendingPingId)); - - // Try to load a pending ping which isn't there anymore. - yield Assert.rejects(TelemetryStorage.loadPendingPing(pendingPingId), - "Telemetry must fail loading a ping which isn't there"); - - h = Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_READ").snapshot(); - Assert.equal(h.sum, 1, "Telemetry must report a pending ping load failure"); - h = Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_PARSE").snapshot(); - Assert.equal(h.sum, 0, "Telemetry must not report a pending ping parse failure"); - - // Save a new ping, so that it gets in the pending pings cache. - pendingPingId = yield TelemetryController.addPendingPing(TEST_TYPE, {}, {}); - // Overwrite it with a corrupted JSON file and then try to load it. - const INVALID_JSON = "{ invalid,JSON { {1}"; - yield OS.File.writeAtomic(getSavePathForPingId(pendingPingId), INVALID_JSON, { encoding: "utf-8" }); - - // Try to load the ping with the corrupted JSON content. - yield Assert.rejects(TelemetryStorage.loadPendingPing(pendingPingId), - "Telemetry must fail loading a corrupted ping"); - - h = Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_READ").snapshot(); - Assert.equal(h.sum, 1, "Telemetry must report a pending ping load failure"); - h = Telemetry.getHistogramById("TELEMETRY_PENDING_LOAD_FAILURE_PARSE").snapshot(); - Assert.equal(h.sum, 1, "Telemetry must report a pending ping parse failure"); - - let exists = yield OS.File.exists(getSavePathForPingId(pendingPingId)); - Assert.ok(!exists, "The unparseable ping should have been removed"); - - yield TelemetryStorage.testClearPendingPings(); -}); - -/** - * Create some recent and overdue pings and verify that they get sent. - */ -add_task(function* test_overdue_pings_trigger_send() { - let pingTypes = [ - { num: RECENT_PINGS }, - { num: OVERDUE_PINGS, age: OVERDUE_PING_FILE_AGE }, - ]; - let pings = yield createSavedPings(pingTypes); - let recentPings = pings.slice(0, RECENT_PINGS); - let overduePings = pings.slice(-OVERDUE_PINGS); - - yield TelemetryController.testReset(); - yield TelemetrySend.testWaitOnOutgoingPings(); - assertReceivedPings(TOTAL_EXPECTED_PINGS); - - yield assertNotSaved(recentPings); - yield assertNotSaved(overduePings); - - Assert.equal(TelemetrySend.overduePingsCount, overduePings.length, - "Should have tracked the correct amount of overdue pings"); - - yield TelemetryStorage.testClearPendingPings(); -}); - -/** - * Create a ping in the old format, send it, and make sure the request URL contains - * the correct version query parameter. - */ -add_task(function* test_overdue_old_format() { - // A test ping in the old, standard format. - const PING_OLD_FORMAT = { - slug: "1234567abcd", - reason: "test-ping", - payload: { - info: { - reason: "test-ping", - OS: "XPCShell", - appID: "SomeId", - appVersion: "1.0", - appName: "XPCShell", - appBuildID: "123456789", - appUpdateChannel: "Test", - platformBuildID: "987654321", - }, - }, - }; - - const filePath = - Path.join(Constants.Path.profileDir, PING_SAVE_FOLDER, PING_OLD_FORMAT.slug); - - // Write the ping to file and make it overdue. - yield TelemetryStorage.savePing(PING_OLD_FORMAT, true); - yield File.setDates(filePath, null, Date.now() - OVERDUE_PING_FILE_AGE); - - let receivedPings = 0; - // Register a new prefix handler to validate the URL. - PingServer.registerPingHandler(request => { - // Check that we have a version query parameter in the URL. - Assert.notEqual(request.queryString, ""); - - // Make sure the version in the query string matches the old ping format version. - let params = request.queryString.split("&"); - Assert.ok(params.find(p => p == "v=1")); - - receivedPings++; - }); - - yield TelemetryController.testReset(); - yield TelemetrySend.testWaitOnOutgoingPings(); - Assert.equal(receivedPings, 1, "We must receive a ping in the old format."); - - yield TelemetryStorage.testClearPendingPings(); - PingServer.resetPingHandler(); -}); - -add_task(function* test_pendingPingsQuota() { - const PING_TYPE = "foo"; - - // Disable upload so pings don't get sent and removed from the pending pings directory. - Services.prefs.setBoolPref(PREF_FHR_UPLOAD, false); - - // Remove all the pending pings then startup and wait for the cleanup task to complete. - // There should be nothing to remove. - yield TelemetryStorage.testClearPendingPings(); - yield TelemetryController.testReset(); - yield TelemetrySend.testWaitOnOutgoingPings(); - yield TelemetryStorage.testPendingQuotaTaskPromise(); - - // Remove the pending deletion ping generated when flipping FHR upload off. - yield TelemetryStorage.testClearPendingPings(); - - let expectedPrunedPings = []; - let expectedNotPrunedPings = []; - - let checkPendingPings = Task.async(function*() { - // Check that the pruned pings are not on disk anymore. - for (let prunedPingId of expectedPrunedPings) { - yield Assert.rejects(TelemetryStorage.loadPendingPing(prunedPingId), - "Ping " + prunedPingId + " should have been pruned."); - const pingPath = getSavePathForPingId(prunedPingId); - Assert.ok(!(yield OS.File.exists(pingPath)), "The ping should not be on the disk anymore."); - } - - // Check that the expected pings are there. - for (let expectedPingId of expectedNotPrunedPings) { - Assert.ok((yield TelemetryStorage.loadPendingPing(expectedPingId)), - "Ping" + expectedPingId + " should be among the pending pings."); - } - }); - - let pendingPingsInfo = []; - let pingsSizeInBytes = 0; - - // Create 10 pings to test the pending pings quota. - for (let days = 1; days < 11; days++) { - const date = fakeNow(2010, 1, days, 1, 1, 0); - const pingId = yield TelemetryController.addPendingPing(PING_TYPE, {}, {}); - - // Find the size of the ping. - const pingFilePath = getSavePathForPingId(pingId); - const pingSize = (yield OS.File.stat(pingFilePath)).size; - // Add the info at the beginning of the array, so that most recent pings come first. - pendingPingsInfo.unshift({id: pingId, size: pingSize, timestamp: date.getTime() }); - - // Set the last modification date. - yield OS.File.setDates(pingFilePath, null, date.getTime()); - - // Add it to the pending ping directory size. - pingsSizeInBytes += pingSize; - } - - // We need to test the pending pings size before we hit the quota, otherwise a special - // value is recorded. - Telemetry.getHistogramById("TELEMETRY_PENDING_PINGS_SIZE_MB").clear(); - Telemetry.getHistogramById("TELEMETRY_PENDING_PINGS_EVICTED_OVER_QUOTA").clear(); - Telemetry.getHistogramById("TELEMETRY_PENDING_EVICTING_OVER_QUOTA_MS").clear(); - - yield TelemetryController.testReset(); - yield TelemetryStorage.testPendingQuotaTaskPromise(); - - // Check that the correct values for quota probes are reported when no quota is hit. - let h = Telemetry.getHistogramById("TELEMETRY_PENDING_PINGS_SIZE_MB").snapshot(); - Assert.equal(h.sum, Math.round(pingsSizeInBytes / 1024 / 1024), - "Telemetry must report the correct pending pings directory size."); - h = Telemetry.getHistogramById("TELEMETRY_PENDING_PINGS_EVICTED_OVER_QUOTA").snapshot(); - Assert.equal(h.sum, 0, "Telemetry must report 0 evictions if quota is not hit."); - h = Telemetry.getHistogramById("TELEMETRY_PENDING_EVICTING_OVER_QUOTA_MS").snapshot(); - Assert.equal(h.sum, 0, "Telemetry must report a null elapsed time if quota is not hit."); - - // Set the quota to 80% of the space. - const testQuotaInBytes = pingsSizeInBytes * 0.8; - fakePendingPingsQuota(testQuotaInBytes); - - // The storage prunes pending pings until we reach 90% of the requested storage quota. - // Based on that, find how many pings should be kept. - const safeQuotaSize = Math.round(testQuotaInBytes * 0.9); - let sizeInBytes = 0; - let pingsWithinQuota = []; - let pingsOutsideQuota = []; - - for (let pingInfo of pendingPingsInfo) { - sizeInBytes += pingInfo.size; - if (sizeInBytes >= safeQuotaSize) { - pingsOutsideQuota.push(pingInfo.id); - continue; - } - pingsWithinQuota.push(pingInfo.id); - } - - expectedNotPrunedPings = pingsWithinQuota; - expectedPrunedPings = pingsOutsideQuota; - - // Reset TelemetryController to start the pending pings cleanup. - yield TelemetryController.testReset(); - yield TelemetryStorage.testPendingQuotaTaskPromise(); - yield checkPendingPings(); - - h = Telemetry.getHistogramById("TELEMETRY_PENDING_PINGS_EVICTED_OVER_QUOTA").snapshot(); - Assert.equal(h.sum, pingsOutsideQuota.length, - "Telemetry must correctly report the over quota pings evicted from the pending pings directory."); - h = Telemetry.getHistogramById("TELEMETRY_PENDING_PINGS_SIZE_MB").snapshot(); - Assert.equal(h.sum, 17, "Pending pings quota was hit, a special size must be reported."); - - // Trigger a cleanup again and make sure we're not removing anything. - yield TelemetryController.testReset(); - yield TelemetryStorage.testPendingQuotaTaskPromise(); - yield checkPendingPings(); - - const OVERSIZED_PING_ID = "9b21ec8f-f762-4d28-a2c1-44e1c4694f24"; - // Create a pending oversized ping. - 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: generateRandomString(2 * 1024 * 1024), - }; - yield TelemetryStorage.savePendingPing(OVERSIZED_PING); - - // Reset the histograms. - Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_PENDING").clear(); - Telemetry.getHistogramById("TELEMETRY_DISCARDED_PENDING_PINGS_SIZE_MB").clear(); - - // Try to manually load the oversized ping. - yield Assert.rejects(TelemetryStorage.loadPendingPing(OVERSIZED_PING_ID), - "The oversized ping should have been pruned."); - Assert.ok(!(yield OS.File.exists(getSavePathForPingId(OVERSIZED_PING_ID))), - "The ping should not be on the disk anymore."); - - // Make sure we're correctly updating the related histograms. - h = Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_PENDING").snapshot(); - Assert.equal(h.sum, 1, "Telemetry must report 1 oversized ping in the pending pings directory."); - h = Telemetry.getHistogramById("TELEMETRY_DISCARDED_PENDING_PINGS_SIZE_MB").snapshot(); - Assert.equal(h.counts[2], 1, "Telemetry must report a 2MB, oversized, ping."); - - // Save the ping again to check if it gets pruned when scanning the pings directory. - yield TelemetryStorage.savePendingPing(OVERSIZED_PING); - expectedPrunedPings.push(OVERSIZED_PING_ID); - - // Scan the pending pings directory. - yield TelemetryController.testReset(); - yield TelemetryStorage.testPendingQuotaTaskPromise(); - yield checkPendingPings(); - - // Make sure we're correctly updating the related histograms. - h = Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_PENDING").snapshot(); - Assert.equal(h.sum, 2, "Telemetry must report 1 oversized ping in the pending pings directory."); - h = Telemetry.getHistogramById("TELEMETRY_DISCARDED_PENDING_PINGS_SIZE_MB").snapshot(); - Assert.equal(h.counts[2], 2, "Telemetry must report two 2MB, oversized, pings."); - - Services.prefs.setBoolPref(PREF_FHR_UPLOAD, true); -}); - -add_task(function* teardown() { - yield PingServer.stop(); -}); |