Index: extensions/test/data/serial_unittest.js |
diff --git a/extensions/test/data/serial_unittest.js b/extensions/test/data/serial_unittest.js |
index dc7bbea56e06cddd8453f3a73358d177fe90f9fb..c3cc504bd6132814736930a0a11e7a92b1a0c185 100644 |
--- a/extensions/test/data/serial_unittest.js |
+++ b/extensions/test/data/serial_unittest.js |
@@ -6,29 +6,69 @@ |
* Unit tests for the JS serial service client. |
* |
* These test that configuration and data are correctly transmitted between the |
- * client and the service. |
+ * client and the service. They are launched by |
+ * extensions/renderer/api/serial/serial_api_unittest.cc. |
*/ |
var test = require('test').binding; |
var serial = require('serial').binding; |
var unittestBindings = require('test_environment_specific_bindings'); |
+var utils = require('utils'); |
+ |
+var timeoutManager = new unittestBindings.TimeoutManager(); |
+timeoutManager.installGlobals(); |
+ |
+var BUFFER_SIZE = 10; |
var connectionId = null; |
function connect(callback, options) { |
options = options || { |
name: 'test connection', |
- bufferSize: 8192, |
+ bufferSize: BUFFER_SIZE, |
receiveTimeout: 12345, |
sendTimeout: 6789, |
persistent: true, |
- } |
+ }; |
serial.connect('device', options, test.callbackPass(function(connectionInfo) { |
connectionId = connectionInfo.connectionId; |
- callback(connectionInfo); |
+ if (callback) |
+ callback(connectionInfo); |
})); |
} |
+// Sets a function to be called once when data is received. Returns a promise |
+// that will resolve once the hook is installed. |
+function addReceiveHook(callback) { |
+ return requireAsync('serial_service').then(function(serialService) { |
+ var called = false; |
+ var dataReceived = serialService.Connection.prototype.onDataReceived_; |
+ serialService.Connection.prototype.onDataReceived_ = function() { |
+ var result = $Function.apply(dataReceived, this, arguments); |
+ if (!called) |
+ callback(); |
+ called = true; |
+ return result; |
+ }; |
+ }); |
+} |
+ |
+// Sets a function to be called once when a receive error is received. Returns a |
+// promise that will resolve once the hook is installed. |
+function addReceiveErrorHook(callback) { |
+ return requireAsync('serial_service').then(function(serialService) { |
+ var called = false; |
+ var receiveError = serialService.Connection.prototype.onReceiveError_; |
+ serialService.Connection.prototype.onReceiveError_ = function() { |
+ var result = $Function.apply(receiveError, this, arguments); |
+ if (!called) |
+ callback(); |
+ called = true; |
+ return result; |
+ }; |
+ }); |
+} |
+ |
function disconnect() { |
serial.disconnect(connectionId, test.callbackPass(function(success) { |
test.assertTrue(success); |
@@ -41,7 +81,7 @@ function checkClientConnectionInfo(connectionInfo) { |
test.assertEq('test connection', connectionInfo.name); |
test.assertEq(12345, connectionInfo.receiveTimeout); |
test.assertEq(6789, connectionInfo.sendTimeout); |
- test.assertEq(8192, connectionInfo.bufferSize); |
+ test.assertEq(BUFFER_SIZE, connectionInfo.bufferSize); |
test.assertFalse(connectionInfo.paused); |
} |
@@ -58,7 +98,52 @@ function checkConnectionInfo(connectionInfo) { |
checkServiceConnectionInfo(connectionInfo); |
} |
+function runReceiveErrorTest(expectedError) { |
+ connect(); |
+ test.listenOnce(serial.onReceiveError, function(result) { |
+ serial.getInfo(connectionId, test.callbackPass(function(connectionInfo) { |
+ disconnect(); |
+ test.assertTrue(connectionInfo.paused); |
+ })); |
+ test.assertEq(connectionId, result.connectionId); |
+ test.assertEq(expectedError, result.error); |
+ }); |
+} |
+ |
+function runSendErrorTest(expectedError) { |
+ connect(function() { |
+ var buffer = new ArrayBuffer(1); |
+ serial.send(connectionId, buffer, test.callbackPass(function(sendInfo) { |
+ disconnect(); |
+ test.assertEq(0, sendInfo.bytesSent); |
+ test.assertEq(expectedError, sendInfo.error); |
+ })); |
+ }); |
+} |
+ |
+function sendData() { |
+ var data = 'data'; |
+ var buffer = new ArrayBuffer(data.length); |
+ var byteBuffer = new Int8Array(buffer); |
+ for (var i = 0; i < data.length; i++) { |
+ byteBuffer[i] = data.charCodeAt(i); |
+ } |
+ return utils.promise(serial.send, connectionId, buffer); |
+} |
+ |
+function checkReceivedData(result) { |
+ var data = 'data'; |
+ test.assertEq(connectionId, result.connectionId); |
+ test.assertEq(data.length, result.data.byteLength); |
+ var resultByteBuffer = new Int8Array(result.data); |
+ for (var i = 0; i < data.length; i++) { |
+ test.assertEq(data.charCodeAt(i), resultByteBuffer[i]); |
+ } |
+} |
+ |
unittestBindings.exportTests([ |
+ // Test that getDevices correctly transforms the data returned by the |
+ // SerialDeviceEnumerator. |
function testGetDevices() { |
serial.getDevices(test.callbackPass(function(devices) { |
test.assertEq(3, devices.length); |
@@ -74,21 +159,29 @@ unittestBindings.exportTests([ |
})); |
}, |
+ // Test that the correct error message is returned when an error occurs in |
+ // connecting to the port. This test uses an IoHandler that fails to connect. |
function testConnectFail() { |
serial.connect('device', |
test.callbackFail('Failed to connect to the port.')); |
}, |
+ // Test that the correct error message is returned when an error occurs in |
+ // calling getPortInfo after connecting to the port. This test uses an |
+ // IoHandler that fails on calls to GetPortInfo. |
function testGetInfoFailOnConnect() { |
serial.connect('device', |
test.callbackFail('Failed to connect to the port.')); |
}, |
+ // Test that the correct error message is returned when an invalid bit-rate |
+ // value is passed to connect. |
function testConnectInvalidBitrate() { |
serial.connect('device', {bitrate: -1}, test.callbackFail( |
'Failed to connect to the port.')); |
}, |
+ // Test that a successful connect returns the expected connection info. |
function testConnect() { |
connect(function(connectionInfo) { |
disconnect(); |
@@ -96,6 +189,8 @@ unittestBindings.exportTests([ |
}); |
}, |
+ // Test that a connection created with no options has the correct default |
+ // options. |
function testConnectDefaultOptions() { |
connect(function(connectionInfo) { |
disconnect(); |
@@ -112,6 +207,8 @@ unittestBindings.exportTests([ |
}, {}); |
}, |
+ // Test that a getInfo call correctly converts the service-side info from the |
+ // Mojo format and returns both it and the client-side configuration. |
function testGetInfo() { |
connect(function() { |
serial.getInfo(connectionId, |
@@ -122,6 +219,9 @@ unittestBindings.exportTests([ |
}); |
}, |
+ // Test that only client-side options are returned when the service fails a |
+ // getInfo call. This test uses an IoHandler that fails GetPortInfo calls |
+ // after the initial call during connect. |
function testGetInfoFailToGetPortInfo() { |
connect(function() { |
serial.getInfo(connectionId, |
@@ -137,6 +237,7 @@ unittestBindings.exportTests([ |
}); |
}, |
+ // Test that getConnections returns an array containing the open connection. |
function testGetConnections() { |
connect(function() { |
serial.getConnections(test.callbackPass(function(connections) { |
@@ -147,6 +248,9 @@ unittestBindings.exportTests([ |
}); |
}, |
+ // Test that getControlSignals correctly converts the Mojo format result. This |
+ // test uses an IoHandler that returns values matching the pattern being |
+ // tested. |
function testGetControlSignals() { |
connect(function() { |
var calls = 0; |
@@ -169,6 +273,9 @@ unittestBindings.exportTests([ |
}); |
}, |
+ // Test that setControlSignals correctly converts to the Mojo format result. |
+ // This test uses an IoHandler that returns values following the same table of |
+ // values as |signalsValues|. |
function testSetControlSignals() { |
connect(function() { |
var signalsValues = [ |
@@ -197,6 +304,10 @@ unittestBindings.exportTests([ |
}); |
}, |
+ // Test that update correctly passes values to the service only for |
+ // service-side options and that all update calls are reflected by the result |
+ // of getInfo calls. This test uses an IoHandler that expects corresponding |
+ // ConfigurePort calls. |
function testUpdate() { |
connect(function() { |
var optionsValues = [ |
@@ -240,6 +351,7 @@ unittestBindings.exportTests([ |
}); |
}, |
+ // Test that passing an invalid bit-rate reslts in an error. |
function testUpdateInvalidBitrate() { |
connect(function() { |
serial.update(connectionId, |
@@ -251,16 +363,19 @@ unittestBindings.exportTests([ |
}); |
}, |
+ // Test flush. This test uses an IoHandler that counts the number of flush |
+ // calls. |
function testFlush() { |
connect(function() { |
- serial.flush(connectionId, |
- test.callbackPass(function(success) { |
+ serial.flush(connectionId, test.callbackPass(function(success) { |
disconnect(); |
test.assertTrue(success); |
})); |
}); |
}, |
+ // Test that setPaused values are reflected by the results returned by getInfo |
+ // calls. |
function testSetPaused() { |
connect(function() { |
serial.setPaused(connectionId, true, test.callbackPass(function() { |
@@ -277,36 +392,283 @@ unittestBindings.exportTests([ |
}); |
}, |
+ // Test that a send and a receive correctly echoes data. This uses an |
+ // IoHandler that echoes data sent to it. |
+ function testEcho() { |
+ connect(function() { |
+ sendData().then(test.callbackPass(function(sendInfo) { |
+ test.assertEq(4, sendInfo.bytesSent); |
+ test.assertEq(undefined, sendInfo.error); |
+ })); |
+ test.listenOnce(serial.onReceive, function(result) { |
+ checkReceivedData(result); |
+ disconnect(); |
+ }); |
+ }); |
+ }, |
+ |
+ // Test that a send while another send is in progress returns a pending error. |
+ function testSendDuringExistingSend() { |
+ connect(function() { |
+ sendData().then(test.callbackPass(function(sendInfo) { |
+ test.assertEq(4, sendInfo.bytesSent); |
+ test.assertEq(undefined, sendInfo.error); |
+ disconnect(); |
+ })); |
+ sendData().then(test.callbackPass(function(sendInfo) { |
+ test.assertEq(0, sendInfo.bytesSent); |
+ test.assertEq('pending', sendInfo.error); |
+ })); |
+ }); |
+ }, |
+ |
+ // Test that a second send after the first finishes is successful. This uses |
+ // an IoHandler that echoes data sent to it. |
+ function testSendAfterSuccessfulSend() { |
+ connect(function() { |
+ sendData().then(test.callbackPass(function(sendInfo) { |
+ test.assertEq(4, sendInfo.bytesSent); |
+ test.assertEq(undefined, sendInfo.error); |
+ return sendData(); |
+ })).then(test.callbackPass(function(sendInfo) { |
+ test.assertEq(4, sendInfo.bytesSent); |
+ test.assertEq(undefined, sendInfo.error); |
+ })); |
+ // Check that the correct data is echoed twice. |
+ test.listenOnce(serial.onReceive, function(result) { |
+ checkReceivedData(result); |
+ test.listenOnce(serial.onReceive, function(result) { |
+ checkReceivedData(result); |
+ disconnect(); |
+ }); |
+ }); |
+ }); |
+ }, |
+ |
+ // Test that a second send after the first fails is successful. This uses an |
+ // IoHandler that returns system_error for only the first send. |
+ function testSendPartialSuccessWithError() { |
+ connect(function() { |
+ sendData().then(test.callbackPass(function(sendInfo) { |
+ test.assertEq(2, sendInfo.bytesSent); |
+ test.assertEq('system_error', sendInfo.error); |
+ return sendData(); |
+ })).then(test.callbackPass(function(sendInfo) { |
+ test.assertEq(4, sendInfo.bytesSent); |
+ test.assertEq(undefined, sendInfo.error); |
+ disconnect(); |
+ })); |
+ }); |
+ }, |
+ |
+ // Test that a timed-out send returns a timeout error and that changing the |
+ // send timeout during a send does not affect its timeout. This test uses an |
+ // IoHandle that never completes sends. |
+ function testSendTimeout() { |
+ connect(function() { |
+ sendData().then(test.callbackPass(function(sendInfo) { |
+ test.assertEq(0, sendInfo.bytesSent); |
+ test.assertEq('timeout', sendInfo.error); |
+ test.assertEq(5, timeoutManager.currentTime); |
+ disconnect(); |
+ })); |
+ serial.update(connectionId, {sendTimeout: 10}, test.callbackPass( |
+ timeoutManager.run.bind(timeoutManager, 1))); |
+ }, {sendTimeout: 5}); |
+ }, |
+ |
+ // Test that a timed-out send returns a timeout error and that disabling the |
+ // send timeout during a send does not affect its timeout. This test uses an |
+ // IoHandle that never completes sends. |
+ function testDisableSendTimeout() { |
+ connect(function() { |
+ sendData().then(test.callbackPass(function(sendInfo) { |
+ test.assertEq(0, sendInfo.bytesSent); |
+ test.assertEq('timeout', sendInfo.error); |
+ test.assertEq(6, timeoutManager.currentTime); |
+ disconnect(); |
+ })); |
+ serial.update(connectionId, {sendTimeout: 0}, test.callbackPass( |
+ timeoutManager.run.bind(timeoutManager, 1))); |
+ }, {sendTimeout: 6}); |
+ }, |
+ |
+ // Test that data received while the connection is paused is queued and |
+ // dispatched once the connection is unpaused. |
+ function testPausedReceive() { |
+ // Wait until the receive hook is installed, then start the test. |
+ addReceiveHook(function() { |
+ // Unpause the connection after the connection has queued the received |
+ // data to ensure the queued data is dispatched when the connection is |
+ // unpaused. |
+ serial.setPaused(connectionId, false, test.callbackPass()); |
+ // Check that setPaused(false) is idempotent. |
+ serial.setPaused(connectionId, false, test.callbackPass()); |
+ }).then(function() { |
+ connect(function() { |
+ // Check that setPaused(true) is idempotent. |
+ serial.setPaused(connectionId, true, test.callbackPass()); |
+ serial.setPaused(connectionId, true, test.callbackPass()); |
+ }); |
+ }); |
+ test.listenOnce(serial.onReceive, function(result) { |
+ checkReceivedData(result); |
+ disconnect(); |
+ }); |
+ }, |
+ |
+ // Test that a receive error received while the connection is paused is queued |
+ // and dispatched once the connection is unpaused. |
+ function testPausedReceiveError() { |
+ addReceiveErrorHook(function() { |
+ // Unpause the connection after the connection has queued the receive |
+ // error to ensure the queued error is dispatched when the connection is |
+ // unpaused. |
+ serial.setPaused(connectionId, false, test.callbackPass()); |
+ }).then(test.callbackPass(function() { |
+ connect(function() { |
+ serial.setPaused(connectionId, true, test.callbackPass()); |
+ }); |
+ })); |
+ |
+ test.listenOnce(serial.onReceiveError, function(result) { |
+ serial.getInfo(connectionId, test.callbackPass(function(connectionInfo) { |
+ disconnect(); |
+ test.assertTrue(connectionInfo.paused); |
+ })); |
+ test.assertEq(connectionId, result.connectionId); |
+ test.assertEq('device_lost', result.error); |
+ }); |
+ serial.onReceive.addListener(function() { |
+ test.fail('unexpected onReceive event'); |
+ }); |
+ }, |
+ |
+ // Test that receive timeouts trigger after the timeout time elapses and that |
+ // changing the receive timeout does not affect a wait in progress. |
+ function testReceiveTimeout() { |
+ connect(function() { |
+ test.listenOnce(serial.onReceiveError, function(result) { |
+ test.assertEq(connectionId, result.connectionId); |
+ test.assertEq('timeout', result.error); |
+ test.assertEq(20, timeoutManager.currentTime); |
+ serial.getInfo(connectionId, test.callbackPass( |
+ function(connectionInfo) { |
+ test.assertFalse(connectionInfo.paused); |
+ disconnect(); |
+ })); |
+ }); |
+ // Changing the timeout does not take effect until the current timeout |
+ // expires or a receive completes. |
+ serial.update(connectionId, {receiveTimeout: 10}, test.callbackPass( |
+ timeoutManager.run.bind(timeoutManager, 1))); |
+ }, {receiveTimeout: 20}); |
+ }, |
+ |
+ // Test that receive timeouts trigger after the timeout time elapses and that |
+ // disabling the receive timeout does not affect a wait in progress. |
+ function testDisableReceiveTimeout() { |
+ connect(function() { |
+ test.listenOnce(serial.onReceiveError, function(result) { |
+ test.assertEq(connectionId, result.connectionId); |
+ test.assertEq('timeout', result.error); |
+ test.assertEq(30, timeoutManager.currentTime); |
+ serial.getInfo(connectionId, test.callbackPass( |
+ function(connectionInfo) { |
+ disconnect(); |
+ test.assertFalse(connectionInfo.paused); |
+ })); |
+ }); |
+ // Disabling the timeout does not take effect until the current timeout |
+ // expires or a receive completes. |
+ serial.update(connectionId, {receiveTimeout: 0}, test.callbackPass( |
+ timeoutManager.run.bind(timeoutManager, 1))); |
+ }, {receiveTimeout: 30}); |
+ }, |
+ |
+ // Test that a receive error from the service is correctly dispatched. This |
+ // test uses an IoHandler that only reports 'disconnected' receive errors. |
+ function testReceiveErrorDisconnected() { |
+ runReceiveErrorTest('disconnected'); |
+ }, |
+ |
+ // Test that a receive error from the service is correctly dispatched. This |
+ // test uses an IoHandler that only reports 'device_lost' receive errors. |
+ function testReceiveErrorDeviceLost() { |
+ runReceiveErrorTest('device_lost'); |
+ }, |
+ |
+ // Test that a receive from error the service is correctly dispatched. This |
+ // test uses an IoHandler that only reports 'system_error' receive errors. |
+ function testReceiveErrorSystemError() { |
+ runReceiveErrorTest('system_error'); |
+ }, |
+ |
+ // Test that a send error from the service is correctly returned as the send |
+ // result. This test uses an IoHandler that only reports 'disconnected' send |
+ // errors. |
+ function testSendErrorDisconnected() { |
+ runSendErrorTest('disconnected'); |
+ }, |
+ |
+ // Test that a send error from the service is correctly returned as the send |
+ // result. This test uses an IoHandler that only reports 'system_error' send |
+ // errors. |
+ function testSendErrorSystemError() { |
+ runSendErrorTest('system_error'); |
+ }, |
+ |
+ // Test that disconnect returns the correct error for a connection ID that |
+ // does not exist. |
function testDisconnectUnknownConnectionId() { |
serial.disconnect(-1, test.callbackFail('Serial connection not found.')); |
}, |
+ // Test that getInfo returns the correct error for a connection ID that does |
+ // not exist. |
function testGetInfoUnknownConnectionId() { |
serial.getInfo(-1, test.callbackFail('Serial connection not found.')); |
}, |
+ // Test that update returns the correct error for a connection ID that does |
+ // not exist. |
function testUpdateUnknownConnectionId() { |
serial.update(-1, {}, test.callbackFail('Serial connection not found.')); |
}, |
+ // Test that setControlSignals returns the correct error for a connection ID |
+ // that does not exist. |
function testSetControlSignalsUnknownConnectionId() { |
serial.setControlSignals(-1, {}, test.callbackFail( |
'Serial connection not found.')); |
}, |
+ // Test that getControlSignals returns the correct error for a connection ID |
+ // that does not exist. |
function testGetControlSignalsUnknownConnectionId() { |
serial.getControlSignals(-1, test.callbackFail( |
'Serial connection not found.')); |
}, |
+ // Test that flush returns the correct error for a connection ID that does not |
+ // exist. |
function testFlushUnknownConnectionId() { |
serial.flush(-1, test.callbackFail('Serial connection not found.')); |
}, |
+ // Test that setPaused returns the correct error for a connection ID that does |
+ // not exist. |
function testSetPausedUnknownConnectionId() { |
serial.setPaused( |
-1, true, test.callbackFail('Serial connection not found.')); |
serial.setPaused( |
-1, false, test.callbackFail('Serial connection not found.')); |
}, |
+ |
+ // Test that send returns the correct error for a connection ID that does not |
+ // exist. |
+ function testSendUnknownConnectionId() { |
+ var buffer = new ArrayBuffer(1); |
+ serial.send(-1, buffer, test.callbackFail('Serial connection not found.')); |
+ }, |
], test.runTests, exports); |