11cb0ef41Sopenharmony_ci<!DOCTYPE html>
21cb0ef41Sopenharmony_ci<meta charset="utf-8">
31cb0ef41Sopenharmony_ci<script src="/resources/testharness.js"></script>
41cb0ef41Sopenharmony_ci<script src="/resources/testharnessreport.js"></script>
51cb0ef41Sopenharmony_ci<script src="resources/helpers.js"></script>
61cb0ef41Sopenharmony_ci<script src="../resources/recording-streams.js"></script>
71cb0ef41Sopenharmony_ci<script src="../resources/test-utils.js"></script>
81cb0ef41Sopenharmony_ci<script>
91cb0ef41Sopenharmony_ci'use strict';
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_cipromise_test(async () => {
121cb0ef41Sopenharmony_ci  const rs = await createTransferredReadableStream({
131cb0ef41Sopenharmony_ci    start(controller) {
141cb0ef41Sopenharmony_ci      controller.enqueue('a');
151cb0ef41Sopenharmony_ci      controller.close();
161cb0ef41Sopenharmony_ci    }
171cb0ef41Sopenharmony_ci  });
181cb0ef41Sopenharmony_ci  const reader = rs.getReader();
191cb0ef41Sopenharmony_ci  {
201cb0ef41Sopenharmony_ci    const {value, done} = await reader.read();
211cb0ef41Sopenharmony_ci    assert_false(done, 'should not be done yet');
221cb0ef41Sopenharmony_ci    assert_equals(value, 'a', 'first chunk should be a');
231cb0ef41Sopenharmony_ci  }
241cb0ef41Sopenharmony_ci  {
251cb0ef41Sopenharmony_ci    const {done} = await reader.read();
261cb0ef41Sopenharmony_ci    assert_true(done, 'should be done now');
271cb0ef41Sopenharmony_ci  }
281cb0ef41Sopenharmony_ci}, 'sending one chunk through a transferred stream should work');
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_cipromise_test(async () => {
311cb0ef41Sopenharmony_ci  let controller;
321cb0ef41Sopenharmony_ci  const rs = await createTransferredReadableStream({
331cb0ef41Sopenharmony_ci    start(c) {
341cb0ef41Sopenharmony_ci      controller = c;
351cb0ef41Sopenharmony_ci    }
361cb0ef41Sopenharmony_ci  });
371cb0ef41Sopenharmony_ci  for (let i = 0; i < 10; ++i) {
381cb0ef41Sopenharmony_ci    controller.enqueue(i);
391cb0ef41Sopenharmony_ci  }
401cb0ef41Sopenharmony_ci  controller.close();
411cb0ef41Sopenharmony_ci  const reader = rs.getReader();
421cb0ef41Sopenharmony_ci  for (let i = 0; i < 10; ++i) {
431cb0ef41Sopenharmony_ci    const {value, done} = await reader.read();
441cb0ef41Sopenharmony_ci    assert_false(done, 'should not be done yet');
451cb0ef41Sopenharmony_ci    assert_equals(value, i, 'chunk content should match index');
461cb0ef41Sopenharmony_ci  }
471cb0ef41Sopenharmony_ci  const {done} = await reader.read();
481cb0ef41Sopenharmony_ci  assert_true(done, 'should be done now');
491cb0ef41Sopenharmony_ci}, 'sending ten chunks through a transferred stream should work');
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_cipromise_test(async () => {
521cb0ef41Sopenharmony_ci  let controller;
531cb0ef41Sopenharmony_ci  const rs = await createTransferredReadableStream({
541cb0ef41Sopenharmony_ci    start(c) {
551cb0ef41Sopenharmony_ci      controller = c;
561cb0ef41Sopenharmony_ci    }
571cb0ef41Sopenharmony_ci  });
581cb0ef41Sopenharmony_ci  const reader = rs.getReader();
591cb0ef41Sopenharmony_ci  for (let i = 0; i < 10; ++i) {
601cb0ef41Sopenharmony_ci    controller.enqueue(i);
611cb0ef41Sopenharmony_ci    const {value, done} = await reader.read();
621cb0ef41Sopenharmony_ci    assert_false(done, 'should not be done yet');
631cb0ef41Sopenharmony_ci    assert_equals(value, i, 'chunk content should match index');
641cb0ef41Sopenharmony_ci  }
651cb0ef41Sopenharmony_ci  controller.close();
661cb0ef41Sopenharmony_ci  const {done} = await reader.read();
671cb0ef41Sopenharmony_ci  assert_true(done, 'should be done now');
681cb0ef41Sopenharmony_ci}, 'sending ten chunks one at a time should work');
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_cipromise_test(async () => {
711cb0ef41Sopenharmony_ci  let controller;
721cb0ef41Sopenharmony_ci  const rs = await createTransferredReadableStream({
731cb0ef41Sopenharmony_ci    start() {
741cb0ef41Sopenharmony_ci      this.counter = 0;
751cb0ef41Sopenharmony_ci    },
761cb0ef41Sopenharmony_ci    pull(controller) {
771cb0ef41Sopenharmony_ci      controller.enqueue(this.counter);
781cb0ef41Sopenharmony_ci      ++this.counter;
791cb0ef41Sopenharmony_ci      if (this.counter === 10)
801cb0ef41Sopenharmony_ci        controller.close();
811cb0ef41Sopenharmony_ci    }
821cb0ef41Sopenharmony_ci  });
831cb0ef41Sopenharmony_ci  const reader = rs.getReader();
841cb0ef41Sopenharmony_ci  for (let i = 0; i < 10; ++i) {
851cb0ef41Sopenharmony_ci    const {value, done} = await reader.read();
861cb0ef41Sopenharmony_ci    assert_false(done, 'should not be done yet');
871cb0ef41Sopenharmony_ci    assert_equals(value, i, 'chunk content should match index');
881cb0ef41Sopenharmony_ci  }
891cb0ef41Sopenharmony_ci  const {done} = await reader.read();
901cb0ef41Sopenharmony_ci  assert_true(done, 'should be done now');
911cb0ef41Sopenharmony_ci}, 'sending ten chunks on demand should work');
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_cipromise_test(async () => {
941cb0ef41Sopenharmony_ci  const rs = recordingReadableStream({}, { highWaterMark: 0 });
951cb0ef41Sopenharmony_ci  await delay(0);
961cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, [], 'pull() should not have been called');
971cb0ef41Sopenharmony_ci  // Eat the message so it can't interfere with other tests.
981cb0ef41Sopenharmony_ci  addEventListener('message', () => {}, {once: true});
991cb0ef41Sopenharmony_ci  // The transfer is done manually to verify that it is posting the stream that
1001cb0ef41Sopenharmony_ci  // relieves backpressure, not receiving it.
1011cb0ef41Sopenharmony_ci  postMessage(rs, '*', [rs]);
1021cb0ef41Sopenharmony_ci  await delay(0);
1031cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, ['pull'], 'pull() should have been called');
1041cb0ef41Sopenharmony_ci}, 'transferring a stream should relieve backpressure');
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_cipromise_test(async () => {
1071cb0ef41Sopenharmony_ci  const rs = await recordingTransferredReadableStream({
1081cb0ef41Sopenharmony_ci    pull(controller) {
1091cb0ef41Sopenharmony_ci      controller.enqueue('a');
1101cb0ef41Sopenharmony_ci    }
1111cb0ef41Sopenharmony_ci  }, { highWaterMark: 2 });
1121cb0ef41Sopenharmony_ci  await delay(0);
1131cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, ['pull', 'pull', 'pull'],
1141cb0ef41Sopenharmony_ci                      'pull() should have been called three times');
1151cb0ef41Sopenharmony_ci}, 'transferring a stream should add one chunk to the queue size');
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_cipromise_test(async () => {
1181cb0ef41Sopenharmony_ci  const rs = await recordingTransferredReadableStream({
1191cb0ef41Sopenharmony_ci    start(controller) {
1201cb0ef41Sopenharmony_ci      controller.enqueue(new Uint8Array(1024));
1211cb0ef41Sopenharmony_ci      controller.enqueue(new Uint8Array(1024));
1221cb0ef41Sopenharmony_ci    }
1231cb0ef41Sopenharmony_ci  }, new ByteLengthQueuingStrategy({highWaterMark: 512}));
1241cb0ef41Sopenharmony_ci  await delay(0);
1251cb0ef41Sopenharmony_ci  // At this point the queue contains 1024/512 bytes and 1/1 chunk, so it's full
1261cb0ef41Sopenharmony_ci  // and pull() is not called.
1271cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, [], 'pull() should not have been called');
1281cb0ef41Sopenharmony_ci  const reader = rs.getReader();
1291cb0ef41Sopenharmony_ci  const {value, done} = await reader.read();
1301cb0ef41Sopenharmony_ci  assert_false(done, 'we should not be done');
1311cb0ef41Sopenharmony_ci  assert_equals(value.byteLength, 1024, 'expected chunk should be returned');
1321cb0ef41Sopenharmony_ci  // Now the queue contains 0/512 bytes and 1/1 chunk, so pull() is called. If
1331cb0ef41Sopenharmony_ci  // the implementation erroneously counted the extra queue space in bytes, then
1341cb0ef41Sopenharmony_ci  // the queue would contain 1024/513 bytes and pull() wouldn't be called.
1351cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, ['pull'], 'pull() should have been called');
1361cb0ef41Sopenharmony_ci}, 'the extra queue from transferring is counted in chunks');
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ciasync function transferredReadableStreamWithCancelPromise() {
1391cb0ef41Sopenharmony_ci  let resolveCancelCalled;
1401cb0ef41Sopenharmony_ci  const cancelCalled = new Promise(resolve => {
1411cb0ef41Sopenharmony_ci    resolveCancelCalled = resolve;
1421cb0ef41Sopenharmony_ci  });
1431cb0ef41Sopenharmony_ci  const rs = await recordingTransferredReadableStream({
1441cb0ef41Sopenharmony_ci    cancel() {
1451cb0ef41Sopenharmony_ci      resolveCancelCalled();
1461cb0ef41Sopenharmony_ci    }
1471cb0ef41Sopenharmony_ci  });
1481cb0ef41Sopenharmony_ci  return { rs, cancelCalled };
1491cb0ef41Sopenharmony_ci}
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_cipromise_test(async () => {
1521cb0ef41Sopenharmony_ci  const { rs, cancelCalled } = await transferredReadableStreamWithCancelPromise();
1531cb0ef41Sopenharmony_ci  rs.cancel('message');
1541cb0ef41Sopenharmony_ci  await cancelCalled;
1551cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, ['pull', 'cancel', 'message'],
1561cb0ef41Sopenharmony_ci                      'cancel() should have been called');
1571cb0ef41Sopenharmony_ci  const reader = rs.getReader();
1581cb0ef41Sopenharmony_ci  // Check the stream really got closed.
1591cb0ef41Sopenharmony_ci  await reader.closed;
1601cb0ef41Sopenharmony_ci}, 'cancel should be propagated to the original');
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_cipromise_test(async () => {
1631cb0ef41Sopenharmony_ci  const { rs, cancelCalled } = await transferredReadableStreamWithCancelPromise();
1641cb0ef41Sopenharmony_ci  const reader = rs.getReader();
1651cb0ef41Sopenharmony_ci  const readPromise = reader.read();
1661cb0ef41Sopenharmony_ci  reader.cancel('done');
1671cb0ef41Sopenharmony_ci  const { done } = await readPromise;
1681cb0ef41Sopenharmony_ci  assert_true(done, 'should be done');
1691cb0ef41Sopenharmony_ci  await cancelCalled;
1701cb0ef41Sopenharmony_ci  assert_array_equals(rs.events, ['pull', 'cancel', 'done'],
1711cb0ef41Sopenharmony_ci                      'events should match');
1721cb0ef41Sopenharmony_ci}, 'cancel should abort a pending read()');
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_cipromise_test(async () => {
1751cb0ef41Sopenharmony_ci  let cancelComplete = false;
1761cb0ef41Sopenharmony_ci  const rs = await createTransferredReadableStream({
1771cb0ef41Sopenharmony_ci    async cancel() {
1781cb0ef41Sopenharmony_ci      await flushAsyncEvents();
1791cb0ef41Sopenharmony_ci      cancelComplete = true;
1801cb0ef41Sopenharmony_ci    }
1811cb0ef41Sopenharmony_ci  });
1821cb0ef41Sopenharmony_ci  await rs.cancel();
1831cb0ef41Sopenharmony_ci  assert_false(cancelComplete,
1841cb0ef41Sopenharmony_ci               'cancel() on the underlying sink should not have completed');
1851cb0ef41Sopenharmony_ci}, 'stream cancel should not wait for underlying source cancel');
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_cipromise_test(async t => {
1881cb0ef41Sopenharmony_ci  const rs = await recordingTransferredReadableStream();
1891cb0ef41Sopenharmony_ci  const reader = rs.getReader();
1901cb0ef41Sopenharmony_ci  let serializationHappened = false;
1911cb0ef41Sopenharmony_ci  rs.controller.enqueue({
1921cb0ef41Sopenharmony_ci    get getter() {
1931cb0ef41Sopenharmony_ci      serializationHappened = true;
1941cb0ef41Sopenharmony_ci      return 'a';
1951cb0ef41Sopenharmony_ci    }
1961cb0ef41Sopenharmony_ci  });
1971cb0ef41Sopenharmony_ci  await flushAsyncEvents();
1981cb0ef41Sopenharmony_ci  assert_false(serializationHappened,
1991cb0ef41Sopenharmony_ci               'serialization should not have happened yet');
2001cb0ef41Sopenharmony_ci  const {value, done} = await reader.read();
2011cb0ef41Sopenharmony_ci  assert_false(done, 'should not be done');
2021cb0ef41Sopenharmony_ci  assert_equals(value.getter, 'a', 'getter should be a');
2031cb0ef41Sopenharmony_ci  assert_true(serializationHappened,
2041cb0ef41Sopenharmony_ci              'serialization should have happened');
2051cb0ef41Sopenharmony_ci}, 'serialization should not happen until the value is read');
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_cipromise_test(async t => {
2081cb0ef41Sopenharmony_ci  const rs = await recordingTransferredReadableStream();
2091cb0ef41Sopenharmony_ci  const reader = rs.getReader();
2101cb0ef41Sopenharmony_ci  rs.controller.enqueue(new ReadableStream());
2111cb0ef41Sopenharmony_ci  await promise_rejects_dom(t, 'DataCloneError', reader.read(),
2121cb0ef41Sopenharmony_ci                            'closed promise should reject');
2131cb0ef41Sopenharmony_ci  assert_throws_js(TypeError, () => rs.controller.enqueue(),
2141cb0ef41Sopenharmony_ci                   'original stream should be errored');
2151cb0ef41Sopenharmony_ci}, 'transferring a non-serializable chunk should error both sides');
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_cipromise_test(async t => {
2181cb0ef41Sopenharmony_ci  const rs = await createTransferredReadableStream({
2191cb0ef41Sopenharmony_ci    start(controller) {
2201cb0ef41Sopenharmony_ci      controller.error('foo');
2211cb0ef41Sopenharmony_ci    }
2221cb0ef41Sopenharmony_ci  });
2231cb0ef41Sopenharmony_ci  const reader = rs.getReader();
2241cb0ef41Sopenharmony_ci  return promise_rejects_exactly(t, 'foo', reader.read(),
2251cb0ef41Sopenharmony_ci                                 'error should be passed through');
2261cb0ef41Sopenharmony_ci}, 'errors should be passed through');
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_cipromise_test(async () => {
2291cb0ef41Sopenharmony_ci  const rs = await recordingTransferredReadableStream();
2301cb0ef41Sopenharmony_ci  await delay(0);
2311cb0ef41Sopenharmony_ci  const reader = rs.getReader();
2321cb0ef41Sopenharmony_ci  reader.cancel();
2331cb0ef41Sopenharmony_ci  rs.controller.error();
2341cb0ef41Sopenharmony_ci  const {done} = await reader.read();
2351cb0ef41Sopenharmony_ci  assert_true(done, 'should be done');
2361cb0ef41Sopenharmony_ci  assert_throws_js(TypeError, () => rs.controller.enqueue(),
2371cb0ef41Sopenharmony_ci                   'enqueue should throw');
2381cb0ef41Sopenharmony_ci}, 'race between cancel() and error() should leave sides in different states');
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_cipromise_test(async () => {
2411cb0ef41Sopenharmony_ci  const rs = await recordingTransferredReadableStream();
2421cb0ef41Sopenharmony_ci  await delay(0);
2431cb0ef41Sopenharmony_ci  const reader = rs.getReader();
2441cb0ef41Sopenharmony_ci  reader.cancel();
2451cb0ef41Sopenharmony_ci  rs.controller.close();
2461cb0ef41Sopenharmony_ci  const {done} = await reader.read();
2471cb0ef41Sopenharmony_ci  assert_true(done, 'should be done');
2481cb0ef41Sopenharmony_ci}, 'race between cancel() and close() should be benign');
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_cipromise_test(async () => {
2511cb0ef41Sopenharmony_ci  const rs = await recordingTransferredReadableStream();
2521cb0ef41Sopenharmony_ci  await delay(0);
2531cb0ef41Sopenharmony_ci  const reader = rs.getReader();
2541cb0ef41Sopenharmony_ci  reader.cancel();
2551cb0ef41Sopenharmony_ci  rs.controller.enqueue('a');
2561cb0ef41Sopenharmony_ci  const {done} = await reader.read();
2571cb0ef41Sopenharmony_ci  assert_true(done, 'should be done');
2581cb0ef41Sopenharmony_ci}, 'race between cancel() and enqueue() should be benign');
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci</script>
261