tor-browser

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

errors.any.js (13372B)


      1 // META: global=window,worker,shadowrealm
      2 // META: script=../resources/test-utils.js
      3 'use strict';
      4 
      5 const thrownError = new Error('bad things are happening!');
      6 thrownError.name = 'error1';
      7 
      8 promise_test(t => {
      9  const ts = new TransformStream({
     10    transform() {
     11      throw thrownError;
     12    },
     13    cancel: t.unreached_func('cancel should not be called')
     14  });
     15 
     16  const reader = ts.readable.getReader();
     17 
     18  const writer = ts.writable.getWriter();
     19 
     20  return Promise.all([
     21    promise_rejects_exactly(t, thrownError, writer.write('a'),
     22                            'writable\'s write should reject with the thrown error'),
     23    promise_rejects_exactly(t, thrownError, reader.read(),
     24                            'readable\'s read should reject with the thrown error'),
     25    promise_rejects_exactly(t, thrownError, reader.closed,
     26                            'readable\'s closed should be rejected with the thrown error'),
     27    promise_rejects_exactly(t, thrownError, writer.closed,
     28                            'writable\'s closed should be rejected with the thrown error')
     29  ]);
     30 }, 'TransformStream errors thrown in transform put the writable and readable in an errored state');
     31 
     32 promise_test(t => {
     33  const ts = new TransformStream({
     34    transform() {
     35    },
     36    flush() {
     37      throw thrownError;
     38    },
     39    cancel: t.unreached_func('cancel should not be called')
     40  });
     41 
     42  const reader = ts.readable.getReader();
     43 
     44  const writer = ts.writable.getWriter();
     45 
     46  return Promise.all([
     47    writer.write('a'),
     48    promise_rejects_exactly(t, thrownError, writer.close(),
     49                            'writable\'s close should reject with the thrown error'),
     50    promise_rejects_exactly(t, thrownError, reader.read(),
     51                            'readable\'s read should reject with the thrown error'),
     52    promise_rejects_exactly(t, thrownError, reader.closed,
     53                            'readable\'s closed should be rejected with the thrown error'),
     54    promise_rejects_exactly(t, thrownError, writer.closed,
     55                            'writable\'s closed should be rejected with the thrown error')
     56  ]);
     57 }, 'TransformStream errors thrown in flush put the writable and readable in an errored state');
     58 
     59 test(t => {
     60  new TransformStream({
     61    start(c) {
     62      c.enqueue('a');
     63      c.error(new Error('generic error'));
     64      assert_throws_js(TypeError, () => c.enqueue('b'), 'enqueue() should throw');
     65    },
     66    cancel: t.unreached_func('cancel should not be called')
     67  });
     68 }, 'errored TransformStream should not enqueue new chunks');
     69 
     70 promise_test(t => {
     71  const ts = new TransformStream({
     72    start() {
     73      return flushAsyncEvents().then(() => {
     74        throw thrownError;
     75      });
     76    },
     77    transform: t.unreached_func('transform should not be called'),
     78    flush: t.unreached_func('flush should not be called'),
     79    cancel: t.unreached_func('cancel should not be called')
     80  });
     81 
     82  const writer = ts.writable.getWriter();
     83  const reader = ts.readable.getReader();
     84  return Promise.all([
     85    promise_rejects_exactly(t, thrownError, writer.write('a'), 'writer should reject with thrownError'),
     86    promise_rejects_exactly(t, thrownError, writer.close(), 'close() should reject with thrownError'),
     87    promise_rejects_exactly(t, thrownError, reader.read(), 'reader should reject with thrownError')
     88  ]);
     89 }, 'TransformStream transformer.start() rejected promise should error the stream');
     90 
     91 promise_test(t => {
     92  const controllerError = new Error('start failure');
     93  controllerError.name = 'controllerError';
     94  const ts = new TransformStream({
     95    start(c) {
     96      return flushAsyncEvents()
     97        .then(() => {
     98          c.error(controllerError);
     99          throw new Error('ignored error');
    100        });
    101    },
    102    transform: t.unreached_func('transform should never be called if start() fails'),
    103    flush: t.unreached_func('flush should never be called if start() fails'),
    104    cancel: t.unreached_func('cancel should never be called if start() fails')
    105  });
    106 
    107  const writer = ts.writable.getWriter();
    108  const reader = ts.readable.getReader();
    109  return Promise.all([
    110    promise_rejects_exactly(t, controllerError, writer.write('a'), 'writer should reject with controllerError'),
    111    promise_rejects_exactly(t, controllerError, writer.close(), 'close should reject with same error'),
    112    promise_rejects_exactly(t, controllerError, reader.read(), 'reader should reject with same error')
    113  ]);
    114 }, 'when controller.error is followed by a rejection, the error reason should come from controller.error');
    115 
    116 test(() => {
    117  assert_throws_js(URIError, () => new TransformStream({
    118    start() { throw new URIError('start thrown error'); },
    119    transform() {}
    120  }), 'constructor should throw');
    121 }, 'TransformStream constructor should throw when start does');
    122 
    123 test(() => {
    124  const strategy = {
    125    size() { throw new URIError('size thrown error'); }
    126  };
    127 
    128  assert_throws_js(URIError, () => new TransformStream({
    129    start(c) {
    130      c.enqueue('a');
    131    },
    132    transform() {}
    133  }, undefined, strategy), 'constructor should throw the same error strategy.size throws');
    134 }, 'when strategy.size throws inside start(), the constructor should throw the same error');
    135 
    136 test(() => {
    137  const controllerError = new URIError('controller.error');
    138 
    139  let controller;
    140  const strategy = {
    141    size() {
    142      controller.error(controllerError);
    143      throw new Error('redundant error');
    144    }
    145  };
    146 
    147  assert_throws_js(URIError, () => new TransformStream({
    148    start(c) {
    149      controller = c;
    150      c.enqueue('a');
    151    },
    152    transform() {}
    153  }, undefined, strategy), 'the first error should be thrown');
    154 }, 'when strategy.size calls controller.error() then throws, the constructor should throw the first error');
    155 
    156 promise_test(t => {
    157  const ts = new TransformStream();
    158  const writer = ts.writable.getWriter();
    159  const closedPromise = writer.closed;
    160  return Promise.all([
    161    ts.readable.cancel(thrownError),
    162    promise_rejects_exactly(t, thrownError, closedPromise, 'closed should throw a TypeError')
    163  ]);
    164 }, 'cancelling the readable side should error the writable');
    165 
    166 promise_test(t => {
    167  let controller;
    168  const ts = new TransformStream({
    169    start(c) {
    170      controller = c;
    171    }
    172  });
    173  const writer = ts.writable.getWriter();
    174  const reader = ts.readable.getReader();
    175  const writePromise = writer.write('a');
    176  const closePromise = writer.close();
    177  controller.error(thrownError);
    178  return Promise.all([
    179    promise_rejects_exactly(t, thrownError, reader.closed, 'reader.closed should reject'),
    180    promise_rejects_exactly(t, thrownError, writePromise, 'writePromise should reject'),
    181    promise_rejects_exactly(t, thrownError, closePromise, 'closePromise should reject')]);
    182 }, 'it should be possible to error the readable between close requested and complete');
    183 
    184 promise_test(t => {
    185  const ts = new TransformStream({
    186    transform(chunk, controller) {
    187      controller.enqueue(chunk);
    188      controller.terminate();
    189      throw thrownError;
    190    }
    191  }, undefined, { highWaterMark: 1 });
    192  const writePromise = ts.writable.getWriter().write('a');
    193  const closedPromise = ts.readable.getReader().closed;
    194  return Promise.all([
    195    promise_rejects_exactly(t, thrownError, writePromise, 'write() should reject'),
    196    promise_rejects_exactly(t, thrownError, closedPromise, 'reader.closed should reject')
    197  ]);
    198 }, 'an exception from transform() should error the stream if terminate has been requested but not completed');
    199 
    200 promise_test(t => {
    201  const ts = new TransformStream();
    202  const writer = ts.writable.getWriter();
    203  // The microtask following transformer.start() hasn't completed yet, so the abort is queued and not notified to the
    204  // TransformStream yet.
    205  const abortPromise = writer.abort(thrownError);
    206  const cancelPromise = ts.readable.cancel(new Error('cancel reason'));
    207  return Promise.all([
    208    abortPromise,
    209    cancelPromise,
    210    promise_rejects_exactly(t, thrownError, writer.closed, 'writer.closed should reject'),
    211  ]);
    212 }, 'abort should set the close reason for the writable when it happens before cancel during start, and cancel should ' +
    213             'reject');
    214 
    215 promise_test(t => {
    216  let resolveTransform;
    217  const transformPromise = new Promise(resolve => {
    218    resolveTransform = resolve;
    219  });
    220  const ts = new TransformStream({
    221    transform() {
    222      return transformPromise;
    223    }
    224  }, undefined, { highWaterMark: 2 });
    225  const writer = ts.writable.getWriter();
    226  return delay(0).then(() => {
    227    const writePromise = writer.write();
    228    const abortPromise = writer.abort(thrownError);
    229    const cancelPromise = ts.readable.cancel(new Error('cancel reason'));
    230    resolveTransform();
    231    return Promise.all([
    232      writePromise,
    233      abortPromise,
    234      cancelPromise,
    235      promise_rejects_exactly(t, thrownError, writer.closed, 'writer.closed should reject with thrownError')]);
    236  });
    237 }, 'abort should set the close reason for the writable when it happens before cancel during underlying sink write, ' +
    238             'but cancel should still succeed');
    239 
    240 const ignoredError = new Error('ignoredError');
    241 ignoredError.name = 'ignoredError';
    242 
    243 promise_test(t => {
    244  const ts = new TransformStream({
    245    start(controller) {
    246      controller.error(thrownError);
    247      controller.error(ignoredError);
    248    }
    249  });
    250  return promise_rejects_exactly(t, thrownError, ts.writable.abort(), 'abort() should reject with thrownError');
    251 }, 'controller.error() should do nothing the second time it is called');
    252 
    253 promise_test(t => {
    254  let controller;
    255  const ts = new TransformStream({
    256    start(c) {
    257      controller = c;
    258    }
    259  });
    260  const cancelPromise = ts.readable.cancel(ignoredError);
    261  controller.error(thrownError);
    262  return Promise.all([
    263    cancelPromise,
    264    promise_rejects_exactly(t, thrownError, ts.writable.getWriter().closed, 'closed should reject with thrownError')
    265  ]);
    266 }, 'controller.error() should close writable immediately after readable.cancel()');
    267 
    268 promise_test(t => {
    269  let controller;
    270  const ts = new TransformStream({
    271    start(c) {
    272      controller = c;
    273    }
    274  });
    275  return ts.readable.cancel(thrownError).then(() => {
    276    controller.error(ignoredError);
    277    return promise_rejects_exactly(t, thrownError, ts.writable.getWriter().closed, 'closed should reject with thrownError');
    278  });
    279 }, 'controller.error() should do nothing after readable.cancel() resolves');
    280 
    281 promise_test(t => {
    282  let controller;
    283  const ts = new TransformStream({
    284    start(c) {
    285      controller = c;
    286    }
    287  });
    288  return ts.writable.abort(thrownError).then(() => {
    289    controller.error(ignoredError);
    290    return promise_rejects_exactly(t, thrownError, ts.writable.getWriter().closed, 'closed should reject with thrownError');
    291  });
    292 }, 'controller.error() should do nothing after writable.abort() has completed');
    293 
    294 promise_test(t => {
    295  let controller;
    296  const ts = new TransformStream({
    297    start(c) {
    298      controller = c;
    299    },
    300    transform() {
    301      throw thrownError;
    302    }
    303  }, undefined, { highWaterMark: Infinity });
    304  const writer = ts.writable.getWriter();
    305  return promise_rejects_exactly(t, thrownError, writer.write(), 'write() should reject').then(() => {
    306    controller.error();
    307    return promise_rejects_exactly(t, thrownError, writer.closed, 'closed should reject with thrownError');
    308  });
    309 }, 'controller.error() should do nothing after a transformer method has thrown an exception');
    310 
    311 promise_test(t => {
    312  let controller;
    313  let calls = 0;
    314  const ts = new TransformStream({
    315    start(c) {
    316      controller = c;
    317    },
    318    transform() {
    319      ++calls;
    320    }
    321  }, undefined, { highWaterMark: 1 });
    322  return delay(0).then(() => {
    323    // Create backpressure.
    324    controller.enqueue('a');
    325    const writer = ts.writable.getWriter();
    326    // transform() will not be called until backpressure is relieved.
    327    const writePromise = writer.write('b');
    328    assert_equals(calls, 0, 'transform() should not have been called');
    329    controller.error(thrownError);
    330    // Now backpressure has been relieved and the write can proceed.
    331    return promise_rejects_exactly(t, thrownError, writePromise, 'write() should reject').then(() => {
    332      assert_equals(calls, 0, 'transform() should not be called');
    333    });
    334  });
    335 }, 'erroring during write with backpressure should result in the write failing');
    336 
    337 promise_test(t => {
    338  const ts = new TransformStream({}, undefined, { highWaterMark: 0 });
    339  return delay(0).then(() => {
    340    const writer = ts.writable.getWriter();
    341    // write should start synchronously
    342    const writePromise = writer.write(0);
    343    // The underlying sink's abort() is not called until the write() completes.
    344    const abortPromise = writer.abort(thrownError);
    345    // Perform a read to relieve backpressure and permit the write() to complete.
    346    const readPromise = ts.readable.getReader().read();
    347    return Promise.all([
    348      promise_rejects_exactly(t, thrownError, readPromise, 'read() should reject'),
    349      promise_rejects_exactly(t, thrownError, writePromise, 'write() should reject'),
    350      abortPromise
    351    ]);
    352  });
    353 }, 'a write() that was waiting for backpressure should reject if the writable is aborted');
    354 
    355 promise_test(t => {
    356  const ts = new TransformStream();
    357  ts.writable.abort(thrownError);
    358  const reader = ts.readable.getReader();
    359  return promise_rejects_exactly(t, thrownError, reader.read(), 'read() should reject with thrownError');
    360 }, 'the readable should be errored with the reason passed to the writable abort() method');