OLD | NEW |
1 'use strict'; | 1 'use strict'; |
2 | 2 |
3 if (self.importScripts) { | 3 if (self.importScripts) { |
4 self.importScripts('/resources/testharness.js'); | 4 self.importScripts('/resources/testharness.js'); |
5 self.importScripts('../resources/test-utils.js'); | 5 self.importScripts('../resources/test-utils.js'); |
6 self.importScripts('../resources/recording-streams.js'); | 6 self.importScripts('../resources/recording-streams.js'); |
7 } | 7 } |
8 | 8 |
9 const error1 = new Error('error1'); | 9 const error1 = new Error('error1'); |
10 error1.name = 'error1'; | 10 error1.name = 'error1'; |
11 | 11 |
| 12 const error2 = new Error('error2'); |
| 13 error2.name = 'error2'; |
| 14 |
12 promise_test(t => { | 15 promise_test(t => { |
13 const ws = new WritableStream({ | 16 const ws = new WritableStream({ |
14 write() { | 17 write() { |
15 return new Promise(() => { }); // forever-pending, so normally .ready woul
d not fulfill. | 18 return new Promise(() => { }); // forever-pending, so normally .ready woul
d not fulfill. |
16 } | 19 } |
17 }); | 20 }); |
18 | 21 |
19 const writer = ws.getWriter(); | 22 const writer = ws.getWriter(); |
20 writer.write('a'); | 23 const writePromise = writer.write('a'); |
21 | 24 |
22 const readyPromise = writer.ready; | 25 const readyPromise = writer.ready; |
23 | 26 |
24 writer.abort(error1); | 27 writer.abort(error1); |
25 | 28 |
26 assert_equals(writer.ready, readyPromise, 'the ready promise property should n
ot change'); | 29 assert_equals(writer.ready, readyPromise, 'the ready promise property should n
ot change'); |
27 | 30 |
28 return promise_rejects(t, new TypeError(), readyPromise, 'the ready promise sh
ould reject with a TypeError'); | 31 return Promise.all([ |
| 32 promise_rejects(t, new TypeError(), readyPromise, 'the ready promise should
reject with a TypeError'), |
| 33 promise_rejects(t, new TypeError(), writePromise, 'the write() promise shoul
d reject with a TypeError') |
| 34 ]); |
29 }, 'Aborting a WritableStream should cause the writer\'s unsettled ready promise
to reject'); | 35 }, 'Aborting a WritableStream should cause the writer\'s unsettled ready promise
to reject'); |
30 | 36 |
31 promise_test(t => { | 37 promise_test(t => { |
32 const ws = new WritableStream(); | 38 const ws = new WritableStream(); |
33 | 39 |
34 const writer = ws.getWriter(); | 40 const writer = ws.getWriter(); |
35 writer.write('a'); | 41 writer.write('a'); |
36 | 42 |
37 const readyPromise = writer.ready; | 43 const readyPromise = writer.ready; |
38 | 44 |
39 return readyPromise.then(() => { | 45 return readyPromise.then(() => { |
40 writer.abort(error1); | 46 writer.abort(error1); |
41 | 47 |
42 assert_not_equals(writer.ready, readyPromise, 'the ready promise property sh
ould change'); | 48 assert_not_equals(writer.ready, readyPromise, 'the ready promise property sh
ould change'); |
43 return promise_rejects(t, new TypeError(), writer.ready, 'the ready promise
should reject with a TypeError'); | 49 return promise_rejects(t, new TypeError(), writer.ready, 'the ready promise
should reject with a TypeError'); |
44 }); | 50 }); |
45 }, 'Aborting a WritableStream should cause the writer\'s fulfilled ready promise
to reset to a rejected one'); | 51 }, 'Aborting a WritableStream should cause the writer\'s fulfilled ready promise
to reset to a rejected one'); |
46 | 52 |
47 promise_test(t => { | 53 promise_test(t => { |
48 const ws = new WritableStream(); | 54 const ws = new WritableStream(); |
49 const writer = ws.getWriter(); | 55 const writer = ws.getWriter(); |
50 | 56 |
51 writer.releaseLock(); | 57 writer.releaseLock(); |
52 | 58 |
53 return promise_rejects(t, new TypeError(), writer.abort(), 'abort() should rej
ect with a TypeError'); | 59 return promise_rejects(t, new TypeError(), writer.abort(), 'abort() should rej
ect with a TypeError'); |
54 }, 'abort() on a released writer rejects'); | 60 }, 'abort() on a released writer rejects'); |
55 | 61 |
56 promise_test(() => { | 62 promise_test(t => { |
57 const ws = recordingWritableStream(); | 63 const ws = recordingWritableStream(); |
58 | 64 |
59 return delay(0) | 65 return delay(0) |
60 .then(() => { | 66 .then(() => { |
61 const writer = ws.getWriter(); | 67 const writer = ws.getWriter(); |
62 | 68 |
63 writer.abort(); | 69 writer.abort(); |
64 writer.write(1); | 70 |
65 writer.write(2); | 71 return Promise.all([ |
| 72 promise_rejects(t, new TypeError(), writer.write(1), 'write(1) must reje
ct with a TypeError'), |
| 73 promise_rejects(t, new TypeError(), writer.write(2), 'write(2) must reje
ct with a TypeError') |
| 74 ]); |
66 }) | 75 }) |
67 .then(() => { | 76 .then(() => { |
68 assert_array_equals(ws.events, ['abort', undefined]); | 77 assert_array_equals(ws.events, ['abort', undefined]); |
69 }); | 78 }); |
70 }, 'Aborting a WritableStream immediately prevents future writes'); | 79 }, 'Aborting a WritableStream immediately prevents future writes'); |
71 | 80 |
72 promise_test(() => { | 81 promise_test(t => { |
73 const ws = recordingWritableStream(); | 82 const ws = recordingWritableStream(); |
| 83 const results = []; |
74 | 84 |
75 return delay(0) | 85 return delay(0) |
76 .then(() => { | 86 .then(() => { |
77 const writer = ws.getWriter(); | 87 const writer = ws.getWriter(); |
78 | 88 |
79 writer.write(1); | 89 results.push( |
80 writer.write(2); | 90 writer.write(1), |
81 writer.write(3); | 91 promise_rejects(t, new TypeError(), writer.write(2), 'write(2) must reje
ct with a TypeError'), |
82 writer.abort(); | 92 promise_rejects(t, new TypeError(), writer.write(3), 'write(3) must reje
ct with a TypeError') |
83 writer.write(4); | 93 ); |
84 writer.write(5); | 94 |
| 95 const abortPromise = writer.abort(); |
| 96 |
| 97 results.push( |
| 98 promise_rejects(t, new TypeError(), writer.write(4), 'write(4) must reje
ct with a TypeError'), |
| 99 promise_rejects(t, new TypeError(), writer.write(5), 'write(5) must reje
ct with a TypeError') |
| 100 ); |
| 101 |
| 102 return abortPromise; |
85 }).then(() => { | 103 }).then(() => { |
86 assert_array_equals(ws.events, ['write', 1, 'abort', undefined]); | 104 assert_array_equals(ws.events, ['write', 1, 'abort', undefined]); |
| 105 |
| 106 return Promise.all(results); |
87 }); | 107 }); |
88 }, 'Aborting a WritableStream prevents further writes after any that are in prog
ress'); | 108 }, 'Aborting a WritableStream prevents further writes after any that are in prog
ress'); |
89 | 109 |
90 promise_test(() => { | 110 promise_test(() => { |
91 const ws = new WritableStream({ | 111 const ws = new WritableStream({ |
92 abort() { | 112 abort() { |
93 return 'Hello'; | 113 return 'Hello'; |
94 } | 114 } |
95 }); | 115 }); |
96 const writer = ws.getWriter(); | 116 const writer = ws.getWriter(); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 | 175 |
156 writer.abort(error1); | 176 writer.abort(error1); |
157 | 177 |
158 return writePromise; | 178 return writePromise; |
159 }, 'Aborting a WritableStream causes any outstanding write() promises to be reje
cted with a TypeError'); | 179 }, 'Aborting a WritableStream causes any outstanding write() promises to be reje
cted with a TypeError'); |
160 | 180 |
161 promise_test(t => { | 181 promise_test(t => { |
162 const ws = new WritableStream(); | 182 const ws = new WritableStream(); |
163 const writer = ws.getWriter(); | 183 const writer = ws.getWriter(); |
164 | 184 |
165 writer.close(); | 185 const closePromise = writer.close(); |
166 writer.abort(error1); | 186 writer.abort(error1); |
167 | 187 |
168 return promise_rejects(t, new TypeError(), writer.closed, 'closed should rejec
t with a TypeError'); | 188 return Promise.all([ |
| 189 promise_rejects(t, new TypeError(), writer.closed, 'closed should reject wit
h a TypeError'), |
| 190 promise_rejects(t, new TypeError(), closePromise, 'close() should reject wit
h a TypeError') |
| 191 ]); |
169 }, 'Closing but then immediately aborting a WritableStream causes the stream to
error'); | 192 }, 'Closing but then immediately aborting a WritableStream causes the stream to
error'); |
170 | 193 |
171 promise_test(t => { | 194 promise_test(t => { |
| 195 let resolveClose; |
172 const ws = new WritableStream({ | 196 const ws = new WritableStream({ |
173 close() { | 197 close() { |
174 return new Promise(() => { }); // forever-pending | 198 return new Promise(resolve => { |
| 199 resolveClose = resolve; |
| 200 }); |
175 } | 201 } |
176 }); | 202 }); |
177 const writer = ws.getWriter(); | 203 const writer = ws.getWriter(); |
178 | 204 |
179 writer.close(); | 205 const closePromise = writer.close(); |
180 | 206 |
181 return delay(0).then(() => { | 207 return delay(0).then(() => { |
182 writer.abort(error1); | 208 writer.abort(error1); |
183 }) | 209 resolveClose(); |
184 .then(() => promise_rejects(t, new TypeError(), writer.closed, 'closed should
reject with a TypeError')); | 210 return Promise.all([ |
| 211 promise_rejects(t, new TypeError(), writer.closed, 'closed should reject w
ith a TypeError'), |
| 212 closePromise |
| 213 ]); |
| 214 }); |
185 }, 'Closing a WritableStream and aborting it while it closes causes the stream t
o error'); | 215 }, 'Closing a WritableStream and aborting it while it closes causes the stream t
o error'); |
186 | 216 |
187 promise_test(() => { | 217 promise_test(() => { |
188 const ws = new WritableStream(); | 218 const ws = new WritableStream(); |
189 const writer = ws.getWriter(); | 219 const writer = ws.getWriter(); |
190 | 220 |
191 writer.close(); | 221 writer.close(); |
192 | 222 |
193 return delay(0).then(() => writer.abort()); | 223 return delay(0).then(() => writer.abort()); |
194 }, 'Aborting a WritableStream after it is closed is a no-op'); | 224 }, 'Aborting a WritableStream after it is closed is a no-op'); |
195 | 225 |
196 test(() => { | 226 promise_test(t => { |
197 const ws = recordingWritableStream(); | 227 // Cannot use recordingWritableStream since it always has an abort |
| 228 let controller; |
| 229 let closeArgs; |
| 230 const ws = new WritableStream({ |
| 231 start(c) { |
| 232 controller = c; |
| 233 }, |
| 234 close(...args) { |
| 235 closeArgs = args; |
| 236 } |
| 237 }); |
| 238 |
198 const writer = ws.getWriter(); | 239 const writer = ws.getWriter(); |
199 | 240 |
200 writer.abort(); | 241 writer.abort(); |
201 | 242 |
202 return writer.closed.then(() => { | 243 return promise_rejects(t, new TypeError(), writer.closed, 'closed should rejec
t with a TypeError').then(() => { |
203 assert_array_equals(ws.events, ['close']); | 244 assert_array_equals(closeArgs, [controller], 'close must have been called, w
ith the controller as its argument'); |
204 }); | 245 }); |
205 }, 'WritableStream should call underlying sink\'s close if no abort is supplied'
); | 246 }, 'WritableStream should call underlying sink\'s close if no abort is supplied'
); |
206 | 247 |
207 promise_test(() => { | 248 promise_test(() => { |
208 let thenCalled = false; | 249 let thenCalled = false; |
209 const ws = new WritableStream({ | 250 const ws = new WritableStream({ |
210 abort() { | 251 abort() { |
211 return { | 252 return { |
212 then(onFulfilled) { | 253 then(onFulfilled) { |
213 thenCalled = true; | 254 thenCalled = true; |
214 onFulfilled(); | 255 onFulfilled(); |
215 } | 256 } |
216 }; | 257 }; |
217 } | 258 } |
218 }); | 259 }); |
219 const writer = ws.getWriter(); | 260 const writer = ws.getWriter(); |
220 return writer.abort().then(() => assert_true(thenCalled, 'then() should be cal
led')); | 261 return writer.abort().then(() => assert_true(thenCalled, 'then() should be cal
led')); |
221 }, 'returning a thenable from abort() should work'); | 262 }, 'returning a thenable from abort() should work'); |
222 | 263 |
| 264 promise_test(t => { |
| 265 const ws = new WritableStream({ |
| 266 write() { |
| 267 return flushAsyncEvents(); |
| 268 } |
| 269 }); |
| 270 const writer = ws.getWriter(); |
| 271 return writer.ready.then(() => { |
| 272 const writePromise = writer.write('a'); |
| 273 writer.abort(error1); |
| 274 let closedResolved = false; |
| 275 return Promise.all([ |
| 276 writePromise.then(() => assert_false(closedResolved, '.closed should not r
esolve before write()')), |
| 277 promise_rejects(t, new TypeError(), writer.closed, '.closed should reject'
).then(() => { |
| 278 closedResolved = true; |
| 279 }) |
| 280 ]); |
| 281 }); |
| 282 }, '.closed should not resolve before fulfilled write()'); |
| 283 |
| 284 promise_test(t => { |
| 285 const ws = new WritableStream({ |
| 286 write() { |
| 287 return Promise.reject(error1); |
| 288 } |
| 289 }); |
| 290 const writer = ws.getWriter(); |
| 291 return writer.ready.then(() => { |
| 292 const writePromise = writer.write('a'); |
| 293 const abortPromise = writer.abort(error2); |
| 294 let closedResolved = false; |
| 295 return Promise.all([ |
| 296 promise_rejects(t, error1, writePromise, 'write() should reject') |
| 297 .then(() => assert_false(closedResolved, '.closed should not resolve b
efore write()')), |
| 298 promise_rejects(t, error1, writer.closed, '.closed should reject') |
| 299 .then(() => { |
| 300 closedResolved = true; |
| 301 }), |
| 302 promise_rejects(t, error1, abortPromise, 'abort() should reject')]); |
| 303 }); |
| 304 }, '.closed should not resolve before rejected write(); write() error should ove
rwrite abort() error'); |
| 305 |
| 306 promise_test(t => { |
| 307 const ws = new WritableStream({ |
| 308 write() { |
| 309 return flushAsyncEvents(); |
| 310 } |
| 311 }, new CountQueuingStrategy(4)); |
| 312 const writer = ws.getWriter(); |
| 313 return writer.ready.then(() => { |
| 314 const settlementOrder = []; |
| 315 return Promise.all([ |
| 316 writer.write('1').then(() => settlementOrder.push(1)), |
| 317 promise_rejects(t, new TypeError(), writer.write('2'), 'first queued write
should be rejected') |
| 318 .then(() => settlementOrder.push(2)), |
| 319 promise_rejects(t, new TypeError(), writer.write('3'), 'second queued writ
e should be rejected') |
| 320 .then(() => settlementOrder.push(3)), |
| 321 writer.abort(error1) |
| 322 ]).then(() => assert_array_equals([1, 2, 3], settlementOrder, 'writes should
be satisfied in order')); |
| 323 }); |
| 324 }, 'writes should be satisfied in order when aborting'); |
| 325 |
| 326 promise_test(t => { |
| 327 const ws = new WritableStream({ |
| 328 write() { |
| 329 return Promise.reject(error1); |
| 330 } |
| 331 }, new CountQueuingStrategy(4)); |
| 332 const writer = ws.getWriter(); |
| 333 return writer.ready.then(() => { |
| 334 const settlementOrder = []; |
| 335 return Promise.all([ |
| 336 promise_rejects(t, error1, writer.write('1'), 'pending write should be rej
ected') |
| 337 .then(() => settlementOrder.push(1)), |
| 338 promise_rejects(t, error1, writer.write('2'), 'first queued write should b
e rejected') |
| 339 .then(() => settlementOrder.push(2)), |
| 340 promise_rejects(t, error1, writer.write('3'), 'second queued write should
be rejected') |
| 341 .then(() => settlementOrder.push(3)), |
| 342 promise_rejects(t, error1, writer.abort(error1), 'abort should be rejected
') |
| 343 ]).then(() => assert_array_equals([1, 2, 3], settlementOrder, 'writes should
be satisfied in order')); |
| 344 }); |
| 345 }, 'writes should be satisfied in order after rejected write when aborting'); |
| 346 |
| 347 promise_test(t => { |
| 348 const ws = new WritableStream({ |
| 349 write() { |
| 350 return Promise.reject(error1); |
| 351 } |
| 352 }); |
| 353 const writer = ws.getWriter(); |
| 354 return writer.ready.then(() => { |
| 355 return Promise.all([ |
| 356 promise_rejects(t, error1, writer.write('a'), 'writer.write() should rejec
t with error from underlying write()'), |
| 357 promise_rejects(t, error1, writer.close(), 'writer.close() should reject w
ith error from underlying write()'), |
| 358 promise_rejects(t, error1, writer.abort(), 'writer.abort() should reject w
ith error from underlying write()') |
| 359 ]); |
| 360 }); |
| 361 }, 'close() should use error from underlying write() on abort'); |
| 362 |
| 363 promise_test(() => { |
| 364 let resolveWrite; |
| 365 let abort_called = false; |
| 366 const ws = new WritableStream({ |
| 367 write() { |
| 368 return new Promise(resolve => { |
| 369 resolveWrite = resolve; |
| 370 }); |
| 371 }, |
| 372 abort() { |
| 373 abort_called = true; |
| 374 } |
| 375 }); |
| 376 |
| 377 const writer = ws.getWriter(); |
| 378 return writer.ready.then(() => { |
| 379 writer.write('a'); |
| 380 const abortPromise = writer.abort(); |
| 381 return flushAsyncEvents().then(() => { |
| 382 assert_false(abort_called, 'abort should not be called while write is pend
ing'); |
| 383 resolveWrite(); |
| 384 return abortPromise.then(() => assert_true(abort_called, 'abort should be
called')); |
| 385 }); |
| 386 }); |
| 387 }, 'underlying abort() should not be called until underlying write() completes')
; |
| 388 |
| 389 promise_test(() => { |
| 390 let resolveClose; |
| 391 let abort_called = false; |
| 392 const ws = new WritableStream({ |
| 393 close() { |
| 394 return new Promise(resolve => { |
| 395 resolveClose = resolve; |
| 396 }); |
| 397 }, |
| 398 abort() { |
| 399 abort_called = true; |
| 400 } |
| 401 }); |
| 402 |
| 403 const writer = ws.getWriter(); |
| 404 return writer.ready.then(() => { |
| 405 writer.close(); |
| 406 const abortPromise = writer.abort(); |
| 407 return flushAsyncEvents().then(() => { |
| 408 assert_false(abort_called, 'abort should not be called while close is pend
ing'); |
| 409 resolveClose(); |
| 410 return abortPromise.then(() => assert_false(abort_called, 'abort should no
t be called after close completes')); |
| 411 }); |
| 412 }); |
| 413 }, 'underlying abort() should not be called if underlying close() has started'); |
| 414 |
| 415 promise_test(t => { |
| 416 let resolveWrite; |
| 417 let abort_called = false; |
| 418 const ws = new WritableStream({ |
| 419 write() { |
| 420 return new Promise(resolve => { |
| 421 resolveWrite = resolve; |
| 422 }); |
| 423 }, |
| 424 abort() { |
| 425 abort_called = true; |
| 426 } |
| 427 }); |
| 428 |
| 429 const writer = ws.getWriter(); |
| 430 return writer.ready.then(() => { |
| 431 writer.write('a'); |
| 432 const closePromise = writer.close(); |
| 433 const abortPromise = writer.abort(); |
| 434 return flushAsyncEvents().then(() => { |
| 435 assert_false(abort_called, 'abort should not be called while write is pend
ing'); |
| 436 resolveWrite(); |
| 437 return abortPromise.then(() => { |
| 438 assert_true(abort_called, 'abort should be called after write completes'
); |
| 439 return promise_rejects(t, new TypeError(), closePromise, 'promise return
ed by close() should be rejected'); |
| 440 }); |
| 441 }); |
| 442 }); |
| 443 }, 'underlying abort() should be called while closing if underlying close() has
not started yet'); |
| 444 |
| 445 promise_test(() => { |
| 446 const ws = new WritableStream(); |
| 447 const writer = ws.getWriter(); |
| 448 return writer.ready.then(() => { |
| 449 const closePromise = writer.close(); |
| 450 const abortPromise = writer.abort(); |
| 451 let closeResolved = false; |
| 452 Promise.all([ |
| 453 closePromise.then(() => { closeResolved = true; }), |
| 454 abortPromise.then(() => { assert_true(closeResolved, 'close() promise shou
ld resolve before abort() promise'); }) |
| 455 ]); |
| 456 }); |
| 457 }, 'writer close() promise should resolve before abort() promise'); |
| 458 |
| 459 promise_test(t => { |
| 460 const ws = new WritableStream({ |
| 461 write(chunk, controller) { |
| 462 controller.error(error1); |
| 463 return new Promise(() => {}); |
| 464 } |
| 465 }); |
| 466 const writer = ws.getWriter(); |
| 467 return writer.ready.then(() => { |
| 468 writer.write('a'); |
| 469 return promise_rejects(t, error1, writer.ready, 'writer.ready should reject'
); |
| 470 }); |
| 471 }, 'writer.ready should reject on controller error without waiting for underlyin
g write'); |
| 472 |
| 473 promise_test(t => { |
| 474 let resolveWrite; |
| 475 const ws = new WritableStream({ |
| 476 write() { |
| 477 return new Promise(resolve => { |
| 478 resolveWrite = resolve; |
| 479 }); |
| 480 } |
| 481 }); |
| 482 const writer = ws.getWriter(); |
| 483 return writer.ready.then(() => { |
| 484 const writePromise = writer.write('a'); |
| 485 const closed = writer.closed; |
| 486 const abortPromise = writer.abort(); |
| 487 writer.releaseLock(); |
| 488 resolveWrite(); |
| 489 return Promise.all([ |
| 490 writePromise, |
| 491 abortPromise, |
| 492 promise_rejects(t, new TypeError(), closed, 'closed should reject')]); |
| 493 }); |
| 494 }, 'releaseLock() while aborting should reject the original closed promise'); |
| 495 |
| 496 promise_test(t => { |
| 497 let resolveWrite; |
| 498 let resolveAbort; |
| 499 let resolveAbortStarted; |
| 500 const abortStarted = new Promise(resolve => { |
| 501 resolveAbortStarted = resolve; |
| 502 }); |
| 503 const ws = new WritableStream({ |
| 504 write() { |
| 505 return new Promise(resolve => { |
| 506 resolveWrite = resolve; |
| 507 }); |
| 508 }, |
| 509 abort() { |
| 510 resolveAbortStarted(); |
| 511 return new Promise(resolve => { |
| 512 resolveAbort = resolve; |
| 513 }); |
| 514 } |
| 515 }); |
| 516 const writer = ws.getWriter(); |
| 517 return writer.ready.then(() => { |
| 518 const writePromise = writer.write('a'); |
| 519 const closed = writer.closed; |
| 520 const abortPromise = writer.abort(); |
| 521 resolveWrite(); |
| 522 return abortStarted.then(() => { |
| 523 writer.releaseLock(); |
| 524 assert_not_equals(writer.closed, closed, 'closed promise should have chang
ed'); |
| 525 resolveAbort(); |
| 526 return Promise.all([ |
| 527 writePromise, |
| 528 abortPromise, |
| 529 promise_rejects(t, new TypeError(), closed, 'original closed should reje
ct'), |
| 530 promise_rejects(t, new TypeError(), writer.closed, 'new closed should re
ject')]); |
| 531 }); |
| 532 }); |
| 533 }, 'releaseLock() during delayed async abort() should create a new rejected clos
ed promise'); |
| 534 |
223 done(); | 535 done(); |
OLD | NEW |