diff options
Diffstat (limited to 'dom/presentation/tests/mochitest/PresentationSessionFrameScript.js')
-rw-r--r-- | dom/presentation/tests/mochitest/PresentationSessionFrameScript.js | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/dom/presentation/tests/mochitest/PresentationSessionFrameScript.js b/dom/presentation/tests/mochitest/PresentationSessionFrameScript.js new file mode 100644 index 0000000000..5385e5d9b9 --- /dev/null +++ b/dom/presentation/tests/mochitest/PresentationSessionFrameScript.js @@ -0,0 +1,291 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* eslint-env mozilla/frame-script */ + +function loadPrivilegedScriptTest() { + /** + * The script is loaded as + * (a) a privileged script in content process for dc_sender.html + * (b) a frame script in the remote iframe process for dc_receiver_oop.html + * |type port == "undefined"| indicates the script is load by + * |loadPrivilegedScript| which is the first case. + */ + function sendMessage(type, data) { + if (typeof port == "undefined") { + sendAsyncMessage(type, { data }); + } else { + port.postMessage({ type, data }); + } + } + + if (typeof port != "undefined") { + /** + * When the script is loaded by |loadPrivilegedScript|, these APIs + * are exposed to this script. + */ + port.onmessage = e => { + var type = e.data.type; + if (!handlers.hasOwnProperty(type)) { + return; + } + var args = [e]; + handlers[type].forEach(handler => handler.apply(null, args)); + }; + var handlers = {}; + /* eslint-disable-next-line no-global-assign */ + addMessageListener = function(message, handler) { + if (handlers.hasOwnProperty(message)) { + handlers[message].push(handler); + } else { + handlers[message] = [handler]; + } + }; + /* eslint-disable-next-line no-global-assign */ + removeMessageListener = function(message, handler) { + if (!handler || !handlers.hasOwnProperty(message)) { + return; + } + var index = handlers[message].indexOf(handler); + if (index != -1) { + handlers[message].splice(index, 1); + } + }; + } + + const Cm = Components.manager; + + const mockedChannelDescription = { + /* eslint-disable-next-line mozilla/use-chromeutils-generateqi */ + QueryInterface(iid) { + const interfaces = [Ci.nsIPresentationChannelDescription]; + + if (!interfaces.some(v => iid.equals(v))) { + throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); + } + return this; + }, + get type() { + /* global Services */ + if ( + Services.prefs.getBoolPref( + "dom.presentation.session_transport.data_channel.enable" + ) + ) { + return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL; + } + return Ci.nsIPresentationChannelDescription.TYPE_TCP; + }, + get dataChannelSDP() { + return "test-sdp"; + }, + }; + + function setTimeout(callback, delay) { + let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + timer.initWithCallback( + { notify: callback }, + delay, + Ci.nsITimer.TYPE_ONE_SHOT + ); + return timer; + } + + const mockedSessionTransport = { + /* eslint-disable-next-line mozilla/use-chromeutils-generateqi */ + QueryInterface(iid) { + const interfaces = [ + Ci.nsIPresentationSessionTransport, + Ci.nsIPresentationDataChannelSessionTransportBuilder, + Ci.nsIFactory, + ]; + + if (!interfaces.some(v => iid.equals(v))) { + throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); + } + return this; + }, + 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; + }, + /* OOP case */ + buildDataChannelTransport(role, window, listener) { + dump("PresentationSessionFrameScript: build data channel transport\n"); + this._listener = listener; + this._role = role; + + var hasNavigator = window + ? typeof window.navigator != "undefined" + : false; + sendMessage("check-navigator", hasNavigator); + + if (this._role == Ci.nsIPresentationService.ROLE_CONTROLLER) { + this._listener.sendOffer(mockedChannelDescription); + } + }, + + enableDataNotification() { + sendMessage("data-transport-notification-enabled"); + }, + send(data) { + sendMessage("message-sent", data); + }, + close(reason) { + sendMessage("data-transport-closed", reason); + this._callback + .QueryInterface(Ci.nsIPresentationSessionTransportCallback) + .notifyTransportClosed(reason); + this._callback = null; + }, + simulateTransportReady() { + this._callback + .QueryInterface(Ci.nsIPresentationSessionTransportCallback) + .notifyTransportReady(); + }, + simulateIncomingMessage(message) { + this._callback + .QueryInterface(Ci.nsIPresentationSessionTransportCallback) + .notifyData(message, false); + }, + onOffer(aOffer) { + this._listener.sendAnswer(mockedChannelDescription); + this._onSessionTransport(); + }, + onAnswer(aAnswer) { + this._onSessionTransport(); + }, + _onSessionTransport() { + setTimeout(() => { + this._listener.onSessionTransport(this); + this.simulateTransportReady(); + this._listener = null; + }, 0); + }, + }; + + function tearDown() { + mockedSessionTransport.callback = null; + + /* Register original factories. */ + for (var data of originalFactoryData) { + registerOriginalFactory( + data.contractId, + data.mockedClassId, + data.mockedFactory, + data.originalClassId, + data.originalFactory + ); + } + sendMessage("teardown-complete"); + } + + 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); + registrar.registerFactory(originalClassId, "", contractId, null); + } + } + + /* Register mocked factories. */ + const originalFactoryData = []; + const uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService( + Ci.nsIUUIDGenerator + ); + originalFactoryData.push( + registerMockedFactory( + "@mozilla.org/presentation/datachanneltransportbuilder;1", + uuidGenerator.generateUUID(), + mockedSessionTransport + ) + ); + + addMessageListener("trigger-incoming-message", function(event) { + mockedSessionTransport.simulateIncomingMessage(event.data.data); + }); + addMessageListener("teardown", () => tearDown()); +} + +// Exposed to the caller of |loadPrivilegedScript| +var contentScript = { + handlers: {}, + addMessageListener(message, handler) { + if (this.handlers.hasOwnProperty(message)) { + this.handlers[message].push(handler); + } else { + this.handlers[message] = [handler]; + } + }, + removeMessageListener(message, handler) { + if (!handler || !this.handlers.hasOwnProperty(message)) { + return; + } + var index = this.handlers[message].indexOf(handler); + if (index != -1) { + this.handlers[message].splice(index, 1); + } + }, + sendAsyncMessage(message, data) { + port.postMessage({ type: message, data }); + }, +}; + +if (!SpecialPowers.isMainProcess()) { + var port; + try { + port = SpecialPowers.loadPrivilegedScript( + loadPrivilegedScriptTest.toString() + ); + } catch (e) { + ok(false, "loadPrivilegedScript should not throw" + e); + } + + port.onmessage = e => { + var type = e.data.type; + if (!contentScript.handlers.hasOwnProperty(type)) { + return; + } + var args = [e.data.data]; + contentScript.handlers[type].forEach(handler => handler.apply(null, args)); + }; +} |