DevTools: kill codeschool extension from whitelist
[chromium-blink-merge.git] / extensions / test / data / serial_unittest.js
blob33197cf3bd62a700037f646acf74ec66898aad63
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.
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  */
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');
18 var timeoutManager = new unittestBindings.TimeoutManager();
19 timeoutManager.installGlobals();
21 var BUFFER_SIZE = 10;
23 var connectionId = null;
25 var OPTIONS_VALUES = [
26   {},  // SetPortOptions is called once during connection.
27   {bitrate: 57600},
28   {dataBits: 'seven'},
29   {dataBits: 'eight'},
30   {parityBit: 'no'},
31   {parityBit: 'odd'},
32   {parityBit: 'even'},
33   {stopBits: 'one'},
34   {stopBits: 'two'},
35   {ctsFlowControl: false},
36   {ctsFlowControl: true},
37   {bufferSize: 1},
38   {sendTimeout: 0},
39   {receiveTimeout: 0},
40   {persistent: false},
41   {name: 'name'},
44 // Create a serial connection. That serial connection will be used by the other
45 // helper functions below.
46 function connect(options) {
47   options = options || {
48     name: 'test connection',
49     bufferSize: BUFFER_SIZE,
50     receiveTimeout: 12345,
51     sendTimeout: 6789,
52     persistent: true,
53   };
54   return utils.promise(serial.connect, 'device', options).then(function(info) {
55     connectionId = info.connectionId;
56     return info;
57   });
60 // Serialize and deserialize all serial connections, preserving onData and
61 // onError event listeners.
62 function serializeRoundTrip() {
63   return requireAsync('serial_service').then(function(serialService) {
64     function serializeConnections(connections) {
65       var serializedConnections = [];
66       for (var connection of connections.values()) {
67         serializedConnections.push(serializeConnection(connection));
68       }
69       return Promise.all(serializedConnections);
70     }
72     function serializeConnection(connection) {
73       var onData = connection.onData;
74       var onError = connection.onError;
75       return connection.serialize().then(function(serialization) {
76         return {
77           serialization: serialization,
78           onData: onData,
79           onError: onError,
80         };
81       });
82     }
84     function deserializeConnections(serializedConnections) {
85       $Array.forEach(serializedConnections, function(serializedConnection) {
86         var connection = serialService.Connection.deserialize(
87             serializedConnection.serialization);
88         connection.onData = serializedConnection.onData;
89         connection.onError = serializedConnection.onError;
90         connection.resumeReceives();
91       });
92     }
94     return serialService.getConnections()
95         .then(serializeConnections)
96         .then(deserializeConnections);
97   });
100 // Returns a promise that will resolve to the connection info for the
101 // connection.
102 function getInfo() {
103   return utils.promise(serial.getInfo, connectionId);
106 // Returns a function that checks that the values of keys contained within
107 // |expectedInfo| match the values of the same keys contained within |info|.
108 function checkInfo(expectedInfo) {
109   return function(info) {
110     for (var key in expectedInfo) {
111       test.assertEq(expectedInfo[key], info[key]);
112     }
113   };
116 // Returns a function that will update the options of the serial connection with
117 // those contained within |values|.
118 function update(values) {
119   return function() {
120     return utils.promise(serial.update, connectionId, values);
121   };
124 // Checks that the previous operation succeeded.
125 function expectSuccess(success) {
126   test.assertTrue(success);
129 // Returns a function that checks that the send result matches |bytesSent| and
130 // |error|. If no error is expected, |error| may be omitted.
131 function expectSendResult(bytesSent, error) {
132   return function(sendInfo) {
133     test.assertEq(bytesSent, sendInfo.bytesSent);
134     test.assertEq(error, sendInfo.error);
135   };
138 // Returns a function that checks that the current time is |expectedTime|.
139 function expectCurrentTime(expectedTime) {
140   return function() {
141     test.assertEq(expectedTime, timeoutManager.currentTime);
142   }
145 // Returns a promise that will resolve to the device control signals for the
146 // serial connection.
147 function getControlSignals() {
148   return utils.promise(serial.getControlSignals, connectionId);
151 // Returns a function that will set the control signals for the serial
152 // connection to |signals|.
153 function setControlSignals(signals) {
154   return function() {
155     return utils.promise(serial.setControlSignals, connectionId, signals);
156   };
159 // Returns a function that will set the paused state of the serial connection to
160 // |paused|.
161 function setPaused(paused) {
162   return function() {
163     return utils.promise(serial.setPaused, connectionId, paused);
164   }
167 // Sets a function to be called once when data is received. Returns a promise
168 // that will resolve once the hook is installed.
169 function addReceiveHook(callback) {
170   return requireAsync('serial_service').then(function(serialService) {
171     var called = false;
172     var dataReceived = serialService.Connection.prototype.onDataReceived_;
173     serialService.Connection.prototype.onDataReceived_ = function() {
174       var result = $Function.apply(dataReceived, this, arguments);
175       if (!called)
176         callback();
177       called = true;
178       return result;
179     };
180   });
183 // Sets a function to be called once when a receive error is received. Returns a
184 // promise that will resolve once the hook is installed.
185 function addReceiveErrorHook(callback) {
186   return requireAsync('serial_service').then(function(serialService) {
187     var called = false;
188     var receiveError = serialService.Connection.prototype.onReceiveError_;
189     serialService.Connection.prototype.onReceiveError_ = function() {
190       var result = $Function.apply(receiveError, this, arguments);
191       if (!called)
192         callback();
193       called = true;
194       return result;
195     };
196   });
199 function listenOnce(targetEvent) {
200   return new Promise(function(resolve, reject) {
201     targetEvent.addListener(function(result) {
202       resolve(result);
203     });
204   });
207 function disconnect() {
208   return utils.promise(serial.disconnect, connectionId).then(function(success) {
209     test.assertTrue(success);
210     connectionId = null;
211   });
214 function checkClientConnectionInfo(connectionInfo) {
215   test.assertTrue(connectionInfo.persistent);
216   test.assertEq('test connection', connectionInfo.name);
217   test.assertEq(12345, connectionInfo.receiveTimeout);
218   test.assertEq(6789, connectionInfo.sendTimeout);
219   test.assertEq(BUFFER_SIZE, connectionInfo.bufferSize);
220   test.assertFalse(connectionInfo.paused);
223 function checkServiceConnectionInfo(connectionInfo) {
224   test.assertEq(9600, connectionInfo.bitrate);
225   test.assertEq('eight', connectionInfo.dataBits);
226   test.assertEq('no', connectionInfo.parityBit);
227   test.assertEq('one', connectionInfo.stopBits);
228   test.assertFalse(connectionInfo.ctsFlowControl);
231 function checkConnectionInfo(connectionInfo) {
232   checkClientConnectionInfo(connectionInfo);
233   checkServiceConnectionInfo(connectionInfo);
234   test.assertEq(12, $Object.keys(connectionInfo).length);
237 function sendData() {
238   var data = 'data';
239   var buffer = new ArrayBuffer(data.length);
240   var byteBuffer = new Int8Array(buffer);
241   for (var i = 0; i < data.length; i++) {
242     byteBuffer[i] = data.charCodeAt(i);
243   }
244   return utils.promise(serial.send, connectionId, buffer);
247 function checkReceivedData(result) {
248   var data = 'data';
249   test.assertEq(connectionId, result.connectionId);
250   test.assertEq(data.length, result.data.byteLength);
251   var resultByteBuffer = new Int8Array(result.data);
252   for (var i = 0; i < data.length; i++) {
253     test.assertEq(data.charCodeAt(i), resultByteBuffer[i]);
254   }
257 function checkReceiveError(expectedError) {
258   return function(result) {
259     test.assertEq(connectionId, result.connectionId);
260     test.assertEq(expectedError, result.error);
261   }
264 function runReceiveErrorTest(expectedError) {
265   var errorReceived = listenOnce(serial.onReceiveError);
266   Promise.all([
267       connect(),
268       errorReceived
269           .then(checkReceiveError(expectedError)),
270       errorReceived
271           .then(getInfo)
272           .then(checkInfo({paused: true})),
273   ])
274       .then(disconnect)
275       .then(test.succeed, test.fail);
278 function runSendErrorTest(expectedError) {
279   connect()
280       .then(sendData)
281       .then(expectSendResult(0, expectedError))
282       .then(disconnect)
283       .then(test.succeed, test.fail);
286 unittestBindings.exportTests([
287   // Test that getDevices correctly transforms the data returned by the
288   // SerialDeviceEnumerator.
289   function testGetDevices() {
290     utils.promise(serial.getDevices).then(function(devices) {
291       test.assertEq(3, devices.length);
292       test.assertEq(4, $Object.keys(devices[0]).length);
293       test.assertEq('device', devices[0].path);
294       test.assertEq(1234, devices[0].vendorId);
295       test.assertEq(5678, devices[0].productId);
296       test.assertEq('foo', devices[0].displayName);
297       test.assertEq(1, $Object.keys(devices[1]).length);
298       test.assertEq('another_device', devices[1].path);
299       test.assertEq(1, $Object.keys(devices[2]).length);
300       test.assertEq('', devices[2].path);
301     }).then(test.succeed, test.fail);
302   },
304   // Test that the correct error message is returned when an error occurs in
305   // connecting to the port. This test uses an IoHandler that fails to connect.
306   function testConnectFail() {
307     serial.connect('device',
308                    test.callbackFail('Failed to connect to the port.'));
309   },
311   // Test that the correct error message is returned when an error occurs in
312   // calling getPortInfo after connecting to the port. This test uses an
313   // IoHandler that fails on calls to GetPortInfo.
314   function testGetInfoFailOnConnect() {
315     serial.connect('device',
316                    test.callbackFail('Failed to connect to the port.'));
317   },
319   // Test that the correct error message is returned when an invalid bit-rate
320   // value is passed to connect.
321   function testConnectInvalidBitrate() {
322     serial.connect('device', {bitrate: -1}, test.callbackFail(
323         'Failed to connect to the port.'));
324   },
326   // Test that a successful connect returns the expected connection info.
327   function testConnect() {
328     connect()
329         .then(checkConnectionInfo)
330         .then(disconnect)
331         .then(test.succeed, test.fail);
332   },
334   // Test that a connection created with no options has the correct default
335   // options.
336   function testConnectDefaultOptions() {
337     connect({}).then(function(connectionInfo) {
338       test.assertEq(9600, connectionInfo.bitrate);
339       test.assertEq('eight', connectionInfo.dataBits);
340       test.assertEq('no', connectionInfo.parityBit);
341       test.assertEq('one', connectionInfo.stopBits);
342       test.assertFalse(connectionInfo.ctsFlowControl);
343       test.assertFalse(connectionInfo.persistent);
344       test.assertEq('', connectionInfo.name);
345       test.assertEq(0, connectionInfo.receiveTimeout);
346       test.assertEq(0, connectionInfo.sendTimeout);
347       test.assertEq(4096, connectionInfo.bufferSize);
348     })
349         .then(disconnect)
350         .then(test.succeed, test.fail);
351   },
353   // Test that a getInfo call correctly converts the service-side info from the
354   // Mojo format and returns both it and the client-side configuration.
355   function testGetInfo() {
356     connect()
357         .then(getInfo)
358         .then(checkConnectionInfo)
359         .then(disconnect)
360         .then(test.succeed, test.fail);
361   },
363   // Test that a getInfo call returns the correct info after serialization.
364   function testGetInfoAfterSerialization() {
365     connect()
366         .then(serializeRoundTrip)
367         .then(getInfo)
368         .then(checkConnectionInfo)
369         .then(disconnect)
370         .then(test.succeed, test.fail);
371   },
373   // Test that only client-side options are returned when the service fails a
374   // getInfo call. This test uses an IoHandler that fails GetPortInfo calls
375   // after the initial call during connect.
376   function testGetInfoFailToGetPortInfo() {
377     var info = connect().then(getInfo);
378     Promise.all([
379         info.then(function(connectionInfo) {
380           test.assertFalse('bitrate' in connectionInfo);
381           test.assertFalse('dataBits' in connectionInfo);
382           test.assertFalse('parityBit' in connectionInfo);
383           test.assertFalse('stopBit' in connectionInfo);
384           test.assertFalse('ctsFlowControl' in connectionInfo);
385         }),
386         info.then(checkClientConnectionInfo),
387     ])
388         .then(disconnect)
389         .then(test.succeed, test.fail);
390   },
392   // Test that getConnections returns an array containing the open connection.
393   function testGetConnections() {
394     connect().then(function() {
395       return utils.promise(serial.getConnections);
396     }).then(function(connections) {
397       test.assertEq(1, connections.length);
398       checkConnectionInfo(connections[0]);
399     })
400         .then(disconnect)
401         .then(test.succeed, test.fail);
402   },
404   // Test that getControlSignals correctly converts the Mojo format result. This
405   // test uses an IoHandler that returns values matching the pattern being
406   // tested.
407   function testGetControlSignals() {
408     function checkControlSignals(expectedBitfield) {
409       return function(signals) {
410         test.assertEq(!!(expectedBitfield & 1), signals.dcd);
411         test.assertEq(!!(expectedBitfield & 2), signals.cts);
412         test.assertEq(!!(expectedBitfield & 4), signals.ri);
413         test.assertEq(!!(expectedBitfield & 8), signals.dsr);
414       };
415     }
416     var promiseChain = connect();
417     for (var i = 0; i < 16; i++) {
418       promiseChain = promiseChain
419           .then(getControlSignals)
420           .then(checkControlSignals(i));
421     }
422     promiseChain
423         .then(disconnect)
424         .then(test.succeed, test.fail);
425   },
427   // Test that setControlSignals correctly converts to the Mojo format result.
428   // This test uses an IoHandler that returns values following the same table of
429   // values as |signalsValues|.
430   function testSetControlSignals() {
431     var signalsValues = [
432       {},
433       {dtr: false},
434       {dtr: true},
435       {rts: false},
436       {dtr: false, rts: false},
437       {dtr: true, rts: false},
438       {rts: true},
439       {dtr: false, rts: true},
440       {dtr: true, rts: true},
441     ];
442     var promiseChain = connect();
443     for (var i = 0; i < signalsValues.length; i++) {
444       promiseChain = promiseChain.then(setControlSignals(signalsValues[i]));
445     }
446     promiseChain
447         .then(disconnect)
448         .then(test.succeed, test.fail);
449   },
451   // Test that update correctly passes values to the service only for
452   // service-side options and that all update calls are reflected by the result
453   // of getInfo calls. This test uses an IoHandler that expects corresponding
454   // ConfigurePort calls.
455   function testUpdate() {
456     var promiseChain = connect()
457         .then(getInfo)
458         .then(checkInfo(OPTIONS_VALUES[i]));
459     for (var i = 1; i < OPTIONS_VALUES.length; i++) {
460       promiseChain = promiseChain
461           .then(update(OPTIONS_VALUES[i]))
462           .then(expectSuccess)
463           .then(getInfo)
464           .then(checkInfo(OPTIONS_VALUES[i]));
465     }
466     promiseChain
467         .then(disconnect)
468         .then(test.succeed, test.fail);
469   },
471   // Test that options set by update persist after serialization.
472   function testUpdateAcrossSerialization() {
473     var promiseChain = connect()
474         .then(serializeRoundTrip)
475         .then(getInfo)
476         .then(checkInfo(OPTIONS_VALUES[i]));
477     for (var i = 1; i < OPTIONS_VALUES.length; i++) {
478       promiseChain = promiseChain
479           .then(update(OPTIONS_VALUES[i]))
480           .then(expectSuccess)
481           .then(serializeRoundTrip)
482           .then(getInfo)
483           .then(checkInfo(OPTIONS_VALUES[i]));
484     }
485     promiseChain
486         .then(disconnect)
487         .then(test.succeed, test.fail);
488   },
490   // Test that passing an invalid bit-rate reslts in an error.
491   function testUpdateInvalidBitrate() {
492     connect()
493         .then(update({bitrate: -1}))
494         .then(function(success) {
495       test.assertFalse(success);
496     })
497         .then(disconnect)
498         .then(test.succeed, test.fail);
499   },
501   // Test flush. This test uses an IoHandler that counts the number of flush
502   // calls.
503   function testFlush() {
504     connect().then(function() {
505       return utils.promise(serial.flush, connectionId);
506     })
507         .then(expectSuccess)
508         .then(disconnect)
509         .then(test.succeed, test.fail);
510   },
512   // Test that setPaused values are reflected by the results returned by getInfo
513   // calls.
514   function testSetPaused() {
515     connect()
516         .then(setPaused(true))
517         .then(getInfo)
518         .then(checkInfo({paused: true}))
519         .then(setPaused(false))
520         .then(getInfo)
521         .then(checkInfo({paused: false}))
522         .then(disconnect)
523         .then(test.succeed, test.fail);
524   },
526   // Test that a send and a receive correctly echoes data. This uses an
527   // IoHandler that echoes data sent to it.
528   function testEcho() {
529     Promise.all([
530         connect()
531             .then(sendData)
532             .then(expectSendResult(4)),
533         listenOnce(serial.onReceive)
534             .then(checkReceivedData),
535     ])
536         .then(disconnect)
537         .then(test.succeed, test.fail);
538   },
540   // Test that a send while another send is in progress returns a pending error.
541   function testSendDuringExistingSend() {
542     var connected = connect();
543     Promise.all([
544         connected
545             .then(sendData)
546             .then(expectSendResult(4)),
547         connected
548             .then(sendData)
549             .then(expectSendResult(0, 'pending')),
550     ])
551         .then(disconnect)
552         .then(test.succeed, test.fail);
553   },
555   // Test that a second send after the first finishes is successful. This uses
556   // an IoHandler that echoes data sent to it.
557   function testSendAfterSuccessfulSend() {
558     connect()
559         .then(sendData)
560         .then(expectSendResult(4))
561         .then(sendData)
562         .then(expectSendResult(4))
563         .then(disconnect)
564         .then(test.succeed, test.fail);
565   },
567   // Test that a second send after the first fails is successful. This uses an
568   // IoHandler that returns system_error for only the first send.
569   function testSendPartialSuccessWithError() {
570     connect()
571         .then(sendData)
572         .then(expectSendResult(2, 'system_error'))
573         .then(sendData)
574         .then(expectSendResult(4))
575         .then(disconnect)
576         .then(test.succeed, test.fail);
577   },
579   // Test that a send and a receive correctly echoes data after serialization.
580   function testEchoAfterSerialization() {
581     Promise.all([
582         connect()
583             .then(serializeRoundTrip)
584             .then(sendData)
585             .then(expectSendResult(4)),
586         listenOnce(serial.onReceive).then(checkReceivedData)
587     ])
588         .then(disconnect)
589         .then(test.succeed, test.fail);
590   },
592   // Test that a timed-out send returns a timeout error and that changing the
593   // send timeout during a send does not affect its timeout. This test uses an
594   // IoHandle that never completes sends.
595   function testSendTimeout() {
596     var connected = connect({sendTimeout: 5});
597     var sent = connected.then(sendData);
598     Promise.all([
599         sent.then(expectSendResult(0, 'timeout')),
600         sent.then(expectCurrentTime(5)),
601         connected.then(update({sendTimeout: 10}))
602             .then(expectSuccess)
603             .then(timeoutManager.run.bind(timeoutManager, 1)),
604     ])
605         .then(disconnect)
606         .then(test.succeed, test.fail);
607   },
609   // Test that send timeouts still function correctly after a serialization
610   // round trip.
611   function testSendTimeoutAfterSerialization() {
612     var connected = connect({sendTimeout: 5}).then(serializeRoundTrip);
613     var sent = connected.then(sendData);
614     Promise.all([
615         sent.then(expectSendResult(0, 'timeout')),
616         sent.then(expectCurrentTime(5)),
617         connected.then(update({sendTimeout: 10}))
618             .then(expectSuccess)
619             .then(timeoutManager.run.bind(timeoutManager, 1)),
620     ])
621         .then(disconnect)
622         .then(test.succeed, test.fail);
623   },
625   // Test that a timed-out send returns a timeout error and that disabling the
626   // send timeout during a send does not affect its timeout. This test uses an
627   // IoHandle that never completes sends.
628   function testDisableSendTimeout() {
629     var connected = connect({sendTimeout: 5});
630     var sent = connected.then(sendData);
631     Promise.all([
632         sent.then(expectSendResult(0, 'timeout')),
633         sent.then(expectCurrentTime(5)),
634         connected.then(update({sendTimeout: 0}))
635             .then(expectSuccess)
636             .then(timeoutManager.run.bind(timeoutManager, 1)),
637     ])
638         .then(disconnect)
639         .then(test.succeed, test.fail);
640   },
642   // Test that data received while the connection is paused is queued and
643   // dispatched once the connection is unpaused.
644   function testPausedReceive() {
645     Promise.all([
646         // Wait until the receive hook is installed, then start the test.
647         addReceiveHook(function() {
648           // Unpause the connection after the connection has queued the received
649           // data to ensure the queued data is dispatched when the connection is
650           // unpaused.
651           Promise.all([
652               utils.promise(serial.setPaused, connectionId, false),
653               // Check that setPaused(false) is idempotent.
654               utils.promise(serial.setPaused, connectionId, false),
655           ]).catch(test.fail);
656         })
657             .then(connect)
658             .then(function() {
659           // Check that setPaused(true) is idempotent.
660           return Promise.all([
661               utils.promise(serial.setPaused, connectionId, true),
662               utils.promise(serial.setPaused, connectionId, true),
663           ]);
664         }),
665         listenOnce(serial.onReceive).then(checkReceivedData),
666     ])
667         .then(disconnect)
668         .then(test.succeed, test.fail);
669   },
671   // Test that a receive error received while the connection is paused is queued
672   // and dispatched once the connection is unpaused.
673   function testPausedReceiveError() {
674     Promise.all([
675         // Wait until the receive hook is installed, then start the test.
676         addReceiveErrorHook(function() {
677           // Unpause the connection after the connection has queued the received
678           // data to ensure the queued data is dispatched when the connection is
679           // unpaused.
680           utils.promise(serial.setPaused, connectionId, false).catch(test.fail);
681         })
682             .then(connect)
683             .then(setPaused(true)),
684         listenOnce(serial.onReceiveError)
685             .then(checkReceiveError('device_lost')),
686     ])
687         .then(disconnect)
688         .then(test.succeed, test.fail);
689     serial.onReceive.addListener(function() {
690       test.fail('unexpected onReceive event');
691     });
692   },
694   // Test that receive timeouts trigger after the timeout time elapses and that
695   // changing the receive timeout does not affect a wait in progress.
696   function testReceiveTimeout() {
697     var errorReceived = listenOnce(serial.onReceiveError);
698     Promise.all([
699         errorReceived.then(checkReceiveError('timeout')),
700         errorReceived.then(expectCurrentTime(20)),
701         errorReceived
702             .then(getInfo)
703             .then(checkInfo({paused: false})),
704         connect({receiveTimeout: 20})
705             // Changing the timeout does not take effect until the current
706             // timeout expires or a receive completes.
707             .then(update({receiveTimeout: 10}))
708             .then(expectSuccess)
709             .then(timeoutManager.run.bind(timeoutManager, 1)),
710     ])
711         .then(disconnect)
712         .then(test.succeed, test.fail);
713   },
715   // Test that receive timeouts still function correctly after a serialization
716   // round trip.
717   function testReceiveTimeoutAfterSerialization() {
718     var errorReceived = listenOnce(serial.onReceiveError);
719     Promise.all([
720         errorReceived.then(checkReceiveError('timeout')),
721         errorReceived.then(expectCurrentTime(20)),
722         errorReceived
723             .then(getInfo)
724             .then(checkInfo({paused: false})),
725         connect({receiveTimeout: 20})
726             .then(serializeRoundTrip)
727             .then(timeoutManager.run.bind(timeoutManager, 1)),
728     ])
729         .then(disconnect)
730         .then(test.succeed, test.fail);
731   },
733   // Test that receive timeouts trigger after the timeout time elapses and that
734   // disabling the receive timeout does not affect a wait in progress.
735   function testDisableReceiveTimeout() {
736     var errorReceived = listenOnce(serial.onReceiveError);
737     Promise.all([
738         errorReceived.then(checkReceiveError('timeout')),
739         errorReceived.then(expectCurrentTime(20)),
740         errorReceived
741             .then(getInfo)
742             .then(checkInfo({paused: false})),
743         connect({receiveTimeout: 20})
744             // Disabling the timeout does not take effect until the current
745             // timeout expires or a receive completes.
746             .then(update({receiveTimeout: 0}))
747             .then(expectSuccess)
748             .then(timeoutManager.run.bind(timeoutManager, 1)),
749     ])
750         .then(disconnect)
751         .then(test.succeed, test.fail);
752   },
754   // Test that a receive error from the service is correctly dispatched. This
755   // test uses an IoHandler that only reports 'disconnected' receive errors.
756   function testReceiveErrorDisconnected() {
757     runReceiveErrorTest('disconnected');
758   },
760   // Test that a receive error from the service is correctly dispatched. This
761   // test uses an IoHandler that only reports 'device_lost' receive errors.
762   function testReceiveErrorDeviceLost() {
763     runReceiveErrorTest('device_lost');
764   },
766   // Test that a receive from error the service is correctly dispatched. This
767   // test uses an IoHandler that only reports 'system_error' receive errors.
768   function testReceiveErrorSystemError() {
769     runReceiveErrorTest('system_error');
770   },
772   // Test that a send error from the service is correctly returned as the send
773   // result. This test uses an IoHandler that only reports 'disconnected' send
774   // errors.
775   function testSendErrorDisconnected() {
776     runSendErrorTest('disconnected');
777   },
779   // Test that a send error from the service is correctly returned as the send
780   // result. This test uses an IoHandler that only reports 'system_error' send
781   // errors.
782   function testSendErrorSystemError() {
783     runSendErrorTest('system_error');
784   },
786   // Test that disconnect returns the correct error for a connection ID that
787   // does not exist.
788   function testDisconnectUnknownConnectionId() {
789     serial.disconnect(-1, test.callbackFail('Serial connection not found.'));
790   },
792   // Test that getInfo returns the correct error for a connection ID that does
793   // not exist.
794   function testGetInfoUnknownConnectionId() {
795     serial.getInfo(-1, test.callbackFail('Serial connection not found.'));
796   },
798   // Test that update returns the correct error for a connection ID that does
799   // not exist.
800   function testUpdateUnknownConnectionId() {
801     serial.update(-1, {}, test.callbackFail('Serial connection not found.'));
802   },
804   // Test that setControlSignals returns the correct error for a connection ID
805   // that does not exist.
806   function testSetControlSignalsUnknownConnectionId() {
807     serial.setControlSignals(-1, {}, test.callbackFail(
808         'Serial connection not found.'));
809   },
811   // Test that getControlSignals returns the correct error for a connection ID
812   // that does not exist.
813   function testGetControlSignalsUnknownConnectionId() {
814     serial.getControlSignals(-1, test.callbackFail(
815         'Serial connection not found.'));
816   },
818   // Test that flush returns the correct error for a connection ID that does not
819   // exist.
820   function testFlushUnknownConnectionId() {
821     serial.flush(-1, test.callbackFail('Serial connection not found.'));
822   },
824   // Test that setPaused returns the correct error for a connection ID that does
825   // not exist.
826   function testSetPausedUnknownConnectionId() {
827     serial.setPaused(
828         -1, true, test.callbackFail('Serial connection not found.'));
829     serial.setPaused(
830         -1, false, test.callbackFail('Serial connection not found.'));
831   },
833   // Test that send returns the correct error for a connection ID that does not
834   // exist.
835   function testSendUnknownConnectionId() {
836     var buffer = new ArrayBuffer(1);
837     serial.send(-1, buffer, test.callbackFail('Serial connection not found.'));
838   },
840   function testSendAndStash() {
841     connect()
842         .then(setPaused(true))
843         .then(sendData)
844         .then(expectSendResult(4))
845         .then(test.succeed, test.fail);
846   },
848   function testRestoreAndReceive() {
849     connectionId = 0;
850     Promise.all([
851         utils.promise(serial.setPaused, connectionId, false),
852         listenOnce(serial.onReceive).then(checkReceivedData),
853     ])
854         .then(disconnect)
855         .then(test.succeed, test.fail);
856   },
858   function testRestoreAndReceiveErrorSetUp() {
859     connect().then(test.succeed, test.fail);
860   },
862   function testRestoreAndReceiveError() {
863     connectionId = 0;
864     Promise.all([
865         utils.promise(serial.setPaused, connectionId, false),
866         listenOnce(serial.onReceiveError)
867             .then(checkReceiveError('device_lost')),
868     ])
869         .then(disconnect)
870         .then(test.succeed, test.fail);
871   },
873   function testStashNoConnections() {
874     connect({persistent: false}).then(test.succeed, test.fail);
875   },
877   function testRestoreNoConnections() {
878     connect()
879         .then(function(connectionInfo) {
880           test.assertEq(0, connectionInfo.connectionId);
881           return connectionInfo;
882         })
883         .then(checkConnectionInfo)
884         .then(disconnect)
885         .then(test.succeed, test.fail);
886   },
888 ], test.runTests, exports);