summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--device/serial/BUILD.gn1
-rw-r--r--device/serial/serial.gyp3
-rw-r--r--device/serial/serial_serialization.mojom31
-rw-r--r--extensions/renderer/api/serial/serial_api_unittest.cc25
-rw-r--r--extensions/renderer/resources/extensions_renderer_resources.grd1
-rw-r--r--extensions/renderer/resources/serial_custom_bindings.js4
-rw-r--r--extensions/renderer/resources/serial_service.js248
-rw-r--r--extensions/test/data/serial_unittest.js799
8 files changed, 713 insertions, 399 deletions
diff --git a/device/serial/BUILD.gn b/device/serial/BUILD.gn
index ccab385..5e0dff6 100644
--- a/device/serial/BUILD.gn
+++ b/device/serial/BUILD.gn
@@ -77,5 +77,6 @@ mojom("serial_mojo") {
"data_stream.mojom",
"data_stream_serialization.mojom",
"serial.mojom",
+ "serial_serialization.mojom",
]
}
diff --git a/device/serial/serial.gyp b/device/serial/serial.gyp
index 1e0d05e..e9e47f2 100644
--- a/device/serial/serial.gyp
+++ b/device/serial/serial.gyp
@@ -21,6 +21,7 @@
'data_stream.mojom',
'data_stream_serialization.mojom',
'serial.mojom',
+ 'serial_serialization.mojom',
],
},
{
@@ -55,6 +56,8 @@
'<(SHARED_INTERMEDIATE_DIR)/device/serial/data_stream_serialization.mojom.h',
'<(SHARED_INTERMEDIATE_DIR)/device/serial/serial.mojom.cc',
'<(SHARED_INTERMEDIATE_DIR)/device/serial/serial.mojom.h',
+ '<(SHARED_INTERMEDIATE_DIR)/device/serial/serial_serialization.mojom.cc',
+ '<(SHARED_INTERMEDIATE_DIR)/device/serial/serial_serialization.mojom.h',
'async_waiter.cc',
'async_waiter.h',
'buffer.cc',
diff --git a/device/serial/serial_serialization.mojom b/device/serial/serial_serialization.mojom
new file mode 100644
index 0000000..77a7ef7
--- /dev/null
+++ b/device/serial/serial_serialization.mojom
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import "serial.mojom"
+import "data_stream_serialization.mojom"
+
+module device.serial {
+
+// The client state of a serial connection.
+struct ConnectionState {
+ uint32 connectionId;
+ bool paused = false;
+ bool persistent = false;
+ string name = "";
+ uint32 receiveTimeout = 0;
+ uint32 sendTimeout = 0;
+ uint32 bufferSize = 4096;
+};
+
+// A serialized serial connection.
+struct SerializedConnection {
+ ConnectionState state;
+ ReceiveError queuedReceiveError = NONE;
+ array<int8>? queuedReceiveData;
+ Connection connection;
+ SerializedDataSender sender;
+ SerializedDataReceiver receiver;
+};
+
+}
diff --git a/extensions/renderer/api/serial/serial_api_unittest.cc b/extensions/renderer/api/serial/serial_api_unittest.cc
index bf14bf3..bc60b7d 100644
--- a/extensions/renderer/api/serial/serial_api_unittest.cc
+++ b/extensions/renderer/api/serial/serial_api_unittest.cc
@@ -407,6 +407,8 @@ class SerialApiTest : public ApiTestBase {
env()->RegisterModule("device/serial/data_stream_serialization.mojom",
IDR_DATA_STREAM_SERIALIZATION_MOJOM_JS);
env()->RegisterModule("device/serial/serial.mojom", IDR_SERIAL_MOJOM_JS);
+ env()->RegisterModule("device/serial/serial_serialization.mojom",
+ IDR_SERIAL_SERIALIZATION_MOJOM_JS);
service_provider()->AddService<device::serial::SerialService>(base::Bind(
&SerialApiTest::CreateSerialService, base::Unretained(this)));
}
@@ -465,6 +467,10 @@ TEST_F(SerialApiTest, GetInfo) {
RunTest("serial_unittest.js", "testGetInfo");
}
+TEST_F(SerialApiTest, GetInfoAfterSerialization) {
+ RunTest("serial_unittest.js", "testGetInfoAfterSerialization");
+}
+
TEST_F(SerialApiTest, GetInfoFailToGetPortInfo) {
io_handler_ = new FailToGetInfoTestIoHandler(1);
RunTest("serial_unittest.js", "testGetInfoFailToGetPortInfo");
@@ -492,6 +498,12 @@ TEST_F(SerialApiTest, Update) {
EXPECT_EQ(11u, io_handler_->num_calls());
}
+TEST_F(SerialApiTest, UpdateAcrossSerialization) {
+ io_handler_ = new ConfigurePortTestIoHandler;
+ RunTest("serial_unittest.js", "testUpdateAcrossSerialization");
+ EXPECT_EQ(11u, io_handler_->num_calls());
+}
+
TEST_F(SerialApiTest, UpdateInvalidBitrate) {
io_handler_ = new ConfigurePortTestIoHandler;
RunTest("serial_unittest.js", "testUpdateInvalidBitrate");
@@ -512,6 +524,10 @@ TEST_F(SerialApiTest, Echo) {
RunTest("serial_unittest.js", "testEcho");
}
+TEST_F(SerialApiTest, EchoAfterSerialization) {
+ RunTest("serial_unittest.js", "testEchoAfterSerialization");
+}
+
TEST_F(SerialApiTest, SendDuringExistingSend) {
RunTest("serial_unittest.js", "testSendDuringExistingSend");
}
@@ -530,6 +546,11 @@ TEST_F(SerialApiTest, SendTimeout) {
RunTest("serial_unittest.js", "testSendTimeout");
}
+TEST_F(SerialApiTest, SendTimeoutAfterSerialization) {
+ io_handler_ = new BlockSendsForeverSendIoHandler();
+ RunTest("serial_unittest.js", "testSendTimeoutAfterSerialization");
+}
+
TEST_F(SerialApiTest, DisableSendTimeout) {
io_handler_ = new BlockSendsForeverSendIoHandler();
RunTest("serial_unittest.js", "testDisableSendTimeout");
@@ -550,6 +571,10 @@ TEST_F(SerialApiTest, ReceiveTimeout) {
RunTest("serial_unittest.js", "testReceiveTimeout");
}
+TEST_F(SerialApiTest, ReceiveTimeoutAfterSerialization) {
+ RunTest("serial_unittest.js", "testReceiveTimeoutAfterSerialization");
+}
+
TEST_F(SerialApiTest, DisableReceiveTimeout) {
RunTest("serial_unittest.js", "testDisableReceiveTimeout");
}
diff --git a/extensions/renderer/resources/extensions_renderer_resources.grd b/extensions/renderer/resources/extensions_renderer_resources.grd
index 82aee00..8d984c7 100644
--- a/extensions/renderer/resources/extensions_renderer_resources.grd
+++ b/extensions/renderer/resources/extensions_renderer_resources.grd
@@ -25,6 +25,7 @@
<include name="IDR_SEND_REQUEST_JS" file="send_request.js" type="BINDATA" />
<include name="IDR_SERIAL_CUSTOM_BINDINGS_JS" file="serial_custom_bindings.js" type="BINDATA" />
<include name="IDR_SERIAL_MOJOM_JS" file="${mojom_root}\device\serial\serial.mojom.js" use_base_dir="false" type="BINDATA" />
+ <include name="IDR_SERIAL_SERIALIZATION_MOJOM_JS" file="${mojom_root}\device\serial\serial_serialization.mojom.js" use_base_dir="false" type="BINDATA" />
<include name="IDR_SERIAL_SERVICE_JS" file="serial_service.js" type="BINDATA" />
<include name="IDR_SET_ICON_JS" file="set_icon.js" type="BINDATA" />
<include name="IDR_BROWSER_TEST_ENVIRONMENT_SPECIFIC_BINDINGS_JS" file="browser_test_environment_specific_bindings.js" type="BINDATA" />
diff --git a/extensions/renderer/resources/serial_custom_bindings.js b/extensions/renderer/resources/serial_custom_bindings.js
index f0af8da..8c943ed 100644
--- a/extensions/renderer/resources/serial_custom_bindings.js
+++ b/extensions/renderer/resources/serial_custom_bindings.js
@@ -93,8 +93,8 @@ binding.registerCustomHook(function(bindingsAPI) {
return serialService.getConnections();
}).then(function(connections) {
var promises = [];
- for (var id in connections) {
- promises.push(connections[id].getInfo());
+ for (var connection of connections.values()) {
+ promises.push(connection.getInfo());
}
return Promise.all(promises);
});
diff --git a/extensions/renderer/resources/serial_service.js b/extensions/renderer/resources/serial_service.js
index 0e0327d..aa53eb4 100644
--- a/extensions/renderer/resources/serial_service.js
+++ b/extensions/renderer/resources/serial_service.js
@@ -7,12 +7,14 @@ define('serial_service', [
'data_receiver',
'data_sender',
'device/serial/serial.mojom',
+ 'device/serial/serial_serialization.mojom',
'mojo/public/js/bindings/core',
'mojo/public/js/bindings/router',
], function(serviceProvider,
dataReceiver,
dataSender,
serialMojom,
+ serialization,
core,
routerModule) {
/**
@@ -42,14 +44,6 @@ define('serial_service', [
});
}
- var DEFAULT_CLIENT_OPTIONS = {
- persistent: false,
- name: '',
- receiveTimeout: 0,
- sendTimeout: 0,
- bufferSize: 4096,
- };
-
var DATA_BITS_TO_MOJO = {
undefined: serialMojom.DataBits.NONE,
'seven': serialMojom.DataBits.SEVEN,
@@ -126,39 +120,66 @@ define('serial_service', [
};
}
- function Connection(
- remoteConnection, router, receivePipe, sendPipe, id, options) {
- this.remoteConnection_ = remoteConnection;
- this.router_ = router;
- this.options_ = {};
- for (var key in DEFAULT_CLIENT_OPTIONS) {
- this.options_[key] = DEFAULT_CLIENT_OPTIONS[key];
- }
- this.setClientOptions_(options);
- this.receivePipe_ =
- new dataReceiver.DataReceiver(receivePipe,
- this.options_.bufferSize,
- serialMojom.ReceiveError.DISCONNECTED);
- this.sendPipe_ = new dataSender.DataSender(
- sendPipe, this.options_.bufferSize, serialMojom.SendError.DISCONNECTED);
- this.id_ = id;
- getConnections().then(function(connections) {
- connections[this.id_] = this;
- }.bind(this));
- this.paused_ = false;
- this.sendInProgress_ = false;
+ // Update client-side options |clientOptions| from the user-provided
+ // |options|.
+ function updateClientOptions(clientOptions, options) {
+ if ('name' in options)
+ clientOptions.name = options.name;
+ if ('receiveTimeout' in options)
+ clientOptions.receiveTimeout = options.receiveTimeout;
+ if ('sendTimeout' in options)
+ clientOptions.sendTimeout = options.sendTimeout;
+ if ('bufferSize' in options)
+ clientOptions.bufferSize = options.bufferSize;
+ };
- // queuedReceiveData_ or queuedReceiveError will store the receive result or
- // error, respectively, if a receive completes or fails while this
+ function Connection(connection, router, receivePipe, sendPipe, id, options) {
+ var state = new serialization.ConnectionState();
+ state.connectionId = id;
+ updateClientOptions(state, options);
+ var receiver = new dataReceiver.DataReceiver(
+ receivePipe, state.bufferSize, serialMojom.ReceiveError.DISCONNECTED);
+ var sender = new dataSender.DataSender(
+ sendPipe, state.bufferSize, serialMojom.SendError.DISCONNECTED);
+ this.init_(state,
+ connection,
+ router,
+ receiver,
+ sender,
+ null,
+ serialMojom.ReceiveError.NONE);
+ connections_.set(id, this);
+ this.startReceive_();
+ }
+
+ // Initializes this Connection from the provided args.
+ Connection.prototype.init_ = function(state,
+ connection,
+ router,
+ receiver,
+ sender,
+ queuedReceiveData,
+ queuedReceiveError) {
+ this.state_ = state;
+
+ // queuedReceiveData_ or queuedReceiveError_ will store the receive result
+ // or error, respectively, if a receive completes or fails while this
// connection is paused. At most one of the the two may be non-null: a
// receive completed while paused will only set one of them, no further
// receives will be performed while paused and a queued result is dispatched
// before any further receives are initiated when unpausing.
- this.queuedReceiveData_ = null;
- this.queuedReceiveError = null;
-
- this.startReceive_();
- }
+ if (queuedReceiveError != serialMojom.ReceiveError.NONE)
+ this.queuedReceiveError_ = {error: queuedReceiveError};
+ if (queuedReceiveData) {
+ this.queuedReceiveData_ = new ArrayBuffer(queuedReceiveData.length);
+ new Int8Array(this.queuedReceiveData_).set(queuedReceiveData);
+ }
+ this.router_ = router;
+ this.remoteConnection_ = connection;
+ this.receivePipe_ = receiver;
+ this.sendPipe_ = sender;
+ this.sendInProgress_ = false;
+ };
Connection.create = function(path, options) {
options = options || {};
@@ -206,21 +227,20 @@ define('serial_service', [
this.sendPipe_.close();
clearTimeout(this.receiveTimeoutId_);
clearTimeout(this.sendTimeoutId_);
- return getConnections().then(function(connections) {
- delete connections[this.id_];
- return true;
- }.bind(this));
+ connections_.delete(this.state_.connectionId);
+ return true;
};
Connection.prototype.getClientInfo_ = function() {
- var info = {
- connectionId: this.id_,
- paused: this.paused_,
+ return {
+ connectionId: this.state_.connectionId,
+ paused: this.state_.paused,
+ persistent: this.state_.persistent,
+ name: this.state_.name,
+ receiveTimeout: this.state_.receiveTimeout,
+ sendTimeout: this.state_.sendTimeout,
+ bufferSize: this.state_.bufferSize,
};
- for (var key in this.options_) {
- info[key] = this.options_[key];
- }
- return info;
};
Connection.prototype.getInfo = function() {
@@ -236,19 +256,8 @@ define('serial_service', [
});
};
- Connection.prototype.setClientOptions_ = function(options) {
- if ('name' in options)
- this.options_.name = options.name;
- if ('receiveTimeout' in options)
- this.options_.receiveTimeout = options.receiveTimeout;
- if ('sendTimeout' in options)
- this.options_.sendTimeout = options.sendTimeout;
- if ('bufferSize' in options)
- this.options_.bufferSize = options.bufferSize;
- };
-
Connection.prototype.setOptions = function(options) {
- this.setClientOptions_(options);
+ updateClientOptions(this.state_, options);
var serviceOptions = getServiceOptions(options);
if ($Object.keys(serviceOptions).length == 0)
return true;
@@ -297,7 +306,7 @@ define('serial_service', [
};
Connection.prototype.setPaused = function(paused) {
- this.paused_ = paused;
+ this.state_.paused = paused;
if (paused) {
clearTimeout(this.receiveTimeoutId_);
this.receiveTimeoutId_ = null;
@@ -310,10 +319,10 @@ define('serial_service', [
if (this.sendInProgress_)
return Promise.resolve({bytesSent: 0, error: 'pending'});
- if (this.options_.sendTimeout) {
+ if (this.state_.sendTimeout) {
this.sendTimeoutId_ = setTimeout(function() {
this.sendPipe_.cancel(serialMojom.SendError.TIMEOUT);
- }.bind(this), this.options_.sendTimeout);
+ }.bind(this), this.state_.sendTimeout);
}
this.sendInProgress_ = true;
return this.sendPipe_.send(data).then(function(bytesSent) {
@@ -340,9 +349,9 @@ define('serial_service', [
if (this.queuedReceiveData_) {
receivePromise = Promise.resolve(this.queuedReceiveData_);
this.queuedReceiveData_ = null;
- } else if (this.queuedReceiveError) {
- receivePromise = Promise.reject(this.queuedReceiveError);
- this.queuedReceiveError = null;
+ } else if (this.queuedReceiveError_) {
+ receivePromise = Promise.reject(this.queuedReceiveError_);
+ this.queuedReceiveError_ = null;
} else {
receivePromise = this.receivePipe_.receive();
}
@@ -354,14 +363,14 @@ define('serial_service', [
Connection.prototype.onDataReceived_ = function(data) {
this.startReceiveTimeoutTimer_();
this.receiveInProgress_ = false;
- if (this.paused_) {
+ if (this.state_.paused) {
this.queuedReceiveData_ = data;
return;
}
if (this.onData) {
this.onData(data);
}
- if (!this.paused_) {
+ if (!this.state_.paused) {
this.startReceive_();
}
};
@@ -369,21 +378,21 @@ define('serial_service', [
Connection.prototype.onReceiveError_ = function(e) {
clearTimeout(this.receiveTimeoutId_);
this.receiveInProgress_ = false;
- if (this.paused_) {
- this.queuedReceiveError = e;
+ if (this.state_.paused) {
+ this.queuedReceiveError_ = e;
return;
}
var error = e.error;
- this.paused_ = true;
+ this.state_.paused = true;
if (this.onError)
this.onError(RECEIVE_ERROR_FROM_MOJO[error]);
};
Connection.prototype.startReceiveTimeoutTimer_ = function() {
clearTimeout(this.receiveTimeoutId_);
- if (this.options_.receiveTimeout && !this.paused_) {
+ if (this.state_.receiveTimeout && !this.state_.paused) {
this.receiveTimeoutId_ = setTimeout(this.onReceiveTimeout_.bind(this),
- this.options_.receiveTimeout);
+ this.state_.receiveTimeout);
}
};
@@ -393,26 +402,105 @@ define('serial_service', [
this.startReceiveTimeoutTimer_();
};
- var connections_ = {};
+ Connection.prototype.serialize = function() {
+ connections_.delete(this.state_.connectionId);
+ this.onData = null;
+ this.onError = null;
+ var handle = this.router_.connector_.handle_;
+ this.router_.connector_.handle_ = null;
+ this.router_.close();
+ clearTimeout(this.receiveTimeoutId_);
+ clearTimeout(this.sendTimeoutId_);
+
+ // Serializing receivePipe_ will cancel an in-progress receive, which would
+ // pause the connection, so save it ahead of time.
+ var paused = this.state_.paused;
+ return Promise.all([
+ this.receivePipe_.serialize(),
+ this.sendPipe_.serialize(),
+ ]).then(function(serializedComponents) {
+ var queuedReceiveError = serialMojom.ReceiveError.NONE;
+ if (this.queuedReceiveError_)
+ queuedReceiveError = this.queuedReceiveError_.error;
+ this.state_.paused = paused;
+ var serialized = new serialization.SerializedConnection();
+ serialized.state = this.state_;
+ serialized.queuedReceiveError = queuedReceiveError;
+ serialized.queuedReceiveData =
+ this.queuedReceiveData_ ? new Int8Array(this.queuedReceiveData_) :
+ null;
+ serialized.connection = handle;
+ serialized.receiver = serializedComponents[0];
+ serialized.sender = serializedComponents[1];
+ return serialized;
+ }.bind(this));
+ };
+
+ Connection.deserialize = function(serialized) {
+ var serialConnection = $Object.create(Connection.prototype);
+ var router = new routerModule.Router(serialized.connection);
+ var connection = new serialMojom.ConnectionProxy(router);
+ var receiver = dataReceiver.DataReceiver.deserialize(serialized.receiver);
+ var sender = dataSender.DataSender.deserialize(serialized.sender);
+
+ // Ensure that paused and persistent are booleans.
+ serialized.state.paused = !!serialized.state.paused;
+ serialized.state.persistent = !!serialized.state.persistent;
+ serialConnection.init_(serialized.state,
+ connection,
+ router,
+ receiver,
+ sender,
+ serialized.queuedReceiveData,
+ serialized.queuedReceiveError);
+ serialConnection.awaitingResume_ = true;
+ var connectionId = serialized.state.connectionId;
+ connections_.set(connectionId, serialConnection);
+ if (connectionId >= nextConnectionId_)
+ nextConnectionId_ = connectionId + 1;
+ return serialConnection;
+ };
+
+ // Resume receives on a deserialized connection.
+ Connection.prototype.resumeReceives = function() {
+ if (!this.awaitingResume_)
+ return;
+ this.awaitingResume_ = false;
+ if (!this.state_.paused)
+ this.startReceive_();
+ };
+
+ // All accesses to connections_ and nextConnectionId_ other than those
+ // involved in deserialization should ensure that
+ // connectionDeserializationComplete_ has resolved first.
+ // Note: this will not immediately resolve once serial connection stashing and
+ // restoring is implemented.
+ var connectionDeserializationComplete_ = Promise.resolve();
+
+ // The map of connection ID to connection object.
+ var connections_ = new Map();
+
+ // The next connection ID to be allocated.
var nextConnectionId_ = 0;
- // Wrap all access to |connections_| through getConnections to avoid adding
- // any synchronous dependencies on it. This will likely be important when
- // supporting persistent connections by stashing them.
function getConnections() {
- return Promise.resolve(connections_);
+ return connectionDeserializationComplete_.then(function() {
+ return new Map(connections_);
+ });
}
function getConnection(id) {
return getConnections().then(function(connections) {
- if (!connections[id])
+ if (!connections.has(id))
throw new Error('Serial connection not found.');
- return connections[id];
+ return connections.get(id);
});
}
function allocateConnectionId() {
- return Promise.resolve(nextConnectionId_++);
+ return connectionDeserializationComplete_.then(function() {
+ return nextConnectionId_++;
+ });
}
return {
diff --git a/extensions/test/data/serial_unittest.js b/extensions/test/data/serial_unittest.js
index c3cc504..56ebee3 100644
--- a/extensions/test/data/serial_unittest.js
+++ b/extensions/test/data/serial_unittest.js
@@ -22,7 +22,28 @@ var BUFFER_SIZE = 10;
var connectionId = null;
-function connect(callback, options) {
+var OPTIONS_VALUES = [
+ {}, // SetPortOptions is called once during connection.
+ {bitrate: 57600},
+ {dataBits: 'seven'},
+ {dataBits: 'eight'},
+ {parityBit: 'no'},
+ {parityBit: 'odd'},
+ {parityBit: 'even'},
+ {stopBits: 'one'},
+ {stopBits: 'two'},
+ {ctsFlowControl: false},
+ {ctsFlowControl: true},
+ {bufferSize: 1},
+ {sendTimeout: 0},
+ {receiveTimeout: 0},
+ {persistent: false},
+ {name: 'name'},
+];
+
+// Create a serial connection. That serial connection will be used by the other
+// helper functions below.
+function connect(options) {
options = options || {
name: 'test connection',
bufferSize: BUFFER_SIZE,
@@ -30,11 +51,117 @@ function connect(callback, options) {
sendTimeout: 6789,
persistent: true,
};
- serial.connect('device', options, test.callbackPass(function(connectionInfo) {
- connectionId = connectionInfo.connectionId;
- if (callback)
- callback(connectionInfo);
- }));
+ return utils.promise(serial.connect, 'device', options).then(function(info) {
+ connectionId = info.connectionId;
+ return info;
+ });
+}
+
+// Serialize and deserialize all serial connections, preserving onData and
+// onError event listeners.
+function serializeRoundTrip() {
+ return requireAsync('serial_service').then(function(serialService) {
+ function serializeConnections(connections) {
+ var serializedConnections = [];
+ for (var connection in connections.values()) {
+ serializedConnections.push(serializeConnection(connection));
+ }
+ return Promise.all(serializedConnections);
+ }
+
+ function serializeConnection(connection) {
+ var onData = connection.onData;
+ var onError = connection.onError;
+ return connection.serialize().then(function(serialization) {
+ return {
+ serialization: serialization,
+ onData: onData,
+ onError: onError,
+ };
+ });
+ }
+
+ function deserializeConnections(serializedConnections) {
+ $Array.forEach(serializedConnections, function(serializedConnection) {
+ var connection = serialService.Connection.deserialize(
+ serializedConnection.serialization);
+ connection.onData = serializedConnection.onData;
+ connection.onError = serializedConnection.onError;
+ connection.resumeReceives();
+ });
+ }
+
+ return serialService.getConnections()
+ .then(serializeConnections)
+ .then(deserializeConnections);
+ });
+}
+
+// Returns a promise that will resolve to the connection info for the
+// connection.
+function getInfo() {
+ return utils.promise(serial.getInfo, connectionId);
+}
+
+// Returns a function that checks that the values of keys contained within
+// |expectedInfo| match the values of the same keys contained within |info|.
+function checkInfo(expectedInfo) {
+ return function(info) {
+ for (var key in expectedInfo) {
+ test.assertEq(expectedInfo[key], info[key]);
+ }
+ };
+}
+
+// Returns a function that will update the options of the serial connection with
+// those contained within |values|.
+function update(values) {
+ return function() {
+ return utils.promise(serial.update, connectionId, values);
+ };
+}
+
+// Checks that the previous operation succeeded.
+function expectSuccess(success) {
+ test.assertTrue(success);
+}
+
+// Returns a function that checks that the send result matches |bytesSent| and
+// |error|. If no error is expected, |error| may be omitted.
+function expectSendResult(bytesSent, error) {
+ return function(sendInfo) {
+ test.assertEq(bytesSent, sendInfo.bytesSent);
+ test.assertEq(error, sendInfo.error);
+ };
+}
+
+// Returns a function that checks that the current time is |expectedTime|.
+function expectCurrentTime(expectedTime) {
+ return function() {
+ test.assertEq(expectedTime, timeoutManager.currentTime);
+ }
+}
+
+// Returns a promise that will resolve to the device control signals for the
+// serial connection.
+function getControlSignals() {
+ return utils.promise(serial.getControlSignals, connectionId);
+}
+
+// Returns a function that will set the control signals for the serial
+// connection to |signals|.
+function setControlSignals(signals) {
+ return function() {
+ return utils.promise(serial.setControlSignals, connectionId, signals);
+ };
+}
+
+// Returns a function that will set the paused state of the serial connection to
+// |paused|.
+function setPaused(paused) {
+ return function() {
+ return utils.promise(serial.setPaused, connectionId, paused);
+ }
}
// Sets a function to be called once when data is received. Returns a promise
@@ -69,11 +196,19 @@ function addReceiveErrorHook(callback) {
});
}
+function listenOnce(targetEvent) {
+ return new Promise(function(resolve, reject) {
+ targetEvent.addListener(function(result) {
+ resolve(result);
+ });
+ });
+}
+
function disconnect() {
- serial.disconnect(connectionId, test.callbackPass(function(success) {
+ return utils.promise(serial.disconnect, connectionId).then(function(success) {
test.assertTrue(success);
connectionId = null;
- }));
+ });
}
function checkClientConnectionInfo(connectionInfo) {
@@ -96,29 +231,7 @@ function checkServiceConnectionInfo(connectionInfo) {
function checkConnectionInfo(connectionInfo) {
checkClientConnectionInfo(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);
- }));
- });
+ test.assertEq(12, $Object.keys(connectionInfo).length);
}
function sendData() {
@@ -141,11 +254,40 @@ function checkReceivedData(result) {
}
}
+function checkReceiveError(expectedError) {
+ return function(result) {
+ test.assertEq(connectionId, result.connectionId);
+ test.assertEq(expectedError, result.error);
+ }
+}
+
+function runReceiveErrorTest(expectedError) {
+ var errorReceived = listenOnce(serial.onReceiveError);
+ Promise.all([
+ connect(),
+ errorReceived
+ .then(checkReceiveError(expectedError)),
+ errorReceived
+ .then(getInfo)
+ .then(checkInfo({paused: true})),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
+}
+
+function runSendErrorTest(expectedError) {
+ connect()
+ .then(sendData)
+ .then(expectSendResult(0, expectedError))
+ .then(disconnect)
+ .then(test.succeed, test.fail);
+}
+
unittestBindings.exportTests([
// Test that getDevices correctly transforms the data returned by the
// SerialDeviceEnumerator.
function testGetDevices() {
- serial.getDevices(test.callbackPass(function(devices) {
+ utils.promise(serial.getDevices).then(function(devices) {
test.assertEq(3, devices.length);
test.assertEq(4, $Object.keys(devices[0]).length);
test.assertEq('device', devices[0].path);
@@ -156,7 +298,7 @@ unittestBindings.exportTests([
test.assertEq('another_device', devices[1].path);
test.assertEq(1, $Object.keys(devices[2]).length);
test.assertEq('', devices[2].path);
- }));
+ }).then(test.succeed, test.fail);
},
// Test that the correct error message is returned when an error occurs in
@@ -183,17 +325,16 @@ unittestBindings.exportTests([
// Test that a successful connect returns the expected connection info.
function testConnect() {
- connect(function(connectionInfo) {
- disconnect();
- checkConnectionInfo(connectionInfo);
- });
+ connect()
+ .then(checkConnectionInfo)
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// Test that a connection created with no options has the correct default
// options.
function testConnectDefaultOptions() {
- connect(function(connectionInfo) {
- disconnect();
+ connect({}).then(function(connectionInfo) {
test.assertEq(9600, connectionInfo.bitrate);
test.assertEq('eight', connectionInfo.dataBits);
test.assertEq('no', connectionInfo.parityBit);
@@ -204,104 +345,107 @@ unittestBindings.exportTests([
test.assertEq(0, connectionInfo.receiveTimeout);
test.assertEq(0, connectionInfo.sendTimeout);
test.assertEq(4096, connectionInfo.bufferSize);
- }, {});
+ })
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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,
- test.callbackPass(function(connectionInfo) {
- disconnect();
- checkConnectionInfo(connectionInfo);
- }));
- });
+ connect()
+ .then(getInfo)
+ .then(checkConnectionInfo)
+ .then(disconnect)
+ .then(test.succeed, test.fail);
+ },
+
+ // Test that a getInfo call returns the correct info after serialization.
+ function testGetInfoAfterSerialization() {
+ connect()
+ .then(serializeRoundTrip)
+ .then(getInfo)
+ .then(checkConnectionInfo)
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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,
- test.callbackPass(function(connectionInfo) {
- disconnect();
- checkClientConnectionInfo(connectionInfo);
- test.assertFalse('bitrate' in connectionInfo);
- test.assertFalse('dataBits' in connectionInfo);
- test.assertFalse('parityBit' in connectionInfo);
- test.assertFalse('stopBit' in connectionInfo);
- test.assertFalse('ctsFlowControl' in connectionInfo);
- }));
- });
+ var info = connect().then(getInfo);
+ Promise.all([
+ info.then(function(connectionInfo) {
+ test.assertFalse('bitrate' in connectionInfo);
+ test.assertFalse('dataBits' in connectionInfo);
+ test.assertFalse('parityBit' in connectionInfo);
+ test.assertFalse('stopBit' in connectionInfo);
+ test.assertFalse('ctsFlowControl' in connectionInfo);
+ }),
+ info.then(checkClientConnectionInfo),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// Test that getConnections returns an array containing the open connection.
function testGetConnections() {
- connect(function() {
- serial.getConnections(test.callbackPass(function(connections) {
- disconnect();
- test.assertEq(1, connections.length);
- checkConnectionInfo(connections[0]);
- }));
- });
+ connect().then(function() {
+ return utils.promise(serial.getConnections);
+ }).then(function(connections) {
+ test.assertEq(1, connections.length);
+ checkConnectionInfo(connections[0]);
+ })
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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;
- function checkControlSignals(signals) {
- if (calls == 15) {
- disconnect();
- } else {
- serial.getControlSignals(
- connectionId,
- test.callbackPass(checkControlSignals));
- }
- test.assertEq(!!(calls & 1), signals.dcd);
- test.assertEq(!!(calls & 2), signals.cts);
- test.assertEq(!!(calls & 4), signals.ri);
- test.assertEq(!!(calls & 8), signals.dsr);
- calls++;
- }
- serial.getControlSignals(connectionId,
- test.callbackPass(checkControlSignals));
- });
+ function checkControlSignals(expectedBitfield) {
+ return function(signals) {
+ test.assertEq(!!(expectedBitfield & 1), signals.dcd);
+ test.assertEq(!!(expectedBitfield & 2), signals.cts);
+ test.assertEq(!!(expectedBitfield & 4), signals.ri);
+ test.assertEq(!!(expectedBitfield & 8), signals.dsr);
+ };
+ }
+ var promiseChain = connect();
+ for (var i = 0; i < 16; i++) {
+ promiseChain = promiseChain
+ .then(getControlSignals)
+ .then(checkControlSignals(i));
+ }
+ promiseChain
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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 = [
- {},
- {dtr: false},
- {dtr: true},
- {rts: false},
- {dtr: false, rts: false},
- {dtr: true, rts: false},
- {rts: true},
- {dtr: false, rts: true},
- {dtr: true, rts: true},
- ];
- var calls = 0;
- function setControlSignals(success) {
- if (calls == signalsValues.length) {
- disconnect();
- } else {
- serial.setControlSignals(connectionId,
- signalsValues[calls++],
- test.callbackPass(setControlSignals));
- }
- test.assertTrue(success);
- }
- setControlSignals(true);
- });
+ var signalsValues = [
+ {},
+ {dtr: false},
+ {dtr: true},
+ {rts: false},
+ {dtr: false, rts: false},
+ {dtr: true, rts: false},
+ {rts: true},
+ {dtr: false, rts: true},
+ {dtr: true, rts: true},
+ ];
+ var promiseChain = connect();
+ for (var i = 0; i < signalsValues.length; i++) {
+ promiseChain = promiseChain.then(setControlSignals(signalsValues[i]));
+ }
+ promiseChain
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// Test that update correctly passes values to the service only for
@@ -309,236 +453,239 @@ unittestBindings.exportTests([
// of getInfo calls. This test uses an IoHandler that expects corresponding
// ConfigurePort calls.
function testUpdate() {
- connect(function() {
- var optionsValues = [
- {}, // SetPortOptions is called once during connection.
- {bitrate: 57600},
- {dataBits: 'seven'},
- {dataBits: 'eight'},
- {parityBit: 'no'},
- {parityBit: 'odd'},
- {parityBit: 'even'},
- {stopBits: 'one'},
- {stopBits: 'two'},
- {ctsFlowControl: false},
- {ctsFlowControl: true},
- {bufferSize: 1},
- {sendTimeout: 0},
- {receiveTimeout: 0},
- {persistent: false},
- {name: 'name'},
- ];
- var calls = 0;
- function checkInfo(info) {
- for (var key in optionsValues[calls]) {
- test.assertEq(optionsValues[calls][key], info[key]);
- }
- setOptions();
- }
- function setOptions() {
- if (++calls == optionsValues.length) {
- disconnect();
- } else {
- serial.update(connectionId,
- optionsValues[calls],
- test.callbackPass(function(success) {
- serial.getInfo(connectionId, test.callbackPass(checkInfo));
- test.assertTrue(success);
- }));
- }
- }
- setOptions();
- });
+ var promiseChain = connect()
+ .then(getInfo)
+ .then(checkInfo(OPTIONS_VALUES[i]));
+ for (var i = 1; i < OPTIONS_VALUES.length; i++) {
+ promiseChain = promiseChain
+ .then(update(OPTIONS_VALUES[i]))
+ .then(expectSuccess)
+ .then(getInfo)
+ .then(checkInfo(OPTIONS_VALUES[i]));
+ }
+ promiseChain
+ .then(disconnect)
+ .then(test.succeed, test.fail);
+ },
+
+ // Test that options set by update persist after serialization.
+ function testUpdateAcrossSerialization() {
+ var promiseChain = connect()
+ .then(serializeRoundTrip)
+ .then(getInfo)
+ .then(checkInfo(OPTIONS_VALUES[i]));
+ for (var i = 1; i < OPTIONS_VALUES.length; i++) {
+ promiseChain = promiseChain
+ .then(update(OPTIONS_VALUES[i]))
+ .then(expectSuccess)
+ .then(serializeRoundTrip)
+ .then(getInfo)
+ .then(checkInfo(OPTIONS_VALUES[i]));
+ }
+ promiseChain
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// Test that passing an invalid bit-rate reslts in an error.
function testUpdateInvalidBitrate() {
- connect(function() {
- serial.update(connectionId,
- {bitrate: -1},
- test.callbackPass(function(success) {
- disconnect();
- test.assertFalse(success);
- }));
- });
+ connect()
+ .then(update({bitrate: -1}))
+ .then(function(success) {
+ test.assertFalse(success);
+ })
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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) {
- disconnect();
- test.assertTrue(success);
- }));
- });
+ connect().then(function() {
+ return utils.promise(serial.flush, connectionId);
+ })
+ .then(expectSuccess)
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// Test that setPaused values are reflected by the results returned by getInfo
// calls.
function testSetPaused() {
- connect(function() {
- serial.setPaused(connectionId, true, test.callbackPass(function() {
- serial.getInfo(connectionId, test.callbackPass(function(info) {
- serial.setPaused(connectionId, false, test.callbackPass(function() {
- serial.getInfo(connectionId, test.callbackPass(function(info) {
- test.assertFalse(info.paused);
- disconnect();
- }));
- }));
- test.assertTrue(info.paused);
- }));
- }));
- });
+ connect()
+ .then(setPaused(true))
+ .then(getInfo)
+ .then(checkInfo({paused: true}))
+ .then(setPaused(false))
+ .then(getInfo)
+ .then(checkInfo({paused: false}))
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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();
- });
- });
+ Promise.all([
+ connect()
+ .then(sendData)
+ .then(expectSendResult(4)),
+ listenOnce(serial.onReceive)
+ .then(checkReceivedData),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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);
- }));
- });
+ var connected = connect();
+ Promise.all([
+ connected
+ .then(sendData)
+ .then(expectSendResult(4)),
+ connected
+ .then(sendData)
+ .then(expectSendResult(0, 'pending')),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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();
- });
- });
- });
+ connect()
+ .then(sendData)
+ .then(expectSendResult(4))
+ .then(sendData)
+ .then(expectSendResult(4))
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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();
- }));
- });
+ connect()
+ .then(sendData)
+ .then(expectSendResult(2, 'system_error'))
+ .then(sendData)
+ .then(expectSendResult(4))
+ .then(disconnect)
+ .then(test.succeed, test.fail);
+ },
+
+ // Test that a send and a receive correctly echoes data after serialization.
+ function testEchoAfterSerialization() {
+ Promise.all([
+ connect()
+ .then(serializeRoundTrip)
+ .then(sendData)
+ .then(expectSendResult(4)),
+ listenOnce(serial.onReceive).then(checkReceivedData)
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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});
+ var connected = connect({sendTimeout: 5});
+ var sent = connected.then(sendData);
+ Promise.all([
+ sent.then(expectSendResult(0, 'timeout')),
+ sent.then(expectCurrentTime(5)),
+ connected.then(update({sendTimeout: 10}))
+ .then(expectSuccess)
+ .then(timeoutManager.run.bind(timeoutManager, 1)),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
+ },
+
+ // Test that send timeouts still function correctly after a serialization
+ // round trip.
+ function testSendTimeoutAfterSerialization() {
+ var connected = connect({sendTimeout: 5}).then(serializeRoundTrip);
+ var sent = connected.then(sendData);
+ Promise.all([
+ sent.then(expectSendResult(0, 'timeout')),
+ sent.then(expectCurrentTime(5)),
+ connected.then(update({sendTimeout: 10}))
+ .then(expectSuccess)
+ .then(timeoutManager.run.bind(timeoutManager, 1)),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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});
+ var connected = connect({sendTimeout: 5});
+ var sent = connected.then(sendData);
+ Promise.all([
+ sent.then(expectSendResult(0, 'timeout')),
+ sent.then(expectCurrentTime(5)),
+ connected.then(update({sendTimeout: 0}))
+ .then(expectSuccess)
+ .then(timeoutManager.run.bind(timeoutManager, 1)),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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();
- });
+ Promise.all([
+ // 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.
+ Promise.all([
+ utils.promise(serial.setPaused, connectionId, false),
+ // Check that setPaused(false) is idempotent.
+ utils.promise(serial.setPaused, connectionId, false),
+ ]).catch(test.fail);
+ })
+ .then(connect)
+ .then(function() {
+ // Check that setPaused(true) is idempotent.
+ return Promise.all([
+ utils.promise(serial.setPaused, connectionId, true),
+ utils.promise(serial.setPaused, connectionId, true),
+ ]);
+ }),
+ listenOnce(serial.onReceive).then(checkReceivedData),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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);
- });
+ Promise.all([
+ // Wait until the receive hook is installed, then start the test.
+ addReceiveErrorHook(function() {
+ // Unpause the connection after the connection has queued the received
+ // data to ensure the queued data is dispatched when the connection is
+ // unpaused.
+ utils.promise(serial.setPaused, connectionId, false).catch(test.fail);
+ })
+ .then(connect)
+ .then(setPaused(true)),
+ listenOnce(serial.onReceiveError)
+ .then(checkReceiveError('device_lost')),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
serial.onReceive.addListener(function() {
test.fail('unexpected onReceive event');
});
@@ -547,43 +694,61 @@ unittestBindings.exportTests([
// 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});
+ var errorReceived = listenOnce(serial.onReceiveError);
+ Promise.all([
+ errorReceived.then(checkReceiveError('timeout')),
+ errorReceived.then(expectCurrentTime(20)),
+ errorReceived
+ .then(getInfo)
+ .then(checkInfo({paused: false})),
+ connect({receiveTimeout: 20})
+ // Changing the timeout does not take effect until the current
+ // timeout expires or a receive completes.
+ .then(update({receiveTimeout: 10}))
+ .then(expectSuccess)
+ .then(timeoutManager.run.bind(timeoutManager, 1)),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
+ },
+
+ // Test that receive timeouts still function correctly after a serialization
+ // round trip.
+ function testReceiveTimeoutAfterSerialization() {
+ var errorReceived = listenOnce(serial.onReceiveError);
+ Promise.all([
+ errorReceived.then(checkReceiveError('timeout')),
+ errorReceived.then(expectCurrentTime(20)),
+ errorReceived
+ .then(getInfo)
+ .then(checkInfo({paused: false})),
+ connect({receiveTimeout: 20})
+ .then(serializeRoundTrip)
+ .then(timeoutManager.run.bind(timeoutManager, 1)),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// 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});
+ var errorReceived = listenOnce(serial.onReceiveError);
+ Promise.all([
+ errorReceived.then(checkReceiveError('timeout')),
+ errorReceived.then(expectCurrentTime(20)),
+ errorReceived
+ .then(getInfo)
+ .then(checkInfo({paused: false})),
+ connect({receiveTimeout: 20})
+ // Disabling the timeout does not take effect until the current
+ // timeout expires or a receive completes.
+ .then(update({receiveTimeout: 0}))
+ .then(expectSuccess)
+ .then(timeoutManager.run.bind(timeoutManager, 1)),
+ ])
+ .then(disconnect)
+ .then(test.succeed, test.fail);
},
// Test that a receive error from the service is correctly dispatched. This