tor-browser

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

browser_target_command_browser_workers.js (8242B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // Test the TargetCommand API around workers
      7 
      8 const FISSION_TEST_URL = URL_ROOT_SSL + "fission_document.html";
      9 const WORKER_FILE = "test_worker.js";
     10 const CHROME_WORKER_URL = CHROME_URL_ROOT + WORKER_FILE;
     11 const SERVICE_WORKER_URL = URL_ROOT_SSL + "test_service_worker.js";
     12 
     13 add_task(async function () {
     14  // Enabled fission's pref as the TargetCommand is almost disabled without it
     15  await pushPref("devtools.browsertoolbox.scope", "everything");
     16 
     17  // Disable the preloaded process as it creates processes intermittently
     18  // which forces the emission of RDP requests we aren't correctly waiting for.
     19  await pushPref("dom.ipc.processPrelaunch.enabled", false);
     20 
     21  const tab = await addTab(FISSION_TEST_URL);
     22 
     23  info("Test TargetCommand against workers via the parent process target");
     24 
     25  // Instantiate a worker in the parent process
     26  // eslint-disable-next-line no-unused-vars
     27  const worker = new Worker(CHROME_WORKER_URL + "#simple-worker");
     28  // eslint-disable-next-line no-unused-vars
     29  const sharedWorker = new SharedWorker(CHROME_WORKER_URL + "#shared-worker");
     30 
     31  const commands = await CommandsFactory.forMainProcess();
     32  const targetCommand = commands.targetCommand;
     33  const { TYPES } = targetCommand;
     34  await targetCommand.startListening();
     35 
     36  // Bug 1918267 - startListening may not collect all worker if any process is slow to respond (on tsan for example)
     37  // So that we have to wait for the worker to be received by the TargetCommand
     38  await waitFor(() =>
     39    targetCommand
     40      .getAllTargets([TYPES.SHARED_WORKER])
     41      .some(target => target.url == CHROME_WORKER_URL + "#shared-worker")
     42  );
     43 
     44  // Very naive sanity check against getAllTargets([workerType])
     45  info("Check that getAllTargets returned the expected targets");
     46  const workers = targetCommand.getAllTargets([TYPES.WORKER]);
     47  const hasWorker = workers.find(workerTarget => {
     48    return workerTarget.url == CHROME_WORKER_URL + "#simple-worker";
     49  });
     50  ok(hasWorker, "retrieve the target for the worker");
     51 
     52  const sharedWorkers = await targetCommand.getAllTargets([
     53    TYPES.SHARED_WORKER,
     54  ]);
     55  const hasSharedWorker = sharedWorkers.find(workerTarget => {
     56    return workerTarget.url == CHROME_WORKER_URL + "#shared-worker";
     57  });
     58  ok(hasSharedWorker, "retrieve the target for the shared worker");
     59 
     60  const serviceWorkers = await targetCommand.getAllTargets([
     61    TYPES.SERVICE_WORKER,
     62  ]);
     63  const hasServiceWorker = serviceWorkers.find(workerTarget => {
     64    return workerTarget.url == SERVICE_WORKER_URL;
     65  });
     66  ok(hasServiceWorker, "retrieve the target for the service worker");
     67 
     68  info(
     69    "Check that calling getAllTargets again return the same target instances"
     70  );
     71  const workers2 = await targetCommand.getAllTargets([TYPES.WORKER]);
     72  const sharedWorkers2 = await targetCommand.getAllTargets([
     73    TYPES.SHARED_WORKER,
     74  ]);
     75  const serviceWorkers2 = await targetCommand.getAllTargets([
     76    TYPES.SERVICE_WORKER,
     77  ]);
     78  is(workers2.length, workers.length, "retrieved the same number of workers");
     79  is(
     80    sharedWorkers2.length,
     81    sharedWorkers.length,
     82    "retrieved the same number of shared workers"
     83  );
     84  is(
     85    serviceWorkers2.length,
     86    serviceWorkers.length,
     87    "retrieved the same number of service workers"
     88  );
     89 
     90  workers.sort(sortFronts);
     91  workers2.sort(sortFronts);
     92  sharedWorkers.sort(sortFronts);
     93  sharedWorkers2.sort(sortFronts);
     94  serviceWorkers.sort(sortFronts);
     95  serviceWorkers2.sort(sortFronts);
     96 
     97  for (let i = 0; i < workers.length; i++) {
     98    is(workers[i], workers2[i], `worker ${i} targets are the same`);
     99  }
    100  for (let i = 0; i < sharedWorkers2.length; i++) {
    101    is(
    102      sharedWorkers[i],
    103      sharedWorkers2[i],
    104      `shared worker ${i} targets are the same`
    105    );
    106  }
    107  for (let i = 0; i < serviceWorkers2.length; i++) {
    108    is(
    109      serviceWorkers[i],
    110      serviceWorkers2[i],
    111      `service worker ${i} targets are the same`
    112    );
    113  }
    114 
    115  info(
    116    "Check that watchTargets will call the create callback for all existing workers"
    117  );
    118  const targets = [];
    119  const topLevelTarget = await commands.targetCommand.targetFront;
    120  const onAvailable = async ({ targetFront }) => {
    121    ok(
    122      targetFront.targetType === TYPES.WORKER ||
    123        targetFront.targetType === TYPES.SHARED_WORKER ||
    124        targetFront.targetType === TYPES.SERVICE_WORKER,
    125      "We are only notified about worker targets"
    126    );
    127    ok(
    128      targetFront == topLevelTarget
    129        ? targetFront.isTopLevel
    130        : !targetFront.isTopLevel,
    131      "isTopLevel property is correct"
    132    );
    133    targets.push(targetFront);
    134  };
    135  await targetCommand.watchTargets({
    136    types: [TYPES.WORKER, TYPES.SHARED_WORKER, TYPES.SERVICE_WORKER],
    137    onAvailable,
    138  });
    139  is(
    140    targets.length,
    141    workers.length + sharedWorkers.length + serviceWorkers.length,
    142    "retrieved the same number of workers via watchTargets"
    143  );
    144 
    145  targets.sort(sortFronts);
    146  const allWorkers = workers
    147    .concat(sharedWorkers, serviceWorkers)
    148    .sort(sortFronts);
    149 
    150  for (let i = 0; i < allWorkers.length; i++) {
    151    is(
    152      allWorkers[i],
    153      targets[i],
    154      `worker ${i} targets are the same via watchTargets`
    155    );
    156  }
    157 
    158  targetCommand.unwatchTargets({
    159    types: [TYPES.WORKER, TYPES.SHARED_WORKER, TYPES.SERVICE_WORKER],
    160    onAvailable,
    161  });
    162 
    163  // Create a new worker and see if the worker target is reported
    164  const onWorkerCreated = new Promise(resolve => {
    165    const onAvailable2 = async ({ targetFront }) => {
    166      if (targets.includes(targetFront)) {
    167        return;
    168      }
    169      if (!targetFront.url.startsWith(CHROME_WORKER_URL)) {
    170        // We might get unrelated workers eg for RemoteSettings.
    171        return;
    172      }
    173      targetCommand.unwatchTargets({
    174        types: [TYPES.WORKER],
    175        onAvailable: onAvailable2,
    176      });
    177      resolve(targetFront);
    178    };
    179    targetCommand.watchTargets({
    180      types: [TYPES.WORKER],
    181      onAvailable: onAvailable2,
    182    });
    183  });
    184  // eslint-disable-next-line no-unused-vars
    185  const worker2 = new Worker(CHROME_WORKER_URL + "#second");
    186  info("Wait for the second worker to be created");
    187  const workerTarget = await onWorkerCreated;
    188 
    189  is(
    190    workerTarget.url,
    191    CHROME_WORKER_URL + "#second",
    192    "This worker target is about the new worker"
    193  );
    194  is(
    195    workerTarget.name,
    196    "test_worker.js#second",
    197    "The worker target has the expected name"
    198  );
    199 
    200  const workers3 = await targetCommand.getAllTargets([TYPES.WORKER]);
    201  const hasWorker2 = workers3.find(
    202    ({ url }) => url == `${CHROME_WORKER_URL}#second`
    203  );
    204  ok(hasWorker2, "retrieve the target for tab via getAllTargets");
    205 
    206  info(
    207    "Check that terminating the worker does trigger the onDestroyed callback"
    208  );
    209  const onWorkerDestroyed = new Promise(resolve => {
    210    const emptyFn = () => {};
    211    const onDestroyed = ({ targetFront }) => {
    212      if (!targetFront.url.startsWith(CHROME_WORKER_URL)) {
    213        // We might get unrelated workers eg for RemoteSettings.
    214        return;
    215      }
    216      targetCommand.unwatchTargets({
    217        types: [TYPES.WORKER],
    218        onAvailable: emptyFn,
    219        onDestroyed,
    220      });
    221      resolve(targetFront);
    222    };
    223 
    224    targetCommand.watchTargets({
    225      types: [TYPES.WORKER],
    226      onAvailable: emptyFn,
    227      onDestroyed,
    228    });
    229  });
    230  worker2.terminate();
    231  const workerTargetFront = await onWorkerDestroyed;
    232  ok(true, "onDestroyed was called when the worker was terminated");
    233 
    234  workerTargetFront.isTopLevel;
    235  ok(
    236    true,
    237    "isTopLevel can be called on the target front after onDestroyed was called"
    238  );
    239 
    240  workerTargetFront.name;
    241  ok(
    242    true,
    243    "name can be accessed on the target front after onDestroyed was called"
    244  );
    245 
    246  targetCommand.destroy();
    247 
    248  info("Unregister service workers so they don't appear in other tests.");
    249  await unregisterAllServiceWorkers(commands.client);
    250 
    251  await commands.destroy();
    252 
    253  await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
    254    // registrationPromise is set by the test page.
    255    const registration = await content.wrappedJSObject.registrationPromise;
    256    registration.unregister();
    257  });
    258 });
    259 
    260 function sortFronts(f1, f2) {
    261  return f1.actorID < f2.actorID;
    262 }