tor-browser

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

query-ordering.https.html (5453B)


      1 <!DOCTYPE html>
      2 <meta charset=utf-8>
      3 <title>Web Locks API: navigator.locks.query ordering</title>
      4 <link rel=help href="https://w3c.github.io/web-locks/">
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="resources/helpers.js"></script>
      8 <style>iframe { display: none; }</style>
      9 <script>
     10 'use strict';
     11 
     12 // Grab a lock and hold until a release function is called. Resolves
     13 // to a release function.
     14 function getLockAndHoldUntilReleased(name, options) {
     15  let release;
     16  const promise = new Promise(resolve => { release = resolve; });
     17  return new Promise(resolve => {
     18    navigator.locks.request(name, options || {}, lock => {
     19      resolve(release);
     20      return promise;
     21    }).catch(_ => {});
     22  });
     23 }
     24 
     25 // Returns a promise resolved by the next message event.
     26 function nextMessage() {
     27  return new Promise(resolve => {
     28    window.addEventListener('message', event => {
     29      resolve(event.data);
     30    }, {once: true});
     31  });
     32 }
     33 
     34 // Tests the ordering constraints on the requested lock state returned by
     35 // navigator.locks.query(). Three separate iframes are instantiated to make
     36 // lock requests on the same resource, first in one order and then in another,
     37 // different order. For each set of requests, it is verified that the requests
     38 // appear in the result of navigator.locks.query() in the same order in which
     39 // they were made.
     40 //
     41 // It is necessary to use separate iframes here so that the lock requests have
     42 // distinguishable client_ids (otherwise it would not be possible to
     43 // distinguish the requests and thus impossible to verify ordering).
     44 promise_test(async testCase => {
     45  assert_implements(navigator.locks);
     46  const resourceName = uniqueName(testCase);
     47 
     48  // Set up clients.
     49  const frame1 = await iframe('resources/iframe.html');
     50  const frame2 = await iframe('resources/iframe.html');
     51  const frame3 = await iframe('resources/iframe.html');
     52  testCase.add_cleanup(() => { frame1.remove(); });
     53  testCase.add_cleanup(() => { frame2.remove(); });
     54  testCase.add_cleanup(() => { frame3.remove(); });
     55 
     56  // Collect the client ids.
     57  const clientId1 =
     58      (await postToFrameAndWait(frame1, {op: 'client_id',
     59                                         name: resourceName})).client_id;
     60  const clientId2 =
     61      (await postToFrameAndWait(frame2, {op: 'client_id',
     62                                         name: resourceName})).client_id;
     63  const clientId3 =
     64      (await postToFrameAndWait(frame3, {op: 'client_id',
     65                                         name: resourceName})).client_id;
     66 
     67  // Preemptively take the lock.
     68  const firstRequestGroupReleaseFunction =
     69      await getLockAndHoldUntilReleased(resourceName);
     70 
     71  // Queue the first group of lock requests from the different clients. These
     72  // will be blocked until firstRequestGroupReleaseFunction() is called.
     73  let lockId1;
     74  let lockId2;
     75  const lockPromise1 =
     76      postToFrameAndWait(frame1, {op: 'request', name: resourceName})
     77          .then(val => {lockId1 = val.lock_id;});
     78  const lockPromise2 =
     79      postToFrameAndWait(frame2, {op: 'request', name: resourceName})
     80          .then(val => {lockId2 = val.lock_id;});
     81 
     82  // This third request will later be granted and held in order to block a
     83  // second group of requests to test a different client ordering. It is not
     84  // meant to be released.
     85  postToFrameAndWait(frame3, {op: 'request', name: resourceName});
     86 
     87  // Request and wait for the release of a separate lock to ensure all previous
     88  // requests are processed.
     89  const checkpointName = uniqueName(testCase, 'checkpoint');
     90  const checkpointId = (await postToFrameAndWait(
     91                                  frame3,
     92                                  {op: 'request', name: checkpointName})).lock_id;
     93  await postToFrameAndWait(frame3, {op: 'release', lock_id: checkpointId});
     94 
     95  // Query the state and test the ordering of requested locks.
     96  const state = await navigator.locks.query();
     97  const relevant_pending_ids = state.pending
     98      .filter(lock => [clientId1, clientId2, clientId3].includes(lock.clientId))
     99      .map(lock => lock.clientId);
    100  assert_array_equals(
    101      [clientId1, clientId2, clientId3],
    102      relevant_pending_ids,
    103      'Querying the state should return requested locks in the order they were '
    104      + 'requested.');
    105 
    106  // Add the second group of requests from the clients in a new order.
    107  postToFrameAndWait(frame3, {op: 'request', name: resourceName});
    108  postToFrameAndWait(frame1, {op: 'request', name: resourceName});
    109  postToFrameAndWait(frame2, {op: 'request', name: resourceName});
    110 
    111  // Release locks such that only the newly added locks are requested. This
    112  // acts like a checkpoint for the newly queued requests.
    113  firstRequestGroupReleaseFunction();
    114  await lockPromise1;
    115  await postToFrameAndWait(frame1, {op: 'release', lock_id: lockId1});
    116  await lockPromise2;
    117  await postToFrameAndWait(frame2, {op: 'release', lock_id: lockId2});
    118 
    119  // Query the state and test the new ordering.
    120  const state2 = await navigator.locks.query();
    121  const relevant_pending_ids2 = state2.pending
    122      .filter(lock => [clientId1, clientId2, clientId3].includes(lock.clientId))
    123      .map(lock => lock.clientId);
    124  assert_array_equals(
    125      [clientId3, clientId1, clientId2],
    126      relevant_pending_ids2,
    127      'Querying the state should return requested locks in the order they were '
    128      + 'requested.');
    129 
    130 }, 'Requests appear in state in order made.');
    131 </script>