tor-browser

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

readable-stream.html (8950B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8">
      3 <script src="/resources/testharness.js"></script>
      4 <script src="/resources/testharnessreport.js"></script>
      5 <script src="resources/helpers.js"></script>
      6 <script src="../resources/recording-streams.js"></script>
      7 <script src="../resources/test-utils.js"></script>
      8 <script>
      9 'use strict';
     10 
     11 promise_test(async () => {
     12  const rs = await createTransferredReadableStream({
     13    start(controller) {
     14      controller.enqueue('a');
     15      controller.close();
     16    }
     17  });
     18  const reader = rs.getReader();
     19  {
     20    const {value, done} = await reader.read();
     21    assert_false(done, 'should not be done yet');
     22    assert_equals(value, 'a', 'first chunk should be a');
     23  }
     24  {
     25    const {done} = await reader.read();
     26    assert_true(done, 'should be done now');
     27  }
     28 }, 'sending one chunk through a transferred stream should work');
     29 
     30 promise_test(async () => {
     31  let controller;
     32  const rs = await createTransferredReadableStream({
     33    start(c) {
     34      controller = c;
     35    }
     36  });
     37  for (let i = 0; i < 10; ++i) {
     38    controller.enqueue(i);
     39  }
     40  controller.close();
     41  const reader = rs.getReader();
     42  for (let i = 0; i < 10; ++i) {
     43    const {value, done} = await reader.read();
     44    assert_false(done, 'should not be done yet');
     45    assert_equals(value, i, 'chunk content should match index');
     46  }
     47  const {done} = await reader.read();
     48  assert_true(done, 'should be done now');
     49 }, 'sending ten chunks through a transferred stream should work');
     50 
     51 promise_test(async () => {
     52  let controller;
     53  const rs = await createTransferredReadableStream({
     54    start(c) {
     55      controller = c;
     56    }
     57  });
     58  const reader = rs.getReader();
     59  for (let i = 0; i < 10; ++i) {
     60    controller.enqueue(i);
     61    const {value, done} = await reader.read();
     62    assert_false(done, 'should not be done yet');
     63    assert_equals(value, i, 'chunk content should match index');
     64  }
     65  controller.close();
     66  const {done} = await reader.read();
     67  assert_true(done, 'should be done now');
     68 }, 'sending ten chunks one at a time should work');
     69 
     70 promise_test(async () => {
     71  let controller;
     72  const rs = await createTransferredReadableStream({
     73    start() {
     74      this.counter = 0;
     75    },
     76    pull(controller) {
     77      controller.enqueue(this.counter);
     78      ++this.counter;
     79      if (this.counter === 10)
     80        controller.close();
     81    }
     82  });
     83  const reader = rs.getReader();
     84  for (let i = 0; i < 10; ++i) {
     85    const {value, done} = await reader.read();
     86    assert_false(done, 'should not be done yet');
     87    assert_equals(value, i, 'chunk content should match index');
     88  }
     89  const {done} = await reader.read();
     90  assert_true(done, 'should be done now');
     91 }, 'sending ten chunks on demand should work');
     92 
     93 promise_test(async () => {
     94  const rs = recordingReadableStream({}, { highWaterMark: 0 });
     95  await delay(0);
     96  assert_array_equals(rs.events, [], 'pull() should not have been called');
     97  // Eat the message so it can't interfere with other tests.
     98  addEventListener('message', () => {}, {once: true});
     99  // The transfer is done manually to verify that it is posting the stream that
    100  // relieves backpressure, not receiving it.
    101  postMessage(rs, '*', [rs]);
    102  await delay(0);
    103  assert_array_equals(rs.events, ['pull'], 'pull() should have been called');
    104 }, 'transferring a stream should relieve backpressure');
    105 
    106 promise_test(async () => {
    107  const rs = await recordingTransferredReadableStream({
    108    pull(controller) {
    109      controller.enqueue('a');
    110    }
    111  }, { highWaterMark: 2 });
    112  await delay(0);
    113  assert_array_equals(rs.events, ['pull', 'pull', 'pull'],
    114                      'pull() should have been called three times');
    115 }, 'transferring a stream should add one chunk to the queue size');
    116 
    117 promise_test(async () => {
    118  const rs = await recordingTransferredReadableStream({
    119    start(controller) {
    120      controller.enqueue(new Uint8Array(1024));
    121      controller.enqueue(new Uint8Array(1024));
    122    }
    123  }, new ByteLengthQueuingStrategy({highWaterMark: 512}));
    124  await delay(0);
    125  // At this point the queue contains 1024/512 bytes and 1/1 chunk, so it's full
    126  // and pull() is not called.
    127  assert_array_equals(rs.events, [], 'pull() should not have been called');
    128  const reader = rs.getReader();
    129  const {value, done} = await reader.read();
    130  assert_false(done, 'we should not be done');
    131  assert_equals(value.byteLength, 1024, 'expected chunk should be returned');
    132  // Now the queue contains 0/512 bytes and 1/1 chunk, so pull() is called. If
    133  // the implementation erroneously counted the extra queue space in bytes, then
    134  // the queue would contain 1024/513 bytes and pull() wouldn't be called.
    135  assert_array_equals(rs.events, ['pull'], 'pull() should have been called');
    136 }, 'the extra queue from transferring is counted in chunks');
    137 
    138 async function transferredReadableStreamWithCancelPromise() {
    139  let resolveCancelCalled;
    140  const cancelCalled = new Promise(resolve => {
    141    resolveCancelCalled = resolve;
    142  });
    143  const rs = await recordingTransferredReadableStream({
    144    cancel() {
    145      resolveCancelCalled();
    146    }
    147  });
    148  return { rs, cancelCalled };
    149 }
    150 
    151 promise_test(async () => {
    152  const { rs, cancelCalled } = await transferredReadableStreamWithCancelPromise();
    153  rs.cancel('message');
    154  await cancelCalled;
    155  assert_array_equals(rs.events, ['pull', 'cancel', 'message'],
    156                      'cancel() should have been called');
    157  const reader = rs.getReader();
    158  // Check the stream really got closed.
    159  await reader.closed;
    160 }, 'cancel should be propagated to the original');
    161 
    162 promise_test(async () => {
    163  const { rs, cancelCalled } = await transferredReadableStreamWithCancelPromise();
    164  const reader = rs.getReader();
    165  const readPromise = reader.read();
    166  reader.cancel('done');
    167  const { done } = await readPromise;
    168  assert_true(done, 'should be done');
    169  await cancelCalled;
    170  assert_array_equals(rs.events, ['pull', 'cancel', 'done'],
    171                      'events should match');
    172 }, 'cancel should abort a pending read()');
    173 
    174 promise_test(async () => {
    175  let cancelComplete = false;
    176  const rs = await createTransferredReadableStream({
    177    async cancel() {
    178      await flushAsyncEvents();
    179      cancelComplete = true;
    180    }
    181  });
    182  await rs.cancel();
    183  assert_false(cancelComplete,
    184               'cancel() on the underlying sink should not have completed');
    185 }, 'stream cancel should not wait for underlying source cancel');
    186 
    187 promise_test(async t => {
    188  const rs = await recordingTransferredReadableStream();
    189  const reader = rs.getReader();
    190  let serializationHappened = false;
    191  rs.controller.enqueue({
    192    get getter() {
    193      serializationHappened = true;
    194      return 'a';
    195    }
    196  });
    197  await flushAsyncEvents();
    198  assert_false(serializationHappened,
    199               'serialization should not have happened yet');
    200  const {value, done} = await reader.read();
    201  assert_false(done, 'should not be done');
    202  assert_equals(value.getter, 'a', 'getter should be a');
    203  assert_true(serializationHappened,
    204              'serialization should have happened');
    205 }, 'serialization should not happen until the value is read');
    206 
    207 promise_test(async t => {
    208  const rs = await recordingTransferredReadableStream();
    209  const reader = rs.getReader();
    210  rs.controller.enqueue(new ReadableStream());
    211  await promise_rejects_dom(t, 'DataCloneError', reader.read(),
    212                            'closed promise should reject');
    213  assert_throws_js(TypeError, () => rs.controller.enqueue(),
    214                   'original stream should be errored');
    215 }, 'transferring a non-serializable chunk should error both sides');
    216 
    217 promise_test(async t => {
    218  const rs = await createTransferredReadableStream({
    219    start(controller) {
    220      controller.error('foo');
    221    }
    222  });
    223  const reader = rs.getReader();
    224  return promise_rejects_exactly(t, 'foo', reader.read(),
    225                                 'error should be passed through');
    226 }, 'errors should be passed through');
    227 
    228 promise_test(async () => {
    229  const rs = await recordingTransferredReadableStream();
    230  await delay(0);
    231  const reader = rs.getReader();
    232  reader.cancel();
    233  rs.controller.error();
    234  const {done} = await reader.read();
    235  assert_true(done, 'should be done');
    236  assert_throws_js(TypeError, () => rs.controller.enqueue(),
    237                   'enqueue should throw');
    238 }, 'race between cancel() and error() should leave sides in different states');
    239 
    240 promise_test(async () => {
    241  const rs = await recordingTransferredReadableStream();
    242  await delay(0);
    243  const reader = rs.getReader();
    244  reader.cancel();
    245  rs.controller.close();
    246  const {done} = await reader.read();
    247  assert_true(done, 'should be done');
    248 }, 'race between cancel() and close() should be benign');
    249 
    250 promise_test(async () => {
    251  const rs = await recordingTransferredReadableStream();
    252  await delay(0);
    253  const reader = rs.getReader();
    254  reader.cancel();
    255  rs.controller.enqueue('a');
    256  const {done} = await reader.read();
    257  assert_true(done, 'should be done');
    258 }, 'race between cancel() and enqueue() should be benign');
    259 
    260 </script>