summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webrtc/RTCPeerConnection-iceGatheringState.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webrtc/RTCPeerConnection-iceGatheringState.html')
-rw-r--r--testing/web-platform/tests/webrtc/RTCPeerConnection-iceGatheringState.html244
1 files changed, 244 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCPeerConnection-iceGatheringState.html b/testing/web-platform/tests/webrtc/RTCPeerConnection-iceGatheringState.html
new file mode 100644
index 0000000000..6afaf0fbfb
--- /dev/null
+++ b/testing/web-platform/tests/webrtc/RTCPeerConnection-iceGatheringState.html
@@ -0,0 +1,244 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.iceGatheringState</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:
+ // exchangeAnswer
+ // exchangeIceCandidates
+ // generateAudioReceiveOnlyOffer
+
+ /*
+ 4.3.2. Interface Definition
+ interface RTCPeerConnection : EventTarget {
+ ...
+ readonly attribute RTCIceGatheringState iceGatheringState;
+ attribute EventHandler onicegatheringstatechange;
+ };
+
+ 4.4.2. RTCIceGatheringState Enum
+ enum RTCIceGatheringState {
+ "new",
+ "gathering",
+ "complete"
+ };
+
+ 5.6. RTCIceTransport Interface
+ interface RTCIceTransport {
+ readonly attribute RTCIceGathererState gatheringState;
+ ...
+ };
+
+ enum RTCIceGathererState {
+ "new",
+ "gathering",
+ "complete"
+ };
+ */
+
+ /*
+ 4.4.2. RTCIceGatheringState Enum
+ new
+ Any of the RTCIceTransport s are in the new gathering state and
+ none of the transports are in the gathering state, or there are
+ no transports.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_equals(pc.iceGatheringState, 'new');
+ }, 'Initial iceGatheringState should be new');
+
+ async_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ let reachedGathering = false;
+ const onIceGatheringStateChange = t.step_func(() => {
+ const { iceGatheringState } = pc;
+
+ if(iceGatheringState === 'gathering') {
+ reachedGathering = true;
+ } else if(iceGatheringState === 'complete') {
+ assert_true(reachedGathering, 'iceGatheringState should reach gathering before complete');
+ t.done();
+ }
+ });
+
+ assert_equals(pc.onicegatheringstatechange, null,
+ 'Expect connection to have icegatheringstatechange event');
+ assert_equals(pc.iceGatheringState, 'new');
+
+ pc.addEventListener('icegatheringstatechange', onIceGatheringStateChange);
+
+ generateAudioReceiveOnlyOffer(pc)
+ .then(offer => pc.setLocalDescription(offer))
+ .then(err => t.step_func(err =>
+ assert_unreached(`Unhandled rejection ${err.name}: ${err.message}`)));
+ }, 'iceGatheringState should eventually become complete after setLocalDescription');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ await initialOfferAnswerWithIceGatheringStateTransitions(
+ pc1, pc2);
+
+ expectNoMoreGatheringStateChanges(t, pc1);
+ expectNoMoreGatheringStateChanges(t, pc2);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc2.setLocalDescription(await pc2.createOffer());
+
+ await new Promise(r => t.step_timeout(r, 500));
+ }, 'setLocalDescription(reoffer) with no new transports should not cause iceGatheringState to change');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+
+ expectNoMoreGatheringStateChanges(t, pc1);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+
+ await new Promise(r => t.step_timeout(r, 500));
+ }, 'setLocalDescription() with no transports should not cause iceGatheringState to change');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ await initialOfferAnswerWithIceGatheringStateTransitions(
+ pc1, pc2);
+ await pc1.setLocalDescription(await pc1.createOffer({iceRestart: true}));
+ await iceGatheringStateTransitions(pc1, 'gathering', 'complete');
+ }, 'setLocalDescription(reoffer) with a new transport should cause iceGatheringState to go to "checking" and then "complete"');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ expectNoMoreGatheringStateChanges(t, pc2);
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ const offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer);
+ await pc2.setRemoteDescription(offer);
+ await pc2.setRemoteDescription({type: 'rollback'});
+ await pc2.setRemoteDescription(offer);
+ }, 'sRD does not cause ICE gathering state changes');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ await initialOfferAnswerWithIceGatheringStateTransitions(
+ pc1, pc2);
+
+ const pc1waiter = iceGatheringStateTransitions(pc1, 'new');
+ const pc2waiter = iceGatheringStateTransitions(pc2, 'new');
+ pc1.getTransceivers()[0].stop();
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ assert_equals(pc2.getTransceivers().length, 0,
+ 'PC2 transceivers should be invisible after negotiation');
+ assert_equals(pc2.iceGatheringState, 'new');
+ await pc2waiter;
+ await pc1.setRemoteDescription(pc2.localDescription);
+ assert_equals(pc1.getTransceivers().length, 0,
+ 'PC1 transceivers should be invisible after negotiation');
+ assert_equals(pc1.iceGatheringState, 'new');
+ await pc1waiter;
+ }, 'renegotiation that closes all transports should result in ICE gathering state "new"');
+
+ /*
+ 4.3.2. RTCIceGatheringState Enum
+ new
+ Any of the RTCIceTransports are in the "new" gathering state and none
+ of the transports are in the "gathering" state, or there are no
+ transports.
+
+ gathering
+ Any of the RTCIceTransport s are in the gathering state.
+
+ complete
+ At least one RTCIceTransport exists, and all RTCIceTransports are
+ in the completed gathering state.
+
+ 5.6. RTCIceGathererState
+ gathering
+ The RTCIceTransport is in the process of gathering candidates.
+
+ complete
+ The RTCIceTransport has completed gathering and the end-of-candidates
+ indication for this transport has been sent. It will not gather candidates
+ again until an ICE restart causes it to restart.
+ */
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc2.close());
+
+ const onIceGatheringStateChange = t.step_func(() => {
+ const { iceGatheringState } = pc2;
+
+ if(iceGatheringState === 'gathering') {
+ const iceTransport = pc2.sctp.transport.iceTransport;
+
+ assert_equals(iceTransport.gatheringState, 'gathering',
+ 'Expect ICE transport to be in gathering gatheringState when iceGatheringState is gathering');
+
+ } else if(iceGatheringState === 'complete') {
+ const iceTransport = pc2.sctp.transport.iceTransport;
+
+ assert_equals(iceTransport.gatheringState, 'complete',
+ 'Expect ICE transport to be in complete gatheringState when iceGatheringState is complete');
+
+ t.done();
+ }
+ });
+
+ pc1.createDataChannel('test');
+
+ // Spec bug w3c/webrtc-pc#1382
+ // Because sctp is only defined when answer is set, we listen
+ // to pc2 so that we can be confident that sctp is defined
+ // when icegatheringstatechange event is fired.
+ pc2.addEventListener('icegatheringstatechange', onIceGatheringStateChange);
+
+
+ exchangeIceCandidates(pc1, pc2);
+
+ await pc1.setLocalDescription();
+ assert_equals(pc1.sctp.transport.iceTransport.gatheringState, 'new');
+ await pc2.setRemoteDescription(pc1.localDescription);
+
+ await exchangeAnswer(pc1, pc2);
+ }, 'connection with one data channel should eventually have connected connection state');
+
+ /*
+ TODO
+ 5.6. RTCIceTransport Interface
+ new
+ The RTCIceTransport was just created, and has not started gathering
+ candidates yet.
+ */
+</script>