Bug 1717899 - [remote] Extend the lifetime of the Remote Agent to the Firefox session. r=webdriver-reviewers,jdescottes

Differential Revision: https://phabricator.services.mozilla.com/D144338
This commit is contained in:
Henrik Skupin 2022-04-27 05:43:23 +00:00
parent 4d5eb6f009
commit dcdabedb93
21 changed files with 80 additions and 196 deletions

View file

@ -9,7 +9,6 @@ with Files("**"):
BROWSER_CHROME_MANIFESTS += [
"test/browser/browser.ini",
"test/browser/component/browser.ini",
"test/browser/dom/browser.ini",
"test/browser/emulation/browser.ini",
"test/browser/fetch/browser.ini",

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0
@ -8,6 +11,7 @@ support-files =
chrome-remote-interface.js
head.js
[browser_agent.js]
[browser_cdp.js]
[browser_httpd.js]
[browser_main_target.js]

View file

@ -0,0 +1,14 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// To fully test the Remote Agent's capabilities an instance of the interface
// also needs to be used.
const remoteAgentInstance = Cc["@mozilla.org/remote/agent;1"].createInstance(
Ci.nsIRemoteAgent
);
add_task(async function listening() {
is(remoteAgentInstance.listening, true, "Agent is listening");
});

View file

@ -4,8 +4,6 @@
"use strict";
add_task(async function json_version() {
await RemoteAgent.listen(`http://localhost:0`);
const { userAgent } = Cc[
"@mozilla.org/network/protocol;1?name=http"
].getService(Ci.nsIHttpProtocolHandler);

View file

@ -1,12 +0,0 @@
[DEFAULT]
tags = remote
subsuite = remote
support-files =
!/remote/cdp/test/browser/chrome-remote-interface.js
!/remote/cdp/test/browser/head.js
head.js
# These tests need to start and close RemoteAgent several times.
# It should be the only tests in this suite to avoid side-effects with
# regular tests which reuse a shared RemoteAgent instance.
[browser_agent.js]

View file

@ -1,75 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const URL = "http://localhost:0";
add_agent_task(async function debuggerAddress() {
const port = getNonAtomicFreePort();
await RemoteAgent.listen(`http://localhost:${port}`);
is(
remoteAgentInstance.debuggerAddress,
`localhost:${port}`,
"debuggerAddress set"
);
});
add_agent_task(async function listening() {
is(remoteAgentInstance.listening, false, "Agent is not listening");
await RemoteAgent.listen(URL);
is(remoteAgentInstance.listening, true, "Agent is listening");
});
add_agent_task(async function remoteListeningNotification() {
let active;
const port = getNonAtomicFreePort();
function observer(subject, topic, data) {
Services.obs.removeObserver(observer, topic);
active = data;
}
Services.obs.addObserver(observer, "remote-listening");
await RemoteAgent.listen("http://localhost:" + port);
is(active, "true", "remote-listening observer notified enabled state");
Services.obs.addObserver(observer, "remote-listening");
await RemoteAgent.close();
is(active, null, "remote-listening observer notified disabled state");
});
// TODO(ato): https://bugzil.la/1590829
add_agent_task(async function listenTakesString() {
await RemoteAgent.listen("http://localhost:0");
await RemoteAgent.close();
});
// TODO(ato): https://bugzil.la/1590829
add_agent_task(async function listenNonURL() {
try {
await RemoteAgent.listen("foobar");
fail("listen() did not reject non-URL");
} catch (e) {
is(e.result, Cr.NS_ERROR_MALFORMED_URI);
}
});
add_agent_task(async function listenRestrictedToLoopbackDevice() {
try {
await RemoteAgent.listen("http://0.0.0.0:9222");
fail("listen() did not reject non-loopback device");
} catch (e) {
is(e.result, Cr.NS_ERROR_ILLEGAL_VALUE);
is(e.message, "Restricted to loopback devices");
}
});
add_agent_task(async function test_close() {
await RemoteAgent.listen(URL);
await RemoteAgent.close();
// no-op when not listening
await RemoteAgent.close();
});

View file

@ -1,42 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/* import-globals-from ../head.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/remote/cdp/test/browser/head.js",
this
);
// To fully test the Remote Agent's capabilities an instance of the interface
// also needs to be used.
const remoteAgentInstance = Cc["@mozilla.org/remote/agent;1"].createInstance(
Ci.nsIRemoteAgent
);
// set up test conditions and clean up
function add_agent_task(originalTask) {
const task = async function() {
await RemoteAgent.close();
await originalTask();
};
Object.defineProperty(task, "name", {
value: originalTask.name,
writable: false,
});
add_plain_task(task);
}
function getNonAtomicFreePort() {
const so = Cc["@mozilla.org/network/server-socket;1"].createInstance(
Ci.nsIServerSocket
);
try {
so.init(-1, true /* aLoopbackOnly */, -1 /* aBackLog */);
return so.port;
} finally {
so.close();
}
}

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0

View file

@ -1,7 +1,12 @@
[DEFAULT]
tags = remote
subsuite = remote
skip-if = fission # Bug 1600054: Make cdp Fission compatible
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0
support-files =
!/remote/cdp/test/browser/chrome-remote-interface.js
!/remote/cdp/test/browser/head.js

View file

