cancel.any.js (7793B)
1 // META: global=window,worker,shadowrealm 2 // META: script=../resources/test-utils.js 3 'use strict'; 4 5 const thrownError = new Error('bad things are happening!'); 6 thrownError.name = 'error1'; 7 8 const originalReason = new Error('original reason'); 9 originalReason.name = 'error2'; 10 11 promise_test(async t => { 12 let cancelled = undefined; 13 const ts = new TransformStream({ 14 cancel(reason) { 15 cancelled = reason; 16 } 17 }); 18 const res = await ts.readable.cancel(thrownError); 19 assert_equals(res, undefined, 'readable.cancel() should return undefined'); 20 assert_equals(cancelled, thrownError, 'transformer.cancel() should be called with the passed reason'); 21 }, 'cancelling the readable side should call transformer.cancel()'); 22 23 promise_test(async t => { 24 const ts = new TransformStream({ 25 cancel(reason) { 26 assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); 27 throw thrownError; 28 } 29 }); 30 const writer = ts.writable.getWriter(); 31 const cancelPromise = ts.readable.cancel(originalReason); 32 await promise_rejects_exactly(t, thrownError, cancelPromise, 'readable.cancel() should reject with thrownError'); 33 await promise_rejects_exactly(t, thrownError, writer.closed, 'writer.closed should reject with thrownError'); 34 }, 'cancelling the readable side should reject if transformer.cancel() throws'); 35 36 promise_test(async t => { 37 let aborted = undefined; 38 const ts = new TransformStream({ 39 cancel(reason) { 40 aborted = reason; 41 }, 42 flush: t.unreached_func('flush should not be called') 43 }); 44 const res = await ts.writable.abort(thrownError); 45 assert_equals(res, undefined, 'writable.abort() should return undefined'); 46 assert_equals(aborted, thrownError, 'transformer.abort() should be called with the passed reason'); 47 }, 'aborting the writable side should call transformer.abort()'); 48 49 promise_test(async t => { 50 const ts = new TransformStream({ 51 cancel(reason) { 52 assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); 53 throw thrownError; 54 }, 55 flush: t.unreached_func('flush should not be called') 56 }); 57 const reader = ts.readable.getReader(); 58 const abortPromise = ts.writable.abort(originalReason); 59 await promise_rejects_exactly(t, thrownError, abortPromise, 'writable.abort() should reject with thrownError'); 60 await promise_rejects_exactly(t, thrownError, reader.closed, 'reader.closed should reject with thrownError'); 61 }, 'aborting the writable side should reject if transformer.cancel() throws'); 62 63 promise_test(async t => { 64 const ts = new TransformStream({ 65 async cancel(reason) { 66 assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); 67 throw thrownError; 68 }, 69 flush: t.unreached_func('flush should not be called') 70 }); 71 const cancelPromise = ts.readable.cancel(originalReason); 72 const closePromise = ts.writable.close(); 73 await Promise.all([ 74 promise_rejects_exactly(t, thrownError, cancelPromise, 'cancelPromise should reject with thrownError'), 75 promise_rejects_exactly(t, thrownError, closePromise, 'closePromise should reject with thrownError'), 76 ]); 77 }, 'closing the writable side should reject if a parallel transformer.cancel() throws'); 78 79 promise_test(async t => { 80 let controller; 81 const ts = new TransformStream({ 82 start(c) { 83 controller = c; 84 }, 85 async cancel(reason) { 86 assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); 87 controller.error(thrownError); 88 }, 89 flush: t.unreached_func('flush should not be called') 90 }); 91 const cancelPromise = ts.readable.cancel(originalReason); 92 const closePromise = ts.writable.close(); 93 await Promise.all([ 94 promise_rejects_exactly(t, thrownError, cancelPromise, 'cancelPromise should reject with thrownError'), 95 promise_rejects_exactly(t, thrownError, closePromise, 'closePromise should reject with thrownError'), 96 ]); 97 }, 'readable.cancel() and a parallel writable.close() should reject if a transformer.cancel() calls controller.error()'); 98 99 promise_test(async t => { 100 let controller; 101 const ts = new TransformStream({ 102 start(c) { 103 controller = c; 104 }, 105 async cancel(reason) { 106 assert_equals(reason, originalReason, 'transformer.cancel() should be called with the passed reason'); 107 controller.error(thrownError); 108 }, 109 flush: t.unreached_func('flush should not be called') 110 }); 111 const cancelPromise = ts.writable.abort(originalReason); 112 await promise_rejects_exactly(t, thrownError, cancelPromise, 'cancelPromise should reject with thrownError'); 113 const closePromise = ts.readable.cancel(1); 114 await promise_rejects_exactly(t, thrownError, closePromise, 'closePromise should reject with thrownError'); 115 }, 'writable.abort() and readable.cancel() should reject if a transformer.cancel() calls controller.error()'); 116 117 promise_test(async t => { 118 const cancelReason = new Error('cancel reason'); 119 let controller; 120 let cancelPromise; 121 let flushCalled = false; 122 const ts = new TransformStream({ 123 start(c) { 124 controller = c; 125 }, 126 flush() { 127 flushCalled = true; 128 cancelPromise = ts.readable.cancel(cancelReason); 129 }, 130 cancel: t.unreached_func('cancel should not be called') 131 }); 132 await flushAsyncEvents(); // ensure stream is started 133 await ts.writable.close(); 134 assert_true(flushCalled, 'flush() was called'); 135 await cancelPromise; 136 }, 'readable.cancel() should not call cancel() when flush() is already called from writable.close()'); 137 138 promise_test(async t => { 139 const cancelReason = new Error('cancel reason'); 140 const abortReason = new Error('abort reason'); 141 let cancelCalls = 0; 142 let controller; 143 let cancelPromise; 144 const ts = new TransformStream({ 145 start(c) { 146 controller = c; 147 }, 148 cancel() { 149 if (++cancelCalls === 1) { 150 cancelPromise = ts.readable.cancel(cancelReason); 151 } 152 }, 153 flush: t.unreached_func('flush should not be called') 154 }); 155 await flushAsyncEvents(); // ensure stream is started 156 await ts.writable.abort(abortReason); 157 assert_equals(cancelCalls, 1); 158 await cancelPromise; 159 assert_equals(cancelCalls, 1); 160 }, 'readable.cancel() should not call cancel() again when already called from writable.abort()'); 161 162 promise_test(async t => { 163 const cancelReason = new Error('cancel reason'); 164 let controller; 165 let closePromise; 166 let cancelCalled = false; 167 const ts = new TransformStream({ 168 start(c) { 169 controller = c; 170 }, 171 cancel() { 172 cancelCalled = true; 173 closePromise = ts.writable.close(); 174 }, 175 flush: t.unreached_func('flush should not be called') 176 }); 177 await flushAsyncEvents(); // ensure stream is started 178 await ts.readable.cancel(cancelReason); 179 assert_true(cancelCalled, 'cancel() was called'); 180 await closePromise; 181 }, 'writable.close() should not call flush() when cancel() is already called from readable.cancel()'); 182 183 promise_test(async t => { 184 const cancelReason = new Error('cancel reason'); 185 const abortReason = new Error('abort reason'); 186 let cancelCalls = 0; 187 let controller; 188 let abortPromise; 189 const ts = new TransformStream({ 190 start(c) { 191 controller = c; 192 }, 193 cancel() { 194 if (++cancelCalls === 1) { 195 abortPromise = ts.writable.abort(abortReason); 196 } 197 }, 198 flush: t.unreached_func('flush should not be called') 199 }); 200 await flushAsyncEvents(); // ensure stream is started 201 await promise_rejects_exactly(t, abortReason, ts.readable.cancel(cancelReason)); 202 assert_equals(cancelCalls, 1); 203 await promise_rejects_exactly(t, abortReason, abortPromise); 204 assert_equals(cancelCalls, 1); 205 }, 'writable.abort() should not call cancel() again when already called from readable.cancel()');