mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-07 03:38:51 +02:00
1088 lines
34 KiB
JavaScript
1088 lines
34 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/
|
|
*/
|
|
|
|
ChromeUtils.defineESModuleGetters(this, {
|
|
TelemetryTestUtils: "resource://testing-common/TelemetryTestUtils.sys.mjs",
|
|
});
|
|
|
|
const UINT_SCALAR = "telemetry.test.unsigned_int_kind";
|
|
const STRING_SCALAR = "telemetry.test.string_kind";
|
|
const BOOLEAN_SCALAR = "telemetry.test.boolean_kind";
|
|
const KEYED_UINT_SCALAR = "telemetry.test.keyed_unsigned_int";
|
|
const KEYED_EXCEED_SCALAR = "telemetry.keyed_scalars_exceed_limit";
|
|
|
|
function getProcessScalars(aProcessName, aKeyed = false, aClear = false) {
|
|
const scalars = aKeyed
|
|
? Telemetry.getSnapshotForKeyedScalars("main", aClear)[aProcessName]
|
|
: Telemetry.getSnapshotForScalars("main", aClear)[aProcessName];
|
|
return scalars || {};
|
|
}
|
|
|
|
add_task(async function test_serializationFormat() {
|
|
Telemetry.clearScalars();
|
|
|
|
// Set the scalars to a known value.
|
|
const expectedUint = 3785;
|
|
const expectedString = "some value";
|
|
Telemetry.scalarSet(UINT_SCALAR, expectedUint);
|
|
Telemetry.scalarSet(STRING_SCALAR, expectedString);
|
|
Telemetry.scalarSet(BOOLEAN_SCALAR, true);
|
|
Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, "first_key", 1234);
|
|
|
|
// Get a snapshot of the scalars for the main process (internally called "default").
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
|
|
// Check that they are serialized to the correct format.
|
|
Assert.equal(
|
|
typeof scalars[UINT_SCALAR],
|
|
"number",
|
|
UINT_SCALAR + " must be serialized to the correct format."
|
|
);
|
|
Assert.ok(
|
|
Number.isInteger(scalars[UINT_SCALAR]),
|
|
UINT_SCALAR + " must be a finite integer."
|
|
);
|
|
Assert.equal(
|
|
scalars[UINT_SCALAR],
|
|
expectedUint,
|
|
UINT_SCALAR + " must have the correct value."
|
|
);
|
|
Assert.equal(
|
|
typeof scalars[STRING_SCALAR],
|
|
"string",
|
|
STRING_SCALAR + " must be serialized to the correct format."
|
|
);
|
|
Assert.equal(
|
|
scalars[STRING_SCALAR],
|
|
expectedString,
|
|
STRING_SCALAR + " must have the correct value."
|
|
);
|
|
Assert.equal(
|
|
typeof scalars[BOOLEAN_SCALAR],
|
|
"boolean",
|
|
BOOLEAN_SCALAR + " must be serialized to the correct format."
|
|
);
|
|
Assert.equal(
|
|
scalars[BOOLEAN_SCALAR],
|
|
true,
|
|
BOOLEAN_SCALAR + " must have the correct value."
|
|
);
|
|
Assert.ok(
|
|
!(KEYED_UINT_SCALAR in scalars),
|
|
"Keyed scalars must be reported in a separate section."
|
|
);
|
|
});
|
|
|
|
add_task(async function test_keyedSerializationFormat() {
|
|
Telemetry.clearScalars();
|
|
|
|
const expectedKey = "first_key";
|
|
const expectedOtherKey = "漢語";
|
|
const expectedUint = 3785;
|
|
const expectedOtherValue = 1107;
|
|
|
|
Telemetry.scalarSet(UINT_SCALAR, expectedUint);
|
|
Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, expectedKey, expectedUint);
|
|
Telemetry.keyedScalarSet(
|
|
KEYED_UINT_SCALAR,
|
|
expectedOtherKey,
|
|
expectedOtherValue
|
|
);
|
|
|
|
// Get a snapshot of the scalars.
|
|
const keyedScalars = TelemetryTestUtils.getProcessScalars("parent", true);
|
|
|
|
Assert.ok(
|
|
!(UINT_SCALAR in keyedScalars),
|
|
UINT_SCALAR + " must not be serialized with the keyed scalars."
|
|
);
|
|
Assert.ok(
|
|
KEYED_UINT_SCALAR in keyedScalars,
|
|
KEYED_UINT_SCALAR + " must be serialized with the keyed scalars."
|
|
);
|
|
Assert.equal(
|
|
Object.keys(keyedScalars[KEYED_UINT_SCALAR]).length,
|
|
2,
|
|
"The keyed scalar must contain exactly 2 keys."
|
|
);
|
|
Assert.ok(
|
|
expectedKey in keyedScalars[KEYED_UINT_SCALAR],
|
|
KEYED_UINT_SCALAR + " must contain the expected keys."
|
|
);
|
|
Assert.ok(
|
|
expectedOtherKey in keyedScalars[KEYED_UINT_SCALAR],
|
|
KEYED_UINT_SCALAR + " must contain the expected keys."
|
|
);
|
|
Assert.ok(
|
|
Number.isInteger(keyedScalars[KEYED_UINT_SCALAR][expectedKey]),
|
|
KEYED_UINT_SCALAR + "." + expectedKey + " must be a finite integer."
|
|
);
|
|
Assert.equal(
|
|
keyedScalars[KEYED_UINT_SCALAR][expectedKey],
|
|
expectedUint,
|
|
KEYED_UINT_SCALAR + "." + expectedKey + " must have the correct value."
|
|
);
|
|
Assert.equal(
|
|
keyedScalars[KEYED_UINT_SCALAR][expectedOtherKey],
|
|
expectedOtherValue,
|
|
KEYED_UINT_SCALAR + "." + expectedOtherKey + " must have the correct value."
|
|
);
|
|
});
|
|
|
|
add_task(async function test_nonexistingScalar() {
|
|
const NON_EXISTING_SCALAR = "telemetry.test.non_existing";
|
|
|
|
Telemetry.clearScalars();
|
|
|
|
// The JS API must not throw when used incorrectly but rather print
|
|
// a message to the console.
|
|
Telemetry.scalarAdd(NON_EXISTING_SCALAR, 11715);
|
|
Telemetry.scalarSet(NON_EXISTING_SCALAR, 11715);
|
|
Telemetry.scalarSetMaximum(NON_EXISTING_SCALAR, 11715);
|
|
|
|
// Make sure we do not throw on any operation for non-existing scalars.
|
|
Telemetry.keyedScalarAdd(NON_EXISTING_SCALAR, "some_key", 11715);
|
|
Telemetry.keyedScalarSet(NON_EXISTING_SCALAR, "some_key", 11715);
|
|
Telemetry.keyedScalarSetMaximum(NON_EXISTING_SCALAR, "some_key", 11715);
|
|
|
|
// Get a snapshot of the scalars.
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
|
|
Assert.ok(
|
|
!(NON_EXISTING_SCALAR in scalars),
|
|
"The non existing scalar must not be persisted."
|
|
);
|
|
|
|
const keyedScalars = TelemetryTestUtils.getProcessScalars("parent", true);
|
|
|
|
Assert.ok(
|
|
!(NON_EXISTING_SCALAR in keyedScalars),
|
|
"The non existing keyed scalar must not be persisted."
|
|
);
|
|
});
|
|
|
|
add_task(async function test_expiredScalar() {
|
|
const EXPIRED_SCALAR = "telemetry.test.expired";
|
|
const EXPIRED_KEYED_SCALAR = "telemetry.test.keyed_expired";
|
|
const UNEXPIRED_SCALAR = "telemetry.test.unexpired";
|
|
|
|
Telemetry.clearScalars();
|
|
|
|
// Try to set the expired scalar to some value. We will not be recording the value,
|
|
// but we shouldn't throw.
|
|
Telemetry.scalarAdd(EXPIRED_SCALAR, 11715);
|
|
Telemetry.scalarSet(EXPIRED_SCALAR, 11715);
|
|
Telemetry.scalarSetMaximum(EXPIRED_SCALAR, 11715);
|
|
Telemetry.keyedScalarAdd(EXPIRED_KEYED_SCALAR, "some_key", 11715);
|
|
Telemetry.keyedScalarSet(EXPIRED_KEYED_SCALAR, "some_key", 11715);
|
|
Telemetry.keyedScalarSetMaximum(EXPIRED_KEYED_SCALAR, "some_key", 11715);
|
|
|
|
// The unexpired scalar has an expiration version, but far away in the future.
|
|
const expectedValue = 11716;
|
|
Telemetry.scalarSet(UNEXPIRED_SCALAR, expectedValue);
|
|
|
|
// Get a snapshot of the scalars.
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
const keyedScalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
|
|
Assert.ok(
|
|
!(EXPIRED_SCALAR in scalars),
|
|
"The expired scalar must not be persisted."
|
|
);
|
|
Assert.equal(
|
|
scalars[UNEXPIRED_SCALAR],
|
|
expectedValue,
|
|
"The unexpired scalar must be persisted with the correct value."
|
|
);
|
|
Assert.ok(
|
|
!(EXPIRED_KEYED_SCALAR in keyedScalars),
|
|
"The expired keyed scalar must not be persisted."
|
|
);
|
|
});
|
|
|
|
add_task(async function test_unsignedIntScalar() {
|
|
let checkScalar = expectedValue => {
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
Assert.equal(
|
|
scalars[UINT_SCALAR],
|
|
expectedValue,
|
|
UINT_SCALAR + " must contain the expected value."
|
|
);
|
|
};
|
|
|
|
Telemetry.clearScalars();
|
|
|
|
// Let's start with an accumulation without a prior set.
|
|
Telemetry.scalarAdd(UINT_SCALAR, 1);
|
|
Telemetry.scalarAdd(UINT_SCALAR, 2);
|
|
// Do we get what we expect?
|
|
checkScalar(3);
|
|
|
|
// Let's test setting the scalar to a value.
|
|
Telemetry.scalarSet(UINT_SCALAR, 3785);
|
|
checkScalar(3785);
|
|
Telemetry.scalarAdd(UINT_SCALAR, 1);
|
|
checkScalar(3786);
|
|
|
|
// Does setMaximum work?
|
|
Telemetry.scalarSet(UINT_SCALAR, 2);
|
|
checkScalar(2);
|
|
Telemetry.scalarSetMaximum(UINT_SCALAR, 5);
|
|
checkScalar(5);
|
|
// The value of the probe should still be 5, as the previous value
|
|
// is greater than the one we want to set.
|
|
Telemetry.scalarSetMaximum(UINT_SCALAR, 3);
|
|
checkScalar(5);
|
|
|
|
// Check that non-integer numbers get truncated and set.
|
|
Telemetry.scalarSet(UINT_SCALAR, 3.785);
|
|
checkScalar(3);
|
|
|
|
// Setting or adding a negative number must report an error through
|
|
// the console and drop the change (shouldn't throw).
|
|
Telemetry.scalarAdd(UINT_SCALAR, -5);
|
|
Telemetry.scalarSet(UINT_SCALAR, -5);
|
|
Telemetry.scalarSetMaximum(UINT_SCALAR, -1);
|
|
checkScalar(3);
|
|
|
|
// If we try to set a value of a different type, the JS API should not
|
|
// throw but rather print a console message.
|
|
Telemetry.scalarSet(UINT_SCALAR, 1);
|
|
Telemetry.scalarSet(UINT_SCALAR, "unexpected value");
|
|
Telemetry.scalarAdd(UINT_SCALAR, "unexpected value");
|
|
Telemetry.scalarSetMaximum(UINT_SCALAR, "unexpected value");
|
|
// The stored value must not be compromised.
|
|
checkScalar(1);
|
|
});
|
|
|
|
add_task(async function test_stringScalar() {
|
|
let checkExpectedString = expectedString => {
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
Assert.equal(
|
|
scalars[STRING_SCALAR],
|
|
expectedString,
|
|
STRING_SCALAR + " must contain the expected string value."
|
|
);
|
|
};
|
|
|
|
Telemetry.clearScalars();
|
|
|
|
// Let's check simple strings...
|
|
let expected = "test string";
|
|
Telemetry.scalarSet(STRING_SCALAR, expected);
|
|
checkExpectedString(expected);
|
|
expected = "漢語";
|
|
Telemetry.scalarSet(STRING_SCALAR, expected);
|
|
checkExpectedString(expected);
|
|
|
|
// We have some unsupported operations for strings.
|
|
Telemetry.scalarAdd(STRING_SCALAR, 1);
|
|
Telemetry.scalarAdd(STRING_SCALAR, "string value");
|
|
Telemetry.scalarSetMaximum(STRING_SCALAR, 1);
|
|
Telemetry.scalarSetMaximum(STRING_SCALAR, "string value");
|
|
Telemetry.scalarSet(STRING_SCALAR, 1);
|
|
|
|
// Try to set the scalar to a string longer than the maximum length limit.
|
|
const LONG_STRING =
|
|
"browser.qaxfiuosnzmhlg.rpvxicawolhtvmbkpnludhedobxvkjwqyeyvmv";
|
|
Telemetry.scalarSet(STRING_SCALAR, LONG_STRING);
|
|
checkExpectedString(LONG_STRING.substr(0, 50));
|
|
});
|
|
|
|
add_task(async function test_booleanScalar() {
|
|
let checkExpectedBool = expectedBoolean => {
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
Assert.equal(
|
|
scalars[BOOLEAN_SCALAR],
|
|
expectedBoolean,
|
|
BOOLEAN_SCALAR + " must contain the expected boolean value."
|
|
);
|
|
};
|
|
|
|
Telemetry.clearScalars();
|
|
|
|
// Set a test boolean value.
|
|
let expected = false;
|
|
Telemetry.scalarSet(BOOLEAN_SCALAR, expected);
|
|
checkExpectedBool(expected);
|
|
expected = true;
|
|
Telemetry.scalarSet(BOOLEAN_SCALAR, expected);
|
|
checkExpectedBool(expected);
|
|
|
|
// Check that setting a numeric value implicitly converts to boolean.
|
|
Telemetry.scalarSet(BOOLEAN_SCALAR, 1);
|
|
checkExpectedBool(true);
|
|
Telemetry.scalarSet(BOOLEAN_SCALAR, 0);
|
|
checkExpectedBool(false);
|
|
Telemetry.scalarSet(BOOLEAN_SCALAR, 1.0);
|
|
checkExpectedBool(true);
|
|
Telemetry.scalarSet(BOOLEAN_SCALAR, 0.0);
|
|
checkExpectedBool(false);
|
|
|
|
// Check that unsupported operations for booleans do not throw.
|
|
Telemetry.scalarAdd(BOOLEAN_SCALAR, 1);
|
|
Telemetry.scalarAdd(BOOLEAN_SCALAR, "string value");
|
|
Telemetry.scalarSetMaximum(BOOLEAN_SCALAR, 1);
|
|
Telemetry.scalarSetMaximum(BOOLEAN_SCALAR, "string value");
|
|
Telemetry.scalarSet(BOOLEAN_SCALAR, "true");
|
|
});
|
|
|
|
add_task(async function test_scalarRecording() {
|
|
const OPTIN_SCALAR = "telemetry.test.release_optin";
|
|
const OPTOUT_SCALAR = "telemetry.test.release_optout";
|
|
|
|
let checkValue = (scalarName, expectedValue) => {
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
Assert.equal(
|
|
scalars[scalarName],
|
|
expectedValue,
|
|
scalarName + " must contain the expected value."
|
|
);
|
|
};
|
|
|
|
let checkNotSerialized = scalarName => {
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
Assert.ok(!(scalarName in scalars), scalarName + " was not recorded.");
|
|
};
|
|
|
|
Telemetry.canRecordBase = false;
|
|
Telemetry.canRecordExtended = false;
|
|
Telemetry.clearScalars();
|
|
|
|
// Check that no scalar is recorded if both base and extended recording are off.
|
|
Telemetry.scalarSet(OPTOUT_SCALAR, 3);
|
|
Telemetry.scalarSet(OPTIN_SCALAR, 3);
|
|
checkNotSerialized(OPTOUT_SCALAR);
|
|
checkNotSerialized(OPTIN_SCALAR);
|
|
|
|
// Check that opt-out scalars are recorded, while opt-in are not.
|
|
Telemetry.canRecordBase = true;
|
|
Telemetry.scalarSet(OPTOUT_SCALAR, 3);
|
|
Telemetry.scalarSet(OPTIN_SCALAR, 3);
|
|
checkValue(OPTOUT_SCALAR, 3);
|
|
checkNotSerialized(OPTIN_SCALAR);
|
|
|
|
// Check that both opt-out and opt-in scalars are recorded.
|
|
Telemetry.canRecordExtended = true;
|
|
Telemetry.scalarSet(OPTOUT_SCALAR, 5);
|
|
Telemetry.scalarSet(OPTIN_SCALAR, 6);
|
|
checkValue(OPTOUT_SCALAR, 5);
|
|
checkValue(OPTIN_SCALAR, 6);
|
|
});
|
|
|
|
add_task(async function test_keyedScalarRecording() {
|
|
const OPTIN_SCALAR = "telemetry.test.keyed_release_optin";
|
|
const OPTOUT_SCALAR = "telemetry.test.keyed_release_optout";
|
|
const testKey = "policy_key";
|
|
|
|
let checkValue = (scalarName, expectedValue) => {
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent", true);
|
|
Assert.equal(
|
|
scalars[scalarName][testKey],
|
|
expectedValue,
|
|
scalarName + " must contain the expected value."
|
|
);
|
|
};
|
|
|
|
let checkNotSerialized = scalarName => {
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent", true);
|
|
Assert.ok(!(scalarName in scalars), scalarName + " was not recorded.");
|
|
};
|
|
|
|
Telemetry.canRecordBase = false;
|
|
Telemetry.canRecordExtended = false;
|
|
Telemetry.clearScalars();
|
|
|
|
// Check that no scalar is recorded if both base and extended recording are off.
|
|
Telemetry.keyedScalarSet(OPTOUT_SCALAR, testKey, 3);
|
|
Telemetry.keyedScalarSet(OPTIN_SCALAR, testKey, 3);
|
|
checkNotSerialized(OPTOUT_SCALAR);
|
|
checkNotSerialized(OPTIN_SCALAR);
|
|
|
|
// Check that opt-out scalars are recorded, while opt-in are not.
|
|
Telemetry.canRecordBase = true;
|
|
Telemetry.keyedScalarSet(OPTOUT_SCALAR, testKey, 3);
|
|
Telemetry.keyedScalarSet(OPTIN_SCALAR, testKey, 3);
|
|
checkValue(OPTOUT_SCALAR, 3);
|
|
checkNotSerialized(OPTIN_SCALAR);
|
|
|
|
// Check that both opt-out and opt-in scalars are recorded.
|
|
Telemetry.canRecordExtended = true;
|
|
Telemetry.keyedScalarSet(OPTOUT_SCALAR, testKey, 5);
|
|
Telemetry.keyedScalarSet(OPTIN_SCALAR, testKey, 6);
|
|
checkValue(OPTOUT_SCALAR, 5);
|
|
checkValue(OPTIN_SCALAR, 6);
|
|
});
|
|
|
|
add_task(async function test_subsession() {
|
|
Telemetry.clearScalars();
|
|
|
|
// Set the scalars to a known value.
|
|
Telemetry.scalarSet(UINT_SCALAR, 3785);
|
|
Telemetry.scalarSet(STRING_SCALAR, "some value");
|
|
Telemetry.scalarSet(BOOLEAN_SCALAR, false);
|
|
Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, "some_random_key", 12);
|
|
|
|
// Get a snapshot and reset the subsession. The value we set must be there.
|
|
let scalars = TelemetryTestUtils.getProcessScalars("parent", false, true);
|
|
let keyedScalars = TelemetryTestUtils.getProcessScalars("parent", true, true);
|
|
|
|
Assert.equal(
|
|
scalars[UINT_SCALAR],
|
|
3785,
|
|
UINT_SCALAR + " must contain the expected value."
|
|
);
|
|
Assert.equal(
|
|
scalars[STRING_SCALAR],
|
|
"some value",
|
|
STRING_SCALAR + " must contain the expected value."
|
|
);
|
|
Assert.equal(
|
|
scalars[BOOLEAN_SCALAR],
|
|
false,
|
|
BOOLEAN_SCALAR + " must contain the expected value."
|
|
);
|
|
Assert.equal(
|
|
keyedScalars[KEYED_UINT_SCALAR].some_random_key,
|
|
12,
|
|
KEYED_UINT_SCALAR + " must contain the expected value."
|
|
);
|
|
|
|
// Get a new snapshot and reset the subsession again. Since no new value
|
|
// was set, the scalars should not be reported.
|
|
scalars = TelemetryTestUtils.getProcessScalars("parent", false, true);
|
|
keyedScalars = TelemetryTestUtils.getProcessScalars("parent", true, true);
|
|
|
|
Assert.ok(
|
|
!(UINT_SCALAR in scalars),
|
|
UINT_SCALAR + " must be empty and not reported."
|
|
);
|
|
Assert.ok(
|
|
!(STRING_SCALAR in scalars),
|
|
STRING_SCALAR + " must be empty and not reported."
|
|
);
|
|
Assert.ok(
|
|
!(BOOLEAN_SCALAR in scalars),
|
|
BOOLEAN_SCALAR + " must be empty and not reported."
|
|
);
|
|
Assert.ok(
|
|
!(KEYED_UINT_SCALAR in keyedScalars),
|
|
KEYED_UINT_SCALAR + " must be empty and not reported."
|
|
);
|
|
});
|
|
|
|
add_task(async function test_keyed_uint() {
|
|
Telemetry.clearScalars();
|
|
|
|
const KEYS = ["a_key", "another_key", "third_key"];
|
|
let expectedValues = [1, 1, 1];
|
|
|
|
// Set all the keys to a baseline value.
|
|
for (let key of KEYS) {
|
|
Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, key, 1);
|
|
}
|
|
|
|
// Increment only one key.
|
|
Telemetry.keyedScalarAdd(KEYED_UINT_SCALAR, KEYS[1], 1);
|
|
expectedValues[1]++;
|
|
|
|
// Use SetMaximum on the third key.
|
|
Telemetry.keyedScalarSetMaximum(KEYED_UINT_SCALAR, KEYS[2], 37);
|
|
expectedValues[2] = 37;
|
|
|
|
// Get a snapshot of the scalars and make sure the keys contain
|
|
// the correct values.
|
|
const keyedScalars = TelemetryTestUtils.getProcessScalars("parent", true);
|
|
|
|
for (let k = 0; k < 3; k++) {
|
|
const keyName = KEYS[k];
|
|
Assert.equal(
|
|
keyedScalars[KEYED_UINT_SCALAR][keyName],
|
|
expectedValues[k],
|
|
KEYED_UINT_SCALAR + "." + keyName + " must contain the correct value."
|
|
);
|
|
}
|
|
|
|
// Do not throw when doing unsupported things on uint keyed scalars.
|
|
// Just test one single unsupported operation, the other are covered in the plain
|
|
// unsigned scalar test.
|
|
Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, "new_key", "unexpected value");
|
|
});
|
|
|
|
add_task(async function test_keyed_boolean() {
|
|
Telemetry.clearScalars();
|
|
|
|
const KEYED_BOOLEAN_TYPE = "telemetry.test.keyed_boolean_kind";
|
|
const first_key = "first_key";
|
|
const second_key = "second_key";
|
|
|
|
// Set the initial values.
|
|
Telemetry.keyedScalarSet(KEYED_BOOLEAN_TYPE, first_key, true);
|
|
Telemetry.keyedScalarSet(KEYED_BOOLEAN_TYPE, second_key, false);
|
|
|
|
// Get a snapshot of the scalars and make sure the keys contain
|
|
// the correct values.
|
|
let keyedScalars = TelemetryTestUtils.getProcessScalars("parent", true);
|
|
Assert.equal(
|
|
keyedScalars[KEYED_BOOLEAN_TYPE][first_key],
|
|
true,
|
|
"The key must contain the expected value."
|
|
);
|
|
Assert.equal(
|
|
keyedScalars[KEYED_BOOLEAN_TYPE][second_key],
|
|
false,
|
|
"The key must contain the expected value."
|
|
);
|
|
|
|
// Now flip the values and make sure we get the expected values back.
|
|
Telemetry.keyedScalarSet(KEYED_BOOLEAN_TYPE, first_key, false);
|
|
Telemetry.keyedScalarSet(KEYED_BOOLEAN_TYPE, second_key, true);
|
|
|
|
keyedScalars = TelemetryTestUtils.getProcessScalars("parent", true);
|
|
Assert.equal(
|
|
keyedScalars[KEYED_BOOLEAN_TYPE][first_key],
|
|
false,
|
|
"The key must contain the expected value."
|
|
);
|
|
Assert.equal(
|
|
keyedScalars[KEYED_BOOLEAN_TYPE][second_key],
|
|
true,
|
|
"The key must contain the expected value."
|
|
);
|
|
|
|
// Do not throw when doing unsupported things on a boolean keyed scalars.
|
|
// Just test one single unsupported operation, the other are covered in the plain
|
|
// boolean scalar test.
|
|
Telemetry.keyedScalarAdd(KEYED_BOOLEAN_TYPE, "somehey", 1);
|
|
});
|
|
|
|
add_task(async function test_keyed_keys_length() {
|
|
Telemetry.clearScalars();
|
|
|
|
const LONG_KEY_STRING =
|
|
"browser.qaxfiuosnzmhlg.rpvxicawolhtvmbkpnludhedobxvkjwqyeyvmv.somemoresowereach70chars";
|
|
const NORMAL_KEY = "a_key";
|
|
|
|
// Set the value for a key within the length limits.
|
|
Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, NORMAL_KEY, 1);
|
|
|
|
// Now try to set and modify the value for a very long key (must not throw).
|
|
Telemetry.keyedScalarAdd(KEYED_UINT_SCALAR, LONG_KEY_STRING, 10);
|
|
Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, LONG_KEY_STRING, 1);
|
|
Telemetry.keyedScalarSetMaximum(KEYED_UINT_SCALAR, LONG_KEY_STRING, 10);
|
|
|
|
// Also attempt to set the value for an empty key.
|
|
Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, "", 1);
|
|
|
|
// Make sure the key with the right length contains the expected value.
|
|
let keyedScalars = TelemetryTestUtils.getProcessScalars("parent", true);
|
|
Assert.equal(
|
|
Object.keys(keyedScalars[KEYED_UINT_SCALAR]).length,
|
|
1,
|
|
"The keyed scalar must contain exactly 1 key."
|
|
);
|
|
Assert.ok(
|
|
NORMAL_KEY in keyedScalars[KEYED_UINT_SCALAR],
|
|
"The keyed scalar must contain the expected key."
|
|
);
|
|
Assert.equal(
|
|
keyedScalars[KEYED_UINT_SCALAR][NORMAL_KEY],
|
|
1,
|
|
"The key must contain the expected value."
|
|
);
|
|
Assert.ok(
|
|
!(LONG_KEY_STRING in keyedScalars[KEYED_UINT_SCALAR]),
|
|
"The data for the long key should not have been recorded."
|
|
);
|
|
Assert.ok(
|
|
!("" in keyedScalars[KEYED_UINT_SCALAR]),
|
|
"The data for the empty key should not have been recorded."
|
|
);
|
|
});
|
|
|
|
add_task(async function test_keyed_max_keys() {
|
|
Telemetry.clearScalars();
|
|
|
|
// Generate the names for the first 100 keys.
|
|
let keyNamesSet = new Set();
|
|
for (let k = 0; k < 100; k++) {
|
|
keyNamesSet.add("key_" + k);
|
|
}
|
|
|
|
// Add 100 keys to an histogram and set their initial value.
|
|
let valueToSet = 0;
|
|
keyNamesSet.forEach(keyName => {
|
|
Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, keyName, valueToSet++);
|
|
});
|
|
|
|
// Perform some operations on the 101th key. This should throw, as
|
|
// we're not allowed to have more than 100 keys.
|
|
const LAST_KEY_NAME = "overflowing_key";
|
|
Telemetry.keyedScalarAdd(KEYED_UINT_SCALAR, LAST_KEY_NAME, 10);
|
|
Telemetry.keyedScalarSet(KEYED_UINT_SCALAR, LAST_KEY_NAME, 1);
|
|
Telemetry.keyedScalarSetMaximum(KEYED_UINT_SCALAR, LAST_KEY_NAME, 10);
|
|
|
|
// Make sure all the keys except the last one are available and have the correct
|
|
// values.
|
|
let keyedScalars = TelemetryTestUtils.getProcessScalars("parent", true);
|
|
|
|
// Check that the keyed scalar only contain the first 100 keys.
|
|
const reportedKeysSet = new Set(Object.keys(keyedScalars[KEYED_UINT_SCALAR]));
|
|
Assert.ok(
|
|
[...keyNamesSet].filter(x => reportedKeysSet.has(x)) &&
|
|
[...reportedKeysSet].filter(x => keyNamesSet.has(x)),
|
|
"The keyed scalar must contain all the 100 keys, and drop the others."
|
|
);
|
|
|
|
// Check that all the keys recorded the expected values.
|
|
let expectedValue = 0;
|
|
keyNamesSet.forEach(keyName => {
|
|
Assert.equal(
|
|
keyedScalars[KEYED_UINT_SCALAR][keyName],
|
|
expectedValue++,
|
|
"The key must contain the expected value."
|
|
);
|
|
});
|
|
|
|
// Check that KEYED_EXCEED_SCALAR is in keyedScalars
|
|
Assert.ok(
|
|
KEYED_EXCEED_SCALAR in keyedScalars,
|
|
"We have exceeded maximum number of Keys."
|
|
);
|
|
|
|
// Generate the names for the exceeded keys
|
|
let keyNamesSet2 = new Set();
|
|
for (let k = 0; k < 100; k++) {
|
|
keyNamesSet2.add("key2_" + k);
|
|
}
|
|
|
|
// Add 100 keys to the keyed exceed scalar and set their initial value.
|
|
valueToSet = 0;
|
|
keyNamesSet2.forEach(keyName2 => {
|
|
Telemetry.keyedScalarSet(KEYED_EXCEED_SCALAR, keyName2, valueToSet++);
|
|
});
|
|
|
|
// Check that there are exactly 100 keys in KEYED_EXCEED_SCALAR
|
|
let snapshot = Telemetry.getSnapshotForKeyedScalars("main", false);
|
|
Assert.equal(
|
|
100,
|
|
Object.keys(snapshot.parent[KEYED_UINT_SCALAR]).length,
|
|
"The keyed scalar must contain all the 100 keys."
|
|
);
|
|
|
|
// Check that KEYED_UINT_SCALAR is in keyedScalars and its value equals 3
|
|
Assert.ok(
|
|
KEYED_UINT_SCALAR in keyedScalars[KEYED_EXCEED_SCALAR],
|
|
"The keyed Scalar is in the keyed exceeded scalar"
|
|
);
|
|
Assert.equal(
|
|
keyedScalars[KEYED_EXCEED_SCALAR][KEYED_UINT_SCALAR],
|
|
3,
|
|
"We have exactly 3 keys over the limit"
|
|
);
|
|
});
|
|
|
|
add_task(async function test_dynamicScalars_registration() {
|
|
Telemetry.clearScalars();
|
|
|
|
const TEST_CASES = [
|
|
{
|
|
category: "telemetry.test",
|
|
data: {
|
|
missing_kind: {
|
|
keyed: false,
|
|
record_on_release: true,
|
|
},
|
|
},
|
|
evaluation: /missing 'kind'/,
|
|
description: "Registration must fail if required fields are missing",
|
|
},
|
|
{
|
|
category: "telemetry.test",
|
|
data: {
|
|
invalid_collection: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
record_on_release: "opt-in",
|
|
},
|
|
},
|
|
evaluation: /Invalid 'record_on_release'/,
|
|
description:
|
|
"Registration must fail if 'record_on_release' is of the wrong type",
|
|
},
|
|
{
|
|
category: "telemetry.test",
|
|
data: {
|
|
invalid_kind: {
|
|
kind: "12",
|
|
},
|
|
},
|
|
evaluation: /Invalid or missing 'kind'/,
|
|
description: "Registration must fail if 'kind' is of the wrong type",
|
|
},
|
|
{
|
|
category: "telemetry.test",
|
|
data: {
|
|
invalid_expired: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
expired: "never",
|
|
},
|
|
},
|
|
evaluation: /Invalid 'expired'/,
|
|
description: "Registration must fail if 'expired' is of the wrong type",
|
|
},
|
|
{
|
|
category: "telemetry.test",
|
|
data: {
|
|
valid_scalar: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
keyed: false,
|
|
record_on_release: true,
|
|
},
|
|
invalid_scalar: {
|
|
expired: false,
|
|
},
|
|
},
|
|
evaluation: /Invalid or missing 'kind'/,
|
|
description:
|
|
"No scalar must be registered if the batch contains an invalid one",
|
|
},
|
|
{
|
|
category: "telemetry.test",
|
|
data: {
|
|
invalid_stores: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
keyed: false,
|
|
stores: true,
|
|
},
|
|
},
|
|
evaluation: /Invalid 'stores'/,
|
|
description: "Registration must fail if 'stores' is of the wrong type",
|
|
},
|
|
{
|
|
category: "telemetry.test",
|
|
data: {
|
|
invalid_stores: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
keyed: false,
|
|
stores: {},
|
|
},
|
|
},
|
|
evaluation: /Invalid 'stores'/,
|
|
description: "Registration must fail if 'stores' is of the wrong type",
|
|
},
|
|
{
|
|
category: "telemetry.test",
|
|
data: {
|
|
invalid_stores: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
keyed: false,
|
|
stores: [{}],
|
|
},
|
|
},
|
|
evaluation: /'stores' array isn't a string./,
|
|
description:
|
|
"Registration must fail if element in 'stores' is of the wrong type",
|
|
},
|
|
];
|
|
|
|
for (let testCase of TEST_CASES) {
|
|
Assert.throws(
|
|
() => Telemetry.registerScalars(testCase.category, testCase.data),
|
|
testCase.evaluation,
|
|
testCase.description
|
|
);
|
|
}
|
|
});
|
|
|
|
add_task(async function test_dynamicScalars_doubleRegistration() {
|
|
Telemetry.clearScalars();
|
|
|
|
// Register a test scalar.
|
|
Telemetry.registerScalars("telemetry.test.dynamic", {
|
|
double_registration_1: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
record_on_release: true,
|
|
},
|
|
});
|
|
|
|
// Verify that we can record the scalar.
|
|
Telemetry.scalarSet("telemetry.test.dynamic.double_registration_1", 1);
|
|
|
|
// Register the same scalar again, along with a second scalar.
|
|
// This must not throw.
|
|
Telemetry.registerScalars("telemetry.test.dynamic", {
|
|
double_registration_1: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
record_on_release: true,
|
|
},
|
|
double_registration_2: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
record_on_release: true,
|
|
},
|
|
});
|
|
|
|
// Set the dynamic scalars to some test values.
|
|
Telemetry.scalarAdd("telemetry.test.dynamic.double_registration_1", 1);
|
|
Telemetry.scalarSet("telemetry.test.dynamic.double_registration_2", 3);
|
|
|
|
// Get a snapshot of the scalars and check that the dynamic ones were correctly set.
|
|
let scalars = getProcessScalars("dynamic", false, false);
|
|
|
|
Assert.equal(
|
|
scalars["telemetry.test.dynamic.double_registration_1"],
|
|
2,
|
|
"The recorded scalar must contain the right value."
|
|
);
|
|
Assert.equal(
|
|
scalars["telemetry.test.dynamic.double_registration_2"],
|
|
3,
|
|
"The recorded scalar must contain the right value."
|
|
);
|
|
|
|
// Register an existing scalar again, only change the definition
|
|
// to make it expire.
|
|
Telemetry.registerScalars("telemetry.test.dynamic", {
|
|
double_registration_2: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
record_on_release: true,
|
|
expired: true,
|
|
},
|
|
});
|
|
|
|
// Attempt to record and make sure that no recording happens.
|
|
Telemetry.scalarAdd("telemetry.test.dynamic.double_registration_2", 1);
|
|
scalars = getProcessScalars("dynamic", false, false);
|
|
Assert.equal(
|
|
scalars["telemetry.test.dynamic.double_registration_2"],
|
|
3,
|
|
"The recorded scalar must contain the right value."
|
|
);
|
|
});
|
|
|
|
add_task(async function test_dynamicScalars_recording() {
|
|
Telemetry.clearScalars();
|
|
|
|
// Disable extended recording so that we will just record opt-out.
|
|
Telemetry.canRecordExtended = false;
|
|
|
|
// Register some test scalars.
|
|
Telemetry.registerScalars("telemetry.test.dynamic", {
|
|
record_optout: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
record_on_release: true,
|
|
},
|
|
record_keyed: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
|
|
keyed: true,
|
|
record_on_release: true,
|
|
},
|
|
record_optin: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_BOOLEAN,
|
|
record_on_release: false,
|
|
},
|
|
record_expired: {
|
|
kind: Ci.nsITelemetry.SCALAR_TYPE_STRING,
|
|
expired: true,
|
|
record_on_release: true,
|
|
},
|
|
});
|
|
|
|
// Set the dynamic scalars to some test values.
|
|
Telemetry.scalarSet("telemetry.test.dynamic.record_optout", 1);
|
|
Telemetry.keyedScalarSet("telemetry.test.dynamic.record_keyed", "someKey", 5);
|
|
Telemetry.scalarSet("telemetry.test.dynamic.record_optin", false);
|
|
Telemetry.scalarSet("telemetry.test.dynamic.record_expired", "test");
|
|
|
|
// Get a snapshot of the scalars and check that the dynamic ones were correctly set.
|
|
let scalars = getProcessScalars("dynamic", false, false);
|
|
let keyedScalars = getProcessScalars("dynamic", true, true);
|
|
|
|
Assert.ok(
|
|
!("telemetry.test.dynamic.record_optin" in scalars),
|
|
"Dynamic opt-in scalars must not be recorded."
|
|
);
|
|
Assert.ok(
|
|
"telemetry.test.dynamic.record_keyed" in keyedScalars,
|
|
"Dynamic opt-out keyed scalars must be recorded."
|
|
);
|
|
Assert.ok(
|
|
!("telemetry.test.dynamic.record_expired" in scalars),
|
|
"Dynamic expired scalars must not be recorded."
|
|
);
|
|
Assert.ok(
|
|
"telemetry.test.dynamic.record_optout" in scalars,
|
|
"Dynamic opt-out scalars must be recorded."
|
|
);
|
|
Assert.equal(
|
|
scalars["telemetry.test.dynamic.record_optout"],
|
|
1,
|
|
"The recorded scalar must contain the right value."
|
|
);
|
|
Assert.equal(
|
|
keyedScalars["telemetry.test.dynamic.record_keyed"].someKey,
|
|
5,
|
|
"The recorded keyed scalar must contain the right value."
|
|
);
|
|
|
|
// Enable extended recording.
|
|
Telemetry.canRecordExtended = true;
|
|
|
|
// Set the dynamic scalars to some test values.
|
|
Telemetry.scalarSet("telemetry.test.dynamic.record_optin", true);
|
|
Telemetry.scalarSet("telemetry.test.dynamic.record_expired", "test");
|
|
|
|
// Get a snapshot of the scalars and check that the dynamic ones were correctly set.
|
|
scalars = getProcessScalars("dynamic", false, true);
|
|
|
|
Assert.ok(
|
|
!("telemetry.test.dynamic.record_expired" in scalars),
|
|
"Dynamic expired scalars must not be recorded."
|
|
);
|
|
Assert.ok(
|
|
"telemetry.test.dynamic.record_optin" in scalars,
|
|
"Dynamic opt-in scalars must be recorded."
|
|
);
|
|
Assert.equal(
|
|
scalars["telemetry.test.dynamic.record_optin"],
|
|
true,
|
|
"The recorded scalar must contain the right value."
|
|
);
|
|
});
|
|
|
|
add_task(
|
|
{
|
|
skip_if: () => gIsAndroid,
|
|
},
|
|
async function test_productSpecificScalar() {
|
|
const DEFAULT_PRODUCT_SCALAR = "telemetry.test.default_products";
|
|
const DESKTOP_ONLY_SCALAR = "telemetry.test.desktop_only";
|
|
const MULTIPRODUCT_SCALAR = "telemetry.test.multiproduct";
|
|
const MOBILE_ONLY_SCALAR = "telemetry.test.mobile_only";
|
|
const MOBILE_ONLY_KEYED_SCALAR = "telemetry.test.keyed_mobile_only";
|
|
|
|
Telemetry.clearScalars();
|
|
|
|
// Try to set the desktop scalars
|
|
let expectedValue = 11714;
|
|
Telemetry.scalarAdd(DEFAULT_PRODUCT_SCALAR, expectedValue);
|
|
Telemetry.scalarAdd(DESKTOP_ONLY_SCALAR, expectedValue);
|
|
Telemetry.scalarAdd(MULTIPRODUCT_SCALAR, expectedValue);
|
|
|
|
// Try to set the mobile-only scalar to some value. We will not be recording the value,
|
|
// but we shouldn't throw.
|
|
let expectedKey = "some_key";
|
|
Telemetry.scalarSet(MOBILE_ONLY_SCALAR, 11715);
|
|
Telemetry.scalarSetMaximum(MOBILE_ONLY_SCALAR, 11715);
|
|
Telemetry.keyedScalarAdd(MOBILE_ONLY_KEYED_SCALAR, expectedKey, 11715);
|
|
Telemetry.keyedScalarSet(MOBILE_ONLY_KEYED_SCALAR, expectedKey, 11715);
|
|
Telemetry.keyedScalarSetMaximum(
|
|
MOBILE_ONLY_KEYED_SCALAR,
|
|
expectedKey,
|
|
11715
|
|
);
|
|
|
|
// Get a snapshot of the scalars.
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
const keyedScalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
|
|
Assert.equal(
|
|
scalars[DEFAULT_PRODUCT_SCALAR],
|
|
expectedValue,
|
|
"The default platfomrs scalar must contain the right value"
|
|
);
|
|
Assert.equal(
|
|
scalars[DESKTOP_ONLY_SCALAR],
|
|
expectedValue,
|
|
"The desktop-only scalar must contain the right value"
|
|
);
|
|
Assert.equal(
|
|
scalars[MULTIPRODUCT_SCALAR],
|
|
expectedValue,
|
|
"The multiproduct scalar must contain the right value"
|
|
);
|
|
|
|
Assert.ok(
|
|
!(MOBILE_ONLY_SCALAR in scalars),
|
|
"The mobile-only scalar must not be persisted."
|
|
);
|
|
Assert.ok(
|
|
!(MOBILE_ONLY_KEYED_SCALAR in keyedScalars),
|
|
"The mobile-only keyed scalar must not be persisted."
|
|
);
|
|
}
|
|
);
|
|
|
|
add_task(
|
|
{
|
|
skip_if: () => !gIsAndroid,
|
|
},
|
|
async function test_mobileSpecificScalar() {
|
|
const DEFAULT_PRODUCT_SCALAR = "telemetry.test.default_products";
|
|
const DESKTOP_ONLY_SCALAR = "telemetry.test.desktop_only";
|
|
const DESKTOP_ONLY_KEYED_SCALAR = "telemetry.test.keyed_desktop_only";
|
|
const MULTIPRODUCT_SCALAR = "telemetry.test.multiproduct";
|
|
const MOBILE_ONLY_SCALAR = "telemetry.test.mobile_only";
|
|
const MOBILE_ONLY_KEYED_SCALAR = "telemetry.test.keyed_mobile_only";
|
|
|
|
Telemetry.clearScalars();
|
|
|
|
// Try to set the mobile and multiproduct scalars
|
|
let expectedValue = 11714;
|
|
let expectedKey = "some_key";
|
|
Telemetry.scalarAdd(DEFAULT_PRODUCT_SCALAR, expectedValue);
|
|
Telemetry.scalarAdd(MOBILE_ONLY_SCALAR, expectedValue);
|
|
Telemetry.keyedScalarSet(
|
|
MOBILE_ONLY_KEYED_SCALAR,
|
|
expectedKey,
|
|
expectedValue
|
|
);
|
|
Telemetry.scalarAdd(MULTIPRODUCT_SCALAR, expectedValue);
|
|
|
|
// Try to set the desktop-only scalar to some value. We will not be recording the value,
|
|
// but we shouldn't throw.
|
|
Telemetry.scalarSet(DESKTOP_ONLY_SCALAR, 11715);
|
|
Telemetry.scalarSetMaximum(DESKTOP_ONLY_SCALAR, 11715);
|
|
Telemetry.keyedScalarAdd(DESKTOP_ONLY_KEYED_SCALAR, expectedKey, 11715);
|
|
Telemetry.keyedScalarSet(DESKTOP_ONLY_KEYED_SCALAR, expectedKey, 11715);
|
|
Telemetry.keyedScalarSetMaximum(
|
|
DESKTOP_ONLY_KEYED_SCALAR,
|
|
expectedKey,
|
|
11715
|
|
);
|
|
|
|
// Get a snapshot of the scalars.
|
|
const scalars = TelemetryTestUtils.getProcessScalars("parent");
|
|
const keyedScalars = TelemetryTestUtils.getProcessScalars("parent", true);
|
|
|
|
Assert.equal(
|
|
scalars[DEFAULT_PRODUCT_SCALAR],
|
|
expectedValue,
|
|
"The default products scalar must contain the right value"
|
|
);
|
|
Assert.equal(
|
|
scalars[MOBILE_ONLY_SCALAR],
|
|
expectedValue,
|
|
"The mobile-only scalar must contain the right value"
|
|
);
|
|
Assert.equal(
|
|
keyedScalars[MOBILE_ONLY_KEYED_SCALAR][expectedKey],
|
|
expectedValue,
|
|
"The mobile-only keyed scalar must contain the right value"
|
|
);
|
|
Assert.equal(
|
|
scalars[MULTIPRODUCT_SCALAR],
|
|
expectedValue,
|
|
"The multiproduct scalar must contain the right value"
|
|
);
|
|
|
|
Assert.ok(
|
|
!(DESKTOP_ONLY_SCALAR in scalars),
|
|
"The desktop-only scalar must not be persisted."
|
|
);
|
|
Assert.ok(
|
|
!(DESKTOP_ONLY_KEYED_SCALAR in keyedScalars),
|
|
"The desktop-only keyed scalar must not be persisted."
|
|
);
|
|
}
|
|
);
|