blob: 74a5e527d1fea9c97d1ed3e3c3c0ba4f8254bf2c [file] [log] [blame]
<!DOCTYPE html>
<script src='../../resources/testharness.js'></script>
<script src='../../resources/testharnessreport.js'></script>
<script src='resources/streams-utils.js'></script>
<script>
var test1 = async_test('ReadableStream cancellation: integration test on an infinite stream derived from a random push source');
test1.step(function() {
var randomSource = new RandomPushSource();
var cancellationFinished = false;
var rs = new ReadableStream({
start: function(c) {
randomSource.ondata = c.enqueue.bind(c);
randomSource.onend = c.close.bind(c);
randomSource.onerror = c.error.bind(c);
},
pull: function() {
randomSource.readStart();
},
cancel: function() {
randomSource.readStop();
randomSource.onend();
return new Promise(test1.step_func(function(resolve) {
setTimeout(test1.step_func(function() {
cancellationFinished = true;
resolve();
}), 50)
}));
}
});
var reader = rs.getReader();
readableStreamToArray(rs, reader).then(test1.step_func(function(chunks) {
assert_equals(cancellationFinished, false, 'it did not wait for the cancellation process to finish before closing');
assert_greater_than(chunks.length, 0, 'at least one chunk should be read');
for (var i = 0; i < chunks.length; i++) {
assert_equals(chunks[i].length, 128, "chunk should have 128 bytes");
}
}), test1.step_func(function(e) { assert_unreached(e); }));
setTimeout(test1.step_func(function() {
reader.cancel().then(test1.step_func(function() {
assert_equals(cancellationFinished, true, 'it returns a promise that is fulfilled when the cancellation finishes');
test1.done();
})).catch(test1.step_func(function(e) { assert_unreached(e); }));
}), 150);
});
test(function() {
var recordedReason;
var rs = new ReadableStream({
cancel: function(reason) {
recordedReason = reason;
}
});
var passedReason = new Error('Sorry, it just wasn\'t meant to be.');
rs.cancel(passedReason);
assert_equals(recordedReason, passedReason,
'the error passed to the underlying source\'s cancel method should equal the one passed to the stream\'s cancel');
}, 'ReadableStream cancellation: cancel(reason) should pass through the given reason to the underlying source');
var test2 = async_test('ReadableStream cancellation: cancel() on a locked stream should fail and not call the underlying source cancel');
test2.step(function() {
var rs = new ReadableStream({
start: function(c) {
c.enqueue('a');
c.close();
},
cancel: function() {
assert_unreached('underlying source cancel() should not have been called');
}
});
var reader = rs.getReader();
rs.cancel().catch(test2.step_func(function(e) {
assert_throws(new TypeError(), e, 'cancel() should be rejected with a TypeError')
}));
reader.read().then(test2.step_func(function(result) {
assert_object_equals(result, { value: 'a', done: false }, 'read() should still work after the attempted cancel');
}));
reader.closed.then(test2.step_func(function() {
test2.done('closed should fulfill without underlying source cancel ever being called');
}));
});
var test3 = async_test('ReadableStream cancellation: returning a value from the underlying source\'s cancel should not affect the fulfillment value of the promise returned by the stream\'s cancel');
test3.step(function() {
var rs = new ReadableStream({
cancel: function(reason) {
return 'Hello';
}
});
rs.cancel().then(test3.step_func(function(v) {
assert_equals(v, undefined, 'cancel() return value should be fulfilled with undefined');
test3.done();
}), test3.step_func(function() {
assert_unreached('cancel() return value should not be rejected');
}));
});
var test4 = async_test('ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should fulfill when that one does');
test4.step(function() {
var resolveSourceCancelPromise;
var sourceCancelPromiseHasFulfilled = false;
var rs = new ReadableStream({
cancel: function() {
var sourceCancelPromise = new Promise(test4.step_func(function(resolve, reject) {
resolveSourceCancelPromise = resolve;
}));
sourceCancelPromise.then(test4.step_func(function() {
sourceCancelPromiseHasFulfilled = true;
}));
return sourceCancelPromise;
}
});
rs.cancel().then(test4.step_func(function(value) {
assert_equals(sourceCancelPromiseHasFulfilled, true, 'cancel() return value should be fulfilled only after the promise returned by the underlying source\'s cancel');
assert_equals(value, undefined, 'cancel() return value should be fulfilled with undefined');
test4.done();
}), test4.step_func(function() { assert_unreached('cancel() return value should not be rejected'); } ));
setTimeout(test4.step_func(function() {
resolveSourceCancelPromise('Hello');
}), 30);
});
var test5 = async_test('ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should reject when that one does');
test5.step(function() {
var rejectSourceCancelPromise;
var sourceCancelPromiseHasRejected = false;
var rs = new ReadableStream({
cancel: function() {
var sourceCancelPromise = new Promise(test5.step_func(function(resolve, reject) {
rejectSourceCancelPromise = reject;
}));
sourceCancelPromise.catch(test5.step_func(function() {
sourceCancelPromiseHasRejected = true;
}));
return sourceCancelPromise;
}
});
var errorInCancel = new Error('Sorry, it just wasn\'t meant to be.');
rs.cancel().then(
test5.step_func(function() { assert_function('cancel() return value should not be rejected'); }),
test5.step_func(function(r) {
assert_equals(sourceCancelPromiseHasRejected, true, 'cancel() return value should be rejected only after the promise returned by the underlying source\'s cancel');
assert_equals(r, errorInCancel, 'cancel() return value should be rejected with the underlying source\'s rejection reason');
test5.done();
}));
setTimeout(test5.step_func(function() {
rejectSourceCancelPromise(errorInCancel);
}), 30);
});
var test6 = async_test('ReadableStream cancellation: cancelling before start finishes should prevent pull() from being called');
test6.step(function() {
var rs = new ReadableStream({
pull: function() {
assert_unreached('pull should not have been called');
}
});
Promise.all([rs.cancel(), rs.getReader().closed]).then(test6.step_func(function() {
test6.done('pull should never have been called');
})).catch(test6.step_func(function(e) { assert_reached(e); } ));
});
var test7 = async_test('ReadableStream cancel should fulfill promise when cancel callback went fine');
test7.step(function()
{
var cancelReceived = false;
var cancelReason = "I am tired of this stream, I prefer to cancel it";
var rs = new ReadableStream({
cancel: function(reason) {
cancelReceived = true;
assert_equals(reason, cancelReason);
}
});
rs.cancel(cancelReason).then(
test7.step_func(function() {
assert_true(cancelReceived);
test7.done();
}),
test7.step_func(function(e) {
assert_unreached("received error " + e)
}));
});
var test8 = async_test('ReadableStream cancel should reject promise when cancel callback raises an exception');
test8.step(function()
{
var thrownError = undefined;
var rs = new ReadableStream({
cancel: function(error) {
thrownError = new Error(error);
throw thrownError;
}
});
rs.cancel("test").then(
test8.step_func(function() {
assert_unreached("cancel should fail")
}),
test8.step_func(function(e) {
assert_not_equals(thrownError, undefined);
assert_equals(e, thrownError);
test8.done();
})
);
});
var test9 = async_test('ReadableStream cancel should fulfill promise when cancel callback went fine after returning a promise');
test9.step(function()
{
var cancelReason = "test";
var rs = new ReadableStream({
cancel: function(error) {
assert_equals(error, cancelReason);
return new Promise(test9.step_func(function(resolve, reject) {
setTimeout(test9.step_func(function() {
resolve();
}), 50);
}))
}
})
rs.cancel(cancelReason).then(
test9.step_func(function() {
test9.done();
}),
test9.step_func(function(e) {
assert_unreached("received error " + e)
}))
});
</script>