4 <title>Test UDPSocket API
</title>
5 <script src=
"chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
6 <link rel=
"stylesheet" type=
"text/css" href=
"chrome://mochikit/content/tests/SimpleTest/test.css"/>
10 <div id=
"content" style=
"display: none">
12 <iframe id=
"iframe"></iframe>
14 <script type=
"application/javascript">
16 SimpleTest.waitForExplicitFinish();
17 SimpleTest.requestFlakyTimeout(
"untriaged");
19 const HELLO_WORLD = 'hlo wrld. ';
20 const DATA_ARRAY = [
0,
255,
254,
0,
1,
2,
3,
0,
255,
255,
254,
0];
21 const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
22 const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
23 const BIG_ARRAY = new Array(
4096);
24 const BIG_ARRAY_BUFFER = new ArrayBuffer(BIG_ARRAY.length);
25 const BIG_TYPED_ARRAY = new Uint8Array(BIG_ARRAY_BUFFER);
27 for (let i =
0; i < BIG_ARRAY.length; i++) {
28 BIG_ARRAY[i] = Math.floor(Math.random() *
256);
31 TYPED_DATA_ARRAY.set(DATA_ARRAY);
32 BIG_TYPED_ARRAY.set(BIG_ARRAY);
34 function is_same_buffer(recv_data, expect_data) {
35 let recv_dataview = new Uint8Array(recv_data);
36 let expected_dataview = new Uint8Array(expect_data);
38 if (recv_dataview.length !== expected_dataview.length) {
42 for (let i =
0; i < recv_dataview.length; i++) {
43 if (recv_dataview[i] != expected_dataview[i]) {
44 info('discover byte differenct at ' + i);
52 info('test for creating an UDP Socket');
53 let socket = new UDPSocket();
54 is(socket.localPort, null, 'expect no local port before socket opened');
55 is(socket.localAddress, null, 'expect no local address before socket opened');
56 is(socket.remotePort, null, 'expected no default remote port');
57 is(socket.remoteAddress, null, 'expected no default remote address');
58 is(socket.readyState, 'opening', 'expected ready state = opening');
59 is(socket.loopback, false, 'expected no loopback');
60 is(socket.addressReuse, true, 'expect to reuse address');
62 return socket.opened.then(function() {
63 ok(true, 'expect openedPromise to be resolved after successful socket binding');
64 ok(!(socket.localPort ===
0), 'expect allocated a local port');
65 is(socket.localAddress, '
0.0.0.0', 'expect assigned to default address');
66 is(socket.readyState, 'open', 'expected ready state = open');
72 function testSendString(socket) {
73 info('test for sending string data');
75 socket.send(HELLO_WORLD, '
127.0.0.1', socket.localPort);
77 return new Promise(function(resolve) {
78 socket.addEventListener('message', function(msg) {
79 let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
80 is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
81 is(recvData, HELLO_WORLD, 'expected same string data');
87 function testSendArrayBuffer(socket) {
88 info('test for sending ArrayBuffer');
90 socket.send(DATA_ARRAY_BUFFER, '
127.0.0.1', socket.localPort);
92 return new Promise(function(resolve) {
93 socket.addEventListener('message', function(msg) {
94 is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
95 ok(is_same_buffer(msg.data, DATA_ARRAY_BUFFER), 'expected same buffer data');
101 function testSendArrayBufferView(socket) {
102 info('test for sending ArrayBufferView');
104 socket.send(TYPED_DATA_ARRAY, '
127.0.0.1', socket.localPort);
106 return new Promise(function(resolve) {
107 socket.addEventListener('message', function(msg) {
108 is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
109 ok(is_same_buffer(msg.data, TYPED_DATA_ARRAY), 'expected same buffer data');
115 function testSendBlob(socket) {
116 info('test for sending Blob');
118 let blob = new Blob([HELLO_WORLD], {type : 'text/plain'});
119 socket.send(blob, '
127.0.0.1', socket.localPort);
121 return new Promise(function(resolve) {
122 socket.addEventListener('message', function(msg) {
123 let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
124 is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
125 is(recvData, HELLO_WORLD, 'expected same string data');
131 function testSendBigArray(socket) {
132 info('test for sending Big ArrayBuffer');
134 socket.send(BIG_TYPED_ARRAY, '
127.0.0.1', socket.localPort);
136 return new Promise(function(resolve) {
137 let byteReceived =
0;
138 socket.addEventListener('message', function recv_callback(msg) {
139 let byteBegin = byteReceived;
140 byteReceived += msg.data.byteLength;
141 is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
142 ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
143 if (byteReceived
>= BIG_TYPED_ARRAY.length) {
144 socket.removeEventListener('message', recv_callback);
151 function testSendBigBlob(socket) {
152 info('test for sending Big Blob');
154 let blob = new Blob([BIG_TYPED_ARRAY]);
155 socket.send(blob, '
127.0.0.1', socket.localPort);
157 return new Promise(function(resolve) {
158 let byteReceived =
0;
159 socket.addEventListener('message', function recv_callback(msg) {
160 let byteBegin = byteReceived;
161 byteReceived += msg.data.byteLength;
162 is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
163 ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
164 if (byteReceived
>= BIG_TYPED_ARRAY.length) {
165 socket.removeEventListener('message', recv_callback);
172 function testUDPOptions(socket) {
173 info('test for UDP init options');
175 let remoteSocket = new UDPSocket({addressReuse: false,
177 localAddress: '
127.0.0.1',
178 remoteAddress: '
127.0.0.1',
179 remotePort: socket.localPort});
180 is(remoteSocket.localAddress, '
127.0.0.1', 'expected local address');
181 is(remoteSocket.remoteAddress, '
127.0.0.1', 'expected remote address');
182 is(remoteSocket.remotePort, socket.localPort, 'expected remote port');
183 is(remoteSocket.addressReuse, false, 'expected address not reusable');
184 is(remoteSocket.loopback, true, 'expected loopback mode is on');
186 return remoteSocket.opened.then(function() {
187 remoteSocket.send(HELLO_WORLD);
188 return new Promise(function(resolve) {
189 socket.addEventListener('message', function(msg) {
190 let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
191 is(msg.remotePort, remoteSocket.localPort, 'expected packet from ' + remoteSocket.localPort);
192 is(recvData, HELLO_WORLD, 'expected same string data');
199 function testClose(socket) {
200 info('test for close');
203 is(socket.readyState, 'closed', 'expect ready state to be
"closed"');
205 socket.send(HELLO_WORLD, '
127.0.0.1', socket.localPort);
206 ok(false, 'unexpect to send successfully');
208 ok(true, 'expected send fail after socket closed');
211 return socket.closed.then(function() {
212 ok(true, 'expected closedPromise is resolved after socket.close()');
216 function testMulticast() {
217 info('test for multicast');
219 let socket = new UDPSocket({loopback: true});
221 const MCAST_ADDRESS = '
224.0.0.255';
222 socket.joinMulticastGroup(MCAST_ADDRESS);
224 return socket.opened.then(function() {
225 socket.send(HELLO_WORLD, MCAST_ADDRESS, socket.localPort);
227 return new Promise(function(resolve) {
228 socket.addEventListener('message', function(msg) {
229 let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
230 is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
231 is(recvData, HELLO_WORLD, 'expected same string data');
232 socket.leaveMulticastGroup(MCAST_ADDRESS);
239 function testInvalidUDPOptions() {
240 info('test for invalid UDPOptions');
242 new UDPSocket({localAddress: 'not-a-valid-address'});
243 ok(false, 'should not create an UDPSocket with an invalid localAddress');
245 is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localAddress is not a valid IPv4/
6 address');
249 new UDPSocket({localPort:
0});
250 ok(false, 'should not create an UDPSocket with an invalid localPort');
252 is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localPort is not a valid port number');
256 new UDPSocket({remotePort:
0});
257 ok(false, 'should not create an UDPSocket with an invalid remotePort');
259 is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localPort is not a valid port number');
263 function testOpenFailed() {
264 info('test for falied on open');
266 //according to RFC5737, address block
192.0.2.0/
24 should not be used in both local and public contexts
267 let socket = new UDPSocket({localAddress: '
192.0.2.0'});
269 return socket.opened.then(function() {
270 ok(false, 'should not resolve openedPromise while fail to bind socket');
272 }).catch(function(reason) {
273 is(reason.name, 'NetworkError', 'expected openedPromise to be rejected while fail to bind socket');
277 function testSendBeforeOpen() {
278 info('test for send before open');
280 let socket = new UDPSocket();
283 socket.send(HELLO_WORLD, '
127.0.0.1',
9);
284 ok(false, 'unexpect to send successfully');
286 ok(true, 'expected send fail before openedPromise is resolved');
289 return socket.opened.then(function() {
294 function testCloseBeforeOpened() {
295 info('test for close socket before opened');
297 let socket = new UDPSocket();
298 socket.opened.then(function() {
299 ok(false, 'should not resolve openedPromise if it has already been closed');
300 }).catch(function(reason) {
301 is(reason.name, 'AbortError', 'expected openedPromise to be rejected while socket is closed during opening');
304 return socket.close().then(function() {
305 ok(true, 'expected closedPromise to be resolved');
306 }).then(socket.opened);
309 function testOpenWithoutClose() {
310 info('test for open without close');
313 for (let i =
0; i <
50; i++) {
314 let socket = new UDPSocket();
315 closed.push(socket.closed);
319 info('all unrefereced socket should be closed right after GC');
321 return Promise.all(closed);
324 function awaitEvent(target, event) {
325 return new Promise(resolve =
> {
326 target.addEventListener(event, resolve, { once: true });
330 async function testBFCache() {
331 info('test for bfcache behavior');
333 let socket = new UDPSocket();
337 let win = window.open(`file_udpsocket_iframe.html?${socket.localPort}`);
339 let msg = await awaitEvent(socket,
"message");
341 win.location =
"file_postMessage_opener.html";
342 await awaitEvent(window,
"message");
344 socket.send(HELLO_WORLD, '
127.0.0.1', msg.remotePort);
346 await new Promise(resolve =
> {
347 function recv_again_callback() {
348 socket.removeEventListener('message', recv_again_callback);
349 ok(false, 'should not receive packet after page unload');
352 socket.addEventListener('message', recv_again_callback);
354 setTimeout(function() {
355 socket.removeEventListener('message', recv_again_callback);
366 .then(testSendString)
367 .then(testSendArrayBuffer)
368 .then(testSendArrayBufferView)
370 .then(testSendBigArray)
371 .then(testSendBigBlob)
372 .then(testUDPOptions)
375 .then(testInvalidUDPOptions)
376 .then(testOpenFailed)
377 .then(testSendBeforeOpen)
378 .then(testCloseBeforeOpened)
379 .then(testOpenWithoutClose)
382 info('test finished');
385 .catch(function(err) {
386 ok(false, 'test failed due to: ' + err);
391 window.addEventListener('load', function () {
392 SpecialPowers.pushPrefEnv({
394 ['dom.udpsocket.enabled', true],
395 ['browser.sessionhistory.max_total_viewers',
10]