|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 // This file tests message ports and semantics of the frameworker which aren't |
|
6 // directly related to the sandbox. See also browser_frameworker_sandbox.js. |
|
7 |
|
8 function makeWorkerUrl(runner) { |
|
9 let prefix = "http://example.com/browser/toolkit/components/social/test/browser/echo.sjs?"; |
|
10 if (typeof runner == "function") { |
|
11 runner = "var run=" + runner.toSource() + ";run();"; |
|
12 } |
|
13 return prefix + encodeURI(runner); |
|
14 } |
|
15 |
|
16 var getFrameWorkerHandle; |
|
17 function test() { |
|
18 waitForExplicitFinish(); |
|
19 |
|
20 let scope = {}; |
|
21 Cu.import("resource://gre/modules/FrameWorker.jsm", scope); |
|
22 getFrameWorkerHandle = scope.getFrameWorkerHandle; |
|
23 |
|
24 runTests(tests); |
|
25 } |
|
26 |
|
27 let tests = { |
|
28 testSimple: function(cbnext) { |
|
29 let run = function() { |
|
30 onconnect = function(e) { |
|
31 let port = e.ports[0]; |
|
32 port.onmessage = function(e) { |
|
33 if (e.data.topic == "ping") { |
|
34 port.postMessage({topic: "pong"}); |
|
35 } |
|
36 } |
|
37 } |
|
38 } |
|
39 |
|
40 let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSimple"); |
|
41 |
|
42 worker.port.onmessage = function(e) { |
|
43 if (e.data.topic == "pong") { |
|
44 worker.terminate(); |
|
45 cbnext(); |
|
46 } |
|
47 } |
|
48 worker.port.postMessage({topic: "ping"}) |
|
49 }, |
|
50 |
|
51 // when the client closes early but the worker tries to send anyway... |
|
52 // XXX - disabled due to bug 919878 - we close the frameworker before the |
|
53 // remote browser has completed initializing, leading to failures. Given |
|
54 // this can realistically only happen in this synthesized test environment, |
|
55 // disabling just this test seems OK for now. |
|
56 /*** |
|
57 testEarlyClose: function(cbnext) { |
|
58 let run = function() { |
|
59 onconnect = function(e) { |
|
60 let port = e.ports[0]; |
|
61 port.postMessage({topic: "oh hai"}); |
|
62 } |
|
63 } |
|
64 |
|
65 let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testEarlyClose"); |
|
66 worker.port.close(); |
|
67 worker.terminate(); |
|
68 cbnext(); |
|
69 }, |
|
70 ***/ |
|
71 |
|
72 // Check we do get a social.port-closing message as the port is closed. |
|
73 testPortClosingMessage: function(cbnext) { |
|
74 // We use 2 ports - we close the first and report success via the second. |
|
75 let run = function() { |
|
76 let firstPort, secondPort; |
|
77 onconnect = function(e) { |
|
78 let port = e.ports[0]; |
|
79 if (firstPort === undefined) { |
|
80 firstPort = port; |
|
81 port.onmessage = function(e) { |
|
82 if (e.data.topic == "social.port-closing") { |
|
83 secondPort.postMessage({topic: "got-closing"}); |
|
84 } |
|
85 } |
|
86 } else { |
|
87 secondPort = port; |
|
88 // now both ports are connected we can trigger the client side |
|
89 // closing the first. |
|
90 secondPort.postMessage({topic: "connected"}); |
|
91 } |
|
92 } |
|
93 } |
|
94 let workerurl = makeWorkerUrl(run); |
|
95 let worker1 = getFrameWorkerHandle(workerurl, undefined, "testPortClosingMessage worker1"); |
|
96 let worker2 = getFrameWorkerHandle(workerurl, undefined, "testPortClosingMessage worker2"); |
|
97 worker2.port.onmessage = function(e) { |
|
98 if (e.data.topic == "connected") { |
|
99 // both ports connected, so close the first. |
|
100 worker1.port.close(); |
|
101 } else if (e.data.topic == "got-closing") { |
|
102 worker2.terminate(); |
|
103 cbnext(); |
|
104 } |
|
105 } |
|
106 }, |
|
107 |
|
108 // Tests that prototypes added to core objects work with data sent over |
|
109 // the message ports. |
|
110 testPrototypes: function(cbnext) { |
|
111 let run = function() { |
|
112 // Modify the Array prototype... |
|
113 Array.prototype.customfunction = function() {}; |
|
114 onconnect = function(e) { |
|
115 let port = e.ports[0]; |
|
116 port.onmessage = function(e) { |
|
117 // Check the data we get via the port has the prototype modification |
|
118 if (e.data.topic == "hello" && e.data.data.customfunction) { |
|
119 port.postMessage({topic: "hello", data: [1,2,3]}); |
|
120 } |
|
121 } |
|
122 } |
|
123 } |
|
124 // hrmph - this kinda sucks as it is really just testing the actual |
|
125 // implementation rather than the end result, but is OK for now. |
|
126 // Really we are just testing that JSON.parse in the client window |
|
127 // is called. |
|
128 let fakeWindow = { |
|
129 JSON: { |
|
130 parse: function(s) { |
|
131 let data = JSON.parse(s); |
|
132 data.data.somextrafunction = function() {}; |
|
133 return data; |
|
134 } |
|
135 } |
|
136 } |
|
137 let worker = getFrameWorkerHandle(makeWorkerUrl(run), fakeWindow, "testPrototypes"); |
|
138 worker.port.onmessage = function(e) { |
|
139 if (e.data.topic == "hello") { |
|
140 ok(e.data.data.somextrafunction, "have someextrafunction") |
|
141 worker.terminate(); |
|
142 cbnext(); |
|
143 } |
|
144 } |
|
145 worker.port.postMessage({topic: "hello", data: [1,2,3]}); |
|
146 }, |
|
147 |
|
148 testSameOriginImport: function(cbnext) { |
|
149 let run = function() { |
|
150 onconnect = function(e) { |
|
151 let port = e.ports[0]; |
|
152 port.onmessage = function(e) { |
|
153 if (e.data.topic == "ping") { |
|
154 try { |
|
155 importScripts("http://mochi.test:8888/error"); |
|
156 } catch(ex) { |
|
157 port.postMessage({topic: "pong", data: ex}); |
|
158 return; |
|
159 } |
|
160 port.postMessage({topic: "pong", data: null}); |
|
161 } |
|
162 } |
|
163 } |
|
164 } |
|
165 |
|
166 let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSameOriginImport"); |
|
167 worker.port.onmessage = function(e) { |
|
168 if (e.data.topic == "pong") { |
|
169 isnot(e.data.data, null, "check same-origin applied to importScripts"); |
|
170 worker.terminate(); |
|
171 cbnext(); |
|
172 } |
|
173 } |
|
174 worker.port.postMessage({topic: "ping"}) |
|
175 }, |
|
176 |
|
177 testRelativeImport: function(cbnext) { |
|
178 let url = "https://example.com/browser/toolkit/components/social/test/browser/worker_relative.js"; |
|
179 let worker = getFrameWorkerHandle(url, undefined, "testSameOriginImport"); |
|
180 worker.port.onmessage = function(e) { |
|
181 if (e.data.topic == "done") { |
|
182 is(e.data.result, "ok", "check relative url in importScripts"); |
|
183 worker.terminate(); |
|
184 cbnext(); |
|
185 } |
|
186 } |
|
187 }, |
|
188 |
|
189 testNavigator: function(cbnext) { |
|
190 let run = function() { |
|
191 let port; |
|
192 ononline = function() { |
|
193 port.postMessage({topic: "ononline", data: navigator.onLine}); |
|
194 } |
|
195 onoffline = function() { |
|
196 port.postMessage({topic: "onoffline", data: navigator.onLine}); |
|
197 } |
|
198 onconnect = function(e) { |
|
199 port = e.ports[0]; |
|
200 port.postMessage({topic: "ready", |
|
201 data: { |
|
202 appName: navigator.appName, |
|
203 appVersion: navigator.appVersion, |
|
204 platform: navigator.platform, |
|
205 userAgent: navigator.userAgent, |
|
206 } |
|
207 }); |
|
208 } |
|
209 } |
|
210 let ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService2); |
|
211 let oldManage = ioService.manageOfflineStatus; |
|
212 let oldOffline = ioService.offline; |
|
213 |
|
214 ioService.manageOfflineStatus = false; |
|
215 let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testNavigator"); |
|
216 let expected_topic = "onoffline"; |
|
217 let expected_data = false; |
|
218 worker.port.onmessage = function(e) { |
|
219 is(e.data.topic, "ready"); |
|
220 for each (let attr in ['appName', 'appVersion', 'platform', 'userAgent']) { |
|
221 // each attribute must be a string with length > 0. |
|
222 is(typeof e.data.data[attr], "string"); |
|
223 ok(e.data.data[attr].length > 0); |
|
224 } |
|
225 |
|
226 worker.port.onmessage = function(e) { |
|
227 // a handler specifically for the offline notification. |
|
228 is(e.data.topic, "onoffline"); |
|
229 is(e.data.data, false); |
|
230 |
|
231 // add another handler specifically for the 'online' case. |
|
232 worker.port.onmessage = function(e) { |
|
233 is(e.data.topic, "ononline"); |
|
234 is(e.data.data, true); |
|
235 // all good! |
|
236 ioService.manageOfflineStatus = oldManage; |
|
237 ioService.offline = oldOffline; |
|
238 worker.terminate(); |
|
239 cbnext(); |
|
240 } |
|
241 ioService.offline = false; |
|
242 } |
|
243 ioService.offline = true; |
|
244 } |
|
245 }, |
|
246 |
|
247 testMissingWorker: function(cbnext) { |
|
248 // don't ever create this file! We want a 404. |
|
249 let url = "https://example.com/browser/toolkit/components/social/test/browser/worker_is_missing.js"; |
|
250 let worker = getFrameWorkerHandle(url, undefined, "testMissingWorker"); |
|
251 Services.obs.addObserver(function handleError(subj, topic, data) { |
|
252 Services.obs.removeObserver(handleError, "social:frameworker-error"); |
|
253 is(data, worker._worker.origin, "social:frameworker-error was handled"); |
|
254 worker.terminate(); |
|
255 cbnext(); |
|
256 }, 'social:frameworker-error', false); |
|
257 worker.port.onmessage = function(e) { |
|
258 ok(false, "social:frameworker-error was handled"); |
|
259 cbnext(); |
|
260 } |
|
261 }, |
|
262 |
|
263 testNoConnectWorker: function(cbnext) { |
|
264 let worker = getFrameWorkerHandle(makeWorkerUrl(function () {}), |
|
265 undefined, "testNoConnectWorker"); |
|
266 Services.obs.addObserver(function handleError(subj, topic, data) { |
|
267 Services.obs.removeObserver(handleError, "social:frameworker-error"); |
|
268 is(data, worker._worker.origin, "social:frameworker-error was handled"); |
|
269 worker.terminate(); |
|
270 cbnext(); |
|
271 }, 'social:frameworker-error', false); |
|
272 worker.port.onmessage = function(e) { |
|
273 ok(false, "social:frameworker-error was handled"); |
|
274 cbnext(); |
|
275 } |
|
276 }, |
|
277 |
|
278 testEmptyWorker: function(cbnext) { |
|
279 let worker = getFrameWorkerHandle(makeWorkerUrl(''), |
|
280 undefined, "testEmptyWorker"); |
|
281 Services.obs.addObserver(function handleError(subj, topic, data) { |
|
282 Services.obs.removeObserver(handleError, "social:frameworker-error"); |
|
283 is(data, worker._worker.origin, "social:frameworker-error was handled"); |
|
284 worker.terminate(); |
|
285 cbnext(); |
|
286 }, 'social:frameworker-error', false); |
|
287 worker.port.onmessage = function(e) { |
|
288 ok(false, "social:frameworker-error was handled"); |
|
289 cbnext(); |
|
290 } |
|
291 }, |
|
292 |
|
293 testWorkerConnectError: function(cbnext) { |
|
294 let run = function () { |
|
295 onconnect = function(e) { |
|
296 throw new Error("worker failure"); |
|
297 } |
|
298 } |
|
299 let worker = getFrameWorkerHandle(makeWorkerUrl(run), |
|
300 undefined, "testWorkerConnectError"); |
|
301 Services.obs.addObserver(function handleError(subj, topic, data) { |
|
302 Services.obs.removeObserver(handleError, "social:frameworker-error"); |
|
303 is(data, worker._worker.origin, "social:frameworker-error was handled"); |
|
304 worker.terminate(); |
|
305 cbnext(); |
|
306 }, 'social:frameworker-error', false); |
|
307 worker.port.onmessage = function(e) { |
|
308 ok(false, "social:frameworker-error was handled"); |
|
309 cbnext(); |
|
310 } |
|
311 }, |
|
312 |
|
313 // This will create the worker, then send a message to the port, then close |
|
314 // the port - all before the worker has actually initialized. |
|
315 testCloseFirstSend: function(cbnext) { |
|
316 let run = function() { |
|
317 let numPings = 0, numCloses = 0; |
|
318 onconnect = function(e) { |
|
319 let port = e.ports[0]; |
|
320 port.onmessage = function(e) { |
|
321 if (e.data.topic == "ping") { |
|
322 numPings += 1; |
|
323 } else if (e.data.topic == "social.port-closing") { |
|
324 numCloses += 1; |
|
325 } else if (e.data.topic == "get-counts") { |
|
326 port.postMessage({topic: "result", |
|
327 result: {ping: numPings, close: numCloses}}); |
|
328 } |
|
329 } |
|
330 } |
|
331 } |
|
332 |
|
333 let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSendAndClose"); |
|
334 worker.port.postMessage({topic: "ping"}); |
|
335 worker.port.close(); |
|
336 let newPort = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSendAndClose").port; |
|
337 newPort.onmessage = function(e) { |
|
338 if (e.data.topic == "result") { |
|
339 is(e.data.result.ping, 1, "the worker got the ping"); |
|
340 is(e.data.result.close, 1, "the worker got 1 close message"); |
|
341 worker.terminate(); |
|
342 cbnext(); |
|
343 } |
|
344 } |
|
345 newPort.postMessage({topic: "get-counts"}); |
|
346 }, |
|
347 |
|
348 // Like testCloseFirstSend, although in this test the worker has already |
|
349 // initialized (so the "connect pending ports" part of the worker isn't |
|
350 // what needs to handle this case.) |
|
351 testCloseAfterInit: function(cbnext) { |
|
352 let run = function() { |
|
353 let numPings = 0, numCloses = 0; |
|
354 onconnect = function(e) { |
|
355 let port = e.ports[0]; |
|
356 port.onmessage = function(e) { |
|
357 if (e.data.topic == "ping") { |
|
358 numPings += 1; |
|
359 } else if (e.data.topic == "social.port-closing") { |
|
360 numCloses += 1; |
|
361 } else if (e.data.topic == "get-counts") { |
|
362 port.postMessage({topic: "result", |
|
363 result: {ping: numPings, close: numCloses}}); |
|
364 } else if (e.data.topic == "get-ready") { |
|
365 port.postMessage({topic: "ready"}); |
|
366 } |
|
367 } |
|
368 } |
|
369 } |
|
370 |
|
371 let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSendAndClose"); |
|
372 worker.port.onmessage = function(e) { |
|
373 if (e.data.topic == "ready") { |
|
374 let newPort = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSendAndClose").port; |
|
375 newPort.postMessage({topic: "ping"}); |
|
376 newPort.close(); |
|
377 worker.port.postMessage({topic: "get-counts"}); |
|
378 } else if (e.data.topic == "result") { |
|
379 is(e.data.result.ping, 1, "the worker got the ping"); |
|
380 is(e.data.result.close, 1, "the worker got 1 close message"); |
|
381 worker.terminate(); |
|
382 cbnext(); |
|
383 } |
|
384 } |
|
385 worker.port.postMessage({topic: "get-ready"}); |
|
386 }, |
|
387 } |