Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests related to ReadableStream of type 'owning' #39520

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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", "transfer" };
youennf marked this conversation as resolved.
Show resolved Hide resolved

interface mixin ReadableStreamGenericReader {
readonly attribute Promise<undefined> closed;
Expand Down
51 changes: 51 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,51 @@
// 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 () => {
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 clone2.getReader().read().then((value) => {
assert_unreached('clone2 should error');
}, () => { });
youennf marked this conversation as resolved.
Show resolved Hide resolved
}, 'Second branch of owning ReadableStream tee should end up into errors with transfer only values');
136 changes: 136 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,136 @@
// 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 () => {
const videoFrame = createVideoFrame();
videoFrame.close();
const source = {
start(controller) {
try {
controller.enqueue(videoFrame, { transfer : [ videoFrame ] });
assert_unreached('enqueue should throw');
} catch (e) {
//
}
youennf marked this conversation as resolved.
Show resolved Hide resolved
},
type: 'owning'
};

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

return reader.read().then(() => {
assert_unreached('enqueue should error the stream');
}, () => {
});
}, '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');