summaryrefslogtreecommitdiffstats
path: root/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/presentation/tests/mochitest/PresentationSessionChromeScript.js')
-rw-r--r--dom/presentation/tests/mochitest/PresentationSessionChromeScript.js553
1 files changed, 553 insertions, 0 deletions
diff --git a/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js b/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
new file mode 100644
index 0000000000..5e5041a870
--- /dev/null
+++ b/dom/presentation/tests/mochitest/PresentationSessionChromeScript.js
@@ -0,0 +1,553 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/* eslint-env mozilla/frame-script */
+
+const Cm = Components.manager;
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
+
+const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(
+ Ci.nsIUUIDGenerator
+);
+
+function registerMockedFactory(contractId, mockedClassId, mockedFactory) {
+ var originalClassId, originalFactory;
+
+ var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
+ if (!registrar.isCIDRegistered(mockedClassId)) {
+ try {
+ originalClassId = registrar.contractIDToCID(contractId);
+ originalFactory = Cm.getClassObject(Cc[contractId], Ci.nsIFactory);
+ } catch (ex) {
+ originalClassId = "";
+ originalFactory = null;
+ }
+ registrar.registerFactory(mockedClassId, "", contractId, mockedFactory);
+ }
+
+ return {
+ contractId,
+ mockedClassId,
+ mockedFactory,
+ originalClassId,
+ originalFactory,
+ };
+}
+
+function registerOriginalFactory(
+ contractId,
+ mockedClassId,
+ mockedFactory,
+ originalClassId,
+ originalFactory
+) {
+ if (originalFactory) {
+ var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
+ registrar.unregisterFactory(mockedClassId, mockedFactory);
+ // Passing null for the factory remaps the original CID to the
+ // contract ID.
+ registrar.registerFactory(originalClassId, "", contractId, null);
+ }
+}
+
+var sessionId = "test-session-id-" + uuidGenerator.generateUUID().toString();
+
+const address = Cc["@mozilla.org/supports-cstring;1"].createInstance(
+ Ci.nsISupportsCString
+);
+address.data = "127.0.0.1";
+const addresses = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
+addresses.appendElement(address);
+
+const mockedChannelDescription = {
+ QueryInterface: ChromeUtils.generateQI(["nsIPresentationChannelDescription"]),
+ get type() {
+ if (
+ Services.prefs.getBoolPref(
+ "dom.presentation.session_transport.data_channel.enable"
+ )
+ ) {
+ return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
+ }
+ return Ci.nsIPresentationChannelDescription.TYPE_TCP;
+ },
+ tcpAddress: addresses,
+ tcpPort: 1234,
+};
+
+const mockedServerSocket = {
+ QueryInterface: ChromeUtils.generateQI(["nsIServerSocket", "nsIFactory"]),
+ createInstance(aOuter, aIID) {
+ if (aOuter) {
+ throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
+ }
+ return this.QueryInterface(aIID);
+ },
+ get port() {
+ return this._port;
+ },
+ set listener(listener) {
+ this._listener = listener;
+ },
+ init(port, loopbackOnly, backLog) {
+ if (port != -1) {
+ this._port = port;
+ } else {
+ this._port = 5678;
+ }
+ },
+ asyncListen(listener) {
+ this._listener = listener;
+ },
+ close() {
+ this._listener.onStopListening(this, Cr.NS_BINDING_ABORTED);
+ },
+ simulateOnSocketAccepted(serverSocket, socketTransport) {
+ this._listener.onSocketAccepted(serverSocket, socketTransport);
+ },
+};
+
+const mockedSocketTransport = Cc[
+ "@mozilla.org/presentation/mockedsockettransport;1"
+].createInstance(Ci.nsISocketTransport);
+
+const mockedControlChannel = {
+ QueryInterface: ChromeUtils.generateQI(["nsIPresentationControlChannel"]),
+ set listener(listener) {
+ this._listener = listener;
+ },
+ get listener() {
+ return this._listener;
+ },
+ sendOffer(offer) {
+ sendAsyncMessage("offer-sent", this._isValidSDP(offer));
+ },
+ sendAnswer(answer) {
+ sendAsyncMessage("answer-sent", this._isValidSDP(answer));
+
+ if (answer.type == Ci.nsIPresentationChannelDescription.TYPE_TCP) {
+ this._listener
+ .QueryInterface(Ci.nsIPresentationSessionTransportCallback)
+ .notifyTransportReady();
+ }
+ },
+ _isValidSDP(aSDP) {
+ var isValid = false;
+ if (aSDP.type == Ci.nsIPresentationChannelDescription.TYPE_TCP) {
+ try {
+ var sdpAddresses = aSDP.tcpAddress;
+ if (sdpAddresses.length > 0) {
+ for (var i = 0; i < sdpAddresses.length; i++) {
+ // Ensure CString addresses are used. Otherwise, an error will be thrown.
+ sdpAddresses.queryElementAt(i, Ci.nsISupportsCString);
+ }
+
+ isValid = true;
+ }
+ } catch (e) {
+ isValid = false;
+ }
+ } else if (
+ aSDP.type == Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL
+ ) {
+ isValid = aSDP.dataChannelSDP == "test-sdp";
+ }
+ return isValid;
+ },
+ launch(presentationId, url) {
+ sessionId = presentationId;
+ },
+ terminate(presentationId) {
+ sendAsyncMessage("sender-terminate", presentationId);
+ },
+ reconnect(presentationId, url) {
+ sendAsyncMessage("start-reconnect", url);
+ },
+ notifyReconnected() {
+ this._listener
+ .QueryInterface(Ci.nsIPresentationControlChannelListener)
+ .notifyReconnected();
+ },
+ disconnect(reason) {
+ sendAsyncMessage("control-channel-closed", reason);
+ this._listener
+ .QueryInterface(Ci.nsIPresentationControlChannelListener)
+ .notifyDisconnected(reason);
+ },
+ simulateReceiverReady() {
+ this._listener
+ .QueryInterface(Ci.nsIPresentationControlChannelListener)
+ .notifyReceiverReady();
+ },
+ simulateOnOffer() {
+ sendAsyncMessage("offer-received");
+ this._listener
+ .QueryInterface(Ci.nsIPresentationControlChannelListener)
+ .onOffer(mockedChannelDescription);
+ },
+ simulateOnAnswer() {
+ sendAsyncMessage("answer-received");
+ this._listener
+ .QueryInterface(Ci.nsIPresentationControlChannelListener)
+ .onAnswer(mockedChannelDescription);
+ },
+ simulateNotifyConnected() {
+ sendAsyncMessage("control-channel-opened");
+ this._listener
+ .QueryInterface(Ci.nsIPresentationControlChannelListener)
+ .notifyConnected();
+ },
+};
+
+const mockedDevice = {
+ QueryInterface: ChromeUtils.generateQI(["nsIPresentationDevice"]),
+ id: "id",
+ name: "name",
+ type: "type",
+ establishControlChannel(url, presentationId) {
+ sendAsyncMessage("control-channel-established");
+ return mockedControlChannel;
+ },
+ disconnect() {},
+ isRequestedUrlSupported(requestedUrl) {
+ return true;
+ },
+};
+
+const mockedDevicePrompt = {
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIPresentationDevicePrompt",
+ "nsIFactory",
+ ]),
+ createInstance(aOuter, aIID) {
+ if (aOuter) {
+ throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
+ }
+ return this.QueryInterface(aIID);
+ },
+ set request(request) {
+ this._request = request;
+ },
+ get request() {
+ return this._request;
+ },
+ promptDeviceSelection(request) {
+ this._request = request;
+ sendAsyncMessage("device-prompt");
+ },
+ simulateSelect() {
+ this._request.select(mockedDevice);
+ },
+ simulateCancel(result) {
+ this._request.cancel(result);
+ },
+};
+
+const mockedSessionTransport = {
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIPresentationSessionTransport",
+ "nsIPresentationSessionTransportBuilder",
+ "nsIPresentationTCPSessionTransportBuilder",
+ "nsIPresentationDataChannelSessionTransportBuilder",
+ "nsIPresentationControlChannelListener",
+ "nsIFactory",
+ ]),
+ createInstance(aOuter, aIID) {
+ if (aOuter) {
+ throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
+ }
+ return this.QueryInterface(aIID);
+ },
+ set callback(callback) {
+ this._callback = callback;
+ },
+ get callback() {
+ return this._callback;
+ },
+ get selfAddress() {
+ return this._selfAddress;
+ },
+ buildTCPSenderTransport(transport, listener) {
+ this._listener = listener;
+ this._role = Ci.nsIPresentationService.ROLE_CONTROLLER;
+ this._listener.onSessionTransport(this);
+ this._listener = null;
+ sendAsyncMessage("data-transport-initialized");
+
+ setTimeout(() => {
+ this.simulateTransportReady();
+ }, 0);
+ },
+ buildTCPReceiverTransport(description, listener) {
+ this._listener = listener;
+ this._role = Ci.nsIPresentationService.ROLE_RECEIVER;
+
+ var tcpAddresses = description.QueryInterface(
+ Ci.nsIPresentationChannelDescription
+ ).tcpAddress;
+ this._selfAddress = {
+ QueryInterface: ChromeUtils.generateQI(["nsINetAddr"]),
+ address:
+ tcpAddresses.length > 0
+ ? tcpAddresses.queryElementAt(0, Ci.nsISupportsCString).data
+ : "",
+ port: description.QueryInterface(Ci.nsIPresentationChannelDescription)
+ .tcpPort,
+ };
+
+ setTimeout(() => {
+ this._listener.onSessionTransport(this);
+ this._listener = null;
+ }, 0);
+ },
+ // in-process case
+ buildDataChannelTransport(role, window, listener) {
+ this._listener = listener;
+ this._role = role;
+
+ var hasNavigator = window ? typeof window.navigator != "undefined" : false;
+ sendAsyncMessage("check-navigator", hasNavigator);
+
+ setTimeout(() => {
+ this._listener.onSessionTransport(this);
+ this._listener = null;
+ this.simulateTransportReady();
+ }, 0);
+ },
+ enableDataNotification() {
+ sendAsyncMessage("data-transport-notification-enabled");
+ },
+ send(data) {
+ sendAsyncMessage("message-sent", data);
+ },
+ close(reason) {
+ // Don't send a message after tearDown, to avoid a leak.
+ if (this._callback) {
+ sendAsyncMessage("data-transport-closed", reason);
+ this._callback
+ .QueryInterface(Ci.nsIPresentationSessionTransportCallback)
+ .notifyTransportClosed(reason);
+ }
+ },
+ simulateTransportReady() {
+ this._callback
+ .QueryInterface(Ci.nsIPresentationSessionTransportCallback)
+ .notifyTransportReady();
+ },
+ simulateIncomingMessage(message) {
+ this._callback
+ .QueryInterface(Ci.nsIPresentationSessionTransportCallback)
+ .notifyData(message, false);
+ },
+ onOffer(aOffer) {},
+ onAnswer(aAnswer) {},
+};
+
+const mockedNetworkInfo = {
+ QueryInterface: ChromeUtils.generateQI(["nsINetworkInfo"]),
+ getAddresses(ips, prefixLengths) {
+ ips.value = ["127.0.0.1"];
+ prefixLengths.value = [0];
+ return 1;
+ },
+};
+
+const mockedNetworkManager = {
+ QueryInterface: ChromeUtils.generateQI(["nsINetworkManager", "nsIFactory"]),
+ createInstance(aOuter, aIID) {
+ if (aOuter) {
+ throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
+ }
+ return this.QueryInterface(aIID);
+ },
+ get activeNetworkInfo() {
+ return mockedNetworkInfo;
+ },
+};
+
+var requestPromise = null;
+
+const mockedRequestUIGlue = {
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIPresentationRequestUIGlue",
+ "nsIFactory",
+ ]),
+ createInstance(aOuter, aIID) {
+ if (aOuter) {
+ throw Components.Exception("", Cr.NS_ERROR_NO_AGGREGATION);
+ }
+ return this.QueryInterface(aIID);
+ },
+ sendRequest(aUrl, aSessionId) {
+ sendAsyncMessage("receiver-launching", aSessionId);
+ return requestPromise;
+ },
+};
+
+// Register mocked factories.
+const originalFactoryData = [];
+originalFactoryData.push(
+ registerMockedFactory(
+ "@mozilla.org/presentation-device/prompt;1",
+ uuidGenerator.generateUUID(),
+ mockedDevicePrompt
+ )
+);
+originalFactoryData.push(
+ registerMockedFactory(
+ "@mozilla.org/network/server-socket;1",
+ uuidGenerator.generateUUID(),
+ mockedServerSocket
+ )
+);
+originalFactoryData.push(
+ registerMockedFactory(
+ "@mozilla.org/presentation/presentationtcpsessiontransport;1",
+ uuidGenerator.generateUUID(),
+ mockedSessionTransport
+ )
+);
+originalFactoryData.push(
+ registerMockedFactory(
+ "@mozilla.org/presentation/datachanneltransportbuilder;1",
+ uuidGenerator.generateUUID(),
+ mockedSessionTransport
+ )
+);
+originalFactoryData.push(
+ registerMockedFactory(
+ "@mozilla.org/network/manager;1",
+ uuidGenerator.generateUUID(),
+ mockedNetworkManager
+ )
+);
+originalFactoryData.push(
+ registerMockedFactory(
+ "@mozilla.org/presentation/requestuiglue;1",
+ uuidGenerator.generateUUID(),
+ mockedRequestUIGlue
+ )
+);
+
+function tearDown() {
+ requestPromise = null;
+ mockedServerSocket.listener = null;
+ mockedControlChannel.listener = null;
+ mockedDevice.listener = null;
+ mockedDevicePrompt.request = null;
+ mockedSessionTransport.callback = null;
+
+ var deviceManager = Cc[
+ "@mozilla.org/presentation-device/manager;1"
+ ].getService(Ci.nsIPresentationDeviceManager);
+ deviceManager
+ .QueryInterface(Ci.nsIPresentationDeviceListener)
+ .removeDevice(mockedDevice);
+
+ // Register original factories.
+ for (var data of originalFactoryData) {
+ registerOriginalFactory(
+ data.contractId,
+ data.mockedClassId,
+ data.mockedFactory,
+ data.originalClassId,
+ data.originalFactory
+ );
+ }
+
+ sendAsyncMessage("teardown-complete");
+}
+
+addMessageListener("trigger-device-add", function() {
+ var deviceManager = Cc[
+ "@mozilla.org/presentation-device/manager;1"
+ ].getService(Ci.nsIPresentationDeviceManager);
+ deviceManager
+ .QueryInterface(Ci.nsIPresentationDeviceListener)
+ .addDevice(mockedDevice);
+});
+
+addMessageListener("trigger-device-prompt-select", function() {
+ mockedDevicePrompt.simulateSelect();
+});
+
+addMessageListener("trigger-device-prompt-cancel", function(result) {
+ mockedDevicePrompt.simulateCancel(result);
+});
+
+addMessageListener("trigger-incoming-session-request", function(url) {
+ var deviceManager = Cc[
+ "@mozilla.org/presentation-device/manager;1"
+ ].getService(Ci.nsIPresentationDeviceManager);
+ deviceManager
+ .QueryInterface(Ci.nsIPresentationDeviceListener)
+ .onSessionRequest(mockedDevice, url, sessionId, mockedControlChannel);
+});
+
+addMessageListener("trigger-incoming-terminate-request", function() {
+ var deviceManager = Cc[
+ "@mozilla.org/presentation-device/manager;1"
+ ].getService(Ci.nsIPresentationDeviceManager);
+ deviceManager
+ .QueryInterface(Ci.nsIPresentationDeviceListener)
+ .onTerminateRequest(mockedDevice, sessionId, mockedControlChannel, true);
+});
+
+addMessageListener("trigger-reconnected-acked", function(url) {
+ mockedControlChannel.notifyReconnected();
+});
+
+addMessageListener("trigger-incoming-offer", function() {
+ mockedControlChannel.simulateOnOffer();
+});
+
+addMessageListener("trigger-incoming-answer", function() {
+ mockedControlChannel.simulateOnAnswer();
+});
+
+addMessageListener("trigger-incoming-transport", function() {
+ mockedServerSocket.simulateOnSocketAccepted(
+ mockedServerSocket,
+ mockedSocketTransport
+ );
+});
+
+addMessageListener("trigger-control-channel-open", function(reason) {
+ mockedControlChannel.simulateNotifyConnected();
+});
+
+addMessageListener("trigger-control-channel-close", function(reason) {
+ mockedControlChannel.disconnect(reason);
+});
+
+addMessageListener("trigger-data-transport-close", function(reason) {
+ mockedSessionTransport.close(reason);
+});
+
+addMessageListener("trigger-incoming-message", function(message) {
+ mockedSessionTransport.simulateIncomingMessage(message);
+});
+
+addMessageListener("teardown", function() {
+ tearDown();
+});
+
+var controlChannelListener;
+addMessageListener("save-control-channel-listener", function() {
+ controlChannelListener = mockedControlChannel.listener;
+});
+
+addMessageListener("restore-control-channel-listener", function(message) {
+ mockedControlChannel.listener = controlChannelListener;
+ controlChannelListener = null;
+});
+
+Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
+ Services.obs.removeObserver(observer, aTopic);
+
+ requestPromise = aSubject;
+}, "setup-request-promise");