Index: mojo/edk/js/tests/connection_tests.js |
diff --git a/mojo/edk/js/tests/connection_tests.js b/mojo/edk/js/tests/connection_tests.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6649dfe7e159545c791612638f8ce5fdc84d8095 |
--- /dev/null |
+++ b/mojo/edk/js/tests/connection_tests.js |
@@ -0,0 +1,261 @@ |
+// Copyright 2013 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. |
+ |
+// Mock out the support module to avoid depending on the message loop. |
+define("mojo/public/js/support", ["timer"], function(timer) { |
+ var waitingCallbacks = []; |
+ |
+ function WaitCookie(id) { |
+ this.id = id; |
+ } |
+ |
+ function asyncWait(handle, flags, callback) { |
+ var id = waitingCallbacks.length; |
+ waitingCallbacks.push(callback); |
+ return new WaitCookie(id); |
+ } |
+ |
+ function cancelWait(cookie) { |
+ waitingCallbacks[cookie.id] = null; |
+ } |
+ |
+ function numberOfWaitingCallbacks() { |
+ var count = 0; |
+ for (var i = 0; i < waitingCallbacks.length; ++i) { |
+ if (waitingCallbacks[i]) |
+ ++count; |
+ } |
+ return count; |
+ } |
+ |
+ function pumpOnce(result) { |
+ var callbacks = waitingCallbacks; |
+ waitingCallbacks = []; |
+ for (var i = 0; i < callbacks.length; ++i) { |
+ if (callbacks[i]) |
+ callbacks[i](result); |
+ } |
+ } |
+ |
+ // Queue up a pumpOnce call to execute after the stack unwinds. Use |
+ // this to trigger a pump after all Promises are executed. |
+ function queuePump(result) { |
+ timer.createOneShot(0, pumpOnce.bind(undefined, result)); |
+ } |
+ |
+ var exports = {}; |
+ exports.asyncWait = asyncWait; |
+ exports.cancelWait = cancelWait; |
+ exports.numberOfWaitingCallbacks = numberOfWaitingCallbacks; |
+ exports.pumpOnce = pumpOnce; |
+ exports.queuePump = queuePump; |
+ return exports; |
+}); |
+ |
+define([ |
+ "gin/test/expect", |
+ "mojo/public/js/support", |
+ "mojo/public/js/core", |
+ "mojo/public/js/connection", |
+ "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom", |
+ "mojo/public/interfaces/bindings/tests/sample_service.mojom", |
+ "mojo/public/js/threading", |
+ "gc", |
+], function(expect, |
+ mockSupport, |
+ core, |
+ connection, |
+ sample_interfaces, |
+ sample_service, |
+ threading, |
+ gc) { |
+ testClientServer(); |
+ testWriteToClosedPipe(); |
+ testRequestResponse().then(function() { |
+ this.result = "PASS"; |
+ gc.collectGarbage(); // should not crash |
+ threading.quit(); |
+ }.bind(this)).catch(function(e) { |
+ this.result = "FAIL: " + (e.stack || e); |
+ threading.quit(); |
+ }.bind(this)); |
+ |
+ function testClientServer() { |
+ var receivedFrobinate = false; |
+ var receivedDidFrobinate = false; |
+ |
+ // ServiceImpl ------------------------------------------------------------ |
+ |
+ function ServiceImpl(peer) { |
+ this.peer = peer; |
+ } |
+ |
+ ServiceImpl.prototype = Object.create( |
+ sample_service.Service.stubClass.prototype); |
+ |
+ ServiceImpl.prototype.frobinate = function(foo, baz, port) { |
+ receivedFrobinate = true; |
+ |
+ expect(foo.name).toBe("Example name"); |
+ expect(baz).toBeTruthy(); |
+ expect(core.close(port)).toBe(core.RESULT_OK); |
+ |
+ this.peer.didFrobinate(42); |
+ }; |
+ |
+ // ServiceClientImpl ------------------------------------------------------ |
+ |
+ function ServiceClientImpl(peer) { |
+ this.peer = peer; |
+ } |
+ |
+ ServiceClientImpl.prototype = |
+ Object.create(sample_service.ServiceClient.stubClass.prototype); |
+ |
+ ServiceClientImpl.prototype.didFrobinate = function(result) { |
+ receivedDidFrobinate = true; |
+ |
+ expect(result).toBe(42); |
+ }; |
+ |
+ var pipe = core.createMessagePipe(); |
+ var anotherPipe = core.createMessagePipe(); |
+ var sourcePipe = core.createMessagePipe(); |
+ |
+ var connection0 = new connection.Connection( |
+ pipe.handle0, ServiceImpl, sample_service.ServiceClient.proxyClass); |
+ |
+ var connection1 = new connection.Connection( |
+ pipe.handle1, ServiceClientImpl, sample_service.Service.proxyClass); |
+ |
+ var foo = new sample_service.Foo(); |
+ foo.bar = new sample_service.Bar(); |
+ foo.name = "Example name"; |
+ foo.source = sourcePipe.handle0; |
+ connection1.remote.frobinate(foo, true, anotherPipe.handle0); |
+ |
+ mockSupport.pumpOnce(core.RESULT_OK); |
+ |
+ expect(receivedFrobinate).toBeTruthy(); |
+ expect(receivedDidFrobinate).toBeTruthy(); |
+ |
+ connection0.close(); |
+ connection1.close(); |
+ |
+ expect(mockSupport.numberOfWaitingCallbacks()).toBe(0); |
+ |
+ // sourcePipe.handle0 was closed automatically when sent over IPC. |
+ expect(core.close(sourcePipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT); |
+ // sourcePipe.handle1 hasn't been closed yet. |
+ expect(core.close(sourcePipe.handle1)).toBe(core.RESULT_OK); |
+ |
+ // anotherPipe.handle0 was closed automatically when sent over IPC. |
+ expect(core.close(anotherPipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT); |
+ // anotherPipe.handle1 hasn't been closed yet. |
+ expect(core.close(anotherPipe.handle1)).toBe(core.RESULT_OK); |
+ |
+ // The Connection object is responsible for closing these handles. |
+ expect(core.close(pipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT); |
+ expect(core.close(pipe.handle1)).toBe(core.RESULT_INVALID_ARGUMENT); |
+ } |
+ |
+ function testWriteToClosedPipe() { |
+ var pipe = core.createMessagePipe(); |
+ |
+ var connection1 = new connection.Connection( |
+ pipe.handle1, function() {}, sample_service.Service.proxyClass); |
+ |
+ // Close the other end of the pipe. |
+ core.close(pipe.handle0); |
+ |
+ // Not observed yet because we haven't pumped events yet. |
+ expect(connection1.encounteredError()).toBeFalsy(); |
+ |
+ var foo = new sample_service.Foo(); |
+ foo.bar = new sample_service.Bar(); |
+ // TODO(darin): crbug.com/357043: pass null in place of |foo| here. |
+ connection1.remote.frobinate(foo, true, null); |
+ |
+ // Write failures are not reported. |
+ expect(connection1.encounteredError()).toBeFalsy(); |
+ |
+ // Pump events, and then we should start observing the closed pipe. |
+ mockSupport.pumpOnce(core.RESULT_OK); |
+ |
+ expect(connection1.encounteredError()).toBeTruthy(); |
+ |
+ connection1.close(); |
+ } |
+ |
+ function testRequestResponse() { |
+ |
+ // ProviderImpl ------------------------------------------------------------ |
+ |
+ function ProviderImpl(peer) { |
+ this.peer = peer; |
+ } |
+ |
+ ProviderImpl.prototype = |
+ Object.create(sample_interfaces.Provider.stubClass.prototype); |
+ |
+ ProviderImpl.prototype.echoString = function(a) { |
+ mockSupport.queuePump(core.RESULT_OK); |
+ return Promise.resolve({a: a}); |
+ }; |
+ |
+ ProviderImpl.prototype.echoStrings = function(a, b) { |
+ mockSupport.queuePump(core.RESULT_OK); |
+ return Promise.resolve({a: a, b: b}); |
+ }; |
+ |
+ // ProviderClientImpl ------------------------------------------------------ |
+ |
+ function ProviderClientImpl(peer) { |
+ this.peer = peer; |
+ } |
+ |
+ ProviderClientImpl.prototype = |
+ Object.create(sample_interfaces.ProviderClient.stubClass.prototype); |
+ |
+ var pipe = core.createMessagePipe(); |
+ |
+ var connection0 = new connection.Connection( |
+ pipe.handle0, |
+ ProviderImpl, |
+ sample_interfaces.ProviderClient.proxyClass); |
+ |
+ var connection1 = new connection.Connection( |
+ pipe.handle1, |
+ ProviderClientImpl, |
+ sample_interfaces.Provider.proxyClass); |
+ |
+ var origReadMessage = core.readMessage; |
+ // echoString |
+ mockSupport.queuePump(core.RESULT_OK); |
+ return connection1.remote.echoString("hello").then(function(response) { |
+ expect(response.a).toBe("hello"); |
+ }).then(function() { |
+ // echoStrings |
+ mockSupport.queuePump(core.RESULT_OK); |
+ return connection1.remote.echoStrings("hello", "world"); |
+ }).then(function(response) { |
+ expect(response.a).toBe("hello"); |
+ expect(response.b).toBe("world"); |
+ }).then(function() { |
+ // Mock a read failure, expect it to fail. |
+ core.readMessage = function() { |
+ return { result: core.RESULT_UNKNOWN }; |
+ }; |
+ mockSupport.queuePump(core.RESULT_OK); |
+ return connection1.remote.echoString("goodbye"); |
+ }).then(function() { |
+ throw Error("Expected echoString to fail."); |
+ }, function(error) { |
+ expect(error.message).toBe("Connection error: " + core.RESULT_UNKNOWN); |
+ |
+ // Clean up. |
+ core.readMessage = origReadMessage; |
+ }); |
+ } |
+}); |