| // META: global=window,worker,shadowrealm |
| // META: script=../resources/test-utils.js |
| 'use strict'; |
| |
| const thrownError = new Error('bad things are happening!'); |
| thrownError.name = 'error1'; |
| |
| const originalReason = new Error('original reason'); |
| originalReason.name = 'error2'; |
| |
| promise_test(async t => { |
| let cancelled = undefined; |
| const ts = new TransformStream({ |
| cancel(reason) { |
| cancelled = reason; |
| } |
| }); |
| const res = await ts.readable.cancel(thrownError); |
| assert_equals(res, undefined, 'readable.cancel() should return undefined'); |
| assert_equals(cancelled, thrownError, 'transformer.cancel() should be called with the passed reason'); |
| }, 'cancelling the readable side should call transformer.cancel()'); |
| |
| promise_test(async t => { |
| const ts = new TransformStream({ |
| cancel(reason) { |
| assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); |
| throw thrownError; |
| } |
| }); |
| const writer = ts.writable.getWriter(); |
| const cancelPromise = ts.readable.cancel(originalReason); |
| await promise_rejects_exactly(t, thrownError, cancelPromise, 'readable.cancel() should reject with thrownError'); |
| await promise_rejects_exactly(t, thrownError, writer.closed, 'writer.closed should reject with thrownError'); |
| }, 'cancelling the readable side should reject if transformer.cancel() throws'); |
| |
| promise_test(async t => { |
| let aborted = undefined; |
| const ts = new TransformStream({ |
| cancel(reason) { |
| aborted = reason; |
| }, |
| flush: t.unreached_func('flush should not be called') |
| }); |
| const res = await ts.writable.abort(thrownError); |
| assert_equals(res, undefined, 'writable.abort() should return undefined'); |
| assert_equals(aborted, thrownError, 'transformer.abort() should be called with the passed reason'); |
| }, 'aborting the writable side should call transformer.abort()'); |
| |
| promise_test(async t => { |
| const ts = new TransformStream({ |
| cancel(reason) { |
| assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); |
| throw thrownError; |
| }, |
| flush: t.unreached_func('flush should not be called') |
| }); |
| const reader = ts.readable.getReader(); |
| const abortPromise = ts.writable.abort(originalReason); |
| await promise_rejects_exactly(t, thrownError, abortPromise, 'writable.abort() should reject with thrownError'); |
| await promise_rejects_exactly(t, thrownError, reader.closed, 'reader.closed should reject with thrownError'); |
| }, 'aborting the writable side should reject if transformer.cancel() throws'); |
| |
| promise_test(async t => { |
| const ts = new TransformStream({ |
| async cancel(reason) { |
| assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); |
| throw thrownError; |
| }, |
| flush: t.unreached_func('flush should not be called') |
| }); |
| const cancelPromise = ts.readable.cancel(originalReason); |
| const closePromise = ts.writable.close(); |
| await Promise.all([ |
| promise_rejects_exactly(t, thrownError, cancelPromise, 'cancelPromise should reject with thrownError'), |
| promise_rejects_exactly(t, thrownError, closePromise, 'closePromise should reject with thrownError'), |
| ]); |
| }, 'closing the writable side should reject if a parallel transformer.cancel() throws'); |
| |
| promise_test(async t => { |
| let controller; |
| const ts = new TransformStream({ |
| start(c) { |
| controller = c; |
| }, |
| async cancel(reason) { |
| assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); |
| controller.error(thrownError); |
| }, |
| flush: t.unreached_func('flush should not be called') |
| }); |
| const cancelPromise = ts.readable.cancel(originalReason); |
| const closePromise = ts.writable.close(); |
| await Promise.all([ |
| promise_rejects_exactly(t, thrownError, cancelPromise, 'cancelPromise should reject with thrownError'), |
| promise_rejects_exactly(t, thrownError, closePromise, 'closePromise should reject with thrownError'), |
| ]); |
| }, 'readable.cancel() and a parallel writable.close() should reject if a transformer.cancel() calls controller.error()'); |
| |
| promise_test(async t => { |
| let controller; |
| const ts = new TransformStream({ |
| start(c) { |
| controller = c; |
| }, |
| async cancel(reason) { |
| assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); |
| controller.error(thrownError); |
| }, |
| flush: t.unreached_func('flush should not be called') |
| }); |
| const cancelPromise = ts.writable.abort(originalReason); |
| await promise_rejects_exactly(t, thrownError, cancelPromise, 'cancelPromise should reject with thrownError'); |
| const closePromise = ts.readable.cancel(1); |
| await promise_rejects_exactly(t, thrownError, closePromise, 'closePromise should reject with thrownError'); |
| }, 'writable.abort() and readable.cancel() should reject if a transformer.cancel() calls controller.error()'); |
| |
| promise_test(async t => { |
| const cancelReason = new Error('cancel reason'); |
| let controller; |
| let cancelPromise; |
| let flushCalled = false; |
| const ts = new TransformStream({ |
| start(c) { |
| controller = c; |
| }, |
| flush() { |
| flushCalled = true; |
| cancelPromise = ts.readable.cancel(cancelReason); |
| }, |
| cancel: t.unreached_func('cancel should not be called') |
| }); |
| await flushAsyncEvents(); // ensure stream is started |
| await ts.writable.close(); |
| assert_true(flushCalled, 'flush() was called'); |
| await cancelPromise; |
| }, 'readable.cancel() should not call cancel() when flush() is already called from writable.close()'); |
| |
| promise_test(async t => { |
| const cancelReason = new Error('cancel reason'); |
| const abortReason = new Error('abort reason'); |
| let cancelCalls = 0; |
| let controller; |
| let cancelPromise; |
| const ts = new TransformStream({ |
| start(c) { |
| controller = c; |
| }, |
| cancel() { |
| if (++cancelCalls === 1) { |
| cancelPromise = ts.readable.cancel(cancelReason); |
| } |
| }, |
| flush: t.unreached_func('flush should not be called') |
| }); |
| await flushAsyncEvents(); // ensure stream is started |
| await ts.writable.abort(abortReason); |
| assert_equals(cancelCalls, 1); |
| await cancelPromise; |
| assert_equals(cancelCalls, 1); |
| }, 'readable.cancel() should not call cancel() again when already called from writable.abort()'); |
| |
| promise_test(async t => { |
| const cancelReason = new Error('cancel reason'); |
| let controller; |
| let closePromise; |
| let cancelCalled = false; |
| const ts = new TransformStream({ |
| start(c) { |
| controller = c; |
| }, |
| cancel() { |
| cancelCalled = true; |
| closePromise = ts.writable.close(); |
| }, |
| flush: t.unreached_func('flush should not be called') |
| }); |
| await flushAsyncEvents(); // ensure stream is started |
| await ts.readable.cancel(cancelReason); |
| assert_true(cancelCalled, 'cancel() was called'); |
| await closePromise; |
| }, 'writable.close() should not call flush() when cancel() is already called from readable.cancel()'); |
| |
| promise_test(async t => { |
| const cancelReason = new Error('cancel reason'); |
| const abortReason = new Error('abort reason'); |
| let cancelCalls = 0; |
| let controller; |
| let abortPromise; |
| const ts = new TransformStream({ |
| start(c) { |
| controller = c; |
| }, |
| cancel() { |
| if (++cancelCalls === 1) { |
| abortPromise = ts.writable.abort(abortReason); |
| } |
| }, |
| flush: t.unreached_func('flush should not be called') |
| }); |
| await flushAsyncEvents(); // ensure stream is started |
| await promise_rejects_exactly(t, abortReason, ts.readable.cancel(cancelReason)); |
| assert_equals(cancelCalls, 1); |
| await promise_rejects_exactly(t, abortReason, abortPromise); |
| assert_equals(cancelCalls, 1); |
| }, 'writable.abort() should not call cancel() again when already called from readable.cancel()'); |