summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webrtc/RTCIceTransport.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webrtc/RTCIceTransport.html')
-rw-r--r--testing/web-platform/tests/webrtc/RTCIceTransport.html193
1 files changed, 193 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCIceTransport.html b/testing/web-platform/tests/webrtc/RTCIceTransport.html
new file mode 100644
index 0000000000..fe12c384e5
--- /dev/null
+++ b/testing/web-platform/tests/webrtc/RTCIceTransport.html
@@ -0,0 +1,193 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCIceTransport</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:
+ // createDataChannelPair
+ // awaitMessage
+
+ /*
+ 5.6. RTCIceTransport Interface
+ interface RTCIceTransport {
+ readonly attribute RTCIceRole role;
+ readonly attribute RTCIceComponent component;
+ readonly attribute RTCIceTransportState state;
+ readonly attribute RTCIceGathererState gatheringState;
+ sequence<RTCIceCandidate> getLocalCandidates();
+ sequence<RTCIceCandidate> getRemoteCandidates();
+ RTCIceCandidatePair? getSelectedCandidatePair();
+ RTCIceParameters? getLocalParameters();
+ RTCIceParameters? getRemoteParameters();
+ ...
+ };
+
+ getLocalCandidates
+ Returns a sequence describing the local ICE candidates gathered for this
+ RTCIceTransport and sent in onicecandidate
+
+ getRemoteCandidates
+ Returns a sequence describing the remote ICE candidates received by this
+ RTCIceTransport via addIceCandidate()
+
+ getSelectedCandidatePair
+ Returns the selected candidate pair on which packets are sent, or null if
+ there is no such pair.
+
+ getLocalParameters
+ Returns the local ICE parameters received by this RTCIceTransport via
+ setLocalDescription , or null if the parameters have not yet been received.
+
+ getRemoteParameters
+ Returns the remote ICE parameters received by this RTCIceTransport via
+ setRemoteDescription or null if the parameters have not yet been received.
+ */
+ function getIceTransportFromSctp(pc) {
+ const sctpTransport = pc.sctp;
+ assert_true(sctpTransport instanceof RTCSctpTransport,
+ 'Expect pc.sctp to be instantiated from RTCSctpTransport');
+
+ const dtlsTransport = sctpTransport.transport;
+ assert_true(dtlsTransport instanceof RTCDtlsTransport,
+ 'Expect sctp.transport to be an RTCDtlsTransport');
+
+ const iceTransport = dtlsTransport.iceTransport;
+ assert_true(iceTransport instanceof RTCIceTransport,
+ 'Expect dtlsTransport.transport to be an RTCIceTransport');
+
+ return iceTransport;
+ }
+
+ function validateCandidates(candidates) {
+ assert_greater_than(candidates.length, 0,
+ 'Expect at least one ICE candidate returned from get*Candidates()');
+
+ for(const candidate of candidates) {
+ assert_true(candidate instanceof RTCIceCandidate,
+ 'Expect candidate elements to be instance of RTCIceCandidate');
+ }
+ }
+
+ function validateCandidateParameter(param) {
+ assert_not_equals(param, null,
+ 'Expect candidate parameter to be non-null after data channels are connected');
+
+ assert_equals(typeof param.usernameFragment, 'string',
+ 'Expect param.usernameFragment to be set with string value');
+ assert_equals(typeof param.password, 'string',
+ 'Expect param.password to be set with string value');
+ }
+
+ function validateConnectedIceTransport(iceTransport) {
+ const { state, gatheringState, role, component } = iceTransport;
+
+ assert_true(role === 'controlling' || role === 'controlled',
+ 'Expect RTCIceRole to be either controlling or controlled, found ' + role);
+
+ assert_true(component === 'rtp' || component === 'rtcp',
+ 'Expect RTCIceComponent to be either rtp or rtcp');
+
+ assert_true(state === 'connected' || state === 'completed',
+ 'Expect ICE transport to be in connected or completed state after data channels are connected');
+
+ assert_true(gatheringState === 'gathering' || gatheringState === 'completed',
+ 'Expect ICE transport to be in gathering or completed gatheringState after data channels are connected');
+
+ validateCandidates(iceTransport.getLocalCandidates());
+ validateCandidates(iceTransport.getRemoteCandidates());
+
+ const candidatePair = iceTransport.getSelectedCandidatePair();
+ assert_not_equals(candidatePair, null,
+ 'Expect selected candidate pair to be non-null after ICE transport is connected');
+
+ assert_true(candidatePair.local instanceof RTCIceCandidate,
+ 'Expect candidatePair.local to be instance of RTCIceCandidate');
+
+ assert_true(candidatePair.remote instanceof RTCIceCandidate,
+ 'Expect candidatePair.remote to be instance of RTCIceCandidate');
+
+ validateCandidateParameter(iceTransport.getLocalParameters());
+ validateCandidateParameter(iceTransport.getRemoteParameters());
+ }
+
+ promise_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ return createDataChannelPair(t, {}, pc1, pc2)
+ .then(([channel1, channel2]) => {
+ // Send a ping message and wait for it just to make sure
+ // that the connection is fully working before testing
+ channel1.send('ping');
+ return awaitMessage(channel2);
+ })
+ .then(() => {
+ const iceTransport1 = getIceTransportFromSctp(pc1);
+ const iceTransport2 = getIceTransportFromSctp(pc2);
+
+ validateConnectedIceTransport(iceTransport1);
+ validateConnectedIceTransport(iceTransport2);
+
+ assert_equals(
+ iceTransport1.getLocalCandidates().length,
+ iceTransport2.getRemoteCandidates().length,
+ `Expect iceTransport1 to have same number of local candidate as iceTransport2's remote candidates`);
+
+ assert_equals(
+ iceTransport1.getRemoteCandidates().length,
+ iceTransport2.getLocalCandidates().length,
+ `Expect iceTransport1 to have same number of remote candidate as iceTransport2's local candidates`);
+
+ const candidatePair1 = iceTransport1.getSelectedCandidatePair();
+ const candidatePair2 = iceTransport2.getSelectedCandidatePair();
+
+ assert_equals(candidatePair1.local.candidate, candidatePair2.remote.candidate,
+ 'Expect selected local candidate of one pc is the selected remote candidate or another');
+
+ assert_equals(candidatePair1.remote.candidate, candidatePair2.local.candidate,
+ 'Expect selected local candidate of one pc is the selected remote candidate or another');
+
+ assert_equals(iceTransport1.role, 'controlling',
+ `Expect offerer's iceTransport to take the controlling role`);
+
+ assert_equals(iceTransport2.role, 'controlled',
+ `Expect answerer's iceTransport to take the controlled role`);
+ });
+ }, 'Two connected iceTransports should has matching local/remote candidates returned');
+
+ promise_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.createDataChannel('');
+
+ // setRemoteDescription(answer) without the other peer
+ // setting answer it's localDescription
+ return pc1.createOffer()
+ .then(offer =>
+ pc1.setLocalDescription(offer)
+ .then(() => pc2.setRemoteDescription(offer))
+ .then(() => pc2.createAnswer()))
+ .then(answer => pc1.setRemoteDescription(answer))
+ .then(() => {
+ const iceTransport = getIceTransportFromSctp(pc1);
+
+ assert_array_equals(iceTransport.getRemoteCandidates(), [],
+ 'Expect iceTransport to not have any remote candidate');
+
+ assert_equals(iceTransport.getSelectedCandidatePair(), null,
+ 'Expect selectedCandidatePair to be null');
+ });
+ }, 'Unconnected iceTransport should have empty remote candidates and selected pair');
+
+</script>