summaryrefslogtreecommitdiff
path: root/toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js')
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js547
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 221b6bcab7..0000000000
--- 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();
-});