Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / extensions / test / data / serial_unittest.js
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6  * Unit tests for the JS serial service client.
7  *
8  * These test that configuration and data are correctly transmitted between the
9  * client and the service. They are launched by
10  * extensions/renderer/api/serial/serial_api_unittest.cc.
11  */
12
13 var test = require('test').binding;
14 var serial = require('serial').binding;
15 var unittestBindings = require('test_environment_specific_bindings');
16 var utils = require('utils');
17
18 var timeoutManager = new unittestBindings.TimeoutManager();
19 timeoutManager.installGlobals();
20
21 var BUFFER_SIZE = 10;
22
23 var connectionId = null;
24
25 function connect(callback, options) {
26   options = options || {
27     name: 'test connection',
28     bufferSize: BUFFER_SIZE,
29     receiveTimeout: 12345,
30     sendTimeout: 6789,
31     persistent: true,
32   };
33   serial.connect('device', options, test.callbackPass(function(connectionInfo) {
34     connectionId = connectionInfo.connectionId;
35     if (callback)
36       callback(connectionInfo);
37   }));
38 }
39
40 // Sets a function to be called once when data is received. Returns a promise
41 // that will resolve once the hook is installed.
42 function addReceiveHook(callback) {
43   return requireAsync('serial_service').then(function(serialService) {
44     var called = false;
45     var dataReceived = serialService.Connection.prototype.onDataReceived_;
46     serialService.Connection.prototype.onDataReceived_ = function() {
47       var result = $Function.apply(dataReceived, this, arguments);
48       if (!called)
49         callback();
50       called = true;
51       return result;
52     };
53   });
54 }
55
56 // Sets a function to be called once when a receive error is received. Returns a
57 // promise that will resolve once the hook is installed.
58 function addReceiveErrorHook(callback) {
59   return requireAsync('serial_service').then(function(serialService) {
60     var called = false;
61     var receiveError = serialService.Connection.prototype.onReceiveError_;
62     serialService.Connection.prototype.onReceiveError_ = function() {
63       var result = $Function.apply(receiveError, this, arguments);
64       if (!called)
65         callback();
66       called = true;
67       return result;
68     };
69   });
70 }
71
72 function disconnect() {
73   serial.disconnect(connectionId, test.callbackPass(function(success) {
74     test.assertTrue(success);
75     connectionId = null;
76   }));
77 }
78
79 function checkClientConnectionInfo(connectionInfo) {
80   test.assertFalse(connectionInfo.persistent);
81   test.assertEq('test connection', connectionInfo.name);
82   test.assertEq(12345, connectionInfo.receiveTimeout);
83   test.assertEq(6789, connectionInfo.sendTimeout);
84   test.assertEq(BUFFER_SIZE, connectionInfo.bufferSize);
85   test.assertFalse(connectionInfo.paused);
86 }
87
88 function checkServiceConnectionInfo(connectionInfo) {
89   test.assertEq(9600, connectionInfo.bitrate);
90   test.assertEq('eight', connectionInfo.dataBits);
91   test.assertEq('no', connectionInfo.parityBit);
92   test.assertEq('one', connectionInfo.stopBits);
93   test.assertFalse(connectionInfo.ctsFlowControl);
94 }
95
96 function checkConnectionInfo(connectionInfo) {
97   checkClientConnectionInfo(connectionInfo);
98   checkServiceConnectionInfo(connectionInfo);
99 }
100
101 function runReceiveErrorTest(expectedError) {
102   connect();
103   test.listenOnce(serial.onReceiveError, function(result) {
104     serial.getInfo(connectionId, test.callbackPass(function(connectionInfo) {
105       disconnect();
106       test.assertTrue(connectionInfo.paused);
107     }));
108     test.assertEq(connectionId, result.connectionId);
109     test.assertEq(expectedError, result.error);
110   });
111 }
112
113 function runSendErrorTest(expectedError) {
114   connect(function() {
115     var buffer = new ArrayBuffer(1);
116     serial.send(connectionId, buffer, test.callbackPass(function(sendInfo) {
117       disconnect();
118       test.assertEq(0, sendInfo.bytesSent);
119       test.assertEq(expectedError, sendInfo.error);
120     }));
121   });
122 }
123
124 function sendData() {
125   var data = 'data';
126   var buffer = new ArrayBuffer(data.length);
127   var byteBuffer = new Int8Array(buffer);
128   for (var i = 0; i < data.length; i++) {
129     byteBuffer[i] = data.charCodeAt(i);
130   }
131   return utils.promise(serial.send, connectionId, buffer);
132 }
133
134 function checkReceivedData(result) {
135   var data = 'data';
136   test.assertEq(connectionId, result.connectionId);
137   test.assertEq(data.length, result.data.byteLength);
138   var resultByteBuffer = new Int8Array(result.data);
139   for (var i = 0; i < data.length; i++) {
140     test.assertEq(data.charCodeAt(i), resultByteBuffer[i]);
141   }
142 }
143
144 unittestBindings.exportTests([
145   // Test that getDevices correctly transforms the data returned by the
146   // SerialDeviceEnumerator.
147   function testGetDevices() {
148     serial.getDevices(test.callbackPass(function(devices) {
149       test.assertEq(3, devices.length);
150       test.assertEq(4, $Object.keys(devices[0]).length);
151       test.assertEq('device', devices[0].path);
152       test.assertEq(1234, devices[0].vendorId);
153       test.assertEq(5678, devices[0].productId);
154       test.assertEq('foo', devices[0].displayName);
155       test.assertEq(1, $Object.keys(devices[1]).length);
156       test.assertEq('another_device', devices[1].path);
157       test.assertEq(1, $Object.keys(devices[2]).length);
158       test.assertEq('', devices[2].path);
159     }));
160   },
161
162   // Test that the correct error message is returned when an error occurs in
163   // connecting to the port. This test uses an IoHandler that fails to connect.
164   function testConnectFail() {
165     serial.connect('device',
166                    test.callbackFail('Failed to connect to the port.'));
167   },
168
169   // Test that the correct error message is returned when an error occurs in
170   // calling getPortInfo after connecting to the port. This test uses an
171   // IoHandler that fails on calls to GetPortInfo.
172   function testGetInfoFailOnConnect() {
173     serial.connect('device',
174                    test.callbackFail('Failed to connect to the port.'));
175   },
176
177   // Test that the correct error message is returned when an invalid bit-rate
178   // value is passed to connect.
179   function testConnectInvalidBitrate() {
180     serial.connect('device', {bitrate: -1}, test.callbackFail(
181         'Failed to connect to the port.'));
182   },
183
184   // Test that a successful connect returns the expected connection info.
185   function testConnect() {
186     connect(function(connectionInfo) {
187       disconnect();
188       checkConnectionInfo(connectionInfo);
189     });
190   },
191
192   // Test that a connection created with no options has the correct default
193   // options.
194   function testConnectDefaultOptions() {
195     connect(function(connectionInfo) {
196       disconnect();
197       test.assertEq(9600, connectionInfo.bitrate);
198       test.assertEq('eight', connectionInfo.dataBits);
199       test.assertEq('no', connectionInfo.parityBit);
200       test.assertEq('one', connectionInfo.stopBits);
201       test.assertFalse(connectionInfo.ctsFlowControl);
202       test.assertFalse(connectionInfo.persistent);
203       test.assertEq('', connectionInfo.name);
204       test.assertEq(0, connectionInfo.receiveTimeout);
205       test.assertEq(0, connectionInfo.sendTimeout);
206       test.assertEq(4096, connectionInfo.bufferSize);
207     }, {});
208   },
209
210   // Test that a getInfo call correctly converts the service-side info from the
211   // Mojo format and returns both it and the client-side configuration.
212   function testGetInfo() {
213     connect(function() {
214       serial.getInfo(connectionId,
215                      test.callbackPass(function(connectionInfo) {
216         disconnect();
217         checkConnectionInfo(connectionInfo);
218       }));
219     });
220   },
221
222   // Test that only client-side options are returned when the service fails a
223   // getInfo call. This test uses an IoHandler that fails GetPortInfo calls
224   // after the initial call during connect.
225   function testGetInfoFailToGetPortInfo() {
226     connect(function() {
227       serial.getInfo(connectionId,
228                      test.callbackPass(function(connectionInfo) {
229         disconnect();
230         checkClientConnectionInfo(connectionInfo);
231         test.assertFalse('bitrate' in connectionInfo);
232         test.assertFalse('dataBits' in connectionInfo);
233         test.assertFalse('parityBit' in connectionInfo);
234         test.assertFalse('stopBit' in connectionInfo);
235         test.assertFalse('ctsFlowControl' in connectionInfo);
236       }));
237     });
238   },
239
240   // Test that getConnections returns an array containing the open connection.
241   function testGetConnections() {
242     connect(function() {
243       serial.getConnections(test.callbackPass(function(connections) {
244         disconnect();
245         test.assertEq(1, connections.length);
246         checkConnectionInfo(connections[0]);
247       }));
248     });
249   },
250
251   // Test that getControlSignals correctly converts the Mojo format result. This
252   // test uses an IoHandler that returns values matching the pattern being
253   // tested.
254   function testGetControlSignals() {
255     connect(function() {
256       var calls = 0;
257       function checkControlSignals(signals) {
258         if (calls == 15) {
259           disconnect();
260         } else {
261           serial.getControlSignals(
262               connectionId,
263               test.callbackPass(checkControlSignals));
264         }
265         test.assertEq(!!(calls & 1), signals.dcd);
266         test.assertEq(!!(calls & 2), signals.cts);
267         test.assertEq(!!(calls & 4), signals.ri);
268         test.assertEq(!!(calls & 8), signals.dsr);
269         calls++;
270       }
271       serial.getControlSignals(connectionId,
272                                test.callbackPass(checkControlSignals));
273     });
274   },
275
276   // Test that setControlSignals correctly converts to the Mojo format result.
277   // This test uses an IoHandler that returns values following the same table of
278   // values as |signalsValues|.
279   function testSetControlSignals() {
280     connect(function() {
281       var signalsValues = [
282         {},
283         {dtr: false},
284         {dtr: true},
285         {rts: false},
286         {dtr: false, rts: false},
287         {dtr: true, rts: false},
288         {rts: true},
289         {dtr: false, rts: true},
290         {dtr: true, rts: true},
291       ];
292       var calls = 0;
293       function setControlSignals(success) {
294         if (calls == signalsValues.length) {
295           disconnect();
296         } else {
297           serial.setControlSignals(connectionId,
298                                    signalsValues[calls++],
299                                    test.callbackPass(setControlSignals));
300         }
301         test.assertTrue(success);
302       }
303       setControlSignals(true);
304     });
305   },
306
307   // Test that update correctly passes values to the service only for
308   // service-side options and that all update calls are reflected by the result
309   // of getInfo calls. This test uses an IoHandler that expects corresponding
310   // ConfigurePort calls.
311   function testUpdate() {
312     connect(function() {
313       var optionsValues = [
314         {},  // SetPortOptions is called once during connection.
315         {bitrate: 57600},
316         {dataBits: 'seven'},
317         {dataBits: 'eight'},
318         {parityBit: 'no'},
319         {parityBit: 'odd'},
320         {parityBit: 'even'},
321         {stopBits: 'one'},
322         {stopBits: 'two'},
323         {ctsFlowControl: false},
324         {ctsFlowControl: true},
325         {bufferSize: 1},
326         {sendTimeout: 0},
327         {receiveTimeout: 0},
328         {persistent: false},
329         {name: 'name'},
330       ];
331       var calls = 0;
332       function checkInfo(info) {
333         for (var key in optionsValues[calls]) {
334           test.assertEq(optionsValues[calls][key], info[key]);
335         }
336         setOptions();
337       }
338       function setOptions() {
339         if (++calls == optionsValues.length) {
340           disconnect();
341         } else {
342           serial.update(connectionId,
343                         optionsValues[calls],
344                         test.callbackPass(function(success) {
345             serial.getInfo(connectionId, test.callbackPass(checkInfo));
346             test.assertTrue(success);
347           }));
348         }
349       }
350       setOptions();
351     });
352   },
353
354   // Test that passing an invalid bit-rate reslts in an error.
355   function testUpdateInvalidBitrate() {
356     connect(function() {
357       serial.update(connectionId,
358                     {bitrate: -1},
359                     test.callbackPass(function(success) {
360         disconnect();
361         test.assertFalse(success);
362       }));
363     });
364   },
365
366   // Test flush. This test uses an IoHandler that counts the number of flush
367   // calls.
368   function testFlush() {
369     connect(function() {
370       serial.flush(connectionId, test.callbackPass(function(success) {
371         disconnect();
372         test.assertTrue(success);
373       }));
374     });
375   },
376
377   // Test that setPaused values are reflected by the results returned by getInfo
378   // calls.
379   function testSetPaused() {
380     connect(function() {
381       serial.setPaused(connectionId, true, test.callbackPass(function() {
382         serial.getInfo(connectionId, test.callbackPass(function(info) {
383           serial.setPaused(connectionId, false, test.callbackPass(function() {
384             serial.getInfo(connectionId, test.callbackPass(function(info) {
385               test.assertFalse(info.paused);
386               disconnect();
387             }));
388           }));
389           test.assertTrue(info.paused);
390         }));
391       }));
392     });
393   },
394
395   // Test that a send and a receive correctly echoes data. This uses an
396   // IoHandler that echoes data sent to it.
397   function testEcho() {
398     connect(function() {
399       sendData().then(test.callbackPass(function(sendInfo) {
400         test.assertEq(4, sendInfo.bytesSent);
401         test.assertEq(undefined, sendInfo.error);
402       }));
403       test.listenOnce(serial.onReceive, function(result) {
404         checkReceivedData(result);
405         disconnect();
406       });
407     });
408   },
409
410   // Test that a send while another send is in progress returns a pending error.
411   function testSendDuringExistingSend() {
412     connect(function() {
413       sendData().then(test.callbackPass(function(sendInfo) {
414         test.assertEq(4, sendInfo.bytesSent);
415         test.assertEq(undefined, sendInfo.error);
416         disconnect();
417       }));
418       sendData().then(test.callbackPass(function(sendInfo) {
419         test.assertEq(0, sendInfo.bytesSent);
420         test.assertEq('pending', sendInfo.error);
421       }));
422     });
423   },
424
425   // Test that a second send after the first finishes is successful. This uses
426   // an IoHandler that echoes data sent to it.
427   function testSendAfterSuccessfulSend() {
428     connect(function() {
429       sendData().then(test.callbackPass(function(sendInfo) {
430         test.assertEq(4, sendInfo.bytesSent);
431         test.assertEq(undefined, sendInfo.error);
432         return sendData();
433       })).then(test.callbackPass(function(sendInfo) {
434         test.assertEq(4, sendInfo.bytesSent);
435         test.assertEq(undefined, sendInfo.error);
436       }));
437       // Check that the correct data is echoed twice.
438       test.listenOnce(serial.onReceive, function(result) {
439         checkReceivedData(result);
440         test.listenOnce(serial.onReceive, function(result) {
441           checkReceivedData(result);
442           disconnect();
443         });
444       });
445     });
446   },
447
448   // Test that a second send after the first fails is successful. This uses an
449   // IoHandler that returns system_error for only the first send.
450   function testSendPartialSuccessWithError() {
451     connect(function() {
452       sendData().then(test.callbackPass(function(sendInfo) {
453         test.assertEq(2, sendInfo.bytesSent);
454         test.assertEq('system_error', sendInfo.error);
455         return sendData();
456       })).then(test.callbackPass(function(sendInfo) {
457         test.assertEq(4, sendInfo.bytesSent);
458         test.assertEq(undefined, sendInfo.error);
459         disconnect();
460       }));
461     });
462   },
463
464   // Test that a timed-out send returns a timeout error and that changing the
465   // send timeout during a send does not affect its timeout. This test uses an
466   // IoHandle that never completes sends.
467   function testSendTimeout() {
468     connect(function() {
469       sendData().then(test.callbackPass(function(sendInfo) {
470         test.assertEq(0, sendInfo.bytesSent);
471         test.assertEq('timeout', sendInfo.error);
472         test.assertEq(5, timeoutManager.currentTime);
473         disconnect();
474       }));
475       serial.update(connectionId, {sendTimeout: 10}, test.callbackPass(
476           timeoutManager.run.bind(timeoutManager, 1)));
477     }, {sendTimeout: 5});
478   },
479
480   // Test that a timed-out send returns a timeout error and that disabling the
481   // send timeout during a send does not affect its timeout. This test uses an
482   // IoHandle that never completes sends.
483   function testDisableSendTimeout() {
484     connect(function() {
485       sendData().then(test.callbackPass(function(sendInfo) {
486         test.assertEq(0, sendInfo.bytesSent);
487         test.assertEq('timeout', sendInfo.error);
488         test.assertEq(6, timeoutManager.currentTime);
489         disconnect();
490       }));
491       serial.update(connectionId, {sendTimeout: 0}, test.callbackPass(
492           timeoutManager.run.bind(timeoutManager, 1)));
493     }, {sendTimeout: 6});
494   },
495
496   // Test that data received while the connection is paused is queued and
497   // dispatched once the connection is unpaused.
498   function testPausedReceive() {
499     // Wait until the receive hook is installed, then start the test.
500     addReceiveHook(function() {
501       // Unpause the connection after the connection has queued the received
502       // data to ensure the queued data is dispatched when the connection is
503       // unpaused.
504       serial.setPaused(connectionId, false, test.callbackPass());
505       // Check that setPaused(false) is idempotent.
506       serial.setPaused(connectionId, false, test.callbackPass());
507     }).then(function() {
508       connect(function() {
509         // Check that setPaused(true) is idempotent.
510         serial.setPaused(connectionId, true, test.callbackPass());
511         serial.setPaused(connectionId, true, test.callbackPass());
512       });
513     });
514     test.listenOnce(serial.onReceive, function(result) {
515       checkReceivedData(result);
516       disconnect();
517     });
518   },
519
520   // Test that a receive error received while the connection is paused is queued
521   // and dispatched once the connection is unpaused.
522   function testPausedReceiveError() {
523     addReceiveErrorHook(function() {
524       // Unpause the connection after the connection has queued the receive
525       // error to ensure the queued error is dispatched when the connection is
526       // unpaused.
527       serial.setPaused(connectionId, false, test.callbackPass());
528     }).then(test.callbackPass(function() {
529       connect(function() {
530         serial.setPaused(connectionId, true, test.callbackPass());
531       });
532     }));
533
534     test.listenOnce(serial.onReceiveError, function(result) {
535       serial.getInfo(connectionId, test.callbackPass(function(connectionInfo) {
536         disconnect();
537         test.assertTrue(connectionInfo.paused);
538       }));
539       test.assertEq(connectionId, result.connectionId);
540       test.assertEq('device_lost', result.error);
541     });
542     serial.onReceive.addListener(function() {
543       test.fail('unexpected onReceive event');
544     });
545   },
546
547   // Test that receive timeouts trigger after the timeout time elapses and that
548   // changing the receive timeout does not affect a wait in progress.
549   function testReceiveTimeout() {
550     connect(function() {
551       test.listenOnce(serial.onReceiveError, function(result) {
552         test.assertEq(connectionId, result.connectionId);
553         test.assertEq('timeout', result.error);
554         test.assertEq(20, timeoutManager.currentTime);
555         serial.getInfo(connectionId, test.callbackPass(
556             function(connectionInfo) {
557           test.assertFalse(connectionInfo.paused);
558           disconnect();
559         }));
560       });
561       // Changing the timeout does not take effect until the current timeout
562       // expires or a receive completes.
563       serial.update(connectionId, {receiveTimeout: 10}, test.callbackPass(
564           timeoutManager.run.bind(timeoutManager, 1)));
565     }, {receiveTimeout: 20});
566   },
567
568   // Test that receive timeouts trigger after the timeout time elapses and that
569   // disabling the receive timeout does not affect a wait in progress.
570   function testDisableReceiveTimeout() {
571     connect(function() {
572       test.listenOnce(serial.onReceiveError, function(result) {
573         test.assertEq(connectionId, result.connectionId);
574         test.assertEq('timeout', result.error);
575         test.assertEq(30, timeoutManager.currentTime);
576         serial.getInfo(connectionId, test.callbackPass(
577             function(connectionInfo) {
578           disconnect();
579           test.assertFalse(connectionInfo.paused);
580         }));
581       });
582       // Disabling the timeout does not take effect until the current timeout
583       // expires or a receive completes.
584       serial.update(connectionId, {receiveTimeout: 0}, test.callbackPass(
585           timeoutManager.run.bind(timeoutManager, 1)));
586     }, {receiveTimeout: 30});
587   },
588
589   // Test that a receive error from the service is correctly dispatched. This
590   // test uses an IoHandler that only reports 'disconnected' receive errors.
591   function testReceiveErrorDisconnected() {
592     runReceiveErrorTest('disconnected');
593   },
594
595   // Test that a receive error from the service is correctly dispatched. This
596   // test uses an IoHandler that only reports 'device_lost' receive errors.
597   function testReceiveErrorDeviceLost() {
598     runReceiveErrorTest('device_lost');
599   },
600
601   // Test that a receive from error the service is correctly dispatched. This
602   // test uses an IoHandler that only reports 'system_error' receive errors.
603   function testReceiveErrorSystemError() {
604     runReceiveErrorTest('system_error');
605   },
606
607   // Test that a send error from the service is correctly returned as the send
608   // result. This test uses an IoHandler that only reports 'disconnected' send
609   // errors.
610   function testSendErrorDisconnected() {
611     runSendErrorTest('disconnected');
612   },
613
614   // Test that a send error from the service is correctly returned as the send
615   // result. This test uses an IoHandler that only reports 'system_error' send
616   // errors.
617   function testSendErrorSystemError() {
618     runSendErrorTest('system_error');
619   },
620
621   // Test that disconnect returns the correct error for a connection ID that
622   // does not exist.
623   function testDisconnectUnknownConnectionId() {
624     serial.disconnect(-1, test.callbackFail('Serial connection not found.'));
625   },
626
627   // Test that getInfo returns the correct error for a connection ID that does
628   // not exist.
629   function testGetInfoUnknownConnectionId() {
630     serial.getInfo(-1, test.callbackFail('Serial connection not found.'));
631   },
632
633   // Test that update returns the correct error for a connection ID that does
634   // not exist.
635   function testUpdateUnknownConnectionId() {
636     serial.update(-1, {}, test.callbackFail('Serial connection not found.'));
637   },
638
639   // Test that setControlSignals returns the correct error for a connection ID
640   // that does not exist.
641   function testSetControlSignalsUnknownConnectionId() {
642     serial.setControlSignals(-1, {}, test.callbackFail(
643         'Serial connection not found.'));
644   },
645
646   // Test that getControlSignals returns the correct error for a connection ID
647   // that does not exist.
648   function testGetControlSignalsUnknownConnectionId() {
649     serial.getControlSignals(-1, test.callbackFail(
650         'Serial connection not found.'));
651   },
652
653   // Test that flush returns the correct error for a connection ID that does not
654   // exist.
655   function testFlushUnknownConnectionId() {
656     serial.flush(-1, test.callbackFail('Serial connection not found.'));
657   },
658
659   // Test that setPaused returns the correct error for a connection ID that does
660   // not exist.
661   function testSetPausedUnknownConnectionId() {
662     serial.setPaused(
663         -1, true, test.callbackFail('Serial connection not found.'));
664     serial.setPaused(
665         -1, false, test.callbackFail('Serial connection not found.'));
666   },
667
668   // Test that send returns the correct error for a connection ID that does not
669   // exist.
670   function testSendUnknownConnectionId() {
671     var buffer = new ArrayBuffer(1);
672     serial.send(-1, buffer, test.callbackFail('Serial connection not found.'));
673   },
674 ], test.runTests, exports);