fune/modules/libpref/test/unit_ipc/test_sharedMap.js
2019-02-21 00:50:18 +00:00

301 lines
9.6 KiB
JavaScript

/* 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/. */
"use strict";
// This file tests the functionality of the preference service when using a
// shared memory snapshot. In this configuration, a snapshot of the initial
// state of the preferences database is made when we first spawn a child
// process, and changes after that point are stored as entries in a dynamic hash
// table, on top of the snapshot.
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {ExtensionTestUtils} = ChromeUtils.import("resource://testing-common/ExtensionXPCShellUtils.jsm");
ExtensionTestUtils.init(this);
let contentPage;
const {prefs} = Services;
const defaultPrefs = prefs.getDefaultBranch("");
const FRAME_SCRIPT_INIT = `
ChromeUtils.import("resource://gre/modules/Services.jsm");
var {prefs} = Services;
var defaultPrefs = prefs.getDefaultBranch("");
`;
function try_(fn) {
try {
return fn();
} catch (e) {
return undefined;
}
}
function getPref(pref) {
let flags = {
locked: try_(() => prefs.prefIsLocked(pref)),
hasUser: try_(() => prefs.prefHasUserValue(pref)),
};
switch (prefs.getPrefType(pref)) {
case prefs.PREF_INT:
return {
...flags,
type: "Int",
user: try_(() => prefs.getIntPref(pref)),
default: try_(() => defaultPrefs.getIntPref(pref)),
};
case prefs.PREF_BOOL:
return {
...flags,
type: "Bool",
user: try_(() => prefs.getBoolPref(pref)),
default: try_(() => defaultPrefs.getBoolPref(pref)),
};
case prefs.PREF_STRING:
return {
...flags,
type: "String",
user: try_(() => prefs.getStringPref(pref)),
default: try_(() => defaultPrefs.getStringPref(pref)),
};
}
return {};
}
function getPrefs(prefNames) {
let result = {};
for (let pref of prefNames) {
result[pref] = getPref(pref);
}
result.childList = prefs.getChildList("");
return result;
}
function checkPref(pref, proc, val, type, userVal, defaultVal, expectedFlags = {}) {
info(`Check "${pref}" ${proc} value`);
equal(val.type, type, `Expected type for "${pref}"`);
equal(val.user, userVal, `Expected user value for "${pref}"`);
// We only send changes to the content process when they'll make a visible
// difference, so ignore content process default values when we have a defined
// user value.
if (proc !== "content" || val.user === undefined) {
equal(val.default, defaultVal, `Expected default value for "${pref}"`);
}
for (let [flag, value] of Object.entries(expectedFlags)) {
equal(val[flag], value, `Expected ${flag} value for "${pref}"`);
}
}
function getPrefList() {
return prefs.getChildList("");
}
const TESTS = {
"exists.thenDoesNot": {
beforeContent(PREF) {
prefs.setBoolPref(PREF, true);
ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
},
contentStartup(PREF, val, childList) {
ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
ok(childList.includes(PREF), `Child list includes "${PREF}"`);
prefs.clearUserPref(PREF);
ok(!getPrefList().includes(PREF), `Parent list doesn't include "${PREF}"`);
},
contentUpdate1(PREF, val, childList) {
ok(!getPrefList().includes(PREF), `Parent list doesn't include "${PREF}"`);
ok(!childList.includes(PREF), `Child list doesn't include "${PREF}"`);
prefs.setCharPref(PREF, "foo");
ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
checkPref(PREF, "parent", getPref(PREF), "String", "foo");
},
contentUpdate2(PREF, val, childList) {
ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
ok(childList.includes(PREF), `Child list includes "${PREF}"`);
checkPref(PREF, "parent", getPref(PREF), "String", "foo");
checkPref(PREF, "child", val, "String", "foo");
},
},
"doesNotExists.thenDoes": {
contentStartup(PREF, val, childList) {
ok(!getPrefList().includes(PREF), `Parent list doesn't include "${PREF}"`);
ok(!childList.includes(PREF), `Child list doesn't include "${PREF}"`);
prefs.setIntPref(PREF, 42);
ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
},
contentUpdate1(PREF, val, childList) {
ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
ok(childList.includes(PREF), `Child list includes "${PREF}"`);
checkPref(PREF, "parent", getPref(PREF), "Int", 42);
checkPref(PREF, "child", val, "Int", 42);
},
},
};
const PREFS = [
{type: "Bool", values: [true, false, true]},
{type: "Int", values: [24, 42, 73]},
{type: "String", values: ["meh", "hem", "hrm"]},
];
for (let {type, values} of PREFS) {
let set = `set${type}Pref`;
function prefTest(opts) {
function check(pref, proc, val, {expectedVal, defaultVal = undefined, expectedDefault = defaultVal, expectedFlags = {}}) {
checkPref(pref, proc, val, type, expectedVal, expectedDefault, expectedFlags);
}
function updatePref(PREF,
{userVal = undefined,
defaultVal = undefined,
flags = {}}) {
info(`Update "${PREF}"`);
if (userVal !== undefined) {
prefs[set](PREF, userVal);
}
if (defaultVal !== undefined) {
defaultPrefs[set](PREF, defaultVal);
}
if (flags.locked === true) {
prefs.lockPref(PREF);
} else if (flags.locked === false) {
prefs.unlockPref(PREF);
}
}
return {
beforeContent(PREF) {
updatePref(PREF, opts.initial);
check(PREF, "parent", getPref(PREF), opts.initial);
},
contentStartup(PREF, contentVal) {
check(PREF, "content", contentVal, opts.initial);
check(PREF, "parent", getPref(PREF), opts.initial);
updatePref(PREF, opts.change1);
check(PREF, "parent", getPref(PREF), opts.change1);
},
contentUpdate1(PREF, contentVal) {
check(PREF, "content", contentVal, opts.change1);
check(PREF, "parent", getPref(PREF), opts.change1);
if (opts.change2) {
updatePref(PREF, opts.change2);
check(PREF, "parent", getPref(PREF), opts.change2);
}
},
contentUpdate2(PREF, contentVal) {
if (opts.change2) {
check(PREF, "content", contentVal, opts.change2);
check(PREF, "parent", getPref(PREF), opts.change2);
}
},
};
}
for (let i of [0, 1]) {
let userVal = values[i];
let defaultVal = values[+!i];
TESTS[`type.${type}.${i}.default`] = prefTest({
initial: {defaultVal, expectedVal: defaultVal},
change1: {defaultVal: values[2], expectedVal: values[2]},
});
TESTS[`type.${type}.${i}.user`] = prefTest({
initial: {userVal, expectedVal: userVal},
change1: {defaultVal: values[2], expectedVal: userVal},
change2: {userVal: values[2],
expectedDefault: values[2],
expectedVal: values[2]},
});
TESTS[`type.${type}.${i}.both`] = prefTest({
initial: {userVal, defaultVal, expectedVal: userVal},
change1: {defaultVal: values[2], expectedVal: userVal},
change2: {userVal: values[2],
expectedDefault: values[2],
expectedVal: values[2]},
});
TESTS[`type.${type}.${i}.both.thenLock`] = prefTest({
initial: {userVal, defaultVal, expectedVal: userVal},
change1: {expectedDefault: defaultVal,
expectedVal: defaultVal,
flags: {locked: true},
expectFlags: {locked: true}},
});
TESTS[`type.${type}.${i}.both.thenUnlock`] = prefTest({
initial: {userVal, defaultVal, expectedVal: defaultVal,
flags: {locked: true}, expectedFlags: {locked: true}},
change1: {expectedDefault: defaultVal,
expectedVal: userVal,
flags: {locked: false},
expectFlags: {locked: false}},
});
TESTS[`type.${type}.${i}.both.locked`] = prefTest({
initial: {userVal, defaultVal, expectedVal: defaultVal,
flags: {locked: true}, expectedFlags: {locked: true}},
change1: {userVal: values[2],
expectedDefault: defaultVal,
expectedVal: defaultVal,
expectedFlags: {locked: true}},
change2: {defaultVal: values[2],
expectedDefault: defaultVal,
expectedVal: defaultVal,
expectedFlags: {locked: true}},
});
}
}
add_task(async function test_sharedMap_prefs() {
let prefValues = {};
async function runChecks(op) {
for (let [pref, ops] of Object.entries(TESTS)) {
if (ops[op]) {
info(`Running ${op} for "${pref}"`);
await ops[op](pref,
prefValues[pref] || undefined,
prefValues.childList || undefined);
}
}
}
await runChecks("beforeContent");
contentPage = await ExtensionTestUtils.loadContentPage("about:blank", {remote: true});
registerCleanupFunction(() => contentPage.close());
contentPage.addFrameScriptHelper(FRAME_SCRIPT_INIT);
contentPage.addFrameScriptHelper(try_);
contentPage.addFrameScriptHelper(getPref);
let prefNames = Object.keys(TESTS);
prefValues = await contentPage.spawn(prefNames, getPrefs);
await runChecks("contentStartup");
prefValues = await contentPage.spawn(prefNames, getPrefs);
await runChecks("contentUpdate1");
prefValues = await contentPage.spawn(prefNames, getPrefs);
await runChecks("contentUpdate2");
});