diff options
Diffstat (limited to 'testing/web-platform/tests/webrtc/RTCDataChannel-close.html')
-rw-r--r-- | testing/web-platform/tests/webrtc/RTCDataChannel-close.html | 180 |
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> |