summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js')
-rw-r--r--toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js2073
1 files changed, 2073 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js b/toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
new file mode 100644
index 0000000000..1ac0c76351
--- /dev/null
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
@@ -0,0 +1,2073 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const INT_MAX = 0x7fffffff;
+
+// 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 check_histogram(histogram_type, name, min, max, bucket_count) {
+ var h = Telemetry.getHistogramById(name);
+ h.add(0);
+ var s = h.snapshot();
+ Assert.equal(0, s.sum);
+
+ var hgrams = Telemetry.getSnapshotForHistograms("main", false).parent;
+ let gh = hgrams[name];
+ Assert.equal(gh.histogram_type, histogram_type);
+
+ Assert.deepEqual(gh.range, [min, max]);
+
+ // Check that booleans work with nonboolean histograms
+ h.add(false);
+ h.add(true);
+ s = Object.values(h.snapshot().values);
+ Assert.deepEqual(s, [2, 1, 0]);
+
+ // Check that clearing works.
+ h.clear();
+ s = h.snapshot();
+ Assert.deepEqual(s.values, {});
+ Assert.equal(s.sum, 0);
+
+ h.add(0);
+ h.add(1);
+ var c = Object.values(h.snapshot().values);
+ Assert.deepEqual(c, [1, 1, 0]);
+}
+
+// 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.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.ok(ID in subsession);
+ 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(async 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(async function test_parameterCounts() {
+ let histogramIds = [
+ "TELEMETRY_TEST_EXPONENTIAL",
+ "TELEMETRY_TEST_LINEAR",
+ "TELEMETRY_TEST_FLAG",
+ "TELEMETRY_TEST_CATEGORICAL",
+ "TELEMETRY_TEST_BOOLEAN",
+ ];
+
+ for (let id of histogramIds) {
+ let h = Telemetry.getHistogramById(id);
+ h.clear();
+ h.add();
+ Assert.equal(
+ h.snapshot().sum,
+ 0,
+ "Calling add() without a value should only log an error."
+ );
+ h.clear();
+ }
+});
+
+add_task(async function test_parameterCountsKeyed() {
+ let histogramIds = [
+ "TELEMETRY_TEST_KEYED_FLAG",
+ "TELEMETRY_TEST_KEYED_BOOLEAN",
+ "TELEMETRY_TEST_KEYED_EXPONENTIAL",
+ "TELEMETRY_TEST_KEYED_LINEAR",
+ ];
+
+ for (let id of histogramIds) {
+ let h = Telemetry.getKeyedHistogramById(id);
+ h.clear();
+ h.add("key");
+ Assert.deepEqual(
+ h.snapshot(),
+ {},
+ "Calling add('key') without a value should only log an error."
+ );
+ h.clear();
+ }
+});
+
+add_task(async 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");
+ let histograms = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.equal(false, "NEWTAB_PAGE_PINNED_SITES_COUNT" in histograms);
+});
+
+add_task(async function test_boolean_histogram() {
+ var h = Telemetry.getHistogramById("TELEMETRY_TEST_BOOLEAN");
+ var r = h.snapshot().range;
+ // boolean histograms ignore numeric parameters
+ Assert.deepEqual(r, [1, 2]);
+ h.add(0);
+ h.add(1);
+ h.add(2);
+
+ h.add(true);
+ h.add(false);
+ var s = h.snapshot();
+ Assert.equal(s.histogram_type, Telemetry.HISTOGRAM_BOOLEAN);
+ // last bucket should always be 0 since .add parameters are normalized to either 0 or 1
+ Assert.deepEqual(s.values, { 0: 2, 1: 3, 2: 0 });
+ Assert.equal(s.sum, 3);
+});
+
+add_task(async function test_flag_histogram() {
+ var h = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG");
+ var r = h.snapshot().range;
+ // Flag histograms ignore numeric parameters.
+ Assert.deepEqual(r, [1, 2]);
+ // Should already have a 0 counted.
+ var v = h.snapshot().values;
+ var s = h.snapshot().sum;
+ Assert.deepEqual(v, { 0: 1, 1: 0 });
+ Assert.equal(s, 0);
+ // Should switch counts.
+ h.add(1);
+ var v2 = h.snapshot().values;
+ var s2 = h.snapshot().sum;
+ Assert.deepEqual(v2, { 0: 0, 1: 1, 2: 0 });
+ Assert.equal(s2, 1);
+ // Should only switch counts once.
+ h.add(1);
+ var v3 = h.snapshot().values;
+ var s3 = h.snapshot().sum;
+ Assert.deepEqual(v3, { 0: 0, 1: 1, 2: 0 });
+ Assert.equal(s3, 1);
+ Assert.equal(h.snapshot().histogram_type, Telemetry.HISTOGRAM_FLAG);
+});
+
+add_task(async function test_count_histogram() {
+ let h = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT2");
+ let s = h.snapshot();
+ Assert.deepEqual(s.range, [1, 2]);
+ Assert.deepEqual(s.values, {});
+ Assert.equal(s.sum, 0);
+ h.add();
+ s = h.snapshot();
+ Assert.deepEqual(s.values, { 0: 1, 1: 0 });
+ Assert.equal(s.sum, 1);
+ h.add();
+ s = h.snapshot();
+ Assert.deepEqual(s.values, { 0: 2, 1: 0 });
+ Assert.equal(s.sum, 2);
+});
+
+add_task(async 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"]) {
+ // The |add| method should not throw for unexpected values, but rather
+ // print an error message in the console.
+ h1.add(s);
+ }
+
+ let snapshot = h1.snapshot();
+ Assert.equal(snapshot.sum, 6);
+ Assert.deepEqual(snapshot.range, [1, 50]);
+ Assert.deepEqual(snapshot.values, { 0: 3, 1: 2, 2: 2, 3: 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"]) {
+ // The |add| method should not throw for unexpected values, but rather
+ // print an error message in the console.
+ h2.add(s);
+ }
+
+ snapshot = h2.snapshot();
+ Assert.equal(snapshot.sum, 7);
+ Assert.deepEqual(snapshot.range, [1, 50]);
+ Assert.deepEqual(snapshot.values, { 0: 3, 1: 2, 2: 1, 3: 1, 4: 0 });
+
+ // This histogram overrides the default of 50 values to 70.
+ let h3 = Telemetry.getHistogramById("TELEMETRY_TEST_CATEGORICAL_NVALUES");
+ for (let v of ["CommonLabel", "Label7", "Label8"]) {
+ h3.add(v);
+ }
+
+ snapshot = h3.snapshot();
+ Assert.equal(snapshot.sum, 3);
+ Assert.deepEqual(snapshot.range, [1, 70]);
+ Assert.deepEqual(snapshot.values, { 0: 1, 1: 1, 2: 1, 3: 0 });
+});
+
+add_task(async function test_getCategoricalLabels() {
+ let h = Telemetry.getCategoricalLabels();
+
+ Assert.deepEqual(h.TELEMETRY_TEST_CATEGORICAL, [
+ "CommonLabel",
+ "Label2",
+ "Label3",
+ ]);
+ Assert.deepEqual(h.TELEMETRY_TEST_CATEGORICAL_OPTOUT, [
+ "CommonLabel",
+ "Label4",
+ "Label5",
+ "Label6",
+ ]);
+ Assert.deepEqual(h.TELEMETRY_TEST_CATEGORICAL_NVALUES, [
+ "CommonLabel",
+ "Label7",
+ "Label8",
+ ]);
+ Assert.deepEqual(h.TELEMETRY_TEST_KEYED_CATEGORICAL, [
+ "CommonLabel",
+ "Label2",
+ "Label3",
+ ]);
+});
+
+add_task(async function test_add_error_behaviour() {
+ const PLAIN_HISTOGRAMS_TO_TEST = [
+ "TELEMETRY_TEST_FLAG",
+ "TELEMETRY_TEST_EXPONENTIAL",
+ "TELEMETRY_TEST_LINEAR",
+ "TELEMETRY_TEST_BOOLEAN",
+ ];
+
+ const KEYED_HISTOGRAMS_TO_TEST = [
+ "TELEMETRY_TEST_KEYED_FLAG",
+ "TELEMETRY_TEST_KEYED_COUNT",
+ "TELEMETRY_TEST_KEYED_BOOLEAN",
+ ];
+
+ // Check that |add| doesn't throw for plain histograms.
+ for (let hist of PLAIN_HISTOGRAMS_TO_TEST) {
+ const returnValue =
+ Telemetry.getHistogramById(hist).add("unexpected-value");
+ Assert.strictEqual(
+ returnValue,
+ undefined,
+ "Adding to an histogram must return 'undefined'."
+ );
+ }
+
+ // And for keyed histograms.
+ for (let hist of KEYED_HISTOGRAMS_TO_TEST) {
+ const returnValue = Telemetry.getKeyedHistogramById(hist).add(
+ "some-key",
+ "unexpected-value"
+ );
+ Assert.strictEqual(
+ returnValue,
+ undefined,
+ "Adding to a keyed histogram must return 'undefined'."
+ );
+ }
+});
+
+add_task(async function test_API_return_values() {
+ // Check that the plain scalar functions don't allow to crash the browser.
+ // We expect 'undefined' to be returned so that .add(1).add() can't be called.
+ // See bug 1321349 for context.
+ let hist = Telemetry.getHistogramById("TELEMETRY_TEST_LINEAR");
+ let keyedHist = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_COUNT");
+
+ const RETURN_VALUES = [
+ hist.clear(),
+ hist.add(1),
+ keyedHist.clear(),
+ keyedHist.add("some-key", 1),
+ ];
+
+ for (let returnValue of RETURN_VALUES) {
+ Assert.strictEqual(
+ returnValue,
+ undefined,
+ "The function must return undefined"
+ );
+ }
+});
+
+add_task(async 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();
+ Assert.equal(s.histogram_type, Telemetry.HISTOGRAM_EXPONENTIAL);
+ Assert.deepEqual(s.range, [1, 10000]);
+});
+
+add_task(async function test_getSlowSQL() {
+ var slow = Telemetry.slowSQL;
+ Assert.ok("mainThread" in slow && "otherThreads" in slow);
+});
+
+// Check that telemetry doesn't record in private mode
+add_task(async function test_privateMode() {
+ var h = Telemetry.getHistogramById("TELEMETRY_TEST_BOOLEAN");
+ var orig = h.snapshot();
+ Telemetry.canRecordExtended = false;
+ h.add(1);
+ Assert.deepEqual(orig, h.snapshot());
+ Telemetry.canRecordExtended = true;
+ h.add(1);
+ Assert.notDeepEqual(orig, h.snapshot());
+});
+
+// Check that telemetry records only when it is suppose to.
+add_task(async 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(async function test_expired_histogram() {
+ var test_expired_id = "TELEMETRY_TEST_EXPIRED";
+ var dummy = Telemetry.getHistogramById(test_expired_id);
+
+ dummy.add(1);
+
+ for (let process of ["main", "content", "gpu", "extension"]) {
+ let histograms = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ );
+ if (!(process in histograms)) {
+ info("Nothing present for process " + process);
+ continue;
+ }
+ Assert.equal(histograms[process].__expired__, undefined);
+ }
+ let parentHgrams = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.equal(parentHgrams[test_expired_id], undefined);
+});
+
+add_task(async function test_keyed_expired_histogram() {
+ var test_expired_id = "TELEMETRY_TEST_EXPIRED_KEYED";
+ var dummy = Telemetry.getKeyedHistogramById(test_expired_id);
+ dummy.add("someKey", 1);
+
+ const histograms = Telemetry.getSnapshotForKeyedHistograms(
+ "main",
+ false /* clear */
+ );
+ for (let process of ["parent", "content", "gpu", "extension"]) {
+ if (!(process in histograms)) {
+ info("Nothing present for process " + process);
+ continue;
+ }
+ Assert.ok(
+ !(test_expired_id in histograms[process]),
+ "The expired keyed histogram must not be reported"
+ );
+ }
+});
+
+add_task(async 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(async 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 = {
+ range: [1, 2],
+ bucket_count: 3,
+ histogram_type: 2,
+ sum: 1,
+ values: { 0: 0, 1: 1, 2: 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].values = { 0: 1, 1: 0 };
+ Assert.deepEqual(h.keys().sort(), testKeys);
+ Assert.deepEqual(h.snapshot(), testSnapShot);
+
+ let parentHgrams = Telemetry.getSnapshotForKeyedHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.deepEqual(parentHgrams[KEYED_ID], testSnapShot);
+
+ h.clear();
+ Assert.deepEqual(h.keys(), []);
+ Assert.deepEqual(h.snapshot(), {});
+});
+
+add_task(async function test_keyed_count_histogram() {
+ const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
+ const KEYS = numberRange(0, 5).map(i => "key" + (i + 1));
+ let histogramBase = {
+ range: [1, 2],
+ bucket_count: 3,
+ histogram_type: 4,
+ sum: 0,
+ values: { 0: 1, 1: 0 },
+ };
+ let testHistograms = numberRange(0, 5).map(i =>
+ JSON.parse(JSON.stringify(histogramBase))
+ );
+ let testKeys = [];
+ let testSnapShot = {};
+
+ let h = Telemetry.getKeyedHistogramById(KEYED_ID);
+ h.clear();
+ 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].values[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].values[0] = 1;
+ testHistograms[4].sum = 1;
+ testSnapShot[key] = testHistograms[4];
+
+ Assert.deepEqual(h.keys().sort(), testKeys);
+ Assert.deepEqual(h.snapshot(), testSnapShot);
+
+ let parentHgrams = Telemetry.getSnapshotForKeyedHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.deepEqual(parentHgrams[KEYED_ID], testSnapShot);
+
+ // Test clearing categorical histogram.
+ h.clear();
+ Assert.deepEqual(h.keys(), []);
+ Assert.deepEqual(h.snapshot(), {});
+
+ // Test leaving out the value argument. That should increment by 1.
+ h.add("key");
+ Assert.equal(h.snapshot().key.sum, 1);
+});
+
+add_task(async function test_keyed_categorical_histogram() {
+ const KEYED_ID = "TELEMETRY_TEST_KEYED_CATEGORICAL";
+ const KEYS = numberRange(0, 5).map(i => "key" + (i + 1));
+
+ let h = Telemetry.getKeyedHistogramById(KEYED_ID);
+
+ for (let k of KEYS) {
+ // Test adding both per label and index.
+ for (let v of ["CommonLabel", "Label2", "Label3", "Label3", 0, 0, 1]) {
+ h.add(k, v);
+ }
+
+ // The |add| method should not throw for unexpected values, but rather
+ // print an error message in the console.
+ for (let s of ["", "Label4", "1234"]) {
+ h.add(k, s);
+ }
+ }
+
+ // Check that the set of keys in the snapshot is what we expect.
+ let snapshot = h.snapshot();
+ let snapshotKeys = Object.keys(snapshot);
+ Assert.equal(KEYS.length, snapshotKeys.length);
+ Assert.ok(KEYS.every(k => snapshotKeys.includes(k)));
+
+ // Check the snapshot values.
+ for (let k of KEYS) {
+ Assert.ok(k in snapshot);
+ Assert.equal(snapshot[k].sum, 6);
+ Assert.deepEqual(snapshot[k].range, [1, 50]);
+ Assert.deepEqual(snapshot[k].values, { 0: 3, 1: 2, 2: 2, 3: 0 });
+ }
+});
+
+add_task(async 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] = {
+ range: [1, 2],
+ bucket_count: 3,
+ histogram_type: 3,
+ sum: 1,
+ values: { 0: 0, 1: 1, 2: 0 },
+ };
+
+ Assert.deepEqual(h.keys().sort(), [KEY]);
+ Assert.deepEqual(h.snapshot(), testSnapshot);
+
+ let parentHgrams = Telemetry.getSnapshotForKeyedHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.deepEqual(parentHgrams[KEYED_ID], testSnapshot);
+
+ h.clear();
+ Assert.deepEqual(h.keys(), []);
+ Assert.deepEqual(h.snapshot(), {});
+});
+
+add_task(async 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.ok(!(TEST_KEY in h.snapshot()));
+
+ // 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.ok(
+ !(TEST_KEY in h.snapshot()),
+ "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(async 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(async 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.ok(
+ !(TEST_KEY in h.snapshot()),
+ "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(async function test_histogramSnapshots() {
+ let keyed = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_COUNT");
+ keyed.add("a", 1);
+
+ // Check that keyed histograms are not returned
+ let parentHgrams = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.ok(!("TELEMETRY_TEST_KEYED_COUNT" in parentHgrams));
+});
+
+add_task(async function test_datasets() {
+ // Check that datasets work as expected.
+
+ const currentRecordExtended = Telemetry.canRecordExtended;
+
+ // Clear everything out
+ Telemetry.getSnapshotForHistograms("main", true /* clear */);
+ Telemetry.getSnapshotForKeyedHistograms("main", true /* clear */);
+
+ // Empty histograms are filtered. Let's record what we check below.
+ Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTIN").add(1);
+ Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTOUT").add(1);
+ // Keyed flag histograms are skipped if empty, let's add data
+ Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_FLAG").add("a", 1);
+ Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTIN").add(
+ "a",
+ 1
+ );
+ Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT").add(
+ "a",
+ 1
+ );
+
+ // Check that registeredHistogram works properly
+ Telemetry.canRecordExtended = true;
+ let registered = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ );
+ registered = new Set(Object.keys(registered.parent));
+ Assert.ok(registered.has("TELEMETRY_TEST_FLAG"));
+ Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTIN"));
+ Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTOUT"));
+ Telemetry.canRecordExtended = false;
+ registered = Telemetry.getSnapshotForHistograms("main", false /* clear */);
+ registered = new Set(Object.keys(registered.parent));
+ 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
+ Telemetry.canRecordExtended = true;
+ registered = Telemetry.getSnapshotForKeyedHistograms(
+ "main",
+ false /* clear */
+ );
+ registered = new Set(Object.keys(registered.parent));
+ Assert.ok(registered.has("TELEMETRY_TEST_KEYED_FLAG"));
+ Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
+ Telemetry.canRecordExtended = false;
+ registered = Telemetry.getSnapshotForKeyedHistograms(
+ "main",
+ false /* clear */
+ );
+ registered = new Set(Object.keys(registered.parent));
+ Assert.ok(!registered.has("TELEMETRY_TEST_KEYED_FLAG"));
+ Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
+
+ Telemetry.canRecordExtended = currentRecordExtended;
+});
+
+add_task(async function test_keyed_keys() {
+ let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_KEYS");
+ h.clear();
+ Telemetry.clearScalars();
+
+ // The |add| method should not throw for keys that are not allowed.
+ h.add("testkey", true);
+ h.add("thirdKey", false);
+ h.add("not-allowed", true);
+
+ // Check that we have the expected keys.
+ let snap = h.snapshot();
+ Assert.equal(Object.keys(snap).length, 2, "Only 2 keys must be recorded.");
+ Assert.ok("testkey" in snap, "'testkey' must be recorded.");
+ Assert.ok("thirdKey" in snap, "'thirdKey' must be recorded.");
+ Assert.deepEqual(
+ snap.testkey.values,
+ { 0: 0, 1: 1, 2: 0 },
+ "'testkey' must contain the correct value."
+ );
+ Assert.deepEqual(
+ snap.thirdKey.values,
+ { 0: 1, 1: 0 },
+ "'thirdKey' must contain the correct value."
+ );
+
+ // Keys that are not allowed must not be recorded.
+ Assert.ok(!("not-allowed" in snap), "'not-allowed' must not be recorded.");
+
+ // Check that these failures were correctly tracked.
+ const parentScalars = Telemetry.getSnapshotForKeyedScalars(
+ "main",
+ false
+ ).parent;
+ const scalarName = "telemetry.accumulate_unknown_histogram_keys";
+ Assert.ok(
+ scalarName in parentScalars,
+ "Accumulation to unallowed keys must be reported."
+ );
+ Assert.ok(
+ "TELEMETRY_TEST_KEYED_KEYS" in parentScalars[scalarName],
+ "Accumulation to unallowed keys must be recorded with the correct key."
+ );
+ Assert.equal(
+ parentScalars[scalarName].TELEMETRY_TEST_KEYED_KEYS,
+ 1,
+ "Accumulation to unallowed keys must report the correct value."
+ );
+});
+
+add_task(async function test_count_multiple_samples() {
+ let valid = [1, 1, 3, 0];
+ let invalid = ["1", "0", "", "random"];
+
+ let h = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
+ h.clear();
+
+ // If the array contains even a single invalid value, no accumulation should take place
+ // Keep the valid values in front of invalid to check if it is simply accumulating as
+ // it's traversing the array and throwing upon first invalid value. That should not happen.
+ h.add(valid.concat(invalid));
+ let s1 = h.snapshot();
+ Assert.equal(s1.sum, 0);
+ // Ensure that no accumulations of 0-like values took place.
+ // These accumulations won't increase the sum.
+ Assert.deepEqual({}, s1.values);
+
+ h.add(valid);
+ let s2 = h.snapshot();
+ Assert.deepEqual(s2.values, { 0: 4, 1: 0 });
+ Assert.equal(s2.sum, 5);
+});
+
+add_task(async function test_categorical_multiple_samples() {
+ let h = Telemetry.getHistogramById("TELEMETRY_TEST_CATEGORICAL");
+ h.clear();
+ let valid = ["CommonLabel", "Label2", "Label3", "Label3", 0, 0, 1];
+ let invalid = ["", "Label4", "1234", "0", "1", 5000];
+
+ // At least one invalid parameter, so no accumulation should happen here
+ // Valid values in front of invalid.
+ h.add(valid.concat(invalid));
+ let s1 = h.snapshot();
+ Assert.equal(s1.sum, 0);
+ Assert.deepEqual({}, s1.values);
+
+ h.add(valid);
+ let snapshot = h.snapshot();
+ Assert.equal(snapshot.sum, 6);
+ Assert.deepEqual(snapshot.values, { 0: 3, 1: 2, 2: 2, 3: 0 });
+});
+
+add_task(async function test_boolean_multiple_samples() {
+ let valid = [true, false, 0, 1, 2];
+ let invalid = ["", "0", "1", ",2", "true", "false", "random"];
+
+ let h = Telemetry.getHistogramById("TELEMETRY_TEST_BOOLEAN");
+ h.clear();
+
+ // At least one invalid parameter, so no accumulation should happen here
+ // Valid values in front of invalid.
+ h.add(valid.concat(invalid));
+ let s1 = h.snapshot();
+ Assert.equal(s1.sum, 0);
+ Assert.deepEqual({}, s1.values);
+
+ h.add(valid);
+ let s = h.snapshot();
+ Assert.deepEqual(s.values, { 0: 2, 1: 3, 2: 0 });
+ Assert.equal(s.sum, 3);
+});
+
+add_task(async function test_linear_multiple_samples() {
+ // According to telemetry.mozilla.org/histogram-simulator, bucket at
+ // index 1 of TELEMETRY_TEST_LINEAR has max value of 268.44M
+ let valid = [0, 1, 5, 10, 268450000, 268450001, Math.pow(2, 31) + 1];
+ let invalid = ["", "0", "1", "random"];
+
+ let h = Telemetry.getHistogramById("TELEMETRY_TEST_LINEAR");
+ h.clear();
+
+ // At least one invalid paramater, so no accumulations.
+ // Valid values in front of invalid.
+ h.add(valid.concat(invalid));
+ let s1 = h.snapshot();
+ Assert.equal(s1.sum, 0);
+ Assert.deepEqual({}, s1.values);
+
+ h.add(valid);
+ let s2 = h.snapshot();
+ // Values >= INT32_MAX are accumulated as INT32_MAX - 1
+ Assert.equal(s2.sum, valid.reduce((acc, cur) => acc + cur) - 3);
+ Assert.deepEqual(Object.values(s2.values), [1, 3, 2, 1]);
+});
+
+add_task(async function test_keyed_no_arguments() {
+ // Test for no accumulation when add is called with no arguments
+ let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_LINEAR");
+ h.clear();
+
+ h.add();
+
+ // No keys should be added due to no accumulation.
+ Assert.equal(h.keys().length, 0);
+});
+
+add_task(async function test_keyed_categorical_invalid_string() {
+ // Test for no accumulation when add is called on a
+ // keyed categorical histogram with an invalid string label.
+ let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_CATEGORICAL");
+ h.clear();
+
+ h.add("someKey", "#notALabel");
+
+ // No keys should be added due to no accumulation.
+ Assert.equal(h.keys().length, 0);
+});
+
+add_task(async function test_keyed_count_multiple_samples() {
+ let valid = [1, 1, 3, 0];
+ let invalid = ["1", "0", "", "random"];
+ let key = "somekeystring";
+
+ let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_COUNT");
+ h.clear();
+
+ // If the array contains even a single invalid value, no accumulation should take place
+ // Keep the valid values in front of invalid to check if it is simply accumulating as
+ // it's traversing the array and throwing upon first invalid value. That should not happen.
+ h.add(key, valid.concat(invalid));
+ let s1 = h.snapshot();
+ Assert.ok(!(key in s1));
+
+ h.add(key, valid);
+ let s2 = h.snapshot()[key];
+ Assert.deepEqual(s2.values, { 0: 4, 1: 0 });
+ Assert.equal(s2.sum, 5);
+});
+
+add_task(async function test_keyed_categorical_multiple_samples() {
+ let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_CATEGORICAL");
+ h.clear();
+ let valid = ["CommonLabel", "Label2", "Label3", "Label3", 0, 0, 1];
+ let invalid = ["", "Label4", "1234", "0", "1", 5000];
+ let key = "somekeystring";
+
+ // At least one invalid parameter, so no accumulation should happen here
+ // Valid values in front of invalid.
+ h.add(key, valid.concat(invalid));
+ let s1 = h.snapshot();
+ Assert.ok(!(key in s1));
+
+ h.add(key, valid);
+ let snapshot = h.snapshot()[key];
+ Assert.equal(snapshot.sum, 6);
+ Assert.deepEqual(Object.values(snapshot.values), [3, 2, 2, 0]);
+});
+
+add_task(async function test_keyed_boolean_multiple_samples() {
+ let valid = [true, false, 0, 1, 2];
+ let invalid = ["", "0", "1", ",2", "true", "false", "random"];
+ let key = "somekey";
+
+ let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_BOOLEAN");
+ h.clear();
+
+ // At least one invalid parameter, so no accumulation should happen here
+ // Valid values in front of invalid.
+ h.add(key, valid.concat(invalid));
+ let s1 = h.snapshot();
+ Assert.ok(!(key in s1));
+
+ h.add(key, valid);
+ let s = h.snapshot()[key];
+ Assert.deepEqual(s.values, { 0: 2, 1: 3, 2: 0 });
+ Assert.equal(s.sum, 3);
+});
+
+add_task(async function test_keyed_linear_multiple_samples() {
+ // According to telemetry.mozilla.org/histogram-simulator, bucket at
+ // index 1 of TELEMETRY_TEST_LINEAR has max value of 3.13K
+ let valid = [0, 1, 5, 10, 268450000, 268450001, Math.pow(2, 31) + 1];
+ let invalid = ["", "0", "1", "random"];
+ let key = "somestring";
+
+ let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_LINEAR");
+ h.clear();
+
+ // At least one invalid paramater, so no accumulations.
+ // Valid values in front of invalid.
+ h.add(key, valid.concat(invalid));
+ let s1 = h.snapshot();
+ Assert.ok(!(key in s1));
+
+ h.add(key, valid);
+ let s2 = h.snapshot()[key];
+ // Values >= INT32_MAX are accumulated as INT32_MAX - 1
+ Assert.equal(s2.sum, valid.reduce((acc, cur) => acc + cur) - 3);
+ Assert.deepEqual(s2.range, [1, 250000]);
+ Assert.deepEqual(s2.values, { 0: 1, 1: 3, 250000: 3 });
+});
+
+add_task(async function test_non_array_non_string_obj() {
+ let invalid_obj = {
+ prop1: "someValue",
+ prop2: "someOtherValue",
+ };
+ let key = "someString";
+
+ let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_LINEAR");
+ h.clear();
+
+ h.add(key, invalid_obj);
+ Assert.equal(h.keys().length, 0);
+});
+
+add_task(
+ {
+ skip_if: () => gIsAndroid,
+ },
+ async function test_productSpecificHistograms() {
+ const DEFAULT_PRODUCTS_HISTOGRAM = "TELEMETRY_TEST_DEFAULT_PRODUCTS";
+ const DESKTOP_ONLY_HISTOGRAM = "TELEMETRY_TEST_DESKTOP_ONLY";
+ const MULTIPRODUCT_HISTOGRAM = "TELEMETRY_TEST_MULTIPRODUCT";
+ const MOBILE_ONLY_HISTOGRAM = "TELEMETRY_TEST_MOBILE_ONLY";
+
+ var default_histo = Telemetry.getHistogramById(DEFAULT_PRODUCTS_HISTOGRAM);
+ var desktop_histo = Telemetry.getHistogramById(DESKTOP_ONLY_HISTOGRAM);
+ var multiproduct_histo = Telemetry.getHistogramById(MULTIPRODUCT_HISTOGRAM);
+ var mobile_histo = Telemetry.getHistogramById(MOBILE_ONLY_HISTOGRAM);
+ default_histo.clear();
+ desktop_histo.clear();
+ multiproduct_histo.clear();
+ mobile_histo.clear();
+
+ default_histo.add(42);
+ desktop_histo.add(42);
+ multiproduct_histo.add(42);
+ mobile_histo.add(42);
+
+ let histograms = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+
+ Assert.ok(
+ DEFAULT_PRODUCTS_HISTOGRAM in histograms,
+ "Should have recorded default products histogram"
+ );
+ Assert.ok(
+ DESKTOP_ONLY_HISTOGRAM in histograms,
+ "Should have recorded desktop-only histogram"
+ );
+ Assert.ok(
+ MULTIPRODUCT_HISTOGRAM in histograms,
+ "Should have recorded multiproduct histogram"
+ );
+
+ Assert.ok(
+ !(MOBILE_ONLY_HISTOGRAM in histograms),
+ "Should not have recorded mobile-only histogram"
+ );
+ }
+);
+
+add_task(
+ {
+ skip_if: () => !gIsAndroid,
+ },
+ async function test_mobileSpecificHistograms() {
+ const DEFAULT_PRODUCTS_HISTOGRAM = "TELEMETRY_TEST_DEFAULT_PRODUCTS";
+ const DESKTOP_ONLY_HISTOGRAM = "TELEMETRY_TEST_DESKTOP_ONLY";
+ const MULTIPRODUCT_HISTOGRAM = "TELEMETRY_TEST_MULTIPRODUCT";
+ const MOBILE_ONLY_HISTOGRAM = "TELEMETRY_TEST_MOBILE_ONLY";
+
+ var default_histo = Telemetry.getHistogramById(DEFAULT_PRODUCTS_HISTOGRAM);
+ var desktop_histo = Telemetry.getHistogramById(DESKTOP_ONLY_HISTOGRAM);
+ var multiproduct_histo = Telemetry.getHistogramById(MULTIPRODUCT_HISTOGRAM);
+ var mobile_histo = Telemetry.getHistogramById(MOBILE_ONLY_HISTOGRAM);
+ default_histo.clear();
+ desktop_histo.clear();
+ multiproduct_histo.clear();
+ mobile_histo.clear();
+
+ default_histo.add(1);
+ desktop_histo.add(1);
+ multiproduct_histo.add(1);
+ mobile_histo.add(1);
+
+ let histograms = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+
+ Assert.ok(
+ DEFAULT_PRODUCTS_HISTOGRAM in histograms,
+ "Should have recorded default products histogram"
+ );
+ Assert.ok(
+ MOBILE_ONLY_HISTOGRAM in histograms,
+ "Should have recorded mobile-only histogram"
+ );
+ Assert.ok(
+ MULTIPRODUCT_HISTOGRAM in histograms,
+ "Should have recorded multiproduct histogram"
+ );
+
+ Assert.ok(
+ !(DESKTOP_ONLY_HISTOGRAM in histograms),
+ "Should not have recorded desktop-only histogram"
+ );
+ }
+);
+
+add_task(async function test_productsOverride() {
+ Services.prefs.setBoolPref(
+ "toolkit.telemetry.testing.overrideProductsCheck",
+ true
+ );
+ const DEFAULT_PRODUCTS_HISTOGRAM = "TELEMETRY_TEST_DEFAULT_PRODUCTS";
+ const DESKTOP_ONLY_HISTOGRAM = "TELEMETRY_TEST_DESKTOP_ONLY";
+ const MULTIPRODUCT_HISTOGRAM = "TELEMETRY_TEST_MULTIPRODUCT";
+ const MOBILE_ONLY_HISTOGRAM = "TELEMETRY_TEST_MOBILE_ONLY";
+
+ var default_histo = Telemetry.getHistogramById(DEFAULT_PRODUCTS_HISTOGRAM);
+ var desktop_histo = Telemetry.getHistogramById(DESKTOP_ONLY_HISTOGRAM);
+ var multiproduct_histo = Telemetry.getHistogramById(MULTIPRODUCT_HISTOGRAM);
+ var mobile_histo = Telemetry.getHistogramById(MOBILE_ONLY_HISTOGRAM);
+ default_histo.clear();
+ desktop_histo.clear();
+ multiproduct_histo.clear();
+ mobile_histo.clear();
+
+ default_histo.add(1);
+ desktop_histo.add(1);
+ multiproduct_histo.add(1);
+ mobile_histo.add(1);
+
+ let histograms = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+
+ Assert.ok(
+ DEFAULT_PRODUCTS_HISTOGRAM in histograms,
+ "Should have recorded default products histogram"
+ );
+ Assert.ok(
+ MOBILE_ONLY_HISTOGRAM in histograms,
+ "Should have recorded mobile-only histogram"
+ );
+ Assert.ok(
+ MULTIPRODUCT_HISTOGRAM in histograms,
+ "Should have recorded multiproduct histogram"
+ );
+
+ Assert.ok(
+ DESKTOP_ONLY_HISTOGRAM in histograms,
+ "Should not have recorded desktop-only histogram"
+ );
+ Services.prefs.clearUserPref(
+ "toolkit.telemetry.testing.overrideProductsCheck"
+ );
+});
+
+add_task(
+ {
+ skip_if: () => gIsAndroid,
+ },
+ async function test_clearHistogramsOnSnapshot() {
+ const COUNT = "TELEMETRY_TEST_COUNT";
+ let h = Telemetry.getHistogramById(COUNT);
+ h.clear();
+ let snapshot;
+
+ // The first snapshot should be empty, nothing recorded.
+ snapshot = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.ok(!(COUNT in snapshot));
+
+ // After recording into a histogram, the data should be in the snapshot. Don't delete it.
+ h.add(1);
+
+ Assert.equal(h.snapshot().sum, 1);
+ snapshot = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.ok(COUNT in snapshot);
+ Assert.equal(snapshot[COUNT].sum, 1);
+
+ // After recording into a histogram again, the data should be updated and in the snapshot.
+ // Clean up after.
+ h.add(41);
+
+ Assert.equal(h.snapshot().sum, 42);
+ snapshot = Telemetry.getSnapshotForHistograms(
+ "main",
+ true /* clear */
+ ).parent;
+ Assert.ok(COUNT in snapshot);
+ Assert.equal(snapshot[COUNT].sum, 42);
+
+ // Finally, no data should be in the snapshot.
+ Assert.equal(h.snapshot().sum, 0);
+ snapshot = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.ok(!(COUNT in snapshot));
+ }
+);
+
+add_task(async function test_valid_os_smoketest() {
+ let nonExistingProbe;
+ let existingProbe;
+
+ switch (AppConstants.platform) {
+ case "linux":
+ nonExistingProbe = "TELEMETRY_TEST_OS_ANDROID_ONLY";
+ existingProbe = "TELEMETRY_TEST_OS_LINUX_ONLY";
+ break;
+ case "macosx":
+ nonExistingProbe = "TELEMETRY_TEST_OS_ANDROID_ONLY";
+ existingProbe = "TELEMETRY_TEST_OS_MAC_ONLY";
+ break;
+ case "win":
+ nonExistingProbe = "TELEMETRY_TEST_OS_ANDROID_ONLY";
+ existingProbe = "TELEMETRY_TEST_OS_WIN_ONLY";
+ break;
+ case "android":
+ nonExistingProbe = "TELEMETRY_TEST_OS_LINUX_ONLY";
+ existingProbe = "TELEMETRY_TEST_OS_ANDROID_ONLY";
+ break;
+ default:
+ /* Unknown OS. Let's not test OS-specific probes */
+ return;
+ }
+
+ Assert.throws(
+ () => Telemetry.getHistogramById(nonExistingProbe),
+ /NS_ERROR_FAILURE/,
+ `Should throw on ${nonExistingProbe} probe that's not available on ${AppConstants.platform}`
+ );
+
+ let h = Telemetry.getHistogramById(existingProbe);
+ h.clear();
+ h.add(1);
+ let snapshot = Telemetry.getSnapshotForHistograms(
+ "main",
+ false /* clear */
+ ).parent;
+ Assert.ok(
+ existingProbe in snapshot,
+ `${existingProbe} should be recorded on ${AppConstants.platform}`
+ );
+ Assert.equal(snapshot[existingProbe].sum, 1);
+});
+
+add_task(async function test_multistore_individual_histogram() {
+ Telemetry.canRecordExtended = true;
+
+ let id;
+ let hist;
+ let snapshot;
+
+ id = "TELEMETRY_TEST_MAIN_ONLY";
+ hist = Telemetry.getHistogramById(id);
+ snapshot = hist.snapshot();
+ Assert.equal(0, snapshot.sum, `Histogram ${id} should be empty.`);
+ hist.add(1);
+ snapshot = hist.snapshot();
+ Assert.equal(
+ 1,
+ snapshot.sum,
+ `Histogram ${id} should have recorded one value.`
+ );
+ hist.clear();
+ snapshot = hist.snapshot();
+ Assert.equal(0, snapshot.sum, `Histogram ${id} should be cleared.`);
+
+ id = "TELEMETRY_TEST_MULTIPLE_STORES";
+ hist = Telemetry.getHistogramById(id);
+ snapshot = hist.snapshot();
+ Assert.equal(0, snapshot.sum, `Histogram ${id} should be empty.`);
+ hist.add(1);
+ snapshot = hist.snapshot();
+ Assert.equal(
+ 1,
+ snapshot.sum,
+ `Histogram ${id} should have recorded one value.`
+ );
+ hist.clear();
+ snapshot = hist.snapshot();
+ Assert.equal(0, snapshot.sum, `Histogram ${id} should be cleared.`);
+
+ // When sync only, then the snapshot will be empty on the main store
+ id = "TELEMETRY_TEST_SYNC_ONLY";
+ hist = Telemetry.getHistogramById(id);
+ snapshot = hist.snapshot();
+ Assert.equal(
+ undefined,
+ snapshot,
+ `Histogram ${id} should not be in the 'main' storage`
+ );
+ hist.add(1);
+ snapshot = hist.snapshot();
+ Assert.equal(
+ undefined,
+ snapshot,
+ `Histogram ${id} should not be in the 'main' storage`
+ );
+ hist.clear();
+ snapshot = hist.snapshot();
+ Assert.equal(
+ undefined,
+ snapshot,
+ `Histogram ${id} should not be in the 'main' storage`
+ );
+
+ id = "TELEMETRY_TEST_KEYED_MULTIPLE_STORES";
+ hist = Telemetry.getKeyedHistogramById(id);
+ snapshot = hist.snapshot();
+ Assert.deepEqual({}, snapshot, `Histogram ${id} should be empty.`);
+ hist.add("key-a", 1);
+ snapshot = hist.snapshot();
+ Assert.equal(
+ 1,
+ snapshot["key-a"].sum,
+ `Histogram ${id} should have recorded one value.`
+ );
+ hist.clear();
+ snapshot = hist.snapshot();
+ Assert.deepEqual({}, snapshot, `Histogram ${id} should be cleared.`);
+
+ // When sync only, then the snapshot will be empty on the main store
+ id = "TELEMETRY_TEST_KEYED_SYNC_ONLY";
+ hist = Telemetry.getKeyedHistogramById(id);
+ snapshot = hist.snapshot();
+ Assert.equal(
+ undefined,
+ snapshot,
+ `Histogram ${id} should not be in the 'main' storage`
+ );
+ hist.add("key-a", 1);
+ snapshot = hist.snapshot();
+ Assert.equal(
+ undefined,
+ snapshot,
+ `Histogram ${id} should not be in the 'main' storage`
+ );
+ hist.clear();
+ snapshot = hist.snapshot();
+ Assert.equal(
+ undefined,
+ snapshot,
+ `Histogram ${id} should not be in the 'main' storage`
+ );
+});
+
+add_task(async function test_multistore_main_snapshot() {
+ Telemetry.canRecordExtended = true;
+ // Clear histograms
+ Telemetry.getSnapshotForHistograms("main", true);
+ Telemetry.getSnapshotForKeyedHistograms("main", true);
+
+ let id;
+ let hist;
+ let snapshot;
+
+ // Plain histograms
+
+ // Fill with data
+ id = "TELEMETRY_TEST_MAIN_ONLY";
+ hist = Telemetry.getHistogramById(id);
+ hist.add(1);
+
+ id = "TELEMETRY_TEST_MULTIPLE_STORES";
+ hist = Telemetry.getHistogramById(id);
+ hist.add(1);
+
+ id = "TELEMETRY_TEST_SYNC_ONLY";
+ hist = Telemetry.getHistogramById(id);
+ hist.add(1);
+
+ // Getting snapshot and NOT clearing (using default values for optional parameters)
+ snapshot = Telemetry.getSnapshotForHistograms().parent;
+ id = "TELEMETRY_TEST_MAIN_ONLY";
+ Assert.ok(id in snapshot, `${id} should be in a main store snapshot`);
+ id = "TELEMETRY_TEST_MULTIPLE_STORES";
+ Assert.ok(id in snapshot, `${id} should be in a main store snapshot`);
+ id = "TELEMETRY_TEST_SYNC_ONLY";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+
+ // Data should still be in, getting snapshot and clearing
+ snapshot = Telemetry.getSnapshotForHistograms(
+ "main",
+ /* clear */ true
+ ).parent;
+ id = "TELEMETRY_TEST_MAIN_ONLY";
+ Assert.ok(id in snapshot, `${id} should be in a main store snapshot`);
+ id = "TELEMETRY_TEST_MULTIPLE_STORES";
+ Assert.ok(id in snapshot, `${id} should be in a main store snapshot`);
+ id = "TELEMETRY_TEST_SYNC_ONLY";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+
+ // Should be empty after clearing
+ snapshot = Telemetry.getSnapshotForHistograms(
+ "main",
+ /* clear */ false
+ ).parent;
+ id = "TELEMETRY_TEST_MAIN_ONLY";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+ id = "TELEMETRY_TEST_MULTIPLE_STORES";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+ id = "TELEMETRY_TEST_SYNC_ONLY";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+
+ // Keyed histograms
+
+ // Fill with data
+ id = "TELEMETRY_TEST_KEYED_MULTIPLE_STORES";
+ hist = Telemetry.getKeyedHistogramById(id);
+ hist.add("key-a", 1);
+
+ id = "TELEMETRY_TEST_KEYED_SYNC_ONLY";
+ hist = Telemetry.getKeyedHistogramById(id);
+ hist.add("key-b", 1);
+
+ // Getting snapshot and NOT clearing (using default values for optional parameters)
+ snapshot = Telemetry.getSnapshotForKeyedHistograms().parent;
+ id = "TELEMETRY_TEST_KEYED_MULTIPLE_STORES";
+ Assert.ok(id in snapshot, `${id} should be in a main store snapshot`);
+ id = "TELEMETRY_TEST_KEYED_SYNC_ONLY";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+
+ // Data should still be in, getting snapshot and clearing
+ snapshot = Telemetry.getSnapshotForKeyedHistograms(
+ "main",
+ /* clear */ true
+ ).parent;
+ id = "TELEMETRY_TEST_KEYED_MULTIPLE_STORES";
+ Assert.ok(id in snapshot, `${id} should be in a main store snapshot`);
+ id = "TELEMETRY_TEST_KEYED_SYNC_ONLY";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+
+ // Should be empty after clearing
+ snapshot = Telemetry.getSnapshotForKeyedHistograms(
+ "main",
+ /* clear */ false
+ ).parent;
+ id = "TELEMETRY_TEST_KEYED_MULTIPLE_STORES";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+ id = "TELEMETRY_TEST_KEYED_SYNC_ONLY";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+});
+
+add_task(async function test_multistore_argument_handling() {
+ Telemetry.canRecordExtended = true;
+ // Clear histograms
+ Telemetry.getSnapshotForHistograms("main", true);
+ Telemetry.getSnapshotForHistograms("sync", true);
+ Telemetry.getSnapshotForKeyedHistograms("main", true);
+ Telemetry.getSnapshotForKeyedHistograms("sync", true);
+
+ let id;
+ let hist;
+ let snapshot;
+
+ // Plain Histograms
+
+ id = "TELEMETRY_TEST_MULTIPLE_STORES";
+ hist = Telemetry.getHistogramById(id);
+ hist.add(37);
+
+ // No argument
+ snapshot = hist.snapshot();
+ Assert.equal(37, snapshot.sum, `${id} should be in a default store snapshot`);
+
+ hist.clear();
+ snapshot = hist.snapshot();
+ Assert.equal(0, snapshot.sum, `${id} should be cleared in the default store`);
+
+ snapshot = hist.snapshot({ store: "sync" });
+ Assert.equal(
+ 37,
+ snapshot.sum,
+ `${id} should not have been cleared in the sync store`
+ );
+
+ Assert.throws(
+ () => hist.snapshot(2, "or", "more", "arguments"),
+ /one argument/,
+ "snapshot should check argument count"
+ );
+ Assert.throws(
+ () => hist.snapshot(2),
+ /object argument/,
+ "snapshot should check argument type"
+ );
+ Assert.throws(
+ () => hist.snapshot({}),
+ /property/,
+ "snapshot should check for object property"
+ );
+ Assert.throws(
+ () => hist.snapshot({ store: 1 }),
+ /string/,
+ "snapshot should check object property's type"
+ );
+
+ Assert.throws(
+ () => hist.clear(2, "or", "more", "arguments"),
+ /one argument/,
+ "clear should check argument count"
+ );
+ Assert.throws(
+ () => hist.clear(2),
+ /object argument/,
+ "clear should check argument type"
+ );
+ Assert.throws(
+ () => hist.clear({}),
+ /property/,
+ "clear should check for object property"
+ );
+ Assert.throws(
+ () => hist.clear({ store: 1 }),
+ /string/,
+ "clear should check object property's type"
+ );
+
+ // Keyed Histogram
+
+ id = "TELEMETRY_TEST_KEYED_MULTIPLE_STORES";
+ hist = Telemetry.getKeyedHistogramById(id);
+ hist.add("key-1", 37);
+
+ // No argument
+ snapshot = hist.snapshot();
+ Assert.equal(
+ 37,
+ snapshot["key-1"].sum,
+ `${id} should be in a default store snapshot`
+ );
+
+ hist.clear();
+ snapshot = hist.snapshot();
+ Assert.ok(
+ !("key-1" in snapshot),
+ `${id} should be cleared in the default store`
+ );
+
+ snapshot = hist.snapshot({ store: "sync" });
+ Assert.equal(
+ 37,
+ snapshot["key-1"].sum,
+ `${id} should not have been cleared in the sync store`
+ );
+
+ Assert.throws(
+ () => hist.snapshot(2, "or", "more", "arguments"),
+ /one argument/,
+ "snapshot should check argument count"
+ );
+ Assert.throws(
+ () => hist.snapshot(2),
+ /object argument/,
+ "snapshot should check argument type"
+ );
+ Assert.throws(
+ () => hist.snapshot({}),
+ /property/,
+ "snapshot should check for object property"
+ );
+ Assert.throws(
+ () => hist.snapshot({ store: 1 }),
+ /string/,
+ "snapshot should check object property's type"
+ );
+
+ Assert.throws(
+ () => hist.clear(2, "or", "more", "arguments"),
+ /one argument/,
+ "clear should check argument count"
+ );
+ Assert.throws(
+ () => hist.clear(2),
+ /object argument/,
+ "clear should check argument type"
+ );
+ Assert.throws(
+ () => hist.clear({}),
+ /property/,
+ "clear should check for object property"
+ );
+ Assert.throws(
+ () => hist.clear({ store: 1 }),
+ /string/,
+ "clear should check object property's type"
+ );
+});
+
+add_task(async function test_multistore_sync_snapshot() {
+ Telemetry.canRecordExtended = true;
+ // Clear histograms
+ Telemetry.getSnapshotForHistograms("main", true);
+ Telemetry.getSnapshotForHistograms("sync", true);
+
+ let id;
+ let hist;
+ let snapshot;
+
+ // Plain histograms
+
+ // Fill with data
+ id = "TELEMETRY_TEST_MAIN_ONLY";
+ hist = Telemetry.getHistogramById(id);
+ hist.add(1);
+
+ id = "TELEMETRY_TEST_MULTIPLE_STORES";
+ hist = Telemetry.getHistogramById(id);
+ hist.add(1);
+
+ id = "TELEMETRY_TEST_SYNC_ONLY";
+ hist = Telemetry.getHistogramById(id);
+ hist.add(1);
+
+ // Getting snapshot and clearing
+ snapshot = Telemetry.getSnapshotForHistograms(
+ "main",
+ /* clear */ true
+ ).parent;
+ id = "TELEMETRY_TEST_MAIN_ONLY";
+ Assert.ok(id in snapshot, `${id} should be in a main store snapshot`);
+ id = "TELEMETRY_TEST_MULTIPLE_STORES";
+ Assert.ok(id in snapshot, `${id} should be in a main store snapshot`);
+ id = "TELEMETRY_TEST_SYNC_ONLY";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+
+ snapshot = Telemetry.getSnapshotForHistograms(
+ "sync",
+ /* clear */ true
+ ).parent;
+ id = "TELEMETRY_TEST_MAIN_ONLY";
+ Assert.ok(!(id in snapshot), `${id} should not be in a sync store snapshot`);
+ id = "TELEMETRY_TEST_MULTIPLE_STORES";
+ Assert.ok(id in snapshot, `${id} should be in a sync store snapshot`);
+ id = "TELEMETRY_TEST_SYNC_ONLY";
+ Assert.ok(id in snapshot, `${id} should be in a sync store snapshot`);
+});
+
+add_task(async function test_multistore_keyed_sync_snapshot() {
+ Telemetry.canRecordExtended = true;
+ // Clear histograms
+ Telemetry.getSnapshotForKeyedHistograms("main", true);
+ Telemetry.getSnapshotForKeyedHistograms("sync", true);
+
+ let id;
+ let hist;
+ let snapshot;
+
+ // Plain histograms
+
+ // Fill with data
+ id = "TELEMETRY_TEST_KEYED_LINEAR";
+ hist = Telemetry.getKeyedHistogramById(id);
+ hist.add("key-1", 1);
+
+ id = "TELEMETRY_TEST_KEYED_MULTIPLE_STORES";
+ hist = Telemetry.getKeyedHistogramById(id);
+ hist.add("key-1", 1);
+
+ id = "TELEMETRY_TEST_KEYED_SYNC_ONLY";
+ hist = Telemetry.getKeyedHistogramById(id);
+ hist.add("key-1", 1);
+
+ // Getting snapshot and clearing
+ snapshot = Telemetry.getSnapshotForKeyedHistograms(
+ "main",
+ /* clear */ true
+ ).parent;
+ id = "TELEMETRY_TEST_KEYED_LINEAR";
+ Assert.ok(id in snapshot, `${id} should be in a main store snapshot`);
+ id = "TELEMETRY_TEST_KEYED_MULTIPLE_STORES";
+ Assert.ok(id in snapshot, `${id} should be in a main store snapshot`);
+ id = "TELEMETRY_TEST_KEYED_SYNC_ONLY";
+ Assert.ok(!(id in snapshot), `${id} should not be in a main store snapshot`);
+
+ snapshot = Telemetry.getSnapshotForKeyedHistograms(
+ "sync",
+ /* clear */ true
+ ).parent;
+ id = "TELEMETRY_TEST_KEYED_LINEAR";
+ Assert.ok(!(id in snapshot), `${id} should not be in a sync store snapshot`);
+ id = "TELEMETRY_TEST_KEYED_MULTIPLE_STORES";
+ Assert.ok(id in snapshot, `${id} should be in a sync store snapshot`);
+ id = "TELEMETRY_TEST_KEYED_SYNC_ONLY";
+ Assert.ok(id in snapshot, `${id} should be in a sync store snapshot`);
+});
+
+add_task(async function test_multistore_plain_individual_snapshot() {
+ Telemetry.canRecordExtended = true;
+ // Clear histograms
+ Telemetry.getSnapshotForHistograms("main", true);
+ Telemetry.getSnapshotForHistograms("sync", true);
+
+ let id;
+ let hist;
+
+ id = "TELEMETRY_TEST_MAIN_ONLY";
+ hist = Telemetry.getHistogramById(id);
+
+ hist.add(37);
+ Assert.deepEqual(37, hist.snapshot({ store: "main" }).sum);
+ Assert.deepEqual(undefined, hist.snapshot({ store: "sync" }));
+
+ hist.clear({ store: "main" });
+ Assert.deepEqual(0, hist.snapshot({ store: "main" }).sum);
+ Assert.deepEqual(undefined, hist.snapshot({ store: "sync" }));
+
+ id = "TELEMETRY_TEST_MULTIPLE_STORES";
+ hist = Telemetry.getHistogramById(id);
+
+ hist.add(37);
+ Assert.deepEqual(37, hist.snapshot({ store: "main" }).sum);
+ Assert.deepEqual(37, hist.snapshot({ store: "sync" }).sum);
+
+ hist.clear({ store: "main" });
+ Assert.deepEqual(0, hist.snapshot({ store: "main" }).sum);
+ Assert.deepEqual(37, hist.snapshot({ store: "sync" }).sum);
+
+ hist.add(3);
+ Assert.deepEqual(3, hist.snapshot({ store: "main" }).sum);
+ Assert.deepEqual(40, hist.snapshot({ store: "sync" }).sum);
+
+ hist.clear({ store: "sync" });
+ Assert.deepEqual(3, hist.snapshot({ store: "main" }).sum);
+ Assert.deepEqual(0, hist.snapshot({ store: "sync" }).sum);
+
+ id = "TELEMETRY_TEST_SYNC_ONLY";
+ hist = Telemetry.getHistogramById(id);
+
+ hist.add(37);
+ Assert.deepEqual(undefined, hist.snapshot({ store: "main" }));
+ Assert.deepEqual(37, hist.snapshot({ store: "sync" }).sum);
+
+ hist.clear({ store: "main" });
+ Assert.deepEqual(undefined, hist.snapshot({ store: "main" }));
+ Assert.deepEqual(37, hist.snapshot({ store: "sync" }).sum);
+
+ hist.add(3);
+ Assert.deepEqual(undefined, hist.snapshot({ store: "main" }));
+ Assert.deepEqual(40, hist.snapshot({ store: "sync" }).sum);
+
+ hist.clear({ store: "sync" });
+ Assert.deepEqual(undefined, hist.snapshot({ store: "main" }));
+ Assert.deepEqual(0, hist.snapshot({ store: "sync" }).sum);
+});
+
+add_task(async function test_multistore_keyed_individual_snapshot() {
+ Telemetry.canRecordExtended = true;
+ // Clear histograms
+ Telemetry.getSnapshotForKeyedHistograms("main", true);
+ Telemetry.getSnapshotForKeyedHistograms("sync", true);
+
+ let id;
+ let hist;
+
+ id = "TELEMETRY_TEST_KEYED_LINEAR";
+ hist = Telemetry.getKeyedHistogramById(id);
+
+ hist.add("key-1", 37);
+ Assert.deepEqual(37, hist.snapshot({ store: "main" })["key-1"].sum);
+ Assert.deepEqual(undefined, hist.snapshot({ store: "sync" }));
+
+ hist.clear({ store: "main" });
+ Assert.deepEqual({}, hist.snapshot({ store: "main" }));
+ Assert.deepEqual(undefined, hist.snapshot({ store: "sync" }));
+
+ hist.add("key-1", 4);
+ hist.clear({ store: "sync" });
+ Assert.deepEqual(4, hist.snapshot({ store: "main" })["key-1"].sum);
+ Assert.deepEqual(undefined, hist.snapshot({ store: "sync" }));
+
+ id = "TELEMETRY_TEST_KEYED_MULTIPLE_STORES";
+ hist = Telemetry.getKeyedHistogramById(id);
+
+ hist.add("key-1", 37);
+ Assert.deepEqual(37, hist.snapshot({ store: "main" })["key-1"].sum);
+ Assert.deepEqual(37, hist.snapshot({ store: "sync" })["key-1"].sum);
+
+ hist.clear({ store: "main" });
+ Assert.deepEqual({}, hist.snapshot({ store: "main" }));
+ Assert.deepEqual(37, hist.snapshot({ store: "sync" })["key-1"].sum);
+
+ hist.add("key-1", 3);
+ Assert.deepEqual(3, hist.snapshot({ store: "main" })["key-1"].sum);
+ Assert.deepEqual(40, hist.snapshot({ store: "sync" })["key-1"].sum);
+
+ hist.clear({ store: "sync" });
+ Assert.deepEqual(3, hist.snapshot({ store: "main" })["key-1"].sum);
+ Assert.deepEqual({}, hist.snapshot({ store: "sync" }));
+
+ id = "TELEMETRY_TEST_KEYED_SYNC_ONLY";
+ hist = Telemetry.getKeyedHistogramById(id);
+
+ hist.add("key-1", 37);
+ Assert.deepEqual(undefined, hist.snapshot({ store: "main" }));
+ Assert.deepEqual(37, hist.snapshot({ store: "sync" })["key-1"].sum);
+
+ hist.clear({ store: "main" });
+ Assert.deepEqual(undefined, hist.snapshot({ store: "main" }));
+ Assert.deepEqual(37, hist.snapshot({ store: "sync" })["key-1"].sum);
+
+ hist.add("key-1", 3);
+ Assert.deepEqual(undefined, hist.snapshot({ store: "main" }));
+ Assert.deepEqual(40, hist.snapshot({ store: "sync" })["key-1"].sum);
+
+ hist.clear({ store: "sync" });
+ Assert.deepEqual(undefined, hist.snapshot({ store: "main" }));
+ Assert.deepEqual({}, hist.snapshot({ store: "sync" }));
+});
+
+add_task(async function test_can_record_in_process_regression_bug_1530361() {
+ Telemetry.getSnapshotForHistograms("main", true);
+
+ // The socket and gpu processes should not have any histograms.
+ // Flag and count histograms have defaults, so if we're accidentally recording them
+ // in these processes they'd show up even immediately after being cleared.
+ let snapshot = Telemetry.getSnapshotForHistograms("main", true);
+
+ Assert.deepEqual(
+ snapshot.gpu,
+ {},
+ "No histograms should have been recorded for the gpu process"
+ );
+ Assert.deepEqual(
+ snapshot.socket,
+ {},
+ "No histograms should have been recorded for the socket process"
+ );
+});
+
+add_task(function test_knows_its_name() {
+ let h;
+
+ // Plain histograms
+ const histNames = [
+ "TELEMETRY_TEST_FLAG",
+ "TELEMETRY_TEST_COUNT",
+ "TELEMETRY_TEST_CATEGORICAL",
+ "TELEMETRY_TEST_EXPIRED",
+ ];
+
+ for (let name of histNames) {
+ h = Telemetry.getHistogramById(name);
+ Assert.equal(name, h.name());
+ }
+
+ // Keyed histograms
+ const keyedHistNames = [
+ "TELEMETRY_TEST_KEYED_EXPONENTIAL",
+ "TELEMETRY_TEST_KEYED_BOOLEAN",
+ "TELEMETRY_TEST_EXPIRED_KEYED",
+ ];
+
+ for (let name of keyedHistNames) {
+ h = Telemetry.getKeyedHistogramById(name);
+ Assert.equal(name, h.name());
+ }
+});