diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/presentation/tests/mochitest/PresentationSessionChromeScript.js | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/presentation/tests/mochitest/PresentationSessionChromeScript.js')
-rw-r--r-- | dom/presentation/tests/mochitest/PresentationSessionChromeScript.js | 553 |
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"); |