| <!doctype html> |
| <meta charset=utf-8> |
| <title>RTCQuicStream.https.html</title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="RTCIceTransport-extension-helper.js"></script> |
| <script src="RTCQuicTransport-helper.js"></script> |
| <script src="RTCQuicStream-helper.js"></script> |
| <script> |
| 'use strict'; |
| |
| // These tests are based on the following specification: |
| // https://w3c.github.io/webrtc-quic/ |
| |
| // The following helper functions are called from RTCQuicTransport-helper.js: |
| // makeStandaloneQuicTransport |
| // makeTwoConnectedQuicTransports |
| // The following helper functions are called from RTCQuicStream-helper.js: |
| // closed_stream_test |
| |
| promise_test(async t => { |
| const [ quicTransport, ] = await makeTwoConnectedQuicTransports(t); |
| const quicStream = quicTransport.createStream(); |
| assert_equals(quicStream.transport, quicTransport, |
| 'Expect transport to be set to the creating RTCQuicTransport.'); |
| assert_equals(quicStream.state, 'open', `Expect state to be 'open'.`); |
| assert_equals(quicStream.readBufferedAmount, 0, |
| 'Expect read buffered amount to be 0.'); |
| assert_equals(quicStream.writeBufferedAmount, 0, |
| 'Expect write buffered amount to be 0.'); |
| assert_greater_than(quicStream.maxWriteBufferedAmount, 0, |
| 'Expect max write buffered amount to be greater than 0.'); |
| }, 'createStream() returns an RTCQuicStream with initial properties set.'); |
| |
| promise_test(async t => { |
| const quicTransport = await makeStandaloneQuicTransport(t); |
| assert_throws('InvalidStateError', () => quicTransport.createStream()); |
| }, 'createStream() throws if the transport is not connected.'); |
| |
| promise_test(async t => { |
| const quicTransport = await makeStandaloneQuicTransport(t); |
| quicTransport.stop(); |
| assert_throws('InvalidStateError', () => quicTransport.createStream()); |
| }, 'createStream() throws if the transport is closed.'); |
| |
| promise_test(async t => { |
| const [ quicTransport, ] = await makeTwoConnectedQuicTransports(t); |
| const firstQuicStream = quicTransport.createStream(); |
| const secondQuicStream = quicTransport.createStream(); |
| quicTransport.stop(); |
| assert_equals(firstQuicStream.state, 'closed'); |
| assert_equals(secondQuicStream.state, 'closed'); |
| }, 'RTCQuicTransport.stop() closes all local streams.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| localQuicTransport.createStream().finish(); |
| localQuicTransport.createStream().finish(); |
| const remoteWatcher = |
| new EventWatcher(t, remoteQuicTransport, [ 'quicstream', 'statechange' ]); |
| const { stream: firstRemoteStream } = |
| await remoteWatcher.wait_for('quicstream'); |
| const { stream: secondRemoteStream } = |
| await remoteWatcher.wait_for('quicstream'); |
| localQuicTransport.stop(); |
| await remoteWatcher.wait_for('statechange'); |
| assert_equals(firstRemoteStream.state, 'closed'); |
| assert_equals(secondRemoteStream.state, 'closed'); |
| }, 'RTCQuicTransport.stop() closes all remote streams.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.finish(); |
| assert_equals(localStream.state, 'closing'); |
| }, `finish() changes state to 'closing'.`); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.finish(); |
| localStream.finish(); |
| assert_equals(localStream.state, 'closing'); |
| }, `finish() twice does not change state.`); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.reset(); |
| assert_equals(localStream.state, 'closed'); |
| }, `reset() changes state to 'closed'.`); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.finish(); |
| localStream.reset(); |
| assert_equals(localStream.state, 'closed'); |
| }, `reset() following finish() changes state to 'closed'.`); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.reset(); |
| const remoteWatcher = new EventWatcher(t, remoteQuicTransport, 'quicstream'); |
| const { stream: remoteStream } = await remoteWatcher.wait_for('quicstream'); |
| assert_equals(remoteStream.state, 'open'); |
| const remoteStreamWatcher = new EventWatcher(t, remoteStream, 'statechange'); |
| await remoteStreamWatcher.wait_for('statechange'); |
| assert_equals(remoteStream.state, 'closed'); |
| }, 'createStream() followed by reset() fires a quicstream event followed ' + |
| `by a statechange event to 'closed' on the remote side.`); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.write(new Uint8Array(0)); |
| assert_equals(localStream.writeBufferedAmount, 0); |
| }, 'write() with an empty array does nothing.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.write(new Uint8Array([65])); |
| assert_equals(localStream.writeBufferedAmount, 1); |
| localStream.write(new Uint8Array([66, 67])); |
| assert_equals(localStream.writeBufferedAmount, 3); |
| localStream.write(new Uint8Array([68, 69, 70])); |
| assert_equals(localStream.writeBufferedAmount, 6); |
| }, 'write() adds to writeBufferedAmount each call.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.write(new Uint8Array(localStream.maxWriteBufferedAmount)); |
| assert_equals(localStream.writeBufferedAmount, |
| localStream.maxWriteBufferedAmount); |
| }, 'write() can write exactly maxWriteBufferedAmount.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| assert_throws('OperationError', |
| () => |
| localStream.write( |
| new Uint8Array(localStream.maxWriteBufferedAmount + 1))); |
| assert_equals(localStream.writeBufferedAmount, 0); |
| }, 'write() throws if data longer than maxWriteBufferedAmount.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.write(new Uint8Array(10)); |
| assert_throws('OperationError', |
| () => |
| localStream.write( |
| new Uint8Array(localStream.maxWriteBufferedAmount))); |
| assert_equals(localStream.writeBufferedAmount, 10); |
| }, 'write() throws if total write buffered amount would be greater than ' + |
| 'maxWriteBufferedAmount.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.write(new Uint8Array(10)); |
| const remoteWatcher = new EventWatcher(t, remoteQuicTransport, 'quicstream'); |
| await remoteWatcher.wait_for('quicstream'); |
| }, 'write() causes quicstream event to fire on the remote transport.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.finish(); |
| const remoteWatcher = new EventWatcher(t, remoteQuicTransport, 'quicstream'); |
| await remoteWatcher.wait_for('quicstream'); |
| }, 'finish() causes quicstream event to fire on the remote transport.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.finish(); |
| assert_throws('InvalidStateError', |
| () => localStream.write(new Uint8Array())); |
| }, 'write() throws InvalidStateError if finish() has been called.'); |
| |
| closed_stream_test(async (t, stream) => { |
| assert_throws('InvalidStateError', () => stream.write(new Uint8Array())); |
| }, 'write() throws InvalidStateError.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.write(new Uint8Array(10)); |
| localStream.reset(); |
| assert_equals(localStream.writeBufferedAmount, 0); |
| }, 'writeBufferedAmount set to 0 after local reset().'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.write(new Uint8Array(10)); |
| localQuicTransport.stop(); |
| assert_equals(localStream.writeBufferedAmount, 0); |
| }, 'writeBufferedAmount set to 0 after local RTCQuicTransport stop().'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.write(new Uint8Array(10)); |
| localStream.finish(); |
| assert_equals(localStream.writeBufferedAmount, 10); |
| }, 'writeBufferedAmount maintained after finish() has been called.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| await localStream.waitForWriteBufferedAmountBelow(0); |
| }, 'waitForWriteBufferedAmountBelow(0) resolves immediately.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| await localStream.waitForWriteBufferedAmountBelow( |
| localStream.maxWriteBufferedAmount); |
| }, 'waitForWriteBufferedAmountBelow(maxWriteBufferedAmount) resolves ' + |
| 'immediately.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.write(new Uint8Array(localStream.maxWriteBufferedAmount)); |
| const promise1 = localStream.waitForWriteBufferedAmountBelow(0); |
| const promise2 = localStream.waitForWriteBufferedAmountBelow(0); |
| localStream.finish(); |
| await Promise.all([ |
| promise_rejects(t, 'InvalidStateError', promise1), |
| promise_rejects(t, 'InvalidStateError', promise2)]); |
| }, 'Pending waitForWriteBufferedAmountBelow() promises rejected after ' + |
| 'finish().'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| localStream.write(new Uint8Array(localStream.maxWriteBufferedAmount)); |
| const promise1 = localStream.waitForWriteBufferedAmountBelow(0); |
| const promise2 = localStream.waitForWriteBufferedAmountBelow(0); |
| localStream.reset(); |
| await Promise.all([ |
| promise_rejects(t, 'InvalidStateError', promise1), |
| promise_rejects(t, 'InvalidStateError', promise2)]); |
| }, 'Pending waitForWriteBufferedAmountBelow() promises rejected after ' + |
| 'reset().'); |
| |
| closed_stream_test(async (t, stream) => { |
| await promise_rejects(t, 'InvalidStateError', |
| stream.waitForWriteBufferedAmountBelow(0)); |
| }, 'waitForWriteBufferedBelow() rejects with InvalidStateError.'); |
| |
| promise_test(async t => { |
| const [ localQuicTransport, remoteQuicTransport ] = |
| await makeTwoConnectedQuicTransports(t); |
| const localStream = localQuicTransport.createStream(); |
| assert_object_equals( |
| localStream.readInto(new Uint8Array(10)), |
| { amount: 0, finished: false }); |
| }, 'readInto() on new local stream returns amount 0.'); |
| |
| closed_stream_test(async (t, stream) => { |
| assert_throws('InvalidStateError', () => stream.readInto(new Uint8Array(1))); |
| }, 'readInto() throws InvalidStateError.'); |
| |
| </script> |