diff options
Diffstat (limited to 'dom/base/test/test_postMessages.html')
-rw-r--r-- | dom/base/test/test_postMessages.html | 654 |
1 files changed, 654 insertions, 0 deletions
diff --git a/dom/base/test/test_postMessages.html b/dom/base/test/test_postMessages.html new file mode 100644 index 000000000..13a284270 --- /dev/null +++ b/dom/base/test/test_postMessages.html @@ -0,0 +1,654 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for postMessages cloning/transferring objects</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> + +<body> +<input id="fileList" type="file"></input> +<script type="application/javascript;version=1.7"> + +function setup_tests() { + SpecialPowers.pushPrefEnv({"set": [["dom.input.dirpicker", true], + ["javascript.options.wasm", true]]}, next); +} + +function getType(a) { + if (a === null || a === undefined) + return 'null'; + + if (Array.isArray(a)) + return 'array'; + + if (typeof a == 'object') + return 'object'; + + if (SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported() && + a instanceof WebAssembly.Module) + return "wasm"; + + return 'primitive'; +} + +function compare(a, b) { + is (getType(a), getType(b), 'Type matches'); + + var type = getType(a); + if (type == 'array') { + is (a.length, b.length, 'Array.length matches'); + for (var i = 0; i < a.length; ++i) { + compare(a[i], b[i]); + } + + return; + } + + if (type == 'object') { + ok (a !== b, 'They should not match'); + + var aProps = []; + for (var p in a) aProps.push(p); + + var bProps = []; + for (var p in b) bProps.push(p); + + is (aProps.length, bProps.length, 'Props match'); + is (aProps.sort().toSource(), bProps.sort().toSource(), 'Props match - using toSource()'); + + for (var p in a) { + compare(a[p], b[p]); + } + + return; + } + + if (type == 'wasm') { + var wasmA = new WebAssembly.Instance(a); + ok(wasmA instanceof WebAssembly.Instance, "got an instance"); + + var wasmB = new WebAssembly.Instance(b); + ok(wasmB instanceof WebAssembly.Instance, "got an instance"); + + ok(wasmA.exports.foo() === wasmB.exports.foo(), "Same result!"); + ok(wasmB.exports.foo() === 42, "We want 42"); + } + + if (type != 'null') { + is (a.toSource(), b.toSource(), 'Matching using toSource()'); + } +} + +var clonableObjects = [ + { target: 'all', data: 'hello world' }, + { target: 'all', data: 123 }, + { target: 'all', data: null }, + { target: 'all', data: true }, + { target: 'all', data: new Date() }, + { target: 'all', data: [ 1, 'test', true, new Date() ] }, + { target: 'all', data: { a: true, b: null, c: new Date(), d: [ true, false, {} ] } }, + { target: 'all', data: new Blob([123], { type: 'plain/text' }) }, + { target: 'all', data: new ImageData(2, 2) }, +]; + +function create_fileList() { + var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js"); + var script = SpecialPowers.loadChromeScript(url); + + function onOpened(message) { + var fileList = document.getElementById('fileList'); + SpecialPowers.wrap(fileList).mozSetFileArray([message.file]); + + // Just a simple test + var domFile = fileList.files[0]; + is(domFile.name, "prefs.js", "fileName should be prefs.js"); + + clonableObjects.push({ target: 'all', data: fileList.files }); + script.destroy(); + next(); + } + + script.addMessageListener("file.opened", onOpened); + script.sendAsyncMessage("file.open"); +} + +function create_directory() { + if (navigator.userAgent.toLowerCase().indexOf('Android') != -1) { + next(); + return; + } + + var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js"); + var script = SpecialPowers.loadChromeScript(url); + + function onOpened(message) { + var fileList = document.getElementById('fileList'); + SpecialPowers.wrap(fileList).mozSetDirectory(message.dir); + + fileList.getFilesAndDirectories().then(function(list) { + // Just a simple test + is(list.length, 1, "This list has 1 element"); + ok(list[0] instanceof Directory, "We have a directory."); + + clonableObjects.push({ target: 'all', data: list[0] }); + script.destroy(); + next(); + }); + } + + script.addMessageListener("dir.opened", onOpened); + script.sendAsyncMessage("dir.open"); +} + +function create_wasmModule() { + info("Checking if we can play with WebAssembly..."); + + if (!SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported()) { + next(); + return; + } + + ok(WebAssembly, "WebAssembly object should exist"); + ok(WebAssembly.compile, "WebAssembly.compile function should exist"); + + const wasmTextToBinary = SpecialPowers.unwrap(SpecialPowers.Cu.getJSTestingFunctions().wasmTextToBinary); + const fooModuleCode = wasmTextToBinary(`(module + (func $foo (result i32) (i32.const 42)) + (export "foo" $foo) + )`, 'new-format'); + + WebAssembly.compile(fooModuleCode).then((m) => { + ok(m instanceof WebAssembly.Module, "The WasmModule has been compiled."); + clonableObjects.push({ target: 'sameProcess', data: m }); + next(); + }, () => { + ok(false, "The compilation of the wasmModule failed."); + }); +} + +function runTests(obj) { + ok(('clonableObjectsEveryWhere' in obj) && + ('clonableObjectsSameProcess' in obj) && + ('transferableObjects' in obj) && + (obj.clonableObjectsEveryWhere || obj.clonableObjectsSameProcess || obj.transferableObjects), "We must run some test!"); + + // cloning tests - everyWhere + new Promise(function(resolve, reject) { + if (!obj.clonableObjectsEveryWhere) { + resolve(); + return; + } + + var clonableObjectsId = 0; + function runClonableTest() { + if (clonableObjectsId >= clonableObjects.length) { + resolve(); + return; + } + + var object = clonableObjects[clonableObjectsId++]; + + if (object.target != 'all') { + runClonableTest(); + return; + } + + obj.send(object.data, []).then(function(received) { + compare(received.data, object.data); + runClonableTest(); + }); + } + + runClonableTest(); + }) + + // clonable same process + .then(function() { + return new Promise(function(resolve, reject) { + if (!obj.clonableObjectsSameProcess) { + resolve(); + return; + } + + var clonableObjectsId = 0; + function runClonableTest() { + if (clonableObjectsId >= clonableObjects.length) { + resolve(); + return; + } + + var object = clonableObjects[clonableObjectsId++]; + + if (object.target != 'sameProcess') { + runClonableTest(); + return; + } + + obj.send(object.data, []).then(function(received) { + compare(received.data, object.data); + runClonableTest(); + }); + } + + runClonableTest(); + }); + }) + + // transfering tests + .then(function() { + if (!obj.transferableObjects) { + return; + } + + // MessagePort + return new Promise(function(r, rr) { + var mc = new MessageChannel(); + obj.send(42, [mc.port1]).then(function(received) { + ok(received.ports.length, 1, "MessagePort has been transferred"); + mc.port2.postMessage("hello world"); + received.ports[0].onmessage = function(e) { + ok(e.data, "hello world", "Ports are connected!"); + r(); + } + }); + }); + }) + + // no dup transfering + .then(function() { + if (!obj.transferableObjects) { + return; + } + + // MessagePort + return new Promise(function(r, rr) { + var mc = new MessageChannel(); + obj.send(42, [mc.port1, mc.port1]).then(function(received) { + ok(false, "Duplicate ports should throw!"); + }, function() { + ok(true, "Duplicate ports should throw!"); + }) + .then(r); + }); + }) + + // non transfering tests + .then(function() { + if (obj.transferableObjects) { + return; + } + + // MessagePort + return new Promise(function(r, rr) { + var mc = new MessageChannel(); + obj.send(42, [mc.port1]).then(function(received) { + ok(false, "This object should not support port transferring"); + }, function() { + ok(true, "This object should not support port transferring"); + }) + .then(r); + }); + }) + + // done. + .then(function() { + obj.finished(); + }); +} + +// PostMessage to the same window. +function test_windowToWindow() { + info("Testing window to window"); + var resolve; + + onmessage = function(e) { + if (!resolve) { + ok(false, "Unexpected message!"); + return; + } + + let tmp = resolve; + resolve = null; + tmp({ data: e.data, ports: e.ports }); + } + + runTests({ + clonableObjectsEveryWhere: true, + clonableObjectsSameProcess: true, + transferableObjects: true, + send: function(what, ports) { + return new Promise(function(r, rr) { + resolve = r; + + try { + postMessage(what, '*', ports); + } catch(e) { + resolve = null; + rr(); + } + }); + }, + + finished: function() { + onmessage = null; + next(); + } + }); +} + +// PostMessage to iframe +function test_windowToIframe() { + info("Testing window to iframe"); + test_windowToIframeURL('iframe_postMessages.html'); +} + +// PostMessage to cross-origin iframe +function test_windowToCrossOriginIframe() { + info("Testing window to cross-origin iframe"); + test_windowToIframeURL('http://example.com/tests/dom/base/test/iframe_postMessages.html'); +} + +// iframe helper class +function test_windowToIframeURL(url) { + var resolve; + + onmessage = function(e) { + if (!resolve) { + ok(false, "Unexpected message!"); + return; + } + + let tmp = resolve; + resolve = null; + tmp({ data: e.data, ports: e.ports }); + } + + var ifr = document.createElement('iframe'); + ifr.src = url; + ifr.onload = function() { + runTests({ + clonableObjectsEveryWhere: true, + clonableObjectsSameProcess: true, + transferableObjects: true, + send: function(what, ports) { + return new Promise(function(r, rr) { + resolve = r; + try { + ifr.contentWindow.postMessage(what, '*', ports); + } catch(e) { + resolve = null; + rr(); + } + }); + }, + + finished: function() { + document.body.removeChild(ifr); + onmessage = null; + next(); + } + }); + } + document.body.appendChild(ifr); +} + +// PostMessage for Workers +function test_workers() { + info("Testing Workers"); + + var resolve; + + var w = new Worker('worker_postMessages.js'); + w.postMessage('workers'); + w.onmessage = function(e) { + is(e.data, 'ok', "Worker ready!"); + + w.onmessage = function(e) { + if (!resolve) { + ok(false, "Unexpected message!"); + return; + } + + let tmp = resolve; + resolve = null; + tmp({ data: e.data, ports: e.ports }); + } + + runTests({ + clonableObjectsEveryWhere: true, + clonableObjectsSameProcess: true, + transferableObjects: true, + send: function(what, ports) { + return new Promise(function(r, rr) { + resolve = r; + try { + w.postMessage(what, ports); + } catch(e) { + resolve = null; + rr(); + } + }); + }, + + finished: function() { + onmessage = null; + next(); + } + }); + } +} + +// PostMessage for BroadcastChannel +function test_broadcastChannel() { + info("Testing broadcastChannel"); + + var bc1 = new BroadcastChannel('postMessagesTest'); + var bc2 = new BroadcastChannel('postMessagesTest'); + + var resolve; + + bc2.onmessage = function(e) { + if (!resolve) { + ok(false, "Unexpected message!"); + return; + } + + let tmp = resolve; + resolve = null; + tmp({ data: e.data, ports: [] }); + } + + runTests({ + clonableObjectsEveryWhere: true, + clonableObjectsSameProcess: false, + transferableObjects: false, + send: function(what, ports) { + return new Promise(function(r, rr) { + if (ports.length) { + rr(); + return; + } + + resolve = r; + bc1.postMessage(what); + }); + }, + + finished: function() { + onmessage = null; + next(); + } + }); +} + +// PostMessage for BroadcastChannel in workers +function test_broadcastChannel_inWorkers() { + info("Testing broadcastChannel in Workers"); + + var bc = new BroadcastChannel('postMessagesTest_inWorkers'); + var resolve; + + var w = new Worker('worker_postMessages.js'); + w.postMessage('broadcastChannel'); + w.onmessage = function(e) { + is(e.data, 'ok', "Worker ready!"); + + w.onmessage = function(e) { + if (!resolve) { + ok(false, "Unexpected message!"); + return; + } + + let tmp = resolve; + resolve = null; + tmp({ data: e.data, ports: e.ports }); + } + + runTests({ + clonableObjectsEveryWhere: true, + clonableObjectsSameProcess: false, + transferableObjects: false, + send: function(what, ports) { + return new Promise(function(r, rr) { + if (ports.length) { + rr(); + return; + } + + resolve = r; + bc.postMessage(what); + }); + }, + + finished: function() { + onmessage = null; + next(); + } + }); + } +} + +// PostMessage for MessagePort +function test_messagePort() { + info("Testing messagePort"); + + var mc = new MessageChannel(); + var resolve; + + mc.port2.onmessage = function(e) { + if (!resolve) { + ok(false, "Unexpected message!"); + return; + } + + let tmp = resolve; + resolve = null; + tmp({ data: e.data, ports: e.ports }); + } + + runTests({ + clonableObjectsEveryWhere: true, + clonableObjectsSameProcess: false, + transferableObjects: true, + send: function(what, ports) { + return new Promise(function(r, rr) { + resolve = r; + try { + mc.port1.postMessage(what, ports); + } catch(e) { + resolve = null; + rr(); + } + }); + }, + + finished: function() { + onmessage = null; + next(); + } + }); +} + +// PostMessage for MessagePort in Workers +function test_messagePort_inWorkers() { + info("Testing messagePort in workers"); + + var mc = new MessageChannel(); + var resolve; + + var w = new Worker('worker_postMessages.js'); + w.postMessage('messagePort', [ mc.port2 ]); + w.onmessage = function(e) { + is(e.data, 'ok', "Worker ready!"); + + w.onmessage = function(e) { + if (!resolve) { + ok(false, "Unexpected message!"); + return; + } + + let tmp = resolve; + resolve = null; + tmp({ data: e.data, ports: e.ports }); + } + + runTests({ + clonableObjectsEveryWhere: true, + clonableObjectsSameProcess: false, + transferableObjects: true, + send: function(what, ports) { + return new Promise(function(r, rr) { + resolve = r; + try { + mc.port1.postMessage(what, ports); + } catch(e) { + resolve = null; + rr(); + } + }); + }, + + finished: function() { + onmessage = null; + next(); + } + }); + } +} + +var tests = [ + setup_tests, + + create_fileList, + create_directory, + create_wasmModule, + + test_windowToWindow, + test_windowToIframe, + test_windowToCrossOriginIframe, + + test_workers, + + test_broadcastChannel, + test_broadcastChannel_inWorkers, + + test_messagePort, + test_messagePort_inWorkers, +]; + +function next() { + if (!tests.length) { + SimpleTest.finish(); + return; + } + + var test = tests.shift(); + test(); +} + +SimpleTest.waitForExplicitFinish(); +next(); +</script> +</body> +</html> |