273 lines
8.3 KiB
JavaScript
273 lines
8.3 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
/* global is ok registerCleanupFunction Services */
|
|
|
|
"use strict";
|
|
|
|
// We try to avoid polluting the global scope as far as possible by defining
|
|
// constants in the methods that use them because this script is not sandboxed
|
|
// meaning that it is loaded via Services.scriptloader.loadSubScript()
|
|
|
|
class TelemetryHelpers {
|
|
constructor() {
|
|
this.oldCanRecord = Services.telemetry.canRecordExtended;
|
|
this.generateTelemetryTests = this.generateTelemetryTests.bind(this);
|
|
registerCleanupFunction(this.stopTelemetry.bind(this));
|
|
}
|
|
|
|
/**
|
|
* Allow collection of extended telemetry data.
|
|
*/
|
|
startTelemetry() {
|
|
Services.telemetry.canRecordExtended = true;
|
|
}
|
|
|
|
/**
|
|
* Clear all telemetry types.
|
|
*/
|
|
stopTelemetry() {
|
|
// Clear histograms, scalars and Telemetry Events.
|
|
this.clearHistograms(Services.telemetry.getSnapshotForHistograms);
|
|
this.clearHistograms(Services.telemetry.getSnapshotForKeyedHistograms);
|
|
Services.telemetry.clearScalars();
|
|
Services.telemetry.clearEvents();
|
|
|
|
Services.telemetry.canRecordExtended = this.oldCanRecord;
|
|
}
|
|
|
|
/**
|
|
* Clears Telemetry Histograms.
|
|
*
|
|
* @param {Function} snapshotFunc
|
|
* The function used to take the snapshot. This can be one of the
|
|
* following:
|
|
* - Services.telemetry.getSnapshotForHistograms
|
|
* - Services.telemetry.getSnapshotForKeyedHistograms
|
|
*/
|
|
clearHistograms(snapshotFunc) {
|
|
snapshotFunc("main", true);
|
|
}
|
|
|
|
/**
|
|
* Check the value of a given telemetry histogram.
|
|
*
|
|
* @param {String} histId
|
|
* Histogram id
|
|
* @param {String} key
|
|
* Keyed histogram key
|
|
* @param {Array|Number} expected
|
|
* Expected value
|
|
* @param {String} checkType
|
|
* "array" (default) - Check that an array matches the histogram data.
|
|
* "hasentries" - For non-enumerated linear and exponential
|
|
* histograms. This checks for at least one entry.
|
|
* "scalar" - Telemetry type is a scalar.
|
|
* "keyedscalar" - Telemetry type is a keyed scalar.
|
|
*/
|
|
checkTelemetry(histId, key, expected, checkType) {
|
|
let actual;
|
|
let msg;
|
|
|
|
if (checkType === "array" || checkType === "hasentries") {
|
|
if (key) {
|
|
const keyedHistogram = Services.telemetry
|
|
.getKeyedHistogramById(histId)
|
|
.snapshot();
|
|
const result = keyedHistogram[key];
|
|
|
|
if (result) {
|
|
actual = result.values;
|
|
} else {
|
|
ok(false, `${histId}[${key}] exists`);
|
|
return;
|
|
}
|
|
} else {
|
|
actual = Services.telemetry.getHistogramById(histId).snapshot().values;
|
|
}
|
|
}
|
|
|
|
switch (checkType) {
|
|
case "array":
|
|
msg = key ? `${histId}["${key}"] correct.` : `${histId} correct.`;
|
|
is(JSON.stringify(actual), JSON.stringify(expected), msg);
|
|
break;
|
|
case "hasentries":
|
|
const hasEntry = Object.values(actual).some(num => num > 0);
|
|
if (key) {
|
|
ok(hasEntry, `${histId}["${key}"] has at least one entry.`);
|
|
} else {
|
|
ok(hasEntry, `${histId} has at least one entry.`);
|
|
}
|
|
break;
|
|
case "scalar":
|
|
const scalars = Services.telemetry.getSnapshotForScalars(
|
|
"main",
|
|
false
|
|
).parent;
|
|
|
|
is(scalars[histId], expected, `${histId} correct`);
|
|
break;
|
|
case "keyedscalar":
|
|
const keyedScalars = Services.telemetry.getSnapshotForKeyedScalars(
|
|
"main",
|
|
false
|
|
).parent;
|
|
const value = keyedScalars[histId][key];
|
|
|
|
msg = key ? `${histId}["${key}"] correct.` : `${histId} correct.`;
|
|
is(value, expected, msg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate telemetry tests. You should call generateTelemetryTests("DEVTOOLS_")
|
|
* from your result checking code in telemetry tests. It logs checkTelemetry
|
|
* calls for all changed telemetry values.
|
|
*
|
|
* @param {String} prefix
|
|
* Optionally limits results to histogram ids starting with prefix.
|
|
*/
|
|
generateTelemetryTests(prefix = "") {
|
|
// Get all histograms and scalars
|
|
const histograms = Services.telemetry.getSnapshotForHistograms(
|
|
"main",
|
|
true
|
|
).parent;
|
|
const keyedHistograms = Services.telemetry.getSnapshotForKeyedHistograms(
|
|
"main",
|
|
true
|
|
).parent;
|
|
const scalars = Services.telemetry.getSnapshotForScalars(
|
|
"main",
|
|
false
|
|
).parent;
|
|
const keyedScalars = Services.telemetry.getSnapshotForKeyedScalars(
|
|
"main",
|
|
false
|
|
).parent;
|
|
const allHistograms = Object.assign(
|
|
{},
|
|
histograms,
|
|
keyedHistograms,
|
|
scalars,
|
|
keyedScalars
|
|
);
|
|
// Get all keys
|
|
const histIds = Object.keys(allHistograms).filter(histId =>
|
|
histId.startsWith(prefix)
|
|
);
|
|
|
|
dump("=".repeat(80) + "\n");
|
|
for (const histId of histIds) {
|
|
const snapshot = allHistograms[histId];
|
|
|
|
if (histId === histId.toLowerCase()) {
|
|
if (typeof snapshot === "object") {
|
|
// Keyed Scalar
|
|
const keys = Object.keys(snapshot);
|
|
|
|
for (const key of keys) {
|
|
const value = snapshot[key];
|
|
|
|
dump(
|
|
`checkTelemetry("${histId}", "${key}", ${value}, "keyedscalar");\n`
|
|
);
|
|
}
|
|
} else {
|
|
// Scalar
|
|
dump(`checkTelemetry("${histId}", "", ${snapshot}, "scalar");\n`);
|
|
}
|
|
} else if (
|
|
typeof snapshot.histogram_type !== "undefined" &&
|
|
typeof snapshot.values !== "undefined"
|
|
) {
|
|
// Histogram
|
|
const actual = snapshot.values;
|
|
|
|
this.displayDataFromHistogramSnapshot(snapshot, "", histId, actual);
|
|
} else {
|
|
// Keyed Histogram
|
|
const keys = Object.keys(snapshot);
|
|
|
|
for (const key of keys) {
|
|
const value = snapshot[key];
|
|
const actual = value.counts;
|
|
|
|
this.displayDataFromHistogramSnapshot(value, key, histId, actual);
|
|
}
|
|
}
|
|
}
|
|
dump("=".repeat(80) + "\n");
|
|
}
|
|
|
|
/**
|
|
* Generates the inner contents of a test's checkTelemetry() method.
|
|
*
|
|
* @param {HistogramSnapshot} snapshot
|
|
* A snapshot of a telemetry chart obtained via getSnapshotForHistograms or
|
|
* similar.
|
|
* @param {String} key
|
|
* Only used for keyed histograms. This is the key we are interested in
|
|
* checking.
|
|
* @param {String} histId
|
|
* The histogram ID.
|
|
* @param {Array|String|Boolean} actual
|
|
* The value of the histogram data.
|
|
*/
|
|
displayDataFromHistogramSnapshot(snapshot, key, histId, actual) {
|
|
key = key ? `"${key}"` : `""`;
|
|
|
|
switch (snapshot.histogram_type) {
|
|
case Services.telemetry.HISTOGRAM_EXPONENTIAL:
|
|
case Services.telemetry.HISTOGRAM_LINEAR:
|
|
let total = 0;
|
|
for (const val of Object.values(actual)) {
|
|
total += val;
|
|
}
|
|
|
|
if (histId.endsWith("_ENUMERATED")) {
|
|
if (total > 0) {
|
|
actual = actual.toSource();
|
|
dump(`checkTelemetry("${histId}", ${key}, ${actual}, "array");\n`);
|
|
}
|
|
return;
|
|
}
|
|
|
|
dump(`checkTelemetry("${histId}", ${key}, null, "hasentries");\n`);
|
|
break;
|
|
case Services.telemetry.HISTOGRAM_BOOLEAN:
|
|
actual = actual.toSource();
|
|
|
|
if (actual !== "({})") {
|
|
dump(`checkTelemetry("${histId}", ${key}, ${actual}, "array");\n`);
|
|
}
|
|
break;
|
|
case Services.telemetry.HISTOGRAM_FLAG:
|
|
actual = actual.toSource();
|
|
|
|
if (actual !== "({0:1, 1:0})") {
|
|
dump(`checkTelemetry("${histId}", ${key}, ${actual}, "array");\n`);
|
|
}
|
|
break;
|
|
case Services.telemetry.HISTOGRAM_COUNT:
|
|
actual = actual.toSource();
|
|
|
|
dump(`checkTelemetry("${histId}", ${key}, ${actual}, "array");\n`);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// "exports"... because this is a helper and not imported via require we need to
|
|
// expose the three main methods that should be used by tests. The reason this
|
|
// is not imported via require is because it needs access to test methods
|
|
// (is, ok etc).
|
|
|
|
/* eslint-disable no-unused-vars */
|
|
const telemetryHelpers = new TelemetryHelpers();
|
|
const generateTelemetryTests = telemetryHelpers.generateTelemetryTests;
|
|
const checkTelemetry = telemetryHelpers.checkTelemetry;
|
|
const startTelemetry = telemetryHelpers.startTelemetry;
|
|
/* eslint-enable no-unused-vars */
|