RTCDataChannel-bufferedAmount.html (11653B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <meta name="timeout" content="long"> 4 <title>RTCDataChannel.prototype.bufferedAmount</title> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="RTCPeerConnection-helper.js"></script> 8 <script> 9 'use strict'; 10 11 // Test is based on the following revision: 12 // https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html 13 14 // The following helper functions are called from RTCPeerConnection-helper.js: 15 // createDataChannelPair 16 // awaitMessage 17 18 /* 19 6.2. RTCDataChannel 20 interface RTCDataChannel : EventTarget { 21 ... 22 readonly attribute unsigned long bufferedAmount; 23 void send(USVString data); 24 void send(Blob data); 25 void send(ArrayBuffer data); 26 void send(ArrayBufferView data); 27 }; 28 29 bufferedAmount 30 The bufferedAmount attribute must return the number of bytes of application 31 data (UTF-8 text and binary data) that have been queued using send() but that, 32 as of the last time the event loop started executing a task, had not yet been 33 transmitted to the network. (This thus includes any text sent during the 34 execution of the current task, regardless of whether the user agent is able 35 to transmit text asynchronously with script execution.) This does not include 36 framing overhead incurred by the protocol, or buffering done by the operating 37 system or network hardware. The value of the [[BufferedAmount]] slot will only 38 increase with each call to the send() method as long as the [[ReadyState]] slot 39 is open; however, the slot does not reset to zero once the channel closes. When 40 the underlying data transport sends data from its queue, the user agent MUST 41 queue a task that reduces [[BufferedAmount]] with the number of bytes that was 42 sent. 43 44 45 [WebMessaging] 46 interface MessageEvent : Event { 47 readonly attribute any data; 48 ... 49 }; 50 */ 51 52 // Simple ASCII encoded string 53 const helloString = 'hello'; 54 // ASCII encoded buffer representation of the string 55 const helloBuffer = Uint8Array.of(0x68, 0x65, 0x6c, 0x6c, 0x6f); 56 const helloBlob = new Blob([helloBuffer]); 57 58 const emptyBuffer = Uint8Array.of(); 59 const emptyBlob = new Blob([emptyBuffer]); 60 61 // Unicode string with multiple code units 62 const unicodeString = '世界你好'; 63 // UTF-8 encoded buffer representation of the string 64 const unicodeBuffer = Uint8Array.of( 65 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c, 66 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd); 67 68 for (const options of [{}, {negotiated: true, id: 0}]) { 69 const mode = `${options.negotiated? "negotiated " : ""}datachannel`; 70 71 /* 72 Ensure .bufferedAmount is 0 initially for both sides. 73 */ 74 promise_test(async (t) => { 75 const [dc1, dc2] = await createDataChannelPair(t, options); 76 77 assert_equals(dc1.bufferedAmount, 0, 'Expect bufferedAmount to be 0'); 78 assert_equals(dc2.bufferedAmount, 0, 'Expect bufferedAmount to be 0'); 79 }, `${mode} bufferedAmount initial value should be 0 for both peers`); 80 81 /* 82 6.2. send() 83 3. Execute the sub step that corresponds to the type of the methods argument: 84 85 string object 86 Let data be the object and increase the bufferedAmount attribute 87 by the number of bytes needed to express data as UTF-8. 88 */ 89 promise_test(async (t) => { 90 const [dc1, dc2] = await createDataChannelPair(t, options); 91 92 dc1.send(unicodeString); 93 assert_equals(dc1.bufferedAmount, unicodeBuffer.byteLength, 94 'Expect bufferedAmount to be the byte length of the unicode string'); 95 96 await awaitMessage(dc2); 97 assert_equals(dc1.bufferedAmount, 0, 98 'Expect sender bufferedAmount to be reduced after message is sent'); 99 }, `${mode} bufferedAmount should increase to byte length of encoded` + 100 `unicode string sent`); 101 102 promise_test(async (t) => { 103 const [dc1, dc2] = await createDataChannelPair(t, options); 104 105 dc1.send(""); 106 assert_equals(dc1.bufferedAmount, 0, 107 'Expect bufferedAmount to stay at zero after sending empty string'); 108 109 await awaitMessage(dc2); 110 assert_equals(dc1.bufferedAmount, 0, 'Expect sender bufferedAmount unchanged'); 111 }, `${mode} bufferedAmount should stay at zero for empty string sent`); 112 113 /* 114 6.2. send() 115 3. Execute the sub step that corresponds to the type of the methods argument: 116 ArrayBuffer object 117 Let data be the data stored in the buffer described by the ArrayBuffer 118 object and increase the bufferedAmount attribute by the length of the 119 ArrayBuffer in bytes. 120 */ 121 promise_test(async (t) => { 122 const [dc1, dc2] = await createDataChannelPair(t, options); 123 124 dc1.send(helloBuffer.buffer); 125 assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, 126 'Expect bufferedAmount to increase to byte length of sent buffer'); 127 128 await awaitMessage(dc2); 129 assert_equals(dc1.bufferedAmount, 0, 130 'Expect sender bufferedAmount to be reduced after message is sent'); 131 }, `${mode} bufferedAmount should increase to byte length of buffer sent`); 132 133 promise_test(async (t) => { 134 const [dc1, dc2] = await createDataChannelPair(t, options); 135 136 dc1.send(emptyBuffer.buffer); 137 assert_equals(dc1.bufferedAmount, 0, 138 'Expect bufferedAmount to stay at zero after sending empty buffer'); 139 140 await awaitMessage(dc2); 141 assert_equals(dc1.bufferedAmount, 0, 142 'Expect sender bufferedAmount unchanged'); 143 }, `${mode} bufferedAmount should stay at zero for empty buffer sent`); 144 145 /* 146 6.2. send() 147 3. Execute the sub step that corresponds to the type of the methods argument: 148 Blob object 149 Let data be the raw data represented by the Blob object and increase 150 the bufferedAmount attribute by the size of data, in bytes. 151 */ 152 promise_test(async (t) => { 153 const [dc1, dc2] = await createDataChannelPair(t, options); 154 155 dc1.send(helloBlob); 156 assert_equals(dc1.bufferedAmount, helloBlob.size, 157 'Expect bufferedAmount to increase to size of sent blob'); 158 159 await awaitMessage(dc2); 160 assert_equals(dc1.bufferedAmount, 0, 161 'Expect sender bufferedAmount to be reduced after message is sent'); 162 }, `${mode} bufferedAmount should increase to size of blob sent`); 163 164 promise_test(async (t) => { 165 const [dc1, dc2] = await createDataChannelPair(t, options); 166 167 dc1.send(emptyBlob); 168 assert_equals(dc1.bufferedAmount, 0, 169 'Expect bufferedAmount to stay at zero after sending empty blob'); 170 171 await awaitMessage(dc2); 172 assert_equals(dc1.bufferedAmount, 0, 173 'Expect sender bufferedAmount unchanged'); 174 }, `${mode} bufferedAmount should stay at zero for empty blob sent`); 175 176 // Test sending 3 messages: helloBuffer, unicodeString, helloBlob 177 promise_test(async (t) => { 178 const resolver = new Resolver(); 179 let messageCount = 0; 180 181 const [dc1, dc2] = await createDataChannelPair(t, options); 182 dc2.onmessage = t.step_func(() => { 183 if (++messageCount === 3) { 184 assert_equals(dc1.bufferedAmount, 0, 185 'Expect sender bufferedAmount to be reduced after message is sent'); 186 resolver.resolve(); 187 } 188 }); 189 190 dc1.send(helloBuffer); 191 assert_equals(dc1.bufferedAmount, helloString.length, 192 'Expect bufferedAmount to be the total length of all messages queued to send'); 193 194 dc1.send(unicodeString); 195 assert_equals(dc1.bufferedAmount, 196 helloString.length + unicodeBuffer.byteLength, 197 'Expect bufferedAmount to be the total length of all messages queued to send'); 198 199 dc1.send(helloBlob); 200 assert_equals(dc1.bufferedAmount, 201 helloString.length*2 + unicodeBuffer.byteLength, 202 'Expect bufferedAmount to be the total length of all messages queued to send'); 203 204 await resolver; 205 }, `${mode} bufferedAmount should increase by byte length for each message sent`); 206 207 promise_test(async (t) => { 208 const [dc1] = await createDataChannelPair(t, options); 209 210 dc1.send(helloBuffer.buffer); 211 assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, 212 'Expect bufferedAmount to increase to byte length of sent buffer'); 213 214 dc1.close(); 215 assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, 216 'Expect bufferedAmount to not decrease immediately after closing the channel'); 217 }, `${mode} bufferedAmount should not decrease immediately after initiating closure`); 218 219 promise_test(async (t) => { 220 const pc1 = new RTCPeerConnection(); 221 t.add_cleanup(() => pc1.close()); 222 const [dc1] = await createDataChannelPair(t, options, pc1); 223 224 dc1.send(helloBuffer.buffer); 225 assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, 226 'Expect bufferedAmount to increase to byte length of sent buffer'); 227 228 pc1.close(); 229 assert_equals(dc1.bufferedAmount, helloBuffer.byteLength, 230 'Expect bufferedAmount to not decrease after closing the peer connection'); 231 }, `${mode} bufferedAmount should not decrease after closing the peer connection`); 232 233 promise_test(async t => { 234 const [channel1, channel2] = await createDataChannelPair(t, options); 235 channel1.addEventListener('bufferedamountlow', t.step_func_done(() => { 236 assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold); 237 })); 238 const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']); 239 channel1.send(helloString); 240 await eventWatcher.wait_for(['bufferedamountlow']); 241 }, `${mode} bufferedamountlow event fires after send() is complete`); 242 243 promise_test(async t => { 244 const [channel1, channel2] = await createDataChannelPair(t, options); 245 channel1.send(helloString); 246 assert_equals(channel1.bufferedAmount, helloString.length); 247 await awaitMessage(channel2); 248 assert_equals(channel1.bufferedAmount, 0); 249 }, `${mode} bufferedamount is data.length on send(data)`); 250 251 promise_test(async t => { 252 const [channel1, channel2] = await createDataChannelPair(t, options); 253 channel1.send(helloString); 254 assert_equals(channel1.bufferedAmount, helloString.length); 255 assert_equals(channel1.bufferedAmount, helloString.length); 256 }, `${mode} bufferedamount returns the same amount if no more data is`); 257 258 promise_test(async t => { 259 const [channel1, channel2] = await createDataChannelPair(t, options); 260 let eventFireCount = 0; 261 channel1.addEventListener('bufferedamountlow', t.step_func(() => { 262 assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold); 263 assert_equals(++eventFireCount, 1); 264 })); 265 const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']); 266 channel1.send(helloString); 267 assert_equals(channel1.bufferedAmount, helloString.length); 268 channel1.send(helloString); 269 assert_equals(channel1.bufferedAmount, 2 * helloString.length); 270 await eventWatcher.wait_for(['bufferedamountlow']); 271 }, `${mode} bufferedamountlow event fires only once after multiple` + 272 ` consecutive send() calls`); 273 274 promise_test(async t => { 275 const [channel1, channel2] = await createDataChannelPair(t, options); 276 const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']); 277 channel1.send(helloString); 278 assert_equals(channel1.bufferedAmount, helloString.length); 279 await eventWatcher.wait_for(['bufferedamountlow']); 280 assert_equals(await awaitMessage(channel2), helloString); 281 channel1.send(helloString); 282 assert_equals(channel1.bufferedAmount, helloString.length); 283 await eventWatcher.wait_for(['bufferedamountlow']); 284 assert_equals(await awaitMessage(channel2), helloString); 285 }, `${mode} bufferedamountlow event fires after each sent message`); 286 } 287 </script>