summaryrefslogtreecommitdiffstats
path: root/toolkit/modules/tests/browser/browser_Troubleshoot.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/modules/tests/browser/browser_Troubleshoot.js')
-rw-r--r--toolkit/modules/tests/browser/browser_Troubleshoot.js546
1 files changed, 546 insertions, 0 deletions
diff --git a/toolkit/modules/tests/browser/browser_Troubleshoot.js b/toolkit/modules/tests/browser/browser_Troubleshoot.js
new file mode 100644
index 000000000..34c2a2791
--- /dev/null
+++ b/toolkit/modules/tests/browser/browser_Troubleshoot.js
@@ -0,0 +1,546 @@
+/* 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.
+
+Components.utils.import("resource://gre/modules/AppConstants.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/Troubleshoot.jsm");
+
+function test() {
+ waitForExplicitFinish();
+ function doNextTest() {
+ if (!tests.length) {
+ finish();
+ return;
+ }
+ tests.shift()(doNextTest);
+ }
+ doNextTest();
+}
+
+registerCleanupFunction(function () {
+ // Troubleshoot.jsm is imported into the global scope -- the window -- above.
+ // If it's not deleted, it outlives the test and is reported as a leak.
+ delete window.Troubleshoot;
+});
+
+var tests = [
+
+ function snapshotSchema(done) {
+ Troubleshoot.snapshot(function (snapshot) {
+ try {
+ validateObject(snapshot, SNAPSHOT_SCHEMA);
+ ok(true, "The snapshot should conform to the schema.");
+ }
+ catch (err) {
+ ok(false, "Schema mismatch, " + err);
+ }
+ done();
+ });
+ },
+
+ function modifiedPreferences(done) {
+ let prefs = [
+ "javascript.troubleshoot",
+ "troubleshoot.foo",
+ "javascript.print_to_filename",
+ "network.proxy.troubleshoot",
+ ];
+ prefs.forEach(function (p) {
+ Services.prefs.setBoolPref(p, true);
+ is(Services.prefs.getBoolPref(p), true, "The pref should be set: " + p);
+ });
+ Troubleshoot.snapshot(function (snapshot) {
+ let p = snapshot.modifiedPreferences;
+ is(p["javascript.troubleshoot"], true,
+ "The pref should be present because it's whitelisted " +
+ "but not blacklisted.");
+ ok(!("troubleshoot.foo" in p),
+ "The pref should be absent because it's not in the whitelist.");
+ ok(!("javascript.print_to_filename" in p),
+ "The pref should be absent because it's blacklisted.");
+ ok(!("network.proxy.troubleshoot" in p),
+ "The pref should be absent because it's blacklisted.");
+ prefs.forEach(p => Services.prefs.deleteBranch(p));
+ done();
+ });
+ },
+
+ function unicodePreferences(done) {
+ 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);
+
+ Troubleshoot.snapshot(function (snapshot) {
+ let p = snapshot.modifiedPreferences;
+ is(p[name], unicodeValue, "The pref should have correct Unicode value.");
+ Services.prefs.deleteBranch(name);
+ done();
+ });
+ }
+];
+
+// This is inspired by JSON Schema, or by the example on its Wikipedia page
+// anyway.
+const SNAPSHOT_SCHEMA = {
+ type: "object",
+ required: true,
+ properties: {
+ application: {
+ required: true,
+ type: "object",
+ properties: {
+ name: {
+ required: true,
+ type: "string",
+ },
+ version: {
+ required: true,
+ type: "string",
+ },
+ buildID: {
+ required: true,
+ type: "string",
+ },
+ userAgent: {
+ required: true,
+ type: "string",
+ },
+ osVersion: {
+ required: true,
+ type: "string",
+ },
+ vendor: {
+ type: "string",
+ },
+ updateChannel: {
+ type: "string",
+ },
+ supportURL: {
+ type: "string",
+ },
+ remoteAutoStart: {
+ type: "boolean",
+ required: true,
+ },
+ autoStartStatus: {
+ type: "number",
+ },
+ numTotalWindows: {
+ type: "number",
+ },
+ numRemoteWindows: {
+ type: "number",
+ },
+ safeMode: {
+ type: "boolean",
+ },
+ },
+ },
+ crashes: {
+ required: false,
+ type: "object",
+ properties: {
+ pending: {
+ required: true,
+ type: "number",
+ },
+ submitted: {
+ required: true,
+ type: "array",
+ items: {
+ type: "object",
+ properties: {
+ id: {
+ required: true,
+ type: "string",
+ },
+ date: {
+ required: true,
+ type: "number",
+ },
+ pending: {
+ required: true,
+ type: "boolean",
+ },
+ },
+ },
+ },
+ },
+ },
+ extensions: {
+ required: true,
+ type: "array",
+ items: {
+ type: "object",
+ properties: {
+ name: {
+ required: true,
+ type: "string",
+ },
+ version: {
+ required: true,
+ type: "string",
+ },
+ id: {
+ required: true,
+ type: "string",
+ },
+ isActive: {
+ required: true,
+ type: "boolean",
+ },
+ },
+ },
+ },
+ modifiedPreferences: {
+ required: true,
+ type: "object",
+ },
+ lockedPreferences: {
+ required: true,
+ type: "object",
+ },
+ graphics: {
+ required: true,
+ type: "object",
+ properties: {
+ numTotalWindows: {
+ required: true,
+ type: "number",
+ },
+ numAcceleratedWindows: {
+ required: true,
+ type: "number",
+ },
+ windowLayerManagerType: {
+ type: "string",
+ },
+ windowLayerManagerRemote: {
+ type: "boolean",
+ },
+ supportsHardwareH264: {
+ type: "string",
+ },
+ currentAudioBackend: {
+ type: "string",
+ },
+ numAcceleratedWindowsMessage: {
+ type: "array",
+ },
+ adapterDescription: {
+ type: "string",
+ },
+ adapterVendorID: {
+ type: "string",
+ },
+ adapterDeviceID: {
+ type: "string",
+ },
+ adapterSubsysID: {
+ type: "string",
+ },
+ adapterRAM: {
+ type: "string",
+ },
+ adapterDrivers: {
+ type: "string",
+ },
+ driverVersion: {
+ type: "string",
+ },
+ driverDate: {
+ type: "string",
+ },
+ adapterDescription2: {
+ type: "string",
+ },
+ adapterVendorID2: {
+ type: "string",
+ },
+ adapterDeviceID2: {
+ type: "string",
+ },
+ adapterSubsysID2: {
+ type: "string",
+ },
+ adapterRAM2: {
+ type: "string",
+ },
+ adapterDrivers2: {
+ type: "string",
+ },
+ driverVersion2: {
+ type: "string",
+ },
+ driverDate2: {
+ type: "string",
+ },
+ isGPU2Active: {
+ type: "boolean",
+ },
+ direct2DEnabled: {
+ type: "boolean",
+ },
+ directWriteEnabled: {
+ type: "boolean",
+ },
+ directWriteVersion: {
+ type: "string",
+ },
+ clearTypeParameters: {
+ type: "string",
+ },
+ webglRenderer: {
+ type: "string",
+ },
+ webgl2Renderer: {
+ type: "string",
+ },
+ info: {
+ type: "object",
+ },
+ failures: {
+ type: "array",
+ items: {
+ type: "string",
+ },
+ },
+ indices: {
+ type: "array",
+ items: {
+ type: "number",
+ },
+ },
+ featureLog: {
+ type: "object",
+ },
+ crashGuards: {
+ type: "array",
+ },
+ direct2DEnabledMessage: {
+ type: "array",
+ },
+ },
+ },
+ javaScript: {
+ required: true,
+ type: "object",
+ properties: {
+ incrementalGCEnabled: {
+ type: "boolean",
+ },
+ },
+ },
+ accessibility: {
+ required: true,
+ type: "object",
+ properties: {
+ isActive: {
+ required: true,
+ type: "boolean",
+ },
+ forceDisabled: {
+ type: "number",
+ },
+ },
+ },
+ libraryVersions: {
+ required: true,
+ type: "object",
+ properties: {
+ NSPR: {
+ required: true,
+ type: "object",
+ properties: {
+ minVersion: {
+ required: true,
+ type: "string",
+ },
+ version: {
+ required: true,
+ type: "string",
+ },
+ },
+ },
+ NSS: {
+ required: true,
+ type: "object",
+ properties: {
+ minVersion: {
+ required: true,
+ type: "string",
+ },
+ version: {
+ required: true,
+ type: "string",
+ },
+ },
+ },
+ NSSUTIL: {
+ required: true,
+ type: "object",
+ properties: {
+ minVersion: {
+ required: true,
+ type: "string",
+ },
+ version: {
+ required: true,
+ type: "string",
+ },
+ },
+ },
+ NSSSSL: {
+ required: true,
+ type: "object",
+ properties: {
+ minVersion: {
+ required: true,
+ type: "string",
+ },
+ version: {
+ required: true,
+ type: "string",
+ },
+ },
+ },
+ NSSSMIME: {
+ required: true,
+ type: "object",
+ properties: {
+ minVersion: {
+ required: true,
+ type: "string",
+ },
+ version: {
+ required: true,
+ type: "string",
+ },
+ },
+ },
+ },
+ },
+ userJS: {
+ required: true,
+ type: "object",
+ properties: {
+ exists: {
+ required: true,
+ type: "boolean",
+ },
+ },
+ },
+ experiments: {
+ type: "array",
+ },
+ sandbox: {
+ required: false,
+ type: "object",
+ properties: {
+ hasSeccompBPF: {
+ required: AppConstants.platform == "linux",
+ type: "boolean"
+ },
+ hasSeccompTSync: {
+ required: AppConstants.platform == "linux",
+ type: "boolean"
+ },
+ hasUserNamespaces: {
+ required: AppConstants.platform == "linux",
+ type: "boolean"
+ },
+ hasPrivilegedUserNamespaces: {
+ required: AppConstants.platform == "linux",
+ type: "boolean"
+ },
+ canSandboxContent: {
+ required: false,
+ type: "boolean"
+ },
+ canSandboxMedia: {
+ required: false,
+ type: "boolean"
+ },
+ contentSandboxLevel: {
+ required: AppConstants.MOZ_CONTENT_SANDBOX,
+ type: "number"
+ },
+ },
+ },
+ },
+};
+
+/**
+ * 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;
+ if (typeof(schema.type) != "string")
+ throw schemaErr("'type' must be a string", schema);
+ if (objType(obj) != schema.type)
+ throw validationErr("Object is not of the expected type", obj, schema);
+ let validatorFnName = "validateObject_" + schema.type;
+ if (!(validatorFnName in this))
+ throw schemaErr("Validator function not defined for type", schema);
+ this[validatorFnName](obj, schema);
+}
+
+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.
+ 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(str, schema) {}
+function validateObject_boolean(bool, schema) {}
+function validateObject_number(num, schema) {}
+
+function validationErr(msg, obj, schema) {
+ return new Error("Validation error: " + msg +
+ ": object=" + JSON.stringify(obj) +
+ ", schema=" + JSON.stringify(schema));
+}
+
+function schemaErr(msg, schema) {
+ return new Error("Schema error: " + msg + ": " + JSON.stringify(schema));
+}
+
+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;
+}