diff options
Diffstat (limited to 'devtools/shared/security/tests/xpcshell')
5 files changed, 262 insertions, 0 deletions
diff --git a/devtools/shared/security/tests/xpcshell/.eslintrc.js b/devtools/shared/security/tests/xpcshell/.eslintrc.js new file mode 100644 index 0000000000..8611c174f5 --- /dev/null +++ b/devtools/shared/security/tests/xpcshell/.eslintrc.js @@ -0,0 +1,6 @@ +"use strict"; + +module.exports = { + // Extend from the common devtools xpcshell eslintrc config. + extends: "../../../../.eslintrc.xpcshell.js", +}; diff --git a/devtools/shared/security/tests/xpcshell/head_dbg.js b/devtools/shared/security/tests/xpcshell/head_dbg.js new file mode 100644 index 0000000000..30359e6ac3 --- /dev/null +++ b/devtools/shared/security/tests/xpcshell/head_dbg.js @@ -0,0 +1,95 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* exported DevToolsClient, initTestDevToolsServer */ + +const { loader, require } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/Loader.sys.mjs" +); +const xpcInspector = require("xpcInspector"); +const { + DevToolsServer, +} = require("resource://devtools/server/devtools-server.js"); +const { + DevToolsClient, +} = require("resource://devtools/client/devtools-client.js"); +// We need to require lazily since will be crashed if we load SocketListener too early +// in xpc shell test due to SocketListener loads PSM module. +loader.lazyRequireGetter( + this, + "SocketListener", + "resource://devtools/shared/security/socket.js", + true +); + +// We do not want to log packets by default, because in some tests, +// we can be sending large amounts of data. The test harness has +// trouble dealing with logging all the data, and we end up with +// intermittent time outs (e.g. bug 775924). +// Services.prefs.setBoolPref("devtools.debugger.log", true); +// Services.prefs.setBoolPref("devtools.debugger.log.verbose", true); +// Enable remote debugging for the relevant tests. +Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true); + +// Convert an nsIScriptError 'logLevel' value into an appropriate string. +function scriptErrorLogLevel(message) { + switch (message.logLevel) { + case Ci.nsIConsoleMessage.info: + return "info"; + case Ci.nsIConsoleMessage.warn: + return "warning"; + default: + Assert.equal(message.logLevel, Ci.nsIConsoleMessage.error); + return "error"; + } +} + +// Register a console listener, so console messages don't just disappear +// into the ether. +var listener = { + observe(message) { + let string; + try { + message.QueryInterface(Ci.nsIScriptError); + dump( + message.sourceName + + ":" + + message.lineNumber + + ": " + + scriptErrorLogLevel(message) + + ": " + + message.errorMessage + + "\n" + ); + string = message.errorMessage; + } catch (ex) { + // Be a little paranoid with message, as the whole goal here is to lose + // no information. + try { + string = "" + message.message; + } catch (e) { + string = "<error converting error message to string>"; + } + } + + // Make sure we exit all nested event loops so that the test can finish. + while (xpcInspector.eventLoopNestLevel > 0) { + xpcInspector.exitNestedEventLoop(); + } + + info("head_dbg.js got console message: " + string + "\n"); + }, +}; + +Services.console.registerListener(listener); + +/** + * Initialize the testing devtools server. + */ +function initTestDevToolsServer() { + const { createRootActor } = require("xpcshell-test/testactors"); + DevToolsServer.setRootActor(createRootActor); + DevToolsServer.init(); +} diff --git a/devtools/shared/security/tests/xpcshell/test_devtools_socket_status.js b/devtools/shared/security/tests/xpcshell/test_devtools_socket_status.js new file mode 100644 index 0000000000..2e41583b05 --- /dev/null +++ b/devtools/shared/security/tests/xpcshell/test_devtools_socket_status.js @@ -0,0 +1,137 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { + useDistinctSystemPrincipalLoader, + releaseDistinctSystemPrincipalLoader, +} = ChromeUtils.importESModule( + "resource://devtools/shared/loader/DistinctSystemPrincipalLoader.sys.mjs" +); + +const { DevToolsSocketStatus } = ChromeUtils.importESModule( + "resource://devtools/shared/security/DevToolsSocketStatus.sys.mjs" +); + +add_task(async function () { + Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true); + Services.prefs.setBoolPref("devtools.debugger.prompt-connection", false); + + info("Without any server started, all states should be set to false"); + checkSocketStatus(false, false); + + info("Start a first server, expect all states to change to true"); + const server = await setupDevToolsServer({ fromBrowserToolbox: false }); + checkSocketStatus(true, true); + + info("Start another server, expect all states to remain true"); + const otherServer = await setupDevToolsServer({ fromBrowserToolbox: false }); + checkSocketStatus(true, true); + + info("Shutdown one of the servers, expect all states to remain true"); + teardownDevToolsServer(otherServer); + checkSocketStatus(true, true); + + info("Shutdown the other server, expect all states to change to false"); + teardownDevToolsServer(server); + checkSocketStatus(false, false); + + info( + "Start a 'browser toolbox' server, expect only the 'include' state to become true" + ); + const browserToolboxServer = await setupDevToolsServer({ + fromBrowserToolbox: true, + }); + checkSocketStatus(true, false); + + info( + "Shutdown the 'browser toolbox' server, expect all states to become false" + ); + teardownDevToolsServer(browserToolboxServer); + checkSocketStatus(false, false); + + Services.prefs.clearUserPref("devtools.debugger.remote-enabled"); + Services.prefs.clearUserPref("devtools.debugger.prompt-connection"); +}); + +function checkSocketStatus(expectedExcludeFalse, expectedExcludeTrue) { + const openedDefault = DevToolsSocketStatus.hasSocketOpened(); + const openedExcludeFalse = DevToolsSocketStatus.hasSocketOpened({ + excludeBrowserToolboxSockets: false, + }); + const openedExcludeTrue = DevToolsSocketStatus.hasSocketOpened({ + excludeBrowserToolboxSockets: true, + }); + + equal( + openedDefault, + openedExcludeFalse, + "DevToolsSocketStatus.hasSocketOpened should default to excludeBrowserToolboxSockets=false" + ); + equal( + openedExcludeFalse, + expectedExcludeFalse, + "DevToolsSocketStatus matches the expectation for excludeBrowserToolboxSockets=false" + ); + equal( + openedExcludeTrue, + expectedExcludeTrue, + "DevToolsSocketStatus matches the expectation for excludeBrowserToolboxSockets=true" + ); +} + +async function setupDevToolsServer({ fromBrowserToolbox }) { + info("Use the dedicated system principal loader for the DevToolsServer."); + const requester = {}; + const loader = useDistinctSystemPrincipalLoader(requester); + + const { DevToolsServer } = loader.require( + "resource://devtools/server/devtools-server.js" + ); + + DevToolsServer.init(); + DevToolsServer.registerAllActors(); + DevToolsServer.allowChromeProcess = true; + const socketOptions = { + fromBrowserToolbox, + // Pass -1 to automatically choose an available port + portOrPath: -1, + }; + + const listener = new SocketListener(DevToolsServer, socketOptions); + ok(listener, "Socket listener created"); + + // Note that useDistinctSystemPrincipalLoader will lead to reuse the same + // loader if we are creating several servers in a row. The DevToolsServer + // singleton might already have sockets opened. + const listeningSockets = DevToolsServer.listeningSockets; + await listener.open(); + equal( + DevToolsServer.listeningSockets, + listeningSockets + 1, + "A new listening socket was created" + ); + + return { DevToolsServer, listener, requester }; +} + +function teardownDevToolsServer({ DevToolsServer, listener, requester }) { + info("Close the listener socket"); + const listeningSockets = DevToolsServer.listeningSockets; + listener.close(); + equal( + DevToolsServer.listeningSockets, + listeningSockets - 1, + "A listening socket was closed" + ); + + if (DevToolsServer.listeningSockets == 0) { + info("Destroy the temporary devtools server"); + DevToolsServer.destroy(); + } + + if (requester) { + releaseDistinctSystemPrincipalLoader(requester); + } +} diff --git a/devtools/shared/security/tests/xpcshell/testactors.js b/devtools/shared/security/tests/xpcshell/testactors.js new file mode 100644 index 0000000000..0a35f05287 --- /dev/null +++ b/devtools/shared/security/tests/xpcshell/testactors.js @@ -0,0 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const { RootActor } = require("resource://devtools/server/actors/root.js"); +const { + ActorRegistry, +} = require("resource://devtools/server/actors/utils/actor-registry.js"); + +exports.createRootActor = function createRootActor(connection) { + const root = new RootActor(connection, { + globalActorFactories: ActorRegistry.globalActorFactories, + }); + root.applicationType = "xpcshell-tests"; + return root; +}; diff --git a/devtools/shared/security/tests/xpcshell/xpcshell.toml b/devtools/shared/security/tests/xpcshell/xpcshell.toml new file mode 100644 index 0000000000..f0d3c8f1d2 --- /dev/null +++ b/devtools/shared/security/tests/xpcshell/xpcshell.toml @@ -0,0 +1,8 @@ +[DEFAULT] +tags = "devtools" +head = "head_dbg.js" +skip-if = ["os == 'android'"] +firefox-appdir = "browser" +support-files = ["testactors.js"] + +["test_devtools_socket_status.js"] |