1 // Copyright 2013 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.
5 // Mock out the support module to avoid depending on the message loop.
6 define("mojo/public/js/bindings/support", ["timer"], function(timer) {
7 var waitingCallbacks = [];
9 function WaitCookie(id) {
13 function asyncWait(handle, flags, callback) {
14 var id = waitingCallbacks.length;
15 waitingCallbacks.push(callback);
16 return new WaitCookie(id);
19 function cancelWait(cookie) {
20 waitingCallbacks[cookie.id] = null;
23 function numberOfWaitingCallbacks() {
25 for (var i = 0; i < waitingCallbacks.length; ++i) {
26 if (waitingCallbacks[i])
32 function pumpOnce(result) {
33 var callbacks = waitingCallbacks;
34 waitingCallbacks = [];
35 for (var i = 0; i < callbacks.length; ++i) {
41 // Queue up a pumpOnce call to execute after the stack unwinds. Use
42 // this to trigger a pump after all Promises are executed.
43 function queuePump(result) {
44 timer.createOneShot(0, pumpOnce.bind(undefined, result));
48 exports.asyncWait = asyncWait;
49 exports.cancelWait = cancelWait;
50 exports.numberOfWaitingCallbacks = numberOfWaitingCallbacks;
51 exports.pumpOnce = pumpOnce;
52 exports.queuePump = queuePump;
58 "mojo/public/js/bindings/support",
59 "mojo/public/js/bindings/core",
60 "mojo/public/js/bindings/connection",
61 "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom",
62 "mojo/public/interfaces/bindings/tests/sample_service.mojom",
63 "mojo/apps/js/bindings/threading",
74 testWriteToClosedPipe();
75 testRequestResponse().then(function() {
77 gc.collectGarbage(); // should not crash
79 }.bind(this)).catch(function(e) {
80 this.result = "FAIL: " + (e.stack || e);
84 function testClientServer() {
85 var receivedFrobinate = false;
86 var receivedDidFrobinate = false;
88 // ServiceImpl -------------------------------------------------------------
90 function ServiceImpl(peer) {
94 ServiceImpl.prototype = Object.create(sample_service.ServiceStub.prototype);
96 ServiceImpl.prototype.frobinate = function(foo, baz, port) {
97 receivedFrobinate = true;
99 expect(foo.name).toBe("Example name");
100 expect(baz).toBeTruthy();
101 expect(core.close(port)).toBe(core.RESULT_OK);
103 this.peer.didFrobinate(42);
106 // ServiceImpl -------------------------------------------------------------
108 function ServiceClientImpl(peer) {
112 ServiceClientImpl.prototype =
113 Object.create(sample_service.ServiceClientStub.prototype);
115 ServiceClientImpl.prototype.didFrobinate = function(result) {
116 receivedDidFrobinate = true;
118 expect(result).toBe(42);
121 var pipe = core.createMessagePipe();
122 var anotherPipe = core.createMessagePipe();
123 var sourcePipe = core.createMessagePipe();
125 var connection0 = new connection.Connection(
126 pipe.handle0, ServiceImpl, sample_service.ServiceClientProxy);
128 var connection1 = new connection.Connection(
129 pipe.handle1, ServiceClientImpl, sample_service.ServiceProxy);
131 var foo = new sample_service.Foo();
132 foo.bar = new sample_service.Bar();
133 foo.name = "Example name";
134 foo.source = sourcePipe.handle0;
135 connection1.remote.frobinate(foo, true, anotherPipe.handle0);
137 mockSupport.pumpOnce(core.RESULT_OK);
139 expect(receivedFrobinate).toBeTruthy();
140 expect(receivedDidFrobinate).toBeTruthy();
145 expect(mockSupport.numberOfWaitingCallbacks()).toBe(0);
147 // sourcePipe.handle0 was closed automatically when sent over IPC.
148 expect(core.close(sourcePipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT);
149 // sourcePipe.handle1 hasn't been closed yet.
150 expect(core.close(sourcePipe.handle1)).toBe(core.RESULT_OK);
152 // anotherPipe.handle0 was closed automatically when sent over IPC.
153 expect(core.close(anotherPipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT);
154 // anotherPipe.handle1 hasn't been closed yet.
155 expect(core.close(anotherPipe.handle1)).toBe(core.RESULT_OK);
157 // The Connection object is responsible for closing these handles.
158 expect(core.close(pipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT);
159 expect(core.close(pipe.handle1)).toBe(core.RESULT_INVALID_ARGUMENT);
162 function testWriteToClosedPipe() {
163 var pipe = core.createMessagePipe();
165 var connection1 = new connection.Connection(
166 pipe.handle1, function() {}, sample_service.ServiceProxy);
168 // Close the other end of the pipe.
169 core.close(pipe.handle0);
171 // Not observed yet because we haven't pumped events yet.
172 expect(connection1.encounteredError()).toBeFalsy();
174 var foo = new sample_service.Foo();
175 foo.bar = new sample_service.Bar();
176 // TODO(darin): crbug.com/357043: pass null in place of |foo| here.
177 connection1.remote.frobinate(foo, true, core.kInvalidHandle);
179 // Write failures are not reported.
180 expect(connection1.encounteredError()).toBeFalsy();
182 // Pump events, and then we should start observing the closed pipe.
183 mockSupport.pumpOnce(core.RESULT_OK);
185 expect(connection1.encounteredError()).toBeTruthy();
190 function testRequestResponse() {
192 // ProviderImpl ------------------------------------------------------------
194 function ProviderImpl(peer) {
198 ProviderImpl.prototype =
199 Object.create(sample_interfaces.ProviderStub.prototype);
201 ProviderImpl.prototype.echoString = function(a) {
202 mockSupport.queuePump(core.RESULT_OK);
203 return Promise.resolve({a: a});
206 ProviderImpl.prototype.echoStrings = function(a, b) {
207 mockSupport.queuePump(core.RESULT_OK);
208 return Promise.resolve({a: a, b: b});
211 // ProviderClientImpl ------------------------------------------------------
213 function ProviderClientImpl(peer) {
217 ProviderClientImpl.prototype =
218 Object.create(sample_interfaces.ProviderClientStub.prototype);
220 var pipe = core.createMessagePipe();
222 var connection0 = new connection.Connection(
223 pipe.handle0, ProviderImpl, sample_interfaces.ProviderClientProxy);
225 var connection1 = new connection.Connection(
226 pipe.handle1, ProviderClientImpl, sample_interfaces.ProviderProxy);
228 var origReadMessage = core.readMessage;
230 mockSupport.queuePump(core.RESULT_OK);
231 return connection1.remote.echoString("hello").then(function(response) {
232 expect(response.a).toBe("hello");
235 mockSupport.queuePump(core.RESULT_OK);
236 return connection1.remote.echoStrings("hello", "world");
237 }).then(function(response) {
238 expect(response.a).toBe("hello");
239 expect(response.b).toBe("world");
241 // Mock a read failure, expect it to fail.
242 core.readMessage = function() {
243 return { result: core.RESULT_UNKNOWN };
245 mockSupport.queuePump(core.RESULT_OK);
246 return connection1.remote.echoString("goodbye");
248 throw Error("Expected echoString to fail.");
250 expect(error.message).toBe("Connection error: " + core.RESULT_UNKNOWN);
253 core.readMessage = origReadMessage;