diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/webrtc/protocol/candidate-exchange.https.html | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/webrtc/protocol/candidate-exchange.https.html')
-rw-r--r-- | testing/web-platform/tests/webrtc/protocol/candidate-exchange.https.html | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/protocol/candidate-exchange.https.html b/testing/web-platform/tests/webrtc/protocol/candidate-exchange.https.html new file mode 100644 index 0000000000..c54f26e6d8 --- /dev/null +++ b/testing/web-platform/tests/webrtc/protocol/candidate-exchange.https.html @@ -0,0 +1,218 @@ +<!DOCTYPE html> +<html> +<head> +<title>Candidate exchange</title> +<meta name=timeout content=long> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../RTCPeerConnection-helper.js"></script> +</head> +<body> +<script> + +class StateLogger { + constructor(source, eventname, field) { + source.addEventListener(eventname, event => { + this.events.push(source[field]); + }); + this.events = [source[field]]; + } +} + +class IceStateLogger extends StateLogger { + constructor(source) { + super(source, 'iceconnectionstatechange', 'iceConnectionState'); + } +} + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + pc1.createDataChannel('datachannel'); + pc1IceStates = new IceStateLogger(pc1); + pc2IceStates = new IceStateLogger(pc1); + exchangeIceCandidates(pc1, pc2); + await exchangeOfferAnswer(pc1, pc2); + // Note - it's been claimed that this state sometimes jumps straight + // to "completed". If so, this test should be flaky. + await waitForIceStateChange(pc1, ['connected']); + assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']); + assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']); +}, 'Two way ICE exchange works'); + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + pc1IceStates = new IceStateLogger(pc1); + pc2IceStates = new IceStateLogger(pc1); + let candidates = []; + pc1.createDataChannel('datachannel'); + pc1.onicecandidate = e => { + candidates.push(e.candidate); + } + // Candidates from PC2 are not delivered to pc1, so pc1 will use + // peer-reflexive candidates. + await exchangeOfferAnswer(pc1, pc2); + const waiter = waitForIceGatheringState(pc1, ['complete']); + await waiter; + for (const candidate of candidates) { + if (candidate) { + pc2.addIceCandidate(candidate); + } + } + await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']), + waitForIceStateChange(pc2, ['connected', 'completed'])]); + const candidate_pair = pc1.sctp.transport.iceTransport.getSelectedCandidatePair(); + assert_equals(candidate_pair.local.type, 'host'); + assert_equals(candidate_pair.remote.type, 'prflx'); + assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']); + assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']); +}, 'Adding only caller -> callee candidates gives a connection'); + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + pc1IceStates = new IceStateLogger(pc1); + pc2IceStates = new IceStateLogger(pc1); + let candidates = []; + pc1.createDataChannel('datachannel'); + pc2.onicecandidate = e => { + candidates.push(e.candidate); + } + // Candidates from pc1 are not delivered to pc2. so pc2 will use + // peer-reflexive candidates. + await exchangeOfferAnswer(pc1, pc2); + const waiter = waitForIceGatheringState(pc2, ['complete']); + await waiter; + for (const candidate of candidates) { + if (candidate) { + pc1.addIceCandidate(candidate); + } + } + await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']), + waitForIceStateChange(pc2, ['connected', 'completed'])]); + const candidate_pair = pc2.sctp.transport.iceTransport.getSelectedCandidatePair(); + assert_equals(candidate_pair.local.type, 'host'); + assert_equals(candidate_pair.remote.type, 'prflx'); + assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']); + assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']); +}, 'Adding only callee -> caller candidates gives a connection'); + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + pc1IceStates = new IceStateLogger(pc1); + pc2IceStates = new IceStateLogger(pc1); + let pc2ToPc1Candidates = []; + pc1.createDataChannel('datachannel'); + pc2.onicecandidate = e => { + pc2ToPc1Candidates.push(e.candidate); + // This particular test verifies that candidates work + // properly if added from the pc2 onicecandidate event. + if (!e.candidate) { + for (const candidate of pc2ToPc1Candidates) { + if (candidate) { + pc1.addIceCandidate(candidate); + } + } + } + } + // Candidates from |pc1| are not delivered to |pc2|. |pc2| will use + // peer-reflexive candidates. + await exchangeOfferAnswer(pc1, pc2); + await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']), + waitForIceStateChange(pc2, ['connected', 'completed'])]); + const candidate_pair = pc2.sctp.transport.iceTransport.getSelectedCandidatePair(); + assert_equals(candidate_pair.local.type, 'host'); + assert_equals(candidate_pair.remote.type, 'prflx'); + assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']); + assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']); +}, 'Adding callee -> caller candidates from end-of-candidates gives a connection'); + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + pc1IceStates = new IceStateLogger(pc1); + pc2IceStates = new IceStateLogger(pc1); + let pc1ToPc2Candidates = []; + let pc2ToPc1Candidates = []; + pc1.createDataChannel('datachannel'); + pc1.onicecandidate = e => { + pc1ToPc2Candidates.push(e.candidate); + } + pc2.onicecandidate = e => { + pc2ToPc1Candidates.push(e.candidate); + } + const offer = await pc1.createOffer(); + await Promise.all([pc1.setLocalDescription(offer), + pc2.setRemoteDescription(offer)]); + const answer = await pc2.createAnswer(); + await waitForIceGatheringState(pc1, ['complete']); + await pc2.setLocalDescription(answer).then(() => { + for (const candidate of pc1ToPc2Candidates) { + if (candidate) { + pc2.addIceCandidate(candidate); + } + } + }); + await waitForIceGatheringState(pc2, ['complete']); + pc1.setRemoteDescription(answer).then(async () => { + for (const candidate of pc2ToPc1Candidates) { + if (candidate) { + await pc1.addIceCandidate(candidate); + } + } + }); + await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']), + waitForIceStateChange(pc2, ['connected', 'completed'])]); + const candidate_pair = + pc1.sctp.transport.iceTransport.getSelectedCandidatePair(); + assert_equals(candidate_pair.local.type, 'host'); + // When we supply remote candidates, we expect a jump to the 'host' candidate, + // but it might also remain as 'prflx'. + assert_true(candidate_pair.remote.type == 'host' || + candidate_pair.remote.type == 'prflx'); + assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']); + assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']); +}, 'Explicit offer/answer exchange gives a connection'); + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + pc1.createDataChannel('datachannel'); + pc1.onicecandidate = assert_unreached; + const offer = await pc1.createOffer(); + await pc1.setLocalDescription(offer); + await new Promise(resolve => { + pc1.onicecandidate = resolve; + }); +}, 'Candidates always arrive after setLocalDescription(offer) resolves'); + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + pc1.createDataChannel('datachannel'); + pc2.onicecandidate = assert_unreached; + const offer = await pc1.createOffer(); + await pc2.setRemoteDescription(offer); + await pc2.setLocalDescription(await pc2.createAnswer()); + await new Promise(resolve => { + pc2.onicecandidate = resolve; + }); +}, 'Candidates always arrive after setLocalDescription(answer) resolves'); + +</script> +</body> +</html> |