diff options
Diffstat (limited to 'testing/web-platform/tests/webrtc/RTCDataChannel-send.html')
-rw-r--r-- | testing/web-platform/tests/webrtc/RTCDataChannel-send.html | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCDataChannel-send.html b/testing/web-platform/tests/webrtc/RTCDataChannel-send.html new file mode 100644 index 0000000000..d75245c347 --- /dev/null +++ b/testing/web-platform/tests/webrtc/RTCDataChannel-send.html @@ -0,0 +1,354 @@ +<!doctype html> +<meta charset=utf-8> +<meta name="timeout" content="long"> +<title>RTCDataChannel.prototype.send</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_typed_array + +/* + 6.2. RTCDataChannel + interface RTCDataChannel : EventTarget { + ... + readonly attribute RTCDataChannelState readyState; + readonly attribute unsigned long bufferedAmount; + attribute EventHandler onmessage; + attribute DOMString binaryType; + + void send(USVString data); + void send(Blob data); + void send(ArrayBuffer data); + void send(ArrayBufferView data); + }; + */ + +// Simple ASCII encoded string +const helloString = 'hello'; +const emptyString = ''; +// ASCII encoded buffer representation of the string +const helloBuffer = Uint8Array.of(0x68, 0x65, 0x6c, 0x6c, 0x6f); +const emptyBuffer = new Uint8Array(); +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() + 2. If channel's readyState attribute is connecting, throw an InvalidStateError. + */ +test(t => { + const pc = new RTCPeerConnection(); + const channel = pc.createDataChannel('test'); + assert_equals(channel.readyState, 'connecting'); + assert_throws_dom('InvalidStateError', () => channel.send(helloString)); +}, 'Calling send() when data channel is in connecting state should throw InvalidStateError'); + +for (const options of [{}, {negotiated: true, id: 0}]) { + const mode = `${options.negotiated? "Negotiated d" : "D"}atachannel`; + + /* + 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. + + [WebSocket] + 5. Feedback from the protocol + When a WebSocket message has been received + 4. If type indicates that the data is Text, then initialize event's data + attribute to data. + */ + promise_test(t => { + return createDataChannelPair(t, options) + .then(([channel1, channel2]) => { + channel1.send(helloString); + return awaitMessage(channel2) + }).then(message => { + assert_equals(typeof message, 'string', + 'Expect message to be a string'); + + assert_equals(message, helloString); + }); + }, `${mode} should be able to send simple string and receive as string`); + + promise_test(t => { + return createDataChannelPair(t, options) + .then(([channel1, channel2]) => { + channel1.send(unicodeString); + return awaitMessage(channel2) + }).then(message => { + assert_equals(typeof message, 'string', + 'Expect message to be a string'); + + assert_equals(message, unicodeString); + }); + }, `${mode} should be able to send unicode string and receive as unicode string`); + promise_test(t => { + return createDataChannelPair(t, options) + .then(([channel1, channel2]) => { + channel2.binaryType = 'arraybuffer'; + channel1.send(helloString); + return awaitMessage(channel2); + }).then(message => { + assert_equals(typeof message, 'string', + 'Expect message to be a string'); + + assert_equals(message, helloString); + }); + }, `${mode} should ignore binaryType and always receive string message as string`); + promise_test(t => { + return createDataChannelPair(t, options) + .then(([channel1, channel2]) => { + channel1.send(emptyString); + // Send a non-empty string in case the implementation ignores empty messages + channel1.send(helloString); + return awaitMessage(channel2) + }).then(message => { + assert_equals(typeof message, 'string', + 'Expect message to be a string'); + + assert_equals(message, emptyString); + }); + }, `${mode} should be able to send an empty string and receive an empty string`); + + /* + 6.2. send() + 3. Execute the sub step that corresponds to the type of the methods argument: + ArrayBufferView object + Let data be the data stored in the section of the buffer described + by the ArrayBuffer object that the ArrayBufferView object references + and increase the bufferedAmount attribute by the length of the + ArrayBufferView in bytes. + + [WebSocket] + 5. Feedback from the protocol + When a WebSocket message has been received + 4. If binaryType is set to "arraybuffer", then initialize event's data + attribute to a new read-only ArrayBuffer object whose contents are data. + + [WebIDL] + 4.1. ArrayBufferView + typedef (Int8Array or Int16Array or Int32Array or + Uint8Array or Uint16Array or Uint32Array or Uint8ClampedArray or + Float32Array or Float64Array or DataView) ArrayBufferView; + */ + promise_test(t => { + return createDataChannelPair(t, options) + .then(([channel1, channel2]) => { + channel2.binaryType = 'arraybuffer'; + channel1.send(helloBuffer); + return awaitMessage(channel2) + }).then(messageBuffer => { + assert_true(messageBuffer instanceof ArrayBuffer, + 'Expect messageBuffer to be an ArrayBuffer'); + + assert_equals_typed_array(messageBuffer, helloBuffer.buffer); + }); + }, `${mode} should be able to send Uint8Array message and receive as ArrayBuffer`); + + /* + 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(t, options) + .then(([channel1, channel2]) => { + channel2.binaryType = 'arraybuffer'; + channel1.send(helloBuffer.buffer); + return awaitMessage(channel2) + }).then(messageBuffer => { + assert_true(messageBuffer instanceof ArrayBuffer, + 'Expect messageBuffer to be an ArrayBuffer'); + + assert_equals_typed_array(messageBuffer, helloBuffer.buffer); + }); + }, `${mode} should be able to send ArrayBuffer message and receive as ArrayBuffer`); + + promise_test(t => { + return createDataChannelPair(t, options) + .then(([channel1, channel2]) => { + channel2.binaryType = 'arraybuffer'; + channel1.send(emptyBuffer.buffer); + // Send a non-empty buffer in case the implementation ignores empty messages + channel1.send(helloBuffer.buffer); + return awaitMessage(channel2) + }).then(messageBuffer => { + assert_true(messageBuffer instanceof ArrayBuffer, + 'Expect messageBuffer to be an ArrayBuffer'); + + assert_equals_typed_array(messageBuffer, emptyBuffer.buffer); + }); + }, `${mode} should be able to send an empty ArrayBuffer message and receive as ArrayBuffer`); + + /* + 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(t, options) + .then(([channel1, channel2]) => { + channel2.binaryType = 'arraybuffer'; + channel1.send(helloBlob); + return awaitMessage(channel2); + }).then(messageBuffer => { + assert_true(messageBuffer instanceof ArrayBuffer, + 'Expect messageBuffer to be an ArrayBuffer'); + + assert_equals_typed_array(messageBuffer, helloBuffer.buffer); + }); + }, `${mode} should be able to send Blob message and receive as ArrayBuffer`); + + /* + [WebSocket] + 5. Feedback from the protocol + When a WebSocket message has been received + 4. If binaryType is set to "blob", then initialize event's data attribute + to a new Blob object that represents data as its raw data. + */ + promise_test(t => { + return createDataChannelPair(t, options) + .then(([channel1, channel2]) => { + channel2.binaryType = 'blob'; + channel1.send(helloBuffer); + return awaitMessage(channel2); + }) + .then(messageBlob => { + assert_true(messageBlob instanceof Blob, + 'Expect received messageBlob to be a Blob'); + + return blobToArrayBuffer(messageBlob); + }).then(messageBuffer => { + assert_true(messageBuffer instanceof ArrayBuffer, + 'Expect messageBuffer to be an ArrayBuffer'); + + assert_equals_typed_array(messageBuffer, helloBuffer.buffer); + }); + }, `${mode} should be able to send ArrayBuffer message and receive as Blob`); + + /* + 6.2. RTCDataChannel + binaryType + The binaryType attribute must, on getting, return the value to which it was + last set. On setting, the user agent must set the IDL attribute to the new + value. When a RTCDataChannel object is created, the binaryType attribute must + be initialized to the string "blob". + */ + promise_test(t => { + return createDataChannelPair(t, options) + .then(([channel1, channel2]) => { + assert_equals(channel2.binaryType, 'blob', + 'Expect initial binaryType value to be blob'); + + channel1.send(helloBuffer); + return awaitMessage(channel2); + }) + .then(messageBlob => { + assert_true(messageBlob instanceof Blob, + 'Expect received messageBlob to be a Blob'); + + return blobToArrayBuffer(messageBlob); + }).then(messageBuffer => { + assert_true(messageBuffer instanceof ArrayBuffer, + 'Expect messageBuffer to be an ArrayBuffer'); + + assert_equals_typed_array(messageBuffer, helloBuffer.buffer); + }); + }, `${mode} binaryType should receive message as Blob by default`); + + // Test sending 3 messages: helloBuffer, unicodeString, helloBlob + async_test(t => { + const receivedMessages = []; + + const onMessage = t.step_func(event => { + const { data } = event; + receivedMessages.push(data); + + if(receivedMessages.length === 3) { + assert_equals_typed_array(receivedMessages[0], helloBuffer.buffer); + assert_equals(receivedMessages[1], unicodeString); + assert_equals_typed_array(receivedMessages[2], helloBuffer.buffer); + + t.done(); + } + }); + + createDataChannelPair(t, options) + .then(([channel1, channel2]) => { + channel2.binaryType = 'arraybuffer'; + channel2.addEventListener('message', onMessage); + + channel1.send(helloBuffer); + channel1.send(unicodeString); + channel1.send(helloBlob); + + }).catch(t.step_func(err => + assert_unreached(`Unexpected promise rejection: ${err}`))); + }, `${mode} sending multiple messages with different types should succeed and be received`); + + /* + [Deferred] + 6.2. RTCDataChannel + The send() method is being amended in w3c/webrtc-pc#1209 to throw error instead + of closing data channel when buffer is full + + send() + 4. If channel's underlying data transport is not established yet, or if the + closing procedure has started, then abort these steps. + 5. Attempt to send data on channel's underlying data transport; if the data + cannot be sent, e.g. because it would need to be buffered but the buffer + is full, the user agent must abruptly close channel's underlying data + transport with an error. + + test(t => { + const pc = new RTCPeerConnection(); + const channel = pc.createDataChannel('test'); + channel.close(); + assert_equals(channel.readyState, 'closing'); + channel.send(helloString); + }, 'Calling send() when data channel is in closing state should succeed'); + */ + + promise_test(async t => { + let pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + let [channel1, channel2] = await createDataChannelPair(t, options, pc1); + let message = 'hello888'; // 8 bytes + while (message.length <= pc1.sctp.maxMessageSize) { + channel1.send(message); + let received_message = await awaitMessage(channel2); + assert_equals(received_message.length, message.length, "Size mismatch"); + // Double size + message = message + message; + } + // "send" method step 4: + // If the byte size of "data" exceeds the value of maxMessageSize, throw + // a TypeError. + assert_throws_js(TypeError, () => channel1.send(message)); + }, `${mode} send() up to max size should succeed, above max size should fail`); +} +</script> |