/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Ideally this would be an xpcshell test, but Troubleshoot relies on things // that aren't initialized outside of a XUL app environment like AddonManager // and the "@mozilla.org/xre/app-info;1" component.
add_task(async function snapshotSchema() {
let snapshot = await Troubleshoot.snapshot(); try {
validateObject(snapshot, SNAPSHOT_SCHEMA);
ok(true, "The snapshot should conform to the schema.");
} catch (err) {
ok(false, "Schema mismatch, " + err);
}
});
add_task(async function experimentalFeatures() {
let featureGates = await FeatureGate.all();
ok(featureGates.length, "Should be at least one FeatureGate");
let snapshot = await Troubleshoot.snapshot(); for (let i = 0; i < snapshot.experimentalFeatures.length; i++) {
let experimentalFeature = snapshot.experimentalFeatures[i];
is(
experimentalFeature[0],
featureGates[i].title, "The first item in the array should be the title's l10n-id of the FeatureGate"
);
is(
experimentalFeature[1],
featureGates[i].preference, "The second item in the array should be the preference name for the FeatureGate"
);
is(
experimentalFeature[2],
Services.prefs.getBoolPref(featureGates[i].preference), "The third item in the array should be the preference value of the FeatureGate"
);
}
});
add_task(async function modifiedPreferences() {
let prefs = [ "javascript.troubleshoot", "troubleshoot.foo", "network.proxy.troubleshoot", "print.print_to_filename",
];
prefs.forEach(function (p) {
Services.prefs.setBoolPref(p, true);
is(Services.prefs.getBoolPref(p), true, "The pref should be set: " + p);
});
Services.prefs.setCharPref("dom.push.userAgentID", "testvalue");
let snapshot = await Troubleshoot.snapshot();
let p = snapshot.modifiedPreferences;
is(
p["javascript.troubleshoot"], true, "The pref should be present because it's in the allowed prefs " + "and not in the pref regexes that are disallowed."
);
ok(
!("troubleshoot.foo" in p), "The pref should be absent because it's not in the allowed prefs."
);
ok(
!("network.proxy.troubleshoot" in p), "The pref should be absent because it's in the pref regexes " + "that are disallowed."
);
ok(
!("dom.push.userAgentID" in p), "The pref should be absent because it's in the pref regexes " + "that are disallowed."
);
ok(
!("print.print_to_filename" in p), "The pref should be absent because it's not in the allowed prefs."
);
prefs.forEach(p => Services.prefs.deleteBranch(p));
Services.prefs.clearUserPref("dom.push.userAgentID");
});
add_task(async function unicodePreferences() {
let name = "font.name.sans-serif.x-western";
let utf8Value = "\xc4\x8capk\xc5\xafv Krasopis";
let unicodeValue = "\u010Capk\u016Fv Krasopis";
// set/getCharPref work with 8bit strings (utf8)
Services.prefs.setCharPref(name, utf8Value);
let snapshot = await Troubleshoot.snapshot();
let p = snapshot.modifiedPreferences;
is(p[name], unicodeValue, "The pref should have correct Unicode value.");
Services.prefs.deleteBranch(name);
});
add_task(async function printingPreferences() {
let prefs = [ "javascript.print_to_filename", "print.print_bgimages", "print.print_to_filename",
];
prefs.forEach(function (p) {
Services.prefs.setBoolPref(p, true);
is(Services.prefs.getBoolPref(p), true, "The pref should be set: " + p);
});
let snapshot = await Troubleshoot.snapshot();
let p = snapshot.printingPreferences;
is(p["print.print_bgimages"], true, "The pref should be present");
ok(
!("print.print_to_filename" in p), "The pref should not be present (sensitive)"
);
ok(
!("javascript.print_to_filename" in p), "The pref should be absent because it's not a print pref."
);
prefs.forEach(p => Services.prefs.deleteBranch(p));
});
return NormandyTestUtils.decorate(
PreferenceExperiments.withMockExperiments([
preferenceStudyFactory({
userFacingName: "Test Pref Study B",
branch: "test-branch-pref",
}),
preferenceStudyFactory({
userFacingName: "Test Pref Study A",
branch: "test-branch-pref",
}),
]),
AddonStudies.withStudies([
branchedAddonStudyFactory({
userFacingName: "Test Addon Study B",
branch: "test-branch-addon",
}),
branchedAddonStudyFactory({
userFacingName: "Test Addon Study A",
branch: "test-branch-addon",
}),
]),
PreferenceRollouts.withTestMock({
rollouts: [
preferenceRolloutFactory({
statue: "ACTIVE",
slug: "test-pref-rollout-b",
}),
preferenceRolloutFactory({
statue: "ACTIVE",
slug: "test-pref-rollout-a",
}),
],
}),
async function testNormandyInfoInTroubleshooting({
prefExperiments,
addonStudies,
prefRollouts,
}) {
let snapshot = await Troubleshoot.snapshot();
let info = snapshot.normandy; // The order should be flipped, since each category is sorted by slug. Assert.deepEqual(
info.prefStudies,
[prefExperiments[1], prefExperiments[0]], "prefs studies should exist in the right order"
); Assert.deepEqual(
info.addonStudies,
[addonStudies[1], addonStudies[0]], "addon studies should exist in the right order"
); Assert.deepEqual(
info.prefRollouts,
[prefRollouts[1], prefRollouts[0]], "pref rollouts should exist in the right order"
);
}
)();
});
add_task(function normandyErrorHandling() { return NormandyTestUtils.decorate(
NormandyTestUtils.withStub(PreferenceExperiments, "getAllActive", {
returnValue: Promise.reject("Expected error - PreferenceExperiments"),
}),
NormandyTestUtils.withStub(AddonStudies, "getAllActive", {
returnValue: Promise.reject("Expected error - AddonStudies"),
}),
NormandyTestUtils.withStub(PreferenceRollouts, "getAllActive", {
returnValue: Promise.reject("Expected error - PreferenceRollouts"),
}),
async function testNormandyErrorHandling() {
let consoleEndFn = TestUtils.listenForConsoleMessages();
let snapshot = await Troubleshoot.snapshot();
let info = snapshot.normandy; Assert.deepEqual(
info.prefStudies,
[], "prefs studies should be an empty list if there is an error"
); Assert.deepEqual(
info.addonStudies,
[], "addon studies should be an empty list if there is an error"
); Assert.deepEqual(
info.prefRollouts,
[], "pref rollouts should be an empty list if there is an error"
);
let msgs = await consoleEndFn();
let expectedSet = new Set([
/Expected error - PreferenceExperiments/,
/Expected error - AddonStudies/,
/Expected error - PreferenceRollouts/,
]);
for (let msg of msgs) {
msg = msg.wrappedJSObject; if (msg.level != "error") { continue;
}
let msgContents = msg.arguments[0]; for (let expected of expectedSet) { if (expected.test(msgContents)) {
expectedSet.delete(expected); break;
}
}
}
Assert.equal(
expectedSet.size,
0, "Should have no messages left in the expected set"
);
}
)();
});
add_task(async function themes() {
let snapshot = await Troubleshoot.snapshot();
let foundTheme = false; for (let addon of snapshot.addons) { if (addon.type == "theme") {
foundTheme = true; break;
}
}
ok(foundTheme, "found a theme in the addons list");
});
/** * Throws an Error if obj doesn't conform to schema. That way you get a nice * error message and a stack to help you figure out what went wrong, which you * wouldn't get if this just returned true or false instead. There's still * room for improvement in communicating validation failures, however. * * @param obj The object to validate. * @param schema The schema that obj should conform to.
*/ function validateObject(obj, schema) { if (obj === undefined && !schema.required) { return;
}
let types = Array.isArray(schema.type) ? schema.type : [schema.type]; if (!types.every(elt => typeof elt == "string")) { throw schemaErr("'type' must be a string or array of strings", schema);
} if (!types.includes(objType(obj))) { throw validationErr("Object is not of the expected type", obj, schema);
}
let lastError; for (let type of types) {
let validatorFnName = "validateObject_" + type; if (!(validatorFnName in this)) { throw schemaErr("Validator function not defined for type", schema);
} try { this[validatorFnName](obj, schema); return;
} catch (e) {
lastError = e;
}
} throw lastError;
}
function validateObject_object(obj, schema) { if (typeof schema.properties != "object") { // Don't care what obj's properties are. return;
} // First check that all the schema's properties match the object. for (let prop in schema.properties) {
validateObject(obj[prop], schema.properties[prop]);
} // Now check that the object doesn't have any properties not in the schema. if (!schema.additionalProperties) { for (let prop in obj) { if (!(prop in schema.properties)) { throw validationErr( "Object has property " + prop + " not in schema",
obj,
schema
);
}
}
}
}
function validateObject_array(array, schema) { if (typeof schema.items != "object") { // Don't care what the array's elements are. return;
}
array.forEach(elt => validateObject(elt, schema.items));
}
function validateObject_string() {} function validateObject_boolean() {} function validateObject_number() {}
function objType(obj) {
let type = typeof obj; if (type != "object") { return type;
} if (Array.isArray(obj)) { return"array";
} if (obj === null) { return"null";
} return type;
}
Messung V0.5
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.24Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.