Skip to content

Commit

Permalink
Add more WebTransport web-platform tests to cover more of the API
Browse files Browse the repository at this point in the history
Differential Revision: https://phabricator.services.mozilla.com/D172427

bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1822058
gecko-commit: af3732371d385722defee38e18cb018e1834bec2
gecko-reviewers: jib
  • Loading branch information
jesup authored and SkyBlack1225 committed Dec 21, 2023
1 parent 2e7f431 commit febeadd
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 2 deletions.
103 changes: 101 additions & 2 deletions webtransport/datagrams.https.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ async function write_datagrams(writer, signal) {
return sentTokens;
}

// Write N datagrams without waiting, then wait for them
async function write_N_datagrams(writer, n) {
const encoder = new TextEncoder();
const sentTokens = [];
const promises = [];
while (sentTokens.length < n) {
const token = sentTokens.length.toString();
sentTokens.push(token);
promises.push(writer.write(encoder.encode(token)));
}
await Promise.all(promises);
return sentTokens;
}

// Read datagrams until the consumer has received enough i.e. N datagrams. Call
// abort() after reading.
async function read_datagrams(reader, controller, N) {
Expand Down Expand Up @@ -155,6 +169,37 @@ promise_test(async t => {
assert_equals(error.name, 'RangeError');
}, 'Reading datagrams with insufficient buffer should be rejected.');

promise_test(async t => {
// Establish a WebTransport session.
const wt = new WebTransport(webtransport_url('echo.py'));
await wt.ready;

const writer = wt.datagrams.writable.getWriter();
const reader = wt.datagrams.readable.getReader();

// Write and read max-size datagram.
await writer.write(new Uint8Array(wt.datagrams.maxDatagramSize));
const { value: token, done } = await reader.read();
assert_false(done);
assert_equals(token.length, wt.datagrams.maxDatagramSize);
}, 'Transfer max-size datagram');

promise_test(async t => {
// Establish a WebTransport session.
const wt = new WebTransport(webtransport_url('echo.py'));
await wt.ready;

const writer = wt.datagrams.writable.getWriter();
const reader = wt.datagrams.readable.getReader();

// Write and read max-size datagram.
await writer.write(new Uint8Array(wt.datagrams.maxDatagramSize+1));
// This should resolve with no datagram sent, which is hard to test for.
// Wait for incoming datagrams to arrive, and if they do, fail.
const result = await Promise.race([reader.read(), wait(500)]);
assert_equals(result, undefined);
}, 'Fail to transfer max-size+1 datagram');

promise_test(async t => {
// Make a WebTransport connection, but session is not necessarily established.
const wt = new WebTransport(webtransport_url('echo.py'));
Expand All @@ -166,9 +211,10 @@ promise_test(async t => {
const signal = controller.signal;

// Write and read datagrams.
const N = 1;
const N = 5;
wt.datagrams.outgoingHighWaterMark = N;
const [sentTokens, receivedTokens] = await Promise.all([
write_datagrams(writer, signal),
write_N_datagrams(writer, N),
read_datagrams(reader, controller, N)
]);

Expand Down Expand Up @@ -269,3 +315,56 @@ promise_test(async t => {
// incomingHighWaterMark.
assert_less_than_equal(receivedDatagrams, N);
}, 'Datagrams read is less than or equal to the incomingHighWaterMark');

promise_test(async t => {
// Establish a WebTransport session.
const wt = new WebTransport(webtransport_url('echo.py'));
await wt.ready;

assert_equals(wt.datagrams.incomingMaxAge, Infinity);
assert_equals(wt.datagrams.outgoingMaxAge, Infinity);

wt.datagrams.incomingMaxAge = 5;
assert_equals(wt.datagrams.incomingMaxAge, 5);
wt.datagrams.outgoingMaxAge = 5;
assert_equals(wt.datagrams.outgoingMaxAge, 5);

assert_throws_js(RangeError, () => { wt.datagrams.incomingMaxAge = -1; });
assert_throws_js(RangeError, () => { wt.datagrams.outgoingMaxAge = -1; });
assert_throws_js(RangeError, () => { wt.datagrams.incomingMaxAge = NaN; });
assert_throws_js(RangeError, () => { wt.datagrams.outgoingMaxAge = NaN; });

wt.datagrams.incomingMaxAge = 0;
assert_equals(wt.datagrams.incomingMaxAge, Infinity);
wt.datagrams.outgoingMaxAge = 0;
assert_equals(wt.datagrams.outgoingMaxAge, Infinity);
}, 'Datagram MaxAge getters/setters work correctly');

promise_test(async t => {
// Establish a WebTransport session.
const wt = new WebTransport(webtransport_url('echo.py'));
await wt.ready;

// Initial values are implementation-defined
assert_greater_than_equal(wt.datagrams.incomingHighWaterMark, 1);
assert_greater_than_equal(wt.datagrams.outgoingHighWaterMark, 1);

wt.datagrams.incomingHighWaterMark = 5;
assert_equals(wt.datagrams.incomingHighWaterMark, 5);
wt.datagrams.outgoingHighWaterMark = 5;
assert_equals(wt.datagrams.outgoingHighWaterMark, 5);

assert_throws_js(RangeError, () => { wt.datagrams.incomingHighWaterMark = -1; });
assert_throws_js(RangeError, () => { wt.datagrams.outgoingHighWaterMark = -1; });
assert_throws_js(RangeError, () => { wt.datagrams.incomingHighWaterMark = NaN; });
assert_throws_js(RangeError, () => { wt.datagrams.outgoingHighWaterMark = NaN; });

wt.datagrams.incomingHighWaterMark = 0.5;
assert_equals(wt.datagrams.incomingHighWaterMark, 1);
wt.datagrams.outgoingHighWaterMark = 0.5;
assert_equals(wt.datagrams.outgoingHighWaterMark, 1);
wt.datagrams.incomingHighWaterMark = 0;
assert_equals(wt.datagrams.incomingHighWaterMark, 1);
wt.datagrams.outgoingHighWaterMark = 0;
assert_equals(wt.datagrams.outgoingHighWaterMark, 1);
}, 'Datagram HighWaterMark getters/setters work correctly');
17 changes: 17 additions & 0 deletions webtransport/resources/webtransport-test-helpers.sub.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ function webtransport_code_to_http_code(n) {
return first + n + Math.floor(n / 0x1e);
}

// Read all chunks from |readable_stream| and return as an array of arrays
async function read_stream(readable_stream) {
const reader = readable_stream.getReader();

let chunks = [];
while (true) {
const {value: chunk, done} = await reader.read();
if (done) {
break;
}
chunks.push(chunk);
}
reader.releaseLock();

return chunks;
}

// Read all chunks from |readable_stream|, decode chunks to a utf-8 string, then
// return the string.
async function read_stream_as_string(readable_stream) {
Expand Down
62 changes: 62 additions & 0 deletions webtransport/streams-echo.https.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,65 @@ promise_test(async t => {
}
reader.releaseLock();
}, 'Can read data from a unidirectional stream with BYOB reader');

promise_test(async t => {
// Establish a WebTransport session.
const wt = new WebTransport(webtransport_url('echo.py'));
await wt.ready;

// Create a bidirectional stream.
const bidi_stream = await wt.createBidirectionalStream();

// Write a message to the writable end, and close it.
const writer = bidi_stream.writable.getWriter();
const bytes = new Uint8Array(16384);
const [reply] = await Promise.all([
read_stream(bidi_stream.readable),
writer.write(bytes),
writer.write(bytes),
writer.write(bytes),
writer.close()
]);
let len = 0;
for (chunk of reply) {
len += chunk.length;
}
// Check that the message from the readable end matches the writable end.
assert_equals(len, 3*bytes.length);
}, 'Transfer large chunks of data on a bidirectional stream');

promise_test(async t => {
// Establish a WebTransport session.
const wt = new WebTransport(webtransport_url('echo.py'));
await wt.ready;

// Create a unidirectional stream.
const uni_stream = await wt.createUnidirectionalStream();

// Write a message to the writable end, and close it.
const writer = uni_stream.getWriter();
const bytes = new Uint8Array(16384);
await Promise.all([
writer.write(bytes),
writer.write(bytes),
writer.write(bytes),
writer.close()
]);
// XXX Update once chrome fixes https://crbug.com/929585
// The echo handler creates a new unidirectional stream to echo back data from
// the server to client. Accept the unidirectional stream.
const readable = wt.incomingUnidirectionalStreams;
const stream_reader = readable.getReader();
const { value: recv_stream } = await stream_reader.read();
stream_reader.releaseLock();

// Read the data on the readable end.
const reply = await read_stream(recv_stream);
let len = 0;
for (chunk of reply) {
len += chunk.length;
}
// Check that the message from the readable end matches the writable end.
assert_equals(len, 3*bytes.length);
}, 'Transfer large chunks of data on a unidirectional stream');

0 comments on commit febeadd

Please sign in to comment.