tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_sharedMap.js (9978B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 "use strict";
      5 
      6 // This file tests the functionality of the preference service when using a
      7 // shared memory snapshot. In this configuration, a snapshot of the initial
      8 // state of the preferences database is made when we first spawn a child
      9 // process, and changes after that point are stored as entries in a dynamic hash
     10 // table, on top of the snapshot.
     11 
     12 const { XPCShellContentUtils } = ChromeUtils.importESModule(
     13  "resource://testing-common/XPCShellContentUtils.sys.mjs"
     14 );
     15 
     16 XPCShellContentUtils.init(this);
     17 
     18 let contentPage;
     19 
     20 const { prefs } = Services;
     21 const defaultPrefs = prefs.getDefaultBranch("");
     22 
     23 const FRAME_SCRIPT_INIT = `
     24  var { prefs } = Services;
     25  var defaultPrefs = prefs.getDefaultBranch("");
     26 `;
     27 
     28 function try_(fn) {
     29  try {
     30    return fn();
     31  } catch (e) {
     32    return undefined;
     33  }
     34 }
     35 
     36 function getPref(pref) {
     37  let flags = {
     38    locked: try_(() => prefs.prefIsLocked(pref)),
     39    hasUser: try_(() => prefs.prefHasUserValue(pref)),
     40  };
     41 
     42  switch (prefs.getPrefType(pref)) {
     43    case prefs.PREF_INT:
     44      return {
     45        ...flags,
     46        type: "Int",
     47        user: try_(() => prefs.getIntPref(pref)),
     48        default: try_(() => defaultPrefs.getIntPref(pref)),
     49      };
     50    case prefs.PREF_BOOL:
     51      return {
     52        ...flags,
     53        type: "Bool",
     54        user: try_(() => prefs.getBoolPref(pref)),
     55        default: try_(() => defaultPrefs.getBoolPref(pref)),
     56      };
     57    case prefs.PREF_STRING:
     58      return {
     59        ...flags,
     60        type: "String",
     61        user: try_(() => prefs.getStringPref(pref)),
     62        default: try_(() => defaultPrefs.getStringPref(pref)),
     63      };
     64  }
     65  return {};
     66 }
     67 
     68 function getPrefs(prefNames) {
     69  let result = {};
     70  for (let pref of prefNames) {
     71    result[pref] = getPref(pref);
     72  }
     73  result.childList = prefs.getChildList("");
     74  return result;
     75 }
     76 
     77 function checkPref(
     78  pref,
     79  proc,
     80  val,
     81  type,
     82  userVal,
     83  defaultVal,
     84  expectedFlags = {}
     85 ) {
     86  info(`Check "${pref}" ${proc} value`);
     87 
     88  equal(val.type, type, `Expected type for "${pref}"`);
     89  equal(val.user, userVal, `Expected user value for "${pref}"`);
     90 
     91  // We only send changes to the content process when they'll make a visible
     92  // difference, so ignore content process default values when we have a defined
     93  // user value.
     94  if (proc !== "content" || val.user === undefined) {
     95    equal(val.default, defaultVal, `Expected default value for "${pref}"`);
     96  }
     97 
     98  for (let [flag, value] of Object.entries(expectedFlags)) {
     99    equal(val[flag], value, `Expected ${flag} value for "${pref}"`);
    100  }
    101 }
    102 
    103 function getPrefList() {
    104  return prefs.getChildList("");
    105 }
    106 
    107 const TESTS = {
    108  "exists.thenDoesNot": {
    109    beforeContent(PREF) {
    110      prefs.setBoolPref(PREF, true);
    111 
    112      ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
    113    },
    114    contentStartup(PREF, val, childList) {
    115      ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
    116      ok(childList.includes(PREF), `Child list includes "${PREF}"`);
    117 
    118      prefs.clearUserPref(PREF);
    119      ok(
    120        !getPrefList().includes(PREF),
    121        `Parent list doesn't include "${PREF}"`
    122      );
    123    },
    124    contentUpdate1(PREF, val, childList) {
    125      ok(
    126        !getPrefList().includes(PREF),
    127        `Parent list doesn't include "${PREF}"`
    128      );
    129      ok(!childList.includes(PREF), `Child list doesn't include "${PREF}"`);
    130 
    131      prefs.setCharPref(PREF, "foo");
    132      ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
    133      checkPref(PREF, "parent", getPref(PREF), "String", "foo");
    134    },
    135    contentUpdate2(PREF, val, childList) {
    136      ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
    137      ok(childList.includes(PREF), `Child list includes "${PREF}"`);
    138 
    139      checkPref(PREF, "parent", getPref(PREF), "String", "foo");
    140      checkPref(PREF, "child", val, "String", "foo");
    141    },
    142  },
    143  "doesNotExists.thenDoes": {
    144    contentStartup(PREF, val, childList) {
    145      ok(
    146        !getPrefList().includes(PREF),
    147        `Parent list doesn't include "${PREF}"`
    148      );
    149      ok(!childList.includes(PREF), `Child list doesn't include "${PREF}"`);
    150 
    151      prefs.setIntPref(PREF, 42);
    152      ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
    153    },
    154    contentUpdate1(PREF, val, childList) {
    155      ok(getPrefList().includes(PREF), `Parent list includes "${PREF}"`);
    156      ok(childList.includes(PREF), `Child list includes "${PREF}"`);
    157 
    158      checkPref(PREF, "parent", getPref(PREF), "Int", 42);
    159      checkPref(PREF, "child", val, "Int", 42);
    160    },
    161  },
    162 };
    163 
    164 const PREFS = [
    165  { type: "Bool", values: [true, false, true] },
    166  { type: "Int", values: [24, 42, 73] },
    167  { type: "String", values: ["meh", "hem", "hrm"] },
    168 ];
    169 
    170 for (let { type, values } of PREFS) {
    171  let set = `set${type}Pref`;
    172 
    173  function prefTest(opts) {
    174    function check(
    175      pref,
    176      proc,
    177      val,
    178      {
    179        expectedVal,
    180        defaultVal = undefined,
    181        expectedDefault = defaultVal,
    182        expectedFlags = {},
    183      }
    184    ) {
    185      checkPref(
    186        pref,
    187        proc,
    188        val,
    189        type,
    190        expectedVal,
    191        expectedDefault,
    192        expectedFlags
    193      );
    194    }
    195 
    196    function updatePref(
    197      PREF,
    198      { userVal = undefined, defaultVal = undefined, flags = {} }
    199    ) {
    200      info(`Update "${PREF}"`);
    201      if (userVal !== undefined) {
    202        prefs[set](PREF, userVal);
    203      }
    204      if (defaultVal !== undefined) {
    205        defaultPrefs[set](PREF, defaultVal);
    206      }
    207      if (flags.locked === true) {
    208        prefs.lockPref(PREF);
    209      } else if (flags.locked === false) {
    210        prefs.unlockPref(PREF);
    211      }
    212    }
    213 
    214    return {
    215      beforeContent(PREF) {
    216        updatePref(PREF, opts.initial);
    217        check(PREF, "parent", getPref(PREF), opts.initial);
    218      },
    219      contentStartup(PREF, contentVal) {
    220        check(PREF, "content", contentVal, opts.initial);
    221        check(PREF, "parent", getPref(PREF), opts.initial);
    222 
    223        updatePref(PREF, opts.change1);
    224        check(PREF, "parent", getPref(PREF), opts.change1);
    225      },
    226      contentUpdate1(PREF, contentVal) {
    227        check(PREF, "content", contentVal, opts.change1);
    228        check(PREF, "parent", getPref(PREF), opts.change1);
    229 
    230        if (opts.change2) {
    231          updatePref(PREF, opts.change2);
    232          check(PREF, "parent", getPref(PREF), opts.change2);
    233        }
    234      },
    235      contentUpdate2(PREF, contentVal) {
    236        if (opts.change2) {
    237          check(PREF, "content", contentVal, opts.change2);
    238          check(PREF, "parent", getPref(PREF), opts.change2);
    239        }
    240      },
    241    };
    242  }
    243 
    244  for (let i of [0, 1]) {
    245    let userVal = values[i];
    246    let defaultVal = values[+!i];
    247 
    248    TESTS[`type.${type}.${i}.default`] = prefTest({
    249      initial: { defaultVal, expectedVal: defaultVal },
    250      change1: { defaultVal: values[2], expectedVal: values[2] },
    251    });
    252 
    253    TESTS[`type.${type}.${i}.user`] = prefTest({
    254      initial: { userVal, expectedVal: userVal },
    255      change1: { defaultVal: values[2], expectedVal: userVal },
    256      change2: {
    257        userVal: values[2],
    258        expectedDefault: values[2],
    259        expectedVal: values[2],
    260      },
    261    });
    262 
    263    TESTS[`type.${type}.${i}.both`] = prefTest({
    264      initial: { userVal, defaultVal, expectedVal: userVal },
    265      change1: { defaultVal: values[2], expectedVal: userVal },
    266      change2: {
    267        userVal: values[2],
    268        expectedDefault: values[2],
    269        expectedVal: values[2],
    270      },
    271    });
    272 
    273    TESTS[`type.${type}.${i}.both.thenLock`] = prefTest({
    274      initial: { userVal, defaultVal, expectedVal: userVal },
    275      change1: {
    276        expectedDefault: defaultVal,
    277        expectedVal: defaultVal,
    278        flags: { locked: true },
    279        expectFlags: { locked: true },
    280      },
    281    });
    282 
    283    TESTS[`type.${type}.${i}.both.thenUnlock`] = prefTest({
    284      initial: {
    285        userVal,
    286        defaultVal,
    287        expectedVal: defaultVal,
    288        flags: { locked: true },
    289        expectedFlags: { locked: true },
    290      },
    291      change1: {
    292        expectedDefault: defaultVal,
    293        expectedVal: userVal,
    294        flags: { locked: false },
    295        expectFlags: { locked: false },
    296      },
    297    });
    298 
    299    TESTS[`type.${type}.${i}.both.locked`] = prefTest({
    300      initial: {
    301        userVal,
    302        defaultVal,
    303        expectedVal: defaultVal,
    304        flags: { locked: true },
    305        expectedFlags: { locked: true },
    306      },
    307      change1: {
    308        userVal: values[2],
    309        expectedDefault: defaultVal,
    310        expectedVal: defaultVal,
    311        expectedFlags: { locked: true },
    312      },
    313      change2: {
    314        defaultVal: values[2],
    315        expectedDefault: defaultVal,
    316        expectedVal: defaultVal,
    317        expectedFlags: { locked: true },
    318      },
    319    });
    320  }
    321 }
    322 
    323 add_task(async function test_sharedMap_prefs() {
    324  let prefValues = {};
    325 
    326  async function runChecks(op) {
    327    for (let [pref, ops] of Object.entries(TESTS)) {
    328      if (ops[op]) {
    329        info(`Running ${op} for "${pref}"`);
    330        await ops[op](
    331          pref,
    332          prefValues[pref] || undefined,
    333          prefValues.childList || undefined
    334        );
    335      }
    336    }
    337  }
    338 
    339  await runChecks("beforeContent");
    340 
    341  contentPage = await XPCShellContentUtils.loadContentPage("about:blank", {
    342    remote: true,
    343  });
    344  registerCleanupFunction(() => contentPage.close());
    345 
    346  contentPage.addFrameScriptHelper(FRAME_SCRIPT_INIT);
    347  contentPage.addFrameScriptHelper(try_);
    348  contentPage.addFrameScriptHelper(getPref);
    349 
    350  let prefNames = Object.keys(TESTS);
    351  prefValues = await contentPage.legacySpawn(prefNames, getPrefs);
    352 
    353  await runChecks("contentStartup");
    354 
    355  prefValues = await contentPage.legacySpawn(prefNames, getPrefs);
    356 
    357  await runChecks("contentUpdate1");
    358 
    359  prefValues = await contentPage.legacySpawn(prefNames, getPrefs);
    360 
    361  await runChecks("contentUpdate2");
    362 });