Skip to content

Commit

Permalink
Add tests related to ReadableStream of type 'owning' (#39520)
Browse files Browse the repository at this point in the history
* Add tests related to ReadableStream of type 'owning'

---------

Co-authored-by: Mattias Buelens <649348+MattiasBuelens@users.noreply.github.com>
  • Loading branch information
youennf and MattiasBuelens committed May 16, 2023
1 parent 9e699dc commit 0d3e62f
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 1 deletion.
2 changes: 1 addition & 1 deletion interfaces/streams.idl
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ callback UnderlyingSourceStartCallback = any (ReadableStreamController controlle
callback UnderlyingSourcePullCallback = Promise<undefined> (ReadableStreamController controller);
callback UnderlyingSourceCancelCallback = Promise<undefined> (optional any reason);

enum ReadableStreamType { "bytes" };
enum ReadableStreamType { "bytes", "owning" };

interface mixin ReadableStreamGenericReader {
readonly attribute Promise<undefined> closed;
Expand Down
49 changes: 49 additions & 0 deletions streams/readable-streams/owning-type-message-port.any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/rs-utils.js
'use strict';

promise_test(async () => {
const channel = new MessageChannel;
const port1 = channel.port1;
const port2 = channel.port2;

const source = {
start(controller) {
controller.enqueue(port1, { transfer : [ port1 ] });
},
type: 'owning'
};

const stream = new ReadableStream(source);

const chunk = await stream.getReader().read();

assert_not_equals(chunk.value, port1);

let promise = new Promise(resolve => port2.onmessage = e => resolve(e.data));
chunk.value.postMessage("toPort2");
assert_equals(await promise, "toPort2");

promise = new Promise(resolve => chunk.value.onmessage = e => resolve(e.data));
port2.postMessage("toPort1");
assert_equals(await promise, "toPort1");
}, 'Transferred MessageChannel works as expected');

promise_test(async t => {
const channel = new MessageChannel;
const port1 = channel.port1;
const port2 = channel.port2;

const source = {
start(controller) {
controller.enqueue({ port1 }, { transfer : [ port1 ] });
},
type: 'owning'
};

const stream = new ReadableStream(source);
const [clone1, clone2] = stream.tee();

await promise_rejects_dom(t, "DataCloneError", clone2.getReader().read());
}, 'Second branch of owning ReadableStream tee should end up into errors with transfer only values');
128 changes: 128 additions & 0 deletions streams/readable-streams/owning-type-video-frame.any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/rs-utils.js
'use strict';

function createVideoFrame()
{
let init = {
format: 'I420',
timestamp: 1234,
codedWidth: 4,
codedHeight: 2
};
let data = new Uint8Array([
1, 2, 3, 4, 5, 6, 7, 8, // y
1, 2, // u
1, 2, // v
]);

return new VideoFrame(data, init);
}

promise_test(async () => {
const videoFrame = createVideoFrame();
videoFrame.test = 1;
const source = {
start(controller) {
assert_equals(videoFrame.format, 'I420');
controller.enqueue(videoFrame, { transfer : [ videoFrame ] });
assert_equals(videoFrame.format, null);
assert_equals(videoFrame.test, 1);
},
type: 'owning'
};

const stream = new ReadableStream(source);
// Cancelling the stream should close all video frames, thus no console messages of GCing VideoFrames should happen.
stream.cancel();
}, 'ReadableStream of type owning should close serialized chunks');

promise_test(async () => {
const videoFrame = createVideoFrame();
videoFrame.test = 1;
const source = {
start(controller) {
assert_equals(videoFrame.format, 'I420');
controller.enqueue({ videoFrame }, { transfer : [ videoFrame ] });
assert_equals(videoFrame.format, null);
assert_equals(videoFrame.test, 1);
},
type: 'owning'
};

const stream = new ReadableStream(source);
const reader = stream.getReader();

const chunk = await reader.read();
assert_equals(chunk.value.videoFrame.format, 'I420');
assert_equals(chunk.value.videoFrame.test, undefined);

chunk.value.videoFrame.close();
}, 'ReadableStream of type owning should transfer JS chunks with transferred values');

promise_test(async t => {
const videoFrame = createVideoFrame();
videoFrame.close();
const source = {
start(controller) {
assert_throws_dom("DataCloneError", () => controller.enqueue(videoFrame, { transfer : [ videoFrame ] }));
},
type: 'owning'
};

const stream = new ReadableStream(source);
const reader = stream.getReader();

await promise_rejects_dom(t, "DataCloneError", reader.read());
}, 'ReadableStream of type owning should error when trying to enqueue not serializable values');

promise_test(async () => {
const videoFrame = createVideoFrame();
const source = {
start(controller) {
controller.enqueue(videoFrame, { transfer : [ videoFrame ] });
},
type: 'owning'
};

const stream = new ReadableStream(source);
const [clone1, clone2] = stream.tee();

const chunk1 = await clone1.getReader().read();
const chunk2 = await clone2.getReader().read();

assert_equals(videoFrame.format, null);
assert_equals(chunk1.value.format, 'I420');
assert_equals(chunk2.value.format, 'I420');

chunk1.value.close();
chunk2.value.close();
}, 'ReadableStream of type owning should clone serializable objects when teeing');

promise_test(async () => {
const videoFrame = createVideoFrame();
videoFrame.test = 1;
const source = {
start(controller) {
assert_equals(videoFrame.format, 'I420');
controller.enqueue({ videoFrame }, { transfer : [ videoFrame ] });
assert_equals(videoFrame.format, null);
assert_equals(videoFrame.test, 1);
},
type: 'owning'
};

const stream = new ReadableStream(source);
const [clone1, clone2] = stream.tee();

const chunk1 = await clone1.getReader().read();
const chunk2 = await clone2.getReader().read();

assert_equals(videoFrame.format, null);
assert_equals(chunk1.value.videoFrame.format, 'I420');
assert_equals(chunk2.value.videoFrame.format, 'I420');

chunk1.value.videoFrame.close();
chunk2.value.videoFrame.close();
}, 'ReadableStream of type owning should clone JS Objects with serializables when teeing');
91 changes: 91 additions & 0 deletions streams/readable-streams/owning-type.any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/rs-utils.js
'use strict';

test(() => {
new ReadableStream({ type: 'owning' }); // ReadableStream constructed with 'owning' type
}, 'ReadableStream can be constructed with owning type');

test(() => {
let startCalled = false;

const source = {
start(controller) {
assert_equals(this, source, 'source is this during start');
assert_true(controller instanceof ReadableStreamDefaultController, 'default controller');
startCalled = true;
},
type: 'owning'
};

new ReadableStream(source);
assert_true(startCalled);
}, 'ReadableStream of type owning should call start with a ReadableStreamDefaultController');

test(() => {
let startCalled = false;

const source = {
start(controller) {
controller.enqueue("a", { transfer: [] });
controller.enqueue("a", { transfer: undefined });
startCalled = true;
},
type: 'owning'
};

new ReadableStream(source);
assert_true(startCalled);
}, 'ReadableStream should be able to call enqueue with an empty transfer list');

test(() => {
let startCalled = false;

const uint8Array = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
const buffer = uint8Array.buffer;
let source = {
start(controller) {
startCalled = true;
assert_throws_js(TypeError, () => { controller.enqueue(buffer, { transfer : [ buffer ] }); }, "transfer list is not empty");
}
};

new ReadableStream(source);
assert_true(startCalled);

startCalled = false;
source = {
start(controller) {
startCalled = true;
assert_throws_js(TypeError, () => { controller.enqueue(buffer, { get transfer() { throw new TypeError(); } }) }, "getter throws");
}
};

new ReadableStream(source);
assert_true(startCalled);
}, 'ReadableStream should check transfer parameter');

promise_test(async () => {
const uint8Array = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
const buffer = uint8Array.buffer;
buffer.test = 1;
const source = {
start(controller) {
assert_equals(buffer.byteLength, 8);
controller.enqueue(buffer, { transfer : [ buffer ] });
assert_equals(buffer.byteLength, 0);
assert_equals(buffer.test, 1);
},
type: 'owning'
};

const stream = new ReadableStream(source);
const reader = stream.getReader();

const chunk = await reader.read();

assert_not_equals(chunk.value, buffer);
assert_equals(chunk.value.byteLength, 8);
assert_equals(chunk.value.test, undefined);
}, 'ReadableStream of type owning should transfer enqueued chunks');

0 comments on commit 0d3e62f

Please sign in to comment.