diff options
Diffstat (limited to 'dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js')
-rw-r--r-- | dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js new file mode 100644 index 000000000..8a7787b40 --- /dev/null +++ b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js @@ -0,0 +1,370 @@ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, +* You can obtain one at http://mozilla.org/MPL/2.0/. */ + +'use strict'; + +function debug(str) { + // info(str); +} + +var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript1UA.js')); +var receiverUrl = SimpleTest.getTestFileURL('file_presentation_1ua_receiver.html'); +var request; +var connection; +var receiverIframe; +var presentationId; +const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0]; +const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length); +const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER); +TYPED_DATA_ARRAY.set(DATA_ARRAY); + +function postMessageToIframe(aType) { + receiverIframe.src = receiverUrl + "#" + + encodeURIComponent(JSON.stringify({ type: aType })); +} + +function setup() { + + gScript.addMessageListener('device-prompt', function devicePromptHandler() { + debug('Got message: device-prompt'); + gScript.removeMessageListener('device-prompt', devicePromptHandler); + gScript.sendAsyncMessage('trigger-device-prompt-select'); + }); + + gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() { + gScript.removeMessageListener('control-channel-established', + controlChannelEstablishedHandler); + gScript.sendAsyncMessage("trigger-control-channel-open"); + }); + + gScript.addMessageListener('sender-launch', function senderLaunchHandler(url) { + debug('Got message: sender-launch'); + gScript.removeMessageListener('sender-launch', senderLaunchHandler); + is(url, receiverUrl, 'Receiver: should receive the same url'); + receiverIframe = document.createElement('iframe'); + receiverIframe.setAttribute('src', receiverUrl); + receiverIframe.setAttribute("mozbrowser", "true"); + receiverIframe.setAttribute("mozpresentation", receiverUrl); + var oop = location.pathname.indexOf('_inproc') == -1; + receiverIframe.setAttribute("remote", oop); + + // This event is triggered when the iframe calls "alert". + receiverIframe.addEventListener("mozbrowsershowmodalprompt", function receiverListener(evt) { + var message = evt.detail.message; + debug('Got iframe message: ' + message); + if (/^OK /.exec(message)) { + ok(true, message.replace(/^OK /, "")); + } else if (/^KO /.exec(message)) { + ok(false, message.replace(/^KO /, "")); + } else if (/^INFO /.exec(message)) { + info(message.replace(/^INFO /, "")); + } else if (/^COMMAND /.exec(message)) { + var command = JSON.parse(message.replace(/^COMMAND /, "")); + gScript.sendAsyncMessage(command.name, command.data); + } else if (/^DONE$/.exec(message)) { + receiverIframe.removeEventListener("mozbrowsershowmodalprompt", + receiverListener); + } + }, false); + + var promise = new Promise(function(aResolve, aReject) { + document.body.appendChild(receiverIframe); + aResolve(receiverIframe); + }); + + var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"] + .getService(SpecialPowers.Ci.nsIObserverService); + obs.notifyObservers(promise, 'setup-request-promise', null); + }); + + gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() { + debug('Got message: promise-setup-ready'); + gScript.removeMessageListener('promise-setup-ready', promiseSetupReadyHandler); + gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl); + }); + + return Promise.resolve(); +} + +function testCreateRequest() { + return new Promise(function(aResolve, aReject) { + info('Sender: --- testCreateRequest ---'); + request = new PresentationRequest("file_presentation_1ua_receiver.html"); + request.getAvailability().then((aAvailability) => { + is(aAvailability.value, false, "Sender: should have no available device after setup"); + aAvailability.onchange = function() { + aAvailability.onchange = null; + ok(aAvailability.value, "Sender: Device should be available."); + aResolve(); + } + + gScript.sendAsyncMessage('trigger-device-add'); + }).catch((aError) => { + ok(false, "Sender: Error occurred when getting availability: " + aError); + teardown(); + aReject(); + }); + }); +} + +function testStartConnection() { + return new Promise(function(aResolve, aReject) { + request.start().then((aConnection) => { + connection = aConnection; + ok(connection, "Sender: Connection should be available."); + ok(connection.id, "Sender: Connection ID should be set."); + is(connection.state, "connecting", "The initial state should be connecting."); + is(connection.url, receiverUrl, "request URL should be expanded to absolute URL"); + connection.onconnect = function() { + connection.onconnect = null; + is(connection.state, "connected", "Connection should be connected."); + presentationId = connection.id; + aResolve(); + }; + }).catch((aError) => { + ok(false, "Sender: Error occurred when establishing a connection: " + aError); + teardown(); + aReject(); + }); + + let request2 = new PresentationRequest("/"); + request2.start().then(() => { + ok(false, "Sender: session start should fail while there is an unsettled promise."); + }).catch((aError) => { + is(aError.name, "OperationError", "Expect to get OperationError."); + }); + }); +} + +function testSendMessage() { + return new Promise(function(aResolve, aReject) { + info('Sender: --- testSendMessage ---'); + gScript.addMessageListener('trigger-message-from-sender', function triggerMessageFromSenderHandler() { + debug('Got message: trigger-message-from-sender'); + gScript.removeMessageListener('trigger-message-from-sender', triggerMessageFromSenderHandler); + info('Send message to receiver'); + connection.send('msg-sender-to-receiver'); + }); + + gScript.addMessageListener('message-from-sender-received', function messageFromSenderReceivedHandler() { + debug('Got message: message-from-sender-received'); + gScript.removeMessageListener('message-from-sender-received', messageFromSenderReceivedHandler); + aResolve(); + }); + }); +} + +function testIncomingMessage() { + return new Promise(function(aResolve, aReject) { + info('Sender: --- testIncomingMessage ---'); + connection.addEventListener('message', function messageHandler(evt) { + connection.removeEventListener('message', messageHandler); + let msg = evt.data; + is(msg, "msg-receiver-to-sender", "Sender: Sender should receive message from Receiver"); + postMessageToIframe('message-from-receiver-received'); + aResolve(); + }); + postMessageToIframe('trigger-message-from-receiver'); + }); +} + +function testSendBlobMessage() { + return new Promise(function(aResolve, aReject) { + info('Sender: --- testSendBlobMessage ---'); + connection.addEventListener('message', function messageHandler(evt) { + connection.removeEventListener('message', messageHandler); + let msg = evt.data; + is(msg, "testIncomingBlobMessage", "Sender: Sender should receive message from Receiver"); + let blob = new Blob(["Hello World"], {type : 'text/plain'}); + connection.send(blob); + aResolve(); + }); + }); +} + +function testSendArrayBuffer() { + return new Promise(function(aResolve, aReject) { + info('Sender: --- testSendArrayBuffer ---'); + connection.addEventListener('message', function messageHandler(evt) { + connection.removeEventListener('message', messageHandler); + let msg = evt.data; + is(msg, "testIncomingArrayBuffer", "Sender: Sender should receive message from Receiver"); + connection.send(DATA_ARRAY_BUFFER); + aResolve(); + }); + }); +} + +function testSendArrayBufferView() { + return new Promise(function(aResolve, aReject) { + info('Sender: --- testSendArrayBufferView ---'); + connection.addEventListener('message', function messageHandler(evt) { + connection.removeEventListener('message', messageHandler); + let msg = evt.data; + is(msg, "testIncomingArrayBufferView", "Sender: Sender should receive message from Receiver"); + connection.send(TYPED_DATA_ARRAY); + aResolve(); + }); + }); +} + +function testCloseConnection() { + info('Sender: --- testCloseConnection ---'); + // Test terminate immediate after close. + function controlChannelEstablishedHandler() + { + gScript.removeMessageListener('control-channel-established', + controlChannelEstablishedHandler); + ok(false, "terminate after close should do nothing"); + } + gScript.addMessageListener('ready-to-close', function onReadyToClose() { + gScript.removeMessageListener('ready-to-close', onReadyToClose); + connection.close(); + + gScript.addMessageListener('control-channel-established', controlChannelEstablishedHandler); + connection.terminate(); + }); + + return Promise.all([ + new Promise(function(aResolve, aReject) { + connection.onclose = function() { + connection.onclose = null; + is(connection.state, 'closed', 'Sender: Connection should be closed.'); + gScript.removeMessageListener('control-channel-established', + controlChannelEstablishedHandler); + aResolve(); + }; + }), + new Promise(function(aResolve, aReject) { + let timeout = setTimeout(function() { + gScript.removeMessageListener('device-disconnected', + deviceDisconnectedHandler); + ok(true, "terminate after close should not trigger device.disconnect"); + aResolve(); + }, 3000); + + function deviceDisconnectedHandler() { + gScript.removeMessageListener('device-disconnected', + deviceDisconnectedHandler); + ok(false, "terminate after close should not trigger device.disconnect"); + clearTimeout(timeout); + aResolve(); + } + + gScript.addMessageListener('device-disconnected', deviceDisconnectedHandler); + }), + new Promise(function(aResolve, aReject) { + gScript.addMessageListener('receiver-closed', function onReceiverClosed() { + gScript.removeMessageListener('receiver-closed', onReceiverClosed); + gScript.removeMessageListener('control-channel-established', + controlChannelEstablishedHandler); + aResolve(); + }); + }), + ]); +} + +function testTerminateAfterClose() { + info('Sender: --- testTerminateAfterClose ---'); + return Promise.race([ + new Promise(function(aResolve, aReject) { + connection.onterminate = function() { + connection.onterminate = null; + ok(false, 'terminate after close should do nothing'); + aResolve(); + }; + connection.terminate(); + }), + new Promise(function(aResolve, aReject) { + setTimeout(function() { + is(connection.state, 'closed', 'Sender: Connection should be closed.'); + aResolve(); + }, 3000); + }), + ]); +} + +function testReconnect() { + return new Promise(function(aResolve, aReject) { + info('Sender: --- testReconnect ---'); + gScript.addMessageListener('control-channel-established', function controlChannelEstablished() { + gScript.removeMessageListener('control-channel-established', controlChannelEstablished); + gScript.sendAsyncMessage("trigger-control-channel-open"); + }); + + gScript.addMessageListener('start-reconnect', function startReconnectHandler(url) { + debug('Got message: start-reconnect'); + gScript.removeMessageListener('start-reconnect', startReconnectHandler); + is(url, receiverUrl, "URLs should be the same.") + gScript.sendAsyncMessage('trigger-reconnected-acked', url); + }); + + gScript.addMessageListener('ready-to-reconnect', function onReadyToReconnect() { + gScript.removeMessageListener('ready-to-reconnect', onReadyToReconnect); + request.reconnect(presentationId).then((aConnection) => { + connection = aConnection; + ok(connection, "Sender: Connection should be available."); + is(connection.id, presentationId, "The presentationId should be the same."); + is(connection.state, "connecting", "The initial state should be connecting."); + connection.onconnect = function() { + connection.onconnect = null; + is(connection.state, "connected", "Connection should be connected."); + aResolve(); + }; + }).catch((aError) => { + ok(false, "Sender: Error occurred when establishing a connection: " + aError); + teardown(); + aReject(); + }); + }); + + postMessageToIframe('prepare-for-reconnect'); + }); +} + +function teardown() { + gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() { + debug('Got message: teardown-complete'); + gScript.removeMessageListener('teardown-complete', teardownCompleteHandler); + gScript.destroy(); + SimpleTest.finish(); + }); + + gScript.sendAsyncMessage('teardown'); +} + +function runTests() { + setup().then(testCreateRequest) + .then(testStartConnection) + .then(testSendMessage) + .then(testIncomingMessage) + .then(testSendBlobMessage) + .then(testCloseConnection) + .then(testReconnect) + .then(testSendArrayBuffer) + .then(testSendArrayBufferView) + .then(testCloseConnection) + .then(testTerminateAfterClose) + .then(teardown); +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout('Test for guarantee not firing async event'); +SpecialPowers.pushPermissions([ + {type: 'presentation-device-manage', allow: false, context: document}, + {type: "browser", allow: true, context: document}, +], () => { + SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true], + /* Mocked TCP session transport builder in the test */ + ["dom.presentation.session_transport.data_channel.enable", true], + ["dom.presentation.controller.enabled", true], + ["dom.presentation.receiver.enabled", true], + ["dom.presentation.test.enabled", true], + ["dom.presentation.test.stage", 0], + ["dom.mozBrowserFramesEnabled", true], + ["network.disable.ipc.security", true], + ["media.navigator.permission.disabled", true]]}, + runTests); +}); |