mirror of
https://github.com/servo/servo.git
synced 2025-08-13 01:15:34 +01:00
Update web-platform-tests to revision 122a4672fa0dc554a6e7528fa3487fd907c792ee
This commit is contained in:
parent
fb1123495f
commit
93d826f7ba
301 changed files with 4775 additions and 1769 deletions
|
@ -3,60 +3,340 @@
|
|||
<title>RTCDataChannel id attribute</title>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src="RTCPeerConnection-helper.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
// This and the test below verify that after a description is set that
|
||||
// negotiates the DTLS role used by SCTP, data channels with unset IDs
|
||||
// have IDs set according to the rules in rtcweb-data-channel.
|
||||
promise_test(test => {
|
||||
const pc = new RTCPeerConnection;
|
||||
test.add_cleanup(() => pc.close());
|
||||
const channel = pc.createDataChannel('');
|
||||
return pc.createOffer()
|
||||
.then(offer => pc.setLocalDescription(offer))
|
||||
.then(() => {
|
||||
// Turn our own offer SDP into valid answer SDP by setting the DTLS role to
|
||||
// "active".
|
||||
const answer = {
|
||||
type: "answer",
|
||||
sdp: pc.localDescription.sdp.replace("actpass", "active")
|
||||
};
|
||||
return pc.setRemoteDescription(answer);
|
||||
})
|
||||
.then(() => {
|
||||
// Since the remote description had an "active" DTLS role, we're the server
|
||||
// and should use odd data channel IDs, according to rtcweb-data-channel.
|
||||
assert_equals(channel.id % 2, 1, 'id');
|
||||
const another_channel = pc.createDataChannel('another');
|
||||
assert_equals(another_channel.id % 2, 1, 'id');
|
||||
assert_not_equals(channel.id, another_channel.id);
|
||||
})
|
||||
}, "DTLS client uses odd data channel IDs");
|
||||
// Test is based on the following revision:
|
||||
// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
|
||||
|
||||
promise_test(test => {
|
||||
// This is the maximum number of streams, NOT the maximum stream ID (which is 65534)
|
||||
// See: https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.2
|
||||
const nStreams = 65535;
|
||||
|
||||
/*
|
||||
6.1.
|
||||
21. If the [[DataChannelId]] slot is null (due to no ID being passed into
|
||||
createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
|
||||
transport has already been negotiated, then initialize [[DataChannelId]] to a value
|
||||
generated by the user agent, according to [RTCWEB-DATA-PROTOCOL] [...]
|
||||
*/
|
||||
promise_test(async (t) => {
|
||||
const pc = new RTCPeerConnection;
|
||||
test.add_cleanup(() => pc.close());
|
||||
const channel = pc.createDataChannel('');
|
||||
return pc.createOffer()
|
||||
.then(offer => pc.setLocalDescription(offer))
|
||||
.then(() => {
|
||||
// Turn our own offer SDP into valid answer SDP by setting the DTLS role to
|
||||
// "passive".
|
||||
const answer = {
|
||||
type: "answer",
|
||||
sdp: pc.localDescription.sdp.replace("actpass", "passive")
|
||||
};
|
||||
return pc.setRemoteDescription(answer);
|
||||
})
|
||||
.then(() => {
|
||||
// Since the remote description had a "passive" DTLS role, we're the client
|
||||
// and should use even data channel IDs, according to rtcweb-data-channel.
|
||||
assert_equals(channel.id % 2, 0, 'id');
|
||||
const another_channel = pc.createDataChannel('another');
|
||||
assert_equals(another_channel.id % 2, 0, 'id');
|
||||
assert_not_equals(channel.id, another_channel.id);
|
||||
})
|
||||
}, "DTLS server uses even data channel IDs");
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc1 = pc.createDataChannel('');
|
||||
const ids = new UniqueSet();
|
||||
|
||||
const offer = await pc.createOffer();
|
||||
await pc.setLocalDescription(offer);
|
||||
// Turn our own offer SDP into valid answer SDP by setting the DTLS role to
|
||||
// "active".
|
||||
const answer = {
|
||||
type: 'answer',
|
||||
sdp: pc.localDescription.sdp.replace('actpass', 'active')
|
||||
};
|
||||
await pc.setRemoteDescription(answer);
|
||||
|
||||
// Since the remote description had an 'active' DTLS role, we're the server
|
||||
// and should use odd data channel IDs, according to rtcweb-data-channel.
|
||||
assert_equals(dc1.id % 2, 1,
|
||||
`Channel created by the DTLS server role must be odd (was ${dc1.id})`);
|
||||
const dc2 = pc.createDataChannel('another');
|
||||
assert_equals(dc2.id % 2, 1,
|
||||
`Channel created by the DTLS server role must be odd (was ${dc2.id})`);
|
||||
|
||||
// Ensure IDs are unique
|
||||
ids.add(dc1.id, `Channel ID ${dc1.id} should be unique`);
|
||||
ids.add(dc2.id, `Channel ID ${dc2.id} should be unique`);
|
||||
}, 'DTLS client uses odd data channel IDs');
|
||||
|
||||
promise_test(async (t) => {
|
||||
const pc = new RTCPeerConnection;
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc1 = pc.createDataChannel('');
|
||||
const ids = new UniqueSet();
|
||||
|
||||
const offer = await pc.createOffer();
|
||||
await pc.setLocalDescription(offer);
|
||||
// Turn our own offer SDP into valid answer SDP by setting the DTLS role to
|
||||
// 'passive'.
|
||||
const answer = {
|
||||
type: 'answer',
|
||||
sdp: pc.localDescription.sdp.replace('actpass', 'passive')
|
||||
};
|
||||
await pc.setRemoteDescription(answer);
|
||||
|
||||
// Since the remote description had a 'passive' DTLS role, we're the client
|
||||
// and should use even data channel IDs, according to rtcweb-data-channel.
|
||||
assert_equals(dc1.id % 2, 0,
|
||||
`Channel created by the DTLS client role must be even (was ${dc1.id})`);
|
||||
const dc2 = pc.createDataChannel('another');
|
||||
assert_equals(dc2.id % 2, 0,
|
||||
`Channel created by the DTLS client role must be even (was ${dc1.id})`);
|
||||
|
||||
// Ensure IDs are unique
|
||||
ids.add(dc1.id, `Channel ID ${dc1.id} should be unique`);
|
||||
ids.add(dc2.id, `Channel ID ${dc2.id} should be unique`);
|
||||
}, 'DTLS server uses even data channel IDs');
|
||||
|
||||
/*
|
||||
Check if the implementation allows using in-band negotiated channels with a specific ID (which
|
||||
is now a spec violation).
|
||||
*/
|
||||
promise_test(async (t) => {
|
||||
const resolver = new Resolver();
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const dc1 = pc1.createDataChannel('', {
|
||||
negotiated: false,
|
||||
id: 42
|
||||
});
|
||||
dc1.onopen = t.step_func(() => {
|
||||
dc1.send(':(');
|
||||
});
|
||||
|
||||
const dc2 = pc2.createDataChannel('', {
|
||||
negotiated: false,
|
||||
id: 42
|
||||
});
|
||||
dc2.onmessage = t.step_func(() => {
|
||||
assert_unreached('Channel established with same ID using negotiated=false');
|
||||
});
|
||||
|
||||
exchangeIceCandidates(pc1, pc2);
|
||||
await doSignalingHandshake(pc1, pc2);
|
||||
|
||||
// Wait a bit to ensure the 'message' event does NOT fire
|
||||
t.step_timeout(() => resolver.resolve(), 500);
|
||||
await resolver;
|
||||
}, 'In-band negotiation with a specific ID should not be allowed');
|
||||
|
||||
/*
|
||||
Check if the implementation still follows the odd/even role correctly if we annoy it with
|
||||
negotiated channels not following that rule.
|
||||
|
||||
Note: This test assumes that the implementation can handle a minimum of 40 data channels.
|
||||
*/
|
||||
promise_test(async (t) => {
|
||||
// Takes the DTLS server role
|
||||
const pc1 = new RTCPeerConnection();
|
||||
// Takes the DTLS client role
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
exchangeIceCandidates(pc1, pc2);
|
||||
const dcs = [];
|
||||
const negotiatedDcs = [];
|
||||
const ids = new UniqueSet();
|
||||
|
||||
// Create 10 DCEP-negotiated channels with pc1
|
||||
// Note: These should not have any associated valid ID at this point
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
const dc = pc1.createDataChannel('before-connection');
|
||||
assert_equals(dc.id, null, 'Channel id must be null before DTLS role has been determined');
|
||||
dcs.push(dc);
|
||||
}
|
||||
|
||||
// Create 10 negotiated channels with pc1 violating the odd/even rule
|
||||
for (let id = 0; id < 20; id += 2) {
|
||||
const dc = pc1.createDataChannel(`negotiated-not-odd-${id}-before-connection`, {
|
||||
negotiated: true,
|
||||
id: id,
|
||||
});
|
||||
assert_equals(dc.id, null, 'Channel id must be null before DTLS role has been determined');
|
||||
negotiatedDcs.push([dc, id]);
|
||||
ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
|
||||
}
|
||||
|
||||
await doSignalingHandshake(pc1, pc2, {
|
||||
offer: (offer) => {
|
||||
// Ensure pc1 takes the server role
|
||||
assert_true(offer.sdp.includes('actpass') || offer.sdp.includes('passive'),
|
||||
'pc1 must take the DTLS server role');
|
||||
return offer;
|
||||
},
|
||||
answer: (answer) => {
|
||||
// Ensure pc2 takes the client role
|
||||
// Note: It very likely will choose 'active' itself
|
||||
answer.sdp = answer.sdp.replace('actpass', 'active');
|
||||
assert_true(answer.sdp.includes('active'), 'pc2 must take the DTLS client role');
|
||||
return answer;
|
||||
},
|
||||
});
|
||||
|
||||
for (const dc of dcs) {
|
||||
assert_equals(dc.id % 2, 1,
|
||||
`Channel created by the DTLS server role must be odd (was ${dc.id})`);
|
||||
ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
|
||||
}
|
||||
|
||||
// Create 10 channels with pc1
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
const dc = pc1.createDataChannel('after-connection');
|
||||
assert_equals(dc.id % 2, 1,
|
||||
`Channel created by the DTLS server role must be odd (was ${dc.id})`);
|
||||
dcs.push(dc);
|
||||
ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
|
||||
}
|
||||
|
||||
// Create 10 negotiated channels with pc1 violating the odd/even rule
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
// Generate a valid even ID that has not been taken, yet.
|
||||
let id = 20;
|
||||
while (ids.has(id)) {
|
||||
id += 2;
|
||||
}
|
||||
const dc = pc1.createDataChannel(`negotiated-not-odd-${i}-after-connection`, {
|
||||
negotiated: true,
|
||||
id: id,
|
||||
});
|
||||
negotiatedDcs.push([dc, id]);
|
||||
ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
|
||||
}
|
||||
|
||||
// Since we've added new channels, let's check again that the odd/even role is not violated
|
||||
for (const dc of dcs) {
|
||||
assert_equals(dc.id % 2, 1,
|
||||
`Channel created by the DTLS server role must be odd (was ${dc.id})`);
|
||||
}
|
||||
|
||||
// Let's also make sure the negotiated channels have kept their ID
|
||||
for (const [dc, id] of negotiatedDcs) {
|
||||
assert_equals(dc.id, id, 'Negotiated channels should keep their assigned ID');
|
||||
}
|
||||
}, 'Odd/even role should not be violated when mixing with negotiated channels');
|
||||
|
||||
/*
|
||||
Create 32768 (client), 32767 (server) channels to make sure all ids are exhausted AFTER
|
||||
establishing a peer connection.
|
||||
|
||||
6.1. createDataChannel
|
||||
21. If the [[DataChannelId]] slot is null (due to no ID being passed into
|
||||
createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
|
||||
transport has already been negotiated, then initialize [[DataChannelId]] to a value
|
||||
generated by the user agent, according to [RTCWEB-DATA-PROTOCOL], and skip
|
||||
to the next step. If no available ID could be generated, or if the value of the
|
||||
[[DataChannelId]] slot is being used by an existing RTCDataChannel, throw an
|
||||
OperationError exception.
|
||||
*/
|
||||
/*
|
||||
TODO: Improve test coverage for RTCSctpTransport.maxChannels.
|
||||
TODO: Improve test coverage for exhausting channel cases.
|
||||
*/
|
||||
|
||||
/*
|
||||
Create 32768 (client), 32767 (server) channels to make sure all ids are exhausted BEFORE
|
||||
establishing a peer connection.
|
||||
|
||||
Be aware that late channel id assignment can currently fail in many places not covered by the
|
||||
spec, see: https://github.com/w3c/webrtc-pc/issues/1818
|
||||
|
||||
4.4.1.6.
|
||||
2.2.6. If description negotiates the DTLS role of the SCTP transport, and there is an
|
||||
RTCDataChannel with a null id, then generate an ID according to [RTCWEB-DATA-PROTOCOL].
|
||||
If no available ID could be generated, then run the following steps:
|
||||
1. Let channel be the RTCDataChannel object for which an ID could not be generated.
|
||||
2. Set channel's [[ReadyState]] slot to "closed".
|
||||
3. Fire an event named error with an OperationError exception at channel.
|
||||
4. Fire a simple event named close at channel.
|
||||
*/
|
||||
promise_test(async (t) => {
|
||||
const resolver = new Resolver();
|
||||
// Takes the DTLS server role
|
||||
const pc1 = new RTCPeerConnection();
|
||||
// Takes the DTLS client role
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
exchangeIceCandidates(pc1, pc2);
|
||||
const dcs = [];
|
||||
const ids = new UniqueSet();
|
||||
let nExpected = 0;
|
||||
let nActualCloses = 0;
|
||||
let nActualErrors = 0;
|
||||
|
||||
const maybeDone = t.step_func(() => {
|
||||
if (nExpected === nActualCloses && nExpected === nActualErrors) {
|
||||
resolver.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
// Create 65535+2 channels (since 65535 streams is a SHOULD, we may have less than that.)
|
||||
// Create two extra channels to possibly trigger the steps in the description.
|
||||
//
|
||||
// Note: Following the spec strictly would assume that this cannot fail. But in reality it will
|
||||
// fail because the implementation knows how many streams it supports. What it doesn't
|
||||
// know is how many streams the other peer supports (e.g. what will be negotiated).
|
||||
for (let i = 0; i < (nStreams + 2); ++i) {
|
||||
let dc;
|
||||
try {
|
||||
const pc = i % 2 === 1 ? pc1 : pc2;
|
||||
dc = pc.createDataChannel('this is going to be fun');
|
||||
dc.onclose = t.step_func(() => {
|
||||
++nActualCloses;
|
||||
maybeDone();
|
||||
});
|
||||
dc.onerror = t.step_func((e) => {
|
||||
assert_true(e instanceof RTCError, 'Expect error object to be instance of RTCError');
|
||||
assert_equals(e.error, 'sctp-failure', "Expect error to be of type 'sctp-failure'");
|
||||
++nActualErrors;
|
||||
maybeDone();
|
||||
});
|
||||
} catch (e) {
|
||||
assert_equals(e.name, 'OperationError', 'Fail on creation should throw OperationError');
|
||||
break;
|
||||
}
|
||||
assert_equals(dc.id, null, 'Channel id must be null before DTLS role has been determined');
|
||||
assert_not_equals(dc.readyState, 'closed',
|
||||
'Channel may not be closed before connection establishment');
|
||||
dcs.push([dc, i % 2 === 1]);
|
||||
}
|
||||
|
||||
await doSignalingHandshake(pc1, pc2, {
|
||||
offer: (offer) => {
|
||||
// Ensure pc1 takes the server role
|
||||
assert_true(offer.sdp.includes('actpass') || offer.sdp.includes('passive'),
|
||||
'pc1 must take the DTLS server role');
|
||||
return offer;
|
||||
},
|
||||
answer: (answer) => {
|
||||
// Ensure pc2 takes the client role
|
||||
// Note: It very likely will choose 'active' itself
|
||||
answer.sdp = answer.sdp.replace('actpass', 'active');
|
||||
assert_true(answer.sdp.includes('active'), 'pc2 must take the DTLS client role');
|
||||
return answer;
|
||||
},
|
||||
});
|
||||
|
||||
// Since the spec does not define a specific order to which channels may fail if an ID could
|
||||
// not be generated, any of the channels may be affected by the steps of the description.
|
||||
for (const [dc, odd] of dcs) {
|
||||
if (dc.readyState !== 'closed') {
|
||||
assert_equals(dc.id % 2, odd ? 1 : 0,
|
||||
`Channels created by the DTLS ${odd ? 'server' : 'client'} role must be
|
||||
${odd ? 'odd' : 'even'} (was ${dc.id})`);
|
||||
ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
|
||||
} else {
|
||||
++nExpected;
|
||||
}
|
||||
}
|
||||
|
||||
// Try creating one further channel on both sides. The attempt should fail since all IDs are
|
||||
// taken. If one ID is available, the implementation probably miscounts (or I did in the test).
|
||||
assert_throws('OperationError', () =>
|
||||
pc1.createDataChannel('this is too exhausting!'));
|
||||
assert_throws('OperationError', () =>
|
||||
pc2.createDataChannel('this is too exhausting!'));
|
||||
|
||||
maybeDone();
|
||||
await resolver;
|
||||
}, 'Channel ID exhaustion handling (before and after connection establishment)');
|
||||
|
||||
</script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue