tor-browser

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

test_install_event_gc.html (4471B)


      1 <!--
      2  Any copyright is dedicated to the Public Domain.
      3  http://creativecommons.org/publicdomain/zero/1.0/
      4 -->
      5 <!DOCTYPE HTML>
      6 <html>
      7 <head>
      8  <title>Test install event being GC'd before waitUntil fulfills</title>
      9  <script src="/tests/SimpleTest/SimpleTest.js"></script>
     10  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     11 </head>
     12 <body>
     13 <script class="testbody" type="text/javascript">
     14 var script = 'blocking_install_event_worker.js';
     15 var scope = 'sw_clients/simple.html?install-event-gc';
     16 var registration;
     17 
     18 function register() {
     19  return navigator.serviceWorker.register(script, { scope })
     20    .then(swr => registration = swr);
     21 }
     22 
     23 function unregister() {
     24  if (!registration) {
     25    return undefined;
     26  }
     27  return registration.unregister();
     28 }
     29 
     30 function waitForInstallEvent() {
     31  return new Promise((resolve, reject) => {
     32    navigator.serviceWorker.addEventListener('message', evt => {
     33      if (evt.data.type === 'INSTALL_EVENT') {
     34        resolve();
     35      }
     36    });
     37  });
     38 }
     39 
     40 function gcWorker() {
     41  return new Promise(function(resolve, reject) {
     42    // We are able to trigger asynchronous garbage collection and cycle
     43    // collection by emitting "child-cc-request" and "child-gc-request"
     44    // observer notifications.  The worker RuntimeService will translate
     45    // these notifications into the appropriate operation on all known
     46    // worker threads.
     47    //
     48    // In the failure case where GC/CC causes us to abort the installation,
     49    // we will know something happened from the statechange event.
     50    const statechangeHandler = evt => {
     51      // Reject rather than resolving to avoid the possibility of us seeing
     52      // an unrelated racing statechange somehow.  Since in the success case we
     53      // will still see a state change on termination, we do explicitly need to
     54      // be removed on the success path.
     55      ok(registration.installing, 'service worker is still installing?');
     56      reject();
     57    };
     58    registration.installing.addEventListener('statechange', statechangeHandler);
     59    // In the success case since the service worker installation is effectively
     60    // hung, we instead depend on sending a 'ping' message to the service worker
     61    // and hearing it 'pong' back.  Since we issue our postMessage after we
     62    // trigger the GC/CC, our 'ping' will only be processed after the GC/CC and
     63    // therefore the pong will also strictly occur after the cycle collection.
     64    navigator.serviceWorker.addEventListener('message', evt => {
     65      if (evt.data.type === 'pong') {
     66        registration.installing.removeEventListener(
     67          'statechange', statechangeHandler);
     68        resolve();
     69      }
     70    });
     71    // At the current time, the service worker will exist in our same process
     72    // and notifyObservers is synchronous.  However, in the future, service
     73    // workers may end up in a separate process and in that case it will be
     74    // appropriate to use notifyObserversInParentProcess or something like it.
     75    // (notifyObserversInParentProcess is a synchronous IPC call to the parent
     76    // process's main thread.  IPDL PContent::CycleCollect is an async message.
     77    // Ordering will be maintained if the postMessage goes via PContent as well,
     78    // but that seems unlikely.)
     79    SpecialPowers.notifyObservers(null, 'child-gc-request');
     80    SpecialPowers.notifyObservers(null, 'child-cc-request');
     81    SpecialPowers.notifyObservers(null, 'child-gc-request');
     82    // (Only send the ping after we set the gc/cc/gc in motion.)
     83    registration.installing.postMessage({ type: 'ping' });
     84  });
     85 }
     86 
     87 function terminateWorker() {
     88  return SpecialPowers.pushPrefEnv({
     89    set: [
     90      ["dom.serviceWorkers.idle_timeout", 0],
     91      ["dom.serviceWorkers.idle_extended_timeout", 0]
     92    ]
     93  }).then(_ => {
     94    registration.installing.postMessage({ type: 'RESET_TIMER' });
     95  });
     96 }
     97 
     98 function runTest() {
     99  Promise.all([
    100    waitForInstallEvent(),
    101    register()
    102  ]).then(_ => ok(registration.installing, 'service worker is installing'))
    103    .then(gcWorker)
    104    .then(_ => ok(registration.installing, 'service worker is still installing'))
    105    .then(terminateWorker)
    106    .catch(e => ok(false, e))
    107    .then(unregister)
    108    .then(SimpleTest.finish);
    109 }
    110 
    111 SimpleTest.waitForExplicitFinish();
    112 SpecialPowers.pushPrefEnv({"set": [
    113  ["dom.serviceWorkers.exemptFromPerDomainMax", true],
    114  ["dom.serviceWorkers.enabled", true],
    115  ["dom.serviceWorkers.testing.enabled", true],
    116 ]}, runTest);
    117 </script>
    118 </pre>
    119 </body>
    120 </html>