@ -15,16 +15,6 @@ const { TabManager } = ChromeUtils.import(
"chrome://remote/content/shared/TabManager.jsm"
);
const { allowNullOrigin } = ChromeUtils.import(
"chrome://remote/content/server/WebSocketHandshake.jsm"
);
// The handshake request created by the browser mochitests contains an origin
// header, which is currently not supported. This origin is a string "null".
// Explicitly allow such an origin for the duration of the test.
allowNullOrigin(true);
registerCleanupFunction(() => allowNullOrigin(false));
const TIMEOUT_MULTIPLIER = SpecialPowers.isDebugBuild ? 4 : 1;
const TIMEOUT_EVENTS = 1000 * TIMEOUT_MULTIPLIER;
@ -52,16 +42,6 @@ setup and teardown described above.
const add_plain_task = add_task.bind(this);
// Start RemoteAgent lazily and reuse it for all the tests in the suite.
// Starting and stopping RemoteAgent for every test would trigger race conditions
// in httpd.js. See Bug 1609162.
async function startRemoteAgent() {
if (!RemoteAgent.listening) {
await RemoteAgent.listen(Services.io.newURI("http://localhost:9222"));
info("Remote agent started");
}
}
this.add_task = function(taskFn, opts = {}) {
const {
createTab = true, // By default run each test in its own tab
@ -70,8 +50,6 @@ this.add_task = function(taskFn, opts = {}) {
const fn = async function() {
let client, tab, target;
await startRemoteAgent();
try {
const CDP = await getCDP();

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0

View file

@ -1,6 +1,9 @@
[DEFAULT]
tags = remote
subsuite = remote
args =
--remote-debugging-port
--remote-allow-origins=null
prefs = # Bug 1600054: Make CDP Fission compatible
fission.bfcacheInParent=false
fission.webContentIsolationStrategy=0

View file

@ -180,7 +180,7 @@ class RemoteAgentClass {
}
}
async listen(url) {
async #listen(url) {
if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
throw Components.Exception(
"May only be instantiated in parent process",
@ -217,12 +217,12 @@ class RemoteAgentClass {
await Promise.all([this.webDriverBiDi?.start(), this.cdp?.start()]);
} catch (e) {
await this.close();
await this.#stop();
logger.error(`Unable to start remote agent: ${e.message}`, e);
}
}
async close() {
async #stop() {
if (!this.listening) {
return;
}
@ -315,37 +315,30 @@ class RemoteAgentClass {
this.#allowHosts = this.handleAllowHostsFlag(subject);
this.#allowOrigins = this.handleAllowOriginsFlag(subject);
}
// Ideally we should only initialize the Remote Agent when the command
// line argument has been specified. But to allow Browser Chrome tests
// to run certain states have to be set and listeners registered.
// Once bug 1762647 is fixed all the next lines can be moved to
// "final-ui-startup".
Services.obs.addObserver(this, "sessionstore-windows-restored");
Services.obs.addObserver(this, "quit-application");
Services.obs.addObserver(this, "sessionstore-windows-restored");
Services.obs.addObserver(this, "quit-application");
// With Bug 1717899 we will extend the lifetime of the Remote Agent to
// the whole Firefox session, which will be identical to Marionette. For
// now prevent logging if the component is not enabled during startup.
if (
(activeProtocols & WEBDRIVER_BIDI_ACTIVE) ===
WEBDRIVER_BIDI_ACTIVE
) {
this.#webDriverBiDi = new WebDriverBiDi(this);
if (this.enabled) {
logger.debug("WebDriver BiDi enabled");
}
}
// With Bug 1717899 we will extend the lifetime of the Remote Agent to
// the whole Firefox session, which will be identical to Marionette. For
// now prevent logging if the component is not enabled during startup.
if (
(activeProtocols & WEBDRIVER_BIDI_ACTIVE) ===
WEBDRIVER_BIDI_ACTIVE
) {
this.#webDriverBiDi = new WebDriverBiDi(this);
if (this.enabled) {
logger.debug("WebDriver BiDi enabled");
if ((activeProtocols & CDP_ACTIVE) === CDP_ACTIVE) {
this.#cdp = new CDP(this);
if (this.enabled) {
logger.debug("CDP enabled");
}
}
}
if ((activeProtocols & CDP_ACTIVE) === CDP_ACTIVE) {
this.#cdp = new CDP(this);
if (this.enabled) {
logger.debug("CDP enabled");
}
}
break;
case "final-ui-startup":
@ -353,7 +346,7 @@ class RemoteAgentClass {
try {
let address = Services.io.newURI(`http://localhost:${this.#port}`);
await this.listen(address);
await this.#listen(address);
} catch (e) {
throw Error(`Unable to start remote agent: ${e}`);
}
@ -372,7 +365,7 @@ class RemoteAgentClass {
case "quit-application":
Services.obs.removeObserver(this, "quit-application");
this.close();
this.#stop();
break;
}
}

View file

@ -4,7 +4,7 @@
"use strict";
var EXPORTED_SYMBOLS = ["allowNullOrigin", "WebSocketHandshake"];
var EXPORTED_SYMBOLS = ["WebSocketHandshake"];
// This file is an XPCOM service-ified copy of ../devtools/server/socket/websocket-server.js.
@ -32,14 +32,6 @@ XPCOMUtils.defineLazyGetter(this, "threadManager", () => {
return Cc["@mozilla.org/thread-manager;1"].getService();
});
// This should only be used by the CDP browser mochitests which create a
// websocket handshake with a non-null origin. It can be removed once
// Mochitest supports custom arguments in browser.ini (bug 1762647)
let nullOriginAllowed = false;
function allowNullOrigin(allowed) {
nullOriginAllowed = allowed;
}
/**
* Allowed origins are exposed through 2 separate getters because while most
* of the values should be valid URIs, `null` is also a valid origin and cannot
@ -154,7 +146,7 @@ function isOriginValid(originHeader) {
// Special case "null" origins, used for privacy sensitive or opaque origins.
if (originHeader === "null") {
return allowedOrigins.includes("null") || nullOriginAllowed;
return allowedOrigins.includes("null");
}
try {