tor-browser

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

browser_target_command_tab_workers.js (11635B)


      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 IFRAME_FILE = "fission_iframe.html";
     10 const REMOTE_IFRAME_URL = URL_ROOT_ORG_SSL + IFRAME_FILE;
     11 const IFRAME_URL = URL_ROOT_SSL + IFRAME_FILE;
     12 const WORKER_FILE = "test_worker.js";
     13 const WORKER_URL = URL_ROOT_SSL + WORKER_FILE;
     14 const REMOTE_IFRAME_WORKER_URL = URL_ROOT_ORG_SSL + WORKER_FILE;
     15 
     16 add_task(async function () {
     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  // The WorkerDebuggerManager#getWorkerDebuggerEnumerator method we're using to retrieve
     22  // workers loops through _all_ the workers in the process, which means it goes over workers
     23  // from other tabs as well. Here we add a few tabs that are not going to be used in the
     24  // test, just to check that their workers won't be retrieved by getAllTargets/watchTargets.
     25  await addTab(`${FISSION_TEST_URL}?id=first-untargetted-tab&noServiceWorker`);
     26  await addTab(`${FISSION_TEST_URL}?id=second-untargetted-tab&noServiceWorker`);
     27 
     28  info("Test TargetCommand against workers via a tab target");
     29  const tab = await addTab(`${FISSION_TEST_URL}?&noServiceWorker`);
     30 
     31  // Create a TargetCommand for the tab
     32  const commands = await CommandsFactory.forTab(tab);
     33  const targetCommand = commands.targetCommand;
     34 
     35  // Workaround to allow listening for workers in the content toolbox
     36  // without the fission preferences
     37  targetCommand.listenForWorkers = true;
     38 
     39  await commands.targetCommand.startListening();
     40 
     41  const { TYPES } = targetCommand;
     42 
     43  info("Check that getAllTargets only returns dedicated workers");
     44  const workers = await targetCommand.getAllTargets([
     45    TYPES.WORKER,
     46    TYPES.SHARED_WORKER,
     47  ]);
     48 
     49  // XXX: This should be modified in Bug 1607778, where we plan to add support for shared workers.
     50  is(workers.length, 2, "Retrieved two worker…");
     51  const mainPageWorker = workers.find(
     52    worker => worker.url == `${WORKER_URL}#simple-worker`
     53  );
     54  is(
     55    mainPageWorker.name,
     56    "Simple worker",
     57    "The custom worker name is exposed on the target object"
     58  );
     59  const iframeWorker = workers.find(worker => {
     60    return worker.url == `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-iframe`;
     61  });
     62  ok(mainPageWorker, "…the dedicated worker on the main page");
     63  ok(iframeWorker, "…and the dedicated worker on the iframe");
     64 
     65  info(
     66    "Assert that watchTargets will call the create callback for existing dedicated workers"
     67  );
     68  const targets = [];
     69  const destroyedTargets = [];
     70  const onAvailable = async ({ targetFront }) => {
     71    info(`onAvailable called for ${targetFront.url}`);
     72    is(
     73      targetFront.targetType,
     74      TYPES.WORKER,
     75      "We are only notified about worker targets"
     76    );
     77    ok(!targetFront.isTopLevel, "The workers are never top level");
     78    targets.push(targetFront);
     79    info(`Handled ${targets.length} targets\n`);
     80  };
     81  const onDestroyed = async ({ targetFront }) => {
     82    is(
     83      targetFront.targetType,
     84      TYPES.WORKER,
     85      "We are only notified about worker targets"
     86    );
     87    ok(!targetFront.isTopLevel, "The workers are never top level");
     88    destroyedTargets.push(targetFront);
     89  };
     90 
     91  await targetCommand.watchTargets({
     92    types: [TYPES.WORKER, TYPES.SHARED_WORKER],
     93    onAvailable,
     94    onDestroyed,
     95  });
     96 
     97  // XXX: This should be modified in Bug 1607778, where we plan to add support for shared workers.
     98  info("Check that watched targets return the same fronts as getAllTargets");
     99  is(targets.length, 2, "watcheTargets retrieved 2 worker…");
    100  const mainPageWorkerTarget = targets.find(t => t === mainPageWorker);
    101  const iframeWorkerTarget = targets.find(t => t === iframeWorker);
    102 
    103  ok(
    104    mainPageWorkerTarget,
    105    "…the dedicated worker in main page, which is the same front we received from getAllTargets"
    106  );
    107  ok(
    108    iframeWorkerTarget,
    109    "…the dedicated worker in iframe, which is the same front we received from getAllTargets"
    110  );
    111 
    112  info("Spawn workers in main page and iframe");
    113  await SpecialPowers.spawn(tab.linkedBrowser, [WORKER_FILE], workerUrl => {
    114    // Put the worker on the global so we can access it later
    115    content.spawnedWorker = new content.Worker(`${workerUrl}#spawned-worker`);
    116    const iframe = content.document.querySelector("iframe");
    117    SpecialPowers.spawn(iframe, [workerUrl], innerWorkerUrl => {
    118      // Put the worker on the global so we can access it later
    119      content.spawnedWorker = new content.Worker(
    120        `${innerWorkerUrl}#spawned-worker-in-iframe`
    121      );
    122    });
    123  });
    124 
    125  await waitFor(
    126    () => targets.length === 4,
    127    "Wait for the target list to notify us about the spawned worker"
    128  );
    129  const mainPageSpawnedWorkerTarget = targets.find(
    130    innerTarget => innerTarget.url == `${WORKER_URL}#spawned-worker`
    131  );
    132  ok(mainPageSpawnedWorkerTarget, "Retrieved spawned worker");
    133  const iframeSpawnedWorkerTarget = targets.find(
    134    innerTarget =>
    135      innerTarget.url == `${REMOTE_IFRAME_WORKER_URL}#spawned-worker-in-iframe`
    136  );
    137  ok(iframeSpawnedWorkerTarget, "Retrieved spawned worker in iframe");
    138 
    139  await wait(100);
    140 
    141  info(
    142    "Check that the target list calls onDestroy when a worker is terminated"
    143  );
    144  await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
    145    content.spawnedWorker.terminate();
    146    content.spawnedWorker = null;
    147 
    148    SpecialPowers.spawn(content.document.querySelector("iframe"), [], () => {
    149      content.spawnedWorker.terminate();
    150      content.spawnedWorker = null;
    151    });
    152  });
    153  await waitFor(
    154    () =>
    155      destroyedTargets.includes(mainPageSpawnedWorkerTarget) &&
    156      destroyedTargets.includes(iframeSpawnedWorkerTarget),
    157    "Wait for the target list to notify us about the terminated workers"
    158  );
    159 
    160  ok(
    161    true,
    162    "The target list handled the terminated workers (from the main page and the iframe)"
    163  );
    164 
    165  info(
    166    "Check that reloading the page will notify about the terminated worker and the new existing one"
    167  );
    168  const targetsCountBeforeReload = targets.length;
    169  await reloadBrowser();
    170 
    171  await waitFor(() => {
    172    return (
    173      destroyedTargets.includes(mainPageWorkerTarget) &&
    174      destroyedTargets.includes(iframeWorkerTarget)
    175    );
    176  }, `Wait for the target list to notify us about the terminated workers when reloading`);
    177  ok(
    178    true,
    179    "The target list notified us about all the expected workers being destroyed when reloading"
    180  );
    181 
    182  await waitFor(
    183    () => targets.length === targetsCountBeforeReload + 2,
    184    "Wait for the target list to notify us about the new workers after reloading"
    185  );
    186 
    187  const mainPageWorkerTargetAfterReload = targets.find(
    188    t => t !== mainPageWorkerTarget && t.url == `${WORKER_URL}#simple-worker`
    189  );
    190  const iframeWorkerTargetAfterReload = targets.find(
    191    t =>
    192      t !== iframeWorkerTarget &&
    193      t.url == `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-iframe`
    194  );
    195 
    196  ok(
    197    mainPageWorkerTargetAfterReload,
    198    "The target list handled the worker created once the page navigated"
    199  );
    200  ok(
    201    iframeWorkerTargetAfterReload,
    202    "The target list handled the worker created in the iframe once the page navigated"
    203  );
    204 
    205  const targetCount = targets.length;
    206 
    207  info(
    208    "Check that when removing an iframe we're notified about its workers being terminated"
    209  );
    210  await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
    211    content.document.querySelector("iframe").remove();
    212  });
    213  await waitFor(() => {
    214    return destroyedTargets.includes(iframeWorkerTargetAfterReload);
    215  }, `Wait for the target list to notify us about the terminated workers when removing an iframe`);
    216 
    217  info("Check that target list handles adding iframes with workers");
    218  const iframeUrl = `${IFRAME_URL}?noServiceWorker=true&hashSuffix=in-created-iframe`;
    219  const remoteIframeUrl = `${REMOTE_IFRAME_URL}?noServiceWorker=true&hashSuffix=in-created-remote-iframe`;
    220 
    221  await SpecialPowers.spawn(
    222    tab.linkedBrowser,
    223    [iframeUrl, remoteIframeUrl],
    224    (url, remoteUrl) => {
    225      const firstIframe = content.document.createElement("iframe");
    226      content.document.body.append(firstIframe);
    227      firstIframe.src = url + "-1";
    228 
    229      const secondIframe = content.document.createElement("iframe");
    230      content.document.body.append(secondIframe);
    231      secondIframe.src = url + "-2";
    232 
    233      const firstRemoteIframe = content.document.createElement("iframe");
    234      content.document.body.append(firstRemoteIframe);
    235      firstRemoteIframe.src = remoteUrl + "-1";
    236 
    237      const secondRemoteIframe = content.document.createElement("iframe");
    238      content.document.body.append(secondRemoteIframe);
    239      secondRemoteIframe.src = remoteUrl + "-2";
    240    }
    241  );
    242 
    243  // It's important to check the length of `targets` here to ensure we don't get unwanted
    244  // worker targets.
    245  await waitFor(
    246    () => targets.length === targetCount + 4,
    247    "Wait for the target list to notify us about the workers in the new iframes"
    248  );
    249  const firstSpawnedIframeWorkerTarget = targets.find(
    250    worker => worker.url == `${WORKER_URL}#simple-worker-in-created-iframe-1`
    251  );
    252  const secondSpawnedIframeWorkerTarget = targets.find(
    253    worker => worker.url == `${WORKER_URL}#simple-worker-in-created-iframe-2`
    254  );
    255  const firstSpawnedRemoteIframeWorkerTarget = targets.find(
    256    worker =>
    257      worker.url ==
    258      `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-created-remote-iframe-1`
    259  );
    260  const secondSpawnedRemoteIframeWorkerTarget = targets.find(
    261    worker =>
    262      worker.url ==
    263      `${REMOTE_IFRAME_WORKER_URL}#simple-worker-in-created-remote-iframe-2`
    264  );
    265 
    266  ok(
    267    firstSpawnedIframeWorkerTarget,
    268    "The target list handled the worker in the first new same-origin iframe"
    269  );
    270  ok(
    271    secondSpawnedIframeWorkerTarget,
    272    "The target list handled the worker in the second new same-origin iframe"
    273  );
    274  ok(
    275    firstSpawnedRemoteIframeWorkerTarget,
    276    "The target list handled the worker in the first new remote iframe"
    277  );
    278  ok(
    279    secondSpawnedRemoteIframeWorkerTarget,
    280    "The target list handled the worker in the second new remote iframe"
    281  );
    282 
    283  info("Check that navigating away does destroy all targets");
    284  BrowserTestUtils.startLoadingURIString(
    285    tab.linkedBrowser,
    286    "data:text/html,<meta charset=utf8>Away"
    287  );
    288 
    289  await waitFor(
    290    () => destroyedTargets.length === targets.length,
    291    "Wait for all the targets to be reported as destroyed"
    292  );
    293 
    294  ok(
    295    destroyedTargets.includes(mainPageWorkerTargetAfterReload),
    296    "main page worker target was destroyed"
    297  );
    298  ok(
    299    destroyedTargets.includes(firstSpawnedIframeWorkerTarget),
    300    "first spawned same-origin iframe worker target was destroyed"
    301  );
    302  ok(
    303    destroyedTargets.includes(secondSpawnedIframeWorkerTarget),
    304    "second spawned same-origin iframe worker target was destroyed"
    305  );
    306  ok(
    307    destroyedTargets.includes(firstSpawnedRemoteIframeWorkerTarget),
    308    "first spawned remote iframe worker target was destroyed"
    309  );
    310  ok(
    311    destroyedTargets.includes(secondSpawnedRemoteIframeWorkerTarget),
    312    "second spawned remote iframe worker target was destroyed"
    313  );
    314 
    315  targetCommand.unwatchTargets({
    316    types: [TYPES.WORKER, TYPES.SHARED_WORKER],
    317    onAvailable,
    318    onDestroyed,
    319  });
    320  targetCommand.destroy();
    321 
    322  info("Unregister service workers so they don't appear in other tests.");
    323  await unregisterAllServiceWorkers(commands.client);
    324 
    325  BrowserTestUtils.removeTab(tab);
    326  await commands.destroy();
    327 });