1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/social/test/browser/browser_frameworker.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,387 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +// This file tests message ports and semantics of the frameworker which aren't 1.9 +// directly related to the sandbox. See also browser_frameworker_sandbox.js. 1.10 + 1.11 +function makeWorkerUrl(runner) { 1.12 + let prefix = "http://example.com/browser/toolkit/components/social/test/browser/echo.sjs?"; 1.13 + if (typeof runner == "function") { 1.14 + runner = "var run=" + runner.toSource() + ";run();"; 1.15 + } 1.16 + return prefix + encodeURI(runner); 1.17 +} 1.18 + 1.19 +var getFrameWorkerHandle; 1.20 +function test() { 1.21 + waitForExplicitFinish(); 1.22 + 1.23 + let scope = {}; 1.24 + Cu.import("resource://gre/modules/FrameWorker.jsm", scope); 1.25 + getFrameWorkerHandle = scope.getFrameWorkerHandle; 1.26 + 1.27 + runTests(tests); 1.28 +} 1.29 + 1.30 +let tests = { 1.31 + testSimple: function(cbnext) { 1.32 + let run = function() { 1.33 + onconnect = function(e) { 1.34 + let port = e.ports[0]; 1.35 + port.onmessage = function(e) { 1.36 + if (e.data.topic == "ping") { 1.37 + port.postMessage({topic: "pong"}); 1.38 + } 1.39 + } 1.40 + } 1.41 + } 1.42 + 1.43 + let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSimple"); 1.44 + 1.45 + worker.port.onmessage = function(e) { 1.46 + if (e.data.topic == "pong") { 1.47 + worker.terminate(); 1.48 + cbnext(); 1.49 + } 1.50 + } 1.51 + worker.port.postMessage({topic: "ping"}) 1.52 + }, 1.53 + 1.54 + // when the client closes early but the worker tries to send anyway... 1.55 + // XXX - disabled due to bug 919878 - we close the frameworker before the 1.56 + // remote browser has completed initializing, leading to failures. Given 1.57 + // this can realistically only happen in this synthesized test environment, 1.58 + // disabling just this test seems OK for now. 1.59 +/*** 1.60 + testEarlyClose: function(cbnext) { 1.61 + let run = function() { 1.62 + onconnect = function(e) { 1.63 + let port = e.ports[0]; 1.64 + port.postMessage({topic: "oh hai"}); 1.65 + } 1.66 + } 1.67 + 1.68 + let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testEarlyClose"); 1.69 + worker.port.close(); 1.70 + worker.terminate(); 1.71 + cbnext(); 1.72 + }, 1.73 +***/ 1.74 + 1.75 + // Check we do get a social.port-closing message as the port is closed. 1.76 + testPortClosingMessage: function(cbnext) { 1.77 + // We use 2 ports - we close the first and report success via the second. 1.78 + let run = function() { 1.79 + let firstPort, secondPort; 1.80 + onconnect = function(e) { 1.81 + let port = e.ports[0]; 1.82 + if (firstPort === undefined) { 1.83 + firstPort = port; 1.84 + port.onmessage = function(e) { 1.85 + if (e.data.topic == "social.port-closing") { 1.86 + secondPort.postMessage({topic: "got-closing"}); 1.87 + } 1.88 + } 1.89 + } else { 1.90 + secondPort = port; 1.91 + // now both ports are connected we can trigger the client side 1.92 + // closing the first. 1.93 + secondPort.postMessage({topic: "connected"}); 1.94 + } 1.95 + } 1.96 + } 1.97 + let workerurl = makeWorkerUrl(run); 1.98 + let worker1 = getFrameWorkerHandle(workerurl, undefined, "testPortClosingMessage worker1"); 1.99 + let worker2 = getFrameWorkerHandle(workerurl, undefined, "testPortClosingMessage worker2"); 1.100 + worker2.port.onmessage = function(e) { 1.101 + if (e.data.topic == "connected") { 1.102 + // both ports connected, so close the first. 1.103 + worker1.port.close(); 1.104 + } else if (e.data.topic == "got-closing") { 1.105 + worker2.terminate(); 1.106 + cbnext(); 1.107 + } 1.108 + } 1.109 + }, 1.110 + 1.111 + // Tests that prototypes added to core objects work with data sent over 1.112 + // the message ports. 1.113 + testPrototypes: function(cbnext) { 1.114 + let run = function() { 1.115 + // Modify the Array prototype... 1.116 + Array.prototype.customfunction = function() {}; 1.117 + onconnect = function(e) { 1.118 + let port = e.ports[0]; 1.119 + port.onmessage = function(e) { 1.120 + // Check the data we get via the port has the prototype modification 1.121 + if (e.data.topic == "hello" && e.data.data.customfunction) { 1.122 + port.postMessage({topic: "hello", data: [1,2,3]}); 1.123 + } 1.124 + } 1.125 + } 1.126 + } 1.127 + // hrmph - this kinda sucks as it is really just testing the actual 1.128 + // implementation rather than the end result, but is OK for now. 1.129 + // Really we are just testing that JSON.parse in the client window 1.130 + // is called. 1.131 + let fakeWindow = { 1.132 + JSON: { 1.133 + parse: function(s) { 1.134 + let data = JSON.parse(s); 1.135 + data.data.somextrafunction = function() {}; 1.136 + return data; 1.137 + } 1.138 + } 1.139 + } 1.140 + let worker = getFrameWorkerHandle(makeWorkerUrl(run), fakeWindow, "testPrototypes"); 1.141 + worker.port.onmessage = function(e) { 1.142 + if (e.data.topic == "hello") { 1.143 + ok(e.data.data.somextrafunction, "have someextrafunction") 1.144 + worker.terminate(); 1.145 + cbnext(); 1.146 + } 1.147 + } 1.148 + worker.port.postMessage({topic: "hello", data: [1,2,3]}); 1.149 + }, 1.150 + 1.151 + testSameOriginImport: function(cbnext) { 1.152 + let run = function() { 1.153 + onconnect = function(e) { 1.154 + let port = e.ports[0]; 1.155 + port.onmessage = function(e) { 1.156 + if (e.data.topic == "ping") { 1.157 + try { 1.158 + importScripts("http://mochi.test:8888/error"); 1.159 + } catch(ex) { 1.160 + port.postMessage({topic: "pong", data: ex}); 1.161 + return; 1.162 + } 1.163 + port.postMessage({topic: "pong", data: null}); 1.164 + } 1.165 + } 1.166 + } 1.167 + } 1.168 + 1.169 + let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSameOriginImport"); 1.170 + worker.port.onmessage = function(e) { 1.171 + if (e.data.topic == "pong") { 1.172 + isnot(e.data.data, null, "check same-origin applied to importScripts"); 1.173 + worker.terminate(); 1.174 + cbnext(); 1.175 + } 1.176 + } 1.177 + worker.port.postMessage({topic: "ping"}) 1.178 + }, 1.179 + 1.180 + testRelativeImport: function(cbnext) { 1.181 + let url = "https://example.com/browser/toolkit/components/social/test/browser/worker_relative.js"; 1.182 + let worker = getFrameWorkerHandle(url, undefined, "testSameOriginImport"); 1.183 + worker.port.onmessage = function(e) { 1.184 + if (e.data.topic == "done") { 1.185 + is(e.data.result, "ok", "check relative url in importScripts"); 1.186 + worker.terminate(); 1.187 + cbnext(); 1.188 + } 1.189 + } 1.190 + }, 1.191 + 1.192 + testNavigator: function(cbnext) { 1.193 + let run = function() { 1.194 + let port; 1.195 + ononline = function() { 1.196 + port.postMessage({topic: "ononline", data: navigator.onLine}); 1.197 + } 1.198 + onoffline = function() { 1.199 + port.postMessage({topic: "onoffline", data: navigator.onLine}); 1.200 + } 1.201 + onconnect = function(e) { 1.202 + port = e.ports[0]; 1.203 + port.postMessage({topic: "ready", 1.204 + data: { 1.205 + appName: navigator.appName, 1.206 + appVersion: navigator.appVersion, 1.207 + platform: navigator.platform, 1.208 + userAgent: navigator.userAgent, 1.209 + } 1.210 + }); 1.211 + } 1.212 + } 1.213 + let ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService2); 1.214 + let oldManage = ioService.manageOfflineStatus; 1.215 + let oldOffline = ioService.offline; 1.216 + 1.217 + ioService.manageOfflineStatus = false; 1.218 + let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testNavigator"); 1.219 + let expected_topic = "onoffline"; 1.220 + let expected_data = false; 1.221 + worker.port.onmessage = function(e) { 1.222 + is(e.data.topic, "ready"); 1.223 + for each (let attr in ['appName', 'appVersion', 'platform', 'userAgent']) { 1.224 + // each attribute must be a string with length > 0. 1.225 + is(typeof e.data.data[attr], "string"); 1.226 + ok(e.data.data[attr].length > 0); 1.227 + } 1.228 + 1.229 + worker.port.onmessage = function(e) { 1.230 + // a handler specifically for the offline notification. 1.231 + is(e.data.topic, "onoffline"); 1.232 + is(e.data.data, false); 1.233 + 1.234 + // add another handler specifically for the 'online' case. 1.235 + worker.port.onmessage = function(e) { 1.236 + is(e.data.topic, "ononline"); 1.237 + is(e.data.data, true); 1.238 + // all good! 1.239 + ioService.manageOfflineStatus = oldManage; 1.240 + ioService.offline = oldOffline; 1.241 + worker.terminate(); 1.242 + cbnext(); 1.243 + } 1.244 + ioService.offline = false; 1.245 + } 1.246 + ioService.offline = true; 1.247 + } 1.248 + }, 1.249 + 1.250 + testMissingWorker: function(cbnext) { 1.251 + // don't ever create this file! We want a 404. 1.252 + let url = "https://example.com/browser/toolkit/components/social/test/browser/worker_is_missing.js"; 1.253 + let worker = getFrameWorkerHandle(url, undefined, "testMissingWorker"); 1.254 + Services.obs.addObserver(function handleError(subj, topic, data) { 1.255 + Services.obs.removeObserver(handleError, "social:frameworker-error"); 1.256 + is(data, worker._worker.origin, "social:frameworker-error was handled"); 1.257 + worker.terminate(); 1.258 + cbnext(); 1.259 + }, 'social:frameworker-error', false); 1.260 + worker.port.onmessage = function(e) { 1.261 + ok(false, "social:frameworker-error was handled"); 1.262 + cbnext(); 1.263 + } 1.264 + }, 1.265 + 1.266 + testNoConnectWorker: function(cbnext) { 1.267 + let worker = getFrameWorkerHandle(makeWorkerUrl(function () {}), 1.268 + undefined, "testNoConnectWorker"); 1.269 + Services.obs.addObserver(function handleError(subj, topic, data) { 1.270 + Services.obs.removeObserver(handleError, "social:frameworker-error"); 1.271 + is(data, worker._worker.origin, "social:frameworker-error was handled"); 1.272 + worker.terminate(); 1.273 + cbnext(); 1.274 + }, 'social:frameworker-error', false); 1.275 + worker.port.onmessage = function(e) { 1.276 + ok(false, "social:frameworker-error was handled"); 1.277 + cbnext(); 1.278 + } 1.279 + }, 1.280 + 1.281 + testEmptyWorker: function(cbnext) { 1.282 + let worker = getFrameWorkerHandle(makeWorkerUrl(''), 1.283 + undefined, "testEmptyWorker"); 1.284 + Services.obs.addObserver(function handleError(subj, topic, data) { 1.285 + Services.obs.removeObserver(handleError, "social:frameworker-error"); 1.286 + is(data, worker._worker.origin, "social:frameworker-error was handled"); 1.287 + worker.terminate(); 1.288 + cbnext(); 1.289 + }, 'social:frameworker-error', false); 1.290 + worker.port.onmessage = function(e) { 1.291 + ok(false, "social:frameworker-error was handled"); 1.292 + cbnext(); 1.293 + } 1.294 + }, 1.295 + 1.296 + testWorkerConnectError: function(cbnext) { 1.297 + let run = function () { 1.298 + onconnect = function(e) { 1.299 + throw new Error("worker failure"); 1.300 + } 1.301 + } 1.302 + let worker = getFrameWorkerHandle(makeWorkerUrl(run), 1.303 + undefined, "testWorkerConnectError"); 1.304 + Services.obs.addObserver(function handleError(subj, topic, data) { 1.305 + Services.obs.removeObserver(handleError, "social:frameworker-error"); 1.306 + is(data, worker._worker.origin, "social:frameworker-error was handled"); 1.307 + worker.terminate(); 1.308 + cbnext(); 1.309 + }, 'social:frameworker-error', false); 1.310 + worker.port.onmessage = function(e) { 1.311 + ok(false, "social:frameworker-error was handled"); 1.312 + cbnext(); 1.313 + } 1.314 + }, 1.315 + 1.316 + // This will create the worker, then send a message to the port, then close 1.317 + // the port - all before the worker has actually initialized. 1.318 + testCloseFirstSend: function(cbnext) { 1.319 + let run = function() { 1.320 + let numPings = 0, numCloses = 0; 1.321 + onconnect = function(e) { 1.322 + let port = e.ports[0]; 1.323 + port.onmessage = function(e) { 1.324 + if (e.data.topic == "ping") { 1.325 + numPings += 1; 1.326 + } else if (e.data.topic == "social.port-closing") { 1.327 + numCloses += 1; 1.328 + } else if (e.data.topic == "get-counts") { 1.329 + port.postMessage({topic: "result", 1.330 + result: {ping: numPings, close: numCloses}}); 1.331 + } 1.332 + } 1.333 + } 1.334 + } 1.335 + 1.336 + let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSendAndClose"); 1.337 + worker.port.postMessage({topic: "ping"}); 1.338 + worker.port.close(); 1.339 + let newPort = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSendAndClose").port; 1.340 + newPort.onmessage = function(e) { 1.341 + if (e.data.topic == "result") { 1.342 + is(e.data.result.ping, 1, "the worker got the ping"); 1.343 + is(e.data.result.close, 1, "the worker got 1 close message"); 1.344 + worker.terminate(); 1.345 + cbnext(); 1.346 + } 1.347 + } 1.348 + newPort.postMessage({topic: "get-counts"}); 1.349 + }, 1.350 + 1.351 + // Like testCloseFirstSend, although in this test the worker has already 1.352 + // initialized (so the "connect pending ports" part of the worker isn't 1.353 + // what needs to handle this case.) 1.354 + testCloseAfterInit: function(cbnext) { 1.355 + let run = function() { 1.356 + let numPings = 0, numCloses = 0; 1.357 + onconnect = function(e) { 1.358 + let port = e.ports[0]; 1.359 + port.onmessage = function(e) { 1.360 + if (e.data.topic == "ping") { 1.361 + numPings += 1; 1.362 + } else if (e.data.topic == "social.port-closing") { 1.363 + numCloses += 1; 1.364 + } else if (e.data.topic == "get-counts") { 1.365 + port.postMessage({topic: "result", 1.366 + result: {ping: numPings, close: numCloses}}); 1.367 + } else if (e.data.topic == "get-ready") { 1.368 + port.postMessage({topic: "ready"}); 1.369 + } 1.370 + } 1.371 + } 1.372 + } 1.373 + 1.374 + let worker = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSendAndClose"); 1.375 + worker.port.onmessage = function(e) { 1.376 + if (e.data.topic == "ready") { 1.377 + let newPort = getFrameWorkerHandle(makeWorkerUrl(run), undefined, "testSendAndClose").port; 1.378 + newPort.postMessage({topic: "ping"}); 1.379 + newPort.close(); 1.380 + worker.port.postMessage({topic: "get-counts"}); 1.381 + } else if (e.data.topic == "result") { 1.382 + is(e.data.result.ping, 1, "the worker got the ping"); 1.383 + is(e.data.result.close, 1, "the worker got 1 close message"); 1.384 + worker.terminate(); 1.385 + cbnext(); 1.386 + } 1.387 + } 1.388 + worker.port.postMessage({topic: "get-ready"}); 1.389 + }, 1.390 +}