Skip to content

Commit d2c906d

Browse files
1 parent bf101f7 commit d2c906d

1 file changed

Lines changed: 111 additions & 0 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// META: global=window,worker
2+
// META: script=resources/webtransport-test-helpers.sub.js
3+
// META: timeout=long
4+
5+
// Tests the pull steps of a WebTransportReceiveStream:
6+
// https://w3c.github.io/webtransport/#webtransportreceivestream-pull-bytes
7+
8+
// Returns a bidirectional stream whose readable end receives |data| echoed back
9+
// by the server, followed by FIN.
10+
async function echo_bidirectional_stream(wt, data) {
11+
const bidi_stream = await wt.createBidirectionalStream();
12+
const writer = bidi_stream.writable.getWriter();
13+
await writer.write(data);
14+
await writer.close();
15+
return bidi_stream;
16+
}
17+
18+
function ascending_bytes(length) {
19+
const data = new Uint8Array(length);
20+
for (let i = 0; i < data.byteLength; ++i) {
21+
data[i] = i;
22+
}
23+
return data;
24+
}
25+
26+
promise_test(async t => {
27+
const wt = new WebTransport(webtransport_url('echo.py'));
28+
await wt.ready;
29+
30+
const data = ascending_bytes(64);
31+
const bidi_stream = await echo_bidirectional_stream(wt, data);
32+
33+
// Give the echoed bytes and the FIN a chance to be received before anything
34+
// reads them, so that the reads below are served from buffered bytes. The test
35+
// is valid either way: a read that arrives first waits for the bytes instead.
36+
await wait(100);
37+
38+
const chunks = await read_stream(bidi_stream.readable);
39+
const received = new Uint8Array(chunks.reduce((length, chunk) => length + chunk.byteLength, 0));
40+
let offset = 0;
41+
for (const chunk of chunks) {
42+
received.set(chunk, offset);
43+
offset += chunk.byteLength;
44+
}
45+
46+
// No bytes may be lost when the stream is closed while bytes are still waiting
47+
// to be given to the readable end.
48+
assert_array_equals(received, data);
49+
wt.close();
50+
}, 'Bytes received before any read are given to later reads');
51+
52+
promise_test(async t => {
53+
const wt = new WebTransport(webtransport_url('echo.py'));
54+
await wt.ready;
55+
56+
const data = ascending_bytes(64);
57+
const bidi_stream = await echo_bidirectional_stream(wt, data);
58+
await wait(100);
59+
60+
// Read one byte at a time. Each view is smaller than what the server sent, so
61+
// the bytes that do not fit in it must be kept for the following reads.
62+
const reader = bidi_stream.readable.getReader({mode: 'byob'});
63+
for (let i = 0; i < data.byteLength; ++i) {
64+
const {value: view, done} = await reader.read(new Uint8Array(1));
65+
assert_false(done, `read ${i} should not be done`);
66+
assert_array_equals(view, data.subarray(i, i + 1), `read ${i}`);
67+
}
68+
69+
// All the bytes have been read and the server ended its stream, so the next
70+
// read closes the readable end.
71+
const {value: view, done} = await reader.read(new Uint8Array(1));
72+
assert_true(done, 'the last read should be done');
73+
assert_equals(view.byteLength, 0, 'the last read should not fill the view');
74+
await reader.closed;
75+
reader.releaseLock();
76+
wt.close();
77+
}, 'A BYOB read smaller than the received bytes keeps the rest for later reads');
78+
79+
promise_test(async t => {
80+
const wt = new WebTransport(webtransport_url('echo.py'));
81+
await wt.ready;
82+
83+
const bidi_stream = await wt.createBidirectionalStream();
84+
85+
// Read before anything is received. The read has to wait until either a byte is
86+
// received or the server ends its stream.
87+
const reader = bidi_stream.readable.getReader();
88+
const read = reader.read();
89+
90+
const data = ascending_bytes(8);
91+
const writer = bidi_stream.writable.getWriter();
92+
await writer.write(data);
93+
94+
const {value: chunk, done} = await read;
95+
assert_false(done, 'the pending read should not be done');
96+
assert_greater_than(chunk.byteLength, 0, 'the pending read should receive at least one byte');
97+
98+
// Read the rest in case the bytes did not all arrive in a single chunk.
99+
let received = Array.from(chunk);
100+
await writer.close();
101+
while (received.length < data.byteLength) {
102+
const {value: chunk, done} = await reader.read();
103+
assert_false(done, 'the stream should not end before all its bytes are read');
104+
received = received.concat(Array.from(chunk));
105+
}
106+
assert_array_equals(received, Array.from(data));
107+
108+
assert_true((await reader.read()).done, 'the read after FIN should be done');
109+
reader.releaseLock();
110+
wt.close();
111+
}, 'A read waits for bytes that have not been received yet');

0 commit comments

Comments
 (0)