summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/telemetry/tests/unit')
-rw-r--r--toolkit/components/telemetry/tests/unit/.eslintrc.js7
-rw-r--r--toolkit/components/telemetry/tests/unit/TelemetryArchiveTesting.jsm86
-rw-r--r--toolkit/components/telemetry/tests/unit/engine.xml7
-rw-r--r--toolkit/components/telemetry/tests/unit/head.js319
-rw-r--r--toolkit/components/telemetry/tests/unit/test_ChildHistograms.js107
-rw-r--r--toolkit/components/telemetry/tests/unit/test_PingAPI.js502
-rw-r--r--toolkit/components/telemetry/tests/unit/test_SubsessionChaining.js236
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryController.js507
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryControllerBuildID.js70
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryControllerShutdown.js70
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryController_idle.js73
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js1522
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js249
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryFlagClear.js14
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryLateWrites.js127
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryLockCount.js53
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryLog.js51
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js268
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryScalars.js574
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetrySend.js427
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js547
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetrySession.js2029
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryTimestamps.js77
-rw-r--r--toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js102
-rw-r--r--toolkit/components/telemetry/tests/unit/test_nsITelemetry.js883
-rw-r--r--toolkit/components/telemetry/tests/unit/xpcshell.ini61
26 files changed, 0 insertions, 8968 deletions
diff --git a/toolkit/components/telemetry/tests/unit/.eslintrc.js b/toolkit/components/telemetry/tests/unit/.eslintrc.js
deleted file mode 100644
index d35787cd2..000000000
--- a/toolkit/components/telemetry/tests/unit/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": [
- "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
- ]
-};
diff --git a/toolkit/components/telemetry/tests/unit/TelemetryArchiveTesting.jsm b/toolkit/components/telemetry/tests/unit/TelemetryArchiveTesting.jsm
deleted file mode 100644
index 9be82c883..000000000
--- a/toolkit/components/telemetry/tests/unit/TelemetryArchiveTesting.jsm
+++ /dev/null
@@ -1,86 +0,0 @@
-const {utils: Cu} = Components;
-Cu.import("resource://gre/modules/TelemetryArchive.jsm");
-Cu.import("resource://testing-common/Assert.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/TelemetryController.jsm");
-
-this.EXPORTED_SYMBOLS = [
- "TelemetryArchiveTesting",
-];
-
-function checkForProperties(ping, expected) {
- for (let [props, val] of expected) {
- let test = ping;
- for (let prop of props) {
- test = test[prop];
- if (test === undefined) {
- return false;
- }
- }
- if (test !== val) {
- return false;
- }
- }
- return true;
-}
-
-/**
- * A helper object that allows test code to check whether a telemetry ping
- * was properly saved. To use, first initialize to collect the starting pings
- * and then check for new ping data.
- */
-function Checker() {
-}
-Checker.prototype = {
- promiseInit: function() {
- this._pingMap = new Map();
- return TelemetryArchive.promiseArchivedPingList().then((plist) => {
- for (let ping of plist) {
- this._pingMap.set(ping.id, ping);
- }
- });
- },
-
- /**
- * Find and return a new ping with certain properties.
- *
- * @param expected: an array of [['prop'...], 'value'] to check
- * For example:
- * [
- * [['environment', 'build', 'applicationId'], '20150101010101'],
- * [['version'], 1],
- * [['metadata', 'OOMAllocationSize'], 123456789],
- * ]
- * @returns a matching ping if found, or null
- */
- promiseFindPing: Task.async(function*(type, expected) {
- let candidates = [];
- let plist = yield TelemetryArchive.promiseArchivedPingList();
- for (let ping of plist) {
- if (this._pingMap.has(ping.id)) {
- continue;
- }
- if (ping.type == type) {
- candidates.push(ping);
- }
- }
-
- for (let candidate of candidates) {
- let ping = yield TelemetryArchive.promiseArchivedPingById(candidate.id);
- if (checkForProperties(ping, expected)) {
- return ping;
- }
- }
- return null;
- }),
-};
-
-const TelemetryArchiveTesting = {
- setup: function() {
- Services.prefs.setCharPref("toolkit.telemetry.log.level", "Trace");
- Services.prefs.setBoolPref("toolkit.telemetry.archive.enabled", true);
- },
-
- Checker: Checker,
-};
diff --git a/toolkit/components/telemetry/tests/unit/engine.xml b/toolkit/components/telemetry/tests/unit/engine.xml
deleted file mode 100644
index 2304fcdd7..000000000
--- a/toolkit/components/telemetry/tests/unit/engine.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
-<ShortName>engine-telemetry</ShortName>
-<Url type="text/html" method="GET" template="http://www.example.com/search">
- <Param name="q" value="{searchTerms}"/>
-</Url>
-</SearchPlugin>
diff --git a/toolkit/components/telemetry/tests/unit/head.js b/toolkit/components/telemetry/tests/unit/head.js
deleted file mode 100644
index 87afd3617..000000000
--- a/toolkit/components/telemetry/tests/unit/head.js
+++ /dev/null
@@ -1,319 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-var { classes: Cc, utils: Cu, interfaces: Ci, results: Cr } = Components;
-
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/Services.jsm", this);
-Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
-Cu.import("resource://gre/modules/Task.jsm", this);
-Cu.import("resource://gre/modules/FileUtils.jsm", this);
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-Cu.import("resource://testing-common/httpd.js", this);
-Cu.import("resource://gre/modules/AppConstants.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "AddonTestUtils",
- "resource://testing-common/AddonTestUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm");
-
-const gIsWindows = AppConstants.platform == "win";
-const gIsMac = AppConstants.platform == "macosx";
-const gIsAndroid = AppConstants.platform == "android";
-const gIsGonk = false;
-const gIsLinux = AppConstants.platform == "linux";
-
-const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
-
-const MILLISECONDS_PER_MINUTE = 60 * 1000;
-const MILLISECONDS_PER_HOUR = 60 * MILLISECONDS_PER_MINUTE;
-const MILLISECONDS_PER_DAY = 24 * MILLISECONDS_PER_HOUR;
-
-const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled";
-
-const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
-
-var gGlobalScope = this;
-
-const PingServer = {
- _httpServer: null,
- _started: false,
- _defers: [ PromiseUtils.defer() ],
- _currentDeferred: 0,
-
- get port() {
- return this._httpServer.identity.primaryPort;
- },
-
- get started() {
- return this._started;
- },
-
- registerPingHandler: function(handler) {
- const wrapped = wrapWithExceptionHandler(handler);
- this._httpServer.registerPrefixHandler("/submit/telemetry/", wrapped);
- },
-
- resetPingHandler: function() {
- this.registerPingHandler((request, response) => {
- let deferred = this._defers[this._defers.length - 1];
- this._defers.push(PromiseUtils.defer());
- deferred.resolve(request);
- });
- },
-
- start: function() {
- this._httpServer = new HttpServer();
- this._httpServer.start(-1);
- this._started = true;
- this.clearRequests();
- this.resetPingHandler();
- },
-
- stop: function() {
- return new Promise(resolve => {
- this._httpServer.stop(resolve);
- this._started = false;
- });
- },
-
- clearRequests: function() {
- this._defers = [ PromiseUtils.defer() ];
- this._currentDeferred = 0;
- },
-
- promiseNextRequest: function() {
- const deferred = this._defers[this._currentDeferred++];
- // Send the ping to the consumer on the next tick, so that the completion gets
- // signaled to Telemetry.
- return new Promise(r => Services.tm.currentThread.dispatch(() => r(deferred.promise),
- Ci.nsIThread.DISPATCH_NORMAL));
- },
-
- promiseNextPing: function() {
- return this.promiseNextRequest().then(request => decodeRequestPayload(request));
- },
-
- promiseNextRequests: Task.async(function*(count) {
- let results = [];
- for (let i=0; i<count; ++i) {
- results.push(yield this.promiseNextRequest());
- }
-
- return results;
- }),
-
- promiseNextPings: function(count) {
- return this.promiseNextRequests(count).then(requests => {
- return Array.from(requests, decodeRequestPayload);
- });
- },
-};
-
-/**
- * Decode the payload of an HTTP request into a ping.
- * @param {Object} request The data representing an HTTP request (nsIHttpRequest).
- * @return {Object} The decoded ping payload.
- */
-function decodeRequestPayload(request) {
- let s = request.bodyInputStream;
- let payload = null;
- let decoder = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON)
-
- if (request.getHeader("content-encoding") == "gzip") {
- let observer = {
- buffer: "",
- onStreamComplete: function(loader, context, status, length, result) {
- this.buffer = String.fromCharCode.apply(this, result);
- }
- };
-
- let scs = Cc["@mozilla.org/streamConverters;1"]
- .getService(Ci.nsIStreamConverterService);
- let listener = Cc["@mozilla.org/network/stream-loader;1"]
- .createInstance(Ci.nsIStreamLoader);
- listener.init(observer);
- let converter = scs.asyncConvertData("gzip", "uncompressed",
- listener, null);
- converter.onStartRequest(null, null);
- converter.onDataAvailable(null, null, s, 0, s.available());
- converter.onStopRequest(null, null, null);
- let unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
- .createInstance(Ci.nsIScriptableUnicodeConverter);
- unicodeConverter.charset = "UTF-8";
- let utf8string = unicodeConverter.ConvertToUnicode(observer.buffer);
- utf8string += unicodeConverter.Finish();
- payload = JSON.parse(utf8string);
- } else {
- payload = decoder.decodeFromStream(s, s.available());
- }
-
- return payload;
-}
-
-function wrapWithExceptionHandler(f) {
- function wrapper(...args) {
- try {
- f(...args);
- } catch (ex) {
- if (typeof(ex) != 'object') {
- throw ex;
- }
- dump("Caught exception: " + ex.message + "\n");
- dump(ex.stack);
- do_test_finished();
- }
- }
- return wrapper;
-}
-
-function loadAddonManager(...args) {
- AddonTestUtils.init(gGlobalScope);
- AddonTestUtils.overrideCertDB();
- createAppInfo(...args);
-
- // As we're not running in application, we need to setup the features directory
- // used by system add-ons.
- const distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "app0"], true);
- AddonTestUtils.registerDirectory("XREAppFeat", distroDir);
- return AddonTestUtils.promiseStartupManager();
-}
-
-var gAppInfo = null;
-
-function createAppInfo(ID="xpcshell@tests.mozilla.org", name="XPCShell",
- version="1.0", platformVersion="1.0") {
- AddonTestUtils.createAppInfo(ID, name, version, platformVersion);
- gAppInfo = AddonTestUtils.appInfo;
-}
-
-// Fake the timeout functions for the TelemetryScheduler.
-function fakeSchedulerTimer(set, clear) {
- let session = Cu.import("resource://gre/modules/TelemetrySession.jsm");
- session.Policy.setSchedulerTickTimeout = set;
- session.Policy.clearSchedulerTickTimeout = clear;
-}
-
-/**
- * Fake the current date.
- * This passes all received arguments to a new Date constructor and
- * uses the resulting date to fake the time in Telemetry modules.
- *
- * @return Date The new faked date.
- */
-function fakeNow(...args) {
- const date = new Date(...args);
- const modules = [
- Cu.import("resource://gre/modules/TelemetrySession.jsm"),
- Cu.import("resource://gre/modules/TelemetryEnvironment.jsm"),
- Cu.import("resource://gre/modules/TelemetryController.jsm"),
- Cu.import("resource://gre/modules/TelemetryStorage.jsm"),
- Cu.import("resource://gre/modules/TelemetrySend.jsm"),
- Cu.import("resource://gre/modules/TelemetryReportingPolicy.jsm"),
- ];
-
- for (let m of modules) {
- m.Policy.now = () => date;
- }
-
- return new Date(date);
-}
-
-function fakeMonotonicNow(ms) {
- const m = Cu.import("resource://gre/modules/TelemetrySession.jsm");
- m.Policy.monotonicNow = () => ms;
- return ms;
-}
-
-// Fake the timeout functions for TelemetryController sending.
-function fakePingSendTimer(set, clear) {
- let module = Cu.import("resource://gre/modules/TelemetrySend.jsm");
- let obj = Cu.cloneInto({set, clear}, module, {cloneFunctions:true});
- module.Policy.setSchedulerTickTimeout = obj.set;
- module.Policy.clearSchedulerTickTimeout = obj.clear;
-}
-
-function fakeMidnightPingFuzzingDelay(delayMs) {
- let module = Cu.import("resource://gre/modules/TelemetrySend.jsm");
- module.Policy.midnightPingFuzzingDelay = () => delayMs;
-}
-
-function fakeGeneratePingId(func) {
- let module = Cu.import("resource://gre/modules/TelemetryController.jsm");
- module.Policy.generatePingId = func;
-}
-
-function fakeCachedClientId(uuid) {
- let module = Cu.import("resource://gre/modules/TelemetryController.jsm");
- module.Policy.getCachedClientID = () => uuid;
-}
-
-// Return a date that is |offset| ms in the future from |date|.
-function futureDate(date, offset) {
- return new Date(date.getTime() + offset);
-}
-
-function truncateToDays(aMsec) {
- return Math.floor(aMsec / MILLISECONDS_PER_DAY);
-}
-
-// Returns a promise that resolves to true when the passed promise rejects,
-// false otherwise.
-function promiseRejects(promise) {
- return promise.then(() => false, () => true);
-}
-
-// Generates a random string of at least a specific length.
-function generateRandomString(length) {
- let string = "";
-
- while (string.length < length) {
- string += Math.random().toString(36);
- }
-
- return string.substring(0, length);
-}
-
-// Short-hand for retrieving the histogram with that id.
-function getHistogram(histogramId) {
- return Telemetry.getHistogramById(histogramId);
-}
-
-// Short-hand for retrieving the snapshot of the Histogram with that id.
-function getSnapshot(histogramId) {
- return Telemetry.getHistogramById(histogramId).snapshot();
-}
-
-// Helper for setting an empty list of Environment preferences to watch.
-function setEmptyPrefWatchlist() {
- let TelemetryEnvironment =
- Cu.import("resource://gre/modules/TelemetryEnvironment.jsm").TelemetryEnvironment;
- return TelemetryEnvironment.onInitialized().then(() => {
- TelemetryEnvironment.testWatchPreferences(new Map());
- });
-}
-
-if (runningInParent) {
- // Set logging preferences for all the tests.
- Services.prefs.setCharPref("toolkit.telemetry.log.level", "Trace");
- // Telemetry archiving should be on.
- Services.prefs.setBoolPref("toolkit.telemetry.archive.enabled", true);
- // Telemetry xpcshell tests cannot show the infobar.
- Services.prefs.setBoolPref("datareporting.policy.dataSubmissionPolicyBypassNotification", true);
- // FHR uploads should be enabled.
- Services.prefs.setBoolPref("datareporting.healthreport.uploadEnabled", true);
-
- fakePingSendTimer((callback, timeout) => {
- Services.tm.mainThread.dispatch(() => callback(), Ci.nsIThread.DISPATCH_NORMAL);
- },
- () => {});
-
- do_register_cleanup(() => TelemetrySend.shutdown());
-}
-
-TelemetryController.testInitLogging();
-
-// Avoid timers interrupting test behavior.
-fakeSchedulerTimer(() => {}, () => {});
-// Make pind sending predictable.
-fakeMidnightPingFuzzingDelay(0);
diff --git a/toolkit/components/telemetry/tests/unit/test_ChildHistograms.js b/toolkit/components/telemetry/tests/unit/test_ChildHistograms.js
deleted file mode 100644
index 11d730499..000000000
--- a/toolkit/components/telemetry/tests/unit/test_ChildHistograms.js
+++ /dev/null
@@ -1,107 +0,0 @@
-
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
-Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
-Cu.import("resource://testing-common/ContentTaskUtils.jsm", this);
-
-const MESSAGE_TELEMETRY_PAYLOAD = "Telemetry:Payload";
-const MESSAGE_TELEMETRY_GET_CHILD_PAYLOAD = "Telemetry:GetChildPayload";
-const MESSAGE_CHILD_TEST_DONE = "ChildTest:Done";
-
-const PLATFORM_VERSION = "1.9.2";
-const APP_VERSION = "1";
-const APP_ID = "xpcshell@tests.mozilla.org";
-const APP_NAME = "XPCShell";
-
-function run_child_test() {
- // Setup histograms with some fixed values.
- let flagHist = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG");
- flagHist.add(1);
- let countHist = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_COUNT", false);
- countHist.add();
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_COUNT", true);
- countHist.add();
- countHist.add();
- let categHist = Telemetry.getHistogramById("TELEMETRY_TEST_CATEGORICAL");
- categHist.add("Label2");
- categHist.add("Label3");
-
- let flagKeyed = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_FLAG");
- flagKeyed.add("a", 1);
- flagKeyed.add("b", 1);
- let countKeyed = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_COUNT");
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_KEYED_COUNT", false);
- countKeyed.add("a");
- countKeyed.add("b");
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_KEYED_COUNT", true);
- countKeyed.add("a");
- countKeyed.add("b");
- countKeyed.add("b");
-}
-
-function check_histogram_values(payload) {
- const hs = payload.histograms;
- Assert.ok("TELEMETRY_TEST_COUNT" in hs, "Should have count test histogram.");
- Assert.ok("TELEMETRY_TEST_FLAG" in hs, "Should have flag test histogram.");
- Assert.ok("TELEMETRY_TEST_CATEGORICAL" in hs, "Should have categorical test histogram.");
- Assert.equal(hs["TELEMETRY_TEST_COUNT"].sum, 2,
- "Count test histogram should have the right value.");
- Assert.equal(hs["TELEMETRY_TEST_FLAG"].sum, 1,
- "Flag test histogram should have the right value.");
- Assert.equal(hs["TELEMETRY_TEST_CATEGORICAL"].sum, 3,
- "Categorical test histogram should have the right sum.");
-
- const kh = payload.keyedHistograms;
- Assert.ok("TELEMETRY_TEST_KEYED_COUNT" in kh, "Should have keyed count test histogram.");
- Assert.ok("TELEMETRY_TEST_KEYED_FLAG" in kh, "Should have keyed flag test histogram.");
- Assert.equal(kh["TELEMETRY_TEST_KEYED_COUNT"]["a"].sum, 1,
- "Keyed count test histogram should have the right value.");
- Assert.equal(kh["TELEMETRY_TEST_KEYED_COUNT"]["b"].sum, 2,
- "Keyed count test histogram should have the right value.");
- Assert.equal(kh["TELEMETRY_TEST_KEYED_FLAG"]["a"].sum, 1,
- "Keyed flag test histogram should have the right value.");
- Assert.equal(kh["TELEMETRY_TEST_KEYED_FLAG"]["b"].sum, 1,
- "Keyed flag test histogram should have the right value.");
-}
-
-add_task(function*() {
- if (!runningInParent) {
- TelemetryController.testSetupContent();
- run_child_test();
- dump("... done with child test\n");
- do_send_remote_message(MESSAGE_CHILD_TEST_DONE);
- return;
- }
-
- // Setup.
- do_get_profile(true);
- loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
- Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
- yield TelemetryController.testSetup();
- if (runningInParent) {
- // Make sure we don't generate unexpected pings due to pref changes.
- yield setEmptyPrefWatchlist();
- }
-
- // Run test in child, don't wait for it to finish.
- run_test_in_child("test_ChildHistograms.js");
- yield do_await_remote_message(MESSAGE_CHILD_TEST_DONE);
-
- yield ContentTaskUtils.waitForCondition(() => {
- let payload = TelemetrySession.getPayload("test-ping");
- return payload &&
- "processes" in payload &&
- "content" in payload.processes &&
- "histograms" in payload.processes.content &&
- "TELEMETRY_TEST_COUNT" in payload.processes.content.histograms;
- });
- const payload = TelemetrySession.getPayload("test-ping");
- Assert.ok("processes" in payload, "Should have processes section");
- Assert.ok("content" in payload.processes, "Should have child process section");
- Assert.ok("histograms" in payload.processes.content, "Child process section should have histograms.");
- Assert.ok("keyedHistograms" in payload.processes.content, "Child process section should have keyed histograms.");
- check_histogram_values(payload.processes.content);
-
- do_test_finished();
-});
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();
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_SubsessionChaining.js b/toolkit/components/telemetry/tests/unit/test_SubsessionChaining.js
deleted file mode 100644
index c86fb0499..000000000
--- a/toolkit/components/telemetry/tests/unit/test_SubsessionChaining.js
+++ /dev/null
@@ -1,236 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-*/
-
-Cu.import("resource://gre/modules/Preferences.jsm", this);
-Cu.import("resource://gre/modules/Promise.jsm", this);
-Cu.import("resource://gre/modules/Task.jsm", this);
-Cu.import("resource://gre/modules/TelemetryArchive.jsm", this);
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetryEnvironment.jsm", this);
-Cu.import("resource://gre/modules/osfile.jsm", this);
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-
-const MS_IN_ONE_HOUR = 60 * 60 * 1000;
-const MS_IN_ONE_DAY = 24 * MS_IN_ONE_HOUR;
-
-const PREF_BRANCH = "toolkit.telemetry.";
-const PREF_ARCHIVE_ENABLED = PREF_BRANCH + "archive.enabled";
-
-const REASON_ABORTED_SESSION = "aborted-session";
-const REASON_DAILY = "daily";
-const REASON_ENVIRONMENT_CHANGE = "environment-change";
-const REASON_SHUTDOWN = "shutdown";
-
-XPCOMUtils.defineLazyGetter(this, "DATAREPORTING_PATH", function() {
- return OS.Path.join(OS.Constants.Path.profileDir, "datareporting");
-});
-
-var promiseValidateArchivedPings = Task.async(function*(aExpectedReasons) {
- // The list of ping reasons which mark the session end (and must reset the subsession
- // count).
- const SESSION_END_PING_REASONS = new Set([ REASON_ABORTED_SESSION, REASON_SHUTDOWN ]);
-
- let list = yield TelemetryArchive.promiseArchivedPingList();
-
- // We're just interested in the "main" pings.
- list = list.filter(p => p.type == "main");
-
- Assert.equal(aExpectedReasons.length, list.length, "All the expected pings must be received.");
-
- let previousPing = yield TelemetryArchive.promiseArchivedPingById(list[0].id);
- Assert.equal(aExpectedReasons.shift(), previousPing.payload.info.reason,
- "Telemetry should only get pings with expected reasons.");
- Assert.equal(previousPing.payload.info.previousSessionId, null,
- "The first session must report a null previous session id.");
- Assert.equal(previousPing.payload.info.previousSubsessionId, null,
- "The first subsession must report a null previous subsession id.");
- Assert.equal(previousPing.payload.info.profileSubsessionCounter, 1,
- "profileSubsessionCounter must be 1 the first time.");
- Assert.equal(previousPing.payload.info.subsessionCounter, 1,
- "subsessionCounter must be 1 the first time.");
-
- let expectedSubsessionCounter = 1;
- let expectedPreviousSessionId = previousPing.payload.info.sessionId;
-
- for (let i = 1; i < list.length; i++) {
- let currentPing = yield TelemetryArchive.promiseArchivedPingById(list[i].id);
- let currentInfo = currentPing.payload.info;
- let previousInfo = previousPing.payload.info;
- do_print("Archive entry " + i + " - id: " + currentPing.id + ", reason: " + currentInfo.reason);
-
- Assert.equal(aExpectedReasons.shift(), currentInfo.reason,
- "Telemetry should only get pings with expected reasons.");
- Assert.equal(currentInfo.previousSessionId, expectedPreviousSessionId,
- "Telemetry must correctly chain session identifiers.");
- Assert.equal(currentInfo.previousSubsessionId, previousInfo.subsessionId,
- "Telemetry must correctly chain subsession identifiers.");
- Assert.equal(currentInfo.profileSubsessionCounter, previousInfo.profileSubsessionCounter + 1,
- "Telemetry must correctly track the profile subsessions count.");
- Assert.equal(currentInfo.subsessionCounter, expectedSubsessionCounter,
- "The subsession counter should be monotonically increasing.");
-
- // Store the current ping as previous.
- previousPing = currentPing;
- // Reset the expected subsession counter, if required. Otherwise increment the expected
- // subsession counter.
- // If this is the final subsession of a session we need to update expected values accordingly.
- if (SESSION_END_PING_REASONS.has(currentInfo.reason)) {
- expectedSubsessionCounter = 1;
- expectedPreviousSessionId = currentInfo.sessionId;
- } else {
- expectedSubsessionCounter++;
- }
- }
-});
-
-add_task(function* test_setup() {
- do_test_pending();
-
- // Addon manager needs a profile directory
- 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();
-
- Preferences.set(PREF_TELEMETRY_ENABLED, true);
-});
-
-add_task(function* test_subsessionsChaining() {
- if (gIsAndroid) {
- // We don't support subsessions yet on Android, so skip the next checks.
- return;
- }
-
- const PREF_TEST = PREF_BRANCH + "test.pref1";
- const PREFS_TO_WATCH = new Map([
- [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
- ]);
- Preferences.reset(PREF_TEST);
-
- // Fake the clock data to manually trigger an aborted-session ping and a daily ping.
- // This is also helpful to make sure we get the archived pings in an expected order.
- let now = fakeNow(2009, 9, 18, 0, 0, 0);
- let monotonicNow = fakeMonotonicNow(1000);
-
- let moveClockForward = (minutes) => {
- let ms = minutes * MILLISECONDS_PER_MINUTE;
- now = fakeNow(futureDate(now, ms));
- monotonicNow = fakeMonotonicNow(monotonicNow + ms);
- }
-
- // Keep track of the ping reasons we're expecting in this test.
- let expectedReasons = [];
-
- // Start and shut down Telemetry. We expect a shutdown ping with profileSubsessionCounter: 1,
- // subsessionCounter: 1, subsessionId: A, and previousSubsessionId: null to be archived.
- yield TelemetryController.testSetup();
- yield TelemetryController.testShutdown();
- expectedReasons.push(REASON_SHUTDOWN);
-
- // Start Telemetry but don't wait for it to initialise before shutting down. We expect a
- // shutdown ping with profileSubsessionCounter: 2, subsessionCounter: 1, subsessionId: B
- // and previousSubsessionId: A to be archived.
- moveClockForward(30);
- TelemetryController.testReset();
- yield TelemetryController.testShutdown();
- expectedReasons.push(REASON_SHUTDOWN);
-
- // Start Telemetry and simulate an aborted-session ping. We expect an aborted-session ping
- // with profileSubsessionCounter: 3, subsessionCounter: 1, subsessionId: C and
- // previousSubsessionId: B to be archived.
- let schedulerTickCallback = null;
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryController.testReset();
- moveClockForward(6);
- // Trigger the an aborted session ping save. When testing,we are not saving the aborted-session
- // ping as soon as Telemetry starts, otherwise we would end up with unexpected pings being
- // sent when calling |TelemetryController.testReset()|, thus breaking some tests.
- Assert.ok(!!schedulerTickCallback);
- yield schedulerTickCallback();
- expectedReasons.push(REASON_ABORTED_SESSION);
-
- // Start Telemetry and trigger an environment change through a pref modification. We expect
- // an environment-change ping with profileSubsessionCounter: 4, subsessionCounter: 1,
- // subsessionId: D and previousSubsessionId: C to be archived.
- moveClockForward(30);
- yield TelemetryController.testReset();
- TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
- moveClockForward(30);
- Preferences.set(PREF_TEST, 1);
- expectedReasons.push(REASON_ENVIRONMENT_CHANGE);
-
- // Shut down Telemetry. We expect a shutdown ping with profileSubsessionCounter: 5,
- // subsessionCounter: 2, subsessionId: E and previousSubsessionId: D to be archived.
- moveClockForward(30);
- yield TelemetryController.testShutdown();
- expectedReasons.push(REASON_SHUTDOWN);
-
- // Start Telemetry and trigger a daily ping. We expect a daily ping with
- // profileSubsessionCounter: 6, subsessionCounter: 1, subsessionId: F and
- // previousSubsessionId: E to be archived.
- moveClockForward(30);
- yield TelemetryController.testReset();
-
- // Delay the callback around midnight.
- now = fakeNow(futureDate(now, MS_IN_ONE_DAY));
- // Trigger the daily ping.
- yield schedulerTickCallback();
- expectedReasons.push(REASON_DAILY);
-
- // Trigger an environment change ping. We expect an environment-changed ping with
- // profileSubsessionCounter: 7, subsessionCounter: 2, subsessionId: G and
- // previousSubsessionId: F to be archived.
- moveClockForward(30);
- Preferences.set(PREF_TEST, 0);
- expectedReasons.push(REASON_ENVIRONMENT_CHANGE);
-
- // Shut down Telemetry and trigger a shutdown ping.
- moveClockForward(30);
- yield TelemetryController.testShutdown();
- expectedReasons.push(REASON_SHUTDOWN);
-
- // Start Telemetry and trigger an environment change.
- yield TelemetryController.testReset();
- TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
- moveClockForward(30);
- Preferences.set(PREF_TEST, 1);
- expectedReasons.push(REASON_ENVIRONMENT_CHANGE);
-
- // Don't shut down, instead trigger an aborted-session ping.
- moveClockForward(6);
- // Trigger the an aborted session ping save.
- yield schedulerTickCallback();
- expectedReasons.push(REASON_ABORTED_SESSION);
-
- // Start Telemetry and trigger a daily ping.
- moveClockForward(30);
- yield TelemetryController.testReset();
- // Delay the callback around midnight.
- now = futureDate(now, MS_IN_ONE_DAY);
- fakeNow(now);
- // Trigger the daily ping.
- yield schedulerTickCallback();
- expectedReasons.push(REASON_DAILY);
-
- // Trigger an environment change.
- moveClockForward(30);
- Preferences.set(PREF_TEST, 0);
- expectedReasons.push(REASON_ENVIRONMENT_CHANGE);
-
- // And an aborted-session ping again.
- moveClockForward(6);
- // Trigger the an aborted session ping save.
- yield schedulerTickCallback();
- expectedReasons.push(REASON_ABORTED_SESSION);
-
- // Make sure the aborted-session ping gets archived.
- yield TelemetryController.testReset();
-
- yield promiseValidateArchivedPings(expectedReasons);
-});
-
-add_task(function* () {
- yield TelemetryController.testShutdown();
- do_test_finished();
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryController.js b/toolkit/components/telemetry/tests/unit/test_TelemetryController.js
deleted file mode 100644
index b383de6bf..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryController.js
+++ /dev/null
@@ -1,507 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-*/
-/* This testcase triggers two telemetry pings.
- *
- * Telemetry code keeps histograms of past telemetry pings. The first
- * ping populates these histograms. One of those histograms is then
- * checked in the second request.
- */
-
-Cu.import("resource://gre/modules/ClientID.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetryStorage.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySend.jsm", this);
-Cu.import("resource://gre/modules/TelemetryArchive.jsm", this);
-Cu.import("resource://gre/modules/Task.jsm", this);
-Cu.import("resource://gre/modules/Promise.jsm", this);
-Cu.import("resource://gre/modules/Preferences.jsm");
-
-const PING_FORMAT_VERSION = 4;
-const DELETION_PING_TYPE = "deletion";
-const TEST_PING_TYPE = "test-ping-type";
-
-const PLATFORM_VERSION = "1.9.2";
-const APP_VERSION = "1";
-const APP_NAME = "XPCShell";
-
-const PREF_BRANCH = "toolkit.telemetry.";
-const PREF_ENABLED = PREF_BRANCH + "enabled";
-const PREF_ARCHIVE_ENABLED = PREF_BRANCH + "archive.enabled";
-const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
-const PREF_UNIFIED = PREF_BRANCH + "unified";
-
-var gClientID = null;
-
-function sendPing(aSendClientId, aSendEnvironment) {
- if (PingServer.started) {
- TelemetrySend.setServer("http://localhost:" + PingServer.port);
- } else {
- TelemetrySend.setServer("http://doesnotexist");
- }
-
- let options = {
- addClientId: aSendClientId,
- addEnvironment: aSendEnvironment,
- };
- return TelemetryController.submitExternalPing(TEST_PING_TYPE, {}, options);
-}
-
-function checkPingFormat(aPing, aType, aHasClientId, aHasEnvironment) {
- const MANDATORY_PING_FIELDS = [
- "type", "id", "creationDate", "version", "application", "payload"
- ];
-
- const APPLICATION_TEST_DATA = {
- buildId: gAppInfo.appBuildID,
- name: APP_NAME,
- version: APP_VERSION,
- displayVersion: AppConstants.MOZ_APP_VERSION_DISPLAY,
- vendor: "Mozilla",
- platformVersion: PLATFORM_VERSION,
- xpcomAbi: "noarch-spidermonkey",
- };
-
- // Check that the ping contains all the mandatory fields.
- for (let f of MANDATORY_PING_FIELDS) {
- Assert.ok(f in aPing, f + " must be available.");
- }
-
- Assert.equal(aPing.type, aType, "The ping must have the correct type.");
- Assert.equal(aPing.version, PING_FORMAT_VERSION, "The ping must have the correct version.");
-
- // Test the application section.
- for (let f in APPLICATION_TEST_DATA) {
- Assert.equal(aPing.application[f], APPLICATION_TEST_DATA[f],
- f + " must have the correct value.");
- }
-
- // We can't check the values for channel and architecture. Just make
- // sure they are in.
- Assert.ok("architecture" in aPing.application,
- "The application section must have an architecture field.");
- Assert.ok("channel" in aPing.application,
- "The application section must have a channel field.");
-
- // Check the clientId and environment fields, as needed.
- Assert.equal("clientId" in aPing, aHasClientId);
- Assert.equal("environment" in aPing, aHasEnvironment);
-}
-
-add_task(function* test_setup() {
- // Addon manager needs a profile directory
- 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_ENABLED, true);
- Services.prefs.setBoolPref(PREF_FHR_UPLOAD_ENABLED, true);
-
- yield new Promise(resolve =>
- Telemetry.asyncFetchTelemetryData(wrapWithExceptionHandler(resolve)));
-});
-
-add_task(function* asyncSetup() {
- yield TelemetryController.testSetup();
-});
-
-// Ensure that not overwriting an existing file fails silently
-add_task(function* test_overwritePing() {
- let ping = {id: "foo"};
- yield TelemetryStorage.savePing(ping, true);
- yield TelemetryStorage.savePing(ping, false);
- yield TelemetryStorage.cleanupPingFile(ping);
-});
-
-// Checks that a sent ping is correctly received by a dummy http server.
-add_task(function* test_simplePing() {
- PingServer.start();
- // Update the Telemetry Server preference with the address of the local server.
- // Otherwise we might end up sending stuff to a non-existing server after
- // |TelemetryController.testReset| is called.
- Preferences.set(TelemetryController.Constants.PREF_SERVER, "http://localhost:" + PingServer.port);
-
- yield sendPing(false, false);
- let request = yield PingServer.promiseNextRequest();
-
- // 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 new ping format version.
- let params = request.queryString.split("&");
- Assert.ok(params.find(p => p == ("v=" + PING_FORMAT_VERSION)));
-
- let ping = decodeRequestPayload(request);
- checkPingFormat(ping, TEST_PING_TYPE, false, false);
-});
-
-add_task(function* test_disableDataUpload() {
- const isUnified = Preferences.get(PREF_UNIFIED, false);
- if (!isUnified) {
- // Skipping the test if unified telemetry is off, as no deletion ping will
- // be generated.
- return;
- }
-
- // Disable FHR upload: this should trigger a deletion ping.
- Preferences.set(PREF_FHR_UPLOAD_ENABLED, false);
-
- let ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, DELETION_PING_TYPE, true, false);
- // Wait on ping activity to settle.
- yield TelemetrySend.testWaitOnOutgoingPings();
-
- // Restore FHR Upload.
- Preferences.set(PREF_FHR_UPLOAD_ENABLED, true);
-
- // Simulate a failure in sending the deletion ping by disabling the HTTP server.
- yield PingServer.stop();
-
- // Try to send a ping. It will be saved as pending and get deleted when disabling upload.
- TelemetryController.submitExternalPing(TEST_PING_TYPE, {});
-
- // Disable FHR upload to send a deletion ping again.
- Preferences.set(PREF_FHR_UPLOAD_ENABLED, false);
-
- // Wait on sending activity to settle, as |TelemetryController.testReset()| doesn't do that.
- yield TelemetrySend.testWaitOnOutgoingPings();
- // Wait for the pending pings to be deleted. Resetting TelemetryController doesn't
- // trigger the shutdown, so we need to call it ourselves.
- yield TelemetryStorage.shutdown();
- // Simulate a restart, and spin the send task.
- yield TelemetryController.testReset();
-
- // Disabling Telemetry upload must clear out all the pending pings.
- let pendingPings = yield TelemetryStorage.loadPendingPingList();
- Assert.equal(pendingPings.length, 1,
- "All the pending pings but the deletion ping should have been deleted");
-
- // Enable the ping server again.
- PingServer.start();
- // We set the new server using the pref, otherwise it would get reset with
- // |TelemetryController.testReset|.
- Preferences.set(TelemetryController.Constants.PREF_SERVER, "http://localhost:" + PingServer.port);
-
- // Stop the sending task and then start it again.
- yield TelemetrySend.shutdown();
- // Reset the controller to spin the ping sending task.
- yield TelemetryController.testReset();
- ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, DELETION_PING_TYPE, true, false);
-
- // Wait on ping activity to settle before moving on to the next test. If we were
- // to shut down telemetry, even though the PingServer caught the expected pings,
- // TelemetrySend could still be processing them (clearing pings would happen in
- // a couple of ticks). Shutting down would cancel the request and save them as
- // pending pings.
- yield TelemetrySend.testWaitOnOutgoingPings();
- // Restore FHR Upload.
- Preferences.set(PREF_FHR_UPLOAD_ENABLED, true);
-});
-
-add_task(function* test_pingHasClientId() {
- const PREF_CACHED_CLIENTID = "toolkit.telemetry.cachedClientID";
-
- // Make sure we have no cached client ID for this test: we'll try to send
- // a ping with it while Telemetry is being initialized.
- Preferences.reset(PREF_CACHED_CLIENTID);
- yield TelemetryController.testShutdown();
- yield ClientID._reset();
- yield TelemetryStorage.testClearPendingPings();
- // And also clear the counter histogram since we're here.
- let h = Telemetry.getHistogramById("TELEMETRY_PING_SUBMISSION_WAITING_CLIENTID");
- h.clear();
-
- // Init telemetry and try to send a ping with a client ID.
- let promisePingSetup = TelemetryController.testReset();
- yield sendPing(true, false);
- Assert.equal(h.snapshot().sum, 1,
- "We must have a ping waiting for the clientId early during startup.");
- // Wait until we are fully initialized. Pings will be assembled but won't get
- // sent before then.
- yield promisePingSetup;
-
- let ping = yield PingServer.promiseNextPing();
- // Fetch the client ID after initializing and fetching the the ping, so we
- // don't unintentionally trigger its loading. We'll still need the client ID
- // to see if the ping looks sane.
- gClientID = yield ClientID.getClientID();
-
- checkPingFormat(ping, TEST_PING_TYPE, true, false);
- Assert.equal(ping.clientId, gClientID, "The correct clientId must be reported.");
-
- // Shutdown Telemetry so we can safely restart it.
- yield TelemetryController.testShutdown();
- yield TelemetryStorage.testClearPendingPings();
-
- // We should have cached the client ID now. Lets confirm that by checking it before
- // the async ping setup is finished.
- h.clear();
- promisePingSetup = TelemetryController.testReset();
- yield sendPing(true, false);
- yield promisePingSetup;
-
- // Check that we received the cached client id.
- Assert.equal(h.snapshot().sum, 0, "We must have used the cached clientId.");
- ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, TEST_PING_TYPE, true, false);
- Assert.equal(ping.clientId, gClientID,
- "Telemetry should report the correct cached clientId.");
-
- // Check that sending a ping without relying on the cache, after the
- // initialization, still works.
- Preferences.reset(PREF_CACHED_CLIENTID);
- yield TelemetryController.testShutdown();
- yield TelemetryStorage.testClearPendingPings();
- yield TelemetryController.testReset();
- yield sendPing(true, false);
- ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, TEST_PING_TYPE, true, false);
- Assert.equal(ping.clientId, gClientID, "The correct clientId must be reported.");
- Assert.equal(h.snapshot().sum, 0, "No ping should have been waiting for a clientId.");
-});
-
-add_task(function* test_pingHasEnvironment() {
- // Send a ping with the environment data.
- yield sendPing(false, true);
- let ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, TEST_PING_TYPE, false, true);
-
- // Test a field in the environment build section.
- Assert.equal(ping.application.buildId, ping.environment.build.buildId);
-});
-
-add_task(function* test_pingHasEnvironmentAndClientId() {
- // Send a ping with the environment data and client id.
- yield sendPing(true, true);
- let ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, TEST_PING_TYPE, true, true);
-
- // Test a field in the environment build section.
- Assert.equal(ping.application.buildId, ping.environment.build.buildId);
- // Test that we have the correct clientId.
- Assert.equal(ping.clientId, gClientID, "The correct clientId must be reported.");
-});
-
-add_task(function* test_archivePings() {
- let now = new Date(2009, 10, 18, 12, 0, 0);
- fakeNow(now);
-
- // Disable ping upload so that pings don't get sent.
- // With unified telemetry the FHR upload pref controls this,
- // with non-unified telemetry the Telemetry enabled pref.
- const isUnified = Preferences.get(PREF_UNIFIED, false);
- const uploadPref = isUnified ? PREF_FHR_UPLOAD_ENABLED : PREF_ENABLED;
- Preferences.set(uploadPref, false);
-
- // If we're using unified telemetry, disabling ping upload will generate a "deletion"
- // ping. Catch it.
- if (isUnified) {
- let ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, DELETION_PING_TYPE, true, false);
- }
-
- // Register a new Ping Handler that asserts if a ping is received, then send a ping.
- PingServer.registerPingHandler(() => Assert.ok(false, "Telemetry must not send pings if not allowed to."));
- let pingId = yield sendPing(true, true);
-
- // Check that the ping was archived, even with upload disabled.
- let ping = yield TelemetryArchive.promiseArchivedPingById(pingId);
- Assert.equal(ping.id, pingId, "TelemetryController should still archive pings.");
-
- // Check that pings don't get archived if not allowed to.
- now = new Date(2010, 10, 18, 12, 0, 0);
- fakeNow(now);
- Preferences.set(PREF_ARCHIVE_ENABLED, false);
- pingId = yield sendPing(true, true);
- let promise = TelemetryArchive.promiseArchivedPingById(pingId);
- Assert.ok((yield promiseRejects(promise)),
- "TelemetryController should not archive pings if the archive pref is disabled.");
-
- // Enable archiving and the upload so that pings get sent and archived again.
- Preferences.set(uploadPref, true);
- Preferences.set(PREF_ARCHIVE_ENABLED, true);
-
- now = new Date(2014, 6, 18, 22, 0, 0);
- fakeNow(now);
- // Restore the non asserting ping handler.
- PingServer.resetPingHandler();
- pingId = yield sendPing(true, true);
-
- // Check that we archive pings when successfully sending them.
- yield PingServer.promiseNextPing();
- ping = yield TelemetryArchive.promiseArchivedPingById(pingId);
- Assert.equal(ping.id, pingId,
- "TelemetryController should still archive pings if ping upload is enabled.");
-});
-
-// Test that we fuzz the submission time around midnight properly
-// to avoid overloading the telemetry servers.
-add_task(function* test_midnightPingSendFuzzing() {
- const fuzzingDelay = 60 * 60 * 1000;
- fakeMidnightPingFuzzingDelay(fuzzingDelay);
- let now = new Date(2030, 5, 1, 11, 0, 0);
- fakeNow(now);
-
- let waitForTimer = () => new Promise(resolve => {
- fakePingSendTimer((callback, timeout) => {
- resolve([callback, timeout]);
- }, () => {});
- });
-
- PingServer.clearRequests();
- yield TelemetryController.testReset();
-
- // A ping after midnight within the fuzzing delay should not get sent.
- now = new Date(2030, 5, 2, 0, 40, 0);
- fakeNow(now);
- PingServer.registerPingHandler((req, res) => {
- Assert.ok(false, "No ping should be received yet.");
- });
- let timerPromise = waitForTimer();
- yield sendPing(true, true);
- let [timerCallback, timerTimeout] = yield timerPromise;
- Assert.ok(!!timerCallback);
- Assert.deepEqual(futureDate(now, timerTimeout), new Date(2030, 5, 2, 1, 0, 0));
-
- // A ping just before the end of the fuzzing delay should not get sent.
- now = new Date(2030, 5, 2, 0, 59, 59);
- fakeNow(now);
- timerPromise = waitForTimer();
- yield sendPing(true, true);
- [timerCallback, timerTimeout] = yield timerPromise;
- Assert.deepEqual(timerTimeout, 1 * 1000);
-
- // Restore the previous ping handler.
- PingServer.resetPingHandler();
-
- // Setting the clock to after the fuzzing delay, we should trigger the two ping sends
- // with the timer callback.
- now = futureDate(now, timerTimeout);
- fakeNow(now);
- yield timerCallback();
- const pings = yield PingServer.promiseNextPings(2);
- for (let ping of pings) {
- checkPingFormat(ping, TEST_PING_TYPE, true, true);
- }
- yield TelemetrySend.testWaitOnOutgoingPings();
-
- // Moving the clock further we should still send pings immediately.
- now = futureDate(now, 5 * 60 * 1000);
- yield sendPing(true, true);
- let ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, TEST_PING_TYPE, true, true);
- yield TelemetrySend.testWaitOnOutgoingPings();
-
- // Check that pings shortly before midnight are immediately sent.
- now = fakeNow(2030, 5, 3, 23, 59, 0);
- yield sendPing(true, true);
- ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, TEST_PING_TYPE, true, true);
- yield TelemetrySend.testWaitOnOutgoingPings();
-
- // Clean-up.
- fakeMidnightPingFuzzingDelay(0);
- fakePingSendTimer(() => {}, () => {});
-});
-
-add_task(function* test_changePingAfterSubmission() {
- // Submit a ping with a custom payload.
- let payload = { canary: "test" };
- let pingPromise = TelemetryController.submitExternalPing(TEST_PING_TYPE, payload, options);
-
- // Change the payload with a predefined value.
- payload.canary = "changed";
-
- // Wait for the ping to be archived.
- const pingId = yield pingPromise;
-
- // Make sure our changes didn't affect the submitted payload.
- let archivedCopy = yield TelemetryArchive.promiseArchivedPingById(pingId);
- Assert.equal(archivedCopy.payload.canary, "test",
- "The payload must not be changed after being submitted.");
-});
-
-add_task(function* test_telemetryEnabledUnexpectedValue() {
- // Remove the default value for toolkit.telemetry.enabled from the default prefs.
- // Otherwise, we wouldn't be able to set the pref to a string.
- let defaultPrefBranch = Services.prefs.getDefaultBranch(null);
- defaultPrefBranch.deleteBranch(PREF_ENABLED);
-
- // Set the preferences controlling the Telemetry status to a string.
- Preferences.set(PREF_ENABLED, "false");
- // Check that Telemetry is not enabled.
- yield TelemetryController.testReset();
- Assert.equal(Telemetry.canRecordExtended, false,
- "Invalid values must not enable Telemetry recording.");
-
- // Delete the pref again.
- defaultPrefBranch.deleteBranch(PREF_ENABLED);
-
- // Make sure that flipping it to true works.
- Preferences.set(PREF_ENABLED, true);
- yield TelemetryController.testReset();
- Assert.equal(Telemetry.canRecordExtended, true,
- "True must enable Telemetry recording.");
-
- // Also check that the false works as well.
- Preferences.set(PREF_ENABLED, false);
- yield TelemetryController.testReset();
- Assert.equal(Telemetry.canRecordExtended, false,
- "False must disable Telemetry recording.");
-});
-
-add_task(function* test_telemetryCleanFHRDatabase() {
- const FHR_DBNAME_PREF = "datareporting.healthreport.dbName";
- const CUSTOM_DB_NAME = "unlikely.to.be.used.sqlite";
- const DEFAULT_DB_NAME = "healthreport.sqlite";
-
- // Check that we're able to remove a FHR DB with a custom name.
- const CUSTOM_DB_PATHS = [
- OS.Path.join(OS.Constants.Path.profileDir, CUSTOM_DB_NAME),
- OS.Path.join(OS.Constants.Path.profileDir, CUSTOM_DB_NAME + "-wal"),
- OS.Path.join(OS.Constants.Path.profileDir, CUSTOM_DB_NAME + "-shm"),
- ];
- Preferences.set(FHR_DBNAME_PREF, CUSTOM_DB_NAME);
-
- // Write fake DB files to the profile directory.
- for (let dbFilePath of CUSTOM_DB_PATHS) {
- yield OS.File.writeAtomic(dbFilePath, "some data");
- }
-
- // Trigger the cleanup and check that the files were removed.
- yield TelemetryStorage.removeFHRDatabase();
- for (let dbFilePath of CUSTOM_DB_PATHS) {
- Assert.ok(!(yield OS.File.exists(dbFilePath)), "The DB must not be on the disk anymore: " + dbFilePath);
- }
-
- // We should not break anything if there's no DB file.
- yield TelemetryStorage.removeFHRDatabase();
-
- // Check that we're able to remove a FHR DB with the default name.
- Preferences.reset(FHR_DBNAME_PREF);
-
- const DEFAULT_DB_PATHS = [
- OS.Path.join(OS.Constants.Path.profileDir, DEFAULT_DB_NAME),
- OS.Path.join(OS.Constants.Path.profileDir, DEFAULT_DB_NAME + "-wal"),
- OS.Path.join(OS.Constants.Path.profileDir, DEFAULT_DB_NAME + "-shm"),
- ];
-
- // Write fake DB files to the profile directory.
- for (let dbFilePath of DEFAULT_DB_PATHS) {
- yield OS.File.writeAtomic(dbFilePath, "some data");
- }
-
- // Trigger the cleanup and check that the files were removed.
- yield TelemetryStorage.removeFHRDatabase();
- for (let dbFilePath of DEFAULT_DB_PATHS) {
- Assert.ok(!(yield OS.File.exists(dbFilePath)), "The DB must not be on the disk anymore: " + dbFilePath);
- }
-});
-
-add_task(function* stopServer() {
- yield PingServer.stop();
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryControllerBuildID.js b/toolkit/components/telemetry/tests/unit/test_TelemetryControllerBuildID.js
deleted file mode 100644
index b8a88afa2..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryControllerBuildID.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-*/
-/* Test inclusion of previous build ID in telemetry pings when build ID changes.
- * bug 841028
- *
- * Cases to cover:
- * 1) Run with no "previousBuildID" stored in prefs:
- * -> no previousBuildID in telemetry system info, new value set in prefs.
- * 2) previousBuildID in prefs, equal to current build ID:
- * -> no previousBuildID in telemetry, prefs not updated.
- * 3) previousBuildID in prefs, not equal to current build ID:
- * -> previousBuildID in telemetry, new value set in prefs.
- */
-
-"use strict";
-
-Cu.import("resource://gre/modules/Services.jsm", this);
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-// Force the Telemetry enabled preference so that TelemetrySession.testReset() doesn't exit early.
-Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
-
-// Set up our dummy AppInfo object so we can control the appBuildID.
-Cu.import("resource://testing-common/AppInfo.jsm", this);
-updateAppInfo();
-
-// Check that when run with no previous build ID stored, we update the pref but do not
-// put anything into the metadata.
-add_task(function* test_firstRun() {
- yield TelemetryController.testReset();
- let metadata = TelemetrySession.getMetadata();
- do_check_false("previousBuildID" in metadata);
- let appBuildID = getAppInfo().appBuildID;
- let buildIDPref = Services.prefs.getCharPref(TelemetrySession.Constants.PREF_PREVIOUS_BUILDID);
- do_check_eq(appBuildID, buildIDPref);
-});
-
-// Check that a subsequent run with the same build ID does not put prev build ID in
-// metadata. Assumes testFirstRun() has already been called to set the previousBuildID pref.
-add_task(function* test_secondRun() {
- yield TelemetryController.testReset();
- let metadata = TelemetrySession.getMetadata();
- do_check_false("previousBuildID" in metadata);
-});
-
-// Set up telemetry with a different app build ID and check that the old build ID
-// is returned in the metadata and the pref is updated to the new build ID.
-// Assumes testFirstRun() has been called to set the previousBuildID pref.
-const NEW_BUILD_ID = "20130314";
-add_task(function* test_newBuild() {
- let info = getAppInfo();
- let oldBuildID = info.appBuildID;
- info.appBuildID = NEW_BUILD_ID;
- yield TelemetryController.testReset();
- let metadata = TelemetrySession.getMetadata();
- do_check_eq(metadata.previousBuildId, oldBuildID);
- let buildIDPref = Services.prefs.getCharPref(TelemetrySession.Constants.PREF_PREVIOUS_BUILDID);
- do_check_eq(NEW_BUILD_ID, buildIDPref);
-});
-
-
-function run_test() {
- // Make sure we have a profile directory.
- do_get_profile();
-
- run_next_test();
-}
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryControllerShutdown.js b/toolkit/components/telemetry/tests/unit/test_TelemetryControllerShutdown.js
deleted file mode 100644
index 391db0d9d..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryControllerShutdown.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-// Test that TelemetryController sends close to shutdown don't lead
-// to AsyncShutdown timeouts.
-
-"use strict";
-
-Cu.import("resource://gre/modules/Services.jsm", this);
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySend.jsm", this);
-Cu.import("resource://gre/modules/Timer.jsm", this);
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-Cu.import("resource://gre/modules/AsyncShutdown.jsm", this);
-Cu.import("resource://testing-common/httpd.js", this);
-
-const PREF_BRANCH = "toolkit.telemetry.";
-const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
-
-function contentHandler(metadata, response)
-{
- dump("contentHandler called for path: " + metadata._path + "\n");
- // We intentionally don't finish writing the response here to let the
- // client time out.
- response.processAsync();
- response.setHeader("Content-Type", "text/plain");
-}
-
-add_task(function* test_setup() {
- // Addon manager needs a profile directory
- 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.setBoolPref(PREF_FHR_UPLOAD_ENABLED, true);
-});
-
-/**
- * Ensures that TelemetryController does not hang processing shutdown
- * phases. Assumes that Telemetry shutdown routines do not take longer than
- * CRASH_TIMEOUT_MS to complete.
- */
-add_task(function* test_sendTelemetryShutsDownWithinReasonableTimeout() {
- const CRASH_TIMEOUT_MS = 5 * 1000;
- // Enable testing mode for AsyncShutdown, otherwise some testing-only functionality
- // is not available.
- Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
- // Reducing the max delay for waitiing on phases to complete from 1 minute
- // (standard) to 10 seconds to avoid blocking the tests in case of misbehavior.
- Services.prefs.setIntPref("toolkit.asyncshutdown.crash_timeout", CRASH_TIMEOUT_MS);
-
- let httpServer = new HttpServer();
- httpServer.registerPrefixHandler("/", contentHandler);
- httpServer.start(-1);
-
- yield TelemetryController.testSetup();
- TelemetrySend.setServer("http://localhost:" + httpServer.identity.primaryPort);
- let submissionPromise = TelemetryController.submitExternalPing("test-ping-type", {});
-
- // Trigger the AsyncShutdown phase TelemetryController hangs off.
- AsyncShutdown.profileBeforeChange._trigger();
- AsyncShutdown.sendTelemetry._trigger();
- // Now wait for the ping submission.
- yield submissionPromise;
-
- // If we get here, we didn't time out in the shutdown routines.
- Assert.ok(true, "Didn't time out on shutdown.");
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryController_idle.js b/toolkit/components/telemetry/tests/unit/test_TelemetryController_idle.js
deleted file mode 100644
index ca5d1820b..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryController_idle.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-// Check that TelemetrySession notifies correctly on idle-daily.
-
-Cu.import("resource://testing-common/httpd.js", this);
-Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
-Cu.import("resource://gre/modules/Services.jsm", this);
-Cu.import("resource://gre/modules/Task.jsm", this);
-Cu.import("resource://gre/modules/TelemetryStorage.jsm", this);
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySend.jsm", this);
-
-const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
-
-var gHttpServer = null;
-
-add_task(function* test_setup() {
- do_get_profile();
-
- // Make sure we don't generate unexpected pings due to pref changes.
- yield setEmptyPrefWatchlist();
-
- Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
- Services.prefs.setBoolPref(PREF_FHR_UPLOAD_ENABLED, true);
-
- // Start the webserver to check if the pending ping correctly arrives.
- gHttpServer = new HttpServer();
- gHttpServer.start(-1);
-});
-
-add_task(function* testSendPendingOnIdleDaily() {
- // Create a valid pending ping.
- const PENDING_PING = {
- id: "2133234d-4ea1-44f4-909e-ce8c6c41e0fc",
- type: "test-ping",
- version: 4,
- application: {},
- payload: {},
- };
- yield TelemetryStorage.savePing(PENDING_PING, true);
-
- // Telemetry will not send this ping at startup, because it's not overdue.
- yield TelemetryController.testSetup();
- TelemetrySend.setServer("http://localhost:" + gHttpServer.identity.primaryPort);
-
- let pendingPromise = new Promise(resolve =>
- gHttpServer.registerPrefixHandler("/submit/telemetry/", request => resolve(request)));
-
- let gatherPromise = PromiseUtils.defer();
- Services.obs.addObserver(gatherPromise.resolve, "gather-telemetry", false);
-
- // Check that we are correctly receiving the gather-telemetry notification.
- TelemetrySession.observe(null, "idle-daily", null);
- yield gatherPromise;
- Assert.ok(true, "Received gather-telemetry notification.");
-
- Services.obs.removeObserver(gatherPromise.resolve, "gather-telemetry");
-
- // Check that the pending ping is correctly received.
- let ns = {};
- let module = Cu.import("resource://gre/modules/TelemetrySend.jsm", ns);
- module.TelemetrySendImpl.observe(null, "idle-daily", null);
- let request = yield pendingPromise;
- let ping = decodeRequestPayload(request);
-
- // Validate the ping data.
- Assert.equal(ping.id, PENDING_PING.id);
- Assert.equal(ping.type, PENDING_PING.type);
-
- yield new Promise(resolve => gHttpServer.stop(resolve));
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
deleted file mode 100644
index 2518a80ba..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ /dev/null
@@ -1,1522 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://gre/modules/AddonManager.jsm");
-Cu.import("resource://gre/modules/TelemetryEnvironment.jsm", this);
-Cu.import("resource://gre/modules/Preferences.jsm", this);
-Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-Cu.import("resource://testing-common/AddonManagerTesting.jsm");
-Cu.import("resource://testing-common/httpd.js");
-Cu.import("resource://testing-common/MockRegistrar.jsm", this);
-Cu.import("resource://gre/modules/FileUtils.jsm");
-
-// AttributionCode is only needed for Firefox
-XPCOMUtils.defineLazyModuleGetter(this, "AttributionCode",
- "resource:///modules/AttributionCode.jsm");
-
-// Lazy load |LightweightThemeManager|, we won't be using it on Gonk.
-XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
- "resource://gre/modules/LightweightThemeManager.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge",
- "resource://gre/modules/ProfileAge.jsm");
-
-// The webserver hosting the addons.
-var gHttpServer = null;
-// The URL of the webserver root.
-var gHttpRoot = null;
-// The URL of the data directory, on the webserver.
-var gDataRoot = null;
-
-const PLATFORM_VERSION = "1.9.2";
-const APP_VERSION = "1";
-const APP_ID = "xpcshell@tests.mozilla.org";
-const APP_NAME = "XPCShell";
-
-const DISTRIBUTION_ID = "distributor-id";
-const DISTRIBUTION_VERSION = "4.5.6b";
-const DISTRIBUTOR_NAME = "Some Distributor";
-const DISTRIBUTOR_CHANNEL = "A Channel";
-const PARTNER_NAME = "test";
-const PARTNER_ID = "NicePartner-ID-3785";
-const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC = "distribution-customization-complete";
-
-const GFX_VENDOR_ID = "0xabcd";
-const GFX_DEVICE_ID = "0x1234";
-
-// The profile reset date, in milliseconds (Today)
-const PROFILE_RESET_DATE_MS = Date.now();
-// The profile creation date, in milliseconds (Yesterday).
-const PROFILE_CREATION_DATE_MS = PROFILE_RESET_DATE_MS - MILLISECONDS_PER_DAY;
-
-const FLASH_PLUGIN_NAME = "Shockwave Flash";
-const FLASH_PLUGIN_DESC = "A mock flash plugin";
-const FLASH_PLUGIN_VERSION = "\u201c1.1.1.1\u201d";
-const PLUGIN_MIME_TYPE1 = "application/x-shockwave-flash";
-const PLUGIN_MIME_TYPE2 = "text/plain";
-
-const PLUGIN2_NAME = "Quicktime";
-const PLUGIN2_DESC = "A mock Quicktime plugin";
-const PLUGIN2_VERSION = "2.3";
-
-const PERSONA_ID = "3785";
-// Defined by LightweightThemeManager, it is appended to the PERSONA_ID.
-const PERSONA_ID_SUFFIX = "@personas.mozilla.org";
-const PERSONA_NAME = "Test Theme";
-const PERSONA_DESCRIPTION = "A nice theme/persona description.";
-
-const PLUGIN_UPDATED_TOPIC = "plugins-list-updated";
-
-// system add-ons are enabled at startup, so record date when the test starts
-const SYSTEM_ADDON_INSTALL_DATE = Date.now();
-
-// Valid attribution code to write so that settings.attribution can be tested.
-const ATTRIBUTION_CODE = "source%3Dgoogle.com";
-
-/**
- * Used to mock plugin tags in our fake plugin host.
- */
-function PluginTag(aName, aDescription, aVersion, aEnabled) {
- this.name = aName;
- this.description = aDescription;
- this.version = aVersion;
- this.disabled = !aEnabled;
-}
-
-PluginTag.prototype = {
- name: null,
- description: null,
- version: null,
- filename: null,
- fullpath: null,
- disabled: false,
- blocklisted: false,
- clicktoplay: true,
-
- mimeTypes: [ PLUGIN_MIME_TYPE1, PLUGIN_MIME_TYPE2 ],
-
- getMimeTypes: function(count) {
- count.value = this.mimeTypes.length;
- return this.mimeTypes;
- }
-};
-
-// A container for the plugins handled by the fake plugin host.
-var gInstalledPlugins = [
- new PluginTag("Java", "A mock Java plugin", "1.0", false /* Disabled */),
- new PluginTag(FLASH_PLUGIN_NAME, FLASH_PLUGIN_DESC, FLASH_PLUGIN_VERSION, true),
-];
-
-// A fake plugin host for testing plugin telemetry environment.
-var PluginHost = {
- getPluginTags: function(countRef) {
- countRef.value = gInstalledPlugins.length;
- return gInstalledPlugins;
- },
-
- QueryInterface: function(iid) {
- if (iid.equals(Ci.nsIPluginHost)
- || iid.equals(Ci.nsISupports))
- return this;
-
- throw Components.results.NS_ERROR_NO_INTERFACE;
- }
-}
-
-function registerFakePluginHost() {
- MockRegistrar.register("@mozilla.org/plugin/host;1", PluginHost);
-}
-
-var SysInfo = {
- overrides: {},
-
- getProperty(name) {
- // Assert.ok(false, "Mock SysInfo: " + name + ", " + JSON.stringify(this.overrides));
- if (name in this.overrides) {
- return this.overrides[name];
- }
- try {
- return this._genuine.getProperty(name);
- } catch (ex) {
- throw ex;
- }
- },
-
- get(name) {
- return this._genuine.get(name);
- },
-
- QueryInterface(iid) {
- if (iid.equals(Ci.nsIPropertyBag2)
- || iid.equals(Ci.nsISupports))
- return this;
-
- throw Cr.NS_ERROR_NO_INTERFACE;
- }
-};
-
-function registerFakeSysInfo() {
- MockRegistrar.register("@mozilla.org/system-info;1", SysInfo);
-}
-
-function MockAddonWrapper(aAddon) {
- this.addon = aAddon;
-}
-MockAddonWrapper.prototype = {
- get id() {
- return this.addon.id;
- },
-
- get type() {
- return "service";
- },
-
- get appDisabled() {
- return false;
- },
-
- get isCompatible() {
- return true;
- },
-
- get isPlatformCompatible() {
- return true;
- },
-
- get scope() {
- return AddonManager.SCOPE_PROFILE;
- },
-
- get foreignInstall() {
- return false;
- },
-
- get providesUpdatesSecurely() {
- return true;
- },
-
- get blocklistState() {
- return 0; // Not blocked.
- },
-
- get pendingOperations() {
- return AddonManager.PENDING_NONE;
- },
-
- get permissions() {
- return AddonManager.PERM_CAN_UNINSTALL | AddonManager.PERM_CAN_DISABLE;
- },
-
- get isActive() {
- return true;
- },
-
- get name() {
- return this.addon.name;
- },
-
- get version() {
- return this.addon.version;
- },
-
- get creator() {
- return new AddonManagerPrivate.AddonAuthor(this.addon.author);
- },
-
- get userDisabled() {
- return this.appDisabled;
- },
-};
-
-function createMockAddonProvider(aName) {
- let mockProvider = {
- _addons: [],
-
- get name() {
- return aName;
- },
-
- addAddon: function(aAddon) {
- this._addons.push(aAddon);
- AddonManagerPrivate.callAddonListeners("onInstalled", new MockAddonWrapper(aAddon));
- },
-
- getAddonsByTypes: function (aTypes, aCallback) {
- aCallback(this._addons.map(a => new MockAddonWrapper(a)));
- },
-
- shutdown() {
- return Promise.resolve();
- },
- };
-
- return mockProvider;
-}
-
-/**
- * Used to spoof the Persona Id.
- */
-function spoofTheme(aId, aName, aDesc) {
- return {
- id: aId,
- name: aName,
- description: aDesc,
- headerURL: "http://lwttest.invalid/a.png",
- footerURL: "http://lwttest.invalid/b.png",
- textcolor: Math.random().toString(),
- accentcolor: Math.random().toString()
- };
-}
-
-function spoofGfxAdapter() {
- try {
- let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
- gfxInfo.spoofVendorID(GFX_VENDOR_ID);
- gfxInfo.spoofDeviceID(GFX_DEVICE_ID);
- } catch (x) {
- // If we can't test gfxInfo, that's fine, we'll note it later.
- }
-}
-
-function spoofProfileReset() {
- let profileAccessor = new ProfileAge();
-
- return profileAccessor.writeTimes({
- created: PROFILE_CREATION_DATE_MS,
- reset: PROFILE_RESET_DATE_MS
- });
-}
-
-function spoofPartnerInfo() {
- let prefsToSpoof = {};
- prefsToSpoof["distribution.id"] = DISTRIBUTION_ID;
- prefsToSpoof["distribution.version"] = DISTRIBUTION_VERSION;
- prefsToSpoof["app.distributor"] = DISTRIBUTOR_NAME;
- prefsToSpoof["app.distributor.channel"] = DISTRIBUTOR_CHANNEL;
- prefsToSpoof["app.partner.test"] = PARTNER_NAME;
- prefsToSpoof["mozilla.partner.id"] = PARTNER_ID;
-
- // Spoof the preferences.
- for (let pref in prefsToSpoof) {
- Preferences.set(pref, prefsToSpoof[pref]);
- }
-}
-
-function getAttributionFile() {
- let file = Services.dirsvc.get("LocalAppData", Ci.nsIFile);
- file.append("mozilla");
- file.append(AppConstants.MOZ_APP_NAME);
- file.append("postSigningData");
- return file;
-}
-
-function spoofAttributionData() {
- if (gIsWindows) {
- AttributionCode._clearCache();
- let stream = Cc["@mozilla.org/network/file-output-stream;1"].
- createInstance(Ci.nsIFileOutputStream);
- stream.init(getAttributionFile(), -1, -1, 0);
- stream.write(ATTRIBUTION_CODE, ATTRIBUTION_CODE.length);
- }
-}
-
-function cleanupAttributionData() {
- if (gIsWindows) {
- getAttributionFile().remove(false);
- AttributionCode._clearCache();
- }
-}
-
-/**
- * Check that a value is a string and not empty.
- *
- * @param aValue The variable to check.
- * @return True if |aValue| has type "string" and is not empty, False otherwise.
- */
-function checkString(aValue) {
- return (typeof aValue == "string") && (aValue != "");
-}
-
-/**
- * If value is non-null, check if it's a valid string.
- *
- * @param aValue The variable to check.
- * @return True if it's null or a valid string, false if it's non-null and an invalid
- * string.
- */
-function checkNullOrString(aValue) {
- if (aValue) {
- return checkString(aValue);
- } else if (aValue === null) {
- return true;
- }
-
- return false;
-}
-
-/**
- * If value is non-null, check if it's a boolean.
- *
- * @param aValue The variable to check.
- * @return True if it's null or a valid boolean, false if it's non-null and an invalid
- * boolean.
- */
-function checkNullOrBool(aValue) {
- return aValue === null || (typeof aValue == "boolean");
-}
-
-function checkBuildSection(data) {
- const expectedInfo = {
- applicationId: APP_ID,
- applicationName: APP_NAME,
- buildId: gAppInfo.appBuildID,
- version: APP_VERSION,
- vendor: "Mozilla",
- platformVersion: PLATFORM_VERSION,
- xpcomAbi: "noarch-spidermonkey",
- };
-
- Assert.ok("build" in data, "There must be a build section in Environment.");
-
- for (let f in expectedInfo) {
- Assert.ok(checkString(data.build[f]), f + " must be a valid string.");
- Assert.equal(data.build[f], expectedInfo[f], f + " must have the correct value.");
- }
-
- // Make sure architecture is in the environment.
- Assert.ok(checkString(data.build.architecture));
-
- if (gIsMac) {
- let macUtils = Cc["@mozilla.org/xpcom/mac-utils;1"].getService(Ci.nsIMacUtils);
- if (macUtils && macUtils.isUniversalBinary) {
- Assert.ok(checkString(data.build.architecturesInBinary));
- }
- }
-}
-
-function checkSettingsSection(data) {
- const EXPECTED_FIELDS_TYPES = {
- blocklistEnabled: "boolean",
- e10sEnabled: "boolean",
- e10sCohort: "string",
- telemetryEnabled: "boolean",
- locale: "string",
- update: "object",
- userPrefs: "object",
- };
-
- Assert.ok("settings" in data, "There must be a settings section in Environment.");
-
- for (let f in EXPECTED_FIELDS_TYPES) {
- Assert.equal(typeof data.settings[f], EXPECTED_FIELDS_TYPES[f],
- f + " must have the correct type.");
- }
-
- // Check "addonCompatibilityCheckEnabled" separately, as it is not available
- // on Gonk.
- if (gIsGonk) {
- Assert.ok(!("addonCompatibilityCheckEnabled" in data.settings), "Must not be available on Gonk.");
- } else {
- Assert.equal(data.settings.addonCompatibilityCheckEnabled, AddonManager.checkCompatibility);
- }
-
- // Check "isDefaultBrowser" separately, as it is not available on Android an can either be
- // null or boolean on other platforms.
- if (gIsAndroid) {
- Assert.ok(!("isDefaultBrowser" in data.settings), "Must not be available on Android.");
- } else {
- Assert.ok(checkNullOrBool(data.settings.isDefaultBrowser));
- }
-
- // Check "channel" separately, as it can either be null or string.
- let update = data.settings.update;
- Assert.ok(checkNullOrString(update.channel));
- Assert.equal(typeof update.enabled, "boolean");
- Assert.equal(typeof update.autoDownload, "boolean");
-
- // Check "defaultSearchEngine" separately, as it can either be undefined or string.
- if ("defaultSearchEngine" in data.settings) {
- checkString(data.settings.defaultSearchEngine);
- Assert.equal(typeof data.settings.defaultSearchEngineData, "object");
- }
-
- if ("attribution" in data.settings) {
- Assert.equal(typeof data.settings.attribution, "object");
- Assert.equal(data.settings.attribution.source, "google.com");
- }
-}
-
-function checkProfileSection(data) {
- Assert.ok("profile" in data, "There must be a profile section in Environment.");
- Assert.equal(data.profile.creationDate, truncateToDays(PROFILE_CREATION_DATE_MS));
- Assert.equal(data.profile.resetDate, truncateToDays(PROFILE_RESET_DATE_MS));
-}
-
-function checkPartnerSection(data, isInitial) {
- const EXPECTED_FIELDS = {
- distributionId: DISTRIBUTION_ID,
- distributionVersion: DISTRIBUTION_VERSION,
- partnerId: PARTNER_ID,
- distributor: DISTRIBUTOR_NAME,
- distributorChannel: DISTRIBUTOR_CHANNEL,
- };
-
- Assert.ok("partner" in data, "There must be a partner section in Environment.");
-
- for (let f in EXPECTED_FIELDS) {
- let expected = isInitial ? null : EXPECTED_FIELDS[f];
- Assert.strictEqual(data.partner[f], expected, f + " must have the correct value.");
- }
-
- // Check that "partnerNames" exists and contains the correct element.
- Assert.ok(Array.isArray(data.partner.partnerNames));
- if (isInitial) {
- Assert.equal(data.partner.partnerNames.length, 0);
- } else {
- Assert.ok(data.partner.partnerNames.includes(PARTNER_NAME));
- }
-}
-
-function checkGfxAdapter(data) {
- const EXPECTED_ADAPTER_FIELDS_TYPES = {
- description: "string",
- vendorID: "string",
- deviceID: "string",
- subsysID: "string",
- RAM: "number",
- driver: "string",
- driverVersion: "string",
- driverDate: "string",
- GPUActive: "boolean",
- };
-
- for (let f in EXPECTED_ADAPTER_FIELDS_TYPES) {
- Assert.ok(f in data, f + " must be available.");
-
- if (data[f]) {
- // Since we have a non-null value, check if it has the correct type.
- Assert.equal(typeof data[f], EXPECTED_ADAPTER_FIELDS_TYPES[f],
- f + " must have the correct type.");
- }
- }
-}
-
-function checkSystemSection(data) {
- const EXPECTED_FIELDS = [ "memoryMB", "cpu", "os", "hdd", "gfx" ];
- const EXPECTED_HDD_FIELDS = [ "profile", "binary", "system" ];
-
- Assert.ok("system" in data, "There must be a system section in Environment.");
-
- // Make sure we have all the top level sections and fields.
- for (let f of EXPECTED_FIELDS) {
- Assert.ok(f in data.system, f + " must be available.");
- }
-
- Assert.ok(Number.isFinite(data.system.memoryMB), "MemoryMB must be a number.");
-
- if (gIsWindows || gIsMac || gIsLinux) {
- let EXTRA_CPU_FIELDS = ["cores", "model", "family", "stepping",
- "l2cacheKB", "l3cacheKB", "speedMHz", "vendor"];
-
- for (let f of EXTRA_CPU_FIELDS) {
- // Note this is testing TelemetryEnvironment.js only, not that the
- // values are valid - null is the fallback.
- Assert.ok(f in data.system.cpu, f + " must be available under cpu.");
- }
-
- if (gIsWindows) {
- Assert.equal(typeof data.system.isWow64, "boolean",
- "isWow64 must be available on Windows and have the correct type.");
- Assert.ok("virtualMaxMB" in data.system, "virtualMaxMB must be available.");
- Assert.ok(Number.isFinite(data.system.virtualMaxMB),
- "virtualMaxMB must be a number.");
- }
-
- // We insist these are available
- for (let f of ["cores"]) {
- Assert.ok(!(f in data.system.cpu) ||
- Number.isFinite(data.system.cpu[f]),
- f + " must be a number if non null.");
- }
-
- // These should be numbers if they are not null
- for (let f of ["model", "family", "stepping", "l2cacheKB",
- "l3cacheKB", "speedMHz"]) {
- Assert.ok(!(f in data.system.cpu) ||
- data.system.cpu[f] === null ||
- Number.isFinite(data.system.cpu[f]),
- f + " must be a number if non null.");
- }
- }
-
- let cpuData = data.system.cpu;
- Assert.ok(Number.isFinite(cpuData.count), "CPU count must be a number.");
- Assert.ok(Array.isArray(cpuData.extensions), "CPU extensions must be available.");
-
- // Device data is only available on Android or Gonk.
- if (gIsAndroid || gIsGonk) {
- let deviceData = data.system.device;
- Assert.ok(checkNullOrString(deviceData.model));
- Assert.ok(checkNullOrString(deviceData.manufacturer));
- Assert.ok(checkNullOrString(deviceData.hardware));
- Assert.ok(checkNullOrBool(deviceData.isTablet));
- }
-
- let osData = data.system.os;
- Assert.ok(checkNullOrString(osData.name));
- Assert.ok(checkNullOrString(osData.version));
- Assert.ok(checkNullOrString(osData.locale));
-
- // Service pack is only available on Windows.
- if (gIsWindows) {
- Assert.ok(Number.isFinite(osData["servicePackMajor"]),
- "ServicePackMajor must be a number.");
- Assert.ok(Number.isFinite(osData["servicePackMinor"]),
- "ServicePackMinor must be a number.");
- if ("windowsBuildNumber" in osData) {
- // This might not be available on all Windows platforms.
- Assert.ok(Number.isFinite(osData["windowsBuildNumber"]),
- "windowsBuildNumber must be a number.");
- }
- if ("windowsUBR" in osData) {
- // This might not be available on all Windows platforms.
- Assert.ok((osData["windowsUBR"] === null) || Number.isFinite(osData["windowsUBR"]),
- "windowsUBR must be null or a number.");
- }
- } else if (gIsAndroid || gIsGonk) {
- Assert.ok(checkNullOrString(osData.kernelVersion));
- }
-
- let check = gIsWindows ? checkString : checkNullOrString;
- for (let disk of EXPECTED_HDD_FIELDS) {
- Assert.ok(check(data.system.hdd[disk].model));
- Assert.ok(check(data.system.hdd[disk].revision));
- }
-
- let gfxData = data.system.gfx;
- Assert.ok("D2DEnabled" in gfxData);
- Assert.ok("DWriteEnabled" in gfxData);
- // DWriteVersion is disabled due to main thread jank and will be enabled
- // again as part of bug 1154500.
- // Assert.ok("DWriteVersion" in gfxData);
- if (gIsWindows) {
- Assert.equal(typeof gfxData.D2DEnabled, "boolean");
- Assert.equal(typeof gfxData.DWriteEnabled, "boolean");
- // As above, will be enabled again as part of bug 1154500.
- // Assert.ok(checkString(gfxData.DWriteVersion));
- }
-
- Assert.ok("adapters" in gfxData);
- Assert.ok(gfxData.adapters.length > 0, "There must be at least one GFX adapter.");
- for (let adapter of gfxData.adapters) {
- checkGfxAdapter(adapter);
- }
- Assert.equal(typeof gfxData.adapters[0].GPUActive, "boolean");
- Assert.ok(gfxData.adapters[0].GPUActive, "The first GFX adapter must be active.");
-
- Assert.ok(Array.isArray(gfxData.monitors));
- if (gIsWindows || gIsMac) {
- Assert.ok(gfxData.monitors.length >= 1, "There is at least one monitor.");
- Assert.equal(typeof gfxData.monitors[0].screenWidth, "number");
- Assert.equal(typeof gfxData.monitors[0].screenHeight, "number");
- if (gIsWindows) {
- Assert.equal(typeof gfxData.monitors[0].refreshRate, "number");
- Assert.equal(typeof gfxData.monitors[0].pseudoDisplay, "boolean");
- }
- if (gIsMac) {
- Assert.equal(typeof gfxData.monitors[0].scale, "number");
- }
- }
-
- Assert.equal(typeof gfxData.features, "object");
- Assert.equal(typeof gfxData.features.compositor, "string");
-
- try {
- // If we've not got nsIGfxInfoDebug, then this will throw and stop us doing
- // this test.
- let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
-
- if (gIsWindows || gIsMac) {
- Assert.equal(GFX_VENDOR_ID, gfxData.adapters[0].vendorID);
- Assert.equal(GFX_DEVICE_ID, gfxData.adapters[0].deviceID);
- }
-
- let features = gfxInfo.getFeatures();
- Assert.equal(features.compositor, gfxData.features.compositor);
- Assert.equal(features.opengl, gfxData.features.opengl);
- Assert.equal(features.webgl, gfxData.features.webgl);
- }
- catch (e) {}
-}
-
-function checkActiveAddon(data) {
- let signedState = mozinfo.addon_signing ? "number" : "undefined";
- // system add-ons have an undefined signState
- if (data.isSystem)
- signedState = "undefined";
-
- const EXPECTED_ADDON_FIELDS_TYPES = {
- blocklisted: "boolean",
- name: "string",
- userDisabled: "boolean",
- appDisabled: "boolean",
- version: "string",
- scope: "number",
- type: "string",
- foreignInstall: "boolean",
- hasBinaryComponents: "boolean",
- installDay: "number",
- updateDay: "number",
- signedState: signedState,
- isSystem: "boolean",
- };
-
- for (let f in EXPECTED_ADDON_FIELDS_TYPES) {
- Assert.ok(f in data, f + " must be available.");
- Assert.equal(typeof data[f], EXPECTED_ADDON_FIELDS_TYPES[f],
- f + " must have the correct type.");
- }
-
- // We check "description" separately, as it can be null.
- Assert.ok(checkNullOrString(data.description));
-}
-
-function checkPlugin(data) {
- const EXPECTED_PLUGIN_FIELDS_TYPES = {
- name: "string",
- version: "string",
- description: "string",
- blocklisted: "boolean",
- disabled: "boolean",
- clicktoplay: "boolean",
- updateDay: "number",
- };
-
- for (let f in EXPECTED_PLUGIN_FIELDS_TYPES) {
- Assert.ok(f in data, f + " must be available.");
- Assert.equal(typeof data[f], EXPECTED_PLUGIN_FIELDS_TYPES[f],
- f + " must have the correct type.");
- }
-
- Assert.ok(Array.isArray(data.mimeTypes));
- for (let type of data.mimeTypes) {
- Assert.ok(checkString(type));
- }
-}
-
-function checkTheme(data) {
- // "hasBinaryComponents" is not available when testing.
- const EXPECTED_THEME_FIELDS_TYPES = {
- id: "string",
- blocklisted: "boolean",
- name: "string",
- userDisabled: "boolean",
- appDisabled: "boolean",
- version: "string",
- scope: "number",
- foreignInstall: "boolean",
- installDay: "number",
- updateDay: "number",
- };
-
- for (let f in EXPECTED_THEME_FIELDS_TYPES) {
- Assert.ok(f in data, f + " must be available.");
- Assert.equal(typeof data[f], EXPECTED_THEME_FIELDS_TYPES[f],
- f + " must have the correct type.");
- }
-
- // We check "description" separately, as it can be null.
- Assert.ok(checkNullOrString(data.description));
-}
-
-function checkActiveGMPlugin(data) {
- // GMP plugin version defaults to null until GMPDownloader runs to update it.
- if (data.version) {
- Assert.equal(typeof data.version, "string");
- }
- Assert.equal(typeof data.userDisabled, "boolean");
- Assert.equal(typeof data.applyBackgroundUpdates, "number");
-}
-
-function checkAddonsSection(data, expectBrokenAddons) {
- const EXPECTED_FIELDS = [
- "activeAddons", "theme", "activePlugins", "activeGMPlugins", "activeExperiment",
- "persona",
- ];
-
- Assert.ok("addons" in data, "There must be an addons section in Environment.");
- for (let f of EXPECTED_FIELDS) {
- Assert.ok(f in data.addons, f + " must be available.");
- }
-
- // Check the active addons, if available.
- if (!expectBrokenAddons) {
- let activeAddons = data.addons.activeAddons;
- for (let addon in activeAddons) {
- checkActiveAddon(activeAddons[addon]);
- }
- }
-
- // Check "theme" structure.
- if (Object.keys(data.addons.theme).length !== 0) {
- checkTheme(data.addons.theme);
- }
-
- // Check the active plugins.
- Assert.ok(Array.isArray(data.addons.activePlugins));
- for (let plugin of data.addons.activePlugins) {
- checkPlugin(plugin);
- }
-
- // Check active GMPlugins
- let activeGMPlugins = data.addons.activeGMPlugins;
- for (let gmPlugin in activeGMPlugins) {
- checkActiveGMPlugin(activeGMPlugins[gmPlugin]);
- }
-
- // Check the active Experiment
- let experiment = data.addons.activeExperiment;
- if (Object.keys(experiment).length !== 0) {
- Assert.ok(checkString(experiment.id));
- Assert.ok(checkString(experiment.branch));
- }
-
- // Check persona
- Assert.ok(checkNullOrString(data.addons.persona));
-}
-
-function checkEnvironmentData(data, isInitial = false, expectBrokenAddons = false) {
- checkBuildSection(data);
- checkSettingsSection(data);
- checkProfileSection(data);
- checkPartnerSection(data, isInitial);
- checkSystemSection(data);
- checkAddonsSection(data, expectBrokenAddons);
-}
-
-add_task(function* setup() {
- // Load a custom manifest to provide search engine loading from JAR files.
- do_load_manifest("chrome.manifest");
- registerFakeSysInfo();
- spoofGfxAdapter();
- do_get_profile();
-
- // The system add-on must be installed before AddonManager is started.
- const distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "app0"], true);
- do_get_file("system.xpi").copyTo(distroDir, "tel-system-xpi@tests.mozilla.org.xpi");
- let system_addon = FileUtils.File(distroDir.path);
- system_addon.append("tel-system-xpi@tests.mozilla.org.xpi");
- system_addon.lastModifiedTime = SYSTEM_ADDON_INSTALL_DATE;
- loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
-
- // Spoof the persona ID, but not on Gonk.
- if (!gIsGonk) {
- LightweightThemeManager.currentTheme =
- spoofTheme(PERSONA_ID, PERSONA_NAME, PERSONA_DESCRIPTION);
- }
- // Register a fake plugin host for consistent flash version data.
- registerFakePluginHost();
-
- // Setup a webserver to serve Addons, Plugins, etc.
- gHttpServer = new HttpServer();
- gHttpServer.start(-1);
- let port = gHttpServer.identity.primaryPort;
- gHttpRoot = "http://localhost:" + port + "/";
- gDataRoot = gHttpRoot + "data/";
- gHttpServer.registerDirectory("/data/", do_get_cwd());
- do_register_cleanup(() => gHttpServer.stop(() => {}));
-
- // Create the attribution data file, so that settings.attribution will exist.
- // The attribution functionality only exists in Firefox.
- if (AppConstants.MOZ_BUILD_APP == "browser") {
- spoofAttributionData();
- do_register_cleanup(cleanupAttributionData);
- }
-
- yield spoofProfileReset();
- TelemetryEnvironment.delayedInit();
-});
-
-add_task(function* test_checkEnvironment() {
- let environmentData = yield TelemetryEnvironment.onInitialized();
- checkEnvironmentData(environmentData, true);
-
- spoofPartnerInfo();
- Services.obs.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, null);
-
- environmentData = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(environmentData);
-});
-
-add_task(function* test_prefWatchPolicies() {
- const PREF_TEST_1 = "toolkit.telemetry.test.pref_new";
- const PREF_TEST_2 = "toolkit.telemetry.test.pref1";
- const PREF_TEST_3 = "toolkit.telemetry.test.pref2";
- const PREF_TEST_4 = "toolkit.telemetry.test.pref_old";
- const PREF_TEST_5 = "toolkit.telemetry.test.requiresRestart";
-
- const expectedValue = "some-test-value";
- const unexpectedValue = "unexpected-test-value";
-
- const PREFS_TO_WATCH = new Map([
- [PREF_TEST_1, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
- [PREF_TEST_2, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
- [PREF_TEST_3, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
- [PREF_TEST_4, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
- [PREF_TEST_5, {what: TelemetryEnvironment.RECORD_PREF_VALUE, requiresRestart: true}],
- ]);
-
- Preferences.set(PREF_TEST_4, expectedValue);
- Preferences.set(PREF_TEST_5, expectedValue);
-
- // Set the Environment preferences to watch.
- TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
- let deferred = PromiseUtils.defer();
-
- // Check that the pref values are missing or present as expected
- Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST_1], undefined);
- Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST_4], expectedValue);
- Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST_5], expectedValue);
-
- TelemetryEnvironment.registerChangeListener("testWatchPrefs",
- (reason, data) => deferred.resolve(data));
- let oldEnvironmentData = TelemetryEnvironment.currentEnvironment;
-
- // Trigger a change in the watched preferences.
- Preferences.set(PREF_TEST_1, expectedValue);
- Preferences.set(PREF_TEST_2, false);
- Preferences.set(PREF_TEST_5, unexpectedValue);
- let eventEnvironmentData = yield deferred.promise;
-
- // Unregister the listener.
- TelemetryEnvironment.unregisterChangeListener("testWatchPrefs");
-
- // Check environment contains the correct data.
- Assert.deepEqual(oldEnvironmentData, eventEnvironmentData);
- let userPrefs = TelemetryEnvironment.currentEnvironment.settings.userPrefs;
-
- Assert.equal(userPrefs[PREF_TEST_1], expectedValue,
- "Environment contains the correct preference value.");
- Assert.equal(userPrefs[PREF_TEST_2], "<user-set>",
- "Report that the pref was user set but the value is not shown.");
- Assert.ok(!(PREF_TEST_3 in userPrefs),
- "Do not report if preference not user set.");
- Assert.equal(userPrefs[PREF_TEST_5], expectedValue,
- "The pref value in the environment data should still be the same");
-});
-
-add_task(function* test_prefWatch_prefReset() {
- const PREF_TEST = "toolkit.telemetry.test.pref1";
- const PREFS_TO_WATCH = new Map([
- [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
- ]);
-
- // Set the preference to a non-default value.
- Preferences.set(PREF_TEST, false);
-
- // Set the Environment preferences to watch.
- TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
- let deferred = PromiseUtils.defer();
- TelemetryEnvironment.registerChangeListener("testWatchPrefs_reset", deferred.resolve);
-
- Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST], "<user-set>");
-
- // Trigger a change in the watched preferences.
- Preferences.reset(PREF_TEST);
- yield deferred.promise;
-
- Assert.strictEqual(TelemetryEnvironment.currentEnvironment.settings.userPrefs[PREF_TEST], undefined);
-
- // Unregister the listener.
- TelemetryEnvironment.unregisterChangeListener("testWatchPrefs_reset");
-});
-
-add_task(function* test_addonsWatch_InterestingChange() {
- const ADDON_INSTALL_URL = gDataRoot + "restartless.xpi";
- const ADDON_ID = "tel-restartless-xpi@tests.mozilla.org";
- // We only expect a single notification for each install, uninstall, enable, disable.
- const EXPECTED_NOTIFICATIONS = 4;
-
- let receivedNotifications = 0;
-
- let registerCheckpointPromise = (aExpected) => {
- return new Promise(resolve => TelemetryEnvironment.registerChangeListener(
- "testWatchAddons_Changes" + aExpected, (reason, data) => {
- Assert.equal(reason, "addons-changed");
- receivedNotifications++;
- resolve();
- }));
- };
-
- let assertCheckpoint = (aExpected) => {
- Assert.equal(receivedNotifications, aExpected);
- TelemetryEnvironment.unregisterChangeListener("testWatchAddons_Changes" + aExpected);
- };
-
- // Test for receiving one notification after each change.
- let checkpointPromise = registerCheckpointPromise(1);
- yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
- yield checkpointPromise;
- assertCheckpoint(1);
- Assert.ok(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons);
-
- checkpointPromise = registerCheckpointPromise(2);
- let addon = yield AddonManagerTesting.getAddonById(ADDON_ID);
- addon.userDisabled = true;
- yield checkpointPromise;
- assertCheckpoint(2);
- Assert.ok(!(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons));
-
- checkpointPromise = registerCheckpointPromise(3);
- addon.userDisabled = false;
- yield checkpointPromise;
- assertCheckpoint(3);
- Assert.ok(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons);
-
- checkpointPromise = registerCheckpointPromise(4);
- yield AddonManagerTesting.uninstallAddonByID(ADDON_ID);
- yield checkpointPromise;
- assertCheckpoint(4);
- Assert.ok(!(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons));
-
- Assert.equal(receivedNotifications, EXPECTED_NOTIFICATIONS,
- "We must only receive the notifications we expect.");
-});
-
-add_task(function* test_pluginsWatch_Add() {
- if (gIsAndroid) {
- Assert.ok(true, "Skipping: there is no Plugin Manager on Android.");
- return;
- }
-
- Assert.equal(TelemetryEnvironment.currentEnvironment.addons.activePlugins.length, 1);
-
- let newPlugin = new PluginTag(PLUGIN2_NAME, PLUGIN2_DESC, PLUGIN2_VERSION, true);
- gInstalledPlugins.push(newPlugin);
-
- let deferred = PromiseUtils.defer();
- let receivedNotifications = 0;
- let callback = (reason, data) => {
- receivedNotifications++;
- Assert.equal(reason, "addons-changed");
- deferred.resolve();
- };
- TelemetryEnvironment.registerChangeListener("testWatchPlugins_Add", callback);
-
- Services.obs.notifyObservers(null, PLUGIN_UPDATED_TOPIC, null);
- yield deferred.promise;
-
- Assert.equal(TelemetryEnvironment.currentEnvironment.addons.activePlugins.length, 2);
-
- TelemetryEnvironment.unregisterChangeListener("testWatchPlugins_Add");
-
- Assert.equal(receivedNotifications, 1, "We must only receive one notification.");
-});
-
-add_task(function* test_pluginsWatch_Remove() {
- if (gIsAndroid) {
- Assert.ok(true, "Skipping: there is no Plugin Manager on Android.");
- return;
- }
-
- // Find the test plugin.
- let plugin = gInstalledPlugins.find(p => (p.name == PLUGIN2_NAME));
- Assert.ok(plugin, "The test plugin must exist.");
-
- // Remove it from the PluginHost.
- gInstalledPlugins = gInstalledPlugins.filter(p => p != plugin);
-
- let deferred = PromiseUtils.defer();
- let receivedNotifications = 0;
- let callback = () => {
- receivedNotifications++;
- deferred.resolve();
- };
- TelemetryEnvironment.registerChangeListener("testWatchPlugins_Remove", callback);
-
- Services.obs.notifyObservers(null, PLUGIN_UPDATED_TOPIC, null);
- yield deferred.promise;
-
- TelemetryEnvironment.unregisterChangeListener("testWatchPlugins_Remove");
-
- Assert.equal(receivedNotifications, 1, "We must only receive one notification.");
-});
-
-add_task(function* test_addonsWatch_NotInterestingChange() {
- // We are not interested to dictionary addons changes.
- const DICTIONARY_ADDON_INSTALL_URL = gDataRoot + "dictionary.xpi";
- const INTERESTING_ADDON_INSTALL_URL = gDataRoot + "restartless.xpi";
-
- let receivedNotification = false;
- let deferred = PromiseUtils.defer();
- TelemetryEnvironment.registerChangeListener("testNotInteresting",
- () => {
- Assert.ok(!receivedNotification, "Should not receive multiple notifications");
- receivedNotification = true;
- deferred.resolve();
- });
-
- yield AddonManagerTesting.installXPIFromURL(DICTIONARY_ADDON_INSTALL_URL);
- yield AddonManagerTesting.installXPIFromURL(INTERESTING_ADDON_INSTALL_URL);
-
- yield deferred.promise;
- Assert.ok(!("telemetry-dictionary@tests.mozilla.org" in
- TelemetryEnvironment.currentEnvironment.addons.activeAddons),
- "Dictionaries should not appear in active addons.");
-
- TelemetryEnvironment.unregisterChangeListener("testNotInteresting");
-});
-
-add_task(function* test_addonsAndPlugins() {
- const ADDON_INSTALL_URL = gDataRoot + "restartless.xpi";
- const ADDON_ID = "tel-restartless-xpi@tests.mozilla.org";
- const ADDON_INSTALL_DATE = truncateToDays(Date.now());
- const EXPECTED_ADDON_DATA = {
- blocklisted: false,
- description: "A restartless addon which gets enabled without a reboot.",
- name: "XPI Telemetry Restartless Test",
- userDisabled: false,
- appDisabled: false,
- version: "1.0",
- scope: 1,
- type: "extension",
- foreignInstall: false,
- hasBinaryComponents: false,
- installDay: ADDON_INSTALL_DATE,
- updateDay: ADDON_INSTALL_DATE,
- signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED,
- isSystem: false,
- };
- const SYSTEM_ADDON_ID = "tel-system-xpi@tests.mozilla.org";
- const EXPECTED_SYSTEM_ADDON_DATA = {
- blocklisted: false,
- description: "A system addon which is shipped with Firefox.",
- name: "XPI Telemetry System Add-on Test",
- userDisabled: false,
- appDisabled: false,
- version: "1.0",
- scope: 1,
- type: "extension",
- foreignInstall: false,
- hasBinaryComponents: false,
- installDay: truncateToDays(SYSTEM_ADDON_INSTALL_DATE),
- updateDay: truncateToDays(SYSTEM_ADDON_INSTALL_DATE),
- signedState: undefined,
- isSystem: true,
- };
-
- const EXPECTED_PLUGIN_DATA = {
- name: FLASH_PLUGIN_NAME,
- version: FLASH_PLUGIN_VERSION,
- description: FLASH_PLUGIN_DESC,
- blocklisted: false,
- disabled: false,
- clicktoplay: true,
- };
-
- // Install an addon so we have some data.
- yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
-
- let data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
-
- // Check addon data.
- Assert.ok(ADDON_ID in data.addons.activeAddons, "We must have one active addon.");
- let targetAddon = data.addons.activeAddons[ADDON_ID];
- for (let f in EXPECTED_ADDON_DATA) {
- Assert.equal(targetAddon[f], EXPECTED_ADDON_DATA[f], f + " must have the correct value.");
- }
-
- // Check system add-on data.
- Assert.ok(SYSTEM_ADDON_ID in data.addons.activeAddons, "We must have one active system addon.");
- let targetSystemAddon = data.addons.activeAddons[SYSTEM_ADDON_ID];
- for (let f in EXPECTED_SYSTEM_ADDON_DATA) {
- Assert.equal(targetSystemAddon[f], EXPECTED_SYSTEM_ADDON_DATA[f], f + " must have the correct value.");
- }
-
- // Check theme data.
- let theme = data.addons.theme;
- Assert.equal(theme.id, (PERSONA_ID + PERSONA_ID_SUFFIX));
- Assert.equal(theme.name, PERSONA_NAME);
- Assert.equal(theme.description, PERSONA_DESCRIPTION);
-
- // Check plugin data.
- Assert.equal(data.addons.activePlugins.length, 1, "We must have only one active plugin.");
- let targetPlugin = data.addons.activePlugins[0];
- for (let f in EXPECTED_PLUGIN_DATA) {
- Assert.equal(targetPlugin[f], EXPECTED_PLUGIN_DATA[f], f + " must have the correct value.");
- }
-
- // Check plugin mime types.
- Assert.ok(targetPlugin.mimeTypes.find(m => m == PLUGIN_MIME_TYPE1));
- Assert.ok(targetPlugin.mimeTypes.find(m => m == PLUGIN_MIME_TYPE2));
- Assert.ok(!targetPlugin.mimeTypes.find(m => m == "Not There."));
-
- let personaId = (gIsGonk) ? null : PERSONA_ID;
- Assert.equal(data.addons.persona, personaId, "The correct Persona Id must be reported.");
-
- // Uninstall the addon.
- yield AddonManagerTesting.uninstallAddonByID(ADDON_ID);
-});
-
-add_task(function* test_signedAddon() {
- const ADDON_INSTALL_URL = gDataRoot + "signed.xpi";
- const ADDON_ID = "tel-signed-xpi@tests.mozilla.org";
- const ADDON_INSTALL_DATE = truncateToDays(Date.now());
- const EXPECTED_ADDON_DATA = {
- blocklisted: false,
- description: "A signed addon which gets enabled without a reboot.",
- name: "XPI Telemetry Signed Test",
- userDisabled: false,
- appDisabled: false,
- version: "1.0",
- scope: 1,
- type: "extension",
- foreignInstall: false,
- hasBinaryComponents: false,
- installDay: ADDON_INSTALL_DATE,
- updateDay: ADDON_INSTALL_DATE,
- signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED,
- };
-
- let deferred = PromiseUtils.defer();
- TelemetryEnvironment.registerChangeListener("test_signedAddon", deferred.resolve);
-
- // Install the addon.
- yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
-
- yield deferred.promise;
- // Unregister the listener.
- TelemetryEnvironment.unregisterChangeListener("test_signedAddon");
-
- let data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
-
- // Check addon data.
- Assert.ok(ADDON_ID in data.addons.activeAddons, "Add-on should be in the environment.");
- let targetAddon = data.addons.activeAddons[ADDON_ID];
- for (let f in EXPECTED_ADDON_DATA) {
- Assert.equal(targetAddon[f], EXPECTED_ADDON_DATA[f], f + " must have the correct value.");
- }
-});
-
-add_task(function* test_addonsFieldsLimit() {
- const ADDON_INSTALL_URL = gDataRoot + "long-fields.xpi";
- const ADDON_ID = "tel-longfields-xpi@tests.mozilla.org";
-
- // Install the addon and wait for the TelemetryEnvironment to pick it up.
- let deferred = PromiseUtils.defer();
- TelemetryEnvironment.registerChangeListener("test_longFieldsAddon", deferred.resolve);
- yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
- yield deferred.promise;
- TelemetryEnvironment.unregisterChangeListener("test_longFieldsAddon");
-
- let data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
-
- // Check that the addon is available and that the string fields are limited.
- Assert.ok(ADDON_ID in data.addons.activeAddons, "Add-on should be in the environment.");
- let targetAddon = data.addons.activeAddons[ADDON_ID];
-
- // TelemetryEnvironment limits the length of string fields for activeAddons to 100 chars,
- // to mitigate misbehaving addons.
- Assert.lessOrEqual(targetAddon.version.length, 100,
- "The version string must have been limited");
- Assert.lessOrEqual(targetAddon.name.length, 100,
- "The name string must have been limited");
- Assert.lessOrEqual(targetAddon.description.length, 100,
- "The description string must have been limited");
-});
-
-add_task(function* test_collectionWithbrokenAddonData() {
- const BROKEN_ADDON_ID = "telemetry-test2.example.com@services.mozilla.org";
- const BROKEN_MANIFEST = {
- id: "telemetry-test2.example.com@services.mozilla.org",
- name: "telemetry broken addon",
- origin: "https://telemetry-test2.example.com",
- version: 1, // This is intentionally not a string.
- signedState: AddonManager.SIGNEDSTATE_SIGNED,
- };
-
- const ADDON_INSTALL_URL = gDataRoot + "restartless.xpi";
- const ADDON_ID = "tel-restartless-xpi@tests.mozilla.org";
- const ADDON_INSTALL_DATE = truncateToDays(Date.now());
- const EXPECTED_ADDON_DATA = {
- blocklisted: false,
- description: "A restartless addon which gets enabled without a reboot.",
- name: "XPI Telemetry Restartless Test",
- userDisabled: false,
- appDisabled: false,
- version: "1.0",
- scope: 1,
- type: "extension",
- foreignInstall: false,
- hasBinaryComponents: false,
- installDay: ADDON_INSTALL_DATE,
- updateDay: ADDON_INSTALL_DATE,
- signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_MISSING :
- AddonManager.SIGNEDSTATE_NOT_REQUIRED,
- };
-
- let receivedNotifications = 0;
-
- let registerCheckpointPromise = (aExpected) => {
- return new Promise(resolve => TelemetryEnvironment.registerChangeListener(
- "testBrokenAddon_collection" + aExpected, (reason, data) => {
- Assert.equal(reason, "addons-changed");
- receivedNotifications++;
- resolve();
- }));
- };
-
- let assertCheckpoint = (aExpected) => {
- Assert.equal(receivedNotifications, aExpected);
- TelemetryEnvironment.unregisterChangeListener("testBrokenAddon_collection" + aExpected);
- };
-
- // Register the broken provider and install the broken addon.
- let checkpointPromise = registerCheckpointPromise(1);
- let brokenAddonProvider = createMockAddonProvider("Broken Extensions Provider");
- AddonManagerPrivate.registerProvider(brokenAddonProvider);
- brokenAddonProvider.addAddon(BROKEN_MANIFEST);
- yield checkpointPromise;
- assertCheckpoint(1);
-
- // Now install an addon which returns the correct information.
- checkpointPromise = registerCheckpointPromise(2);
- yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
- yield checkpointPromise;
- assertCheckpoint(2);
-
- // Check that the new environment contains the Social addon installed with the broken
- // manifest and the rest of the data.
- let data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data, false, true /* expect broken addons*/);
-
- let activeAddons = data.addons.activeAddons;
- Assert.ok(BROKEN_ADDON_ID in activeAddons,
- "The addon with the broken manifest must be reported.");
- Assert.equal(activeAddons[BROKEN_ADDON_ID].version, null,
- "null should be reported for invalid data.");
- Assert.ok(ADDON_ID in activeAddons,
- "The valid addon must be reported.");
- Assert.equal(activeAddons[ADDON_ID].description, EXPECTED_ADDON_DATA.description,
- "The description for the valid addon should be correct.");
-
- // Unregister the broken provider so we don't mess with other tests.
- AddonManagerPrivate.unregisterProvider(brokenAddonProvider);
-
- // Uninstall the valid addon.
- yield AddonManagerTesting.uninstallAddonByID(ADDON_ID);
-});
-
-add_task(function* test_defaultSearchEngine() {
- // Check that no default engine is in the environment before the search service is
- // initialized.
- let data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
- Assert.ok(!("defaultSearchEngine" in data.settings));
- Assert.ok(!("defaultSearchEngineData" in data.settings));
-
- // Load the engines definitions from a custom JAR file: that's needed so that
- // the search provider reports an engine identifier.
- let url = "chrome://testsearchplugin/locale/searchplugins/";
- let resProt = Services.io.getProtocolHandler("resource")
- .QueryInterface(Ci.nsIResProtocolHandler);
- resProt.setSubstitution("search-plugins",
- Services.io.newURI(url, null, null));
-
- // Initialize the search service.
- yield new Promise(resolve => Services.search.init(resolve));
-
- // Our default engine from the JAR file has an identifier. Check if it is correctly
- // reported.
- data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
- Assert.equal(data.settings.defaultSearchEngine, "telemetrySearchIdentifier");
- let expectedSearchEngineData = {
- name: "telemetrySearchIdentifier",
- loadPath: "jar:[other]/searchTest.jar!testsearchplugin/telemetrySearchIdentifier.xml",
- origin: "default",
- submissionURL: "http://ar.wikipedia.org/wiki/%D8%AE%D8%A7%D8%B5:%D8%A8%D8%AD%D8%AB?search=&sourceid=Mozilla-search"
- };
- Assert.deepEqual(data.settings.defaultSearchEngineData, expectedSearchEngineData);
-
- // Remove all the search engines.
- for (let engine of Services.search.getEngines()) {
- Services.search.removeEngine(engine);
- }
- // The search service does not notify "engine-current" when removing a default engine.
- // Manually force the notification.
- // TODO: remove this when bug 1165341 is resolved.
- Services.obs.notifyObservers(null, "browser-search-engine-modified", "engine-current");
-
- // Then check that no default engine is reported if none is available.
- data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
- Assert.equal(data.settings.defaultSearchEngine, "NONE");
- Assert.deepEqual(data.settings.defaultSearchEngineData, {name:"NONE"});
-
- // Add a new search engine (this will have no engine identifier).
- const SEARCH_ENGINE_ID = "telemetry_default";
- const SEARCH_ENGINE_URL = "http://www.example.org/?search={searchTerms}";
- Services.search.addEngineWithDetails(SEARCH_ENGINE_ID, "", null, "", "get", SEARCH_ENGINE_URL);
-
- // Register a new change listener and then wait for the search engine change to be notified.
- let deferred = PromiseUtils.defer();
- TelemetryEnvironment.registerChangeListener("testWatch_SearchDefault", deferred.resolve);
- Services.search.defaultEngine = Services.search.getEngineByName(SEARCH_ENGINE_ID);
- yield deferred.promise;
-
- data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
-
- const EXPECTED_SEARCH_ENGINE = "other-" + SEARCH_ENGINE_ID;
- Assert.equal(data.settings.defaultSearchEngine, EXPECTED_SEARCH_ENGINE);
-
- const EXPECTED_SEARCH_ENGINE_DATA = {
- name: "telemetry_default",
- loadPath: "[other]addEngineWithDetails",
- origin: "verified"
- };
- Assert.deepEqual(data.settings.defaultSearchEngineData, EXPECTED_SEARCH_ENGINE_DATA);
- TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault");
-
- // Cleanly install an engine from an xml file, and check if origin is
- // recorded as "verified".
- let promise = new Promise(resolve => {
- TelemetryEnvironment.registerChangeListener("testWatch_SearchDefault", resolve);
- });
- let engine = yield new Promise((resolve, reject) => {
- Services.obs.addObserver(function obs(obsSubject, obsTopic, obsData) {
- try {
- let searchEngine = obsSubject.QueryInterface(Ci.nsISearchEngine);
- do_print("Observed " + obsData + " for " + searchEngine.name);
- if (obsData != "engine-added" || searchEngine.name != "engine-telemetry") {
- return;
- }
-
- Services.obs.removeObserver(obs, "browser-search-engine-modified");
- resolve(searchEngine);
- } catch (ex) {
- reject(ex);
- }
- }, "browser-search-engine-modified", false);
- Services.search.addEngine("file://" + do_get_cwd().path + "/engine.xml",
- null, null, false);
- });
- Services.search.defaultEngine = engine;
- yield promise;
- TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault");
- data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
- Assert.deepEqual(data.settings.defaultSearchEngineData,
- {"name":"engine-telemetry", "loadPath":"[other]/engine.xml", "origin":"verified"});
-
- // Now break this engine's load path hash.
- promise = new Promise(resolve => {
- TelemetryEnvironment.registerChangeListener("testWatch_SearchDefault", resolve);
- });
- engine.wrappedJSObject.setAttr("loadPathHash", "broken");
- Services.obs.notifyObservers(null, "browser-search-engine-modified", "engine-current");
- yield promise;
- TelemetryEnvironment.unregisterChangeListener("testWatch_SearchDefault");
- data = TelemetryEnvironment.currentEnvironment;
- Assert.equal(data.settings.defaultSearchEngineData.origin, "invalid");
- Services.search.removeEngine(engine);
-
- // Define and reset the test preference.
- const PREF_TEST = "toolkit.telemetry.test.pref1";
- const PREFS_TO_WATCH = new Map([
- [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
- ]);
- Preferences.reset(PREF_TEST);
-
- // Watch the test preference.
- TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
- deferred = PromiseUtils.defer();
- TelemetryEnvironment.registerChangeListener("testSearchEngine_pref", deferred.resolve);
- // Trigger an environment change.
- Preferences.set(PREF_TEST, 1);
- yield deferred.promise;
- TelemetryEnvironment.unregisterChangeListener("testSearchEngine_pref");
-
- // Check that the search engine information is correctly retained when prefs change.
- data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
- Assert.equal(data.settings.defaultSearchEngine, EXPECTED_SEARCH_ENGINE);
-
- // Check that by default we are not sending a cohort identifier...
- Assert.equal(data.settings.searchCohort, undefined);
-
- // ... but that if a cohort identifier is set, we send it.
- Services.prefs.setCharPref("browser.search.cohort", "testcohort");
- Services.obs.notifyObservers(null, "browser-search-service", "init-complete");
- data = TelemetryEnvironment.currentEnvironment;
- Assert.equal(data.settings.searchCohort, "testcohort");
-});
-
-add_task(function* test_osstrings() {
- // First test that numbers in sysinfo properties are converted to string fields
- // in system.os.
- SysInfo.overrides = {
- version: 1,
- name: 2,
- kernel_version: 3,
- };
-
- yield TelemetryEnvironment.testCleanRestart().onInitialized();
- let data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
-
- Assert.equal(data.system.os.version, "1");
- Assert.equal(data.system.os.name, "2");
- if (AppConstants.platform == "android") {
- Assert.equal(data.system.os.kernelVersion, "3");
- }
-
- // Check that null values are also handled.
- SysInfo.overrides = {
- version: null,
- name: null,
- kernel_version: null,
- };
-
- yield TelemetryEnvironment.testCleanRestart().onInitialized();
- data = TelemetryEnvironment.currentEnvironment;
- checkEnvironmentData(data);
-
- Assert.equal(data.system.os.version, null);
- Assert.equal(data.system.os.name, null);
- if (AppConstants.platform == "android") {
- Assert.equal(data.system.os.kernelVersion, null);
- }
-
- // Clean up.
- SysInfo.overrides = {};
- yield TelemetryEnvironment.testCleanRestart().onInitialized();
-});
-
-add_task(function* test_environmentShutdown() {
- // Define and reset the test preference.
- const PREF_TEST = "toolkit.telemetry.test.pref1";
- const PREFS_TO_WATCH = new Map([
- [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
- ]);
- Preferences.reset(PREF_TEST);
-
- // Set up the preferences and listener, then the trigger shutdown
- TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
- TelemetryEnvironment.registerChangeListener("test_environmentShutdownChange", () => {
- // Register a new change listener that asserts if change is propogated
- Assert.ok(false, "No change should be propagated after shutdown.");
- });
- TelemetryEnvironment.shutdown();
-
- // Flipping the test preference after shutdown should not trigger the listener
- Preferences.set(PREF_TEST, 1);
-
- // Unregister the listener.
- TelemetryEnvironment.unregisterChangeListener("test_environmentShutdownChange");
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js
deleted file mode 100644
index 2bfb62c14..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEvents.js
+++ /dev/null
@@ -1,249 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-*/
-
-const OPTIN = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN;
-const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
-
-function checkEventFormat(events) {
- Assert.ok(Array.isArray(events), "Events should be serialized to an array.");
- for (let e of events) {
- Assert.ok(Array.isArray(e), "Event should be an array.");
- Assert.greaterOrEqual(e.length, 4, "Event should have at least 4 elements.");
- Assert.lessOrEqual(e.length, 6, "Event should have at most 6 elements.");
-
- Assert.equal(typeof(e[0]), "number", "Element 0 should be a number.");
- Assert.equal(typeof(e[1]), "string", "Element 1 should be a string.");
- Assert.equal(typeof(e[2]), "string", "Element 2 should be a string.");
- Assert.equal(typeof(e[3]), "string", "Element 3 should be a string.");
-
- if (e.length > 4) {
- Assert.ok(e[4] === null || typeof(e[4]) == "string",
- "Event element 4 should be null or a string.");
- }
- if (e.length > 5) {
- Assert.ok(e[5] === null || typeof(e[5]) == "object",
- "Event element 5 should be null or an object.");
- }
-
- let extra = e[5];
- if (extra) {
- Assert.ok(Object.keys(extra).every(k => typeof(k) == "string"),
- "All extra keys should be strings.");
- Assert.ok(Object.values(extra).every(v => typeof(v) == "string"),
- "All extra values should be strings.");
- }
- }
-}
-
-add_task(function* test_recording() {
- Telemetry.clearEvents();
-
- // Record some events.
- let expected = [
- {optout: false, event: ["telemetry.test", "test1", "object1"]},
- {optout: false, event: ["telemetry.test", "test2", "object2"]},
-
- {optout: false, event: ["telemetry.test", "test1", "object1", "value"]},
- {optout: false, event: ["telemetry.test", "test1", "object1", "value", null]},
- {optout: false, event: ["telemetry.test", "test1", "object1", null, {"key1": "value1"}]},
- {optout: false, event: ["telemetry.test", "test1", "object1", "value", {"key1": "value1", "key2": "value2"}]},
-
- {optout: true, event: ["telemetry.test", "optout", "object1"]},
- {optout: false, event: ["telemetry.test.second", "test", "object1"]},
- {optout: false, event: ["telemetry.test.second", "test", "object1", null, {"key1": "value1"}]},
- ];
-
- for (let entry of expected) {
- entry.tsBefore = Math.floor(Telemetry.msSinceProcessStart());
- try {
- Telemetry.recordEvent(...entry.event);
- } catch (ex) {
- Assert.ok(false, `Failed to record event ${JSON.stringify(entry.event)}: ${ex}`);
- }
- entry.tsAfter = Math.floor(Telemetry.msSinceProcessStart());
- }
-
- // Strip off trailing null values to match the serialized events.
- for (let entry of expected) {
- let e = entry.event;
- while ((e.length >= 3) && (e[e.length - 1] === null)) {
- e.pop();
- }
- }
-
- // The following should not result in any recorded events.
- Assert.throws(() => Telemetry.recordEvent("unknown.category", "test1", "object1"),
- /Error: Unknown event: \["unknown.category", "test1", "object1"\]/,
- "Should throw on unknown category.");
- Assert.throws(() => Telemetry.recordEvent("telemetry.test", "unknown", "object1"),
- /Error: Unknown event: \["telemetry.test", "unknown", "object1"\]/,
- "Should throw on unknown method.");
- Assert.throws(() => Telemetry.recordEvent("telemetry.test", "test1", "unknown"),
- /Error: Unknown event: \["telemetry.test", "test1", "unknown"\]/,
- "Should throw on unknown object.");
-
- let checkEvents = (events, expectedEvents) => {
- checkEventFormat(events);
- Assert.equal(events.length, expectedEvents.length,
- "Snapshot should have the right number of events.");
-
- for (let i = 0; i < events.length; ++i) {
- let {tsBefore, tsAfter} = expectedEvents[i];
- let ts = events[i][0];
- Assert.greaterOrEqual(ts, tsBefore, "The recorded timestamp should be greater than the one before recording.");
- Assert.lessOrEqual(ts, tsAfter, "The recorded timestamp should be less than the one after recording.");
-
- let recordedData = events[i].slice(1);
- let expectedData = expectedEvents[i].event.slice();
- Assert.deepEqual(recordedData, expectedData, "The recorded event data should match.");
- }
- };
-
- // Check that the expected events were recorded.
- let events = Telemetry.snapshotBuiltinEvents(OPTIN, false);
- checkEvents(events, expected);
-
- // Check serializing only opt-out events.
- events = Telemetry.snapshotBuiltinEvents(OPTOUT, false);
- filtered = expected.filter(e => e.optout == true);
- checkEvents(events, filtered);
-});
-
-add_task(function* test_clear() {
- Telemetry.clearEvents();
-
- const COUNT = 10;
- for (let i = 0; i < COUNT; ++i) {
- Telemetry.recordEvent("telemetry.test", "test1", "object1");
- Telemetry.recordEvent("telemetry.test.second", "test", "object1");
- }
-
- // Check that events were recorded.
- // The events are cleared by passing the respective flag.
- let events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
- Assert.equal(events.length, 2 * COUNT, `Should have recorded ${2 * COUNT} events.`);
-
- // Now the events should be cleared.
- events = Telemetry.snapshotBuiltinEvents(OPTIN, false);
- Assert.equal(events.length, 0, `Should have cleared the events.`);
-});
-
-add_task(function* test_expiry() {
- Telemetry.clearEvents();
-
- // Recording call with event that is expired by version.
- Telemetry.recordEvent("telemetry.test", "expired_version", "object1");
- let events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
- Assert.equal(events.length, 0, "Should not record event with expired version.");
-
- // Recording call with event that is expired by date.
- Telemetry.recordEvent("telemetry.test", "expired_date", "object1");
- events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
- Assert.equal(events.length, 0, "Should not record event with expired date.");
-
- // Recording call with event that has expiry_version and expiry_date in the future.
- Telemetry.recordEvent("telemetry.test", "not_expired_optout", "object1");
- events = Telemetry.snapshotBuiltinEvents(OPTOUT, true);
- Assert.equal(events.length, 1, "Should record event when date and version are not expired.");
-});
-
-add_task(function* test_invalidParams() {
- Telemetry.clearEvents();
-
- // Recording call with wrong type for value argument.
- Telemetry.recordEvent("telemetry.test", "test1", "object1", 1);
- let events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
- Assert.equal(events.length, 0, "Should not record event when value argument with invalid type is passed.");
-
- // Recording call with wrong type for extra argument.
- Telemetry.recordEvent("telemetry.test", "test1", "object1", null, "invalid");
- events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
- Assert.equal(events.length, 0, "Should not record event when extra argument with invalid type is passed.");
-
- // Recording call with unknown extra key.
- Telemetry.recordEvent("telemetry.test", "test1", "object1", null, {"key3": "x"});
- events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
- Assert.equal(events.length, 0, "Should not record event when extra argument with invalid key is passed.");
-
- // Recording call with invalid value type.
- Telemetry.recordEvent("telemetry.test", "test1", "object1", null, {"key3": 1});
- events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
- Assert.equal(events.length, 0, "Should not record event when extra argument with invalid value type is passed.");
-});
-
-add_task(function* test_storageLimit() {
- Telemetry.clearEvents();
-
- // Record more events than the storage limit allows.
- let LIMIT = 1000;
- let COUNT = LIMIT + 10;
- for (let i = 0; i < COUNT; ++i) {
- Telemetry.recordEvent("telemetry.test", "test1", "object1", String(i));
- }
-
- // Check that the right events were recorded.
- let events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
- Assert.equal(events.length, LIMIT, `Should have only recorded ${LIMIT} events`);
- Assert.ok(events.every((e, idx) => e[4] === String(idx)),
- "Should have recorded all events from before hitting the limit.");
-});
-
-add_task(function* test_valueLimits() {
- Telemetry.clearEvents();
-
- // Record values that are at or over the limits for string lengths.
- let LIMIT = 80;
- let expected = [
- ["telemetry.test", "test1", "object1", "a".repeat(LIMIT - 10), null],
- ["telemetry.test", "test1", "object1", "a".repeat(LIMIT ), null],
- ["telemetry.test", "test1", "object1", "a".repeat(LIMIT + 1), null],
- ["telemetry.test", "test1", "object1", "a".repeat(LIMIT + 10), null],
-
- ["telemetry.test", "test1", "object1", null, {key1: "a".repeat(LIMIT - 10)}],
- ["telemetry.test", "test1", "object1", null, {key1: "a".repeat(LIMIT )}],
- ["telemetry.test", "test1", "object1", null, {key1: "a".repeat(LIMIT + 1)}],
- ["telemetry.test", "test1", "object1", null, {key1: "a".repeat(LIMIT + 10)}],
- ];
-
- for (let event of expected) {
- Telemetry.recordEvent(...event);
- if (event[3]) {
- event[3] = event[3].substr(0, LIMIT);
- }
- if (event[4]) {
- event[4].key1 = event[4].key1.substr(0, LIMIT);
- }
- }
-
- // Strip off trailing null values to match the serialized events.
- for (let e of expected) {
- while ((e.length >= 3) && (e[e.length - 1] === null)) {
- e.pop();
- }
- }
-
- // Check that the right events were recorded.
- let events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
- Assert.equal(events.length, expected.length,
- "Should have recorded the expected number of events");
- for (let i = 0; i < expected.length; ++i) {
- Assert.deepEqual(events[i].slice(1), expected[i],
- "Should have recorded the expected event data.");
- }
-});
-
-add_task(function* test_unicodeValues() {
- Telemetry.clearEvents();
-
- // Record string values containing unicode characters.
- let value = "漢語";
- Telemetry.recordEvent("telemetry.test", "test1", "object1", value);
- Telemetry.recordEvent("telemetry.test", "test1", "object1", null, {"key1": value});
-
- // Check that the values were correctly recorded.
- let events = Telemetry.snapshotBuiltinEvents(OPTIN, true);
- Assert.equal(events.length, 2, "Should have recorded 2 events.");
- Assert.equal(events[0][4], value, "Should have recorded the right value.");
- Assert.equal(events[1][5]["key1"], value, "Should have recorded the right extra value.");
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryFlagClear.js b/toolkit/components/telemetry/tests/unit/test_TelemetryFlagClear.js
deleted file mode 100644
index 712aceb3b..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryFlagClear.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-function run_test()
-{
- let testFlag = Services.telemetry.getHistogramById("TELEMETRY_TEST_FLAG");
- equal(JSON.stringify(testFlag.snapshot().counts), "[1,0,0]", "Original value is correct");
- testFlag.add(1);
- equal(JSON.stringify(testFlag.snapshot().counts), "[0,1,0]", "Value is correct after ping.");
- testFlag.clear();
- equal(JSON.stringify(testFlag.snapshot().counts), "[1,0,0]", "Value is correct after calling clear()");
- testFlag.add(1);
- equal(JSON.stringify(testFlag.snapshot().counts), "[0,1,0]", "Value is correct after ping.");
-}
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryLateWrites.js b/toolkit/components/telemetry/tests/unit/test_TelemetryLateWrites.js
deleted file mode 100644
index f2b2b3bba..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryLateWrites.js
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-*/
-/* A testcase to make sure reading late writes stacks works. */
-
-Cu.import("resource://gre/modules/Services.jsm", this);
-
-// Constants from prio.h for nsIFileOutputStream.init
-const PR_WRONLY = 0x2;
-const PR_CREATE_FILE = 0x8;
-const PR_TRUNCATE = 0x20;
-const RW_OWNER = parseInt("0600", 8);
-
-const STACK_SUFFIX1 = "stack1.txt";
-const STACK_SUFFIX2 = "stack2.txt";
-const STACK_BOGUS_SUFFIX = "bogus.txt";
-const LATE_WRITE_PREFIX = "Telemetry.LateWriteFinal-";
-
-// The names and IDs don't matter, but the format of the IDs does.
-const LOADED_MODULES = {
- '4759A7E6993548C89CAF716A67EC242D00': 'libtest.so',
- 'F77AF15BB8D6419FA875954B4A3506CA00': 'libxul.so',
- '1E2F7FB590424E8F93D60BB88D66B8C500': 'libc.so'
-};
-const N_MODULES = Object.keys(LOADED_MODULES).length;
-
-// Format of individual items is [index, offset-in-library].
-const STACK1 = [
- [ 0, 0 ],
- [ 1, 1 ],
- [ 2, 2 ]
-];
-const STACK2 = [
- [ 0, 0 ],
- [ 1, 5 ],
- [ 2, 10 ],
-];
-// XXX The only error checking is for a zero-sized stack.
-const STACK_BOGUS = [];
-
-function write_string_to_file(file, contents) {
- let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"]
- .createInstance(Ci.nsIFileOutputStream);
- ostream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
- RW_OWNER, ostream.DEFER_OPEN);
- ostream.write(contents, contents.length);
- ostream.QueryInterface(Ci.nsISafeOutputStream).finish();
- ostream.close();
-}
-
-function construct_file(suffix) {
- let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
- let file = profileDirectory.clone();
- file.append(LATE_WRITE_PREFIX + suffix);
- return file;
-}
-
-function write_late_writes_file(stack, suffix)
-{
- let file = construct_file(suffix);
- let contents = N_MODULES + "\n";
- for (let id in LOADED_MODULES) {
- contents += id + " " + LOADED_MODULES[id] + "\n";
- }
-
- contents += stack.length + "\n";
- for (let element of stack) {
- contents += element[0] + " " + element[1].toString(16) + "\n";
- }
-
- write_string_to_file(file, contents);
-}
-
-function run_test() {
- do_get_profile();
-
- write_late_writes_file(STACK1, STACK_SUFFIX1);
- write_late_writes_file(STACK2, STACK_SUFFIX2);
- write_late_writes_file(STACK_BOGUS, STACK_BOGUS_SUFFIX);
-
- let lateWrites = Telemetry.lateWrites;
- do_check_true("memoryMap" in lateWrites);
- do_check_eq(lateWrites.memoryMap.length, 0);
- do_check_true("stacks" in lateWrites);
- do_check_eq(lateWrites.stacks.length, 0);
-
- do_test_pending();
- Telemetry.asyncFetchTelemetryData(function () {
- actual_test();
- });
-}
-
-function actual_test() {
- do_check_false(construct_file(STACK_SUFFIX1).exists());
- do_check_false(construct_file(STACK_SUFFIX2).exists());
- do_check_false(construct_file(STACK_BOGUS_SUFFIX).exists());
-
- let lateWrites = Telemetry.lateWrites;
-
- do_check_true("memoryMap" in lateWrites);
- do_check_eq(lateWrites.memoryMap.length, N_MODULES);
- for (let id in LOADED_MODULES) {
- let matchingLibrary = lateWrites.memoryMap.filter(function(library, idx, array) {
- return library[1] == id;
- });
- do_check_eq(matchingLibrary.length, 1);
- let library = matchingLibrary[0]
- let name = library[0];
- do_check_eq(LOADED_MODULES[id], name);
- }
-
- do_check_true("stacks" in lateWrites);
- do_check_eq(lateWrites.stacks.length, 2);
- let uneval_STACKS = [uneval(STACK1), uneval(STACK2)];
- let first_stack = lateWrites.stacks[0];
- let second_stack = lateWrites.stacks[1];
- function stackChecker(canonicalStack) {
- let unevalCanonicalStack = uneval(canonicalStack);
- return function(obj, idx, array) {
- return unevalCanonicalStack == obj;
- }
- }
- do_check_eq(uneval_STACKS.filter(stackChecker(first_stack)).length, 1);
- do_check_eq(uneval_STACKS.filter(stackChecker(second_stack)).length, 1);
-
- do_test_finished();
-}
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryLockCount.js b/toolkit/components/telemetry/tests/unit/test_TelemetryLockCount.js
deleted file mode 100644
index 808f2f3ec..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryLockCount.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-*/
-/* A testcase to make sure reading the failed profile lock count works. */
-
-Cu.import("resource://gre/modules/Services.jsm", this);
-
-const LOCK_FILE_NAME = "Telemetry.FailedProfileLocks.txt";
-const N_FAILED_LOCKS = 10;
-
-// Constants from prio.h for nsIFileOutputStream.init
-const PR_WRONLY = 0x2;
-const PR_CREATE_FILE = 0x8;
-const PR_TRUNCATE = 0x20;
-const RW_OWNER = parseInt("0600", 8);
-
-function write_string_to_file(file, contents) {
- let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"]
- .createInstance(Ci.nsIFileOutputStream);
- ostream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
- RW_OWNER, ostream.DEFER_OPEN);
- ostream.write(contents, contents.length);
- ostream.QueryInterface(Ci.nsISafeOutputStream).finish();
- ostream.close();
-}
-
-function construct_file() {
- let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
- let file = profileDirectory.clone();
- file.append(LOCK_FILE_NAME);
- return file;
-}
-
-function run_test() {
- do_get_profile();
-
- do_check_eq(Telemetry.failedProfileLockCount, 0);
-
- write_string_to_file(construct_file(), N_FAILED_LOCKS.toString());
-
- // Make sure that we're not eagerly reading the count now that the
- // file exists.
- do_check_eq(Telemetry.failedProfileLockCount, 0);
-
- do_test_pending();
- Telemetry.asyncFetchTelemetryData(actual_test);
-}
-
-function actual_test() {
- do_check_eq(Telemetry.failedProfileLockCount, N_FAILED_LOCKS);
- do_check_false(construct_file().exists());
- do_test_finished();
-}
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryLog.js b/toolkit/components/telemetry/tests/unit/test_TelemetryLog.js
deleted file mode 100644
index ea37a1bc5..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryLog.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://gre/modules/TelemetryLog.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
-
-const TEST_PREFIX = "TEST-";
-const TEST_REGEX = new RegExp("^" + TEST_PREFIX);
-
-function check_event(event, id, data)
-{
- do_print("Checking message " + id);
- do_check_eq(event[0], id);
- do_check_true(event[1] > 0);
-
- if (data === undefined) {
- do_check_true(event.length == 2);
- } else {
- do_check_eq(event.length, data.length + 2);
- for (var i = 0; i < data.length; ++i) {
- do_check_eq(typeof(event[i + 2]), "string");
- do_check_eq(event[i + 2], data[i]);
- }
- }
-}
-
-add_task(function* ()
-{
- do_get_profile();
- // TODO: After Bug 1254550 lands we should not need to set the pref here.
- Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
- yield TelemetryController.testSetup();
-
- TelemetryLog.log(TEST_PREFIX + "1", ["val", 123, undefined]);
- TelemetryLog.log(TEST_PREFIX + "2", []);
- TelemetryLog.log(TEST_PREFIX + "3");
-
- var log = TelemetrySession.getPayload().log.filter(function(e) {
- // Only want events that were generated by the test.
- return TEST_REGEX.test(e[0]);
- });
-
- do_check_eq(log.length, 3);
- check_event(log[0], TEST_PREFIX + "1", ["val", "123", "undefined"]);
- check_event(log[1], TEST_PREFIX + "2", []);
- check_event(log[2], TEST_PREFIX + "3", undefined);
- do_check_true(log[0][1] <= log[1][1]);
- do_check_true(log[1][1] <= log[2][1]);
-
- yield TelemetryController.testShutdown();
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js b/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js
deleted file mode 100644
index 68606a98e..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js
+++ /dev/null
@@ -1,268 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-// Test that TelemetryController sends close to shutdown don't lead
-// to AsyncShutdown timeouts.
-
-"use strict";
-
-Cu.import("resource://gre/modules/Preferences.jsm", this);
-Cu.import("resource://gre/modules/Services.jsm", this);
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySend.jsm", this);
-Cu.import("resource://gre/modules/TelemetryReportingPolicy.jsm", this);
-Cu.import("resource://gre/modules/TelemetryUtils.jsm", this);
-Cu.import("resource://gre/modules/Timer.jsm", this);
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-Cu.import("resource://gre/modules/UpdateUtils.jsm", this);
-
-const PREF_BRANCH = "toolkit.telemetry.";
-const PREF_SERVER = PREF_BRANCH + "server";
-
-const TEST_CHANNEL = "TestChannelABC";
-
-const PREF_POLICY_BRANCH = "datareporting.policy.";
-const PREF_BYPASS_NOTIFICATION = PREF_POLICY_BRANCH + "dataSubmissionPolicyBypassNotification";
-const PREF_DATA_SUBMISSION_ENABLED = PREF_POLICY_BRANCH + "dataSubmissionEnabled";
-const PREF_CURRENT_POLICY_VERSION = PREF_POLICY_BRANCH + "currentPolicyVersion";
-const PREF_MINIMUM_POLICY_VERSION = PREF_POLICY_BRANCH + "minimumPolicyVersion";
-const PREF_MINIMUM_CHANNEL_POLICY_VERSION = PREF_MINIMUM_POLICY_VERSION + ".channel-" + TEST_CHANNEL;
-const PREF_ACCEPTED_POLICY_VERSION = PREF_POLICY_BRANCH + "dataSubmissionPolicyAcceptedVersion";
-const PREF_ACCEPTED_POLICY_DATE = PREF_POLICY_BRANCH + "dataSubmissionPolicyNotifiedTime";
-
-function fakeShowPolicyTimeout(set, clear) {
- let reportingPolicy = Cu.import("resource://gre/modules/TelemetryReportingPolicy.jsm");
- reportingPolicy.Policy.setShowInfobarTimeout = set;
- reportingPolicy.Policy.clearShowInfobarTimeout = clear;
-}
-
-function fakeResetAcceptedPolicy() {
- Preferences.reset(PREF_ACCEPTED_POLICY_DATE);
- Preferences.reset(PREF_ACCEPTED_POLICY_VERSION);
-}
-
-function setMinimumPolicyVersion(aNewPolicyVersion) {
- const CHANNEL_NAME = UpdateUtils.getUpdateChannel(false);
- // We might have channel-dependent minimum policy versions.
- const CHANNEL_DEPENDENT_PREF = PREF_MINIMUM_POLICY_VERSION + ".channel-" + CHANNEL_NAME;
-
- // Does the channel-dependent pref exist? If so, set its value.
- if (Preferences.get(CHANNEL_DEPENDENT_PREF, undefined)) {
- Preferences.set(CHANNEL_DEPENDENT_PREF, aNewPolicyVersion);
- return;
- }
-
- // We don't have a channel specific minimu, so set the common one.
- Preferences.set(PREF_MINIMUM_POLICY_VERSION, aNewPolicyVersion);
-}
-
-add_task(function* test_setup() {
- // Addon manager needs a profile directory
- do_get_profile(true);
- 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);
- // Don't bypass the notifications in this test, we'll fake it.
- Services.prefs.setBoolPref(PREF_BYPASS_NOTIFICATION, false);
-
- TelemetryReportingPolicy.setup();
-});
-
-add_task(function* test_firstRun() {
- const PREF_FIRST_RUN = "toolkit.telemetry.reportingpolicy.firstRun";
- const FIRST_RUN_TIMEOUT_MSEC = 60 * 1000; // 60s
- const OTHER_RUNS_TIMEOUT_MSEC = 10 * 1000; // 10s
-
- Preferences.reset(PREF_FIRST_RUN);
-
- let startupTimeout = 0;
- fakeShowPolicyTimeout((callback, timeout) => startupTimeout = timeout, () => {});
- TelemetryReportingPolicy.reset();
-
- Services.obs.notifyObservers(null, "sessionstore-windows-restored", null);
- Assert.equal(startupTimeout, FIRST_RUN_TIMEOUT_MSEC,
- "The infobar display timeout should be 60s on the first run.");
-
- // Run again, and check that we actually wait only 10 seconds.
- TelemetryReportingPolicy.reset();
- Services.obs.notifyObservers(null, "sessionstore-windows-restored", null);
- Assert.equal(startupTimeout, OTHER_RUNS_TIMEOUT_MSEC,
- "The infobar display timeout should be 10s on other runs.");
-});
-
-add_task(function* test_prefs() {
- TelemetryReportingPolicy.reset();
-
- let now = fakeNow(2009, 11, 18);
-
- // If the date is not valid (earlier than 2012), we don't regard the policy as accepted.
- TelemetryReportingPolicy.testInfobarShown();
- Assert.ok(!TelemetryReportingPolicy.testIsUserNotified());
- Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), 0,
- "Invalid dates should not make the policy accepted.");
-
- // Check that the notification date and version are correctly saved to the prefs.
- now = fakeNow(2012, 11, 18);
- TelemetryReportingPolicy.testInfobarShown();
- Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), now.getTime(),
- "A valid date must correctly be saved.");
-
- // Now that user is notified, check if we are allowed to upload.
- Assert.ok(TelemetryReportingPolicy.canUpload(),
- "We must be able to upload after the policy is accepted.");
-
- // Disable submission and check that we're no longer allowed to upload.
- Preferences.set(PREF_DATA_SUBMISSION_ENABLED, false);
- Assert.ok(!TelemetryReportingPolicy.canUpload(),
- "We must not be able to upload if data submission is disabled.");
-
- // Turn the submission back on.
- Preferences.set(PREF_DATA_SUBMISSION_ENABLED, true);
- Assert.ok(TelemetryReportingPolicy.canUpload(),
- "We must be able to upload if data submission is enabled and the policy was accepted.");
-
- // Set a new minimum policy version and check that user is no longer notified.
- let newMinimum = Preferences.get(PREF_CURRENT_POLICY_VERSION, 1) + 1;
- setMinimumPolicyVersion(newMinimum);
- Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(),
- "A greater minimum policy version must invalidate the policy and disable upload.");
-
- // Eventually accept the policy and make sure user is notified.
- Preferences.set(PREF_CURRENT_POLICY_VERSION, newMinimum);
- TelemetryReportingPolicy.testInfobarShown();
- Assert.ok(TelemetryReportingPolicy.testIsUserNotified(),
- "Accepting the policy again should show the user as notified.");
- Assert.ok(TelemetryReportingPolicy.canUpload(),
- "Accepting the policy again should let us upload data.");
-
- // Set a new, per channel, minimum policy version. Start by setting a test current channel.
- let defaultPrefs = new Preferences({ defaultBranch: true });
- defaultPrefs.set("app.update.channel", TEST_CHANNEL);
-
- // Increase and set the new minimum version, then check that we're not notified anymore.
- newMinimum++;
- Preferences.set(PREF_MINIMUM_CHANNEL_POLICY_VERSION, newMinimum);
- Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(),
- "Increasing the minimum policy version should invalidate the policy.");
-
- // Eventually accept the policy and make sure user is notified.
- Preferences.set(PREF_CURRENT_POLICY_VERSION, newMinimum);
- TelemetryReportingPolicy.testInfobarShown();
- Assert.ok(TelemetryReportingPolicy.testIsUserNotified(),
- "Accepting the policy again should show the user as notified.");
- Assert.ok(TelemetryReportingPolicy.canUpload(),
- "Accepting the policy again should let us upload data.");
-});
-
-add_task(function* test_migratePrefs() {
- const DEPRECATED_FHR_PREFS = {
- "datareporting.policy.dataSubmissionPolicyAccepted": true,
- "datareporting.policy.dataSubmissionPolicyBypassAcceptance": true,
- "datareporting.policy.dataSubmissionPolicyResponseType": "foxyeah",
- "datareporting.policy.dataSubmissionPolicyResponseTime": Date.now().toString(),
- };
-
- // Make sure the preferences are set before setting up the policy.
- for (let name in DEPRECATED_FHR_PREFS) {
- Preferences.set(name, DEPRECATED_FHR_PREFS[name]);
- }
- // Set up the policy.
- TelemetryReportingPolicy.reset();
- // They should have been removed by now.
- for (let name in DEPRECATED_FHR_PREFS) {
- Assert.ok(!Preferences.has(name), name + " should have been removed.");
- }
-});
-
-add_task(function* test_userNotifiedOfCurrentPolicy() {
- fakeResetAcceptedPolicy();
- TelemetryReportingPolicy.reset();
-
- // User should be reported as not notified by default.
- Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(),
- "The initial state should be unnotified.");
-
- // Forcing a policy version should not automatically make the user notified.
- Preferences.set(PREF_ACCEPTED_POLICY_VERSION,
- TelemetryReportingPolicy.DEFAULT_DATAREPORTING_POLICY_VERSION);
- Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(),
- "The default state of the date should have a time of 0 and it should therefore fail");
-
- // Showing the notification bar should make the user notified.
- fakeNow(2012, 11, 11);
- TelemetryReportingPolicy.testInfobarShown();
- Assert.ok(TelemetryReportingPolicy.testIsUserNotified(),
- "Using the proper API causes user notification to report as true.");
-
- // It is assumed that later versions of the policy will incorporate previous
- // ones, therefore this should also return true.
- let newVersion =
- Preferences.get(PREF_CURRENT_POLICY_VERSION, 1) + 1;
- Preferences.set(PREF_ACCEPTED_POLICY_VERSION, newVersion);
- Assert.ok(TelemetryReportingPolicy.testIsUserNotified(),
- "A future version of the policy should pass.");
-
- newVersion =
- Preferences.get(PREF_CURRENT_POLICY_VERSION, 1) - 1;
- Preferences.set(PREF_ACCEPTED_POLICY_VERSION, newVersion);
- Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(),
- "A previous version of the policy should fail.");
-});
-
-add_task(function* test_canSend() {
- const TEST_PING_TYPE = "test-ping";
-
- PingServer.start();
- Preferences.set(PREF_SERVER, "http://localhost:" + PingServer.port);
-
- yield TelemetryController.testReset();
- TelemetryReportingPolicy.reset();
-
- // User should be reported as not notified by default.
- Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(),
- "The initial state should be unnotified.");
-
- // Assert if we receive any ping before the policy is accepted.
- PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now"));
- yield TelemetryController.submitExternalPing(TEST_PING_TYPE, {});
-
- // Reset the ping handler.
- PingServer.resetPingHandler();
-
- // Fake the infobar: this should also trigger the ping send task.
- TelemetryReportingPolicy.testInfobarShown();
- let ping = yield PingServer.promiseNextPings(1);
- Assert.equal(ping.length, 1, "We should have received one ping.");
- Assert.equal(ping[0].type, TEST_PING_TYPE,
- "We should have received the previous ping.");
-
- // Submit another ping, to make sure it gets sent.
- yield TelemetryController.submitExternalPing(TEST_PING_TYPE, {});
-
- // Get the ping and check its type.
- ping = yield PingServer.promiseNextPings(1);
- Assert.equal(ping.length, 1, "We should have received one ping.");
- Assert.equal(ping[0].type, TEST_PING_TYPE, "We should have received the new ping.");
-
- // Fake a restart with a pending ping.
- yield TelemetryController.addPendingPing(TEST_PING_TYPE, {});
- yield TelemetryController.testReset();
-
- // We should be immediately sending the ping out.
- ping = yield PingServer.promiseNextPings(1);
- Assert.equal(ping.length, 1, "We should have received one ping.");
- Assert.equal(ping[0].type, TEST_PING_TYPE, "We should have received the pending ping.");
-
- // Submit another ping, to make sure it gets sent.
- yield TelemetryController.submitExternalPing(TEST_PING_TYPE, {});
-
- // Get the ping and check its type.
- ping = yield PingServer.promiseNextPings(1);
- Assert.equal(ping.length, 1, "We should have received one ping.");
- Assert.equal(ping[0].type, TEST_PING_TYPE, "We should have received the new ping.");
-
- yield PingServer.stop();
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryScalars.js b/toolkit/components/telemetry/tests/unit/test_TelemetryScalars.js
deleted file mode 100644
index 5914a4235..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryScalars.js
+++ /dev/null
@@ -1,574 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-*/
-
-const UINT_SCALAR = "telemetry.test.unsigned_int_kind";
-const STRING_SCALAR = "telemetry.test.string_kind";
-const BOOLEAN_SCALAR = "telemetry.test.boolean_kind";
-const KEYED_UINT_SCALAR = "telemetry.test.keyed_unsigned_int";
-
-add_task(function* test_serializationFormat() {
- Telemetry.clearScalars();
-
- // Set the scalars to a known value.
- const expectedUint = 3785;
- const expectedString = "some value";
- Telemetry.scalarSet(UINT_SCALAR, expectedUint);
- Telemetry.scalarSet(STRING_SCALAR, expectedString);
- Telemetry.scalarSet(BOOLEAN_SCALAR, true);
- Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, "first_key", 1234);
-
- // Get a snapshot of the scalars.
- const scalars =
- Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
-
- // Check that they are serialized to the correct format.
- Assert.equal(typeof(scalars[UINT_SCALAR]), "number",
- UINT_SCALAR + " must be serialized to the correct format.");
- Assert.ok(Number.isInteger(scalars[UINT_SCALAR]),
- UINT_SCALAR + " must be a finite integer.");
- Assert.equal(scalars[UINT_SCALAR], expectedUint,
- UINT_SCALAR + " must have the correct value.");
- Assert.equal(typeof(scalars[STRING_SCALAR]), "string",
- STRING_SCALAR + " must be serialized to the correct format.");
- Assert.equal(scalars[STRING_SCALAR], expectedString,
- STRING_SCALAR + " must have the correct value.");
- Assert.equal(typeof(scalars[BOOLEAN_SCALAR]), "boolean",
- BOOLEAN_SCALAR + " must be serialized to the correct format.");
- Assert.equal(scalars[BOOLEAN_SCALAR], true,
- BOOLEAN_SCALAR + " must have the correct value.");
- Assert.ok(!(KEYED_UINT_SCALAR in scalars),
- "Keyed scalars must be reported in a separate section.");
-});
-
-add_task(function* test_keyedSerializationFormat() {
- Telemetry.clearScalars();
-
- const expectedKey = "first_key";
- const expectedOtherKey = "漢語";
- const expectedUint = 3785;
- const expectedOtherValue = 1107;
-
- Telemetry.scalarSet(UINT_SCALAR, expectedUint);
- Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, expectedKey, expectedUint);
- Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, expectedOtherKey, expectedOtherValue);
-
- // Get a snapshot of the scalars.
- const keyedScalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
-
- Assert.ok(!(UINT_SCALAR in keyedScalars),
- UINT_SCALAR + " must not be serialized with the keyed scalars.");
- Assert.ok(KEYED_UINT_SCALAR in keyedScalars,
- KEYED_UINT_SCALAR + " must be serialized with the keyed scalars.");
- Assert.equal(Object.keys(keyedScalars[KEYED_UINT_SCALAR]).length, 2,
- "The keyed scalar must contain exactly 2 keys.");
- Assert.ok(expectedKey in keyedScalars[KEYED_UINT_SCALAR],
- KEYED_UINT_SCALAR + " must contain the expected keys.");
- Assert.ok(expectedOtherKey in keyedScalars[KEYED_UINT_SCALAR],
- KEYED_UINT_SCALAR + " must contain the expected keys.");
- Assert.ok(Number.isInteger(keyedScalars[KEYED_UINT_SCALAR][expectedKey]),
- KEYED_UINT_SCALAR + "." + expectedKey + " must be a finite integer.");
- Assert.equal(keyedScalars[KEYED_UINT_SCALAR][expectedKey], expectedUint,
- KEYED_UINT_SCALAR + "." + expectedKey + " must have the correct value.");
- Assert.equal(keyedScalars[KEYED_UINT_SCALAR][expectedOtherKey], expectedOtherValue,
- KEYED_UINT_SCALAR + "." + expectedOtherKey + " must have the correct value.");
-});
-
-add_task(function* test_nonexistingScalar() {
- const NON_EXISTING_SCALAR = "telemetry.test.non_existing";
-
- Telemetry.clearScalars();
-
- // Make sure we throw on any operation for non-existing scalars.
- Assert.throws(() => Telemetry.scalarAdd(NON_EXISTING_SCALAR, 11715),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Adding to a non existing scalar must throw.");
- Assert.throws(() => Telemetry.scalarSet(NON_EXISTING_SCALAR, 11715),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Setting a non existing scalar must throw.");
- Assert.throws(() => Telemetry.scalarSetMaximum(NON_EXISTING_SCALAR, 11715),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Setting the maximum of a non existing scalar must throw.");
-
- // Make sure we throw on any operation for non-existing scalars.
- Assert.throws(() => Telemetry.keyedScalarAdd(NON_EXISTING_SCALAR, "some_key", 11715),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Adding to a non existing keyed scalar must throw.");
- Assert.throws(() => Telemetry.keyedScalarSet(NON_EXISTING_SCALAR, "some_key", 11715),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Setting a non existing keyed scalar must throw.");
- Assert.throws(() => Telemetry.keyedScalarSetMaximum(NON_EXISTING_SCALAR, "some_key", 11715),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Setting the maximum of a non keyed existing scalar must throw.");
-
- // Get a snapshot of the scalars.
- const scalars =
- Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
-
- Assert.ok(!(NON_EXISTING_SCALAR in scalars), "The non existing scalar must not be persisted.");
-
- const keyedScalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
-
- Assert.ok(!(NON_EXISTING_SCALAR in keyedScalars),
- "The non existing keyed scalar must not be persisted.");
-});
-
-add_task(function* test_expiredScalar() {
- const EXPIRED_SCALAR = "telemetry.test.expired";
- const EXPIRED_KEYED_SCALAR = "telemetry.test.keyed_expired";
- const UNEXPIRED_SCALAR = "telemetry.test.unexpired";
-
- Telemetry.clearScalars();
-
- // Try to set the expired scalar to some value. We will not be recording the value,
- // but we shouldn't throw.
- Telemetry.scalarAdd(EXPIRED_SCALAR, 11715);
- Telemetry.scalarSet(EXPIRED_SCALAR, 11715);
- Telemetry.scalarSetMaximum(EXPIRED_SCALAR, 11715);
- Telemetry.keyedScalarAdd(EXPIRED_KEYED_SCALAR, "some_key", 11715);
- Telemetry.keyedScalarSet(EXPIRED_KEYED_SCALAR, "some_key", 11715);
- Telemetry.keyedScalarSetMaximum(EXPIRED_KEYED_SCALAR, "some_key", 11715);
-
- // The unexpired scalar has an expiration version, but far away in the future.
- const expectedValue = 11716;
- Telemetry.scalarSet(UNEXPIRED_SCALAR, expectedValue);
-
- // Get a snapshot of the scalars.
- const scalars =
- Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- const keyedScalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
-
- Assert.ok(!(EXPIRED_SCALAR in scalars), "The expired scalar must not be persisted.");
- Assert.equal(scalars[UNEXPIRED_SCALAR], expectedValue,
- "The unexpired scalar must be persisted with the correct value.");
- Assert.ok(!(EXPIRED_KEYED_SCALAR in keyedScalars),
- "The expired keyed scalar must not be persisted.");
-});
-
-add_task(function* test_unsignedIntScalar() {
- let checkScalar = (expectedValue) => {
- const scalars =
- Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- Assert.equal(scalars[UINT_SCALAR], expectedValue,
- UINT_SCALAR + " must contain the expected value.");
- };
-
- Telemetry.clearScalars();
-
- // Let's start with an accumulation without a prior set.
- Telemetry.scalarAdd(UINT_SCALAR, 1);
- Telemetry.scalarAdd(UINT_SCALAR, 2);
- // Do we get what we expect?
- checkScalar(3);
-
- // Let's test setting the scalar to a value.
- Telemetry.scalarSet(UINT_SCALAR, 3785);
- checkScalar(3785);
- Telemetry.scalarAdd(UINT_SCALAR, 1);
- checkScalar(3786);
-
- // Does setMaximum work?
- Telemetry.scalarSet(UINT_SCALAR, 2);
- checkScalar(2);
- Telemetry.scalarSetMaximum(UINT_SCALAR, 5);
- checkScalar(5);
- // The value of the probe should still be 5, as the previous value
- // is greater than the one we want to set.
- Telemetry.scalarSetMaximum(UINT_SCALAR, 3);
- checkScalar(5);
-
- // Check that non-integer numbers get truncated and set.
- Telemetry.scalarSet(UINT_SCALAR, 3.785);
- checkScalar(3);
-
- // Setting or adding a negative number must report an error through
- // the console and drop the change (shouldn't throw).
- Telemetry.scalarAdd(UINT_SCALAR, -5);
- Telemetry.scalarSet(UINT_SCALAR, -5);
- Telemetry.scalarSetMaximum(UINT_SCALAR, -1);
- checkScalar(3);
-
- // What happens if we try to set a value of a different type?
- Telemetry.scalarSet(UINT_SCALAR, 1);
- Assert.throws(() => Telemetry.scalarSet(UINT_SCALAR, "unexpected value"),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Setting the scalar to an unexpected value type must throw.");
- Assert.throws(() => Telemetry.scalarAdd(UINT_SCALAR, "unexpected value"),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Adding an unexpected value type must throw.");
- Assert.throws(() => Telemetry.scalarSetMaximum(UINT_SCALAR, "unexpected value"),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Setting the scalar to an unexpected value type must throw.");
- // The stored value must not be compromised.
- checkScalar(1);
-});
-
-add_task(function* test_stringScalar() {
- let checkExpectedString = (expectedString) => {
- const scalars =
- Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- Assert.equal(scalars[STRING_SCALAR], expectedString,
- STRING_SCALAR + " must contain the expected string value.");
- };
-
- Telemetry.clearScalars();
-
- // Let's check simple strings...
- let expected = "test string";
- Telemetry.scalarSet(STRING_SCALAR, expected);
- checkExpectedString(expected);
- expected = "漢語";
- Telemetry.scalarSet(STRING_SCALAR, expected);
- checkExpectedString(expected);
-
- // We have some unsupported operations for strings.
- Assert.throws(() => Telemetry.scalarAdd(STRING_SCALAR, 1),
- /NS_ERROR_NOT_AVAILABLE/,
- "Using an unsupported operation must throw.");
- Assert.throws(() => Telemetry.scalarAdd(STRING_SCALAR, "string value"),
- /NS_ERROR_NOT_AVAILABLE/,
- "Using an unsupported operation must throw.");
- Assert.throws(() => Telemetry.scalarSetMaximum(STRING_SCALAR, 1),
- /NS_ERROR_NOT_AVAILABLE/,
- "Using an unsupported operation must throw.");
- Assert.throws(() => Telemetry.scalarSetMaximum(STRING_SCALAR, "string value"),
- /NS_ERROR_NOT_AVAILABLE/,
- "Using an unsupported operation must throw.");
- Assert.throws(() => Telemetry.scalarSet(STRING_SCALAR, 1),
- /NS_ERROR_ILLEGAL_VALUE/,
- "The string scalar must throw if we're not setting a string.");
-
- // Try to set the scalar to a string longer than the maximum length limit.
- const LONG_STRING = "browser.qaxfiuosnzmhlg.rpvxicawolhtvmbkpnludhedobxvkjwqyeyvmv";
- Telemetry.scalarSet(STRING_SCALAR, LONG_STRING);
- checkExpectedString(LONG_STRING.substr(0, 50));
-});
-
-add_task(function* test_booleanScalar() {
- let checkExpectedBool = (expectedBoolean) => {
- const scalars =
- Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- Assert.equal(scalars[BOOLEAN_SCALAR], expectedBoolean,
- BOOLEAN_SCALAR + " must contain the expected boolean value.");
- };
-
- Telemetry.clearScalars();
-
- // Set a test boolean value.
- let expected = false;
- Telemetry.scalarSet(BOOLEAN_SCALAR, expected);
- checkExpectedBool(expected);
- expected = true;
- Telemetry.scalarSet(BOOLEAN_SCALAR, expected);
- checkExpectedBool(expected);
-
- // Check that setting a numeric value implicitly converts to boolean.
- Telemetry.scalarSet(BOOLEAN_SCALAR, 1);
- checkExpectedBool(true);
- Telemetry.scalarSet(BOOLEAN_SCALAR, 0);
- checkExpectedBool(false);
- Telemetry.scalarSet(BOOLEAN_SCALAR, 1.0);
- checkExpectedBool(true);
- Telemetry.scalarSet(BOOLEAN_SCALAR, 0.0);
- checkExpectedBool(false);
-
- // Check that unsupported operations for booleans throw.
- Assert.throws(() => Telemetry.scalarAdd(BOOLEAN_SCALAR, 1),
- /NS_ERROR_NOT_AVAILABLE/,
- "Using an unsupported operation must throw.");
- Assert.throws(() => Telemetry.scalarAdd(BOOLEAN_SCALAR, "string value"),
- /NS_ERROR_NOT_AVAILABLE/,
- "Using an unsupported operation must throw.");
- Assert.throws(() => Telemetry.scalarSetMaximum(BOOLEAN_SCALAR, 1),
- /NS_ERROR_NOT_AVAILABLE/,
- "Using an unsupported operation must throw.");
- Assert.throws(() => Telemetry.scalarSetMaximum(BOOLEAN_SCALAR, "string value"),
- /NS_ERROR_NOT_AVAILABLE/,
- "Using an unsupported operation must throw.");
- Assert.throws(() => Telemetry.scalarSet(BOOLEAN_SCALAR, "true"),
- /NS_ERROR_ILLEGAL_VALUE/,
- "The boolean scalar must throw if we're not setting a boolean.");
-});
-
-add_task(function* test_scalarRecording() {
- const OPTIN_SCALAR = "telemetry.test.release_optin";
- const OPTOUT_SCALAR = "telemetry.test.release_optout";
-
- let checkValue = (scalarName, expectedValue) => {
- const scalars =
- Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- Assert.equal(scalars[scalarName], expectedValue,
- scalarName + " must contain the expected value.");
- };
-
- let checkNotSerialized = (scalarName) => {
- const scalars =
- Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- Assert.ok(!(scalarName in scalars), scalarName + " was not recorded.");
- };
-
- Telemetry.canRecordBase = false;
- Telemetry.canRecordExtended = false;
- Telemetry.clearScalars();
-
- // Check that no scalar is recorded if both base and extended recording are off.
- Telemetry.scalarSet(OPTOUT_SCALAR, 3);
- Telemetry.scalarSet(OPTIN_SCALAR, 3);
- checkNotSerialized(OPTOUT_SCALAR);
- checkNotSerialized(OPTIN_SCALAR);
-
- // Check that opt-out scalars are recorded, while opt-in are not.
- Telemetry.canRecordBase = true;
- Telemetry.scalarSet(OPTOUT_SCALAR, 3);
- Telemetry.scalarSet(OPTIN_SCALAR, 3);
- checkValue(OPTOUT_SCALAR, 3);
- checkNotSerialized(OPTIN_SCALAR);
-
- // Check that both opt-out and opt-in scalars are recorded.
- Telemetry.canRecordExtended = true;
- Telemetry.scalarSet(OPTOUT_SCALAR, 5);
- Telemetry.scalarSet(OPTIN_SCALAR, 6);
- checkValue(OPTOUT_SCALAR, 5);
- checkValue(OPTIN_SCALAR, 6);
-});
-
-add_task(function* test_keyedScalarRecording() {
- const OPTIN_SCALAR = "telemetry.test.keyed_release_optin";
- const OPTOUT_SCALAR = "telemetry.test.keyed_release_optout";
- const testKey = "policy_key";
-
- let checkValue = (scalarName, expectedValue) => {
- const scalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- Assert.equal(scalars[scalarName][testKey], expectedValue,
- scalarName + " must contain the expected value.");
- };
-
- let checkNotSerialized = (scalarName) => {
- const scalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- Assert.ok(!(scalarName in scalars), scalarName + " was not recorded.");
- };
-
- Telemetry.canRecordBase = false;
- Telemetry.canRecordExtended = false;
- Telemetry.clearScalars();
-
- // Check that no scalar is recorded if both base and extended recording are off.
- Telemetry.keyedScalarSet(OPTOUT_SCALAR, testKey, 3);
- Telemetry.keyedScalarSet(OPTIN_SCALAR, testKey, 3);
- checkNotSerialized(OPTOUT_SCALAR);
- checkNotSerialized(OPTIN_SCALAR);
-
- // Check that opt-out scalars are recorded, while opt-in are not.
- Telemetry.canRecordBase = true;
- Telemetry.keyedScalarSet(OPTOUT_SCALAR, testKey, 3);
- Telemetry.keyedScalarSet(OPTIN_SCALAR, testKey, 3);
- checkValue(OPTOUT_SCALAR, 3);
- checkNotSerialized(OPTIN_SCALAR);
-
- // Check that both opt-out and opt-in scalars are recorded.
- Telemetry.canRecordExtended = true;
- Telemetry.keyedScalarSet(OPTOUT_SCALAR, testKey, 5);
- Telemetry.keyedScalarSet(OPTIN_SCALAR, testKey, 6);
- checkValue(OPTOUT_SCALAR, 5);
- checkValue(OPTIN_SCALAR, 6);
-});
-
-add_task(function* test_subsession() {
- Telemetry.clearScalars();
-
- // Set the scalars to a known value.
- Telemetry.scalarSet(UINT_SCALAR, 3785);
- Telemetry.scalarSet(STRING_SCALAR, "some value");
- Telemetry.scalarSet(BOOLEAN_SCALAR, false);
- Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, "some_random_key", 12);
-
- // Get a snapshot and reset the subsession. The value we set must be there.
- let scalars =
- Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
- let keyedScalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
-
- Assert.equal(scalars[UINT_SCALAR], 3785,
- UINT_SCALAR + " must contain the expected value.");
- Assert.equal(scalars[STRING_SCALAR], "some value",
- STRING_SCALAR + " must contain the expected value.");
- Assert.equal(scalars[BOOLEAN_SCALAR], false,
- BOOLEAN_SCALAR + " must contain the expected value.");
- Assert.equal(keyedScalars[KEYED_UINT_SCALAR]["some_random_key"], 12,
- KEYED_UINT_SCALAR + " must contain the expected value.");
-
- // Get a new snapshot and reset the subsession again. Since no new value
- // was set, the scalars should not be reported.
- scalars =
- Telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
- keyedScalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true);
-
- Assert.ok(!(UINT_SCALAR in scalars), UINT_SCALAR + " must be empty and not reported.");
- Assert.ok(!(STRING_SCALAR in scalars), STRING_SCALAR + " must be empty and not reported.");
- Assert.ok(!(BOOLEAN_SCALAR in scalars), BOOLEAN_SCALAR + " must be empty and not reported.");
- Assert.ok(!(KEYED_UINT_SCALAR in keyedScalars), KEYED_UINT_SCALAR + " must be empty and not reported.");
-});
-
-add_task(function* test_keyed_uint() {
- Telemetry.clearScalars();
-
- const KEYS = [ "a_key", "another_key", "third_key" ];
- let expectedValues = [ 1, 1, 1 ];
-
- // Set all the keys to a baseline value.
- for (let key of KEYS) {
- Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, key, 1);
- }
-
- // Increment only one key.
- Telemetry.keyedScalarAdd(KEYED_UINT_SCALAR, KEYS[1], 1);
- expectedValues[1]++;
-
- // Use SetMaximum on the third key.
- Telemetry.keyedScalarSetMaximum(KEYED_UINT_SCALAR, KEYS[2], 37);
- expectedValues[2] = 37;
-
- // Get a snapshot of the scalars and make sure the keys contain
- // the correct values.
- const keyedScalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
-
- for (let k = 0; k < 3; k++) {
- const keyName = KEYS[k];
- Assert.equal(keyedScalars[KEYED_UINT_SCALAR][keyName], expectedValues[k],
- KEYED_UINT_SCALAR + "." + keyName + " must contain the correct value.");
- }
-
- // Are we still throwing when doing unsupported things on uint keyed scalars?
- // Just test one single unsupported operation, the other are covered in the plain
- // unsigned scalar test.
- Assert.throws(() => Telemetry.scalarSet(KEYED_UINT_SCALAR, "new_key", "unexpected value"),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Setting the scalar to an unexpected value type must throw.");
-});
-
-add_task(function* test_keyed_boolean() {
- Telemetry.clearScalars();
-
- const KEYED_BOOLEAN_TYPE = "telemetry.test.keyed_boolean_kind";
- const first_key = "first_key";
- const second_key = "second_key";
-
- // Set the initial values.
- Telemetry.keyedScalarSet(KEYED_BOOLEAN_TYPE, first_key, true);
- Telemetry.keyedScalarSet(KEYED_BOOLEAN_TYPE, second_key, false);
-
- // Get a snapshot of the scalars and make sure the keys contain
- // the correct values.
- let keyedScalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- Assert.equal(keyedScalars[KEYED_BOOLEAN_TYPE][first_key], true,
- "The key must contain the expected value.");
- Assert.equal(keyedScalars[KEYED_BOOLEAN_TYPE][second_key], false,
- "The key must contain the expected value.");
-
- // Now flip the values and make sure we get the expected values back.
- Telemetry.keyedScalarSet(KEYED_BOOLEAN_TYPE, first_key, false);
- Telemetry.keyedScalarSet(KEYED_BOOLEAN_TYPE, second_key, true);
-
- keyedScalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- Assert.equal(keyedScalars[KEYED_BOOLEAN_TYPE][first_key], false,
- "The key must contain the expected value.");
- Assert.equal(keyedScalars[KEYED_BOOLEAN_TYPE][second_key], true,
- "The key must contain the expected value.");
-
- // Are we still throwing when doing unsupported things on a boolean keyed scalars?
- // Just test one single unsupported operation, the other are covered in the plain
- // boolean scalar test.
- Assert.throws(() => Telemetry.keyedScalarAdd(KEYED_BOOLEAN_TYPE, "somehey", 1),
- /NS_ERROR_NOT_AVAILABLE/,
- "Using an unsupported operation must throw.");
-});
-
-add_task(function* test_keyed_keys_length() {
- Telemetry.clearScalars();
-
- const LONG_KEY_STRING =
- "browser.qaxfiuosnzmhlg.rpvxicawolhtvmbkpnludhedobxvkjwqyeyvmv.somemoresowereach70chars";
- const NORMAL_KEY = "a_key";
-
- // Set the value for a key within the length limits.
- Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, NORMAL_KEY, 1);
-
- // Now try to set and modify the value for a very long key.
- Assert.throws(() => Telemetry.keyedScalarAdd(KEYED_UINT_SCALAR, LONG_KEY_STRING, 10),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Using keys longer than 70 characters must throw.");
- Assert.throws(() => Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, LONG_KEY_STRING, 1),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Using keys longer than 70 characters must throw.");
- Assert.throws(() => Telemetry.keyedScalarSetMaximum(KEYED_UINT_SCALAR, LONG_KEY_STRING, 10),
- /NS_ERROR_ILLEGAL_VALUE/,
- "Using keys longer than 70 characters must throw.");
-
- // Make sure the key with the right length contains the expected value.
- let keyedScalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
- Assert.equal(Object.keys(keyedScalars[KEYED_UINT_SCALAR]).length, 1,
- "The keyed scalar must contain exactly 1 key.");
- Assert.ok(NORMAL_KEY in keyedScalars[KEYED_UINT_SCALAR],
- "The keyed scalar must contain the expected key.");
- Assert.equal(keyedScalars[KEYED_UINT_SCALAR][NORMAL_KEY], 1,
- "The key must contain the expected value.");
- Assert.ok(!(LONG_KEY_STRING in keyedScalars[KEYED_UINT_SCALAR]),
- "The data for the long key should not have been recorded.");
-});
-
-add_task(function* test_keyed_max_keys() {
- Telemetry.clearScalars();
-
- // Generate the names for the first 100 keys.
- let keyNamesSet = new Set();
- for (let k = 0; k < 100; k++) {
- keyNamesSet.add("key_" + k);
- }
-
- // Add 100 keys to an histogram and set their initial value.
- let valueToSet = 0;
- keyNamesSet.forEach(keyName => {
- Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, keyName, valueToSet++);
- });
-
- // Perform some operations on the 101th key. This should throw, as
- // we're not allowed to have more than 100 keys.
- const LAST_KEY_NAME = "overflowing_key";
- Assert.throws(() => Telemetry.keyedScalarAdd(KEYED_UINT_SCALAR, LAST_KEY_NAME, 10),
- /NS_ERROR_FAILURE/,
- "Using more than 100 keys must throw.");
- Assert.throws(() => Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, LAST_KEY_NAME, 1),
- /NS_ERROR_FAILURE/,
- "Using more than 100 keys must throw.");
- Assert.throws(() => Telemetry.keyedScalarSetMaximum(KEYED_UINT_SCALAR, LAST_KEY_NAME, 10),
- /NS_ERROR_FAILURE/,
- "Using more than 100 keys must throw.");
-
- // Make sure all the keys except the last one are available and have the correct
- // values.
- let keyedScalars =
- Telemetry.snapshotKeyedScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
-
- // Check that the keyed scalar only contain the first 100 keys.
- const reportedKeysSet = new Set(Object.keys(keyedScalars[KEYED_UINT_SCALAR]));
- Assert.ok([...keyNamesSet].filter(x => reportedKeysSet.has(x)) &&
- [...reportedKeysSet].filter(x => keyNamesSet.has(x)),
- "The keyed scalar must contain all the 100 keys, and drop the others.");
-
- // Check that all the keys recorded the expected values.
- let expectedValue = 0;
- keyNamesSet.forEach(keyName => {
- Assert.equal(keyedScalars[KEYED_UINT_SCALAR][keyName], expectedValue++,
- "The key must contain the expected value.");
- });
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetrySend.js b/toolkit/components/telemetry/tests/unit/test_TelemetrySend.js
deleted file mode 100644
index 88ff8cf44..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySend.js
+++ /dev/null
@@ -1,427 +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/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySend.jsm", this);
-Cu.import("resource://gre/modules/TelemetryUtils.jsm", this);
-Cu.import("resource://gre/modules/Services.jsm", this);
-Cu.import("resource://gre/modules/Preferences.jsm", this);
-Cu.import("resource://gre/modules/osfile.jsm", this);
-
-const PREF_TELEMETRY_SERVER = "toolkit.telemetry.server";
-
-const MS_IN_A_MINUTE = 60 * 1000;
-
-function countPingTypes(pings) {
- let countByType = new Map();
- for (let p of pings) {
- countByType.set(p.type, 1 + (countByType.get(p.type) || 0));
- }
- return countByType;
-}
-
-function setPingLastModified(id, timestamp) {
- const path = OS.Path.join(TelemetryStorage.pingDirectoryPath, id);
- return OS.File.setDates(path, null, timestamp);
-}
-
-// Mock out the send timer activity.
-function waitForTimer() {
- return new Promise(resolve => {
- fakePingSendTimer((callback, timeout) => {
- resolve([callback, timeout]);
- }, () => {});
- });
-}
-
-// Allow easy faking of readable ping ids.
-// This helps with debugging issues with e.g. ordering in the send logic.
-function fakePingId(type, number) {
- const HEAD = "93bd0011-2c8f-4e1c-bee0-";
- const TAIL = "000000000000";
- const N = String(number);
- const id = HEAD + type + TAIL.slice(type.length, - N.length) + N;
- fakeGeneratePingId(() => id);
- return id;
-}
-
-var checkPingsSaved = Task.async(function* (pingIds) {
- let allFound = true;
- for (let id of pingIds) {
- const path = OS.Path.join(TelemetryStorage.pingDirectoryPath, id);
- let exists = false;
- try {
- exists = yield OS.File.exists(path);
- } catch (ex) {}
-
- if (!exists) {
- dump("checkPingsSaved - failed to find ping: " + path + "\n");
- allFound = false;
- }
- }
-
- return allFound;
-});
-
-function histogramValueCount(h) {
- return h.counts.reduce((a, b) => a + b);
-}
-
-add_task(function* test_setup() {
- // Trigger a proper telemetry init.
- 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);
-});
-
-// Test the ping sending logic.
-add_task(function* test_sendPendingPings() {
- const TYPE_PREFIX = "test-sendPendingPings-";
- const TEST_TYPE_A = TYPE_PREFIX + "A";
- const TEST_TYPE_B = TYPE_PREFIX + "B";
-
- const TYPE_A_COUNT = 20;
- const TYPE_B_COUNT = 5;
-
- let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
- let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
- let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
- histSuccess.clear();
- histSendTimeSuccess.clear();
- histSendTimeFail.clear();
-
- // Fake a current date.
- let now = TelemetryUtils.truncateToDays(new Date());
- now = fakeNow(futureDate(now, 10 * 60 * MS_IN_A_MINUTE));
-
- // Enable test-mode for TelemetrySend, otherwise we won't store pending pings
- // before the module is fully initialized later.
- TelemetrySend.setTestModeEnabled(true);
-
- // Submit some pings without the server and telemetry started yet.
- for (let i = 0; i < TYPE_A_COUNT; ++i) {
- fakePingId("a", i);
- const id = yield TelemetryController.submitExternalPing(TEST_TYPE_A, {});
- yield setPingLastModified(id, now.getTime() + (i * 1000));
- }
-
- Assert.equal(TelemetrySend.pendingPingCount, TYPE_A_COUNT,
- "Should have correct pending ping count");
-
- // Submit some more pings of a different type.
- now = fakeNow(futureDate(now, 5 * MS_IN_A_MINUTE));
- for (let i = 0; i < TYPE_B_COUNT; ++i) {
- fakePingId("b", i);
- const id = yield TelemetryController.submitExternalPing(TEST_TYPE_B, {});
- yield setPingLastModified(id, now.getTime() + (i * 1000));
- }
-
- Assert.equal(TelemetrySend.pendingPingCount, TYPE_A_COUNT + TYPE_B_COUNT,
- "Should have correct pending ping count");
-
- Assert.deepEqual(histSuccess.snapshot().counts, [0, 0, 0],
- "Should not have recorded any sending in histograms yet.");
- Assert.equal(histSendTimeSuccess.snapshot().sum, 0,
- "Should not have recorded any sending in histograms yet.");
- Assert.equal(histSendTimeFail.snapshot().sum, 0,
- "Should not have recorded any sending in histograms yet.");
-
- // Now enable sending to the ping server.
- now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
- PingServer.start();
- Preferences.set(PREF_TELEMETRY_SERVER, "http://localhost:" + PingServer.port);
-
- let timerPromise = waitForTimer();
- yield TelemetryController.testReset();
- let [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
- Assert.ok(!!pingSendTimerCallback, "Should have a timer callback");
-
- // We should have received 10 pings from the first send batch:
- // 5 of type B and 5 of type A, as sending is newest-first.
- // The other pings should be delayed by the 10-pings-per-minute limit.
- let pings = yield PingServer.promiseNextPings(10);
- Assert.equal(TelemetrySend.pendingPingCount, TYPE_A_COUNT - 5,
- "Should have correct pending ping count");
- PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now"));
- let countByType = countPingTypes(pings);
-
- Assert.equal(countByType.get(TEST_TYPE_B), TYPE_B_COUNT,
- "Should have received the correct amount of type B pings");
- Assert.equal(countByType.get(TEST_TYPE_A), 10 - TYPE_B_COUNT,
- "Should have received the correct amount of type A pings");
-
- Assert.deepEqual(histSuccess.snapshot().counts, [0, 10, 0],
- "Should have recorded sending success in histograms.");
- Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 10,
- "Should have recorded successful send times in histograms.");
- Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0,
- "Should not have recorded any failed sending in histograms yet.");
-
- // As we hit the ping send limit and still have pending pings, a send tick should
- // be scheduled in a minute.
- Assert.ok(!!pingSendTimerCallback, "Timer callback should be set");
- Assert.equal(pingSendTimeout, MS_IN_A_MINUTE, "Send tick timeout should be correct");
-
- // Trigger the next tick - we should receive the next 10 type A pings.
- PingServer.resetPingHandler();
- now = fakeNow(futureDate(now, pingSendTimeout));
- timerPromise = waitForTimer();
- pingSendTimerCallback();
- [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
-
- pings = yield PingServer.promiseNextPings(10);
- PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now"));
- countByType = countPingTypes(pings);
-
- Assert.equal(countByType.get(TEST_TYPE_A), 10, "Should have received the correct amount of type A pings");
-
- // We hit the ping send limit again and still have pending pings, a send tick should
- // be scheduled in a minute.
- Assert.equal(pingSendTimeout, MS_IN_A_MINUTE, "Send tick timeout should be correct");
-
- // Trigger the next tick - we should receive the remaining type A pings.
- PingServer.resetPingHandler();
- now = fakeNow(futureDate(now, pingSendTimeout));
- yield pingSendTimerCallback();
-
- pings = yield PingServer.promiseNextPings(5);
- PingServer.registerPingHandler(() => Assert.ok(false, "Should not have received any pings now"));
- countByType = countPingTypes(pings);
-
- Assert.equal(countByType.get(TEST_TYPE_A), 5, "Should have received the correct amount of type A pings");
-
- yield TelemetrySend.testWaitOnOutgoingPings();
- PingServer.resetPingHandler();
-});
-
-add_task(function* test_sendDateHeader() {
- fakeNow(new Date(Date.UTC(2011, 1, 1, 11, 0, 0)));
- yield TelemetrySend.reset();
-
- let pingId = yield TelemetryController.submitExternalPing("test-send-date-header", {});
- let req = yield PingServer.promiseNextRequest();
- let ping = decodeRequestPayload(req);
- Assert.equal(req.getHeader("Date"), "Tue, 01 Feb 2011 11:00:00 GMT",
- "Telemetry should send the correct Date header with requests.");
- Assert.equal(ping.id, pingId, "Should have received the correct ping id.");
-});
-
-// Test the backoff timeout behavior after send failures.
-add_task(function* test_backoffTimeout() {
- const TYPE_PREFIX = "test-backoffTimeout-";
- const TEST_TYPE_C = TYPE_PREFIX + "C";
- const TEST_TYPE_D = TYPE_PREFIX + "D";
- const TEST_TYPE_E = TYPE_PREFIX + "E";
-
- let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
- let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
- let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
-
- // Failing a ping send now should trigger backoff behavior.
- let now = fakeNow(2010, 1, 1, 11, 0, 0);
- yield TelemetrySend.reset();
- PingServer.stop();
-
- histSuccess.clear();
- histSendTimeSuccess.clear();
- histSendTimeFail.clear();
-
- fakePingId("c", 0);
- now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
- let sendAttempts = 0;
- let timerPromise = waitForTimer();
- yield TelemetryController.submitExternalPing(TEST_TYPE_C, {});
- let [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
- Assert.equal(TelemetrySend.pendingPingCount, 1, "Should have one pending ping.");
- ++sendAttempts;
-
- const MAX_BACKOFF_TIMEOUT = 120 * MS_IN_A_MINUTE;
- for (let timeout = 2 * MS_IN_A_MINUTE; timeout <= MAX_BACKOFF_TIMEOUT; timeout *= 2) {
- Assert.ok(!!pingSendTimerCallback, "Should have received a timer callback");
- Assert.equal(pingSendTimeout, timeout, "Send tick timeout should be correct");
-
- let callback = pingSendTimerCallback;
- now = fakeNow(futureDate(now, pingSendTimeout));
- timerPromise = waitForTimer();
- yield callback();
- [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
- ++sendAttempts;
- }
-
- timerPromise = waitForTimer();
- yield pingSendTimerCallback();
- [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
- Assert.equal(pingSendTimeout, MAX_BACKOFF_TIMEOUT, "Tick timeout should be capped");
- ++sendAttempts;
-
- Assert.deepEqual(histSuccess.snapshot().counts, [sendAttempts, 0, 0],
- "Should have recorded sending failure in histograms.");
- Assert.equal(histSendTimeSuccess.snapshot().sum, 0,
- "Should not have recorded any sending success in histograms yet.");
- Assert.greater(histSendTimeFail.snapshot().sum, 0,
- "Should have recorded send failure times in histograms.");
- Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), sendAttempts,
- "Should have recorded send failure times in histograms.");
-
- // Submitting a new ping should reset the backoff behavior.
- fakePingId("d", 0);
- now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
- timerPromise = waitForTimer();
- yield TelemetryController.submitExternalPing(TEST_TYPE_D, {});
- [pingSendTimerCallback, pingSendTimeout] = yield timerPromise;
- Assert.equal(pingSendTimeout, 2 * MS_IN_A_MINUTE, "Send tick timeout should be correct");
- sendAttempts += 2;
-
- // With the server running again, we should send out the pending pings immediately
- // when a new ping is submitted.
- PingServer.start();
- TelemetrySend.setServer("http://localhost:" + PingServer.port);
- fakePingId("e", 0);
- now = fakeNow(futureDate(now, MS_IN_A_MINUTE));
- timerPromise = waitForTimer();
- yield TelemetryController.submitExternalPing(TEST_TYPE_E, {});
-
- let pings = yield PingServer.promiseNextPings(3);
- let countByType = countPingTypes(pings);
-
- Assert.equal(countByType.get(TEST_TYPE_C), 1, "Should have received the correct amount of type C pings");
- Assert.equal(countByType.get(TEST_TYPE_D), 1, "Should have received the correct amount of type D pings");
- Assert.equal(countByType.get(TEST_TYPE_E), 1, "Should have received the correct amount of type E pings");
-
- yield TelemetrySend.testWaitOnOutgoingPings();
- Assert.equal(TelemetrySend.pendingPingCount, 0, "Should have no pending pings left");
-
- Assert.deepEqual(histSuccess.snapshot().counts, [sendAttempts, 3, 0],
- "Should have recorded sending failure in histograms.");
- Assert.greater(histSendTimeSuccess.snapshot().sum, 0,
- "Should have recorded sending success in histograms.");
- Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 3,
- "Should have recorded sending success in histograms.");
- Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), sendAttempts,
- "Should have recorded send failure times in histograms.");
-});
-
-add_task(function* test_discardBigPings() {
- const TEST_PING_TYPE = "test-ping-type";
-
- let histSizeExceeded = Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_SEND");
- let histDiscardedSize = Telemetry.getHistogramById("TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB");
- let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
- let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
- let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
- for (let h of [histSizeExceeded, histDiscardedSize, histSuccess, histSendTimeSuccess, histSendTimeFail]) {
- h.clear();
- }
-
- // Generate a 2MB string and create an oversized payload.
- const OVERSIZED_PAYLOAD = {"data": generateRandomString(2 * 1024 * 1024)};
-
- // Reset the histograms.
- Telemetry.getHistogramById("TELEMETRY_PING_SIZE_EXCEEDED_SEND").clear();
- Telemetry.getHistogramById("TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB").clear();
-
- // Submit a ping of a normal size and check that we don't count it in the histogram.
- yield TelemetryController.submitExternalPing(TEST_PING_TYPE, { test: "test" });
- yield TelemetrySend.testWaitOnOutgoingPings();
-
- Assert.equal(histSizeExceeded.snapshot().sum, 0, "Telemetry must report no oversized ping submitted.");
- Assert.equal(histDiscardedSize.snapshot().sum, 0, "Telemetry must report no oversized pings.");
- Assert.deepEqual(histSuccess.snapshot().counts, [0, 1, 0], "Should have recorded sending success.");
- Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 1, "Should have recorded send success time.");
- Assert.greater(histSendTimeSuccess.snapshot().sum, 0, "Should have recorded send success time.");
- Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0, "Should not have recorded send failure time.");
-
- // Submit an oversized ping and check that it gets discarded.
- yield TelemetryController.submitExternalPing(TEST_PING_TYPE, OVERSIZED_PAYLOAD);
- yield TelemetrySend.testWaitOnOutgoingPings();
-
- Assert.equal(histSizeExceeded.snapshot().sum, 1, "Telemetry must report 1 oversized ping submitted.");
- Assert.equal(histDiscardedSize.snapshot().counts[2], 1, "Telemetry must report a 2MB, oversized, ping submitted.");
- Assert.deepEqual(histSuccess.snapshot().counts, [0, 1, 0], "Should have recorded sending success.");
- Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 1, "Should have recorded send success time.");
- Assert.greater(histSendTimeSuccess.snapshot().sum, 0, "Should have recorded send success time.");
- Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0, "Should not have recorded send failure time.");
-});
-
-add_task(function* test_evictedOnServerErrors() {
- const TEST_TYPE = "test-evicted";
-
- yield TelemetrySend.reset();
-
- let histEvicted = Telemetry.getHistogramById("TELEMETRY_PING_EVICTED_FOR_SERVER_ERRORS");
- let histSuccess = Telemetry.getHistogramById("TELEMETRY_SUCCESS");
- let histSendTimeSuccess = Telemetry.getHistogramById("TELEMETRY_SEND_SUCCESS");
- let histSendTimeFail = Telemetry.getHistogramById("TELEMETRY_SEND_FAILURE");
- for (let h of [histEvicted, histSuccess, histSendTimeSuccess, histSendTimeFail]) {
- h.clear();
- }
-
- // Write a custom ping handler which will return 403. This will trigger ping eviction
- // on client side.
- PingServer.registerPingHandler((req, res) => {
- res.setStatusLine(null, 403, "Forbidden");
- res.processAsync();
- res.finish();
- });
-
- // Clear the histogram and submit a ping.
- let pingId = yield TelemetryController.submitExternalPing(TEST_TYPE, {});
- yield TelemetrySend.testWaitOnOutgoingPings();
-
- Assert.equal(histEvicted.snapshot().sum, 1,
- "Telemetry must report a ping evicted due to server errors");
- Assert.deepEqual(histSuccess.snapshot().counts, [0, 1, 0]);
- Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 1);
- Assert.greater(histSendTimeSuccess.snapshot().sum, 0);
- Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0);
-
- // The ping should not be persisted.
- yield Assert.rejects(TelemetryStorage.loadPendingPing(pingId), "The ping must not be persisted.");
-
- // Reset the ping handler and submit a new ping.
- PingServer.resetPingHandler();
- pingId = yield TelemetryController.submitExternalPing(TEST_TYPE, {});
-
- let ping = yield PingServer.promiseNextPings(1);
- Assert.equal(ping[0].id, pingId, "The correct ping must be received");
-
- // We should not have updated the error histogram.
- yield TelemetrySend.testWaitOnOutgoingPings();
- Assert.equal(histEvicted.snapshot().sum, 1, "Telemetry must report only one ping evicted due to server errors");
- Assert.deepEqual(histSuccess.snapshot().counts, [0, 2, 0]);
- Assert.equal(histogramValueCount(histSendTimeSuccess.snapshot()), 2);
- Assert.equal(histogramValueCount(histSendTimeFail.snapshot()), 0);
-});
-
-// Test that the current, non-persisted pending pings are properly saved on shutdown.
-add_task(function* test_persistCurrentPingsOnShutdown() {
- const TEST_TYPE = "test-persistCurrentPingsOnShutdown";
- const PING_COUNT = 5;
- yield TelemetrySend.reset();
- PingServer.stop();
- Assert.equal(TelemetrySend.pendingPingCount, 0, "Should have no pending pings yet");
-
- // Submit new pings that shouldn't be persisted yet.
- let ids = [];
- for (let i=0; i<5; ++i) {
- ids.push(fakePingId("f", i));
- TelemetryController.submitExternalPing(TEST_TYPE, {});
- }
-
- Assert.equal(TelemetrySend.pendingPingCount, PING_COUNT, "Should have the correct pending ping count");
-
- // Triggering a shutdown should persist the pings.
- yield TelemetrySend.shutdown();
- Assert.ok((yield checkPingsSaved(ids)), "All pending pings should have been persisted");
-
- // After a restart the pings should have been found when scanning.
- yield TelemetrySend.reset();
- Assert.equal(TelemetrySend.pendingPingCount, PING_COUNT, "Should have the correct pending ping count");
-});
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();
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
deleted file mode 100644
index 698133162..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ /dev/null
@@ -1,2029 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-*/
-/* This testcase triggers two telemetry pings.
- *
- * Telemetry code keeps histograms of past telemetry pings. The first
- * ping populates these histograms. One of those histograms is then
- * checked in the second request.
- */
-
-Cu.import("resource://services-common/utils.js");
-Cu.import("resource://gre/modules/ClientID.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/LightweightThemeManager.jsm", this);
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
-Cu.import("resource://gre/modules/TelemetryStorage.jsm", this);
-Cu.import("resource://gre/modules/TelemetryEnvironment.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySend.jsm", this);
-Cu.import("resource://gre/modules/Task.jsm", this);
-Cu.import("resource://gre/modules/Promise.jsm", this);
-Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/osfile.jsm", this);
-
-const PING_FORMAT_VERSION = 4;
-const PING_TYPE_MAIN = "main";
-const PING_TYPE_SAVED_SESSION = "saved-session";
-
-const REASON_ABORTED_SESSION = "aborted-session";
-const REASON_SAVED_SESSION = "saved-session";
-const REASON_SHUTDOWN = "shutdown";
-const REASON_TEST_PING = "test-ping";
-const REASON_DAILY = "daily";
-const REASON_ENVIRONMENT_CHANGE = "environment-change";
-
-const PLATFORM_VERSION = "1.9.2";
-const APP_VERSION = "1";
-const APP_ID = "xpcshell@tests.mozilla.org";
-const APP_NAME = "XPCShell";
-
-const IGNORE_HISTOGRAM_TO_CLONE = "MEMORY_HEAP_ALLOCATED";
-const IGNORE_CLONED_HISTOGRAM = "test::ignore_me_also";
-const ADDON_NAME = "Telemetry test addon";
-const ADDON_HISTOGRAM = "addon-histogram";
-// Add some unicode characters here to ensure that sending them works correctly.
-const SHUTDOWN_TIME = 10000;
-const FAILED_PROFILE_LOCK_ATTEMPTS = 2;
-
-// Constants from prio.h for nsIFileOutputStream.init
-const PR_WRONLY = 0x2;
-const PR_CREATE_FILE = 0x8;
-const PR_TRUNCATE = 0x20;
-const RW_OWNER = parseInt("0600", 8);
-
-const NUMBER_OF_THREADS_TO_LAUNCH = 30;
-var gNumberOfThreadsLaunched = 0;
-
-const MS_IN_ONE_HOUR = 60 * 60 * 1000;
-const MS_IN_ONE_DAY = 24 * MS_IN_ONE_HOUR;
-
-const PREF_BRANCH = "toolkit.telemetry.";
-const PREF_SERVER = PREF_BRANCH + "server";
-const PREF_FHR_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
-
-const DATAREPORTING_DIR = "datareporting";
-const ABORTED_PING_FILE_NAME = "aborted-session-ping";
-const ABORTED_SESSION_UPDATE_INTERVAL_MS = 5 * 60 * 1000;
-
-XPCOMUtils.defineLazyGetter(this, "DATAREPORTING_PATH", function() {
- return OS.Path.join(OS.Constants.Path.profileDir, DATAREPORTING_DIR);
-});
-
-var gClientID = null;
-var gMonotonicNow = 0;
-
-function generateUUID() {
- let str = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
- // strip {}
- return str.substring(1, str.length - 1);
-}
-
-function truncateDateToDays(date) {
- return new Date(date.getFullYear(),
- date.getMonth(),
- date.getDate(),
- 0, 0, 0, 0);
-}
-
-function sendPing() {
- TelemetrySession.gatherStartup();
- if (PingServer.started) {
- TelemetrySend.setServer("http://localhost:" + PingServer.port);
- return TelemetrySession.testPing();
- }
- TelemetrySend.setServer("http://doesnotexist");
- return TelemetrySession.testPing();
-}
-
-function fakeGenerateUUID(sessionFunc, subsessionFunc) {
- let session = Cu.import("resource://gre/modules/TelemetrySession.jsm");
- session.Policy.generateSessionUUID = sessionFunc;
- session.Policy.generateSubsessionUUID = subsessionFunc;
-}
-
-function fakeIdleNotification(topic) {
- let session = Cu.import("resource://gre/modules/TelemetrySession.jsm");
- return session.TelemetryScheduler.observe(null, topic, null);
-}
-
-function setupTestData() {
-
- Services.startup.interrupted = true;
- Telemetry.registerAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM,
- Telemetry.HISTOGRAM_LINEAR,
- 1, 5, 6);
- let h1 = Telemetry.getAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM);
- h1.add(1);
- let h2 = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
- h2.add();
-
- let k1 = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_COUNT");
- k1.add("a");
- k1.add("a");
- k1.add("b");
-}
-
-function getSavedPingFile(basename) {
- let tmpDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
- let pingFile = tmpDir.clone();
- pingFile.append(basename);
- if (pingFile.exists()) {
- pingFile.remove(true);
- }
- do_register_cleanup(function () {
- try {
- pingFile.remove(true);
- } catch (e) {
- }
- });
- return pingFile;
-}
-
-function checkPingFormat(aPing, aType, aHasClientId, aHasEnvironment) {
- const MANDATORY_PING_FIELDS = [
- "type", "id", "creationDate", "version", "application", "payload"
- ];
-
- const APPLICATION_TEST_DATA = {
- buildId: gAppInfo.appBuildID,
- name: APP_NAME,
- version: APP_VERSION,
- vendor: "Mozilla",
- platformVersion: PLATFORM_VERSION,
- xpcomAbi: "noarch-spidermonkey",
- };
-
- // Check that the ping contains all the mandatory fields.
- for (let f of MANDATORY_PING_FIELDS) {
- Assert.ok(f in aPing, f + "must be available.");
- }
-
- Assert.equal(aPing.type, aType, "The ping must have the correct type.");
- Assert.equal(aPing.version, PING_FORMAT_VERSION, "The ping must have the correct version.");
-
- // Test the application section.
- for (let f in APPLICATION_TEST_DATA) {
- Assert.equal(aPing.application[f], APPLICATION_TEST_DATA[f],
- f + " must have the correct value.");
- }
-
- // We can't check the values for channel and architecture. Just make
- // sure they are in.
- Assert.ok("architecture" in aPing.application,
- "The application section must have an architecture field.");
- Assert.ok("channel" in aPing.application,
- "The application section must have a channel field.");
-
- // Check the clientId and environment fields, as needed.
- Assert.equal("clientId" in aPing, aHasClientId);
- Assert.equal("environment" in aPing, aHasEnvironment);
-}
-
-function checkPayloadInfo(data) {
- const ALLOWED_REASONS = [
- "environment-change", "shutdown", "daily", "saved-session", "test-ping"
- ];
- let numberCheck = arg => { return (typeof arg == "number"); };
- let positiveNumberCheck = arg => { return numberCheck(arg) && (arg >= 0); };
- let stringCheck = arg => { return (typeof arg == "string") && (arg != ""); };
- let revisionCheck = arg => {
- return (Services.appinfo.isOfficial) ? stringCheck(arg) : (typeof arg == "string");
- };
- let uuidCheck = arg => {
- return UUID_REGEX.test(arg);
- };
- let isoDateCheck = arg => {
- // We expect use of this version of the ISO format:
- // 2015-04-12T18:51:19.1+00:00
- const isoDateRegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+[+-]\d{2}:\d{2}$/;
- return stringCheck(arg) && !Number.isNaN(Date.parse(arg)) &&
- isoDateRegEx.test(arg);
- };
-
- const EXPECTED_INFO_FIELDS_TYPES = {
- reason: stringCheck,
- revision: revisionCheck,
- timezoneOffset: numberCheck,
- sessionId: uuidCheck,
- subsessionId: uuidCheck,
- // Special cases: previousSessionId and previousSubsessionId are null on first run.
- previousSessionId: (arg) => { return (arg) ? uuidCheck(arg) : true; },
- previousSubsessionId: (arg) => { return (arg) ? uuidCheck(arg) : true; },
- subsessionCounter: positiveNumberCheck,
- profileSubsessionCounter: positiveNumberCheck,
- sessionStartDate: isoDateCheck,
- subsessionStartDate: isoDateCheck,
- subsessionLength: positiveNumberCheck,
- };
-
- for (let f in EXPECTED_INFO_FIELDS_TYPES) {
- Assert.ok(f in data, f + " must be available.");
-
- let checkFunc = EXPECTED_INFO_FIELDS_TYPES[f];
- Assert.ok(checkFunc(data[f]),
- f + " must have the correct type and valid data " + data[f]);
- }
-
- // Previous buildId is not mandatory.
- if (data.previousBuildId) {
- Assert.ok(stringCheck(data.previousBuildId));
- }
-
- Assert.ok(ALLOWED_REASONS.find(r => r == data.reason),
- "Payload must contain an allowed reason.");
-
- Assert.ok(Date.parse(data.subsessionStartDate) >= Date.parse(data.sessionStartDate));
- Assert.ok(data.profileSubsessionCounter >= data.subsessionCounter);
- Assert.ok(data.timezoneOffset >= -12*60, "The timezone must be in a valid range.");
- Assert.ok(data.timezoneOffset <= 12*60, "The timezone must be in a valid range.");
-}
-
-function checkScalars(processes) {
- // Check that the scalars section is available in the ping payload.
- const parentProcess = processes.parent;
- Assert.ok("scalars" in parentProcess, "The scalars section must be available in the parent process.");
- Assert.ok("keyedScalars" in parentProcess, "The keyedScalars section must be available in the parent process.");
- Assert.equal(typeof parentProcess.scalars, "object", "The scalars entry must be an object.");
- Assert.equal(typeof parentProcess.keyedScalars, "object", "The keyedScalars entry must be an object.");
-
- let checkScalar = function(scalar) {
- // Check if the value is of a supported type.
- const valueType = typeof(scalar);
- switch (valueType) {
- case "string":
- Assert.ok(scalar.length <= 50,
- "String values can't have more than 50 characters");
- break;
- case "number":
- Assert.ok(scalar >= 0,
- "We only support unsigned integer values in scalars.");
- break;
- case "boolean":
- Assert.ok(true,
- "Boolean scalar found.");
- break;
- default:
- Assert.ok(false,
- name + " contains an unsupported value type (" + valueType + ")");
- }
- }
-
- // Check that we have valid scalar entries.
- const scalars = parentProcess.scalars;
- for (let name in scalars) {
- Assert.equal(typeof name, "string", "Scalar names must be strings.");
- checkScalar(scalar[name]);
- }
-
- // Check that we have valid keyed scalar entries.
- const keyedScalars = parentProcess.keyedScalars;
- for (let name in keyedScalars) {
- Assert.equal(typeof name, "string", "Scalar names must be strings.");
- Assert.ok(Object.keys(keyedScalars[name]).length,
- "The reported keyed scalars must contain at least 1 key.");
- for (let key in keyedScalars[name]) {
- Assert.equal(typeof key, "string", "Keyed scalar keys must be strings.");
- Assert.ok(key.length <= 70, "Keyed scalar keys can't have more than 70 characters.");
- checkScalar(scalar[name][key]);
- }
- }
-}
-
-function checkEvents(processes) {
- // Check that the events section is available in the ping payload.
- const parent = processes.parent;
- Assert.ok("events" in parent, "The events section must be available in the parent process.");
-
- // Check that the events section has the right format.
- Assert.ok(Array.isArray(parent.events), "The events entry must be an array.");
- for (let [ts, category, method, object, value, extra] of parent.events) {
- Assert.equal(typeof(ts), "number", "Timestamp field should be a number.");
- Assert.greaterOrEqual(ts, 0, "Timestamp should be >= 0.");
-
- Assert.equal(typeof(category), "string", "Category should have the right type.");
- Assert.lessOrEqual(category.length, 100, "Category should have the right string length.");
-
- Assert.equal(typeof(method), "string", "Method should have the right type.");
- Assert.lessOrEqual(method.length, 40, "Method should have the right string length.");
-
- Assert.equal(typeof(object), "string", "Object should have the right type.");
- Assert.lessOrEqual(object.length, 40, "Object should have the right string length.");
-
- Assert.ok(value === null || typeof(value) === "string",
- "Value should be null or a string.");
- if (value) {
- Assert.lessOrEqual(value.length, 100, "Value should have the right string length.");
- }
-
- Assert.ok(extra === null || typeof(extra) === "object",
- "Extra should be null or an object.");
- if (extra) {
- let keys = Object.keys(extra);
- let keyTypes = keys.map(k => typeof(k));
- Assert.lessOrEqual(keys.length, 20, "Should not have too many extra keys.");
- Assert.ok(keyTypes.every(t => t === "string"),
- "All extra keys should be strings.");
- Assert.ok(keys.every(k => k.length <= 20),
- "All extra keys should have the right string length.");
-
- let values = Object.values(extra);
- let valueTypes = values.map(v => typeof(v));
- Assert.ok(valueTypes.every(t => t === "string"),
- "All extra values should be strings.");
- Assert.ok(values.every(v => v.length <= 100),
- "All extra values should have the right string length.");
- }
- }
-}
-
-function checkPayload(payload, reason, successfulPings, savedPings) {
- Assert.ok("info" in payload, "Payload must contain an info section.");
- checkPayloadInfo(payload.info);
-
- Assert.ok(payload.simpleMeasurements.totalTime >= 0);
- Assert.ok(payload.simpleMeasurements.uptime >= 0);
- Assert.equal(payload.simpleMeasurements.startupInterrupted, 1);
- Assert.equal(payload.simpleMeasurements.shutdownDuration, SHUTDOWN_TIME);
- Assert.equal(payload.simpleMeasurements.savedPings, savedPings);
- Assert.ok("maximalNumberOfConcurrentThreads" in payload.simpleMeasurements);
- Assert.ok(payload.simpleMeasurements.maximalNumberOfConcurrentThreads >= gNumberOfThreadsLaunched);
-
- let activeTicks = payload.simpleMeasurements.activeTicks;
- Assert.ok(activeTicks >= 0);
-
- Assert.equal(payload.simpleMeasurements.failedProfileLockCount,
- FAILED_PROFILE_LOCK_ATTEMPTS);
- let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
- let failedProfileLocksFile = profileDirectory.clone();
- failedProfileLocksFile.append("Telemetry.FailedProfileLocks.txt");
- Assert.ok(!failedProfileLocksFile.exists());
-
-
- let isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
- if (isWindows) {
- Assert.ok(payload.simpleMeasurements.startupSessionRestoreReadBytes > 0);
- Assert.ok(payload.simpleMeasurements.startupSessionRestoreWriteBytes > 0);
- }
-
- const TELEMETRY_SEND_SUCCESS = "TELEMETRY_SEND_SUCCESS";
- const TELEMETRY_SUCCESS = "TELEMETRY_SUCCESS";
- const TELEMETRY_TEST_FLAG = "TELEMETRY_TEST_FLAG";
- const TELEMETRY_TEST_COUNT = "TELEMETRY_TEST_COUNT";
- const TELEMETRY_TEST_KEYED_FLAG = "TELEMETRY_TEST_KEYED_FLAG";
- const TELEMETRY_TEST_KEYED_COUNT = "TELEMETRY_TEST_KEYED_COUNT";
-
- if (successfulPings > 0) {
- Assert.ok(TELEMETRY_SEND_SUCCESS in payload.histograms);
- }
- Assert.ok(TELEMETRY_TEST_FLAG in payload.histograms);
- Assert.ok(TELEMETRY_TEST_COUNT in payload.histograms);
-
- Assert.ok(!(IGNORE_CLONED_HISTOGRAM in payload.histograms));
-
- // Flag histograms should automagically spring to life.
- const expected_flag = {
- range: [1, 2],
- bucket_count: 3,
- histogram_type: 3,
- values: {0:1, 1:0},
- sum: 0
- };
- let flag = payload.histograms[TELEMETRY_TEST_FLAG];
- Assert.equal(uneval(flag), uneval(expected_flag));
-
- // We should have a test count.
- const expected_count = {
- range: [1, 2],
- bucket_count: 3,
- histogram_type: 4,
- values: {0:1, 1:0},
- sum: 1,
- };
- let count = payload.histograms[TELEMETRY_TEST_COUNT];
- Assert.equal(uneval(count), uneval(expected_count));
-
- // There should be one successful report from the previous telemetry ping.
- if (successfulPings > 0) {
- const expected_tc = {
- range: [1, 2],
- bucket_count: 3,
- histogram_type: 2,
- values: {0:2, 1:successfulPings, 2:0},
- sum: successfulPings
- };
- let tc = payload.histograms[TELEMETRY_SUCCESS];
- Assert.equal(uneval(tc), uneval(expected_tc));
- }
-
- // The ping should include data from memory reporters. We can't check that
- // this data is correct, because we can't control the values returned by the
- // memory reporters. But we can at least check that the data is there.
- //
- // It's important to check for the presence of reporters with a mix of units,
- // because TelemetryController has separate logic for each one. But we can't
- // currently check UNITS_COUNT_CUMULATIVE or UNITS_PERCENTAGE because
- // Telemetry doesn't touch a memory reporter with these units that's
- // available on all platforms.
-
- Assert.ok('MEMORY_JS_GC_HEAP' in payload.histograms); // UNITS_BYTES
- Assert.ok('MEMORY_JS_COMPARTMENTS_SYSTEM' in payload.histograms); // UNITS_COUNT
-
- // We should have included addon histograms.
- Assert.ok("addonHistograms" in payload);
- Assert.ok(ADDON_NAME in payload.addonHistograms);
- Assert.ok(ADDON_HISTOGRAM in payload.addonHistograms[ADDON_NAME]);
-
- Assert.ok(("mainThread" in payload.slowSQL) &&
- ("otherThreads" in payload.slowSQL));
-
- Assert.ok(("IceCandidatesStats" in payload.webrtc) &&
- ("webrtc" in payload.webrtc.IceCandidatesStats));
-
- // Check keyed histogram payload.
-
- Assert.ok("keyedHistograms" in payload);
- let keyedHistograms = payload.keyedHistograms;
- Assert.ok(!(TELEMETRY_TEST_KEYED_FLAG in keyedHistograms));
- Assert.ok(TELEMETRY_TEST_KEYED_COUNT in keyedHistograms);
-
- const expected_keyed_count = {
- "a": {
- range: [1, 2],
- bucket_count: 3,
- histogram_type: 4,
- values: {0:2, 1:0},
- sum: 2,
- },
- "b": {
- range: [1, 2],
- bucket_count: 3,
- histogram_type: 4,
- values: {0:1, 1:0},
- sum: 1,
- },
- };
- Assert.deepEqual(expected_keyed_count, keyedHistograms[TELEMETRY_TEST_KEYED_COUNT]);
-
- Assert.ok("processes" in payload, "The payload must have a processes section.");
- Assert.ok("parent" in payload.processes, "There must be at least a parent process.");
- checkScalars(payload.processes);
- checkEvents(payload.processes);
-}
-
-function writeStringToFile(file, contents) {
- let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"]
- .createInstance(Ci.nsIFileOutputStream);
- ostream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
- RW_OWNER, ostream.DEFER_OPEN);
- ostream.write(contents, contents.length);
- ostream.QueryInterface(Ci.nsISafeOutputStream).finish();
- ostream.close();
-}
-
-function write_fake_shutdown_file() {
- let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
- let file = profileDirectory.clone();
- file.append("Telemetry.ShutdownTime.txt");
- let contents = "" + SHUTDOWN_TIME;
- writeStringToFile(file, contents);
-}
-
-function write_fake_failedprofilelocks_file() {
- let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
- let file = profileDirectory.clone();
- file.append("Telemetry.FailedProfileLocks.txt");
- let contents = "" + FAILED_PROFILE_LOCK_ATTEMPTS;
- writeStringToFile(file, contents);
-}
-
-add_task(function* test_setup() {
- // Addon manager needs a profile directory
- do_get_profile();
- loadAddonManager(APP_ID, APP_NAME, APP_VERSION, PLATFORM_VERSION);
- // Make sure we don't generate unexpected pings due to pref changes.
- yield setEmptyPrefWatchlist();
-
- Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
- Services.prefs.setBoolPref(PREF_FHR_UPLOAD_ENABLED, true);
-
- // Make it look like we've previously failed to lock a profile a couple times.
- write_fake_failedprofilelocks_file();
-
- // Make it look like we've shutdown before.
- write_fake_shutdown_file();
-
- let currentMaxNumberOfThreads = Telemetry.maximalNumberOfConcurrentThreads;
- do_check_true(currentMaxNumberOfThreads > 0);
-
- // Try to augment the maximal number of threads currently launched
- let threads = [];
- try {
- for (let i = 0; i < currentMaxNumberOfThreads + 10; ++i) {
- threads.push(Services.tm.newThread(0));
- }
- } catch (ex) {
- // If memory is too low, it is possible that not all threads will be launched.
- }
- gNumberOfThreadsLaunched = threads.length;
-
- do_check_true(Telemetry.maximalNumberOfConcurrentThreads >= gNumberOfThreadsLaunched);
-
- do_register_cleanup(function() {
- threads.forEach(function(thread) {
- thread.shutdown();
- });
- });
-
- yield new Promise(resolve =>
- Telemetry.asyncFetchTelemetryData(wrapWithExceptionHandler(resolve)));
-});
-
-add_task(function* asyncSetup() {
- yield TelemetryController.testSetup();
- // Load the client ID from the client ID provider to check for pings sanity.
- gClientID = yield ClientID.getClientID();
-});
-
-// Ensures that expired histograms are not part of the payload.
-add_task(function* test_expiredHistogram() {
-
- let dummy = Telemetry.getHistogramById("TELEMETRY_TEST_EXPIRED");
-
- dummy.add(1);
-
- do_check_eq(TelemetrySession.getPayload()["histograms"]["TELEMETRY_TEST_EXPIRED"], undefined);
-});
-
-// Sends a ping to a non existing server. If we remove this test, we won't get
-// all the histograms we need in the main ping.
-add_task(function* test_noServerPing() {
- yield sendPing();
- // We need two pings in order to make sure STARTUP_MEMORY_STORAGE_SQLIE histograms
- // are initialised. See bug 1131585.
- yield sendPing();
- // Allowing Telemetry to persist unsent pings as pending. If omitted may cause
- // problems to the consequent tests.
- yield TelemetryController.testShutdown();
-});
-
-// Checks that a sent ping is correctly received by a dummy http server.
-add_task(function* test_simplePing() {
- yield TelemetryStorage.testClearPendingPings();
- PingServer.start();
- Preferences.set(PREF_SERVER, "http://localhost:" + PingServer.port);
-
- let now = new Date(2020, 1, 1, 12, 0, 0);
- let expectedDate = new Date(2020, 1, 1, 0, 0, 0);
- fakeNow(now);
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 5000);
-
- const expectedSessionUUID = "bd314d15-95bf-4356-b682-b6c4a8942202";
- const expectedSubsessionUUID = "3e2e5f6c-74ba-4e4d-a93f-a48af238a8c7";
- fakeGenerateUUID(() => expectedSessionUUID, () => expectedSubsessionUUID);
- yield TelemetryController.testReset();
-
- // Session and subsession start dates are faked during TelemetrySession setup. We can
- // now fake the session duration.
- const SESSION_DURATION_IN_MINUTES = 15;
- fakeNow(new Date(2020, 1, 1, 12, SESSION_DURATION_IN_MINUTES, 0));
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + SESSION_DURATION_IN_MINUTES * 60 * 1000);
-
- yield sendPing();
- let ping = yield PingServer.promiseNextPing();
-
- checkPingFormat(ping, PING_TYPE_MAIN, true, true);
-
- // Check that we get the data we expect.
- let payload = ping.payload;
- Assert.equal(payload.info.sessionId, expectedSessionUUID);
- Assert.equal(payload.info.subsessionId, expectedSubsessionUUID);
- let sessionStartDate = new Date(payload.info.sessionStartDate);
- Assert.equal(sessionStartDate.toISOString(), expectedDate.toISOString());
- let subsessionStartDate = new Date(payload.info.subsessionStartDate);
- Assert.equal(subsessionStartDate.toISOString(), expectedDate.toISOString());
- Assert.equal(payload.info.subsessionLength, SESSION_DURATION_IN_MINUTES * 60);
-
- // Restore the UUID generator so we don't mess with other tests.
- fakeGenerateUUID(generateUUID, generateUUID);
-});
-
-// Saves the current session histograms, reloads them, performs a ping
-// and checks that the dummy http server received both the previously
-// saved ping and the new one.
-add_task(function* test_saveLoadPing() {
- // Let's start out with a defined state.
- yield TelemetryStorage.testClearPendingPings();
- yield TelemetryController.testReset();
- PingServer.clearRequests();
-
- // Setup test data and trigger pings.
- setupTestData();
- yield TelemetrySession.testSavePendingPing();
- yield sendPing();
-
- // Get requests received by dummy server.
- const requests = yield PingServer.promiseNextRequests(2);
-
- for (let req of requests) {
- Assert.equal(req.getHeader("content-type"), "application/json; charset=UTF-8",
- "The request must have the correct content-type.");
- }
-
- // We decode both requests to check for the |reason|.
- let pings = Array.from(requests, decodeRequestPayload);
-
- // Check we have the correct two requests. Ordering is not guaranteed. The ping type
- // is encoded in the URL.
- if (pings[0].type != PING_TYPE_MAIN) {
- pings.reverse();
- }
-
- checkPingFormat(pings[0], PING_TYPE_MAIN, true, true);
- checkPayload(pings[0].payload, REASON_TEST_PING, 0, 1);
- checkPingFormat(pings[1], PING_TYPE_SAVED_SESSION, true, true);
- checkPayload(pings[1].payload, REASON_SAVED_SESSION, 0, 0);
-});
-
-add_task(function* test_checkSubsessionScalars() {
- if (gIsAndroid) {
- // We don't support subsessions yet on Android.
- return;
- }
-
- // Clear the scalars.
- Telemetry.clearScalars();
- yield TelemetryController.testReset();
-
- // Set some scalars.
- const UINT_SCALAR = "telemetry.test.unsigned_int_kind";
- const STRING_SCALAR = "telemetry.test.string_kind";
- let expectedUint = 37;
- let expectedString = "Test value. Yay.";
- Telemetry.scalarSet(UINT_SCALAR, expectedUint);
- Telemetry.scalarSet(STRING_SCALAR, expectedString);
-
- // Check that scalars are not available in classic pings but are in subsession
- // pings. Also clear the subsession.
- let classic = TelemetrySession.getPayload();
- let subsession = TelemetrySession.getPayload("environment-change", true);
-
- const TEST_SCALARS = [ UINT_SCALAR, STRING_SCALAR ];
- for (let name of TEST_SCALARS) {
- // Scalar must be reported in subsession pings (e.g. main).
- Assert.ok(name in subsession.processes.parent.scalars,
- name + " must be reported in a subsession ping.");
- }
- // No scalar must be reported in classic pings (e.g. saved-session).
- Assert.ok(Object.keys(classic.processes.parent.scalars).length == 0,
- "Scalars must not be reported in a classic ping.");
-
- // And make sure that we're getting the right values in the
- // subsession ping.
- Assert.equal(subsession.processes.parent.scalars[UINT_SCALAR], expectedUint,
- UINT_SCALAR + " must contain the expected value.");
- Assert.equal(subsession.processes.parent.scalars[STRING_SCALAR], expectedString,
- STRING_SCALAR + " must contain the expected value.");
-
- // Since we cleared the subsession in the last getPayload(), check that
- // breaking subsessions clears the scalars.
- subsession = TelemetrySession.getPayload("environment-change");
- for (let name of TEST_SCALARS) {
- Assert.ok(!(name in subsession.processes.parent.scalars),
- name + " must be cleared with the new subsession.");
- }
-
- // Check if setting the scalars again works as expected.
- expectedUint = 85;
- expectedString = "A creative different value";
- Telemetry.scalarSet(UINT_SCALAR, expectedUint);
- Telemetry.scalarSet(STRING_SCALAR, expectedString);
- subsession = TelemetrySession.getPayload("environment-change");
- Assert.equal(subsession.processes.parent.scalars[UINT_SCALAR], expectedUint,
- UINT_SCALAR + " must contain the expected value.");
- Assert.equal(subsession.processes.parent.scalars[STRING_SCALAR], expectedString,
- STRING_SCALAR + " must contain the expected value.");
-});
-
-add_task(function* test_checkSubsessionEvents() {
- if (gIsAndroid) {
- // We don't support subsessions yet on Android.
- return;
- }
-
- // Clear the events.
- Telemetry.clearEvents();
- yield TelemetryController.testReset();
-
- // Record some events.
- let expected = [
- ["telemetry.test", "test1", "object1", "a", null],
- ["telemetry.test", "test1", "object1", null, {key1: "value"}],
- ];
- for (let event of expected) {
- Telemetry.recordEvent(...event);
- }
-
- // Strip off trailing null values to match the serialized events.
- for (let e of expected) {
- while ((e.length >= 3) && (e[e.length - 1] === null)) {
- e.pop();
- }
- }
-
- // Check that events are not available in classic pings but are in subsession
- // pings. Also clear the subsession.
- let classic = TelemetrySession.getPayload();
- let subsession = TelemetrySession.getPayload("environment-change", true);
-
- Assert.ok("events" in classic.processes.parent, "Should have an events field in classic payload.");
- Assert.ok("events" in subsession.processes.parent, "Should have an events field in subsession payload.");
-
- // They should be empty in the classic payload.
- Assert.deepEqual(classic.processes.parent.events, [], "Events in classic payload should be empty.");
-
- // In the subsession payload, they should contain the recorded test events.
- let events = subsession.processes.parent.events.filter(e => e[1] === "telemetry.test");
- Assert.equal(events.length, expected.length, "Should have the right amount of events in the payload.");
- for (let i = 0; i < expected.length; ++i) {
- Assert.deepEqual(events[i].slice(1), expected[i],
- "Should have the right event data in the ping.");
- }
-
- // As we cleared the subsession above, the events entry should now be empty.
- subsession = TelemetrySession.getPayload("environment-change", false);
- Assert.ok("events" in subsession.processes.parent, "Should have an events field in subsession payload.");
- events = subsession.processes.parent.events.filter(e => e[1] === "telemetry.test");
- Assert.equal(events.length, 0, "Should have no test events in the subsession payload now.");
-});
-
-add_task(function* test_checkSubsessionHistograms() {
- if (gIsAndroid) {
- // We don't support subsessions yet on Android.
- return;
- }
-
- let now = new Date(2020, 1, 1, 12, 0, 0);
- let expectedDate = new Date(2020, 1, 1, 0, 0, 0);
- fakeNow(now);
- yield TelemetryController.testReset();
-
- const COUNT_ID = "TELEMETRY_TEST_COUNT";
- const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
- const count = Telemetry.getHistogramById(COUNT_ID);
- const keyed = Telemetry.getKeyedHistogramById(KEYED_ID);
- const registeredIds =
- new Set(Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []));
-
- const stableHistograms = new Set([
- "TELEMETRY_TEST_FLAG",
- "TELEMETRY_TEST_COUNT",
- "TELEMETRY_TEST_RELEASE_OPTOUT",
- "TELEMETRY_TEST_RELEASE_OPTIN",
- "STARTUP_CRASH_DETECTED",
- ]);
-
- const stableKeyedHistograms = new Set([
- "TELEMETRY_TEST_KEYED_FLAG",
- "TELEMETRY_TEST_KEYED_COUNT",
- "TELEMETRY_TEST_KEYED_RELEASE_OPTIN",
- "TELEMETRY_TEST_KEYED_RELEASE_OPTOUT",
- ]);
-
- // Compare the two sets of histograms.
- // The "subsession" histograms should match the registered
- // "classic" histograms. However, histograms can change
- // between us collecting the different payloads, so we only
- // check for deep equality on known stable histograms.
- checkHistograms = (classic, subsession) => {
- for (let id of Object.keys(classic)) {
- if (!registeredIds.has(id)) {
- continue;
- }
-
- Assert.ok(id in subsession);
- if (stableHistograms.has(id)) {
- Assert.deepEqual(classic[id],
- subsession[id]);
- } else {
- Assert.equal(classic[id].histogram_type,
- subsession[id].histogram_type);
- }
- }
- };
-
- // Same as above, except for keyed histograms.
- checkKeyedHistograms = (classic, subsession) => {
- for (let id of Object.keys(classic)) {
- if (!registeredIds.has(id)) {
- continue;
- }
-
- Assert.ok(id in subsession);
- if (stableKeyedHistograms.has(id)) {
- Assert.deepEqual(classic[id],
- subsession[id]);
- }
- }
- };
-
- // Both classic and subsession payload histograms should start the same.
- // The payloads should be identical for now except for the reason.
- count.clear();
- keyed.clear();
- let classic = TelemetrySession.getPayload();
- let subsession = TelemetrySession.getPayload("environment-change");
-
- Assert.equal(classic.info.reason, "gather-payload");
- Assert.equal(subsession.info.reason, "environment-change");
- Assert.ok(!(COUNT_ID in classic.histograms));
- Assert.ok(!(COUNT_ID in subsession.histograms));
- Assert.ok(!(KEYED_ID in classic.keyedHistograms));
- Assert.ok(!(KEYED_ID in subsession.keyedHistograms));
-
- checkHistograms(classic.histograms, subsession.histograms);
- checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
-
- // Adding values should get picked up in both.
- count.add(1);
- keyed.add("a", 1);
- keyed.add("b", 1);
- classic = TelemetrySession.getPayload();
- subsession = TelemetrySession.getPayload("environment-change");
-
- Assert.ok(COUNT_ID in classic.histograms);
- Assert.ok(COUNT_ID in subsession.histograms);
- Assert.ok(KEYED_ID in classic.keyedHistograms);
- Assert.ok(KEYED_ID in subsession.keyedHistograms);
- Assert.equal(classic.histograms[COUNT_ID].sum, 1);
- Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 1);
- Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 1);
-
- checkHistograms(classic.histograms, subsession.histograms);
- checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
-
- // Values should still reset properly.
- count.clear();
- keyed.clear();
- classic = TelemetrySession.getPayload();
- subsession = TelemetrySession.getPayload("environment-change");
-
- Assert.ok(!(COUNT_ID in classic.histograms));
- Assert.ok(!(COUNT_ID in subsession.histograms));
- Assert.ok(!(KEYED_ID in classic.keyedHistograms));
- Assert.ok(!(KEYED_ID in subsession.keyedHistograms));
-
- checkHistograms(classic.histograms, subsession.histograms);
- checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
-
- // Adding values should get picked up in both.
- count.add(1);
- keyed.add("a", 1);
- keyed.add("b", 1);
- classic = TelemetrySession.getPayload();
- subsession = TelemetrySession.getPayload("environment-change");
-
- Assert.ok(COUNT_ID in classic.histograms);
- Assert.ok(COUNT_ID in subsession.histograms);
- Assert.ok(KEYED_ID in classic.keyedHistograms);
- Assert.ok(KEYED_ID in subsession.keyedHistograms);
- Assert.equal(classic.histograms[COUNT_ID].sum, 1);
- Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 1);
- Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 1);
-
- checkHistograms(classic.histograms, subsession.histograms);
- checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
-
- // We should be able to reset only the subsession histograms.
- // First check that "snapshot and clear" still returns the old state...
- classic = TelemetrySession.getPayload();
- subsession = TelemetrySession.getPayload("environment-change", true);
-
- let subsessionStartDate = new Date(classic.info.subsessionStartDate);
- Assert.equal(subsessionStartDate.toISOString(), expectedDate.toISOString());
- subsessionStartDate = new Date(subsession.info.subsessionStartDate);
- Assert.equal(subsessionStartDate.toISOString(), expectedDate.toISOString());
- checkHistograms(classic.histograms, subsession.histograms);
- checkKeyedHistograms(classic.keyedHistograms, subsession.keyedHistograms);
-
- // ... then check that the next snapshot shows the subsession
- // histograms got reset.
- classic = TelemetrySession.getPayload();
- subsession = TelemetrySession.getPayload("environment-change");
-
- Assert.ok(COUNT_ID in classic.histograms);
- Assert.ok(COUNT_ID in subsession.histograms);
- Assert.equal(classic.histograms[COUNT_ID].sum, 1);
- Assert.equal(subsession.histograms[COUNT_ID].sum, 0);
-
- Assert.ok(KEYED_ID in classic.keyedHistograms);
- Assert.ok(!(KEYED_ID in subsession.keyedHistograms));
- Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 1);
- Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 1);
-
- // Adding values should get picked up in both again.
- count.add(1);
- keyed.add("a", 1);
- keyed.add("b", 1);
- classic = TelemetrySession.getPayload();
- subsession = TelemetrySession.getPayload("environment-change");
-
- Assert.ok(COUNT_ID in classic.histograms);
- Assert.ok(COUNT_ID in subsession.histograms);
- Assert.equal(classic.histograms[COUNT_ID].sum, 2);
- Assert.equal(subsession.histograms[COUNT_ID].sum, 1);
-
- Assert.ok(KEYED_ID in classic.keyedHistograms);
- Assert.ok(KEYED_ID in subsession.keyedHistograms);
- Assert.equal(classic.keyedHistograms[KEYED_ID]["a"].sum, 2);
- Assert.equal(classic.keyedHistograms[KEYED_ID]["b"].sum, 2);
- Assert.equal(subsession.keyedHistograms[KEYED_ID]["a"].sum, 1);
- Assert.equal(subsession.keyedHistograms[KEYED_ID]["b"].sum, 1);
-});
-
-add_task(function* test_checkSubsessionData() {
- if (gIsAndroid) {
- // We don't support subsessions yet on Android.
- return;
- }
-
- // Keep track of the active ticks count if the session recorder is available.
- let sessionRecorder = TelemetryController.getSessionRecorder();
- let activeTicksAtSubsessionStart = sessionRecorder.activeTicks;
- let expectedActiveTicks = activeTicksAtSubsessionStart;
-
- incrementActiveTicks = () => {
- sessionRecorder.incrementActiveTicks();
- ++expectedActiveTicks;
- }
-
- yield TelemetryController.testReset();
-
- // Both classic and subsession payload data should be the same on the first subsession.
- incrementActiveTicks();
- let classic = TelemetrySession.getPayload();
- let subsession = TelemetrySession.getPayload("environment-change");
- Assert.equal(classic.simpleMeasurements.activeTicks, expectedActiveTicks,
- "Classic pings must count active ticks since the beginning of the session.");
- Assert.equal(subsession.simpleMeasurements.activeTicks, expectedActiveTicks,
- "Subsessions must count active ticks as classic pings on the first subsession.");
-
- // Start a new subsession and check that the active ticks are correctly reported.
- incrementActiveTicks();
- activeTicksAtSubsessionStart = sessionRecorder.activeTicks;
- classic = TelemetrySession.getPayload();
- subsession = TelemetrySession.getPayload("environment-change", true);
- Assert.equal(classic.simpleMeasurements.activeTicks, expectedActiveTicks,
- "Classic pings must count active ticks since the beginning of the session.");
- Assert.equal(subsession.simpleMeasurements.activeTicks, expectedActiveTicks,
- "Pings must not loose the tick count when starting a new subsession.");
-
- // Get a new subsession payload without clearing the subsession.
- incrementActiveTicks();
- classic = TelemetrySession.getPayload();
- subsession = TelemetrySession.getPayload("environment-change");
- Assert.equal(classic.simpleMeasurements.activeTicks, expectedActiveTicks,
- "Classic pings must count active ticks since the beginning of the session.");
- Assert.equal(subsession.simpleMeasurements.activeTicks,
- expectedActiveTicks - activeTicksAtSubsessionStart,
- "Subsessions must count active ticks since the last new subsession.");
-});
-
-add_task(function* test_dailyCollection() {
- if (gIsAndroid) {
- // We don't do daily collections yet on Android.
- return;
- }
-
- let now = new Date(2030, 1, 1, 12, 0, 0);
- let nowDay = new Date(2030, 1, 1, 0, 0, 0);
- let schedulerTickCallback = null;
-
- PingServer.clearRequests();
-
- fakeNow(now);
-
- // Fake scheduler functions to control daily collection flow in tests.
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
-
- // Init and check timer.
- yield TelemetryStorage.testClearPendingPings();
- yield TelemetryController.testSetup();
- TelemetrySend.setServer("http://localhost:" + PingServer.port);
-
- // Set histograms to expected state.
- const COUNT_ID = "TELEMETRY_TEST_COUNT";
- const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
- const count = Telemetry.getHistogramById(COUNT_ID);
- const keyed = Telemetry.getKeyedHistogramById(KEYED_ID);
-
- count.clear();
- keyed.clear();
- count.add(1);
- keyed.add("a", 1);
- keyed.add("b", 1);
- keyed.add("b", 1);
-
- // Make sure the daily ping gets triggered.
- let expectedDate = nowDay;
- now = futureDate(nowDay, MS_IN_ONE_DAY);
- fakeNow(now);
-
- Assert.ok(!!schedulerTickCallback);
- // Run a scheduler tick: it should trigger the daily ping.
- yield schedulerTickCallback();
-
- // Collect the daily ping.
- let ping = yield PingServer.promiseNextPing();
- Assert.ok(!!ping);
-
- Assert.equal(ping.type, PING_TYPE_MAIN);
- Assert.equal(ping.payload.info.reason, REASON_DAILY);
- let subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
- Assert.equal(subsessionStartDate.toISOString(), expectedDate.toISOString());
-
- Assert.equal(ping.payload.histograms[COUNT_ID].sum, 1);
- Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["a"].sum, 1);
- Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["b"].sum, 2);
-
- // The daily ping is rescheduled for "tomorrow".
- expectedDate = futureDate(expectedDate, MS_IN_ONE_DAY);
- now = futureDate(now, MS_IN_ONE_DAY);
- fakeNow(now);
-
- // Run a scheduler tick. Trigger and collect another ping. The histograms should be reset.
- yield schedulerTickCallback();
-
- ping = yield PingServer.promiseNextPing();
- Assert.ok(!!ping);
-
- Assert.equal(ping.type, PING_TYPE_MAIN);
- Assert.equal(ping.payload.info.reason, REASON_DAILY);
- subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
- Assert.equal(subsessionStartDate.toISOString(), expectedDate.toISOString());
-
- Assert.equal(ping.payload.histograms[COUNT_ID].sum, 0);
- Assert.ok(!(KEYED_ID in ping.payload.keyedHistograms));
-
- // Trigger and collect another daily ping, with the histograms being set again.
- count.add(1);
- keyed.add("a", 1);
- keyed.add("b", 1);
-
- // The daily ping is rescheduled for "tomorrow".
- expectedDate = futureDate(expectedDate, MS_IN_ONE_DAY);
- now = futureDate(now, MS_IN_ONE_DAY);
- fakeNow(now);
-
- yield schedulerTickCallback();
- ping = yield PingServer.promiseNextPing();
- Assert.ok(!!ping);
-
- Assert.equal(ping.type, PING_TYPE_MAIN);
- Assert.equal(ping.payload.info.reason, REASON_DAILY);
- subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
- Assert.equal(subsessionStartDate.toISOString(), expectedDate.toISOString());
-
- Assert.equal(ping.payload.histograms[COUNT_ID].sum, 1);
- Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["a"].sum, 1);
- Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["b"].sum, 1);
-
- // Shutdown to cleanup the aborted-session if it gets created.
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_dailyDuplication() {
- if (gIsAndroid) {
- // We don't do daily collections yet on Android.
- return;
- }
-
- yield TelemetrySend.reset();
- yield TelemetryStorage.testClearPendingPings();
- PingServer.clearRequests();
-
- let schedulerTickCallback = null;
- let now = new Date(2030, 1, 1, 0, 0, 0);
- fakeNow(now);
- // Fake scheduler functions to control daily collection flow in tests.
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryController.testReset();
-
- // Make sure the daily ping gets triggered at midnight.
- // We need to make sure that we trigger this after the period where we wait for
- // the user to become idle.
- let firstDailyDue = new Date(2030, 1, 2, 0, 0, 0);
- fakeNow(firstDailyDue);
-
- // Run a scheduler tick: it should trigger the daily ping.
- Assert.ok(!!schedulerTickCallback);
- yield schedulerTickCallback();
-
- // Get the first daily ping.
- let ping = yield PingServer.promiseNextPing();
- Assert.ok(!!ping);
-
- Assert.equal(ping.type, PING_TYPE_MAIN);
- Assert.equal(ping.payload.info.reason, REASON_DAILY);
-
- // We don't expect to receive any other daily ping in this test, so assert if we do.
- PingServer.registerPingHandler((req, res) => {
- Assert.ok(false, "No more daily pings should be sent/received in this test.");
- });
-
- // Set the current time to a bit after midnight.
- let secondDailyDue = new Date(firstDailyDue);
- secondDailyDue.setHours(0);
- secondDailyDue.setMinutes(15);
- fakeNow(secondDailyDue);
-
- // Run a scheduler tick: it should NOT trigger the daily ping.
- Assert.ok(!!schedulerTickCallback);
- yield schedulerTickCallback();
-
- // Shutdown to cleanup the aborted-session if it gets created.
- PingServer.resetPingHandler();
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_dailyOverdue() {
- if (gIsAndroid) {
- // We don't do daily collections yet on Android.
- return;
- }
-
- let schedulerTickCallback = null;
- let now = new Date(2030, 1, 1, 11, 0, 0);
- fakeNow(now);
- // Fake scheduler functions to control daily collection flow in tests.
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryStorage.testClearPendingPings();
- yield TelemetryController.testReset();
-
- // Skip one hour ahead: nothing should be due.
- now.setHours(now.getHours() + 1);
- fakeNow(now);
-
- // Assert if we receive something!
- PingServer.registerPingHandler((req, res) => {
- Assert.ok(false, "No daily ping should be received if not overdue!.");
- });
-
- // This tick should not trigger any daily ping.
- Assert.ok(!!schedulerTickCallback);
- yield schedulerTickCallback();
-
- // Restore the non asserting ping handler.
- PingServer.resetPingHandler();
- PingServer.clearRequests();
-
- // Simulate an overdue ping: we're not close to midnight, but the last daily ping
- // time is too long ago.
- let dailyOverdue = new Date(2030, 1, 2, 13, 0, 0);
- fakeNow(dailyOverdue);
-
- // Run a scheduler tick: it should trigger the daily ping.
- Assert.ok(!!schedulerTickCallback);
- yield schedulerTickCallback();
-
- // Get the first daily ping.
- let ping = yield PingServer.promiseNextPing();
- Assert.ok(!!ping);
-
- Assert.equal(ping.type, PING_TYPE_MAIN);
- Assert.equal(ping.payload.info.reason, REASON_DAILY);
-
- // Shutdown to cleanup the aborted-session if it gets created.
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_environmentChange() {
- if (gIsAndroid) {
- // We don't split subsessions on environment changes yet on Android.
- return;
- }
-
- yield TelemetryStorage.testClearPendingPings();
- PingServer.clearRequests();
-
- let now = fakeNow(2040, 1, 1, 12, 0, 0);
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
-
- const PREF_TEST = "toolkit.telemetry.test.pref1";
- Preferences.reset(PREF_TEST);
-
- const PREFS_TO_WATCH = new Map([
- [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
- ]);
-
- // Setup.
- yield TelemetryController.testReset();
- TelemetrySend.setServer("http://localhost:" + PingServer.port);
- TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
-
- // Set histograms to expected state.
- const COUNT_ID = "TELEMETRY_TEST_COUNT";
- const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
- const count = Telemetry.getHistogramById(COUNT_ID);
- const keyed = Telemetry.getKeyedHistogramById(KEYED_ID);
-
- count.clear();
- keyed.clear();
- count.add(1);
- keyed.add("a", 1);
- keyed.add("b", 1);
-
- // Trigger and collect environment-change ping.
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
- let startDay = truncateDateToDays(now);
- now = fakeNow(futureDate(now, 10 * MILLISECONDS_PER_MINUTE));
-
- Preferences.set(PREF_TEST, 1);
- let ping = yield PingServer.promiseNextPing();
- Assert.ok(!!ping);
-
- Assert.equal(ping.type, PING_TYPE_MAIN);
- Assert.equal(ping.environment.settings.userPrefs[PREF_TEST], undefined);
- Assert.equal(ping.payload.info.reason, REASON_ENVIRONMENT_CHANGE);
- let subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
- Assert.equal(subsessionStartDate.toISOString(), startDay.toISOString());
-
- Assert.equal(ping.payload.histograms[COUNT_ID].sum, 1);
- Assert.equal(ping.payload.keyedHistograms[KEYED_ID]["a"].sum, 1);
-
- // Trigger and collect another ping. The histograms should be reset.
- startDay = truncateDateToDays(now);
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
- now = fakeNow(futureDate(now, 10 * MILLISECONDS_PER_MINUTE));
-
- Preferences.set(PREF_TEST, 2);
- ping = yield PingServer.promiseNextPing();
- Assert.ok(!!ping);
-
- Assert.equal(ping.type, PING_TYPE_MAIN);
- Assert.equal(ping.environment.settings.userPrefs[PREF_TEST], 1);
- Assert.equal(ping.payload.info.reason, REASON_ENVIRONMENT_CHANGE);
- subsessionStartDate = new Date(ping.payload.info.subsessionStartDate);
- Assert.equal(subsessionStartDate.toISOString(), startDay.toISOString());
-
- Assert.equal(ping.payload.histograms[COUNT_ID].sum, 0);
- Assert.ok(!(KEYED_ID in ping.payload.keyedHistograms));
-});
-
-add_task(function* test_savedPingsOnShutdown() {
- // On desktop, we expect both "saved-session" and "shutdown" pings. We only expect
- // the former on Android.
- const expectedPingCount = (gIsAndroid) ? 1 : 2;
- // Assure that we store the ping properly when saving sessions on shutdown.
- // We make the TelemetryController shutdown to trigger a session save.
- const dir = TelemetryStorage.pingDirectoryPath;
- yield OS.File.removeDir(dir, {ignoreAbsent: true});
- yield OS.File.makeDir(dir);
- yield TelemetryController.testShutdown();
-
- PingServer.clearRequests();
- yield TelemetryController.testReset();
-
- const pings = yield PingServer.promiseNextPings(expectedPingCount);
-
- for (let ping of pings) {
- Assert.ok("type" in ping);
-
- let expectedReason =
- (ping.type == PING_TYPE_SAVED_SESSION) ? REASON_SAVED_SESSION : REASON_SHUTDOWN;
-
- checkPingFormat(ping, ping.type, true, true);
- Assert.equal(ping.payload.info.reason, expectedReason);
- Assert.equal(ping.clientId, gClientID);
- }
-});
-
-add_task(function* test_savedSessionData() {
- // Create the directory which will contain the data file, if it doesn't already
- // exist.
- yield OS.File.makeDir(DATAREPORTING_PATH);
- getHistogram("TELEMETRY_SESSIONDATA_FAILED_LOAD").clear();
- getHistogram("TELEMETRY_SESSIONDATA_FAILED_PARSE").clear();
- getHistogram("TELEMETRY_SESSIONDATA_FAILED_VALIDATION").clear();
-
- // Write test data to the session data file.
- const dataFilePath = OS.Path.join(DATAREPORTING_PATH, "session-state.json");
- const sessionState = {
- sessionId: null,
- subsessionId: null,
- profileSubsessionCounter: 3785,
- };
- yield CommonUtils.writeJSON(sessionState, dataFilePath);
-
- const PREF_TEST = "toolkit.telemetry.test.pref1";
- Preferences.reset(PREF_TEST);
- const PREFS_TO_WATCH = new Map([
- [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
- ]);
-
- // We expect one new subsession when starting TelemetrySession and one after triggering
- // an environment change.
- const expectedSubsessions = sessionState.profileSubsessionCounter + 2;
- const expectedSessionUUID = "ff602e52-47a1-b7e8-4c1a-ffffffffc87a";
- const expectedSubsessionUUID = "009fd1ad-b85e-4817-b3e5-000000003785";
- fakeGenerateUUID(() => expectedSessionUUID, () => expectedSubsessionUUID);
-
- if (gIsAndroid) {
- // We don't support subsessions yet on Android, so skip the next checks.
- return;
- }
-
- // Start TelemetrySession so that it loads the session data file.
- yield TelemetryController.testReset();
- Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_LOAD").sum);
- Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_PARSE").sum);
- Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_VALIDATION").sum);
-
- // Watch a test preference, trigger and environment change and wait for it to propagate.
- // _watchPreferences triggers a subsession notification
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
- fakeNow(new Date(2050, 1, 1, 12, 0, 0));
- TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
- let changePromise = new Promise(resolve =>
- TelemetryEnvironment.registerChangeListener("test_fake_change", resolve));
- Preferences.set(PREF_TEST, 1);
- yield changePromise;
- TelemetryEnvironment.unregisterChangeListener("test_fake_change");
-
- let payload = TelemetrySession.getPayload();
- Assert.equal(payload.info.profileSubsessionCounter, expectedSubsessions);
- yield TelemetryController.testShutdown();
-
- // Restore the UUID generator so we don't mess with other tests.
- fakeGenerateUUID(generateUUID, generateUUID);
-
- // Load back the serialised session data.
- let data = yield CommonUtils.readJSON(dataFilePath);
- Assert.equal(data.profileSubsessionCounter, expectedSubsessions);
- Assert.equal(data.sessionId, expectedSessionUUID);
- Assert.equal(data.subsessionId, expectedSubsessionUUID);
-});
-
-add_task(function* test_sessionData_ShortSession() {
- if (gIsAndroid) {
- // We don't support subsessions yet on Android, so skip the next checks.
- return;
- }
-
- const SESSION_STATE_PATH = OS.Path.join(DATAREPORTING_PATH, "session-state.json");
-
- // Shut down Telemetry and remove the session state file.
- yield TelemetryController.testReset();
- yield OS.File.remove(SESSION_STATE_PATH, { ignoreAbsent: true });
- getHistogram("TELEMETRY_SESSIONDATA_FAILED_LOAD").clear();
- getHistogram("TELEMETRY_SESSIONDATA_FAILED_PARSE").clear();
- getHistogram("TELEMETRY_SESSIONDATA_FAILED_VALIDATION").clear();
-
- const expectedSessionUUID = "ff602e52-47a1-b7e8-4c1a-ffffffffc87a";
- const expectedSubsessionUUID = "009fd1ad-b85e-4817-b3e5-000000003785";
- fakeGenerateUUID(() => expectedSessionUUID, () => expectedSubsessionUUID);
-
- // We intentionally don't wait for the setup to complete and shut down to simulate
- // short sessions. We expect the profile subsession counter to be 1.
- TelemetryController.testReset();
- yield TelemetryController.testShutdown();
-
- Assert.equal(1, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_LOAD").sum);
- Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_PARSE").sum);
- Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_VALIDATION").sum);
-
- // Restore the UUID generation functions.
- fakeGenerateUUID(generateUUID, generateUUID);
-
- // Start TelemetryController so that it loads the session data file. We expect the profile
- // subsession counter to be incremented by 1 again.
- yield TelemetryController.testReset();
-
- // We expect 2 profile subsession counter updates.
- let payload = TelemetrySession.getPayload();
- Assert.equal(payload.info.profileSubsessionCounter, 2);
- Assert.equal(payload.info.previousSessionId, expectedSessionUUID);
- Assert.equal(payload.info.previousSubsessionId, expectedSubsessionUUID);
- Assert.equal(1, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_LOAD").sum);
- Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_PARSE").sum);
- Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_VALIDATION").sum);
-});
-
-add_task(function* test_invalidSessionData() {
- // Create the directory which will contain the data file, if it doesn't already
- // exist.
- yield OS.File.makeDir(DATAREPORTING_PATH);
- getHistogram("TELEMETRY_SESSIONDATA_FAILED_LOAD").clear();
- getHistogram("TELEMETRY_SESSIONDATA_FAILED_PARSE").clear();
- getHistogram("TELEMETRY_SESSIONDATA_FAILED_VALIDATION").clear();
-
- // Write test data to the session data file. This should fail to parse.
- const dataFilePath = OS.Path.join(DATAREPORTING_PATH, "session-state.json");
- const unparseableData = "{asdf:@äü";
- OS.File.writeAtomic(dataFilePath, unparseableData,
- {encoding: "utf-8", tmpPath: dataFilePath + ".tmp"});
-
- // Start TelemetryController so that it loads the session data file.
- yield TelemetryController.testReset();
-
- // The session data file should not load. Only expect the current subsession.
- Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_LOAD").sum);
- Assert.equal(1, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_PARSE").sum);
- Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_VALIDATION").sum);
-
- // Write test data to the session data file. This should fail validation.
- const sessionState = {
- profileSubsessionCounter: "not-a-number?",
- someOtherField: 12,
- };
- yield CommonUtils.writeJSON(sessionState, dataFilePath);
-
- // The session data file should not load. Only expect the current subsession.
- const expectedSubsessions = 1;
- const expectedSessionUUID = "ff602e52-47a1-b7e8-4c1a-ffffffffc87a";
- const expectedSubsessionUUID = "009fd1ad-b85e-4817-b3e5-000000003785";
- fakeGenerateUUID(() => expectedSessionUUID, () => expectedSubsessionUUID);
-
- // Start TelemetryController so that it loads the session data file.
- yield TelemetryController.testReset();
-
- let payload = TelemetrySession.getPayload();
- Assert.equal(payload.info.profileSubsessionCounter, expectedSubsessions);
- Assert.equal(0, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_LOAD").sum);
- Assert.equal(1, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_PARSE").sum);
- Assert.equal(1, getSnapshot("TELEMETRY_SESSIONDATA_FAILED_VALIDATION").sum);
-
- yield TelemetryController.testShutdown();
-
- // Restore the UUID generator so we don't mess with other tests.
- fakeGenerateUUID(generateUUID, generateUUID);
-
- // Load back the serialised session data.
- let data = yield CommonUtils.readJSON(dataFilePath);
- Assert.equal(data.profileSubsessionCounter, expectedSubsessions);
- Assert.equal(data.sessionId, expectedSessionUUID);
- Assert.equal(data.subsessionId, expectedSubsessionUUID);
-});
-
-add_task(function* test_abortedSession() {
- if (gIsAndroid || gIsGonk) {
- // We don't have the aborted session ping here.
- return;
- }
-
- const ABORTED_FILE = OS.Path.join(DATAREPORTING_PATH, ABORTED_PING_FILE_NAME);
-
- // Make sure the aborted sessions directory does not exist to test its creation.
- yield OS.File.removeDir(DATAREPORTING_PATH, { ignoreAbsent: true });
-
- let schedulerTickCallback = null;
- let now = new Date(2040, 1, 1, 0, 0, 0);
- fakeNow(now);
- // Fake scheduler functions to control aborted-session flow in tests.
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryController.testReset();
-
- Assert.ok((yield OS.File.exists(DATAREPORTING_PATH)),
- "Telemetry must create the aborted session directory when starting.");
-
- // Fake now again so that the scheduled aborted-session save takes place.
- now = futureDate(now, ABORTED_SESSION_UPDATE_INTERVAL_MS);
- fakeNow(now);
- // The first aborted session checkpoint must take place right after the initialisation.
- Assert.ok(!!schedulerTickCallback);
- // Execute one scheduler tick.
- yield schedulerTickCallback();
- // Check that the aborted session is due at the correct time.
- Assert.ok((yield OS.File.exists(ABORTED_FILE)),
- "There must be an aborted session ping.");
-
- // This ping is not yet in the pending pings folder, so we can't access it using
- // TelemetryStorage.popPendingPings().
- let pingContent = yield OS.File.read(ABORTED_FILE, { encoding: "utf-8" });
- let abortedSessionPing = JSON.parse(pingContent);
-
- // Validate the ping.
- checkPingFormat(abortedSessionPing, PING_TYPE_MAIN, true, true);
- Assert.equal(abortedSessionPing.payload.info.reason, REASON_ABORTED_SESSION);
-
- // Trigger a another aborted-session ping and check that it overwrites the previous one.
- now = futureDate(now, ABORTED_SESSION_UPDATE_INTERVAL_MS);
- fakeNow(now);
- yield schedulerTickCallback();
-
- pingContent = yield OS.File.read(ABORTED_FILE, { encoding: "utf-8" });
- let updatedAbortedSessionPing = JSON.parse(pingContent);
- checkPingFormat(updatedAbortedSessionPing, PING_TYPE_MAIN, true, true);
- Assert.equal(updatedAbortedSessionPing.payload.info.reason, REASON_ABORTED_SESSION);
- Assert.notEqual(abortedSessionPing.id, updatedAbortedSessionPing.id);
- Assert.notEqual(abortedSessionPing.creationDate, updatedAbortedSessionPing.creationDate);
-
- yield TelemetryController.testShutdown();
- Assert.ok(!(yield OS.File.exists(ABORTED_FILE)),
- "No aborted session ping must be available after a shutdown.");
-
- // Write the ping to the aborted-session file. TelemetrySession will add it to the
- // saved pings directory when it starts.
- yield TelemetryStorage.savePingToFile(abortedSessionPing, ABORTED_FILE, false);
- Assert.ok((yield OS.File.exists(ABORTED_FILE)),
- "The aborted session ping must exist in the aborted session ping directory.");
-
- yield TelemetryStorage.testClearPendingPings();
- PingServer.clearRequests();
- yield TelemetryController.testReset();
-
- Assert.ok(!(yield OS.File.exists(ABORTED_FILE)),
- "The aborted session ping must be removed from the aborted session ping directory.");
-
- // Restarting Telemetry again to trigger sending pings in TelemetrySend.
- yield TelemetryController.testReset();
-
- // We should have received an aborted-session ping.
- const receivedPing = yield PingServer.promiseNextPing();
- Assert.equal(receivedPing.type, PING_TYPE_MAIN, "Should have the correct type");
- Assert.equal(receivedPing.payload.info.reason, REASON_ABORTED_SESSION, "Ping should have the correct reason");
-
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_abortedSession_Shutdown() {
- if (gIsAndroid || gIsGonk) {
- // We don't have the aborted session ping here.
- return;
- }
-
- const ABORTED_FILE = OS.Path.join(DATAREPORTING_PATH, ABORTED_PING_FILE_NAME);
-
- let schedulerTickCallback = null;
- let now = fakeNow(2040, 1, 1, 0, 0, 0);
- // Fake scheduler functions to control aborted-session flow in tests.
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryController.testReset();
-
- Assert.ok((yield OS.File.exists(DATAREPORTING_PATH)),
- "Telemetry must create the aborted session directory when starting.");
-
- // Fake now again so that the scheduled aborted-session save takes place.
- fakeNow(futureDate(now, ABORTED_SESSION_UPDATE_INTERVAL_MS));
- // The first aborted session checkpoint must take place right after the initialisation.
- Assert.ok(!!schedulerTickCallback);
- // Execute one scheduler tick.
- yield schedulerTickCallback();
- // Check that the aborted session is due at the correct time.
- Assert.ok((yield OS.File.exists(ABORTED_FILE)), "There must be an aborted session ping.");
-
- // Remove the aborted session file and then shut down to make sure exceptions (e.g file
- // not found) do not compromise the shutdown.
- yield OS.File.remove(ABORTED_FILE);
-
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_abortedDailyCoalescing() {
- if (gIsAndroid || gIsGonk) {
- // We don't have the aborted session or the daily ping here.
- return;
- }
-
- const ABORTED_FILE = OS.Path.join(DATAREPORTING_PATH, ABORTED_PING_FILE_NAME);
-
- // Make sure the aborted sessions directory does not exist to test its creation.
- yield OS.File.removeDir(DATAREPORTING_PATH, { ignoreAbsent: true });
-
- let schedulerTickCallback = null;
- PingServer.clearRequests();
-
- let nowDate = new Date(2009, 10, 18, 0, 0, 0);
- fakeNow(nowDate);
-
- // Fake scheduler functions to control aborted-session flow in tests.
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryStorage.testClearPendingPings();
- PingServer.clearRequests();
- yield TelemetryController.testReset();
-
- Assert.ok((yield OS.File.exists(DATAREPORTING_PATH)),
- "Telemetry must create the aborted session directory when starting.");
-
- // Delay the callback around midnight so that the aborted-session ping gets merged with the
- // daily ping.
- let dailyDueDate = futureDate(nowDate, MS_IN_ONE_DAY);
- fakeNow(dailyDueDate);
- // Trigger both the daily ping and the saved-session.
- Assert.ok(!!schedulerTickCallback);
- // Execute one scheduler tick.
- yield schedulerTickCallback();
-
- // Wait for the daily ping.
- let dailyPing = yield PingServer.promiseNextPing();
- Assert.equal(dailyPing.payload.info.reason, REASON_DAILY);
-
- // Check that an aborted session ping was also written to disk.
- Assert.ok((yield OS.File.exists(ABORTED_FILE)),
- "There must be an aborted session ping.");
-
- // Read aborted session ping and check that the session/subsession ids equal the
- // ones in the daily ping.
- let pingContent = yield OS.File.read(ABORTED_FILE, { encoding: "utf-8" });
- let abortedSessionPing = JSON.parse(pingContent);
- Assert.equal(abortedSessionPing.payload.info.sessionId, dailyPing.payload.info.sessionId);
- Assert.equal(abortedSessionPing.payload.info.subsessionId, dailyPing.payload.info.subsessionId);
-
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_schedulerComputerSleep() {
- if (gIsAndroid || gIsGonk) {
- // We don't have the aborted session or the daily ping here.
- return;
- }
-
- const ABORTED_FILE = OS.Path.join(DATAREPORTING_PATH, ABORTED_PING_FILE_NAME);
-
- yield TelemetryStorage.testClearPendingPings();
- yield TelemetryController.testReset();
- PingServer.clearRequests();
-
- // Remove any aborted-session ping from the previous tests.
- yield OS.File.removeDir(DATAREPORTING_PATH, { ignoreAbsent: true });
-
- // Set a fake current date and start Telemetry.
- let nowDate = fakeNow(2009, 10, 18, 0, 0, 0);
- let schedulerTickCallback = null;
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryController.testReset();
-
- // Set the current time 3 days in the future at midnight, before running the callback.
- nowDate = fakeNow(futureDate(nowDate, 3 * MS_IN_ONE_DAY));
- Assert.ok(!!schedulerTickCallback);
- // Execute one scheduler tick.
- yield schedulerTickCallback();
-
- let dailyPing = yield PingServer.promiseNextPing();
- Assert.equal(dailyPing.payload.info.reason, REASON_DAILY,
- "The wake notification should have triggered a daily ping.");
- Assert.equal(dailyPing.creationDate, nowDate.toISOString(),
- "The daily ping date should be correct.");
-
- Assert.ok((yield OS.File.exists(ABORTED_FILE)),
- "There must be an aborted session ping.");
-
- // Now also test if we are sending a daily ping if we wake up on the next
- // day even when the timer doesn't trigger.
- // This can happen due to timeouts not running out during sleep times,
- // see bug 1262386, bug 1204823 et al.
- // Note that we don't get wake notifications on Linux due to bug 758848.
- nowDate = fakeNow(futureDate(nowDate, 1 * MS_IN_ONE_DAY));
-
- // We emulate the mentioned timeout behavior by sending the wake notification
- // instead of triggering the timeout callback.
- // This should trigger a daily ping, because we passed midnight.
- Services.obs.notifyObservers(null, "wake_notification", null);
-
- dailyPing = yield PingServer.promiseNextPing();
- Assert.equal(dailyPing.payload.info.reason, REASON_DAILY,
- "The wake notification should have triggered a daily ping.");
- Assert.equal(dailyPing.creationDate, nowDate.toISOString(),
- "The daily ping date should be correct.");
-
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_schedulerEnvironmentReschedules() {
- if (gIsAndroid || gIsGonk) {
- // We don't have the aborted session or the daily ping here.
- return;
- }
-
- // Reset the test preference.
- const PREF_TEST = "toolkit.telemetry.test.pref1";
- Preferences.reset(PREF_TEST);
- const PREFS_TO_WATCH = new Map([
- [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_VALUE}],
- ]);
-
- yield TelemetryStorage.testClearPendingPings();
- PingServer.clearRequests();
- yield TelemetryController.testReset();
-
- // Set a fake current date and start Telemetry.
- let nowDate = fakeNow(2060, 10, 18, 0, 0, 0);
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
- let schedulerTickCallback = null;
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryController.testReset();
- TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
-
- // Set the current time at midnight.
- fakeNow(futureDate(nowDate, MS_IN_ONE_DAY));
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
-
- // Trigger the environment change.
- Preferences.set(PREF_TEST, 1);
-
- // Wait for the environment-changed ping.
- yield PingServer.promiseNextPing();
-
- // We don't expect to receive any daily ping in this test, so assert if we do.
- PingServer.registerPingHandler((req, res) => {
- Assert.ok(false, "No ping should be sent/received in this test.");
- });
-
- // Execute one scheduler tick. It should not trigger a daily ping.
- Assert.ok(!!schedulerTickCallback);
- yield schedulerTickCallback();
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_schedulerNothingDue() {
- if (gIsAndroid || gIsGonk) {
- // We don't have the aborted session or the daily ping here.
- return;
- }
-
- const ABORTED_FILE = OS.Path.join(DATAREPORTING_PATH, ABORTED_PING_FILE_NAME);
-
- // Remove any aborted-session ping from the previous tests.
- yield OS.File.removeDir(DATAREPORTING_PATH, { ignoreAbsent: true });
- yield TelemetryStorage.testClearPendingPings();
- yield TelemetryController.testReset();
-
- // We don't expect to receive any ping in this test, so assert if we do.
- PingServer.registerPingHandler((req, res) => {
- Assert.ok(false, "No ping should be sent/received in this test.");
- });
-
- // Set a current date/time away from midnight, so that the daily ping doesn't get
- // sent.
- let nowDate = new Date(2009, 10, 18, 11, 0, 0);
- fakeNow(nowDate);
- let schedulerTickCallback = null;
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryController.testReset();
-
- // Delay the callback execution to a time when no ping should be due.
- let nothingDueDate = futureDate(nowDate, ABORTED_SESSION_UPDATE_INTERVAL_MS / 2);
- fakeNow(nothingDueDate);
- Assert.ok(!!schedulerTickCallback);
- // Execute one scheduler tick.
- yield schedulerTickCallback();
-
- // Check that no aborted session ping was written to disk.
- Assert.ok(!(yield OS.File.exists(ABORTED_FILE)));
-
- yield TelemetryController.testShutdown();
- PingServer.resetPingHandler();
-});
-
-add_task(function* test_pingExtendedStats() {
- const EXTENDED_PAYLOAD_FIELDS = [
- "chromeHangs", "threadHangStats", "log", "slowSQL", "fileIOReports", "lateWrites",
- "addonHistograms", "addonDetails", "UIMeasurements", "webrtc"
- ];
-
- // Reset telemetry and disable sending extended statistics.
- yield TelemetryStorage.testClearPendingPings();
- PingServer.clearRequests();
- yield TelemetryController.testReset();
- Telemetry.canRecordExtended = false;
-
- yield sendPing();
-
- let ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, PING_TYPE_MAIN, true, true);
-
- // Check that the payload does not contain extended statistics fields.
- for (let f in EXTENDED_PAYLOAD_FIELDS) {
- Assert.ok(!(EXTENDED_PAYLOAD_FIELDS[f] in ping.payload),
- EXTENDED_PAYLOAD_FIELDS[f] + " must not be in the payload if the extended set is off.");
- }
-
- // We check this one separately so that we can reuse EXTENDED_PAYLOAD_FIELDS below, since
- // slowSQLStartup might not be there.
- Assert.ok(!("slowSQLStartup" in ping.payload),
- "slowSQLStartup must not be sent if the extended set is off");
-
- Assert.ok(!("addonManager" in ping.payload.simpleMeasurements),
- "addonManager must not be sent if the extended set is off.");
- Assert.ok(!("UITelemetry" in ping.payload.simpleMeasurements),
- "UITelemetry must not be sent if the extended set is off.");
-
- // Restore the preference.
- Telemetry.canRecordExtended = true;
-
- // Send a new ping that should contain the extended data.
- yield sendPing();
- ping = yield PingServer.promiseNextPing();
- checkPingFormat(ping, PING_TYPE_MAIN, true, true);
-
- // Check that the payload now contains extended statistics fields.
- for (let f in EXTENDED_PAYLOAD_FIELDS) {
- Assert.ok(EXTENDED_PAYLOAD_FIELDS[f] in ping.payload,
- EXTENDED_PAYLOAD_FIELDS[f] + " must be in the payload if the extended set is on.");
- }
-
- Assert.ok("addonManager" in ping.payload.simpleMeasurements,
- "addonManager must be sent if the extended set is on.");
- Assert.ok("UITelemetry" in ping.payload.simpleMeasurements,
- "UITelemetry must be sent if the extended set is on.");
-});
-
-add_task(function* test_schedulerUserIdle() {
- if (gIsAndroid || gIsGonk) {
- // We don't have the aborted session or the daily ping here.
- return;
- }
-
- const SCHEDULER_TICK_INTERVAL_MS = 5 * 60 * 1000;
- const SCHEDULER_TICK_IDLE_INTERVAL_MS = 60 * 60 * 1000;
-
- let now = new Date(2010, 1, 1, 11, 0, 0);
- fakeNow(now);
-
- let schedulerTimeout = 0;
- fakeSchedulerTimer((callback, timeout) => {
- schedulerTimeout = timeout;
- }, () => {});
- yield TelemetryController.testReset();
- yield TelemetryStorage.testClearPendingPings();
- PingServer.clearRequests();
-
- // When not idle, the scheduler should have a 5 minutes tick interval.
- Assert.equal(schedulerTimeout, SCHEDULER_TICK_INTERVAL_MS);
-
- // Send an "idle" notification to the scheduler.
- fakeIdleNotification("idle");
-
- // When idle, the scheduler should have a 1hr tick interval.
- Assert.equal(schedulerTimeout, SCHEDULER_TICK_IDLE_INTERVAL_MS);
-
- // Send an "active" notification to the scheduler.
- fakeIdleNotification("active");
-
- // When user is back active, the scheduler tick should be 5 minutes again.
- Assert.equal(schedulerTimeout, SCHEDULER_TICK_INTERVAL_MS);
-
- // We should not miss midnight when going to idle.
- now.setHours(23);
- now.setMinutes(50);
- fakeNow(now);
- fakeIdleNotification("idle");
- Assert.equal(schedulerTimeout, 10 * 60 * 1000);
-
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_DailyDueAndIdle() {
- if (gIsAndroid || gIsGonk) {
- // We don't have the aborted session or the daily ping here.
- return;
- }
-
- yield TelemetryStorage.testClearPendingPings();
- PingServer.clearRequests();
-
- let receivedPingRequest = null;
- // Register a ping handler that will assert when receiving multiple daily pings.
- PingServer.registerPingHandler(req => {
- Assert.ok(!receivedPingRequest, "Telemetry must only send one daily ping.");
- receivedPingRequest = req;
- });
-
- // Faking scheduler timer has to happen before resetting TelemetryController
- // to be effective.
- let schedulerTickCallback = null;
- let now = new Date(2030, 1, 1, 0, 0, 0);
- fakeNow(now);
- // Fake scheduler functions to control daily collection flow in tests.
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryController.testReset();
-
- // Trigger the daily ping.
- let firstDailyDue = new Date(2030, 1, 2, 0, 0, 0);
- fakeNow(firstDailyDue);
-
- // Run a scheduler tick: it should trigger the daily ping.
- Assert.ok(!!schedulerTickCallback);
- let tickPromise = schedulerTickCallback();
-
- // Send an idle and then an active user notification.
- fakeIdleNotification("idle");
- fakeIdleNotification("active");
-
- // Wait on the tick promise.
- yield tickPromise;
-
- yield TelemetrySend.testWaitOnOutgoingPings();
-
- // Decode the ping contained in the request and check that's a daily ping.
- Assert.ok(receivedPingRequest, "Telemetry must send one daily ping.");
- const receivedPing = decodeRequestPayload(receivedPingRequest);
- checkPingFormat(receivedPing, PING_TYPE_MAIN, true, true);
- Assert.equal(receivedPing.payload.info.reason, REASON_DAILY);
-
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_userIdleAndSchedlerTick() {
- if (gIsAndroid || gIsGonk) {
- // We don't have the aborted session or the daily ping here.
- return;
- }
-
- let receivedPingRequest = null;
- // Register a ping handler that will assert when receiving multiple daily pings.
- PingServer.registerPingHandler(req => {
- Assert.ok(!receivedPingRequest, "Telemetry must only send one daily ping.");
- receivedPingRequest = req;
- });
-
- let schedulerTickCallback = null;
- let now = new Date(2030, 1, 1, 0, 0, 0);
- fakeNow(now);
- // Fake scheduler functions to control daily collection flow in tests.
- fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
- yield TelemetryStorage.testClearPendingPings();
- yield TelemetryController.testReset();
- PingServer.clearRequests();
-
- // Move the current date/time to midnight.
- let firstDailyDue = new Date(2030, 1, 2, 0, 0, 0);
- fakeNow(firstDailyDue);
-
- // The active notification should trigger a scheduler tick. The latter will send the
- // due daily ping.
- fakeIdleNotification("active");
-
- // Immediately running another tick should not send a daily ping again.
- Assert.ok(!!schedulerTickCallback);
- yield schedulerTickCallback();
-
- // A new "idle" notification should not send a new daily ping.
- fakeIdleNotification("idle");
-
- yield TelemetrySend.testWaitOnOutgoingPings();
-
- // Decode the ping contained in the request and check that's a daily ping.
- Assert.ok(receivedPingRequest, "Telemetry must send one daily ping.");
- const receivedPing = decodeRequestPayload(receivedPingRequest);
- checkPingFormat(receivedPing, PING_TYPE_MAIN, true, true);
- Assert.equal(receivedPing.payload.info.reason, REASON_DAILY);
-
- PingServer.resetPingHandler();
- yield TelemetryController.testShutdown();
-});
-
-add_task(function* test_changeThrottling() {
- if (gIsAndroid) {
- // We don't support subsessions yet on Android.
- return;
- }
-
- let getSubsessionCount = () => {
- return TelemetrySession.getPayload().info.subsessionCounter;
- };
-
- const PREF_TEST = "toolkit.telemetry.test.pref1";
- const PREFS_TO_WATCH = new Map([
- [PREF_TEST, {what: TelemetryEnvironment.RECORD_PREF_STATE}],
- ]);
- Preferences.reset(PREF_TEST);
-
- let now = fakeNow(2050, 1, 2, 0, 0, 0);
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 10 * MILLISECONDS_PER_MINUTE);
- yield TelemetryController.testReset();
- Assert.equal(getSubsessionCount(), 1);
-
- // Set the Environment preferences to watch.
- TelemetryEnvironment.testWatchPreferences(PREFS_TO_WATCH);
-
- // The first pref change should not trigger a notification.
- Preferences.set(PREF_TEST, 1);
- Assert.equal(getSubsessionCount(), 1);
-
- // We should get a change notification after the 5min throttling interval.
- fakeNow(futureDate(now, 5 * MILLISECONDS_PER_MINUTE + 1));
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 5 * MILLISECONDS_PER_MINUTE + 1);
- Preferences.set(PREF_TEST, 2);
- Assert.equal(getSubsessionCount(), 2);
-
- // After that, changes should be throttled again.
- now = fakeNow(futureDate(now, 1 * MILLISECONDS_PER_MINUTE));
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 1 * MILLISECONDS_PER_MINUTE);
- Preferences.set(PREF_TEST, 3);
- Assert.equal(getSubsessionCount(), 2);
-
- // ... for 5min.
- now = fakeNow(futureDate(now, 4 * MILLISECONDS_PER_MINUTE + 1));
- gMonotonicNow = fakeMonotonicNow(gMonotonicNow + 4 * MILLISECONDS_PER_MINUTE + 1);
- Preferences.set(PREF_TEST, 4);
- Assert.equal(getSubsessionCount(), 3);
-
- // Unregister the listener.
- TelemetryEnvironment.unregisterChangeListener("testWatchPrefs_throttling");
-});
-
-add_task(function* stopServer() {
- yield PingServer.stop();
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryTimestamps.js b/toolkit/components/telemetry/tests/unit/test_TelemetryTimestamps.js
deleted file mode 100644
index 75bf3157a..000000000
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryTimestamps.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-var Cu = Components.utils;
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/TelemetryController.jsm", this);
-Cu.import("resource://gre/modules/TelemetrySession.jsm", this);
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-
-// The @mozilla/xre/app-info;1 XPCOM object provided by the xpcshell test harness doesn't
-// implement the nsIXULAppInfo interface, which is needed by Services.jsm and
-// TelemetrySession.jsm. updateAppInfo() creates and registers a minimal mock app-info.
-Cu.import("resource://testing-common/AppInfo.jsm");
-updateAppInfo();
-
-var gGlobalScope = this;
-
-function getSimpleMeasurementsFromTelemetryController() {
- return TelemetrySession.getPayload().simpleMeasurements;
-}
-
-add_task(function* test_setup() {
- // Telemetry needs the AddonManager.
- loadAddonManager();
- // Make profile available for |TelemetryController.testShutdown()|.
- do_get_profile();
-
- // Make sure we don't generate unexpected pings due to pref changes.
- yield setEmptyPrefWatchlist();
-
- yield new Promise(resolve =>
- Services.telemetry.asyncFetchTelemetryData(resolve));
-});
-
-add_task(function* actualTest() {
- yield TelemetryController.testSetup();
-
- // Test the module logic
- let tmp = {};
- Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", tmp);
- let TelemetryTimestamps = tmp.TelemetryTimestamps;
- let now = Date.now();
- TelemetryTimestamps.add("foo");
- do_check_true(TelemetryTimestamps.get().foo != null); // foo was added
- do_check_true(TelemetryTimestamps.get().foo >= now); // foo has a reasonable value
-
- // Add timestamp with value
- // Use a value far in the future since TelemetryController substracts the time of
- // process initialization.
- const YEAR_4000_IN_MS = 64060588800000;
- TelemetryTimestamps.add("bar", YEAR_4000_IN_MS);
- do_check_eq(TelemetryTimestamps.get().bar, YEAR_4000_IN_MS); // bar has the right value
-
- // Can't add the same timestamp twice
- TelemetryTimestamps.add("bar", 2);
- do_check_eq(TelemetryTimestamps.get().bar, YEAR_4000_IN_MS); // bar wasn't overwritten
-
- let threw = false;
- try {
- TelemetryTimestamps.add("baz", "this isn't a number");
- } catch (ex) {
- threw = true;
- }
- do_check_true(threw); // adding non-number threw
- do_check_null(TelemetryTimestamps.get().baz); // no baz was added
-
- // Test that the data gets added to the telemetry ping properly
- let simpleMeasurements = getSimpleMeasurementsFromTelemetryController();
- do_check_true(simpleMeasurements != null); // got simple measurements from ping data
- do_check_true(simpleMeasurements.foo > 1); // foo was included
- do_check_true(simpleMeasurements.bar > 1); // bar was included
- do_check_eq(undefined, simpleMeasurements.baz); // baz wasn't included since it wasn't added
-
- yield TelemetryController.testShutdown();
-});
diff --git a/toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js b/toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js
deleted file mode 100644
index e8c9f868a..000000000
--- a/toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js
+++ /dev/null
@@ -1,102 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-function getMainThreadHangStats() {
- let threads = Services.telemetry.threadHangStats;
- return threads.find((thread) => (thread.name === "Gecko"));
-}
-
-function run_test() {
- let startHangs = getMainThreadHangStats();
-
- // We disable hang reporting in several situations (e.g. debug builds,
- // official releases). In those cases, we don't have hang stats available
- // and should exit the test early.
- if (!startHangs) {
- ok("Hang reporting not enabled.");
- return;
- }
-
- if (Services.appinfo.OS === 'Linux' || Services.appinfo.OS === 'Android') {
- // We use the rt_tgsigqueueinfo syscall on Linux which requires a
- // certain kernel version. It's not an error if the system running
- // the test is older than that.
- let kernel = Services.sysinfo.get('kernel_version') ||
- Services.sysinfo.get('version');
- if (Services.vc.compare(kernel, '2.6.31') < 0) {
- ok("Hang reporting not supported for old kernel.");
- return;
- }
- }
-
- // Run three events in the event loop:
- // the first event causes a transient hang;
- // the second event causes a permanent hang;
- // the third event checks results from previous events.
-
- do_execute_soon(() => {
- // Cause a hang lasting 1 second (transient hang).
- let startTime = Date.now();
- while ((Date.now() - startTime) < 1000);
- });
-
- do_execute_soon(() => {
- // Cause a hang lasting 10 seconds (permanent hang).
- let startTime = Date.now();
- while ((Date.now() - startTime) < 10000);
- });
-
- do_execute_soon(() => {
- do_test_pending();
-
- let check_results = () => {
- let endHangs = getMainThreadHangStats();
-
- // Because hangs are recorded asynchronously, if we don't see new hangs,
- // we should wait for pending hangs to be recorded. On the other hand,
- // if hang monitoring is broken, this test will time out.
- if (endHangs.hangs.length === startHangs.hangs.length) {
- do_timeout(100, check_results);
- return;
- }
-
- let check_histogram = (histogram) => {
- equal(typeof histogram, "object");
- equal(histogram.histogram_type, 0);
- equal(typeof histogram.min, "number");
- equal(typeof histogram.max, "number");
- equal(typeof histogram.sum, "number");
- ok(Array.isArray(histogram.ranges));
- ok(Array.isArray(histogram.counts));
- equal(histogram.counts.length, histogram.ranges.length);
- };
-
- // Make sure the hang stats structure is what we expect.
- equal(typeof endHangs, "object");
- check_histogram(endHangs.activity);
-
- ok(Array.isArray(endHangs.hangs));
- notEqual(endHangs.hangs.length, 0);
-
- ok(Array.isArray(endHangs.hangs[0].stack));
- notEqual(endHangs.hangs[0].stack.length, 0);
- equal(typeof endHangs.hangs[0].stack[0], "string");
-
- // Make sure one of the hangs is a permanent
- // hang containing a native stack.
- ok(endHangs.hangs.some((hang) => (
- Array.isArray(hang.nativeStack) &&
- hang.nativeStack.length !== 0 &&
- typeof hang.nativeStack[0] === "string"
- )));
-
- check_histogram(endHangs.hangs[0].histogram);
-
- do_test_finished();
- };
-
- check_results();
- });
-}
diff --git a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
deleted file mode 100644
index 8dc552604..000000000
--- a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
+++ /dev/null
@@ -1,883 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-const INT_MAX = 0x7FFFFFFF;
-
-Cu.import("resource://gre/modules/Services.jsm", this);
-Cu.import("resource://gre/modules/TelemetryUtils.jsm", this);
-
-// Return an array of numbers from lower up to, excluding, upper
-function numberRange(lower, upper)
-{
- let a = [];
- for (let i=lower; i<upper; ++i) {
- a.push(i);
- }
- return a;
-}
-
-function expect_fail(f) {
- let failed = false;
- try {
- f();
- failed = false;
- } catch (e) {
- failed = true;
- }
- do_check_true(failed);
-}
-
-function expect_success(f) {
- let succeeded = false;
- try {
- f();
- succeeded = true;
- } catch (e) {
- succeeded = false;
- }
- do_check_true(succeeded);
-}
-
-function compareHistograms(h1, h2) {
- let s1 = h1.snapshot();
- let s2 = h2.snapshot();
-
- do_check_eq(s1.histogram_type, s2.histogram_type);
- do_check_eq(s1.min, s2.min);
- do_check_eq(s1.max, s2.max);
- do_check_eq(s1.sum, s2.sum);
-
- do_check_eq(s1.counts.length, s2.counts.length);
- for (let i = 0; i < s1.counts.length; i++)
- do_check_eq(s1.counts[i], s2.counts[i]);
-
- do_check_eq(s1.ranges.length, s2.ranges.length);
- for (let i = 0; i < s1.ranges.length; i++)
- do_check_eq(s1.ranges[i], s2.ranges[i]);
-}
-
-function check_histogram(histogram_type, name, min, max, bucket_count) {
- var h = Telemetry.getHistogramById(name);
- var r = h.snapshot().ranges;
- var sum = 0;
- for (let i=0;i<r.length;i++) {
- var v = r[i];
- sum += v;
- h.add(v);
- }
- var s = h.snapshot();
- // verify properties
- do_check_eq(sum, s.sum);
-
- // there should be exactly one element per bucket
- for (let i of s.counts) {
- do_check_eq(i, 1);
- }
- var hgrams = Telemetry.histogramSnapshots
- let gh = hgrams[name]
- do_check_eq(gh.histogram_type, histogram_type);
-
- do_check_eq(gh.min, min)
- do_check_eq(gh.max, max)
-
- // Check that booleans work with nonboolean histograms
- h.add(false);
- h.add(true);
- s = h.snapshot().counts;
- do_check_eq(s[0], 2)
- do_check_eq(s[1], 2)
-
- // Check that clearing works.
- h.clear();
- s = h.snapshot();
- for (var i of s.counts) {
- do_check_eq(i, 0);
- }
- do_check_eq(s.sum, 0);
-
- h.add(0);
- h.add(1);
- var c = h.snapshot().counts;
- do_check_eq(c[0], 1);
- do_check_eq(c[1], 1);
-}
-
-// This MUST be the very first test of this file.
-add_task({
- skip_if: () => gIsAndroid
-},
-function* test_instantiate() {
- const ID = "TELEMETRY_TEST_COUNT";
- let h = Telemetry.getHistogramById(ID);
-
- // Instantiate the subsession histogram through |add| and make sure they match.
- // This MUST be the first use of "TELEMETRY_TEST_COUNT" in this file, otherwise
- // |add| will not instantiate the histogram.
- h.add(1);
- let snapshot = h.snapshot();
- let subsession = Telemetry.snapshotSubsessionHistograms();
- Assert.equal(snapshot.sum, subsession[ID].sum,
- "Histogram and subsession histogram sum must match.");
- // Clear the histogram, so we don't void the assumptions from the other tests.
- h.clear();
-});
-
-add_task(function* test_parameterChecks() {
- let kinds = [Telemetry.HISTOGRAM_EXPONENTIAL, Telemetry.HISTOGRAM_LINEAR]
- let testNames = ["TELEMETRY_TEST_EXPONENTIAL", "TELEMETRY_TEST_LINEAR"]
- for (let i = 0; i < kinds.length; i++) {
- let histogram_type = kinds[i];
- let test_type = testNames[i];
- let [min, max, bucket_count] = [1, INT_MAX - 1, 10]
- check_histogram(histogram_type, test_type, min, max, bucket_count);
- }
-});
-
-add_task(function* test_noSerialization() {
- // Instantiate the storage for this histogram and make sure it doesn't
- // get reflected into JS, as it has no interesting data in it.
- Telemetry.getHistogramById("NEWTAB_PAGE_PINNED_SITES_COUNT");
- do_check_false("NEWTAB_PAGE_PINNED_SITES_COUNT" in Telemetry.histogramSnapshots);
-});
-
-add_task(function* test_boolean_histogram() {
- var h = Telemetry.getHistogramById("TELEMETRY_TEST_BOOLEAN");
- var r = h.snapshot().ranges;
- // boolean histograms ignore numeric parameters
- do_check_eq(uneval(r), uneval([0, 1, 2]))
- for (var i=0;i<r.length;i++) {
- var v = r[i];
- h.add(v);
- }
- h.add(true);
- h.add(false);
- var s = h.snapshot();
- do_check_eq(s.histogram_type, Telemetry.HISTOGRAM_BOOLEAN);
- // last bucket should always be 0 since .add parameters are normalized to either 0 or 1
- do_check_eq(s.counts[2], 0);
- do_check_eq(s.sum, 3);
- do_check_eq(s.counts[0], 2);
-});
-
-add_task(function* test_flag_histogram() {
- var h = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG");
- var r = h.snapshot().ranges;
- // Flag histograms ignore numeric parameters.
- do_check_eq(uneval(r), uneval([0, 1, 2]));
- // Should already have a 0 counted.
- var c = h.snapshot().counts;
- var s = h.snapshot().sum;
- do_check_eq(uneval(c), uneval([1, 0, 0]));
- do_check_eq(s, 0);
- // Should switch counts.
- h.add(1);
- var c2 = h.snapshot().counts;
- var s2 = h.snapshot().sum;
- do_check_eq(uneval(c2), uneval([0, 1, 0]));
- do_check_eq(s2, 1);
- // Should only switch counts once.
- h.add(1);
- var c3 = h.snapshot().counts;
- var s3 = h.snapshot().sum;
- do_check_eq(uneval(c3), uneval([0, 1, 0]));
- do_check_eq(s3, 1);
- do_check_eq(h.snapshot().histogram_type, Telemetry.HISTOGRAM_FLAG);
-});
-
-add_task(function* test_count_histogram() {
- let h = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT2");
- let s = h.snapshot();
- do_check_eq(uneval(s.ranges), uneval([0, 1, 2]));
- do_check_eq(uneval(s.counts), uneval([0, 0, 0]));
- do_check_eq(s.sum, 0);
- h.add();
- s = h.snapshot();
- do_check_eq(uneval(s.counts), uneval([1, 0, 0]));
- do_check_eq(s.sum, 1);
- h.add();
- s = h.snapshot();
- do_check_eq(uneval(s.counts), uneval([2, 0, 0]));
- do_check_eq(s.sum, 2);
-});
-
-add_task(function* test_categorical_histogram()
-{
- let h1 = Telemetry.getHistogramById("TELEMETRY_TEST_CATEGORICAL");
- for (let v of ["CommonLabel", "Label2", "Label3", "Label3", 0, 0, 1]) {
- h1.add(v);
- }
- for (let s of ["", "Label4", "1234"]) {
- Assert.throws(() => h1.add(s));
- }
-
- let snapshot = h1.snapshot();
- Assert.equal(snapshot.sum, 6);
- Assert.deepEqual(snapshot.ranges, [0, 1, 2, 3]);
- Assert.deepEqual(snapshot.counts, [3, 2, 2, 0]);
-
- let h2 = Telemetry.getHistogramById("TELEMETRY_TEST_CATEGORICAL_OPTOUT");
- for (let v of ["CommonLabel", "CommonLabel", "Label4", "Label5", "Label6", 0, 1]) {
- h2.add(v);
- }
- for (let s of ["", "Label3", "1234"]) {
- Assert.throws(() => h2.add(s));
- }
-
- snapshot = h2.snapshot();
- Assert.equal(snapshot.sum, 7);
- Assert.deepEqual(snapshot.ranges, [0, 1, 2, 3, 4]);
- Assert.deepEqual(snapshot.counts, [3, 2, 1, 1, 0]);
-});
-
-add_task(function* test_getHistogramById() {
- try {
- Telemetry.getHistogramById("nonexistent");
- do_throw("This can't happen");
- } catch (e) {
-
- }
- var h = Telemetry.getHistogramById("CYCLE_COLLECTOR");
- var s = h.snapshot();
- do_check_eq(s.histogram_type, Telemetry.HISTOGRAM_EXPONENTIAL);
- do_check_eq(s.min, 1);
- do_check_eq(s.max, 10000);
-});
-
-add_task(function* test_getSlowSQL() {
- var slow = Telemetry.slowSQL;
- do_check_true(("mainThread" in slow) && ("otherThreads" in slow));
-});
-
-add_task(function* test_getWebrtc() {
- var webrtc = Telemetry.webrtcStats;
- do_check_true("IceCandidatesStats" in webrtc);
- var icestats = webrtc.IceCandidatesStats;
- do_check_true("webrtc" in icestats);
-});
-
-// Check that telemetry doesn't record in private mode
-add_task(function* test_privateMode() {
- var h = Telemetry.getHistogramById("TELEMETRY_TEST_BOOLEAN");
- var orig = h.snapshot();
- Telemetry.canRecordExtended = false;
- h.add(1);
- do_check_eq(uneval(orig), uneval(h.snapshot()));
- Telemetry.canRecordExtended = true;
- h.add(1);
- do_check_neq(uneval(orig), uneval(h.snapshot()));
-});
-
-// Check that telemetry records only when it is suppose to.
-add_task(function* test_histogramRecording() {
- // Check that no histogram is recorded if both base and extended recording are off.
- Telemetry.canRecordBase = false;
- Telemetry.canRecordExtended = false;
-
- let h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTOUT");
- h.clear();
- let orig = h.snapshot();
- h.add(1);
- Assert.equal(orig.sum, h.snapshot().sum);
-
- // Check that only base histograms are recorded.
- Telemetry.canRecordBase = true;
- h.add(1);
- Assert.equal(orig.sum + 1, h.snapshot().sum,
- "Histogram value should have incremented by 1 due to recording.");
-
- // Extended histograms should not be recorded.
- h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTIN");
- orig = h.snapshot();
- h.add(1);
- Assert.equal(orig.sum, h.snapshot().sum,
- "Histograms should be equal after recording.");
-
- // Runtime created histograms should not be recorded.
- h = Telemetry.getHistogramById("TELEMETRY_TEST_BOOLEAN");
- orig = h.snapshot();
- h.add(1);
- Assert.equal(orig.sum, h.snapshot().sum,
- "Histograms should be equal after recording.");
-
- // Check that extended histograms are recorded when required.
- Telemetry.canRecordExtended = true;
-
- h.add(1);
- Assert.equal(orig.sum + 1, h.snapshot().sum,
- "Runtime histogram value should have incremented by 1 due to recording.");
-
- h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTIN");
- orig = h.snapshot();
- h.add(1);
- Assert.equal(orig.sum + 1, h.snapshot().sum,
- "Histogram value should have incremented by 1 due to recording.");
-
- // Check that base histograms are still being recorded.
- h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTOUT");
- h.clear();
- orig = h.snapshot();
- h.add(1);
- Assert.equal(orig.sum + 1, h.snapshot().sum,
- "Histogram value should have incremented by 1 due to recording.");
-});
-
-add_task(function* test_addons() {
- var addon_id = "testing-addon";
- var fake_addon_id = "fake-addon";
- var name1 = "testing-histogram1";
- var register = Telemetry.registerAddonHistogram;
- expect_success(() =>
- register(addon_id, name1, Telemetry.HISTOGRAM_LINEAR, 1, 5, 6));
- // Can't register the same histogram multiple times.
- expect_fail(() =>
- register(addon_id, name1, Telemetry.HISTOGRAM_LINEAR, 1, 5, 6));
- // Make sure we can't get at it with another name.
- expect_fail(() => Telemetry.getAddonHistogram(fake_addon_id, name1));
-
- // Check for reflection capabilities.
- var h1 = Telemetry.getAddonHistogram(addon_id, name1);
- // Verify that although we've created storage for it, we don't reflect it into JS.
- var snapshots = Telemetry.addonHistogramSnapshots;
- do_check_false(name1 in snapshots[addon_id]);
- h1.add(1);
- h1.add(3);
- var s1 = h1.snapshot();
- do_check_eq(s1.histogram_type, Telemetry.HISTOGRAM_LINEAR);
- do_check_eq(s1.min, 1);
- do_check_eq(s1.max, 5);
- do_check_eq(s1.counts[1], 1);
- do_check_eq(s1.counts[3], 1);
-
- var name2 = "testing-histogram2";
- expect_success(() =>
- register(addon_id, name2, Telemetry.HISTOGRAM_LINEAR, 2, 4, 4));
-
- var h2 = Telemetry.getAddonHistogram(addon_id, name2);
- h2.add(2);
- h2.add(3);
- var s2 = h2.snapshot();
- do_check_eq(s2.histogram_type, Telemetry.HISTOGRAM_LINEAR);
- do_check_eq(s2.min, 2);
- do_check_eq(s2.max, 4);
- do_check_eq(s2.counts[1], 1);
- do_check_eq(s2.counts[2], 1);
-
- // Check that we can register histograms for a different addon with
- // identical names.
- var extra_addon = "testing-extra-addon";
- expect_success(() =>
- register(extra_addon, name1, Telemetry.HISTOGRAM_BOOLEAN));
-
- // Check that we can register flag histograms.
- var flag_addon = "testing-flag-addon";
- var flag_histogram = "flag-histogram";
- expect_success(() =>
- register(flag_addon, flag_histogram, Telemetry.HISTOGRAM_FLAG));
- expect_success(() =>
- register(flag_addon, name2, Telemetry.HISTOGRAM_LINEAR, 2, 4, 4));
-
- // Check that we reflect registered addons and histograms.
- snapshots = Telemetry.addonHistogramSnapshots;
- do_check_true(addon_id in snapshots)
- do_check_true(extra_addon in snapshots);
- do_check_true(flag_addon in snapshots);
-
- // Check that we have data for our created histograms.
- do_check_true(name1 in snapshots[addon_id]);
- do_check_true(name2 in snapshots[addon_id]);
- var s1_alt = snapshots[addon_id][name1];
- var s2_alt = snapshots[addon_id][name2];
- do_check_eq(s1_alt.min, s1.min);
- do_check_eq(s1_alt.max, s1.max);
- do_check_eq(s1_alt.histogram_type, s1.histogram_type);
- do_check_eq(s2_alt.min, s2.min);
- do_check_eq(s2_alt.max, s2.max);
- do_check_eq(s2_alt.histogram_type, s2.histogram_type);
-
- // Even though we've registered it, it shouldn't show up until data is added to it.
- do_check_false(name1 in snapshots[extra_addon]);
-
- // Flag histograms should show up automagically.
- do_check_true(flag_histogram in snapshots[flag_addon]);
- do_check_false(name2 in snapshots[flag_addon]);
-
- // Check that we can remove addon histograms.
- Telemetry.unregisterAddonHistograms(addon_id);
- snapshots = Telemetry.addonHistogramSnapshots;
- do_check_false(addon_id in snapshots);
- // Make sure other addons are unaffected.
- do_check_true(extra_addon in snapshots);
-});
-
-add_task(function* test_expired_histogram() {
- var test_expired_id = "TELEMETRY_TEST_EXPIRED";
- var dummy = Telemetry.getHistogramById(test_expired_id);
- var rh = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []);
- Assert.ok(!!rh);
-
- dummy.add(1);
-
- do_check_eq(Telemetry.histogramSnapshots["__expired__"], undefined);
- do_check_eq(Telemetry.histogramSnapshots[test_expired_id], undefined);
- do_check_eq(rh[test_expired_id], undefined);
-});
-
-add_task(function* test_keyed_histogram() {
- // Check that invalid names get rejected.
-
- let threw = false;
- try {
- Telemetry.getKeyedHistogramById("test::unknown histogram", "never", Telemetry.HISTOGRAM_BOOLEAN);
- } catch (e) {
- // This should throw as it is an unknown ID
- threw = true;
- }
- Assert.ok(threw, "getKeyedHistogramById should have thrown");
-});
-
-add_task(function* test_keyed_boolean_histogram() {
- const KEYED_ID = "TELEMETRY_TEST_KEYED_BOOLEAN";
- let KEYS = numberRange(0, 2).map(i => "key" + (i + 1));
- KEYS.push("漢語");
- let histogramBase = {
- "min": 1,
- "max": 2,
- "histogram_type": 2,
- "sum": 1,
- "ranges": [0, 1, 2],
- "counts": [0, 1, 0]
- };
- let testHistograms = numberRange(0, 3).map(i => JSON.parse(JSON.stringify(histogramBase)));
- let testKeys = [];
- let testSnapShot = {};
-
- let h = Telemetry.getKeyedHistogramById(KEYED_ID);
- for (let i=0; i<2; ++i) {
- let key = KEYS[i];
- h.add(key, true);
- testSnapShot[key] = testHistograms[i];
- testKeys.push(key);
-
- Assert.deepEqual(h.keys().sort(), testKeys);
- Assert.deepEqual(h.snapshot(), testSnapShot);
- }
-
- h = Telemetry.getKeyedHistogramById(KEYED_ID);
- Assert.deepEqual(h.keys().sort(), testKeys);
- Assert.deepEqual(h.snapshot(), testSnapShot);
-
- let key = KEYS[2];
- h.add(key, false);
- testKeys.push(key);
- testSnapShot[key] = testHistograms[2];
- testSnapShot[key].sum = 0;
- testSnapShot[key].counts = [1, 0, 0];
- Assert.deepEqual(h.keys().sort(), testKeys);
- Assert.deepEqual(h.snapshot(), testSnapShot);
-
- let allSnapshots = Telemetry.keyedHistogramSnapshots;
- Assert.deepEqual(allSnapshots[KEYED_ID], testSnapShot);
-
- h.clear();
- Assert.deepEqual(h.keys(), []);
- Assert.deepEqual(h.snapshot(), {});
-});
-
-add_task(function* test_keyed_count_histogram() {
- const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
- const KEYS = numberRange(0, 5).map(i => "key" + (i + 1));
- let histogramBase = {
- "min": 1,
- "max": 2,
- "histogram_type": 4,
- "sum": 0,
- "ranges": [0, 1, 2],
- "counts": [1, 0, 0]
- };
- let testHistograms = numberRange(0, 5).map(i => JSON.parse(JSON.stringify(histogramBase)));
- let testKeys = [];
- let testSnapShot = {};
-
- let h = Telemetry.getKeyedHistogramById(KEYED_ID);
- for (let i=0; i<4; ++i) {
- let key = KEYS[i];
- let value = i*2 + 1;
-
- for (let k=0; k<value; ++k) {
- h.add(key);
- }
- testHistograms[i].counts[0] = value;
- testHistograms[i].sum = value;
- testSnapShot[key] = testHistograms[i];
- testKeys.push(key);
-
- Assert.deepEqual(h.keys().sort(), testKeys);
- Assert.deepEqual(h.snapshot(key), testHistograms[i]);
- Assert.deepEqual(h.snapshot(), testSnapShot);
- }
-
- h = Telemetry.getKeyedHistogramById(KEYED_ID);
- Assert.deepEqual(h.keys().sort(), testKeys);
- Assert.deepEqual(h.snapshot(), testSnapShot);
-
- let key = KEYS[4];
- h.add(key);
- testKeys.push(key);
- testHistograms[4].counts[0] = 1;
- testHistograms[4].sum = 1;
- testSnapShot[key] = testHistograms[4];
-
- Assert.deepEqual(h.keys().sort(), testKeys);
- Assert.deepEqual(h.snapshot(), testSnapShot);
-
- let allSnapshots = Telemetry.keyedHistogramSnapshots;
- Assert.deepEqual(allSnapshots[KEYED_ID], testSnapShot);
-
- h.clear();
- Assert.deepEqual(h.keys(), []);
- Assert.deepEqual(h.snapshot(), {});
-});
-
-add_task(function* test_keyed_flag_histogram() {
- const KEYED_ID = "TELEMETRY_TEST_KEYED_FLAG";
- let h = Telemetry.getKeyedHistogramById(KEYED_ID);
-
- const KEY = "default";
- h.add(KEY, true);
-
- let testSnapshot = {};
- testSnapshot[KEY] = {
- "min": 1,
- "max": 2,
- "histogram_type": 3,
- "sum": 1,
- "ranges": [0, 1, 2],
- "counts": [0, 1, 0]
- };
-
- Assert.deepEqual(h.keys().sort(), [KEY]);
- Assert.deepEqual(h.snapshot(), testSnapshot);
-
- let allSnapshots = Telemetry.keyedHistogramSnapshots;
- Assert.deepEqual(allSnapshots[KEYED_ID], testSnapshot);
-
- h.clear();
- Assert.deepEqual(h.keys(), []);
- Assert.deepEqual(h.snapshot(), {});
-});
-
-add_task(function* test_keyed_histogram_recording() {
- // Check that no histogram is recorded if both base and extended recording are off.
- Telemetry.canRecordBase = false;
- Telemetry.canRecordExtended = false;
-
- const TEST_KEY = "record_foo";
- let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT");
- h.clear();
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 0);
-
- // Check that only base histograms are recorded.
- Telemetry.canRecordBase = true;
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 1,
- "The keyed histogram should record the correct value.");
-
- // Extended set keyed histograms should not be recorded.
- h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTIN");
- h.clear();
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 0,
- "The keyed histograms should not record any data.");
-
- // Check that extended histograms are recorded when required.
- Telemetry.canRecordExtended = true;
-
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 1,
- "The runtime keyed histogram should record the correct value.");
-
- h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTIN");
- h.clear();
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 1,
- "The keyed histogram should record the correct value.");
-
- // Check that base histograms are still being recorded.
- h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT");
- h.clear();
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 1);
-});
-
-add_task(function* test_histogram_recording_enabled() {
- Telemetry.canRecordBase = true;
- Telemetry.canRecordExtended = true;
-
- // Check that a "normal" histogram respects recording-enabled on/off
- var h = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
- var orig = h.snapshot();
-
- h.add(1);
- Assert.equal(orig.sum + 1, h.snapshot().sum,
- "add should record by default.");
-
- // Check that when recording is disabled - add is ignored
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_COUNT", false);
- h.add(1);
- Assert.equal(orig.sum + 1, h.snapshot().sum,
- "When recording is disabled add should not record.");
-
- // Check that we're back to normal after recording is enabled
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_COUNT", true);
- h.add(1);
- Assert.equal(orig.sum + 2, h.snapshot().sum,
- "When recording is re-enabled add should record.");
-
- // Check that we're correctly accumulating values other than 1.
- h.clear();
- h.add(3);
- Assert.equal(3, h.snapshot().sum, "Recording counts greater than 1 should work.");
-
- // Check that a histogram with recording disabled by default behaves correctly
- h = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT_INIT_NO_RECORD");
- orig = h.snapshot();
-
- h.add(1);
- Assert.equal(orig.sum, h.snapshot().sum,
- "When recording is disabled by default, add should not record by default.");
-
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_COUNT_INIT_NO_RECORD", true);
- h.add(1);
- Assert.equal(orig.sum + 1, h.snapshot().sum,
- "When recording is enabled add should record.");
-
- // Restore to disabled
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_COUNT_INIT_NO_RECORD", false);
- h.add(1);
- Assert.equal(orig.sum + 1, h.snapshot().sum,
- "When recording is disabled add should not record.");
-});
-
-add_task(function* test_keyed_histogram_recording_enabled() {
- Telemetry.canRecordBase = true;
- Telemetry.canRecordExtended = true;
-
- // Check RecordingEnabled for keyed histograms which are recording by default
- const TEST_KEY = "record_foo";
- let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT");
-
- h.clear();
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 1,
- "Keyed histogram add should record by default");
-
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT", false);
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 1,
- "Keyed histogram add should not record when recording is disabled");
-
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT", true);
- h.clear();
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 1,
- "Keyed histogram add should record when recording is re-enabled");
-
- // Check that a histogram with recording disabled by default behaves correctly
- h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD");
- h.clear();
-
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 0,
- "Keyed histogram add should not record by default for histograms which don't record by default");
-
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD", true);
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 1,
- "Keyed histogram add should record when recording is enabled");
-
- // Restore to disabled
- Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD", false);
- h.add(TEST_KEY, 1);
- Assert.equal(h.snapshot(TEST_KEY).sum, 1,
- "Keyed histogram add should not record when recording is disabled");
-});
-
-add_task(function* test_datasets() {
- // Check that datasets work as expected.
-
- const RELEASE_CHANNEL_OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
- const RELEASE_CHANNEL_OPTIN = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN;
-
- // Histograms should default to the extended dataset
- let h = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG");
- Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
- h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_FLAG");
- Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
-
- // Check test histograms with explicit dataset definitions
- h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTIN");
- Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
- h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTOUT");
- Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTOUT);
- h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTIN");
- Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTIN);
- h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT");
- Assert.equal(h.dataset(), RELEASE_CHANNEL_OPTOUT);
-
- // Check that registeredHistogram works properly
- let registered = Telemetry.registeredHistograms(RELEASE_CHANNEL_OPTIN, []);
- registered = new Set(registered);
- Assert.ok(registered.has("TELEMETRY_TEST_FLAG"));
- Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTIN"));
- Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTOUT"));
- registered = Telemetry.registeredHistograms(RELEASE_CHANNEL_OPTOUT, []);
- registered = new Set(registered);
- Assert.ok(!registered.has("TELEMETRY_TEST_FLAG"));
- Assert.ok(!registered.has("TELEMETRY_TEST_RELEASE_OPTIN"));
- Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTOUT"));
-
- // Check that registeredKeyedHistograms works properly
- registered = Telemetry.registeredKeyedHistograms(RELEASE_CHANNEL_OPTIN, []);
- registered = new Set(registered);
- Assert.ok(registered.has("TELEMETRY_TEST_KEYED_FLAG"));
- Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
- registered = Telemetry.registeredKeyedHistograms(RELEASE_CHANNEL_OPTOUT, []);
- registered = new Set(registered);
- Assert.ok(!registered.has("TELEMETRY_TEST_KEYED_FLAG"));
- Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
-});
-
-add_task({
- skip_if: () => gIsAndroid
-},
-function* test_subsession() {
- const ID = "TELEMETRY_TEST_COUNT";
- const FLAG = "TELEMETRY_TEST_FLAG";
- let h = Telemetry.getHistogramById(ID);
- let flag = Telemetry.getHistogramById(FLAG);
-
- // Both original and duplicate should start out the same.
- h.clear();
- let snapshot = Telemetry.histogramSnapshots;
- let subsession = Telemetry.snapshotSubsessionHistograms();
- Assert.ok(!(ID in snapshot));
- Assert.ok(!(ID in subsession));
-
- // They should instantiate and pick-up the count.
- h.add(1);
- snapshot = Telemetry.histogramSnapshots;
- subsession = Telemetry.snapshotSubsessionHistograms();
- Assert.ok(ID in snapshot);
- Assert.ok(ID in subsession);
- Assert.equal(snapshot[ID].sum, 1);
- Assert.equal(subsession[ID].sum, 1);
-
- // They should still reset properly.
- h.clear();
- snapshot = Telemetry.histogramSnapshots;
- subsession = Telemetry.snapshotSubsessionHistograms();
- Assert.ok(!(ID in snapshot));
- Assert.ok(!(ID in subsession));
-
- // Both should instantiate and pick-up the count.
- h.add(1);
- snapshot = Telemetry.histogramSnapshots;
- subsession = Telemetry.snapshotSubsessionHistograms();
- Assert.equal(snapshot[ID].sum, 1);
- Assert.equal(subsession[ID].sum, 1);
-
- // Check that we are able to only reset the duplicate histogram.
- h.clear(true);
- snapshot = Telemetry.histogramSnapshots;
- subsession = Telemetry.snapshotSubsessionHistograms();
- Assert.ok(ID in snapshot);
- Assert.ok(ID in subsession);
- Assert.equal(snapshot[ID].sum, 1);
- Assert.equal(subsession[ID].sum, 0);
-
- // Both should register the next count.
- h.add(1);
- snapshot = Telemetry.histogramSnapshots;
- subsession = Telemetry.snapshotSubsessionHistograms();
- Assert.equal(snapshot[ID].sum, 2);
- Assert.equal(subsession[ID].sum, 1);
-
- // Retrieve a subsession snapshot and pass the flag to
- // clear subsession histograms too.
- h.clear();
- flag.clear();
- h.add(1);
- flag.add(1);
- snapshot = Telemetry.histogramSnapshots;
- subsession = Telemetry.snapshotSubsessionHistograms(true);
- Assert.ok(ID in snapshot);
- Assert.ok(ID in subsession);
- Assert.ok(FLAG in snapshot);
- Assert.ok(FLAG in subsession);
- Assert.equal(snapshot[ID].sum, 1);
- Assert.equal(subsession[ID].sum, 1);
- Assert.equal(snapshot[FLAG].sum, 1);
- Assert.equal(subsession[FLAG].sum, 1);
-
- // The next subsesssion snapshot should show the histograms
- // got reset.
- snapshot = Telemetry.histogramSnapshots;
- subsession = Telemetry.snapshotSubsessionHistograms();
- Assert.ok(ID in snapshot);
- Assert.ok(ID in subsession);
- Assert.ok(FLAG in snapshot);
- Assert.ok(FLAG in subsession);
- Assert.equal(snapshot[ID].sum, 1);
- Assert.equal(subsession[ID].sum, 0);
- Assert.equal(snapshot[FLAG].sum, 1);
- Assert.equal(subsession[FLAG].sum, 0);
-});
-
-add_task({
- skip_if: () => gIsAndroid
-},
-function* test_keyed_subsession() {
- let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_FLAG");
- const KEY = "foo";
-
- // Both original and subsession should start out the same.
- h.clear();
- Assert.ok(!(KEY in h.snapshot()));
- Assert.ok(!(KEY in h.subsessionSnapshot()));
- Assert.equal(h.snapshot(KEY).sum, 0);
- Assert.equal(h.subsessionSnapshot(KEY).sum, 0);
-
- // Both should register the flag.
- h.add(KEY, 1);
- Assert.ok(KEY in h.snapshot());
- Assert.ok(KEY in h.subsessionSnapshot());
- Assert.equal(h.snapshot(KEY).sum, 1);
- Assert.equal(h.subsessionSnapshot(KEY).sum, 1);
-
- // Check that we are able to only reset the subsession histogram.
- h.clear(true);
- Assert.ok(KEY in h.snapshot());
- Assert.ok(!(KEY in h.subsessionSnapshot()));
- Assert.equal(h.snapshot(KEY).sum, 1);
- Assert.equal(h.subsessionSnapshot(KEY).sum, 0);
-
- // Setting the flag again should make both match again.
- h.add(KEY, 1);
- Assert.ok(KEY in h.snapshot());
- Assert.ok(KEY in h.subsessionSnapshot());
- Assert.equal(h.snapshot(KEY).sum, 1);
- Assert.equal(h.subsessionSnapshot(KEY).sum, 1);
-
- // Check that "snapshot and clear" works properly.
- let snapshot = h.snapshot();
- let subsession = h.snapshotSubsessionAndClear();
- Assert.ok(KEY in snapshot);
- Assert.ok(KEY in subsession);
- Assert.equal(snapshot[KEY].sum, 1);
- Assert.equal(subsession[KEY].sum, 1);
-
- subsession = h.subsessionSnapshot();
- Assert.ok(!(KEY in subsession));
- Assert.equal(h.subsessionSnapshot(KEY).sum, 0);
-});
diff --git a/toolkit/components/telemetry/tests/unit/xpcshell.ini b/toolkit/components/telemetry/tests/unit/xpcshell.ini
deleted file mode 100644
index 224516f57..000000000
--- a/toolkit/components/telemetry/tests/unit/xpcshell.ini
+++ /dev/null
@@ -1,61 +0,0 @@
-[DEFAULT]
-head = head.js
-tail =
-firefox-appdir = browser
-# The *.xpi files are only needed for test_TelemetryEnvironment.js, but
-# xpcshell fails to install tests if we move them under the test entry.
-support-files =
- ../search/chrome.manifest
- ../search/searchTest.jar
- dictionary.xpi
- experiment.xpi
- extension.xpi
- extension-2.xpi
- engine.xml
- system.xpi
- restartless.xpi
- theme.xpi
-generated-files =
- dictionary.xpi
- experiment.xpi
- extension.xpi
- extension-2.xpi
- system.xpi
- restartless.xpi
- theme.xpi
-
-[test_nsITelemetry.js]
-[test_SubsessionChaining.js]
-tags = addons
-[test_TelemetryEnvironment.js]
-skip-if = os == "android"
-tags = addons
-[test_PingAPI.js]
-skip-if = os == "android"
-[test_TelemetryFlagClear.js]
-[test_TelemetryLateWrites.js]
-[test_TelemetryLockCount.js]
-[test_TelemetryLog.js]
-[test_TelemetryController.js]
-tags = addons
-[test_TelemetryController_idle.js]
-[test_TelemetryControllerShutdown.js]
-tags = addons
-[test_TelemetryControllerBuildID.js]
-[test_TelemetrySendOldPings.js]
-skip-if = os == "android" # Disabled due to intermittent orange on Android
-tags = addons
-[test_TelemetrySession.js]
-tags = addons
-[test_ThreadHangStats.js]
-run-sequentially = Bug 1046307, test can fail intermittently when CPU load is high
-[test_TelemetrySend.js]
-[test_ChildHistograms.js]
-skip-if = os == "android"
-tags = addons
-[test_TelemetryReportingPolicy.js]
-tags = addons
-[test_TelemetryScalars.js]
-[test_TelemetryTimestamps.js]
-skip-if = toolkit == 'android'
-[test_TelemetryEvents.js]