OLD | NEW |
| (Empty) |
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/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/support", | |
59 "mojo/public/js/core", | |
60 "mojo/public/js/connection", | |
61 "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom", | |
62 "mojo/public/interfaces/bindings/tests/sample_service.mojom", | |
63 "mojo/public/js/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 createPeerConnection(handle, stubClass, proxyClass) { | |
85 var c = new connection.Connection(handle, stubClass, proxyClass); | |
86 c.local.peer = c.remote; | |
87 c.remote.peer = c.local; | |
88 return c; | |
89 } | |
90 | |
91 function testClientServer() { | |
92 var receivedFrobinate = false; | |
93 var receivedDidFrobinate = false; | |
94 | |
95 // ServiceImpl ------------------------------------------------------------ | |
96 | |
97 function ServiceImpl() { | |
98 } | |
99 | |
100 ServiceImpl.prototype = Object.create( | |
101 sample_service.Service.stubClass.prototype); | |
102 | |
103 ServiceImpl.prototype.frobinate = function(foo, baz, port) { | |
104 receivedFrobinate = true; | |
105 | |
106 expect(foo.name).toBe("Example name"); | |
107 expect(baz).toBeTruthy(); | |
108 expect(core.close(port)).toBe(core.RESULT_OK); | |
109 | |
110 this.peer.didFrobinate(42); | |
111 }; | |
112 | |
113 // ServiceClientImpl ------------------------------------------------------ | |
114 | |
115 function ServiceClientImpl() { | |
116 } | |
117 | |
118 ServiceClientImpl.prototype = | |
119 Object.create(sample_service.ServiceClient.stubClass.prototype); | |
120 | |
121 ServiceClientImpl.prototype.didFrobinate = function(result) { | |
122 receivedDidFrobinate = true; | |
123 | |
124 expect(result).toBe(42); | |
125 }; | |
126 | |
127 var pipe = core.createMessagePipe(); | |
128 var anotherPipe = core.createMessagePipe(); | |
129 var sourcePipe = core.createMessagePipe(); | |
130 | |
131 var connection0 = createPeerConnection( | |
132 pipe.handle0, ServiceImpl, sample_service.ServiceClient.proxyClass); | |
133 | |
134 var connection1 = createPeerConnection( | |
135 pipe.handle1, ServiceClientImpl, sample_service.Service.proxyClass); | |
136 | |
137 var foo = new sample_service.Foo(); | |
138 foo.bar = new sample_service.Bar(); | |
139 foo.name = "Example name"; | |
140 foo.source = sourcePipe.handle0; | |
141 connection1.remote.frobinate(foo, true, anotherPipe.handle0); | |
142 | |
143 mockSupport.pumpOnce(core.RESULT_OK); | |
144 | |
145 expect(receivedFrobinate).toBeTruthy(); | |
146 expect(receivedDidFrobinate).toBeTruthy(); | |
147 | |
148 connection0.close(); | |
149 connection1.close(); | |
150 | |
151 expect(mockSupport.numberOfWaitingCallbacks()).toBe(0); | |
152 | |
153 // sourcePipe.handle0 was closed automatically when sent over IPC. | |
154 expect(core.close(sourcePipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT); | |
155 // sourcePipe.handle1 hasn't been closed yet. | |
156 expect(core.close(sourcePipe.handle1)).toBe(core.RESULT_OK); | |
157 | |
158 // anotherPipe.handle0 was closed automatically when sent over IPC. | |
159 expect(core.close(anotherPipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT); | |
160 // anotherPipe.handle1 hasn't been closed yet. | |
161 expect(core.close(anotherPipe.handle1)).toBe(core.RESULT_OK); | |
162 | |
163 // The Connection object is responsible for closing these handles. | |
164 expect(core.close(pipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT); | |
165 expect(core.close(pipe.handle1)).toBe(core.RESULT_INVALID_ARGUMENT); | |
166 } | |
167 | |
168 function testWriteToClosedPipe() { | |
169 var pipe = core.createMessagePipe(); | |
170 | |
171 var connection1 = createPeerConnection( | |
172 pipe.handle1, function() {}, sample_service.Service.proxyClass); | |
173 | |
174 // Close the other end of the pipe. | |
175 core.close(pipe.handle0); | |
176 | |
177 // Not observed yet because we haven't pumped events yet. | |
178 expect(connection1.encounteredError()).toBeFalsy(); | |
179 | |
180 var foo = new sample_service.Foo(); | |
181 foo.bar = new sample_service.Bar(); | |
182 // TODO(darin): crbug.com/357043: pass null in place of |foo| here. | |
183 connection1.remote.frobinate(foo, true, null); | |
184 | |
185 // Write failures are not reported. | |
186 expect(connection1.encounteredError()).toBeFalsy(); | |
187 | |
188 // Pump events, and then we should start observing the closed pipe. | |
189 mockSupport.pumpOnce(core.RESULT_OK); | |
190 | |
191 expect(connection1.encounteredError()).toBeTruthy(); | |
192 | |
193 connection1.close(); | |
194 } | |
195 | |
196 function testRequestResponse() { | |
197 | |
198 // ProviderImpl ------------------------------------------------------------ | |
199 | |
200 function ProviderImpl() { | |
201 } | |
202 | |
203 ProviderImpl.prototype = | |
204 Object.create(sample_interfaces.Provider.stubClass.prototype); | |
205 | |
206 ProviderImpl.prototype.echoString = function(a) { | |
207 mockSupport.queuePump(core.RESULT_OK); | |
208 return Promise.resolve({a: a}); | |
209 }; | |
210 | |
211 ProviderImpl.prototype.echoStrings = function(a, b) { | |
212 mockSupport.queuePump(core.RESULT_OK); | |
213 return Promise.resolve({a: a, b: b}); | |
214 }; | |
215 | |
216 // ProviderClientImpl ------------------------------------------------------ | |
217 | |
218 function ProviderClientImpl() { | |
219 } | |
220 | |
221 ProviderClientImpl.prototype = | |
222 Object.create(sample_interfaces.ProviderClient.stubClass.prototype); | |
223 | |
224 var pipe = core.createMessagePipe(); | |
225 | |
226 var connection0 = createPeerConnection( | |
227 pipe.handle0, | |
228 ProviderImpl, | |
229 sample_interfaces.ProviderClient.proxyClass); | |
230 | |
231 var connection1 = createPeerConnection( | |
232 pipe.handle1, | |
233 ProviderClientImpl, | |
234 sample_interfaces.Provider.proxyClass); | |
235 | |
236 var origReadMessage = core.readMessage; | |
237 // echoString | |
238 mockSupport.queuePump(core.RESULT_OK); | |
239 return connection1.remote.echoString("hello").then(function(response) { | |
240 expect(response.a).toBe("hello"); | |
241 }).then(function() { | |
242 // echoStrings | |
243 mockSupport.queuePump(core.RESULT_OK); | |
244 return connection1.remote.echoStrings("hello", "world"); | |
245 }).then(function(response) { | |
246 expect(response.a).toBe("hello"); | |
247 expect(response.b).toBe("world"); | |
248 }).then(function() { | |
249 // Mock a read failure, expect it to fail. | |
250 core.readMessage = function() { | |
251 return { result: core.RESULT_UNKNOWN }; | |
252 }; | |
253 mockSupport.queuePump(core.RESULT_OK); | |
254 return connection1.remote.echoString("goodbye"); | |
255 }).then(function() { | |
256 throw Error("Expected echoString to fail."); | |
257 }, function(error) { | |
258 expect(error.message).toBe("Connection error: " + core.RESULT_UNKNOWN); | |
259 | |
260 // Clean up. | |
261 core.readMessage = origReadMessage; | |
262 }); | |
263 } | |
264 }); | |
OLD | NEW |