tor-browser

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

signal.https.any.js (7985B)


      1 // META: title=Web Locks API: AbortSignal integration
      2 // META: script=resources/helpers.js
      3 // META: global=window,dedicatedworker,sharedworker,serviceworker
      4 
      5 'use strict';
      6 
      7 promise_test(async t => {
      8  const res = uniqueName(t);
      9 
     10  // These cases should not work:
     11  for (const signal of ['string', 12.34, false, {}, Symbol(), () => {}, self]) {
     12    await promise_rejects_js(
     13      t, TypeError,
     14      navigator.locks.request(
     15        res, {signal}, t.unreached_func('callback should not run')),
     16      'Bindings should throw if the signal option is a not an AbortSignal');
     17  }
     18 }, 'The signal option must be an AbortSignal');
     19 
     20 promise_test(async t => {
     21  const res = uniqueName(t);
     22  const controller = new AbortController();
     23  controller.abort();
     24 
     25  await promise_rejects_dom(
     26    t, 'AbortError',
     27    navigator.locks.request(res, {signal: controller.signal},
     28                            t.unreached_func('callback should not run')),
     29    'Request should reject with AbortError');
     30 }, 'Passing an already aborted signal aborts');
     31 
     32 promise_test(async t => {
     33  const res = uniqueName(t);
     34 
     35  const controller = new AbortController();
     36  const reason = 'My dog ate it.';
     37  controller.abort(reason);
     38 
     39  const promise =
     40        navigator.locks.request(res, {signal: controller.signal},
     41                                t.unreached_func('callback should not run'));
     42 
     43  await promise_rejects_exactly(
     44    t, reason, promise, "Rejection should give the abort reason");
     45 }, 'Passing an already aborted signal rejects with the custom abort reason.');
     46 
     47 promise_test(async t => {
     48  const res = uniqueName(t);
     49 
     50  const controller = new AbortController();
     51  controller.abort();
     52 
     53  const promise =
     54        navigator.locks.request(res, {signal: controller.signal},
     55                                t.unreached_func('callback should not run'));
     56 
     57  await promise_rejects_exactly(
     58    t, controller.signal.reason, promise,
     59    "Rejection should give the abort reason");
     60 }, 'Passing an already aborted signal rejects with the default abort reason.');
     61 
     62 promise_test(async t => {
     63  const res = uniqueName(t);
     64 
     65  // Grab a lock and hold it until this subtest completes.
     66  requestLockAndHold(t, res);
     67 
     68  const controller = new AbortController();
     69 
     70  const promise =
     71    navigator.locks.request(res, {signal: controller.signal},
     72                            t.unreached_func('callback should not run'));
     73 
     74  // Verify the request is enqueued:
     75  const state = await navigator.locks.query();
     76  assert_equals(state.held.filter(lock => lock.name === res).length, 1,
     77                'Number of held locks');
     78  assert_equals(state.pending.filter(lock => lock.name === res).length, 1,
     79                'Number of pending locks');
     80 
     81  const rejected = promise_rejects_dom(
     82    t, 'AbortError', promise, 'Request should reject with AbortError');
     83 
     84  controller.abort();
     85 
     86  await rejected;
     87 
     88 }, 'An aborted request results in AbortError');
     89 
     90 promise_test(async t => {
     91  const res = uniqueName(t);
     92 
     93  // Grab a lock and hold it until this subtest completes.
     94  requestLockAndHold(t, res);
     95 
     96  const controller = new AbortController();
     97 
     98  const promise =
     99    navigator.locks.request(res, {signal: controller.signal}, lock => {});
    100 
    101  // Verify the request is enqueued:
    102  const state = await navigator.locks.query();
    103  assert_equals(state.held.filter(lock => lock.name === res).length, 1,
    104                'Number of held locks');
    105  assert_equals(state.pending.filter(lock => lock.name === res).length, 1,
    106                'Number of pending locks');
    107 
    108  const rejected = promise_rejects_dom(
    109    t, 'AbortError', promise, 'Request should reject with AbortError');
    110 
    111  let callback_called = false;
    112  t.step_timeout(() => {
    113    callback_called = true;
    114    controller.abort();
    115  }, 10);
    116 
    117  await rejected;
    118  assert_true(callback_called, 'timeout should have caused the abort');
    119 
    120 }, 'Abort after a timeout');
    121 
    122 promise_test(async t => {
    123  const res = uniqueName(t);
    124 
    125  const controller = new AbortController();
    126 
    127  let got_lock = false;
    128  await navigator.locks.request(
    129    res, {signal: controller.signal}, async lock => { got_lock = true; });
    130 
    131  assert_true(got_lock, 'Lock should be acquired if abort is not signaled.');
    132 
    133 }, 'Signal that is not aborted');
    134 
    135 promise_test(async t => {
    136  const res = uniqueName(t);
    137 
    138  const controller = new AbortController();
    139 
    140  let got_lock = false;
    141  const p = navigator.locks.request(
    142    res, {signal: controller.signal}, lock => { got_lock = true; });
    143 
    144  // Even though lock is grantable, this abort should be processed synchronously.
    145  controller.abort();
    146 
    147  await promise_rejects_dom(t, 'AbortError', p, 'Request should abort');
    148 
    149  assert_false(got_lock, 'Request should be aborted if signal is synchronous');
    150 
    151  await navigator.locks.request(res, lock => { got_lock = true; });
    152  assert_true(got_lock, 'Subsequent request should not be blocked');
    153 
    154 }, 'Synchronously signaled abort');
    155 
    156 promise_test(async t => {
    157  const res = uniqueName(t);
    158 
    159  const controller = new AbortController();
    160 
    161  // Make a promise that resolves when the lock is acquired.
    162  const [acquired_promise, acquired_func] = makePromiseAndResolveFunc();
    163 
    164  // Request the lock.
    165  let release_func;
    166  const released_promise = navigator.locks.request(
    167    res, {signal: controller.signal}, lock => {
    168      acquired_func();
    169 
    170      // Hold lock until release_func is called.
    171      const [waiting_promise, waiting_func] = makePromiseAndResolveFunc();
    172      release_func = waiting_func;
    173      return waiting_promise;
    174    });
    175 
    176  // Wait for the lock to be acquired.
    177  await acquired_promise;
    178 
    179  // Signal an abort.
    180  controller.abort();
    181 
    182  // Release the lock.
    183  release_func('resolved ok');
    184 
    185  assert_equals(await released_promise, 'resolved ok',
    186                'Lock released promise should not reject');
    187 
    188 }, 'Abort signaled after lock granted');
    189 
    190 promise_test(async t => {
    191  const res = uniqueName(t);
    192 
    193  const controller = new AbortController();
    194 
    195  // Make a promise that resolves when the lock is acquired.
    196  const [acquired_promise, acquired_func] = makePromiseAndResolveFunc();
    197 
    198  // Request the lock.
    199  let release_func;
    200  const released_promise = navigator.locks.request(
    201    res, {signal: controller.signal}, lock => {
    202      acquired_func();
    203 
    204      // Hold lock until release_func is called.
    205      const [waiting_promise, waiting_func] = makePromiseAndResolveFunc();
    206      release_func = waiting_func;
    207      return waiting_promise;
    208    });
    209 
    210  // Wait for the lock to be acquired.
    211  await acquired_promise;
    212 
    213  // Release the lock.
    214  release_func('resolved ok');
    215 
    216  // Signal an abort.
    217  controller.abort();
    218 
    219  assert_equals(await released_promise, 'resolved ok',
    220                'Lock released promise should not reject');
    221 
    222 }, 'Abort signaled after lock released');
    223 
    224 promise_test(async t => {
    225  const res = uniqueName(t);
    226 
    227  const controller = new AbortController();
    228  const first = requestLockAndHold(t, res, { signal: controller.signal });
    229  const next = navigator.locks.request(res, () => "resolved");
    230  controller.abort();
    231 
    232  await promise_rejects_dom(t, "AbortError", first, "Request should abort");
    233  assert_equals(
    234    await next,
    235    "resolved",
    236    "The next request is processed after abort"
    237  );
    238 }, "Abort should process the next pending lock request");
    239 
    240 promise_test(async t => {
    241  const res = uniqueName(t);
    242 
    243  const controller = new AbortController();
    244  const promise = requestLockAndHold(t, res, { signal: controller.signal });
    245 
    246  const reason = "My cat handled it";
    247  controller.abort(reason);
    248 
    249  await promise_rejects_exactly(t, reason, promise, "Rejection should give the abort reason");
    250 }, "Aborted promise should reject with the custom abort reason");
    251 
    252 promise_test(async t => {
    253  const res = uniqueName(t);
    254 
    255  const controller = new AbortController();
    256  const promise = requestLockAndHold(t, res, { signal: controller.signal });
    257 
    258  controller.abort();
    259 
    260  await promise_rejects_exactly(t, controller.signal.reason, promise, "Should be the same reason");
    261 }, "Aborted promise should reject with the default abort reason");