summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webrtc/RTCDataChannel-close.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webrtc/RTCDataChannel-close.html')
-rw-r--r--testing/web-platform/tests/webrtc/RTCDataChannel-close.html180
1 files changed, 180 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCDataChannel-close.html b/testing/web-platform/tests/webrtc/RTCDataChannel-close.html
new file mode 100644
index 0000000000..64534fc507
--- /dev/null
+++ b/testing/web-platform/tests/webrtc/RTCDataChannel-close.html
@@ -0,0 +1,180 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCDataChannel.prototype.close</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+for (const options of [{}, {negotiated: true, id: 0}]) {
+ const mode = `${options.negotiated? "negotiated " : ""}datachannel`;
+
+ promise_test(async t => {
+ const [channel1, channel2] = await createDataChannelPair(t, options);
+ const haveClosed = new Promise(r => channel2.onclose = r);
+ let closingSeen = false;
+ channel1.onclosing = t.unreached_func();
+ channel2.onclosing = () => {
+ assert_equals(channel2.readyState, 'closing');
+ closingSeen = true;
+ };
+ channel2.addEventListener('error', t.unreached_func());
+ channel1.close();
+ await haveClosed;
+ assert_equals(channel2.readyState, 'closed');
+ assert_true(closingSeen, 'Closing event was seen');
+ }, `Close ${mode} causes onclosing and onclose to be called`);
+
+ promise_test(async t => {
+ // This is the same test as above, but using addEventListener
+ // rather than the "onclose" attribute.
+ const [channel1, channel2] = await createDataChannelPair(t, options);
+ const haveClosed = new Promise(r => channel2.addEventListener('close', r));
+ let closingSeen = false;
+ channel1.addEventListener('closing', t.unreached_func());
+ channel2.addEventListener('closing', () => {
+ assert_equals(channel2.readyState, 'closing');
+ closingSeen = true;
+ });
+ channel2.addEventListener('error', t.unreached_func());
+ channel1.close();
+ await haveClosed;
+ assert_equals(channel2.readyState, 'closed');
+ assert_true(closingSeen, 'Closing event was seen');
+ }, `Close ${mode} causes closing and close event to be called`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const [channel1, channel2] = await createDataChannelPair(t, options, pc1);
+ const events = [];
+ let error = null;
+ channel2.addEventListener('error', t.step_func(event => {
+ events.push('error');
+ assert_true(event instanceof RTCErrorEvent);
+ error = event.error;
+ }));
+ const haveClosed = new Promise(r => channel2.addEventListener('close', () => {
+ events.push('close');
+ r();
+ }));
+ pc1.close();
+ await haveClosed;
+ // Error should fire before close.
+ assert_array_equals(events, ['error', 'close']);
+ assert_true(error instanceof RTCError);
+ assert_equals(error.name, 'OperationError');
+ assert_equals(error.errorDetail, 'sctp-failure');
+ // Expects the sctpErrorCode is either null or 12 (User-Initiated Abort) as it is
+ // optional in the SCTP specification.
+ assert_in_array(error.sctpCauseCode, [null, 12]);
+ }, `Close peerconnection causes close event and error to be called on ${mode}`);
+
+ promise_test(async t => {
+ let pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ let [channel1, channel2] = await createDataChannelPair(t, options, pc1);
+ // The expected sequence of events when closing a DC is that
+ // channel1 goes to closing, channel2 fires onclose, and when
+ // the close is confirmed, channel1 fires onclose.
+ // After that, no more events should fire.
+ channel1.onerror = t.unreached_func();
+ let close2Handler = new Promise(resolve => {
+ channel2.onclose = event => {
+ resolve();
+ };
+ });
+ let close1Handler = new Promise(resolve => {
+ channel1.onclose = event => {
+ resolve();
+ };
+ });
+ channel1.close();
+ await close2Handler;
+ await close1Handler;
+ channel1.onclose = t.unreached_func();
+ channel2.onclose = t.unreached_func();
+ channel2.onerror = t.unreached_func();
+ pc1.close();
+ await new Promise(resolve => t.step_timeout(resolve, 10));
+ }, `Close peerconnection after ${mode} close causes no events`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.createDataChannel('not-counted', options);
+ const tokenDataChannel = new Promise(resolve => {
+ pc2.ondatachannel = resolve;
+ });
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ if (!options.negotiated) {
+ await tokenDataChannel;
+ }
+ let closeExpectedCount = 0;
+ let errorExpectedCount = 0;
+ let resolveCountIsZero;
+ let waitForCountIsZero = new Promise(resolve => {
+ resolveCountIsZero = resolve;
+ });
+ for (let i = 1; i <= 10; i++) {
+ if ('id' in options) {
+ options.id = i;
+ }
+ pc1.createDataChannel('', options);
+ if (options.negotiated) {
+ const channel = pc2.createDataChannel('', options);
+ channel.addEventListener('error', t.step_func(event => {
+ assert_true(event instanceof RTCErrorEvent, 'error event ' + event);
+ errorExpectedCount -= 1;
+ }));
+ channel.addEventListener('close', t.step_func(event => {
+ closeExpectedCount -= 1;
+ if (closeExpectedCount == 0) {
+ resolveCountIsZero();
+ }
+ }));
+ } else {
+ await new Promise(resolve => {
+ pc2.ondatachannel = ({channel}) => {
+ channel.addEventListener('error', t.step_func(event => {
+ assert_true(event instanceof RTCErrorEvent);
+ errorExpectedCount -= 1;
+ }));
+ channel.addEventListener('close', t.step_func(event => {
+ closeExpectedCount -= 1;
+ if (closeExpectedCount == 0) {
+ resolveCountIsZero();
+ }
+ }));
+ resolve();
+ }
+ });
+ }
+ ++closeExpectedCount;
+ ++errorExpectedCount;
+ }
+ assert_equals(closeExpectedCount, 10);
+ // We have to wait until SCTP is connected before we close, otherwise
+ // there will be no signal.
+ // The state is not available under Plan B, and unreliable on negotiated
+ // channels.
+ // TODO(bugs.webrtc.org/12259): Remove dependency on "negotiated"
+ if (pc1.sctp && !options.negotiated) {
+ waitForState(pc1.sctp, 'connected');
+ } else {
+ // Under plan B, we don't have a dtls transport to wait on, so just
+ // wait a bit.
+ await new Promise(resolve => t.step_timeout(resolve, 100));
+ }
+ pc1.close();
+ await waitForCountIsZero;
+ assert_equals(closeExpectedCount, 0);
+ assert_equals(errorExpectedCount, 0);
+ }, `Close peerconnection causes close event and error on many channels, ${mode}`);
+}
+</script>