| <!doctype html> |
| <meta charset=utf-8> |
| <title>RTCDataChannel.prototype.bufferedAmount</title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="RTCPeerConnection-helper.js"></script> |
| <script> |
| 'use strict'; |
| |
| // Test is based on the following editor draft: |
| // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html |
| |
| // The following helper functions are called from RTCPeerConnection-helper.js: |
| // createDataChannelPair |
| // awaitMessage |
| // blobToArrayBuffer |
| // assert_equals_array_buffer |
| |
| /* |
| 6.2. RTCDataChannel |
| interface RTCDataChannel : EventTarget { |
| ... |
| readonly attribute unsigned long bufferedAmount; |
| void send(USVString data); |
| void send(Blob data); |
| void send(ArrayBuffer data); |
| void send(ArrayBufferView data); |
| }; |
| |
| bufferedAmount |
| The bufferedAmount attribute must return the number of bytes of application |
| data (UTF-8 text and binary data) that have been queued using send() but that, |
| as of the last time the event loop started executing a task, had not yet been |
| transmitted to the network. (This thus includes any text sent during the |
| execution of the current task, regardless of whether the user agent is able |
| to transmit text asynchronously with script execution.) This does not include |
| framing overhead incurred by the protocol, or buffering done by the operating |
| system or network hardware. If the channel is closed, this attribute's value |
| will only increase with each call to the send() method (the attribute does not |
| reset to zero once the channel closes). |
| |
| |
| [WebMessaging] |
| interface MessageEvent : Event { |
| readonly attribute any data; |
| ... |
| }; |
| */ |
| |
| // Simple ASCII encoded string |
| const helloString = 'hello'; |
| // ASCII encoded buffer representation of the string |
| const helloBuffer = Uint8Array.of(0x68, 0x65, 0x6c, 0x6c, 0x6f); |
| const helloBlob = new Blob([helloBuffer]); |
| |
| // Unicode string with multiple code units |
| const unicodeString = '世界你好'; |
| // UTF-8 encoded buffer representation of the string |
| const unicodeBuffer = Uint8Array.of( |
| 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c, |
| 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd); |
| |
| /* |
| 6.2. send() |
| 3. Execute the sub step that corresponds to the type of the methods argument: |
| |
| string object |
| Let data be the object and increase the bufferedAmount attribute |
| by the number of bytes needed to express data as UTF-8. |
| */ |
| promise_test(t => { |
| return createDataChannelPair() |
| .then(([channel1, channel2]) => { |
| channel1.send(unicodeString); |
| assert_equals(channel1.bufferedAmount, unicodeBuffer.byteLength, |
| 'Expect bufferedAmount to be the byte length of the unicode string'); |
| |
| return awaitMessage(channel2) |
| .then(message => { |
| assert_equals(channel1.bufferedAmount, 0, |
| 'Expect sender bufferedAmount to be reduced after message is sent'); |
| }); |
| }); |
| }, 'bufferedAmount should increase to byte length of encoded unicode string sent'); |
| |
| /* |
| 6.2. send() |
| 3. Execute the sub step that corresponds to the type of the methods argument: |
| ArrayBuffer object |
| Let data be the data stored in the buffer described by the ArrayBuffer |
| object and increase the bufferedAmount attribute by the length of the |
| ArrayBuffer in bytes. |
| */ |
| promise_test(t => { |
| return createDataChannelPair() |
| .then(([channel1, channel2]) => { |
| channel1.send(helloBuffer.buffer); |
| assert_equals(channel1.bufferedAmount, helloBuffer.byteLength, |
| 'Expect bufferedAmount to increase to byte length of sent buffer'); |
| |
| return awaitMessage(channel2) |
| .then(messageBuffer => { |
| assert_equals(channel1.bufferedAmount, 0, |
| 'Expect sender bufferedAmount to be reduced after message is sent'); |
| }); |
| }); |
| }, 'bufferedAmount should increase to byte length of buffer sent'); |
| |
| /* |
| 6.2. send() |
| 3. Execute the sub step that corresponds to the type of the methods argument: |
| Blob object |
| Let data be the raw data represented by the Blob object and increase |
| the bufferedAmount attribute by the size of data, in bytes. |
| */ |
| promise_test(t => { |
| return createDataChannelPair() |
| .then(([channel1, channel2]) => { |
| channel1.send(helloBlob); |
| assert_equals(channel1.bufferedAmount, helloBlob.size, |
| 'Expect bufferedAmount to increase to size of sent blob'); |
| |
| return awaitMessage(channel2) |
| .then(messageBuffer => { |
| assert_equals(channel1.bufferedAmount, 0, |
| 'Expect sender bufferedAmount to be reduced after message is sent'); |
| }); |
| }); |
| }, 'bufferedAmount should increase to size of blob sent'); |
| |
| // Test sending 3 messages: helloBuffer, unicodeString, helloBlob |
| async_test(t => { |
| let messageCount = 0; |
| |
| createDataChannelPair() |
| .then(([channel1, channel2]) => { |
| const onMessage = t.step_func(event => { |
| const { data } = event; |
| messageCount++; |
| |
| if(messageCount === 3) { |
| assert_equals(channel1.bufferedAmount, 0, |
| 'Expect sender bufferedAmount to be reduced after message is sent'); |
| |
| t.done(); |
| } |
| }); |
| |
| channel2.addEventListener('message', onMessage); |
| |
| channel1.send(helloBuffer); |
| assert_equals(channel1.bufferedAmount, helloString.length, |
| 'Expect bufferedAmount to be the total length of all messages queued to send'); |
| |
| channel1.send(unicodeString); |
| assert_equals(channel1.bufferedAmount, |
| helloString.length + unicodeBuffer.byteLength, |
| 'Expect bufferedAmount to be the total length of all messages queued to send'); |
| |
| channel1.send(helloBlob); |
| assert_equals(channel1.bufferedAmount, |
| helloString.length*2 + unicodeBuffer.byteLength, |
| 'Expect bufferedAmount to be the total length of all messages queued to send'); |
| |
| }).catch(t.step_func(err => |
| assert_unreached(`Unexpected promise rejection: ${err}`))); |
| }, 'bufferedAmount should increase by byte length for each message sent'); |
| |
| promise_test(async t => { |
| const [channel1, channel2] = await createDataChannelPair(); |
| channel1.addEventListener('bufferedamountlow', t.step_func_done(() => { |
| assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold); |
| })); |
| const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']); |
| channel1.send(helloString); |
| await eventWatcher.wait_for(['bufferedamountlow']); |
| }, 'Data channel bufferedamountlow event fires after send() is complete'); |
| |
| promise_test(async t => { |
| const [channel1, channel2] = await createDataChannelPair(); |
| channel1.send(helloString); |
| assert_equals(channel1.bufferedAmount, helloString.length); |
| await awaitMessage(channel2); |
| assert_equals(channel1.bufferedAmount, 0); |
| }, 'Data channel bufferedamount is data.length on send(data)'); |
| |
| promise_test(async t => { |
| const [channel1, channel2] = await createDataChannelPair(); |
| channel1.send(helloString); |
| assert_equals(channel1.bufferedAmount, helloString.length); |
| assert_equals(channel1.bufferedAmount, helloString.length); |
| }, 'Data channel bufferedamount returns the same amount if no more data is' + |
| ' sent on the channel'); |
| |
| promise_test(async t => { |
| const [channel1, channel2] = await createDataChannelPair(); |
| let eventFireCount = 0; |
| channel1.addEventListener('bufferedamountlow', t.step_func(() => { |
| assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold); |
| assert_equals(++eventFireCount, 1); |
| })); |
| const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']); |
| channel1.send(helloString); |
| assert_equals(channel1.bufferedAmount, helloString.length); |
| channel1.send(helloString); |
| assert_equals(channel1.bufferedAmount, 2 * helloString.length); |
| await eventWatcher.wait_for(['bufferedamountlow']); |
| }, 'Data channel bufferedamountlow event fires only once after multiple' + |
| ' consecutive send() calls'); |
| |
| promise_test(async t => { |
| const [channel1, channel2] = await createDataChannelPair(); |
| const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']); |
| channel1.send(helloString); |
| assert_equals(channel1.bufferedAmount, helloString.length); |
| await eventWatcher.wait_for(['bufferedamountlow']); |
| assert_equals(await awaitMessage(channel2), helloString); |
| channel1.send(helloString); |
| assert_equals(channel1.bufferedAmount, helloString.length); |
| await eventWatcher.wait_for(['bufferedamountlow']); |
| assert_equals(await awaitMessage(channel2), helloString); |
| }, 'Data channel bufferedamountlow event fires after each sent message'); |
| |
| </script> |