зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1551316 - Add restartIce wpt tests. r=bwc
Differential Revision: https://phabricator.services.mozilla.com/D30978 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
3aef894f49
Коммит
0f0353066d
|
@ -0,0 +1,6 @@
|
|||
[RTCPeerConnection-restartIce.https.html]
|
||||
restart-after:
|
||||
if (os == "android") and e10s: bug 1566857 (frequently fails on geckoview)
|
||||
[restartIce() survives remote offer containing partial restart]
|
||||
expected: FAIL
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1468993
|
|
@ -0,0 +1,361 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title></title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src="RTCPeerConnection-helper.js"></script>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
function getLines(sdp, startsWith) {
|
||||
const lines = sdp.split("\r\n").filter(l => l.startsWith(startsWith));
|
||||
assert_true(lines.length > 0, `One or more ${startsWith} in sdp`);
|
||||
return lines;
|
||||
}
|
||||
|
||||
const getUfrags = ({sdp}) => getLines(sdp, "a=ice-ufrag:");
|
||||
const getPwds = ({sdp}) => getLines(sdp, "a=ice-pwd:");
|
||||
|
||||
async function doSignalingHandshakeEndOnFirst(pc1, pc2) {
|
||||
await pc1.setLocalDescription(await pc1.createOffer());
|
||||
await pc2.setRemoteDescription(pc1.localDescription);
|
||||
await pc2.setLocalDescription(await pc2.createAnswer());
|
||||
await pc1.setRemoteDescription(pc2.localDescription); // End on pc1. No race
|
||||
}
|
||||
|
||||
async function doSignalingHandshakeEndOnSecond(pc1, pc2) {
|
||||
await pc1.setLocalDescription(await pc1.createOffer());
|
||||
await pc2.setRemoteDescription(pc1.localDescription);
|
||||
await pc1.setRemoteDescription(await pc2.createAnswer());
|
||||
await pc2.setLocalDescription(pc1.remoteDescription); // End on pc2. No race
|
||||
}
|
||||
|
||||
async function assertNoNegotiationNeeded(t, pc) {
|
||||
assert_equals(pc.signalingState, "stable", "In stable state");
|
||||
const event = await Promise.race([
|
||||
new Promise(r => pc.onnegotiationneeded = r),
|
||||
new Promise(r => t.step_timeout(r, 10))
|
||||
]);
|
||||
assert_equals(event, undefined, "No negotiationneeded event");
|
||||
}
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.restartIce();
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
pc1.addTransceiver("audio");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() does not trigger negotiation ahead of initial negotiation");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
pc1.restartIce();
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() has no effect on initial negotiation");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
pc1.restartIce();
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
}, "restartIce() fires negotiationneeded after initial negotiation");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
|
||||
const [oldUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [oldUfrag2] = getUfrags(pc2.localDescription);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "control 1");
|
||||
assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "control 2");
|
||||
|
||||
pc1.restartIce();
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
const [newUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [newUfrag2] = getUfrags(pc2.localDescription);
|
||||
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
|
||||
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
assert_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1");
|
||||
assert_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2");
|
||||
}, "restartIce() causes fresh ufrags");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
|
||||
const [oldUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [oldUfrag2] = getUfrags(pc2.localDescription);
|
||||
|
||||
await pc1.setLocalDescription(await pc1.createOffer());
|
||||
pc1.restartIce();
|
||||
await pc2.setRemoteDescription(pc1.localDescription);
|
||||
await pc2.setLocalDescription(await pc2.createAnswer());
|
||||
await pc1.setRemoteDescription(pc2.localDescription);
|
||||
assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1");
|
||||
assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
const [newUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [newUfrag2] = getUfrags(pc2.localDescription);
|
||||
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
|
||||
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() works in have-local-offer");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await pc1.setLocalDescription(await pc1.createOffer());
|
||||
pc1.restartIce();
|
||||
await pc2.setRemoteDescription(pc1.localDescription);
|
||||
await pc2.setLocalDescription(await pc2.createAnswer());
|
||||
await pc1.setRemoteDescription(pc2.localDescription);
|
||||
const [oldUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [oldUfrag2] = getUfrags(pc2.localDescription);
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
const [newUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [newUfrag2] = getUfrags(pc2.localDescription);
|
||||
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
|
||||
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() works in initial have-local-offer");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
|
||||
const [oldUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [oldUfrag2] = getUfrags(pc2.localDescription);
|
||||
|
||||
await pc2.setLocalDescription(await pc2.createOffer());
|
||||
await pc1.setRemoteDescription(pc2.localDescription);
|
||||
pc1.restartIce();
|
||||
await pc2.setRemoteDescription(await pc1.createAnswer());
|
||||
await pc1.setLocalDescription(pc2.remoteDescription); // End on pc1. No race
|
||||
assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1");
|
||||
assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
const [newUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [newUfrag2] = getUfrags(pc2.localDescription);
|
||||
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
|
||||
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() works in have-remote-offer");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc2.addTransceiver("audio");
|
||||
await pc2.setLocalDescription(await pc2.createOffer());
|
||||
await pc1.setRemoteDescription(pc2.localDescription);
|
||||
pc1.restartIce();
|
||||
await pc2.setRemoteDescription(await pc1.createAnswer());
|
||||
await pc1.setLocalDescription(pc2.remoteDescription); // End on pc1. No race
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() does nothing in initial have-remote-offer");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
|
||||
const [oldUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [oldUfrag2] = getUfrags(pc2.localDescription);
|
||||
|
||||
pc1.restartIce();
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnSecond(pc2, pc1);
|
||||
assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "nothing yet 1");
|
||||
assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "nothing yet 2");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
const [newUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [newUfrag2] = getUfrags(pc2.localDescription);
|
||||
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
|
||||
assert_not_equals(newUfrag2, oldUfrag2, "ufrag 2 changed");
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() survives remote offer");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
|
||||
const [oldUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [oldUfrag2] = getUfrags(pc2.localDescription);
|
||||
|
||||
pc1.restartIce();
|
||||
pc2.restartIce();
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnSecond(pc2, pc1);
|
||||
const [newUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [newUfrag2] = getUfrags(pc2.localDescription);
|
||||
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
|
||||
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
assert_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1");
|
||||
assert_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2");
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() is satisfied by remote ICE restart");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
|
||||
const [oldUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [oldUfrag2] = getUfrags(pc2.localDescription);
|
||||
|
||||
pc1.restartIce();
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await pc1.setLocalDescription(await pc1.createOffer({iceRestart: false}));
|
||||
await pc2.setRemoteDescription(pc1.localDescription);
|
||||
await pc2.setLocalDescription(await pc2.createAnswer());
|
||||
await pc1.setRemoteDescription(pc2.localDescription);
|
||||
const [newUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [newUfrag2] = getUfrags(pc2.localDescription);
|
||||
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
|
||||
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() trumps {iceRestart: false}");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
|
||||
const [oldUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [oldUfrag2] = getUfrags(pc2.localDescription);
|
||||
|
||||
pc1.restartIce();
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await pc1.setLocalDescription(await pc1.createOffer());
|
||||
await pc1.setLocalDescription({type: "rollback"});
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
const [newUfrag1] = getUfrags(pc1.localDescription);
|
||||
const [newUfrag2] = getUfrags(pc2.localDescription);
|
||||
assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
|
||||
assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() survives rollback");
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection({bundlePolicy: "max-compat"});
|
||||
const pc2 = new RTCPeerConnection({bundlePolicy: "max-compat"});
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTransceiver("audio");
|
||||
pc1.addTransceiver("video");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await doSignalingHandshakeEndOnFirst(pc1, pc2);
|
||||
|
||||
const oldUfrags1 = getUfrags(pc1.localDescription);
|
||||
const oldUfrags2 = getUfrags(pc2.localDescription);
|
||||
const oldPwds2 = getPwds(pc2.localDescription);
|
||||
|
||||
pc1.restartIce();
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
|
||||
// Engineer a partial ICE restart from pc2
|
||||
pc2.restartIce();
|
||||
await pc2.setLocalDescription(await pc2.createOffer());
|
||||
{
|
||||
let {type, sdp} = pc2.localDescription;
|
||||
// Restore both old ice-ufrag and old ice-pwd to trigger a partial restart
|
||||
sdp = sdp.replace(getUfrags({sdp})[0], oldUfrags2[0]);
|
||||
sdp = sdp.replace(getPwds({sdp})[0], oldPwds2[0]);
|
||||
const newUfrags2 = getUfrags({sdp});
|
||||
const newPwds2 = getPwds({sdp});
|
||||
assert_equals(newUfrags2[0], oldUfrags2[0], "control ufrag match");
|
||||
assert_equals(newPwds2[0], oldPwds2[0], "control pwd match");
|
||||
assert_not_equals(newUfrags2[1], oldUfrags2[1], "control ufrag non-match");
|
||||
assert_not_equals(newPwds2[1], oldPwds2[1], "control pwd non-match");
|
||||
await pc1.setRemoteDescription({type, sdp});
|
||||
}
|
||||
await pc1.setLocalDescription(await pc1.createAnswer());
|
||||
const newUfrags1 = getUfrags(pc1.localDescription);
|
||||
assert_equals(newUfrags1[0], oldUfrags1[0], "Unchanged 1");
|
||||
assert_not_equals(newUfrags1[1], oldUfrags1[1], "Restarted 2");
|
||||
await new Promise(r => pc1.onnegotiationneeded = r);
|
||||
await pc1.setLocalDescription(await pc1.createOffer());
|
||||
const newestUfrags1 = getUfrags(pc1.localDescription);
|
||||
assert_not_equals(newestUfrags1[0], oldUfrag1[0], "Restarted 1");
|
||||
assert_not_equals(newestUfrags1[1], oldUfrag1[1], "Restarted 2");
|
||||
await assertNoNegotiationNeeded(t, pc1);
|
||||
}, "restartIce() survives remote offer containing partial restart");
|
||||
|
||||
</script>
|
Загрузка…
Ссылка в новой задаче