blob: 4ae9e784bad52093c442384c2bd0ee8174c60b9b [file] [log] [blame]
foolip72525e92017-04-24 09:31:031<!doctype html>
2<meta charset=utf-8>
Soares Chen6a9b7812017-06-08 13:25:473<title>RTCPeerConnection.prototype.createDataChannel</title>
foolip72525e92017-04-24 09:31:034<script src=/resources/testharness.js></script>
5<script src=/resources/testharnessreport.js></script>
youennf0e97d092019-03-23 18:02:566<script src="RTCPeerConnection-helper.js"></script>
foolip72525e92017-04-24 09:31:037<script>
8'use strict';
9
youennf0e97d092019-03-23 18:02:5610// Test is based on the following revision:
11// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
Soares Chen6a9b7812017-06-08 13:25:4712
13/*
14 6.1. RTCPeerConnection Interface Extensions
15
16 partial interface RTCPeerConnection {
youennf0e97d092019-03-23 18:02:5617 [...]
18 RTCDataChannel createDataChannel(USVString label,
19 optional RTCDataChannelInit dataChannelDict);
20 [...]
Soares Chen6a9b7812017-06-08 13:25:4721 };
22
23 6.2. RTCDataChannel
Soares Chen199b65f2017-06-21 09:20:3924
25 interface RTCDataChannel : EventTarget {
youennf0e97d092019-03-23 18:02:5626 readonly attribute USVString label;
27 readonly attribute boolean ordered;
28 readonly attribute unsigned short? maxPacketLifeTime;
29 readonly attribute unsigned short? maxRetransmits;
30 readonly attribute USVString protocol;
31 readonly attribute boolean negotiated;
32 readonly attribute unsigned short? id;
33 readonly attribute RTCPriorityType priority;
34 readonly attribute RTCDataChannelState readyState;
35 readonly attribute unsigned long bufferedAmount;
36 attribute unsigned long bufferedAmountLowThreshold;
37 [...]
38 attribute DOMString binaryType;
39 [...]
Soares Chen199b65f2017-06-21 09:20:3940 };
41
Soares Chen6a9b7812017-06-08 13:25:4742 dictionary RTCDataChannelInit {
youennf0e97d092019-03-23 18:02:5643 boolean ordered = true;
44 unsigned short maxPacketLifeTime;
45 unsigned short maxRetransmits;
46 USVString protocol = "";
47 boolean negotiated = false;
48 [EnforceRange]
49 unsigned short id;
50 RTCPriorityType priority = "low";
Soares Chen6a9b7812017-06-08 13:25:4751 };
Soares Chen199b65f2017-06-21 09:20:3952
53 4.9.1. RTCPriorityType Enum
54
55 enum RTCPriorityType {
56 "very-low",
57 "low",
58 "medium",
59 "high"
60 };
Soares Chen6a9b7812017-06-08 13:25:4761 */
foolip72525e92017-04-24 09:31:0362
Harald Alvestrandf6cf3bd2019-04-04 12:39:5763test(t => {
Soares Chen6a9b7812017-06-08 13:25:4764 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:5665 t.add_cleanup(() => pc.close());
66
Soares Chen6a9b7812017-06-08 13:25:4767 assert_equals(pc.createDataChannel.length, 1);
68 assert_throws(new TypeError(), () => pc.createDataChannel());
69}, 'createDataChannel with no argument should throw TypeError');
70
71/*
72 6.2. createDataChannel
73 2. If connection's [[isClosed]] slot is true, throw an InvalidStateError.
74 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:5775test(t => {
Soares Chen6a9b7812017-06-08 13:25:4776 const pc = new RTCPeerConnection();
foolip72525e92017-04-24 09:31:0377 pc.close();
78 assert_equals(pc.signalingState, 'closed', 'signaling state');
79 assert_throws('InvalidStateError', () => pc.createDataChannel(''));
Soares Chen6a9b7812017-06-08 13:25:4780}, 'createDataChannel with closed connection should throw InvalidStateError');
foolip72525e92017-04-24 09:31:0381
Soares Chen6a9b7812017-06-08 13:25:4782/*
Soares Chen199b65f2017-06-21 09:20:3983 6.1. createDataChannel
youennf0e97d092019-03-23 18:02:5684 4. Let channel have a [[DataChannelLabel]] internal slot initialized to the value of the
Soares Chen199b65f2017-06-21 09:20:3985 first argument.
youennf0e97d092019-03-23 18:02:5686 6. Let options be the second argument.
87 7. Let channel have an [[MaxPacketLifeTime]] internal slot initialized to
Soares Chen199b65f2017-06-21 09:20:3988 option's maxPacketLifeTime member, if present, otherwise null.
youennf0e97d092019-03-23 18:02:5689 8. Let channel have a [[ReadyState]] internal slot initialized to "connecting".
90 9. Let channel have a [[BufferedAmount]] internal slot initialized to 0.
91 10. Let channel have an [[MaxRetransmits]] internal slot initialized to
Soares Chen199b65f2017-06-21 09:20:3992 option's maxRetransmits member, if present, otherwise null.
youennf0e97d092019-03-23 18:02:5693 11. Let channel have an [[Ordered]] internal slot initialized to option's
Soares Chen199b65f2017-06-21 09:20:3994 ordered member.
youennf0e97d092019-03-23 18:02:5695 12. Let channel have a [[DataChannelProtocol]] internal slot initialized to option's
Soares Chen199b65f2017-06-21 09:20:3996 protocol member.
youennf0e97d092019-03-23 18:02:5697 14. Let channel have a [[Negotiated]] internal slot initialized to option's negotiated
98 member.
99 15. Let channel have an [[DataChannelId]] internal slot initialized to option's id
100 member, if it is present and [[Negotiated]] is true, otherwise null.
101 17. Let channel have an [[DataChannelPriority]] internal slot initialized to option's
102 priority member.
103 21. If the [[DataChannelId]] slot is null (due to no ID being passed into
104 createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
105 transport has already been negotiated, then initialize [[DataChannelId]] to a value
106 generated by the user agent, according to [RTCWEB-DATA-PROTOCOL], and skip
107 to the next step. If no available ID could be generated, or if the value of the
108 [[DataChannelId]] slot is being used by an existing RTCDataChannel, throw an
109 OperationError exception.
110
111 Note
112 If the [[DataChannelId]] slot is null after this step, it will be populated once
113 the DTLS role is determined during the process of setting an RTCSessionDescription.
114 22. If channel is the first RTCDataChannel created on connection, update the
115 negotiation-needed flag for connection.
116
Soares Chen199b65f2017-06-21 09:20:39117
118 6.2. RTCDataChannel
119
120 A RTCDataChannel, created with createDataChannel or dispatched via a
121 RTCDataChannelEvent, MUST initially be in the connecting state
122
youennf0e97d092019-03-23 18:02:56123 bufferedAmountLowThreshold
124 [...] The bufferedAmountLowThreshold is initially zero on each new RTCDataChannel,
125 but the application may change its value at any time.
126
Soares Chen199b65f2017-06-21 09:20:39127 binaryType
youennf0e97d092019-03-23 18:02:56128 [...] When a RTCDataChannel object is created, the binaryType attribute MUST
Soares Chen199b65f2017-06-21 09:20:39129 be initialized to the string "blob".
Soares Chen6a9b7812017-06-08 13:25:47130 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:57131test(t => {
Soares Chen6a9b7812017-06-08 13:25:47132 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56133 t.add_cleanup(() => pc.close());
Soares Chen199b65f2017-06-21 09:20:39134
youennf0e97d092019-03-23 18:02:56135 const dc = pc.createDataChannel('');
136
137 assert_true(dc instanceof RTCDataChannel, 'is RTCDataChannel');
138 assert_equals(dc.label, '');
139 assert_equals(dc.ordered, true);
140 assert_equals(dc.maxPacketLifeTime, null);
141 assert_equals(dc.maxRetransmits, null);
142 assert_equals(dc.protocol, '');
143 assert_equals(dc.negotiated, false);
Taylor Brandstetterce56f0e2017-05-09 13:53:14144 // Since no offer/answer exchange has occurred yet, the DTLS role is unknown
145 // and so the ID should be null.
youennf0e97d092019-03-23 18:02:56146 assert_equals(dc.id, null);
147 assert_equals(dc.priority, 'low');
148 assert_equals(dc.readyState, 'connecting');
149 assert_equals(dc.bufferedAmount, 0);
150 assert_equals(dc.bufferedAmountLowThreshold, 0);
151 assert_equals(dc.binaryType, 'blob');
Soares Chen6a9b7812017-06-08 13:25:47152}, 'createDataChannel attribute default values');
foolip72525e92017-04-24 09:31:03153
Harald Alvestrandf6cf3bd2019-04-04 12:39:57154test(t => {
Soares Chen199b65f2017-06-21 09:20:39155 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56156 t.add_cleanup(() => pc.close());
157
158 const dc = pc.createDataChannel('test', {
Soares Chen199b65f2017-06-21 09:20:39159 ordered: false,
Soares Chen199b65f2017-06-21 09:20:39160 maxRetransmits: 1,
Harald Alvestrandf6cf3bd2019-04-04 12:39:57161 // Note: maxPacketLifeTime is not set in this test.
Soares Chen199b65f2017-06-21 09:20:39162 protocol: 'custom',
163 negotiated: true,
164 id: 3,
165 priority: 'high'
166 });
167
youennf0e97d092019-03-23 18:02:56168 assert_true(dc instanceof RTCDataChannel, 'is RTCDataChannel');
169 assert_equals(dc.label, 'test');
170 assert_equals(dc.ordered, false);
171 assert_equals(dc.maxPacketLifeTime, null);
172 assert_equals(dc.maxRetransmits, 1);
173 assert_equals(dc.protocol, 'custom');
174 assert_equals(dc.negotiated, true);
175 assert_equals(dc.id, 3);
176 assert_equals(dc.priority, 'high');
177 assert_equals(dc.readyState, 'connecting');
178 assert_equals(dc.bufferedAmount, 0);
179 assert_equals(dc.bufferedAmountLowThreshold, 0);
180 assert_equals(dc.binaryType, 'blob');
Harald Alvestrandf6cf3bd2019-04-04 12:39:57181
182 const dc2 = pc.createDataChannel('test2', {
183 ordered: false,
184 maxPacketLifeTime: 42
185 });
186 assert_equals(dc2.label, 'test2');
187 assert_equals(dc2.maxPacketLifeTime, 42);
188 assert_equals(dc.maxRetransmits, null);
Soares Chen199b65f2017-06-21 09:20:39189}, 'createDataChannel with provided parameters should initialize attributes to provided values');
Soares Chen6a9b7812017-06-08 13:25:47190
191/*
192 6.2. createDataChannel
youennf0e97d092019-03-23 18:02:56193 4. Let channel have a [[DataChannelLabel]] internal slot initialized to the value of the
Soares Chen199b65f2017-06-21 09:20:39194 first argument.
Soares Chen6a9b7812017-06-08 13:25:47195
196 [ECMA262] 7.1.12. ToString(argument)
197 undefined -> "undefined"
198 null -> "null"
199
200 [WebIDL] 3.10.15. Convert a DOMString to a sequence of Unicode scalar values
201 */
foolip72525e92017-04-24 09:31:03202const labels = [
203 ['"foo"', 'foo', 'foo'],
204 ['null', null, 'null'],
205 ['undefined', undefined, 'undefined'],
206 ['lone surrogate', '\uD800', '\uFFFD'],
207];
208for (const [description, label, expected] of labels) {
Harald Alvestrandf6cf3bd2019-04-04 12:39:57209 test(t => {
foolip72525e92017-04-24 09:31:03210 const pc = new RTCPeerConnection;
youennf0e97d092019-03-23 18:02:56211 t.add_cleanup(() => pc.close());
212
213 const dc = pc.createDataChannel(label);
214 assert_equals(dc.label, expected);
Soares Chen6a9b7812017-06-08 13:25:47215 }, `createDataChannel with label ${description} should succeed`);
foolip72525e92017-04-24 09:31:03216}
217
Soares Chen6a9b7812017-06-08 13:25:47218/*
219 6.2. RTCDataChannel
Soares Chen199b65f2017-06-21 09:20:39220 createDataChannel
youennf0e97d092019-03-23 18:02:56221 11. Let channel have an [[Ordered]] internal slot initialized to option's
Soares Chen199b65f2017-06-21 09:20:39222 ordered member.
Soares Chen6a9b7812017-06-08 13:25:47223 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:57224test(t => {
Soares Chen6a9b7812017-06-08 13:25:47225 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56226 t.add_cleanup(() => pc.close());
227
228 const dc = pc.createDataChannel('', { ordered: false });
229 assert_equals(dc.ordered, false);
Soares Chen6a9b7812017-06-08 13:25:47230}, 'createDataChannel with ordered false should succeed');
foolip72525e92017-04-24 09:31:03231
232// true as the default value of a boolean is confusing because null is converted
233// to false while undefined is converted to true.
Harald Alvestrandf6cf3bd2019-04-04 12:39:57234test(t => {
Soares Chen6a9b7812017-06-08 13:25:47235 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56236 t.add_cleanup(() => pc.close());
237
238 const dc1 = pc.createDataChannel('', { ordered: null });
239 assert_equals(dc1.ordered, false);
240 const dc2 = pc.createDataChannel('', { ordered: undefined });
241 assert_equals(dc2.ordered, true);
Soares Chen6a9b7812017-06-08 13:25:47242}, 'createDataChannel with ordered null/undefined should succeed');
foolip72525e92017-04-24 09:31:03243
Soares Chen6a9b7812017-06-08 13:25:47244/*
245 6.2. RTCDataChannel
Soares Chen199b65f2017-06-21 09:20:39246 createDataChannel
youennf0e97d092019-03-23 18:02:56247 7. Let channel have an [[MaxPacketLifeTime]] internal slot initialized to
Soares Chen199b65f2017-06-21 09:20:39248 option's maxPacketLifeTime member, if present, otherwise null.
Soares Chen6a9b7812017-06-08 13:25:47249 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:57250test(t => {
foolip72525e92017-04-24 09:31:03251 const pc = new RTCPeerConnection;
youennf0e97d092019-03-23 18:02:56252 t.add_cleanup(() => pc.close());
253
254 const dc = pc.createDataChannel('', { maxPacketLifeTime: 0 });
255 assert_equals(dc.maxPacketLifeTime, 0);
Soares Chen6a9b7812017-06-08 13:25:47256}, 'createDataChannel with maxPacketLifeTime 0 should succeed');
foolip72525e92017-04-24 09:31:03257
Soares Chen6a9b7812017-06-08 13:25:47258/*
259 6.2. RTCDataChannel
Soares Chen199b65f2017-06-21 09:20:39260 createDataChannel
youennf0e97d092019-03-23 18:02:56261 10. Let channel have an [[MaxRetransmits]] internal slot initialized to
Soares Chen199b65f2017-06-21 09:20:39262 option's maxRetransmits member, if present, otherwise null.
Soares Chen6a9b7812017-06-08 13:25:47263 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:57264test(t => {
foolip72525e92017-04-24 09:31:03265 const pc = new RTCPeerConnection;
youennf0e97d092019-03-23 18:02:56266 t.add_cleanup(() => pc.close());
267
268 const dc = pc.createDataChannel('', { maxRetransmits: 0 });
269 assert_equals(dc.maxRetransmits, 0);
Soares Chen6a9b7812017-06-08 13:25:47270}, 'createDataChannel with maxRetransmits 0 should succeed');
foolip72525e92017-04-24 09:31:03271
Soares Chen6a9b7812017-06-08 13:25:47272/*
273 6.2. createDataChannel
youennf0e97d092019-03-23 18:02:56274 18. If both [[MaxPacketLifeTime]] and [[MaxRetransmits]] attributes are set (not null),
275 throw a TypeError.
Soares Chen6a9b7812017-06-08 13:25:47276 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:57277test(t => {
foolip72525e92017-04-24 09:31:03278 const pc = new RTCPeerConnection;
youennf0e97d092019-03-23 18:02:56279 t.add_cleanup(() => pc.close());
280
281 pc.createDataChannel('', {
Harald Alvestrandf6cf3bd2019-04-04 12:39:57282 maxPacketLifeTime: undefined,
283 maxRetransmits: undefined
youennf0e97d092019-03-23 18:02:56284 });
Harald Alvestrandf6cf3bd2019-04-04 12:39:57285}, 'createDataChannel with both maxPacketLifeTime and maxRetransmits undefined should succeed');
youennf0e97d092019-03-23 18:02:56286
Harald Alvestrandf6cf3bd2019-04-04 12:39:57287test(t => {
youennf0e97d092019-03-23 18:02:56288 const pc = new RTCPeerConnection;
289 t.add_cleanup(() => pc.close());
290
Soares Chen199b65f2017-06-21 09:20:39291 assert_throws(new TypeError(), () => pc.createDataChannel('', {
foolip72525e92017-04-24 09:31:03292 maxPacketLifeTime: 0,
293 maxRetransmits: 0
294 }));
youennf0e97d092019-03-23 18:02:56295 assert_throws(new TypeError(), () => pc.createDataChannel('', {
296 maxPacketLifeTime: 42,
297 maxRetransmits: 42
298 }));
299}, 'createDataChannel with both maxPacketLifeTime and maxRetransmits should throw TypeError');
foolip72525e92017-04-24 09:31:03300
Soares Chen6a9b7812017-06-08 13:25:47301/*
302 6.2. RTCDataChannel
Soares Chen199b65f2017-06-21 09:20:39303 createDataChannel
youennf0e97d092019-03-23 18:02:56304 12. Let channel have a [[DataChannelProtocol]] internal slot initialized to option's
Soares Chen199b65f2017-06-21 09:20:39305 protocol member.
Soares Chen6a9b7812017-06-08 13:25:47306 */
foolip72525e92017-04-24 09:31:03307const protocols = [
308 ['"foo"', 'foo', 'foo'],
309 ['null', null, 'null'],
310 ['undefined', undefined, ''],
311 ['lone surrogate', '\uD800', '\uFFFD'],
312];
313for (const [description, protocol, expected] of protocols) {
Harald Alvestrandf6cf3bd2019-04-04 12:39:57314 test(t => {
foolip72525e92017-04-24 09:31:03315 const pc = new RTCPeerConnection;
youennf0e97d092019-03-23 18:02:56316 t.add_cleanup(() => pc.close());
317
318 const dc = pc.createDataChannel('', { protocol });
319 assert_equals(dc.protocol, expected);
Soares Chen6a9b7812017-06-08 13:25:47320 }, `createDataChannel with protocol ${description} should succeed`);
foolip72525e92017-04-24 09:31:03321}
322
Soares Chen6a9b7812017-06-08 13:25:47323/*
324 6.2. RTCDataChannel
Soares Chen199b65f2017-06-21 09:20:39325 createDataChannel
youennf0e97d092019-03-23 18:02:56326 20. If [[DataChannelId]] is equal to 65535, which is greater than the maximum allowed
327 ID of 65534 but still qualifies as an unsigned short, throw a TypeError.
Soares Chen6a9b7812017-06-08 13:25:47328 */
329for (const id of [0, 1, 65534]) {
Harald Alvestrandf6cf3bd2019-04-04 12:39:57330 test(t => {
Soares Chen6a9b7812017-06-08 13:25:47331 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56332 t.add_cleanup(() => pc.close());
333
334 const dc = pc.createDataChannel('', { id });
335 assert_equals(dc.id, id);
Soares Chen6a9b7812017-06-08 13:25:47336 }, `createDataChannel with id ${id} should succeed`);
foolip72525e92017-04-24 09:31:03337}
338
Soares Chen6a9b7812017-06-08 13:25:47339for (const id of [-1, 65535, 65536]) {
Harald Alvestrandf6cf3bd2019-04-04 12:39:57340 test(t => {
Soares Chen6a9b7812017-06-08 13:25:47341 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56342 t.add_cleanup(() => pc.close());
343
Soares Chen6a9b7812017-06-08 13:25:47344 assert_throws(new TypeError(), () => pc.createDataChannel('', { id }));
345 }, `createDataChannel with id ${id} should throw TypeError`);
346}
347
348/*
349 6.2. RTCDataChannel
Soares Chen199b65f2017-06-21 09:20:39350 createDataChannel
youennf0e97d092019-03-23 18:02:56351 17. Let channel have an [[DataChannelPriority]] internal slot initialized to option's
352 priority member.
Soares Chen6a9b7812017-06-08 13:25:47353 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:57354test(t => {
Soares Chen6a9b7812017-06-08 13:25:47355 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56356 t.add_cleanup(() => pc.close());
357
358 const dc = pc.createDataChannel('', { priority: 'high' });
359 assert_equals(dc.priority, 'high');
Soares Chen6a9b7812017-06-08 13:25:47360}, 'createDataChannel with priority "high" should succeed');
361
Harald Alvestrandf6cf3bd2019-04-04 12:39:57362test(t => {
Soares Chen6a9b7812017-06-08 13:25:47363 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56364 t.add_cleanup(() => pc.close());
365
Soares Chen6a9b7812017-06-08 13:25:47366 assert_throws(new TypeError(),
367 () => pc.createDataChannel('', { priority: 'invalid' }));
368}, 'createDataChannel with invalid priority should throw TypeError');
369
370/*
371 6.2. createDataChannel
youennf0e97d092019-03-23 18:02:56372 5. If [[DataChannelLabel]] is longer than 65535 bytes, throw a TypeError.
373 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:57374test(t => {
Soares Chen6a9b7812017-06-08 13:25:47375 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56376 t.add_cleanup(() => pc.close());
377
Soares Chen6a9b7812017-06-08 13:25:47378 assert_throws(new TypeError(), () =>
youennf0e97d092019-03-23 18:02:56379 pc.createDataChannel('l'.repeat(65536)));
380
381 assert_throws(new TypeError(), () =>
382 pc.createDataChannel('l'.repeat(65536), {
383 negotiated: true,
384 id: 42
Soares Chen6a9b7812017-06-08 13:25:47385 }));
youennf0e97d092019-03-23 18:02:56386}, 'createDataChannel with too long label should throw TypeError');
387
Harald Alvestrandf6cf3bd2019-04-04 12:39:57388test(t => {
youennf0e97d092019-03-23 18:02:56389 const pc = new RTCPeerConnection();
390 t.add_cleanup(() => pc.close());
391
392 assert_throws(new TypeError(), () =>
393 pc.createDataChannel('\u00b5'.repeat(32768)));
394
395 assert_throws(new TypeError(), () =>
396 pc.createDataChannel('\u00b5'.repeat(32768), {
397 negotiated: true,
398 id: 42
399 }));
400}, 'createDataChannel with too long label (2 byte unicode) should throw TypeError');
401
402/*
403 6.2. label
404 [...] Scripts are allowed to create multiple RTCDataChannel objects with the same label.
405 [...]
406 */
407test(t => {
408 const pc = new RTCPeerConnection();
409 t.add_cleanup(() => pc.close());
410
411 const label = 'test';
412
413 pc.createDataChannel(label);
414 pc.createDataChannel(label);
415}, 'createDataChannel with same label used twice should not throw');
Soares Chen6a9b7812017-06-08 13:25:47416
417/*
418 6.2. createDataChannel
youennf0e97d092019-03-23 18:02:56419 13. If [[DataChannelProtocol]] is longer than 65535 bytes long, throw a TypeError.
Soares Chen6a9b7812017-06-08 13:25:47420 */
youennf0e97d092019-03-23 18:02:56421
Harald Alvestrandf6cf3bd2019-04-04 12:39:57422test(t => {
youennf0e97d092019-03-23 18:02:56423 const pc = new RTCPeerConnection;
Harald Alvestrandf6cf3bd2019-04-04 12:39:57424 t.add_cleanup(() => pc.close());
425 const channel = pc.createDataChannel('', { negotiated: true, id: 42 });
youennf0e97d092019-03-23 18:02:56426 assert_equals(channel.negotiated, true);
Harald Alvestrandf6cf3bd2019-04-04 12:39:57427}, 'createDataChannel with negotiated true and id should succeed');
youennf0e97d092019-03-23 18:02:56428
Harald Alvestrandf6cf3bd2019-04-04 12:39:57429test(t => {
Soares Chen6a9b7812017-06-08 13:25:47430 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56431 t.add_cleanup(() => pc.close());
432
Soares Chen6a9b7812017-06-08 13:25:47433 assert_throws(new TypeError(), () =>
434 pc.createDataChannel('', {
youennf0e97d092019-03-23 18:02:56435 protocol: 'p'.repeat(65536)
Soares Chen6a9b7812017-06-08 13:25:47436 }));
Soares Chen6a9b7812017-06-08 13:25:47437
youennf0e97d092019-03-23 18:02:56438 assert_throws(new TypeError(), () =>
439 pc.createDataChannel('', {
440 protocol: 'p'.repeat(65536),
441 negotiated: true,
442 id: 42
443 }));
444}, 'createDataChannel with too long protocol should throw TypeError');
445
Harald Alvestrandf6cf3bd2019-04-04 12:39:57446test(t => {
Soares Chen6a9b7812017-06-08 13:25:47447 const pc = new RTCPeerConnection();
youennf0e97d092019-03-23 18:02:56448 t.add_cleanup(() => pc.close());
Soares Chen199b65f2017-06-21 09:20:39449
youennf0e97d092019-03-23 18:02:56450 assert_throws(new TypeError(), () =>
451 pc.createDataChannel('', {
452 protocol: '\u00b6'.repeat(32768)
453 }));
454
455 assert_throws(new TypeError(), () =>
456 pc.createDataChannel('', {
457 protocol: '\u00b6'.repeat(32768),
458 negotiated: true,
459 id: 42
460 }));
461}, 'createDataChannel with too long protocol (2 byte unicode) should throw TypeError');
462
Harald Alvestrandf6cf3bd2019-04-04 12:39:57463test(t => {
youennf0e97d092019-03-23 18:02:56464 const pc = new RTCPeerConnection();
465 t.add_cleanup(() => pc.close());
466
467 const label = 'l'.repeat(65535);
468 const protocol = 'p'.repeat(65535);
469
470 const dc = pc.createDataChannel(label, {
471 protocol: protocol
Soares Chen6a9b7812017-06-08 13:25:47472 });
Soares Chen199b65f2017-06-21 09:20:39473
youennf0e97d092019-03-23 18:02:56474 assert_equals(dc.label, label);
475 assert_equals(dc.protocol, protocol);
476}, 'createDataChannel with maximum length label and protocol should succeed');
477
478/*
479 6.2 createDataChannel
480 15. Let channel have an [[DataChannelId]] internal slot initialized to option's id member,
481 if it is present and [[Negotiated]] is true, otherwise null.
482
483 NOTE
484 This means the id member will be ignored if the data channel is negotiated in-band; this
485 is intentional. Data channels negotiated in-band should have IDs selected based on the
486 DTLS role, as specified in [RTCWEB-DATA-PROTOCOL].
487 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:57488test(t => {
youennf0e97d092019-03-23 18:02:56489 const pc = new RTCPeerConnection;
490 t.add_cleanup(() => pc.close());
491
492 const dc = pc.createDataChannel('', {
493 negotiated: false,
494 });
495 assert_equals(dc.negotiated, false, 'Expect dc.negotiated to be false');
496}, 'createDataChannel with negotiated false should succeed');
497
Harald Alvestrandf6cf3bd2019-04-04 12:39:57498test(t => {
youennf0e97d092019-03-23 18:02:56499 const pc = new RTCPeerConnection;
500 t.add_cleanup(() => pc.close());
501
502 const dc = pc.createDataChannel('', {
503 negotiated: false,
504 id: 42
505 });
506 assert_equals(dc.negotiated, false, 'Expect dc.negotiated to be false');
507 assert_equals(dc.id, null, 'Expect dc.id to be ignored (null)');
508}, 'createDataChannel with negotiated false and id 42 should ignore the id');
509
510/*
511 6.2. createDataChannel
512 16. If [[Negotiated]] is true and [[DataChannelId]] is null, throw a TypeError.
513 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:57514test(t => {
youennf0e97d092019-03-23 18:02:56515 const pc = new RTCPeerConnection();
516 t.add_cleanup(() => pc.close());
517
518 assert_throws(new TypeError(), () =>
519 pc.createDataChannel('test', {
520 negotiated: true
521 }));
522}, 'createDataChannel with negotiated true and id not defined should throw TypeError');
523
Soares Chen6a9b7812017-06-08 13:25:47524/*
Soares Chen199b65f2017-06-21 09:20:39525 4.4.1.6. Set the RTCSessionSessionDescription
526 2.2.6. If description is of type "answer" or "pranswer", then run the
527 following steps:
youennf0e97d092019-03-23 18:02:56528 3. If description negotiates the DTLS role of the SCTP transport, and there is an
529 RTCDataChannel with a null id, then generate an ID according to
530 [RTCWEB-DATA-PROTOCOL]. [...]
Soares Chen199b65f2017-06-21 09:20:39531
youennf0e97d092019-03-23 18:02:56532 6.1. createDataChannel
533 21. If the [[DataChannelId]] slot is null (due to no ID being passed into
534 createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
535 transport has already been negotiated, then initialize [[DataChannelId]] to a value
536 generated by the user agent, according to [RTCWEB-DATA-PROTOCOL], and skip
537 to the next step. If no available ID could be generated, or if the value of the
538 [[DataChannelId]] slot is being used by an existing RTCDataChannel, throw an
539 OperationError exception.
540
541 Note
542 If the [[DataChannelId]] slot is null after this step, it will be populated once
543 the DTLS role is determined during the process of setting an RTCSessionDescription.
Soares Chen199b65f2017-06-21 09:20:39544 */
Harald Alvestrandf6cf3bd2019-04-04 12:39:57545promise_test(async t => {
youennf0e97d092019-03-23 18:02:56546 const pc1 = new RTCPeerConnection();
547 const pc2 = new RTCPeerConnection();
548 t.add_cleanup(() => pc1.close());
549 t.add_cleanup(() => pc2.close());
550
551 const negotiatedDc = pc1.createDataChannel('negotiated-channel', {
552 negotiated: true,
553 id: 42,
554 });
555 assert_equals(negotiatedDc.id, 42, 'Expect negotiatedDc.id to be 42');
556
557 const dc1 = pc1.createDataChannel('channel');
558 assert_equals(dc1.id, null, 'Expect initial id to be null');
559
560 const offer = await pc1.createOffer();
561 await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
562 const answer = await pc2.createAnswer();
563 await pc1.setRemoteDescription(answer);
564
565 assert_not_equals(dc1.id, null,
566 'Expect dc1.id to be assigned after remote description has been set');
567
568 assert_greater_than_equal(dc1.id, 0,
569 'Expect dc1.id to be set to valid unsigned short');
570
571 assert_less_than(dc1.id, 65535,
572 'Expect dc1.id to be set to valid unsigned short');
573
574 const dc2 = pc1.createDataChannel('channel');
575
576 assert_not_equals(dc2.id, null,
577 'Expect dc2.id to be assigned after remote description has been set');
578
579 assert_greater_than_equal(dc2.id, 0,
580 'Expect dc2.id to be set to valid unsigned short');
581
582 assert_less_than(dc2.id, 65535,
583 'Expect dc2.id to be set to valid unsigned short');
584
585 assert_not_equals(dc2, dc1,
586 'Expect channels created from same label to be different');
587
588 assert_equals(dc2.label, dc1.label,
589 'Expect different channels can have the same label but different id');
590
591 assert_not_equals(dc2.id, dc1.id,
592 'Expect different channels can have the same label but different id');
593
594 assert_equals(negotiatedDc.id, 42,
595 'Expect negotiatedDc.id to be 42 after remote description has been set');
596}, 'Channels created (after setRemoteDescription) should have id assigned');
597
Harald Alvestrandf6cf3bd2019-04-04 12:39:57598test(t => {
Soares Chen199b65f2017-06-21 09:20:39599 const pc = new RTCPeerConnection();
Philipp Hancke1622a022018-06-11 10:00:53600 t.add_cleanup(() => pc.close());
Soares Chen199b65f2017-06-21 09:20:39601
youennf0e97d092019-03-23 18:02:56602 const dc1 = pc.createDataChannel('channel-1', {
603 negotiated: true,
604 id: 42,
Soares Chen199b65f2017-06-21 09:20:39605 });
youennf0e97d092019-03-23 18:02:56606 assert_equals(dc1.id, 42,
607 'Expect dc1.id to be 42');
608
609 const dc2 = pc.createDataChannel('channel-2', {
610 negotiated: true,
611 id: 43,
612 });
613 assert_equals(dc2.id, 43,
614 'Expect dc2.id to be 43');
615
616 assert_throws('OperationError', () =>
617 pc.createDataChannel('channel-3', {
618 negotiated: true,
619 id: 42,
620 }));
621
622}, 'Reusing a data channel id that is in use should throw OperationError');
623
624// We've seen implementations behaving differently before and after the connection has been
625// established.
Harald Alvestrandf6cf3bd2019-04-04 12:39:57626promise_test(async t => {
youennf0e97d092019-03-23 18:02:56627 const pc1 = new RTCPeerConnection();
628 const pc2 = new RTCPeerConnection();
629 t.add_cleanup(() => pc1.close());
630 t.add_cleanup(() => pc2.close());
631
632 const dc1 = pc1.createDataChannel('channel-1', {
633 negotiated: true,
634 id: 42,
635 });
636 assert_equals(dc1.id, 42, 'Expect dc1.id to be 42');
637
638 const dc2 = pc1.createDataChannel('channel-2', {
639 negotiated: true,
640 id: 43,
641 });
642 assert_equals(dc2.id, 43, 'Expect dc2.id to be 43');
643
644 const offer = await pc1.createOffer();
645 await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
646 const answer = await pc2.createAnswer();
647 await pc1.setRemoteDescription(answer);
648
649 assert_equals(dc1.id, 42, 'Expect dc1.id to be 42');
650
651 assert_equals(dc2.id, 43, 'Expect dc2.id to be 43');
652
653 assert_throws('OperationError', () =>
654 pc1.createDataChannel('channel-3', {
655 negotiated: true,
656 id: 42,
657 }));
658}, 'Reusing a data channel id that is in use (after setRemoteDescription) should throw ' +
659 'OperationError');
660
Harald Alvestrandf6cf3bd2019-04-04 12:39:57661promise_test(async t => {
youennf0e97d092019-03-23 18:02:56662 const pc1 = new RTCPeerConnection();
663 const pc2 = new RTCPeerConnection();
664 t.add_cleanup(() => pc1.close());
665 t.add_cleanup(() => pc2.close());
666
667 const dc1 = pc1.createDataChannel('channel-1');
668
669 const offer = await pc1.createOffer();
670 await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
671 const answer = await pc2.createAnswer();
672 await pc1.setRemoteDescription(answer);
673
674 assert_not_equals(dc1.id, null,
675 'Expect dc1.id to be assigned after remote description has been set');
676
677 assert_throws('OperationError', () =>
678 pc1.createDataChannel('channel-2', {
679 negotiated: true,
680 id: dc1.id,
681 }));
682}, 'Reusing a data channel id that is in use (after setRemoteDescription, negotiated via DCEP) ' +
683 'should throw OperationError');
684
685// Based on https://bugzilla.mozilla.org/show_bug.cgi?id=1441723
Harald Alvestrandf6cf3bd2019-04-04 12:39:57686promise_test(async t => {
youennf0e97d092019-03-23 18:02:56687 const pc1 = new RTCPeerConnection();
688 const pc2 = new RTCPeerConnection();
689 t.add_cleanup(() => pc1.close());
690 t.add_cleanup(() => pc2.close());
691
692 await createDataChannelPair(pc1, pc2);
693
694 const dc = pc1.createDataChannel('');
695 assert_equals(dc.readyState, 'connecting', 'Channel should be in the connecting state');
696}, 'New data channel should be in the connecting state after creation (after connection ' +
697 'establishment)');
Soares Chen199b65f2017-06-21 09:20:39698
699/*
Soares Chen6a9b7812017-06-08 13:25:47700 Untestable
Soares Chen199b65f2017-06-21 09:20:39701 6.1. createDataChannel
youennf0e97d092019-03-23 18:02:56702 19. If a setting, either [[MaxPacketLifeTime]] or [[MaxRetransmits]], has been set to
703 indicate unreliable mode, and that value exceeds the maximum value supported
704 by the user agent, the value MUST be set to the user agents maximum value.
Soares Chen199b65f2017-06-21 09:20:39705
youennf0e97d092019-03-23 18:02:56706 23. Return channel and continue the following steps in parallel.
707 24. Create channel's associated underlying data transport and configure
Soares Chen199b65f2017-06-21 09:20:39708 it according to the relevant properties of channel.
709
710 Tested in RTCPeerConnection-onnegotiationneeded.html
youennf0e97d092019-03-23 18:02:56711 22. If channel is the first RTCDataChannel created on connection, update the
712 negotiation-needed flag for connection.
Soares Chen199b65f2017-06-21 09:20:39713
youennf0e97d092019-03-23 18:02:56714 Tested in RTCDataChannel-id.html
715 - Odd/even rules for '.id'
Soares Chen199b65f2017-06-21 09:20:39716
youennf0e97d092019-03-23 18:02:56717 Tested in RTCDataChannel-dcep.html
718 - Transmission of '.label' and further options
Soares Chen199b65f2017-06-21 09:20:39719*/
foolip72525e92017-04-24 09:31:03720</script>