summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webrtc/RTCPeerConnection-connectionState.https.html
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/webrtc/RTCPeerConnection-connectionState.https.html
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/webrtc/RTCPeerConnection-connectionState.https.html')
-rw-r--r--testing/web-platform/tests/webrtc/RTCPeerConnection-connectionState.https.html335
1 files changed, 335 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCPeerConnection-connectionState.https.html b/testing/web-platform/tests/webrtc/RTCPeerConnection-connectionState.https.html
new file mode 100644
index 0000000000..b3884e4314
--- /dev/null
+++ b/testing/web-platform/tests/webrtc/RTCPeerConnection-connectionState.https.html
@@ -0,0 +1,335 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.connectionState</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.htm
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // exchangeIceCandidates
+ // exchangeOfferAnswer
+
+ /*
+ 4.3.2. Interface Definition
+ interface RTCPeerConnection : EventTarget {
+ ...
+ readonly attribute RTCPeerConnectionState connectionState;
+ attribute EventHandler onconnectionstatechange;
+ };
+
+ 4.4.3. RTCPeerConnectionState Enum
+ enum RTCPeerConnectionState {
+ "new",
+ "connecting",
+ "connected",
+ "disconnected",
+ "failed",
+ "closed"
+ };
+
+ 5.5. RTCDtlsTransport Interface
+ interface RTCDtlsTransport {
+ readonly attribute RTCIceTransport iceTransport;
+ readonly attribute RTCDtlsTransportState state;
+ ...
+ };
+
+ enum RTCDtlsTransportState {
+ "new",
+ "connecting",
+ "connected",
+ "closed",
+ "failed"
+ };
+
+ 5.6. RTCIceTransport Interface
+ interface RTCIceTransport {
+ readonly attribute RTCIceTransportState state;
+ ...
+ };
+
+ enum RTCIceTransportState {
+ "new",
+ "checking",
+ "connected",
+ "completed",
+ "failed",
+ "disconnected",
+ "closed"
+ };
+ */
+
+ /*
+ 4.4.3. RTCPeerConnectionState Enum
+ new
+ Any of the RTCIceTransports or RTCDtlsTransports are in the new
+ state and none of the transports are in the connecting, checking,
+ failed or disconnected state, or all transports are in the closed state.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ assert_equals(pc.connectionState, 'new');
+ }, 'Initial connectionState should be new');
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ pc.close();
+ assert_equals(pc.connectionState, 'closed');
+ }, 'Closing the connection should set connectionState to closed');
+
+ /*
+ 4.4.3. RTCPeerConnectionState Enum
+ connected
+ All RTCIceTransports and RTCDtlsTransports are in the connected,
+ completed or closed state and at least of them is in the connected
+ or completed state.
+
+ 5.5. RTCDtlsTransportState
+ connected
+ DTLS has completed negotiation of a secure connection.
+
+ 5.6. RTCIceTransportState
+ connected
+ The RTCIceTransport has found a usable connection, but is still
+ checking other candidate pairs to see if there is a better connection.
+ It may also still be gathering and/or waiting for additional remote
+ candidates. If consent checks [RFC7675] fail on the connection in use,
+ and there are no other successful candidate pairs available, then the
+ state transitions to "checking" (if there are candidate pairs remaining
+ to be checked) or "disconnected" (if there are no candidate pairs to
+ check, but the peer is still gathering and/or waiting for additional
+ remote candidates).
+
+ completed
+ The RTCIceTransport has finished gathering, received an indication that
+ there are no more remote candidates, finished checking all candidate
+ pairs and found a connection. If consent checks [RFC7675] subsequently
+ fail on all successful candidate pairs, the state transitions to "failed".
+ */
+
+ async_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ let had_connecting = false;
+
+ const onConnectionStateChange = t.step_func(() => {
+ const {connectionState} = pc1;
+ if (connectionState === 'connecting') {
+ had_connecting = true;
+ } else if (connectionState === 'connected') {
+ assert_true(had_connecting, "state should pass connecting before reaching connected");
+ t.done();
+ }
+ });
+
+ pc1.createDataChannel('test');
+
+ pc1.addEventListener('connectionstatechange', onConnectionStateChange);
+
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ }, 'connection with one data channel should eventually have connected connection state');
+
+ async_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const onConnectionStateChange = t.step_func(() => {
+ const {connectionState} = pc1;
+ if (connectionState === 'connected') {
+ const sctpTransport = pc1.sctp;
+
+ const dtlsTransport = sctpTransport.transport;
+ assert_equals(dtlsTransport.state, 'connected',
+ 'Expect DTLS transport to be in connected state');
+
+ const iceTransport = dtlsTransport.iceTransport
+ assert_true(iceTransport.state === 'connected' ||
+ iceTransport.state === 'completed',
+ 'Expect ICE transport to be in connected or completed state');
+
+ t.done();
+ }
+ });
+
+ pc1.createDataChannel('test');
+
+ pc1.addEventListener('connectionstatechange', onConnectionStateChange);
+
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ }, 'connection with one data channel should eventually have transports in connected state');
+
+ /*
+ TODO
+ 4.4.3. RTCPeerConnectionState Enum
+ connecting
+ Any of the RTCIceTransports or RTCDtlsTransports are in the
+ connecting or checking state and none of them is in the failed state.
+
+ disconnected
+ Any of the RTCIceTransports or RTCDtlsTransports are in the disconnected
+ state and none of them are in the failed or connecting or checking state.
+
+ failed
+ Any of the RTCIceTransports or RTCDtlsTransports are in a failed state.
+
+ closed
+ The RTCPeerConnection object's [[isClosed]] slot is true.
+
+ 5.5. RTCDtlsTransportState
+ new
+ DTLS has not started negotiating yet.
+
+ connecting
+ DTLS is in the process of negotiating a secure connection.
+
+ closed
+ The transport has been closed.
+
+ failed
+ The transport has failed as the result of an error (such as a failure
+ to validate the remote fingerprint).
+
+ 5.6. RTCIceTransportState
+ new
+ The RTCIceTransport is gathering candidates and/or waiting for
+ remote candidates to be supplied, and has not yet started checking.
+
+ checking
+ The RTCIceTransport has received at least one remote candidate and
+ is checking candidate pairs and has either not yet found a connection
+ or consent checks [RFC7675] have failed on all previously successful
+ candidate pairs. In addition to checking, it may also still be gathering.
+
+ failed
+ The RTCIceTransport has finished gathering, received an indication that
+ there are no more remote candidates, finished checking all candidate pairs,
+ and all pairs have either failed connectivity checks or have lost consent.
+
+ disconnected
+ The ICE Agent has determined that connectivity is currently lost for this
+ RTCIceTransport . This is more aggressive than failed, and may trigger
+ intermittently (and resolve itself without action) on a flaky network.
+ The way this state is determined is implementation dependent.
+
+ Examples include:
+ Losing the network interface for the connection in use.
+ Repeatedly failing to receive a response to STUN requests.
+
+ Alternatively, the RTCIceTransport has finished checking all existing
+ candidates pairs and failed to find a connection (or consent checks
+ [RFC7675] once successful, have now failed), but it is still gathering
+ and/or waiting for additional remote candidates.
+
+ closed
+ The RTCIceTransport has shut down and is no longer responding to STUN requests.
+ */
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ caller.addTrack(track, stream);
+
+ await exchangeOfferAnswer(caller, callee);
+
+ assert_equals(caller.iceConnectionState, 'new');
+ assert_equals(callee.iceConnectionState, 'new');
+ }, 'connectionState remains new when not adding remote ice candidates');
+
+ promise_test(async t => {
+
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ caller.addTrack(track, stream);
+
+ const states = [];
+ caller.addEventListener('connectionstatechange', () => states.push(caller.connectionState));
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+
+ await listenToConnected(caller);
+
+ assert_array_equals(states, ['connecting', 'connected']);
+ }, 'connectionState transitions to connected via connecting');
+
+
+ // Make the callee act as if not bundle-aware
+ async function exchangeOfferAnswerUnbundled(caller, callee) {
+ const offer = await caller.createOffer();
+ const sdp = offer.sdp.replace('BUNDLE', 'SOMETHING')
+ .replace(/rtp-hdrext:sdes/g, 'rtp-hdrext:something')
+ .replace(/a=ssrc:/g, 'a=notssrc');
+ await caller.setLocalDescription(offer);
+ await callee.setRemoteDescription({type: 'offer', sdp});
+
+ await exchangeAnswer(caller, callee);
+ }
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection({bundlePolicy: 'max-compat'});
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ stream.getTracks().forEach(track => pc1.addTrack(track, stream));
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswerUnbundled(pc1, pc2);
+ await listenToConnected(pc1);
+
+ // https://github.com/w3c/webrtc-pc/issues/2678#issuecomment-948554126
+ let had_intermediary_connecting = false
+ let channel;
+ const onConnectionStateChange = t.step_func(() => {
+ const {connectionState, iceConnectionState} = pc1;
+ if (connectionState === 'connecting') {
+ had_intermediary_connecting = true;
+ }
+ });
+
+ pc1.addEventListener('connectionstatechange', onConnectionStateChange);
+ channel = pc1.createDataChannel('test');
+ await exchangeOfferAnswer(pc1, pc2);
+ await listenToConnected(pc1);
+
+ assert_true(had_intermediary_connecting, "state should re-pass connecting before reaching connected");
+ }, 'when adding a datachannel to an existing unbundled connected PC, it should go through a connecting state');
+
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+
+ stream.getTracks().forEach(track => pc1.addTrack(track, stream));
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ await listenToIceConnected(pc2);
+
+ pc2.onconnectionstatechange = t.unreached_func();
+ pc2.close();
+ assert_equals(pc2.connectionState, 'closed');
+ await new Promise(r => t.step_timeout(r, 100));
+ }, 'Closing a PeerConnection should not fire connectionstatechange event');
+</script>