summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--testing/web-platform/tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html149
1 files changed, 149 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html b/testing/web-platform/tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html
new file mode 100644
index 0000000000..9793844f56
--- /dev/null
+++ b/testing/web-platform/tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html
@@ -0,0 +1,149 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+'use strict';
+
+// In this test, the promises should resolve in the execution order
+// (setLocalDescription, setLocalDescription, addIceCandidate) as is ensured by
+// the Operations Chain; if an operation is pending, executing another operation
+// will queue it. This test will fail if an Operations Chain is not implemented,
+// but it gives the implementation some slack: it only ensures that
+// addIceCandidate() is not resolved first, allowing timing issues in resolving
+// promises where the test still passes even if addIceCandidate() is resolved
+// *before* the second setLocalDescription().
+//
+// This test covers Chrome issue (https://crbug.com/1019222), but does not
+// require setLocalDescription-promises to resolve immediately which is another
+// Chrome bug (https://crbug.com/1019232). The true order is covered by the next
+// test.
+// TODO(https://crbug.com/1019232): Delete this test when the next test passes
+// in Chrome.
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ caller.addTransceiver('audio');
+
+ const candidatePromise = new Promise(resolve => {
+ caller.onicecandidate = e => resolve(e.candidate);
+ });
+ await caller.setLocalDescription(await caller.createOffer());
+ await callee.setRemoteDescription(caller.localDescription);
+ const candidate = await candidatePromise;
+
+ // Chain setLocalDescription(), setLocalDescription() and addIceCandidate()
+ // without performing await between the calls.
+ const pendingPromises = [];
+ const resolveOrder = [];
+ pendingPromises.push(callee.setLocalDescription().then(() => {
+ resolveOrder.push('setLocalDescription 1');
+ }));
+ pendingPromises.push(callee.setLocalDescription().then(() => {
+ resolveOrder.push('setLocalDescription 2');
+ }));
+ pendingPromises.push(callee.addIceCandidate(candidate).then(() => {
+ resolveOrder.push('addIceCandidate');
+ }));
+ await Promise.all(pendingPromises);
+
+ assert_equals(resolveOrder[0], 'setLocalDescription 1');
+}, 'addIceCandidate is not resolved first if 2x setLocalDescription ' +
+ 'operations are pending');
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ caller.addTransceiver('audio');
+
+ const candidatePromise = new Promise(resolve => {
+ caller.onicecandidate = e => resolve(e.candidate);
+ });
+ await caller.setLocalDescription(await caller.createOffer());
+ await callee.setRemoteDescription(caller.localDescription);
+ const candidate = await candidatePromise;
+
+ // Chain setLocalDescription(), setLocalDescription() and addIceCandidate()
+ // without performing await between the calls.
+ const pendingPromises = [];
+ const resolveOrder = [];
+ pendingPromises.push(callee.setLocalDescription().then(() => {
+ resolveOrder.push('setLocalDescription 1');
+ }));
+ pendingPromises.push(callee.setLocalDescription().then(() => {
+ resolveOrder.push('setLocalDescription 2');
+ }));
+ pendingPromises.push(callee.addIceCandidate(candidate).then(() => {
+ resolveOrder.push('addIceCandidate');
+ }));
+ await Promise.all(pendingPromises);
+
+ // This test verifies that both issues described in https://crbug.com/1019222
+ // and https://crbug.com/1019232 are fixed. If this test passes in Chrome, the
+ // ICE candidate exchange issues described in
+ // https://github.com/web-platform-tests/wpt/issues/19866 should be resolved.
+ assert_array_equals(
+ resolveOrder,
+ ['setLocalDescription 1', 'setLocalDescription 2', 'addIceCandidate']);
+}, 'addIceCandidate and setLocalDescription are resolved in the correct ' +
+ 'order, as defined by the operations chain specification');
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ caller.addTransceiver('audio');
+ let events = [];
+ let pendingPromises = [];
+
+ const onCandidatePromise = new Promise(resolve => {
+ caller.onicecandidate = () => {
+ events.push('candidate generated');
+ resolve();
+ }
+ });
+ pendingPromises.push(onCandidatePromise);
+ pendingPromises.push(caller.setLocalDescription().then(() => {
+ events.push('setLocalDescription');
+ }));
+ await Promise.all(pendingPromises);
+ assert_array_equals(events, ['setLocalDescription', 'candidate generated']);
+}, 'onicecandidate fires after resolving setLocalDescription in offerer');
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ caller.addTransceiver('audio');
+ let events = [];
+ let pendingPromises = [];
+
+ caller.onicecandidate = (ev) => {
+ if (ev.candidate) {
+ callee.addIceCandidate(ev.candidate);
+ }
+ }
+ const offer = await caller.createOffer();
+ const onCandidatePromise = new Promise(resolve => {
+ callee.onicecandidate = () => {
+ events.push('candidate generated');
+ resolve();
+ }
+ });
+ await callee.setRemoteDescription(offer);
+ const answer = await callee.createAnswer();
+ pendingPromises.push(onCandidatePromise);
+ pendingPromises.push(callee.setLocalDescription(answer).then(() => {
+ events.push('setLocalDescription');
+ }));
+ await Promise.all(pendingPromises);
+ assert_array_equals(events, ['setLocalDescription', 'candidate generated']);
+}, 'onicecandidate fires after resolving setLocalDescription in answerer');
+
+</script>