summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/tests/unit/test_PingAPI.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_PingAPI.js')
-rw-r--r--toolkit/components/telemetry/tests/unit/test_PingAPI.js502
1 files changed, 0 insertions, 502 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_PingAPI.js b/toolkit/components/telemetry/tests/unit/test_PingAPI.js
deleted file mode 100644
index d4d79aad4..000000000
--- a/toolkit/components/telemetry/tests/unit/test_PingAPI.js
+++ /dev/null
@@ -1,502 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-*/
-
-// This tests the public Telemetry API for submitting pings.
-
-"use strict";
-
-Cu.import("resource://gre/modules/ClientID.jsm", this);
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetryArchive.jsm", this);
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-Cu.import("resource://gre/modules/osfile.jsm", this);
-Cu.import("resource://gre/modules/Task.jsm", this);
-Cu.import("resource://gre/modules/Services.jsm", this);
-
-XPCOMUtils.defineLazyGetter(this, "gPingsArchivePath", function() {
- return OS.Path.join(OS.Constants.Path.profileDir, "datareporting", "archived");
-});
-
-/**
- * Fakes the archive storage quota.
- * @param {Integer} aArchiveQuota The new quota, in bytes.
- */
-function fakeStorageQuota(aArchiveQuota) {
- let storage = Cu.import("resource://gre/modules/TelemetryStorage.jsm");
- storage.Policy.getArchiveQuota = () => aArchiveQuota;
-}
-
-/**
- * Lists all the valid archived pings and their metadata, sorted by creation date.
- *
- * @param aFileName {String} The filename.
- * @return {Object[]} A list of objects with the extracted data in the form:
- * { timestamp: <number>,
- * id: <string>,
- * type: <string>,
- * size: <integer> }
- */
-var getArchivedPingsInfo = Task.async(function*() {
- let dirIterator = new OS.File.DirectoryIterator(gPingsArchivePath);
- let subdirs = (yield dirIterator.nextBatch()).filter(e => e.isDir);
- let archivedPings = [];
-
- // Iterate through the subdirs of |gPingsArchivePath|.
- for (let dir of subdirs) {
- let fileIterator = new OS.File.DirectoryIterator(dir.path);
- let files = (yield fileIterator.nextBatch()).filter(e => !e.isDir);
-
- // Then get a list of the files for the current subdir.
- for (let f of files) {
- let pingInfo = TelemetryStorage._testGetArchivedPingDataFromFileName(f.name);
- if (!pingInfo) {
- // This is not a valid archived ping, skip it.
- continue;
- }
- // Find the size of the ping and then add the info to the array.
- pingInfo.size = (yield OS.File.stat(f.path)).size;
- archivedPings.push(pingInfo);
- }
- }
-
- // Sort the list by creation date and then return it.
- archivedPings.sort((a, b) => b.timestamp - a.timestamp);
- return archivedPings;
-});
-
-add_task(function* test_setup() {
- do_get_profile(true);
- // Make sure we don't generate unexpected pings due to pref changes.
- yield setEmptyPrefWatchlist();
- Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
-});
-
-add_task(function* test_archivedPings() {
- // TelemetryController should not be fully initialized at this point.
- // Submitting pings should still work fine.
-
- const PINGS = [
- {
- type: "test-ping-api-1",
- payload: { foo: "bar"},
- dateCreated: new Date(2010, 1, 1, 10, 0, 0),
- },
- {
- type: "test-ping-api-2",
- payload: { moo: "meh"},
- dateCreated: new Date(2010, 2, 1, 10, 0, 0),
- },
- ];
-
- // Submit pings and check the ping list.
- let expectedPingList = [];
-
- for (let data of PINGS) {
- fakeNow(data.dateCreated);
- data.id = yield TelemetryController.submitExternalPing(data.type, data.payload);
- let list = yield TelemetryArchive.promiseArchivedPingList();
-
- expectedPingList.push({
- id: data.id,
- type: data.type,
- timestampCreated: data.dateCreated.getTime(),
- });
- Assert.deepEqual(list, expectedPingList, "Archived ping list should contain submitted pings");
- }
-
- // Check loading the archived pings.
- let checkLoadingPings = Task.async(function*() {
- for (let data of PINGS) {
- let ping = yield TelemetryArchive.promiseArchivedPingById(data.id);
- Assert.equal(ping.id, data.id, "Archived ping should have matching id");
- Assert.equal(ping.type, data.type, "Archived ping should have matching type");
- Assert.equal(ping.creationDate, data.dateCreated.toISOString(),
- "Archived ping should have matching creation date");
- }
- });
-
- yield checkLoadingPings();
-
- // Check that we find the archived pings again by scanning after a restart.
- yield TelemetryController.testReset();
-
- let pingList = yield TelemetryArchive.promiseArchivedPingList();
- Assert.deepEqual(expectedPingList, pingList,
- "Should have submitted pings in archive list after restart");
- yield checkLoadingPings();
-
- // Write invalid pings into the archive with both valid and invalid names.
- let writeToArchivedDir = Task.async(function*(dirname, filename, content, compressed) {
- const dirPath = OS.Path.join(gPingsArchivePath, dirname);
- yield OS.File.makeDir(dirPath, { ignoreExisting: true });
- const filePath = OS.Path.join(dirPath, filename);
- const options = { tmpPath: filePath + ".tmp", noOverwrite: false };
- if (compressed) {
- options.compression = "lz4";
- }
- yield OS.File.writeAtomic(filePath, content, options);
- });
-
- const FAKE_ID1 = "10000000-0123-0123-0123-0123456789a1";
- const FAKE_ID2 = "20000000-0123-0123-0123-0123456789a2";
- const FAKE_ID3 = "20000000-0123-0123-0123-0123456789a3";
- const FAKE_TYPE = "foo";
-
- // These should get rejected.
- yield writeToArchivedDir("xx", "foo.json", "{}");
- yield writeToArchivedDir("2010-02", "xx.xx.xx.json", "{}");
- // This one should get picked up...
- yield writeToArchivedDir("2010-02", "1." + FAKE_ID1 + "." + FAKE_TYPE + ".json", "{}");
- // ... but get overwritten by this one.
- yield writeToArchivedDir("2010-02", "2." + FAKE_ID1 + "." + FAKE_TYPE + ".json", "");
- // This should get picked up fine.
- yield writeToArchivedDir("2010-02", "3." + FAKE_ID2 + "." + FAKE_TYPE + ".json", "");
- // This compressed ping should get picked up fine as well.
- yield writeToArchivedDir("2010-02", "4." + FAKE_ID3 + "." + FAKE_TYPE + ".jsonlz4", "");
-
- expectedPingList.push({
- id: FAKE_ID1,
- type: "foo",
- timestampCreated: 2,
- });
- expectedPingList.push({
- id: FAKE_ID2,
- type: "foo",
- timestampCreated: 3,
- });
- expectedPingList.push({
- id: FAKE_ID3,
- type: "foo",
- timestampCreated: 4,
- });
- expectedPingList.sort((a, b) => a.timestampCreated - b.timestampCreated);
-
- // Reset the TelemetryArchive so we scan the archived dir again.
- yield TelemetryController.testReset();
-
- // Check that we are still picking up the valid archived pings on disk,
- // plus the valid ones above.
- pingList = yield TelemetryArchive.promiseArchivedPingList();
- Assert.deepEqual(expectedPingList, pingList, "Should have picked up valid archived pings");
- yield checkLoadingPings();
-
- // Now check that we fail to load the two invalid pings from above.
- Assert.ok((yield promiseRejects(TelemetryArchive.promiseArchivedPingById(FAKE_ID1))),
- "Should have rejected invalid ping");
- Assert.ok((yield promiseRejects(TelemetryArchive.promiseArchivedPingById(FAKE_ID2))),
- "Should have rejected invalid ping");
-});
-
-add_task(function* test_archiveCleanup() {
- const PING_TYPE = "foo";
-
- // Empty the archive.
- yield OS.File.removeDir(gPingsArchivePath);
-
- Telemetry.getHistogramById("TELEMETRY_ARCHIVE_SCAN_PING_COUNT").clear();
- Telemetry.getHistogramById("TELEMETRY_ARCHIVE_DIRECTORIES_COUNT").clear();
- // Also reset these histograms to make sure normal sized pings don't get counted.
- Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_ARCHIVED").clear();
- Telemetry.getHistogramById("TELEMETRY_DISCARDED_ARCHIVED_PINGS_SIZE_MB").clear();
-
- // Build the cache. Nothing should be evicted as there's no ping directory.
- yield TelemetryController.testReset();
- yield TelemetryStorage.testCleanupTaskPromise();
- yield TelemetryArchive.promiseArchivedPingList();
-
- let h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_SCAN_PING_COUNT").snapshot();
- Assert.equal(h.sum, 0, "Telemetry must report 0 pings scanned if no archive dir exists.");
- // One directory out of four was removed as well.
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_EVICTED_OLD_DIRS").snapshot();
- Assert.equal(h.sum, 0, "Telemetry must report 0 evicted dirs if no archive dir exists.");
-
- let expectedPrunedInfo = [];
- let expectedNotPrunedInfo = [];
-
- let checkArchive = Task.async(function*() {
- // Check that the pruned pings are not on disk anymore.
- for (let prunedInfo of expectedPrunedInfo) {
- yield Assert.rejects(TelemetryArchive.promiseArchivedPingById(prunedInfo.id),
- "Ping " + prunedInfo.id + " should have been pruned.");
- const pingPath =
- TelemetryStorage._testGetArchivedPingPath(prunedInfo.id, prunedInfo.creationDate, PING_TYPE);
- 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 expectedInfo of expectedNotPrunedInfo) {
- Assert.ok((yield TelemetryArchive.promiseArchivedPingById(expectedInfo.id)),
- "Ping" + expectedInfo.id + " should be in the archive.");
- }
- });
-
- Telemetry.getHistogramById("TELEMETRY_ARCHIVE_SESSION_PING_COUNT").clear();
-
- // Create a ping which should be pruned because it is past the retention period.
- let date = fakeNow(2010, 1, 1, 1, 0, 0);
- let firstDate = date;
- let pingId = yield TelemetryController.submitExternalPing(PING_TYPE, {}, {});
- expectedPrunedInfo.push({ id: pingId, creationDate: date });
-
- // Create a ping which should be kept because it is within the retention period.
- const oldestDirectoryDate = fakeNow(2010, 2, 1, 1, 0, 0);
- pingId = yield TelemetryController.submitExternalPing(PING_TYPE, {}, {});
- expectedNotPrunedInfo.push({ id: pingId, creationDate: oldestDirectoryDate });
-
- // Create 20 other pings which are within the retention period, but would be affected
- // by the disk quota.
- for (let month of [3, 4]) {
- for (let minute = 0; minute < 10; minute++) {
- date = fakeNow(2010, month, 1, 1, minute, 0);
- pingId = yield TelemetryController.submitExternalPing(PING_TYPE, {}, {});
- expectedNotPrunedInfo.push({ id: pingId, creationDate: date });
- }
- }
-
- // We expect all the pings we archived to be in this histogram.
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_SESSION_PING_COUNT");
- Assert.equal(h.snapshot().sum, 22, "All the pings must be live-accumulated in the histogram.");
- // Reset the histogram that will be populated by the archive scan.
- Telemetry.getHistogramById("TELEMETRY_ARCHIVE_EVICTED_OLD_DIRS").clear();
- Telemetry.getHistogramById("TELEMETRY_ARCHIVE_OLDEST_DIRECTORY_AGE").clear();
-
- // Move the current date 60 days ahead of the first ping.
- fakeNow(futureDate(firstDate, 60 * MILLISECONDS_PER_DAY));
- // Reset TelemetryArchive and TelemetryController to start the startup cleanup.
- yield TelemetryController.testReset();
- // Wait for the cleanup to finish.
- yield TelemetryStorage.testCleanupTaskPromise();
- // Then scan the archived dir.
- yield TelemetryArchive.promiseArchivedPingList();
-
- // Check that the archive is in the correct state.
- yield checkArchive();
-
- // Make sure the ping count is correct after the scan (one ping was removed).
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_SCAN_PING_COUNT").snapshot();
- Assert.equal(h.sum, 21, "The histogram must count all the pings in the archive.");
- // One directory out of four was removed as well.
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_EVICTED_OLD_DIRS").snapshot();
- Assert.equal(h.sum, 1, "Telemetry must correctly report removed archive directories.");
- // Check that the remaining directories are correctly counted.
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_DIRECTORIES_COUNT").snapshot();
- Assert.equal(h.sum, 3, "Telemetry must correctly report the remaining archive directories.");
- // Check that the remaining directories are correctly counted.
- const oldestAgeInMonths = 1;
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_OLDEST_DIRECTORY_AGE").snapshot();
- Assert.equal(h.sum, oldestAgeInMonths,
- "Telemetry must correctly report age of the oldest directory in the archive.");
-
- // We need to test the archive size before we hit the quota, otherwise a special
- // value is recorded.
- Telemetry.getHistogramById("TELEMETRY_ARCHIVE_SIZE_MB").clear();
- Telemetry.getHistogramById("TELEMETRY_ARCHIVE_EVICTED_OVER_QUOTA").clear();
- Telemetry.getHistogramById("TELEMETRY_ARCHIVE_EVICTING_OVER_QUOTA_MS").clear();
-
- // Move the current date 60 days ahead of the second ping.
- fakeNow(futureDate(oldestDirectoryDate, 60 * MILLISECONDS_PER_DAY));
- // Reset TelemetryController and TelemetryArchive.
- yield TelemetryController.testReset();
- // Wait for the cleanup to finish.
- yield TelemetryStorage.testCleanupTaskPromise();
- // Then scan the archived dir again.
- yield TelemetryArchive.promiseArchivedPingList();
-
- // Move the oldest ping to the unexpected pings list.
- expectedPrunedInfo.push(expectedNotPrunedInfo.shift());
- // Check that the archive is in the correct state.
- yield checkArchive();
-
- // Find how much disk space the archive takes.
- const archivedPingsInfo = yield getArchivedPingsInfo();
- let archiveSizeInBytes =
- archivedPingsInfo.reduce((lastResult, element) => lastResult + element.size, 0);
-
- // Check that the correct values for quota probes are reported when no quota is hit.
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_SIZE_MB").snapshot();
- Assert.equal(h.sum, Math.round(archiveSizeInBytes / 1024 / 1024),
- "Telemetry must report the correct archive size.");
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_EVICTED_OVER_QUOTA").snapshot();
- Assert.equal(h.sum, 0, "Telemetry must report 0 evictions if quota is not hit.");
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_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 = archiveSizeInBytes * 0.8;
- fakeStorageQuota(testQuotaInBytes);
-
- // The storage prunes archived pings until we reach 90% of the requested storage quota.
- // Based on that, find how many pings should be kept.
- const safeQuotaSize = testQuotaInBytes * 0.9;
- let sizeInBytes = 0;
- let pingsWithinQuota = [];
- let pingsOutsideQuota = [];
-
- for (let pingInfo of archivedPingsInfo) {
- sizeInBytes += pingInfo.size;
- if (sizeInBytes >= safeQuotaSize) {
- pingsOutsideQuota.push({ id: pingInfo.id, creationDate: new Date(pingInfo.timestamp) });
- continue;
- }
- pingsWithinQuota.push({ id: pingInfo.id, creationDate: new Date(pingInfo.timestamp) });
- }
-
- expectedNotPrunedInfo = pingsWithinQuota;
- expectedPrunedInfo = expectedPrunedInfo.concat(pingsOutsideQuota);
-
- // Reset TelemetryArchive and TelemetryController to start the startup cleanup.
- yield TelemetryController.testReset();
- yield TelemetryStorage.testCleanupTaskPromise();
- yield TelemetryArchive.promiseArchivedPingList();
- // Check that the archive is in the correct state.
- yield checkArchive();
-
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_EVICTED_OVER_QUOTA").snapshot();
- Assert.equal(h.sum, pingsOutsideQuota.length,
- "Telemetry must correctly report the over quota pings evicted from the archive.");
- h = Telemetry.getHistogramById("TELEMETRY_ARCHIVE_SIZE_MB").snapshot();
- Assert.equal(h.sum, 300, "Archive 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.testCleanupTaskPromise();
- yield TelemetryArchive.promiseArchivedPingList();
- yield checkArchive();
-
- const OVERSIZED_PING_ID = "9b21ec8f-f762-4d28-a2c1-44e1c4694f24";
- // Create and archive an oversized, uncompressed, ping.
- const OVERSIZED_PING = {
- id: OVERSIZED_PING_ID,
- type: PING_TYPE,
- creationDate: (new Date()).toISOString(),
- // Generate a ~2MB string to use as the payload.
- payload: generateRandomString(2 * 1024 * 1024)
- };
- yield TelemetryArchive.promiseArchivePing(OVERSIZED_PING);
-
- // Get the size of the archived ping.
- const oversizedPingPath =
- TelemetryStorage._testGetArchivedPingPath(OVERSIZED_PING.id, new Date(OVERSIZED_PING.creationDate), PING_TYPE) + "lz4";
- const archivedPingSizeMB = Math.floor((yield OS.File.stat(oversizedPingPath)).size / 1024 / 1024);
-
- // We expect the oversized ping to be pruned when scanning the archive.
- expectedPrunedInfo.push({ id: OVERSIZED_PING_ID, creationDate: new Date(OVERSIZED_PING.creationDate) });
-
- // Scan the archive.
- yield TelemetryController.testReset();
- yield TelemetryStorage.testCleanupTaskPromise();
- yield TelemetryArchive.promiseArchivedPingList();
- // The following also checks that non oversized pings are not removed.
- yield checkArchive();
-
- // Make sure we're correctly updating the related histograms.
- h = Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_ARCHIVED").snapshot();
- Assert.equal(h.sum, 1, "Telemetry must report 1 oversized ping in the archive.");
- h = Telemetry.getHistogramById("TELEMETRY_DISCARDED_ARCHIVED_PINGS_SIZE_MB").snapshot();
- Assert.equal(h.counts[archivedPingSizeMB], 1,
- "Telemetry must report the correct size for the oversized ping.");
-});
-
-add_task(function* test_clientId() {
- // Check that a ping submitted after the delayed telemetry initialization completed
- // should get a valid client id.
- yield TelemetryController.testReset();
- const clientId = yield ClientID.getClientID();
-
- let id = yield TelemetryController.submitExternalPing("test-type", {}, {addClientId: true});
- let ping = yield TelemetryArchive.promiseArchivedPingById(id);
-
- Assert.ok(!!ping, "Should have loaded the ping.");
- Assert.ok("clientId" in ping, "Ping should have a client id.");
- Assert.ok(UUID_REGEX.test(ping.clientId), "Client id is in UUID format.");
- Assert.equal(ping.clientId, clientId, "Ping client id should match the global client id.");
-
- // We should have cached the client id now. Lets confirm that by
- // checking the client id on a ping submitted before the async
- // controller setup is finished.
- let promiseSetup = TelemetryController.testReset();
- id = yield TelemetryController.submitExternalPing("test-type", {}, {addClientId: true});
- ping = yield TelemetryArchive.promiseArchivedPingById(id);
- Assert.equal(ping.clientId, clientId);
-
- // Finish setup.
- yield promiseSetup;
-});
-
-add_task(function* test_InvalidPingType() {
- const TYPES = [
- "a",
- "-",
- "¿€€€?",
- "-foo-",
- "-moo",
- "zoo-",
- ".bar",
- "asfd.asdf",
- ];
-
- for (let type of TYPES) {
- let histogram = Telemetry.getKeyedHistogramById("TELEMETRY_INVALID_PING_TYPE_SUBMITTED");
- Assert.equal(histogram.snapshot(type).sum, 0,
- "Should not have counted this invalid ping yet: " + type);
- Assert.ok(promiseRejects(TelemetryController.submitExternalPing(type, {})),
- "Ping type should have been rejected.");
- Assert.equal(histogram.snapshot(type).sum, 1,
- "Should have counted this as an invalid ping type.");
- }
-});
-
-add_task(function* test_InvalidPayloadType() {
- const PAYLOAD_TYPES = [
- 19,
- "string",
- [1, 2, 3, 4],
- null,
- undefined,
- ];
-
- let histogram = Telemetry.getHistogramById("TELEMETRY_INVALID_PAYLOAD_SUBMITTED");
- for (let i = 0; i < PAYLOAD_TYPES.length; i++) {
- histogram.clear();
- Assert.equal(histogram.snapshot().sum, 0,
- "Should not have counted this invalid payload yet: " + JSON.stringify(PAYLOAD_TYPES[i]));
- Assert.ok(yield promiseRejects(TelemetryController.submitExternalPing("payload-test", PAYLOAD_TYPES[i])),
- "Payload type should have been rejected.");
- Assert.equal(histogram.snapshot().sum, 1,
- "Should have counted this as an invalid payload type.");
- }
-});
-
-add_task(function* test_currentPingData() {
- yield TelemetryController.testSetup();
-
- // Setup test data.
- let h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTOUT");
- h.clear();
- h.add(1);
- let k = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT");
- k.clear();
- k.add("a", 1);
-
- // Get current ping data objects and check that their data is sane.
- for (let subsession of [true, false]) {
- let ping = TelemetryController.getCurrentPingData(subsession);
-
- Assert.ok(!!ping, "Should have gotten a ping.");
- Assert.equal(ping.type, "main", "Ping should have correct type.");
- const expectedReason = subsession ? "gather-subsession-payload" : "gather-payload";
- Assert.equal(ping.payload.info.reason, expectedReason, "Ping should have the correct reason.");
-
- let id = "TELEMETRY_TEST_RELEASE_OPTOUT";
- Assert.ok(id in ping.payload.histograms, "Payload should have test count histogram.");
- Assert.equal(ping.payload.histograms[id].sum, 1, "Test count value should match.");
- id = "TELEMETRY_TEST_KEYED_RELEASE_OPTOUT";
- Assert.ok(id in ping.payload.keyedHistograms, "Payload should have keyed test histogram.");
- Assert.equal(ping.payload.keyedHistograms[id]["a"].sum, 1, "Keyed test value should match.");
- }
-});
-
-add_task(function* test_shutdown() {
- yield TelemetryController.testShutdown();
-});