Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* Any copyright is dedicated to the Public Domain.
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) {
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(() =>
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(() =>
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());
}
});