summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webrtc/RTCDataChannel-send.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webrtc/RTCDataChannel-send.html')
-rw-r--r--testing/web-platform/tests/webrtc/RTCDataChannel-send.html354
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>