Home | History | Annotate | Download | only in data
      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);
    675