| OLD | NEW |
| (Empty) |
| 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 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'}, | |
| 42 ]; | |
| 43 | |
| 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 }); | |
| 58 } | |
| 59 | |
| 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 } | |
| 71 | |
| 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 } | |
| 83 | |
| 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 } | |
| 93 | |
| 94 return serialService.getConnections() | |
| 95 .then(serializeConnections) | |
| 96 .then(deserializeConnections); | |
| 97 }); | |
| 98 } | |
| 99 | |
| 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); | |
| 104 } | |
| 105 | |
| 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 }; | |
| 114 } | |
| 115 | |
| 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 }; | |
| 122 } | |
| 123 | |
| 124 // Checks that the previous operation succeeded. | |
| 125 function expectSuccess(success) { | |
| 126 test.assertTrue(success); | |
| 127 } | |
| 128 | |
| 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 }; | |
| 136 } | |
| 137 | |
| 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 } | |
| 143 } | |
| 144 | |
| 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); | |
| 149 } | |
| 150 | |
| 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 }; | |
| 157 } | |
| 158 | |
| 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 } | |
| 165 } | |
| 166 | |
| 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 }); | |
| 181 } | |
| 182 | |
| 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 }); | |
| 197 } | |
| 198 | |
| 199 function listenOnce(targetEvent) { | |
| 200 return new Promise(function(resolve, reject) { | |
| 201 targetEvent.addListener(function(result) { | |
| 202 resolve(result); | |
| 203 }); | |
| 204 }); | |
| 205 } | |
| 206 | |
| 207 function disconnect() { | |
| 208 return utils.promise(serial.disconnect, connectionId).then(function(success) { | |
| 209 test.assertTrue(success); | |
| 210 connectionId = null; | |
| 211 }); | |
| 212 } | |
| 213 | |
| 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); | |
| 221 } | |
| 222 | |
| 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); | |
| 229 } | |
| 230 | |
| 231 function checkConnectionInfo(connectionInfo) { | |
| 232 checkClientConnectionInfo(connectionInfo); | |
| 233 checkServiceConnectionInfo(connectionInfo); | |
| 234 test.assertEq(12, $Object.keys(connectionInfo).length); | |
| 235 } | |
| 236 | |
| 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); | |
| 245 } | |
| 246 | |
| 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 } | |
| 255 } | |
| 256 | |
| 257 function checkReceiveError(expectedError) { | |
| 258 return function(result) { | |
| 259 test.assertEq(connectionId, result.connectionId); | |
| 260 test.assertEq(expectedError, result.error); | |
| 261 } | |
| 262 } | |
| 263 | |
| 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); | |
| 276 } | |
| 277 | |
| 278 function runSendErrorTest(expectedError) { | |
| 279 connect() | |
| 280 .then(sendData) | |
| 281 .then(expectSendResult(0, expectedError)) | |
| 282 .then(disconnect) | |
| 283 .then(test.succeed, test.fail); | |
| 284 } | |
| 285 | |
| 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 }, | |
| 303 | |
| 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 }, | |
| 310 | |
| 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 }, | |
| 318 | |
| 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 }, | |
| 325 | |
| 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 }, | |
| 333 | |
| 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 }, | |
| 352 | |
| 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 }, | |
| 362 | |
| 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 }, | |
| 372 | |
| 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 }, | |
| 391 | |
| 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 }, | |
| 403 | |
| 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 }, | |
| 426 | |
| 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 }, | |
| 450 | |
| 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 }, | |
| 470 | |
| 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 }, | |
| 489 | |
| 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 }, | |
| 500 | |
| 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 }, | |
| 511 | |
| 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 }, | |
| 525 | |
| 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 }, | |
| 539 | |
| 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 }, | |
| 554 | |
| 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 }, | |
| 566 | |
| 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 }, | |
| 578 | |
| 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 }, | |
| 591 | |
| 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 }, | |
| 608 | |
| 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 }, | |
| 624 | |
| 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 }, | |
| 641 | |
| 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 }, | |
| 670 | |
| 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 }, | |
| 693 | |
| 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 }, | |
| 714 | |
| 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 }, | |
| 732 | |
| 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 }, | |
| 753 | |
| 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 }, | |
| 759 | |
| 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 }, | |
| 765 | |
| 766 // Test that a receive from error the service is correctly dispatched. This | |
| 767 // test uses an IoHandler that only reports 'break' receive errors. | |
| 768 function testReceiveErrorBreak() { | |
| 769 runReceiveErrorTest('break'); | |
| 770 }, | |
| 771 | |
| 772 // Test that a receive from error the service is correctly dispatched. This | |
| 773 // test uses an IoHandler that only reports 'frame_error' receive errors. | |
| 774 function testReceiveErrorFrameError() { | |
| 775 runReceiveErrorTest('frame_error'); | |
| 776 }, | |
| 777 | |
| 778 // Test that a receive from error the service is correctly dispatched. This | |
| 779 // test uses an IoHandler that only reports 'overrun' receive errors. | |
| 780 function testReceiveErrorOverrun() { | |
| 781 runReceiveErrorTest('overrun'); | |
| 782 }, | |
| 783 | |
| 784 // Test that a receive from error the service is correctly dispatched. This | |
| 785 // test uses an IoHandler that only reports 'buffer_overflow' receive errors. | |
| 786 function testReceiveErrorBufferOverflow() { | |
| 787 runReceiveErrorTest('buffer_overflow'); | |
| 788 }, | |
| 789 | |
| 790 // Test that a receive from error the service is correctly dispatched. This | |
| 791 // test uses an IoHandler that only reports 'parity_error' receive errors. | |
| 792 function testReceiveErrorParityError() { | |
| 793 runReceiveErrorTest('parity_error'); | |
| 794 }, | |
| 795 | |
| 796 // Test that a receive from error the service is correctly dispatched. This | |
| 797 // test uses an IoHandler that only reports 'system_error' receive errors. | |
| 798 function testReceiveErrorSystemError() { | |
| 799 runReceiveErrorTest('system_error'); | |
| 800 }, | |
| 801 | |
| 802 // Test that a send error from the service is correctly returned as the send | |
| 803 // result. This test uses an IoHandler that only reports 'disconnected' send | |
| 804 // errors. | |
| 805 function testSendErrorDisconnected() { | |
| 806 runSendErrorTest('disconnected'); | |
| 807 }, | |
| 808 | |
| 809 // Test that a send error from the service is correctly returned as the send | |
| 810 // result. This test uses an IoHandler that only reports 'system_error' send | |
| 811 // errors. | |
| 812 function testSendErrorSystemError() { | |
| 813 runSendErrorTest('system_error'); | |
| 814 }, | |
| 815 | |
| 816 // Test that disconnect returns the correct error for a connection ID that | |
| 817 // does not exist. | |
| 818 function testDisconnectUnknownConnectionId() { | |
| 819 serial.disconnect(-1, test.callbackFail('Serial connection not found.')); | |
| 820 }, | |
| 821 | |
| 822 // Test that getInfo returns the correct error for a connection ID that does | |
| 823 // not exist. | |
| 824 function testGetInfoUnknownConnectionId() { | |
| 825 serial.getInfo(-1, test.callbackFail('Serial connection not found.')); | |
| 826 }, | |
| 827 | |
| 828 // Test that update returns the correct error for a connection ID that does | |
| 829 // not exist. | |
| 830 function testUpdateUnknownConnectionId() { | |
| 831 serial.update(-1, {}, test.callbackFail('Serial connection not found.')); | |
| 832 }, | |
| 833 | |
| 834 // Test that setControlSignals returns the correct error for a connection ID | |
| 835 // that does not exist. | |
| 836 function testSetControlSignalsUnknownConnectionId() { | |
| 837 serial.setControlSignals(-1, {}, test.callbackFail( | |
| 838 'Serial connection not found.')); | |
| 839 }, | |
| 840 | |
| 841 // Test that getControlSignals returns the correct error for a connection ID | |
| 842 // that does not exist. | |
| 843 function testGetControlSignalsUnknownConnectionId() { | |
| 844 serial.getControlSignals(-1, test.callbackFail( | |
| 845 'Serial connection not found.')); | |
| 846 }, | |
| 847 | |
| 848 // Test that flush returns the correct error for a connection ID that does not | |
| 849 // exist. | |
| 850 function testFlushUnknownConnectionId() { | |
| 851 serial.flush(-1, test.callbackFail('Serial connection not found.')); | |
| 852 }, | |
| 853 | |
| 854 // Test that setPaused returns the correct error for a connection ID that does | |
| 855 // not exist. | |
| 856 function testSetPausedUnknownConnectionId() { | |
| 857 serial.setPaused( | |
| 858 -1, true, test.callbackFail('Serial connection not found.')); | |
| 859 serial.setPaused( | |
| 860 -1, false, test.callbackFail('Serial connection not found.')); | |
| 861 }, | |
| 862 | |
| 863 // Test that send returns the correct error for a connection ID that does not | |
| 864 // exist. | |
| 865 function testSendUnknownConnectionId() { | |
| 866 var buffer = new ArrayBuffer(1); | |
| 867 serial.send(-1, buffer, test.callbackFail('Serial connection not found.')); | |
| 868 }, | |
| 869 | |
| 870 function testSendAndStash() { | |
| 871 connect() | |
| 872 .then(setPaused(true)) | |
| 873 .then(sendData) | |
| 874 .then(expectSendResult(4)) | |
| 875 .then(test.succeed, test.fail); | |
| 876 }, | |
| 877 | |
| 878 function testRestoreAndReceive() { | |
| 879 connectionId = 0; | |
| 880 Promise.all([ | |
| 881 utils.promise(serial.setPaused, connectionId, false), | |
| 882 listenOnce(serial.onReceive).then(checkReceivedData), | |
| 883 ]) | |
| 884 .then(disconnect) | |
| 885 .then(test.succeed, test.fail); | |
| 886 }, | |
| 887 | |
| 888 function testRestoreAndReceiveErrorSetUp() { | |
| 889 connect().then(test.succeed, test.fail); | |
| 890 }, | |
| 891 | |
| 892 function testRestoreAndReceiveError() { | |
| 893 connectionId = 0; | |
| 894 Promise.all([ | |
| 895 utils.promise(serial.setPaused, connectionId, false), | |
| 896 listenOnce(serial.onReceiveError) | |
| 897 .then(checkReceiveError('device_lost')), | |
| 898 ]) | |
| 899 .then(disconnect) | |
| 900 .then(test.succeed, test.fail); | |
| 901 }, | |
| 902 | |
| 903 function testStashNoConnections() { | |
| 904 connect({persistent: false}).then(test.succeed, test.fail); | |
| 905 }, | |
| 906 | |
| 907 function testRestoreNoConnections() { | |
| 908 connect() | |
| 909 .then(function(connectionInfo) { | |
| 910 test.assertEq(0, connectionInfo.connectionId); | |
| 911 return connectionInfo; | |
| 912 }) | |
| 913 .then(checkConnectionInfo) | |
| 914 .then(disconnect) | |
| 915 .then(test.succeed, test.fail); | |
| 916 }, | |
| 917 | |
| 918 ], test.runTests, exports); | |
| OLD | NEW |