write.any.js (4411B)
1 // META: script=../../constants.sub.js 2 // META: script=resources/url-constants.js 3 // META: script=/common/gc.js 4 // META: global=window,worker 5 // META: variant=?default 6 // META: variant=?wss 7 // META: variant=?wpt_flags=h2 8 9 'use strict'; 10 11 const GOODBYE_MESSAGE = 'Goodbye'; // Must match echo_exit_wsh.py 12 13 // This message needs to be large enough that writing it cannot complete 14 // synchronously, and to fill up the TCP send buffer and any user agent internal 15 // send buffers so that the user agent has to receive the "Close" frame from the 16 // server before it can complete sending this message. 17 const BIG_MESSAGE_SIZE = 8 * 1024 * 1024; 18 19 // Common setup used by two tests. Sends a "Goodbye" message to tell the server 20 // to close the WebSocket, and immediately afterwards a big message that cannot 21 // be completely sent before the connection closes. Waits for the "Goodbye" 22 // message to be sent and the connection to be closed before returning. `t` is 23 // the test object provided by promse_test. 24 async function sendGoodbyeThenBigMessage(t) { 25 const wss = new WebSocketStream(BASEURL + '/echo_exit'); 26 const { writable } = await wss.opened; 27 const writer = writable.getWriter(); 28 const bigMessage = new Uint8Array(BIG_MESSAGE_SIZE); 29 const goodbyePromise = writer.write(GOODBYE_MESSAGE); 30 const bigMessagePromise = writer.write(bigMessage); 31 await goodbyePromise; 32 // testharness.js doesn't know about WebSocketError yet. 33 await wss.closed.then( 34 t.unreached_func('closed promise should reject'), 35 e => assert_equals( 36 e.constructor, WebSocketError, 37 'a WebSocketError should be thrown')); 38 return { writer, bigMessagePromise }; 39 } 40 41 promise_test(async t => { 42 const { writer, bigMessagePromise } = await sendGoodbyeThenBigMessage(t); 43 await promise_rejects_dom( 44 t, 'InvalidStateError', bigMessagePromise, 45 'write() should reject with an InvalidStateError'); 46 const invalidStateError = await bigMessagePromise.then( 47 t.unreached_func('write() promise should reject'), e => e); 48 await promise_rejects_exactly( 49 t, invalidStateError, writer.write('word'), 50 'stream should be errored with same object'); 51 }, 'a write that was incomplete at close time should reject'); 52 53 promise_test(async t => { 54 const { bigMessagePromise } = await sendGoodbyeThenBigMessage(t); 55 // For some reason 5 is the magic number that causes garbage collection to 56 // really really collect garbage. 57 for (let i = 0; i < 5; ++i) { 58 await garbageCollect(); 59 } 60 await promise_rejects_dom( 61 t, 'InvalidStateError', bigMessagePromise, 62 'write() should reject with an InvalidStateError'); 63 }, 'garbage collection after close with a pending write promise should not ' + 64 'crash'); 65 66 promise_test(async t => { 67 const wss = new WebSocketStream(ECHOURL); 68 const { writable } = await wss.opened; 69 const writer = writable.getWriter(); 70 const cannotStringify = { toString() { return this; } }; 71 await promise_rejects_js( 72 t, TypeError, writer.write(cannotStringify), 'write() should reject'); 73 }, 'writing a value that cannot be stringified should cause a rejection'); 74 75 promise_test(async t => { 76 const wss = new WebSocketStream(ECHOURL); 77 const { writable } = await wss.opened; 78 const writer = writable.getWriter(); 79 const buffer = new ArrayBuffer(1024, { maxByteLength: 65536 }); 80 await promise_rejects_js( 81 t, TypeError, writer.write(buffer), 'write() should reject'); 82 }, 'writing a resizable ArrayBuffer should be rejected'); 83 84 promise_test(async t => { 85 const wss = new WebSocketStream(ECHOURL); 86 const { writable } = await wss.opened; 87 const writer = writable.getWriter(); 88 const memory = new WebAssembly.Memory({ 89 initial: 4096, 90 maximum: 65536, 91 shared: true, 92 }); 93 const view = new Uint8Array(memory.buffer); 94 await promise_rejects_js( 95 t, TypeError, writer.write(view), 'write() should reject'); 96 }, 'writing a view on a shared buffer should be rejected'); 97 98 promise_test(async () => { 99 let wss = new WebSocketStream(ECHOURL); 100 let { writable } = await wss.opened; 101 let writer = writable.getWriter(); 102 wss = writable = null; 103 const promises = []; 104 for (let i = 0; i < 20; ++i) { 105 promises.push(writer.write(new Uint8Array(100000))); 106 } 107 writer = null; 108 for (let i = 0; i < 5; ++i) { 109 await garbageCollect(); 110 } 111 }, 'Garbage collecting a WebSocket stream doesn\'t crash while write promise is pending');