summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/test/unit/test_telemetry.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/passwordmgr/test/unit/test_telemetry.js')
-rw-r--r--toolkit/components/passwordmgr/test/unit/test_telemetry.js201
1 files changed, 201 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/test/unit/test_telemetry.js b/toolkit/components/passwordmgr/test/unit/test_telemetry.js
new file mode 100644
index 0000000000..56fe6233d9
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/unit/test_telemetry.js
@@ -0,0 +1,201 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests the statistics and other counters reported through telemetry.
+ */
+
+"use strict";
+
+// Globals
+
+const { TestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+);
+
+const MS_PER_DAY = 24 * 60 * 60 * 1000;
+
+// To prevent intermittent failures when the test is executed at a time that is
+// very close to a day boundary, we make it deterministic by using a static
+// reference date for all the time-based statistics.
+const gReferenceTimeMs = new Date("2000-01-01T00:00:00").getTime();
+
+// Returns a milliseconds value to use with nsILoginMetaInfo properties, falling
+// approximately in the middle of the specified number of days before the
+// reference time, where zero days indicates a time within the past 24 hours.
+const daysBeforeMs = days => gReferenceTimeMs - (days + 0.5) * MS_PER_DAY;
+
+/**
+ * Contains metadata that will be attached to test logins in order to verify
+ * that the statistics collection is working properly. Most properties of the
+ * logins are initialized to the default test values already.
+ *
+ * If you update this data or any of the telemetry histograms it checks, you'll
+ * probably need to update the expected statistics in the test below.
+ */
+const StatisticsTestData = [
+ {
+ timeLastUsed: daysBeforeMs(0),
+ },
+ {
+ timeLastUsed: daysBeforeMs(1),
+ },
+ {
+ timeLastUsed: daysBeforeMs(7),
+ formActionOrigin: null,
+ httpRealm: "The HTTP Realm",
+ },
+ {
+ username: "",
+ timeLastUsed: daysBeforeMs(7),
+ },
+ {
+ username: "",
+ timeLastUsed: daysBeforeMs(30),
+ },
+ {
+ username: "",
+ timeLastUsed: daysBeforeMs(31),
+ },
+ {
+ timeLastUsed: daysBeforeMs(365),
+ },
+ {
+ username: "",
+ timeLastUsed: daysBeforeMs(366),
+ },
+ {
+ // If the login was saved in the future, it is ignored for statistiscs.
+ timeLastUsed: daysBeforeMs(-1),
+ },
+ {
+ timeLastUsed: daysBeforeMs(1000),
+ },
+];
+
+/**
+ * Triggers the collection of those statistics that are not accumulated each
+ * time an action is taken, but are a static snapshot of the current state.
+ */
+async function triggerStatisticsCollection() {
+ Services.obs.notifyObservers(null, "gather-telemetry", "" + gReferenceTimeMs);
+ await TestUtils.topicObserved("passwordmgr-gather-telemetry-complete");
+}
+
+/**
+ * Tests the telemetry histogram with the given ID contains only the specified
+ * non-zero ranges, expressed in the format { range1: value1, range2: value2 }.
+ */
+function testHistogram(histogramId, expectedNonZeroRanges) {
+ let snapshot = Services.telemetry.getHistogramById(histogramId).snapshot();
+
+ // Compute the actual ranges in the format { range1: value1, range2: value2 }.
+ let actualNonZeroRanges = {};
+ for (let [range, value] of Object.entries(snapshot.values)) {
+ if (value > 0) {
+ actualNonZeroRanges[range] = value;
+ }
+ }
+
+ // These are stringified to visualize the differences between the values.
+ info("Testing histogram: " + histogramId);
+ Assert.equal(
+ JSON.stringify(actualNonZeroRanges),
+ JSON.stringify(expectedNonZeroRanges)
+ );
+}
+
+// Tests
+
+/**
+ * Enable local telemetry recording for the duration of the tests, and prepare
+ * the test data that will be used by the following tests.
+ */
+add_setup(async () => {
+ let oldCanRecord = Services.telemetry.canRecordExtended;
+ Services.telemetry.canRecordExtended = true;
+ registerCleanupFunction(function () {
+ Services.telemetry.canRecordExtended = oldCanRecord;
+ });
+
+ let uniqueNumber = 1;
+ let logins = [];
+ for (let loginModifications of StatisticsTestData) {
+ loginModifications.origin = `http://${uniqueNumber++}.example.com`;
+ if (typeof loginModifications.httpRealm != "undefined") {
+ logins.push(TestData.authLogin(loginModifications));
+ } else {
+ logins.push(TestData.formLogin(loginModifications));
+ }
+ }
+ await Services.logins.addLogins(logins);
+});
+
+/**
+ * Tests the collection of statistics related to login metadata.
+ */
+add_task(async function test_logins_statistics() {
+ // Repeat the operation twice to test that histograms are not accumulated.
+ for (let pass of [1, 2]) {
+ info(`pass ${pass}`);
+ await triggerStatisticsCollection();
+
+ // Should record 1 in the bucket corresponding to the number of passwords.
+ testHistogram("PWMGR_NUM_SAVED_PASSWORDS", { 10: 1 });
+
+ // Should record 1 in the bucket corresponding to the number of passwords.
+ testHistogram("PWMGR_NUM_HTTPAUTH_PASSWORDS", { 1: 1 });
+
+ // For each saved login, should record 1 in the bucket corresponding to the
+ // age in days since the login was last used.
+ testHistogram("PWMGR_LOGIN_LAST_USED_DAYS", {
+ 0: 1,
+ 1: 1,
+ 7: 2,
+ 29: 2,
+ 356: 2,
+ 750: 1,
+ });
+
+ // Should record the number of logins without a username in bucket 0, and
+ // the number of logins with a username in bucket 1.
+ testHistogram("PWMGR_USERNAME_PRESENT", { 0: 4, 1: 6 });
+ }
+});
+
+/**
+ * Tests the collection of statistics related to hosts for which passowrd saving
+ * has been explicitly disabled.
+ */
+add_task(async function test_disabledHosts_statistics() {
+ // Should record 1 in the bucket corresponding to the number of sites for
+ // which password saving is disabled.
+ Services.logins.setLoginSavingEnabled("http://www.example.com", false);
+ await triggerStatisticsCollection();
+ testHistogram("PWMGR_BLOCKLIST_NUM_SITES", { 1: 1 });
+
+ Services.logins.setLoginSavingEnabled("http://www.example.com", true);
+ await triggerStatisticsCollection();
+ testHistogram("PWMGR_BLOCKLIST_NUM_SITES", { 0: 1 });
+});
+
+/**
+ * Tests the collection of statistics related to general settings.
+ */
+add_task(async function test_settings_statistics() {
+ let oldRememberSignons = Services.prefs.getBoolPref("signon.rememberSignons");
+ registerCleanupFunction(function () {
+ Services.prefs.setBoolPref("signon.rememberSignons", oldRememberSignons);
+ });
+
+ // Repeat the operation twice per value to test that histograms are reset.
+ for (let remember of [false, true, false, true]) {
+ // This change should be observed immediately by the login service.
+ Services.prefs.setBoolPref("signon.rememberSignons", remember);
+
+ await triggerStatisticsCollection();
+
+ // Should record 1 in either bucket 0 or bucket 1 based on the preference.
+ testHistogram("PWMGR_SAVING_ENABLED", remember ? { 1: 1 } : { 0: 1 });
+ }
+});