Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / mojo / apps / js / bindings / connection_unittests.js
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.
4
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 = [];
8
9   function WaitCookie(id) {
10     this.id = id;
11   }
12
13   function asyncWait(handle, flags, callback) {
14     var id = waitingCallbacks.length;
15     waitingCallbacks.push(callback);
16     return new WaitCookie(id);
17   }
18
19   function cancelWait(cookie) {
20     waitingCallbacks[cookie.id] = null;
21   }
22
23   function numberOfWaitingCallbacks() {
24     var count = 0;
25     for (var i = 0; i < waitingCallbacks.length; ++i) {
26       if (waitingCallbacks[i])
27         ++count;
28     }
29     return count;
30   }
31
32   function pumpOnce(result) {
33     var callbacks = waitingCallbacks;
34     waitingCallbacks = [];
35     for (var i = 0; i < callbacks.length; ++i) {
36       if (callbacks[i])
37         callbacks[i](result);
38     }
39   }
40
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));
45   }
46
47   var exports = {};
48   exports.asyncWait = asyncWait;
49   exports.cancelWait = cancelWait;
50   exports.numberOfWaitingCallbacks = numberOfWaitingCallbacks;
51   exports.pumpOnce = pumpOnce;
52   exports.queuePump = queuePump;
53   return exports;
54 });
55
56 define([
57     "gin/test/expect",
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",
64     "gc",
65 ], function(expect,
66             mockSupport,
67             core,
68             connection,
69             sample_interfaces,
70             sample_service,
71             threading,
72             gc) {
73   testClientServer();
74   testWriteToClosedPipe();
75   testRequestResponse().then(function() {
76     this.result = "PASS";
77     gc.collectGarbage();  // should not crash
78     threading.quit();
79   }.bind(this)).catch(function(e) {
80     this.result = "FAIL: " + (e.stack || e);
81     threading.quit();
82   }.bind(this));
83
84   function testClientServer() {
85     var receivedFrobinate = false;
86     var receivedDidFrobinate = false;
87
88     // ServiceImpl -------------------------------------------------------------
89
90     function ServiceImpl(peer) {
91       this.peer = peer;
92     }
93
94     ServiceImpl.prototype = Object.create(sample_service.ServiceStub.prototype);
95
96     ServiceImpl.prototype.frobinate = function(foo, baz, port) {
97       receivedFrobinate = true;
98
99       expect(foo.name).toBe("Example name");
100       expect(baz).toBeTruthy();
101       expect(core.close(port)).toBe(core.RESULT_OK);
102
103       this.peer.didFrobinate(42);
104     };
105
106     // ServiceImpl -------------------------------------------------------------
107
108     function ServiceClientImpl(peer) {
109       this.peer = peer;
110     }
111
112     ServiceClientImpl.prototype =
113         Object.create(sample_service.ServiceClientStub.prototype);
114
115     ServiceClientImpl.prototype.didFrobinate = function(result) {
116       receivedDidFrobinate = true;
117
118       expect(result).toBe(42);
119     };
120
121     var pipe = core.createMessagePipe();
122     var anotherPipe = core.createMessagePipe();
123     var sourcePipe = core.createMessagePipe();
124
125     var connection0 = new connection.Connection(
126         pipe.handle0, ServiceImpl, sample_service.ServiceClientProxy);
127
128     var connection1 = new connection.Connection(
129         pipe.handle1, ServiceClientImpl, sample_service.ServiceProxy);
130
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);
136
137     mockSupport.pumpOnce(core.RESULT_OK);
138
139     expect(receivedFrobinate).toBeTruthy();
140     expect(receivedDidFrobinate).toBeTruthy();
141
142     connection0.close();
143     connection1.close();
144
145     expect(mockSupport.numberOfWaitingCallbacks()).toBe(0);
146
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);
151
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);
156
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);
160   }
161
162   function testWriteToClosedPipe() {
163     var pipe = core.createMessagePipe();
164
165     var connection1 = new connection.Connection(
166         pipe.handle1, function() {}, sample_service.ServiceProxy);
167
168     // Close the other end of the pipe.
169     core.close(pipe.handle0);
170
171     // Not observed yet because we haven't pumped events yet.
172     expect(connection1.encounteredError()).toBeFalsy();
173
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);
178
179     // Write failures are not reported.
180     expect(connection1.encounteredError()).toBeFalsy();
181
182     // Pump events, and then we should start observing the closed pipe.
183     mockSupport.pumpOnce(core.RESULT_OK);
184
185     expect(connection1.encounteredError()).toBeTruthy();
186
187     connection1.close();
188   }
189
190   function testRequestResponse() {
191
192     // ProviderImpl ------------------------------------------------------------
193
194     function ProviderImpl(peer) {
195       this.peer = peer;
196     }
197
198     ProviderImpl.prototype =
199         Object.create(sample_interfaces.ProviderStub.prototype);
200
201     ProviderImpl.prototype.echoString = function(a) {
202       mockSupport.queuePump(core.RESULT_OK);
203       return Promise.resolve({a: a});
204     };
205
206     ProviderImpl.prototype.echoStrings = function(a, b) {
207       mockSupport.queuePump(core.RESULT_OK);
208       return Promise.resolve({a: a, b: b});
209     };
210
211     // ProviderClientImpl ------------------------------------------------------
212
213     function ProviderClientImpl(peer) {
214       this.peer = peer;
215     }
216
217     ProviderClientImpl.prototype =
218         Object.create(sample_interfaces.ProviderClientStub.prototype);
219
220     var pipe = core.createMessagePipe();
221
222     var connection0 = new connection.Connection(
223         pipe.handle0, ProviderImpl, sample_interfaces.ProviderClientProxy);
224
225     var connection1 = new connection.Connection(
226         pipe.handle1, ProviderClientImpl, sample_interfaces.ProviderProxy);
227
228     var origReadMessage = core.readMessage;
229     // echoString
230     mockSupport.queuePump(core.RESULT_OK);
231     return connection1.remote.echoString("hello").then(function(response) {
232       expect(response.a).toBe("hello");
233     }).then(function() {
234       // echoStrings
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");
240     }).then(function() {
241       // Mock a read failure, expect it to fail.
242       core.readMessage = function() {
243         return { result: core.RESULT_UNKNOWN };
244       };
245       mockSupport.queuePump(core.RESULT_OK);
246       return connection1.remote.echoString("goodbye");
247     }).then(function() {
248       throw Error("Expected echoString to fail.");
249     }, function(error) {
250       expect(error.message).toBe("Connection error: " + core.RESULT_UNKNOWN);
251
252       // Clean up.
253       core.readMessage = origReadMessage;
254     });
255   }
256 });