mirror of
https://github.com/servo/servo.git
synced 2025-08-11 16:35:33 +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,44 +3,51 @@
|
|||
<title>RTCPeerConnection.prototype.createDataChannel</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://rawgit.com/w3c/webrtc-pc/cc8d80f455b86c8041d63bceb8b457f45c72aa89/webrtc.html
|
||||
// Test is based on the following revision:
|
||||
// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
|
||||
|
||||
/*
|
||||
6.1. RTCPeerConnection Interface Extensions
|
||||
|
||||
partial interface RTCPeerConnection {
|
||||
RTCDataChannel createDataChannel(USVString label,
|
||||
optional RTCDataChannelInit dataChannelDict);
|
||||
...
|
||||
[...]
|
||||
RTCDataChannel createDataChannel(USVString label,
|
||||
optional RTCDataChannelInit dataChannelDict);
|
||||
[...]
|
||||
};
|
||||
|
||||
6.2. RTCDataChannel
|
||||
|
||||
interface RTCDataChannel : EventTarget {
|
||||
readonly attribute USVString label;
|
||||
readonly attribute boolean ordered;
|
||||
readonly attribute unsigned short? maxPacketLifeTime;
|
||||
readonly attribute unsigned short? maxRetransmits;
|
||||
readonly attribute USVString protocol;
|
||||
readonly attribute boolean negotiated;
|
||||
readonly attribute unsigned short? id;
|
||||
readonly attribute RTCPriorityType priority;
|
||||
readonly attribute RTCDataChannelState readyState;
|
||||
readonly attribute USVString label;
|
||||
readonly attribute boolean ordered;
|
||||
readonly attribute unsigned short? maxPacketLifeTime;
|
||||
readonly attribute unsigned short? maxRetransmits;
|
||||
readonly attribute USVString protocol;
|
||||
readonly attribute boolean negotiated;
|
||||
readonly attribute unsigned short? id;
|
||||
readonly attribute RTCPriorityType priority;
|
||||
readonly attribute RTCDataChannelState readyState;
|
||||
readonly attribute unsigned long bufferedAmount;
|
||||
attribute unsigned long bufferedAmountLowThreshold;
|
||||
[...]
|
||||
attribute DOMString binaryType;
|
||||
[...]
|
||||
};
|
||||
|
||||
dictionary RTCDataChannelInit {
|
||||
boolean ordered = true;
|
||||
unsigned short maxPacketLifeTime;
|
||||
unsigned short maxRetransmits;
|
||||
USVString protocol = "";
|
||||
boolean negotiated = false;
|
||||
[EnforceRange]
|
||||
unsigned short id;
|
||||
RTCPriorityType priority = "low";
|
||||
boolean ordered = true;
|
||||
unsigned short maxPacketLifeTime;
|
||||
unsigned short maxRetransmits;
|
||||
USVString protocol = "";
|
||||
boolean negotiated = false;
|
||||
[EnforceRange]
|
||||
unsigned short id;
|
||||
RTCPriorityType priority = "low";
|
||||
};
|
||||
|
||||
4.9.1. RTCPriorityType Enum
|
||||
|
@ -53,8 +60,10 @@
|
|||
};
|
||||
*/
|
||||
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
assert_equals(pc.createDataChannel.length, 1);
|
||||
assert_throws(new TypeError(), () => pc.createDataChannel());
|
||||
}, 'createDataChannel with no argument should throw TypeError');
|
||||
|
@ -63,7 +72,7 @@ test(() => {
|
|||
6.2. createDataChannel
|
||||
2. If connection's [[isClosed]] slot is true, throw an InvalidStateError.
|
||||
*/
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
pc.close();
|
||||
assert_equals(pc.signalingState, 'closed', 'signaling state');
|
||||
|
@ -72,57 +81,81 @@ test(() => {
|
|||
|
||||
/*
|
||||
6.1. createDataChannel
|
||||
4. Let channel have a [[Label]] internal slot initialized to the value of the
|
||||
4. Let channel have a [[DataChannelLabel]] internal slot initialized to the value of the
|
||||
first argument.
|
||||
5. Let options be the second argument.
|
||||
6. Let channel have an [[MaxPacketLifeTime]] internal slot initialized to
|
||||
6. Let options be the second argument.
|
||||
7. Let channel have an [[MaxPacketLifeTime]] internal slot initialized to
|
||||
option's maxPacketLifeTime member, if present, otherwise null.
|
||||
7. Let channel have an [[MaxRetransmits]] internal slot initialized to
|
||||
8. Let channel have a [[ReadyState]] internal slot initialized to "connecting".
|
||||
9. Let channel have a [[BufferedAmount]] internal slot initialized to 0.
|
||||
10. Let channel have an [[MaxRetransmits]] internal slot initialized to
|
||||
option's maxRetransmits member, if present, otherwise null.
|
||||
8. Let channel have an [[DataChannelId]] internal slot initialized to
|
||||
option's id member, if present, otherwise null.
|
||||
9. Let channel have an [[Ordered]] internal slot initialized to option's
|
||||
11. Let channel have an [[Ordered]] internal slot initialized to option's
|
||||
ordered member.
|
||||
10. Let channel have an [[Protocol]] internal slot initialized to option's
|
||||
12. Let channel have a [[DataChannelProtocol]] internal slot initialized to option's
|
||||
protocol member.
|
||||
11. Let channel have an [[Negotiated]] internal slot initialized to option's
|
||||
negotiated member.
|
||||
12. Let channel have an [[DataChannelPriority]] internal slot initialized
|
||||
to option's priority member.
|
||||
14. Let channel have a [[Negotiated]] internal slot initialized to option's negotiated
|
||||
member.
|
||||
15. Let channel have an [[DataChannelId]] internal slot initialized to option's id
|
||||
member, if it is present and [[Negotiated]] is true, otherwise null.
|
||||
17. Let channel have an [[DataChannelPriority]] internal slot initialized to option's
|
||||
priority member.
|
||||
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.
|
||||
|
||||
Note
|
||||
If the [[DataChannelId]] slot is null after this step, it will be populated once
|
||||
the DTLS role is determined during the process of setting an RTCSessionDescription.
|
||||
22. If channel is the first RTCDataChannel created on connection, update the
|
||||
negotiation-needed flag for connection.
|
||||
|
||||
|
||||
6.2. RTCDataChannel
|
||||
|
||||
A RTCDataChannel, created with createDataChannel or dispatched via a
|
||||
RTCDataChannelEvent, MUST initially be in the connecting state
|
||||
|
||||
bufferedAmountLowThreshold
|
||||
[...] The bufferedAmountLowThreshold is initially zero on each new RTCDataChannel,
|
||||
but the application may change its value at any time.
|
||||
|
||||
binaryType
|
||||
When a RTCDataChannel object is created, the binaryType attribute MUST
|
||||
[...] When a RTCDataChannel object is created, the binaryType attribute MUST
|
||||
be initialized to the string "blob".
|
||||
*/
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const channel = pc.createDataChannel('');
|
||||
assert_true(channel instanceof RTCDataChannel, 'is RTCDataChannel');
|
||||
assert_equals(channel.label, '');
|
||||
assert_equals(channel.ordered, true);
|
||||
assert_equals(channel.maxPacketLifeTime, null);
|
||||
assert_equals(channel.maxRetransmits, null);
|
||||
assert_equals(channel.protocol, '');
|
||||
assert_equals(channel.negotiated, false);
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel('');
|
||||
|
||||
assert_true(dc instanceof RTCDataChannel, 'is RTCDataChannel');
|
||||
assert_equals(dc.label, '');
|
||||
assert_equals(dc.ordered, true);
|
||||
assert_equals(dc.maxPacketLifeTime, null);
|
||||
assert_equals(dc.maxRetransmits, null);
|
||||
assert_equals(dc.protocol, '');
|
||||
assert_equals(dc.negotiated, false);
|
||||
// Since no offer/answer exchange has occurred yet, the DTLS role is unknown
|
||||
// and so the ID should be null.
|
||||
assert_equals(channel.id, null);
|
||||
assert_equals(channel.priority, 'low');
|
||||
|
||||
assert_equals(channel.readyState, 'connecting');
|
||||
assert_equals(channel.binaryType, 'blob');
|
||||
|
||||
assert_equals(dc.id, null);
|
||||
assert_equals(dc.priority, 'low');
|
||||
assert_equals(dc.readyState, 'connecting');
|
||||
assert_equals(dc.bufferedAmount, 0);
|
||||
assert_equals(dc.bufferedAmountLowThreshold, 0);
|
||||
assert_equals(dc.binaryType, 'blob');
|
||||
}, 'createDataChannel attribute default values');
|
||||
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const channel = pc.createDataChannel('test', {
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel('test', {
|
||||
ordered: false,
|
||||
maxPacketLifeTime: null,
|
||||
maxRetransmits: 1,
|
||||
|
@ -132,23 +165,24 @@ test(() => {
|
|||
priority: 'high'
|
||||
});
|
||||
|
||||
assert_true(channel instanceof RTCDataChannel, 'is RTCDataChannel');
|
||||
assert_equals(channel.label, 'test');
|
||||
assert_equals(channel.ordered, false);
|
||||
assert_equals(channel.maxPacketLifeTime, null);
|
||||
assert_equals(channel.maxRetransmits, 1);
|
||||
assert_equals(channel.protocol, 'custom');
|
||||
assert_equals(channel.negotiated, true);
|
||||
assert_equals(channel.id, 3);
|
||||
assert_equals(channel.priority, 'high');
|
||||
assert_equals(channel.readyState, 'connecting');
|
||||
assert_equals(channel.binaryType, 'blob');
|
||||
|
||||
assert_true(dc instanceof RTCDataChannel, 'is RTCDataChannel');
|
||||
assert_equals(dc.label, 'test');
|
||||
assert_equals(dc.ordered, false);
|
||||
assert_equals(dc.maxPacketLifeTime, null);
|
||||
assert_equals(dc.maxRetransmits, 1);
|
||||
assert_equals(dc.protocol, 'custom');
|
||||
assert_equals(dc.negotiated, true);
|
||||
assert_equals(dc.id, 3);
|
||||
assert_equals(dc.priority, 'high');
|
||||
assert_equals(dc.readyState, 'connecting');
|
||||
assert_equals(dc.bufferedAmount, 0);
|
||||
assert_equals(dc.bufferedAmountLowThreshold, 0);
|
||||
assert_equals(dc.binaryType, 'blob');
|
||||
}, 'createDataChannel with provided parameters should initialize attributes to provided values');
|
||||
|
||||
/*
|
||||
6.2. createDataChannel
|
||||
4. Let channel have a [[Label]] internal slot initialized to the value of the
|
||||
4. Let channel have a [[DataChannelLabel]] internal slot initialized to the value of the
|
||||
first argument.
|
||||
|
||||
[ECMA262] 7.1.12. ToString(argument)
|
||||
|
@ -164,76 +198,102 @@ const labels = [
|
|||
['lone surrogate', '\uD800', '\uFFFD'],
|
||||
];
|
||||
for (const [description, label, expected] of labels) {
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection;
|
||||
const channel = pc.createDataChannel(label);
|
||||
assert_equals(channel.label, expected);
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel(label);
|
||||
assert_equals(dc.label, expected);
|
||||
}, `createDataChannel with label ${description} should succeed`);
|
||||
}
|
||||
|
||||
/*
|
||||
6.2. RTCDataChannel
|
||||
createDataChannel
|
||||
9. Let channel have an [[Ordered]] internal slot initialized to option's
|
||||
11. Let channel have an [[Ordered]] internal slot initialized to option's
|
||||
ordered member.
|
||||
*/
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const channel = pc.createDataChannel('', { ordered: false });
|
||||
assert_equals(channel.ordered, false);
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel('', { ordered: false });
|
||||
assert_equals(dc.ordered, false);
|
||||
}, 'createDataChannel with ordered false should succeed');
|
||||
|
||||
// true as the default value of a boolean is confusing because null is converted
|
||||
// to false while undefined is converted to true.
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const channel1 = pc.createDataChannel('', { ordered: null });
|
||||
assert_equals(channel1.ordered, false);
|
||||
const channel2 = pc.createDataChannel('', { ordered: undefined });
|
||||
assert_equals(channel2.ordered, true);
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc1 = pc.createDataChannel('', { ordered: null });
|
||||
assert_equals(dc1.ordered, false);
|
||||
const dc2 = pc.createDataChannel('', { ordered: undefined });
|
||||
assert_equals(dc2.ordered, true);
|
||||
}, 'createDataChannel with ordered null/undefined should succeed');
|
||||
|
||||
/*
|
||||
6.2. RTCDataChannel
|
||||
createDataChannel
|
||||
6. Let channel have an [[MaxPacketLifeTime]] internal slot initialized to
|
||||
7. Let channel have an [[MaxPacketLifeTime]] internal slot initialized to
|
||||
option's maxPacketLifeTime member, if present, otherwise null.
|
||||
*/
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection;
|
||||
const channel = pc.createDataChannel('', { maxPacketLifeTime: 0 });
|
||||
assert_equals(channel.maxPacketLifeTime, 0);
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel('', { maxPacketLifeTime: 0 });
|
||||
assert_equals(dc.maxPacketLifeTime, 0);
|
||||
}, 'createDataChannel with maxPacketLifeTime 0 should succeed');
|
||||
|
||||
/*
|
||||
6.2. RTCDataChannel
|
||||
createDataChannel
|
||||
7. Let channel have an [[MaxRetransmits]] internal slot initialized to
|
||||
10. Let channel have an [[MaxRetransmits]] internal slot initialized to
|
||||
option's maxRetransmits member, if present, otherwise null.
|
||||
*/
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection;
|
||||
const channel = pc.createDataChannel('', { maxRetransmits: 0 });
|
||||
assert_equals(channel.maxRetransmits, 0);
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel('', { maxRetransmits: 0 });
|
||||
assert_equals(dc.maxRetransmits, 0);
|
||||
}, 'createDataChannel with maxRetransmits 0 should succeed');
|
||||
|
||||
/*
|
||||
6.2. createDataChannel
|
||||
15. If both [[MaxPacketLifeTime]] and [[MaxRetransmits]] attributes are set
|
||||
(not null), throw a TypeError.
|
||||
18. If both [[MaxPacketLifeTime]] and [[MaxRetransmits]] attributes are set (not null),
|
||||
throw a TypeError.
|
||||
*/
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection;
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
pc.createDataChannel('', {
|
||||
maxPacketLifeTime: null,
|
||||
maxRetransmits: null
|
||||
});
|
||||
}, 'createDataChannel with both maxPacketLifeTime and maxRetransmits null should succeed');
|
||||
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection;
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
assert_throws(new TypeError(), () => pc.createDataChannel('', {
|
||||
maxPacketLifeTime: 0,
|
||||
maxRetransmits: 0
|
||||
}));
|
||||
}, 'createDataChannel with both maxPacketLifeTime and maxRetransmits should throw SyntaxError');
|
||||
assert_throws(new TypeError(), () => pc.createDataChannel('', {
|
||||
maxPacketLifeTime: 42,
|
||||
maxRetransmits: 42
|
||||
}));
|
||||
}, 'createDataChannel with both maxPacketLifeTime and maxRetransmits should throw TypeError');
|
||||
|
||||
/*
|
||||
6.2. RTCDataChannel
|
||||
createDataChannel
|
||||
10. Let channel have an [[Protocol]] internal slot initialized to option's
|
||||
12. Let channel have a [[DataChannelProtocol]] internal slot initialized to option's
|
||||
protocol member.
|
||||
*/
|
||||
const protocols = [
|
||||
|
@ -243,43 +303,36 @@ const protocols = [
|
|||
['lone surrogate', '\uD800', '\uFFFD'],
|
||||
];
|
||||
for (const [description, protocol, expected] of protocols) {
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection;
|
||||
const channel = pc.createDataChannel('', { protocol });
|
||||
assert_equals(channel.protocol, expected);
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel('', { protocol });
|
||||
assert_equals(dc.protocol, expected);
|
||||
}, `createDataChannel with protocol ${description} should succeed`);
|
||||
}
|
||||
|
||||
/*
|
||||
6.2. RTCDataChannel
|
||||
createDataChannel
|
||||
11. Let channel have an [[Negotiated]] internal slot initialized to option's
|
||||
negotiated member.
|
||||
*/
|
||||
test(() => {
|
||||
const pc = new RTCPeerConnection;
|
||||
const channel = pc.createDataChannel('', { negotiated: true });
|
||||
assert_equals(channel.negotiated, true);
|
||||
}, 'createDataChannel with negotiated true should succeed');
|
||||
|
||||
|
||||
/*
|
||||
6.2. RTCDataChannel
|
||||
createDataChannel
|
||||
10. If id is equal to 65535, which is greater than the maximum allowed ID
|
||||
of 65534 but still qualifies as an unsigned short, throw a TypeError.
|
||||
20. If [[DataChannelId]] is equal to 65535, which is greater than the maximum allowed
|
||||
ID of 65534 but still qualifies as an unsigned short, throw a TypeError.
|
||||
*/
|
||||
for (const id of [0, 1, 65534]) {
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const channel = pc.createDataChannel('', { id });
|
||||
assert_equals(channel.id, id);
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel('', { id });
|
||||
assert_equals(dc.id, id);
|
||||
}, `createDataChannel with id ${id} should succeed`);
|
||||
}
|
||||
|
||||
for (const id of [-1, 65535, 65536]) {
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
assert_throws(new TypeError(), () => pc.createDataChannel('', { id }));
|
||||
}, `createDataChannel with id ${id} should throw TypeError`);
|
||||
}
|
||||
|
@ -287,152 +340,383 @@ for (const id of [-1, 65535, 65536]) {
|
|||
/*
|
||||
6.2. RTCDataChannel
|
||||
createDataChannel
|
||||
12. Let channel have an [[DataChannelPriority]] internal slot initialized
|
||||
to option's priority member.
|
||||
|
||||
17. Let channel have an [[DataChannelPriority]] internal slot initialized to option's
|
||||
priority member.
|
||||
*/
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const channel = pc.createDataChannel('', { priority: 'high' });
|
||||
assert_equals(channel.priority, 'high');
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel('', { priority: 'high' });
|
||||
assert_equals(dc.priority, 'high');
|
||||
}, 'createDataChannel with priority "high" should succeed');
|
||||
|
||||
test(() => {
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
assert_throws(new TypeError(),
|
||||
() => pc.createDataChannel('', { priority: 'invalid' }));
|
||||
}, 'createDataChannel with invalid priority should throw TypeError');
|
||||
|
||||
/*
|
||||
6.2. createDataChannel
|
||||
13. If [[Negotiated]] is false and [[Label]] is longer than 65535 bytes
|
||||
long, throw a TypeError. */
|
||||
test(() => {
|
||||
5. If [[DataChannelLabel]] is longer than 65535 bytes, throw a TypeError.
|
||||
*/
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
assert_throws(new TypeError(), () =>
|
||||
pc.createDataChannel('', {
|
||||
label: ' '.repeat(65536),
|
||||
negotiated: false
|
||||
pc.createDataChannel('l'.repeat(65536)));
|
||||
|
||||
assert_throws(new TypeError(), () =>
|
||||
pc.createDataChannel('l'.repeat(65536), {
|
||||
negotiated: true,
|
||||
id: 42
|
||||
}));
|
||||
}, 'createDataChannel with negotiated false and long label should throw TypeError');
|
||||
}, 'createDataChannel with too long label should throw TypeError');
|
||||
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
assert_throws(new TypeError(), () =>
|
||||
pc.createDataChannel('\u00b5'.repeat(32768)));
|
||||
|
||||
assert_throws(new TypeError(), () =>
|
||||
pc.createDataChannel('\u00b5'.repeat(32768), {
|
||||
negotiated: true,
|
||||
id: 42
|
||||
}));
|
||||
}, 'createDataChannel with too long label (2 byte unicode) should throw TypeError');
|
||||
|
||||
/*
|
||||
6.2. label
|
||||
[...] Scripts are allowed to create multiple RTCDataChannel objects with the same label.
|
||||
[...]
|
||||
*/
|
||||
test(t => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const label = 'test';
|
||||
|
||||
pc.createDataChannel(label);
|
||||
pc.createDataChannel(label);
|
||||
}, 'createDataChannel with same label used twice should not throw');
|
||||
|
||||
/*
|
||||
6.2. createDataChannel
|
||||
14. If [[Negotiated]] is false and [[Protocol]] is longer than 65535 bytes long,
|
||||
throw a TypeError.
|
||||
13. If [[DataChannelProtocol]] is longer than 65535 bytes long, throw a TypeError.
|
||||
*/
|
||||
|
||||
test(() => {
|
||||
const pc = new RTCPeerConnection;
|
||||
const channel = pc.createDataChannel('', { negotiated: true });
|
||||
assert_equals(channel.negotiated, true);
|
||||
}, 'createDataChannel with negotiated true should succeed');
|
||||
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
assert_throws(new TypeError(), () =>
|
||||
pc.createDataChannel('', {
|
||||
protocol: ' '.repeat(65536),
|
||||
negotiated: false
|
||||
protocol: 'p'.repeat(65536)
|
||||
}));
|
||||
}, 'createDataChannel with negotiated false and long protocol should throw TypeError');
|
||||
|
||||
test(() => {
|
||||
assert_throws(new TypeError(), () =>
|
||||
pc.createDataChannel('', {
|
||||
protocol: 'p'.repeat(65536),
|
||||
negotiated: true,
|
||||
id: 42
|
||||
}));
|
||||
}, 'createDataChannel with too long protocol should throw TypeError');
|
||||
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const label = ' '.repeat(65536)
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const channel = pc.createDataChannel('', {
|
||||
label,
|
||||
protocol: ' '.repeat(65536),
|
||||
negotiated: true
|
||||
assert_throws(new TypeError(), () =>
|
||||
pc.createDataChannel('', {
|
||||
protocol: '\u00b6'.repeat(32768)
|
||||
}));
|
||||
|
||||
assert_throws(new TypeError(), () =>
|
||||
pc.createDataChannel('', {
|
||||
protocol: '\u00b6'.repeat(32768),
|
||||
negotiated: true,
|
||||
id: 42
|
||||
}));
|
||||
}, 'createDataChannel with too long protocol (2 byte unicode) should throw TypeError');
|
||||
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const label = 'l'.repeat(65535);
|
||||
const protocol = 'p'.repeat(65535);
|
||||
|
||||
const dc = pc.createDataChannel(label, {
|
||||
protocol: protocol
|
||||
});
|
||||
|
||||
assert_equals(channel.label, label);
|
||||
}, 'createDataChannel with negotiated true and long label and long protocol should succeed');
|
||||
assert_equals(dc.label, label);
|
||||
assert_equals(dc.protocol, protocol);
|
||||
}, 'createDataChannel with maximum length label and protocol should succeed');
|
||||
|
||||
/*
|
||||
6.2 createDataChannel
|
||||
15. Let channel have an [[DataChannelId]] internal slot initialized to option's id member,
|
||||
if it is present and [[Negotiated]] is true, otherwise null.
|
||||
|
||||
NOTE
|
||||
This means the id member will be ignored if the data channel is negotiated in-band; this
|
||||
is intentional. Data channels negotiated in-band should have IDs selected based on the
|
||||
DTLS role, as specified in [RTCWEB-DATA-PROTOCOL].
|
||||
*/
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection;
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel('', {
|
||||
negotiated: false,
|
||||
});
|
||||
assert_equals(dc.negotiated, false, 'Expect dc.negotiated to be false');
|
||||
}, 'createDataChannel with negotiated false should succeed');
|
||||
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection;
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
const dc = pc.createDataChannel('', {
|
||||
negotiated: false,
|
||||
id: 42
|
||||
});
|
||||
assert_equals(dc.negotiated, false, 'Expect dc.negotiated to be false');
|
||||
assert_equals(dc.id, null, 'Expect dc.id to be ignored (null)');
|
||||
}, 'createDataChannel with negotiated false and id 42 should ignore the id');
|
||||
|
||||
/*
|
||||
6.2. createDataChannel
|
||||
16. If [[Negotiated]] is true and [[DataChannelId]] is null, throw a TypeError.
|
||||
*/
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
assert_throws(new TypeError(), () =>
|
||||
pc.createDataChannel('test', {
|
||||
negotiated: true
|
||||
}));
|
||||
}, 'createDataChannel with negotiated true and id not defined should throw TypeError');
|
||||
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
|
||||
assert_throws(new TypeError(), () =>
|
||||
pc.createDataChannel('test', {
|
||||
negotiated: true,
|
||||
id: null
|
||||
}));
|
||||
}, 'createDataChannel with negotiated true and id null should throw TypeError');
|
||||
|
||||
/*
|
||||
4.4.1.6. Set the RTCSessionSessionDescription
|
||||
2.2.6. If description is of type "answer" or "pranswer", then run the
|
||||
following steps:
|
||||
1. If description initiates the establishment of a new SCTP association,
|
||||
as defined in [SCTP-SDP], Sections 10.3 and 10.4, set the value of
|
||||
connection's [[sctpTransport]] internal slot to a newly created RTCSctpTransport.
|
||||
2. 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].
|
||||
3. 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]. [...]
|
||||
|
||||
6.2. createDataChannel
|
||||
18. If the [[DataChannelId]] slot is null (due to no ID being passed into
|
||||
createDataChannel), 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].
|
||||
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.
|
||||
|
||||
Note
|
||||
If the [[DataChannelId]] slot is null after this step, it will be populated once
|
||||
the DTLS role is determined during the process of setting an RTCSessionDescription.
|
||||
*/
|
||||
promise_test(t => {
|
||||
promise_test(async (t) => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const negotiatedDc = pc1.createDataChannel('negotiated-channel', {
|
||||
negotiated: true,
|
||||
id: 42,
|
||||
});
|
||||
assert_equals(negotiatedDc.id, 42, 'Expect negotiatedDc.id to be 42');
|
||||
|
||||
const dc1 = pc1.createDataChannel('channel');
|
||||
assert_equals(dc1.id, null, 'Expect initial id to be null');
|
||||
|
||||
const offer = await pc1.createOffer();
|
||||
await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
|
||||
const answer = await pc2.createAnswer();
|
||||
await pc1.setRemoteDescription(answer);
|
||||
|
||||
assert_not_equals(dc1.id, null,
|
||||
'Expect dc1.id to be assigned after remote description has been set');
|
||||
|
||||
assert_greater_than_equal(dc1.id, 0,
|
||||
'Expect dc1.id to be set to valid unsigned short');
|
||||
|
||||
assert_less_than(dc1.id, 65535,
|
||||
'Expect dc1.id to be set to valid unsigned short');
|
||||
|
||||
const dc2 = pc1.createDataChannel('channel');
|
||||
|
||||
assert_not_equals(dc2.id, null,
|
||||
'Expect dc2.id to be assigned after remote description has been set');
|
||||
|
||||
assert_greater_than_equal(dc2.id, 0,
|
||||
'Expect dc2.id to be set to valid unsigned short');
|
||||
|
||||
assert_less_than(dc2.id, 65535,
|
||||
'Expect dc2.id to be set to valid unsigned short');
|
||||
|
||||
assert_not_equals(dc2, dc1,
|
||||
'Expect channels created from same label to be different');
|
||||
|
||||
assert_equals(dc2.label, dc1.label,
|
||||
'Expect different channels can have the same label but different id');
|
||||
|
||||
assert_not_equals(dc2.id, dc1.id,
|
||||
'Expect different channels can have the same label but different id');
|
||||
|
||||
assert_equals(negotiatedDc.id, 42,
|
||||
'Expect negotiatedDc.id to be 42 after remote description has been set');
|
||||
}, 'Channels created (after setRemoteDescription) should have id assigned');
|
||||
|
||||
test((t) => {
|
||||
const pc = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc.close());
|
||||
const channel1 = pc.createDataChannel('channel');
|
||||
assert_equals(channel1.id, null,
|
||||
'Expect initial id to be null');
|
||||
|
||||
return pc.createOffer()
|
||||
.then(offer =>
|
||||
pc.setLocalDescription(offer)
|
||||
.then(() => generateAnswer(offer)))
|
||||
.then(answer => pc.setRemoteDescription(answer))
|
||||
.then(() => {
|
||||
assert_not_equals(channel1.id, null,
|
||||
'Expect channel1.id to be assigned');
|
||||
|
||||
assert_greater_than_equal(channel1.id, 0,
|
||||
'Expect channel1.id to be set to valid unsigned short');
|
||||
|
||||
assert_less_than(channel1.id, 65535,
|
||||
'Expect channel1.id to be set to valid unsigned short');
|
||||
|
||||
const channel2 = pc.createDataChannel('channel');
|
||||
|
||||
assert_not_equals(channel2.id, null,
|
||||
'Expect channel2.id to be assigned');
|
||||
|
||||
assert_greater_than_equal(channel2.id, 0,
|
||||
'Expect channel2.id to be set to valid unsigned short');
|
||||
|
||||
assert_less_than(channel2.id, 65535,
|
||||
'Expect channel2.id to be set to valid unsigned short');
|
||||
|
||||
assert_not_equals(channel2, channel1,
|
||||
'Expect channels created from same label to be different');
|
||||
|
||||
assert_equals(channel2.label, channel1.label,
|
||||
'Expect different channnels can have the same label but different id');
|
||||
|
||||
assert_not_equals(channel2.id, channel1.id,
|
||||
'Expect different channnels can have the same label but different id');
|
||||
const dc1 = pc.createDataChannel('channel-1', {
|
||||
negotiated: true,
|
||||
id: 42,
|
||||
});
|
||||
}, 'Channels created after SCTP transport is established should have id assigned');
|
||||
assert_equals(dc1.id, 42,
|
||||
'Expect dc1.id to be 42');
|
||||
|
||||
const dc2 = pc.createDataChannel('channel-2', {
|
||||
negotiated: true,
|
||||
id: 43,
|
||||
});
|
||||
assert_equals(dc2.id, 43,
|
||||
'Expect dc2.id to be 43');
|
||||
|
||||
assert_throws('OperationError', () =>
|
||||
pc.createDataChannel('channel-3', {
|
||||
negotiated: true,
|
||||
id: 42,
|
||||
}));
|
||||
|
||||
}, 'Reusing a data channel id that is in use should throw OperationError');
|
||||
|
||||
// We've seen implementations behaving differently before and after the connection has been
|
||||
// established.
|
||||
promise_test(async (t) => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const dc1 = pc1.createDataChannel('channel-1', {
|
||||
negotiated: true,
|
||||
id: 42,
|
||||
});
|
||||
assert_equals(dc1.id, 42, 'Expect dc1.id to be 42');
|
||||
|
||||
const dc2 = pc1.createDataChannel('channel-2', {
|
||||
negotiated: true,
|
||||
id: 43,
|
||||
});
|
||||
assert_equals(dc2.id, 43, 'Expect dc2.id to be 43');
|
||||
|
||||
const offer = await pc1.createOffer();
|
||||
await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
|
||||
const answer = await pc2.createAnswer();
|
||||
await pc1.setRemoteDescription(answer);
|
||||
|
||||
assert_equals(dc1.id, 42, 'Expect dc1.id to be 42');
|
||||
|
||||
assert_equals(dc2.id, 43, 'Expect dc2.id to be 43');
|
||||
|
||||
assert_throws('OperationError', () =>
|
||||
pc1.createDataChannel('channel-3', {
|
||||
negotiated: true,
|
||||
id: 42,
|
||||
}));
|
||||
}, 'Reusing a data channel id that is in use (after setRemoteDescription) should throw ' +
|
||||
'OperationError');
|
||||
|
||||
promise_test(async (t) => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const dc1 = pc1.createDataChannel('channel-1');
|
||||
|
||||
const offer = await pc1.createOffer();
|
||||
await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
|
||||
const answer = await pc2.createAnswer();
|
||||
await pc1.setRemoteDescription(answer);
|
||||
|
||||
assert_not_equals(dc1.id, null,
|
||||
'Expect dc1.id to be assigned after remote description has been set');
|
||||
|
||||
assert_throws('OperationError', () =>
|
||||
pc1.createDataChannel('channel-2', {
|
||||
negotiated: true,
|
||||
id: dc1.id,
|
||||
}));
|
||||
}, 'Reusing a data channel id that is in use (after setRemoteDescription, negotiated via DCEP) ' +
|
||||
'should throw OperationError');
|
||||
|
||||
// Based on https://bugzilla.mozilla.org/show_bug.cgi?id=1441723
|
||||
promise_test(async (t) => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
await createDataChannelPair(pc1, pc2);
|
||||
|
||||
const dc = pc1.createDataChannel('');
|
||||
assert_equals(dc.readyState, 'connecting', 'Channel should be in the connecting state');
|
||||
}, 'New data channel should be in the connecting state after creation (after connection ' +
|
||||
'establishment)');
|
||||
|
||||
/*
|
||||
TODO
|
||||
6.1. createDataChannel
|
||||
18. If no available ID could be generated, or if the value of the
|
||||
id member of the dictionary is taken by an existing RTCDataChannel, throw
|
||||
a ResourceInUse exception.
|
||||
|
||||
Untestable
|
||||
6.1. createDataChannel
|
||||
16. If a setting, either [[MaxPacketLifeTime]] or [[MaxRetransmits]], has
|
||||
been set to indicate unreliable mode, and that value exceeds the maximum
|
||||
value supported by the user agent, the value MUST be set to the user
|
||||
agents maximum value.
|
||||
19. If a setting, either [[MaxPacketLifeTime]] or [[MaxRetransmits]], has been set to
|
||||
indicate unreliable mode, and that value exceeds the maximum value supported
|
||||
by the user agent, the value MUST be set to the user agents maximum value.
|
||||
|
||||
20. Create channel's associated underlying data transport and configure
|
||||
23. Return channel and continue the following steps in parallel.
|
||||
24. Create channel's associated underlying data transport and configure
|
||||
it according to the relevant properties of channel.
|
||||
|
||||
Tested in RTCPeerConnection-onnegotiationneeded.html
|
||||
21. If channel was the first RTCDataChannel created on connection, update
|
||||
the negotiation-needed flag for connection.
|
||||
22. If channel is the first RTCDataChannel created on connection, update the
|
||||
negotiation-needed flag for connection.
|
||||
|
||||
Issues
|
||||
w3c/webrtc-pc#1412
|
||||
ResourceInUse exception is not defined
|
||||
Tested in RTCDataChannel-id.html
|
||||
- Odd/even rules for '.id'
|
||||
|
||||
Coverage Report
|
||||
Tested 22
|
||||
Not Tested 1
|
||||
Untestable 2
|
||||
Total 25
|
||||
Tested in RTCDataChannel-dcep.html
|
||||
- Transmission of '.label' and further options
|
||||
*/
|
||||
</script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue