зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 7 changesets (bug 1350887) for build bustage on a CLOSED TREE
Backed out changeset d2b395e6c5c0 (bug 1350887) Backed out changeset 5a6d5c43135f (bug 1350887) Backed out changeset ec57676ad0d1 (bug 1350887) Backed out changeset 4a3d1a8767f7 (bug 1350887) Backed out changeset 40cd9ca1553e (bug 1350887) Backed out changeset d264991a436d (bug 1350887) Backed out changeset b915d40a6ba6 (bug 1350887) --HG-- rename : testing/marionette/prefs/marionette.js => testing/marionette/prefs.js
This commit is contained in:
Родитель
be2b5e3c07
Коммит
d11e3dc66d
|
@ -653,10 +653,6 @@
|
||||||
; gre location for now.
|
; gre location for now.
|
||||||
@RESPATH@/defaults/pref/channel-prefs.js
|
@RESPATH@/defaults/pref/channel-prefs.js
|
||||||
|
|
||||||
; Remote control protocol prefs
|
|
||||||
; defined in ../../testing/marionette/prefs/marionette.js
|
|
||||||
@RESPATH@/defaults/prefs/marionette.js
|
|
||||||
|
|
||||||
; Services (gre) prefs
|
; Services (gre) prefs
|
||||||
@RESPATH@/defaults/pref/services-sync.js
|
@RESPATH@/defaults/pref/services-sync.js
|
||||||
|
|
||||||
|
|
|
@ -1,174 +0,0 @@
|
||||||
MARIONETTE
|
|
||||||
|
|
||||||
Marionette is the remote protocol that lets OOP programs communicate
|
|
||||||
with, instrument, and control Gecko.
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
|
|
||||||
Marionette is an automation driver for Mozilla’s Gecko engine.
|
|
||||||
It can remotely control either the UI or the internal JavaScript of
|
|
||||||
the Gecko platform, such as Firefox. It can control both the chrome
|
|
||||||
and the content document, giving a high level of control and ability to
|
|
||||||
replicate user interaction. In addition to performing actions on the
|
|
||||||
browser, Marionette can also read properties and attributes of the DOM.
|
|
||||||
|
|
||||||
USAGE
|
|
||||||
|
|
||||||
It is included in Firefox, but not enabled by default unless the
|
|
||||||
--marionette flag is passed or the marionette.enabled preference is
|
|
||||||
set to true.
|
|
||||||
|
|
||||||
To start Firefox with the remote protocol turned on:
|
|
||||||
|
|
||||||
% firefox --marionette
|
|
||||||
…
|
|
||||||
1491228343089 Marionette INFO Listening on port 2828
|
|
||||||
|
|
||||||
This binds to a TCP socket, over which CLIENTS can communicate with
|
|
||||||
Marionette using the PROTOCOL.
|
|
||||||
|
|
||||||
PROTOCOL
|
|
||||||
|
|
||||||
Marionette provides an asynchronous, parallel pipelining user-facing
|
|
||||||
interface. Message sequencing limits chances of payload race conditions
|
|
||||||
and provides a uniform way in which payloads are serialised.
|
|
||||||
|
|
||||||
Clients that deliver a blocking WebDriver interface are still expected
|
|
||||||
to not send further command requests before the response from the last
|
|
||||||
command has come back, but if they still happen to do so because of
|
|
||||||
programming error, no harm will be done. This guards against bugs
|
|
||||||
such as https://bugzil.la/1207125.
|
|
||||||
|
|
||||||
Schematic flow of messages:
|
|
||||||
|
|
||||||
client server
|
|
||||||
| |
|
|
||||||
msgid=1 |----------->|
|
|
||||||
| command |
|
|
||||||
| |
|
|
||||||
msgid=2 |<-----------|
|
|
||||||
| command |
|
|
||||||
| |
|
|
||||||
msgid=2 |----------->|
|
|
||||||
| response |
|
|
||||||
| |
|
|
||||||
msgid=1 |<-----------|
|
|
||||||
| response |
|
|
||||||
| |
|
|
||||||
|
|
||||||
The protocol consists of a COMMAND message and the corresponding
|
|
||||||
RESPONSE message. A RESPONSE message must always be sent in reply to
|
|
||||||
a COMMAND message.
|
|
||||||
|
|
||||||
This means that the server implementation does not need to send the
|
|
||||||
reply precisely in the order of the received commands: if it receives
|
|
||||||
multiple messages, the server may even reply in random order. It is
|
|
||||||
therefore strongly adviced that clients take this into account when
|
|
||||||
implementing the client end of this wire protocol.
|
|
||||||
|
|
||||||
This is required for pipelining messages. On the server side, some
|
|
||||||
functions are fast, and some less so. If the server must reply in
|
|
||||||
order, the slow functions delay the other replies even if its execution
|
|
||||||
is already completed.
|
|
||||||
|
|
||||||
COMMAND
|
|
||||||
|
|
||||||
The request, or command message, is a four element JSON array as shown
|
|
||||||
below, that may originate from either the client- or server remote ends:
|
|
||||||
|
|
||||||
[type, message ID, command, parameters]
|
|
||||||
|
|
||||||
type
|
|
||||||
Must be 0 (integer). This indicates that the message is the
|
|
||||||
COMMAND message.
|
|
||||||
|
|
||||||
message ID
|
|
||||||
A 32-bit unsigned integer. This number is used as sequencing number
|
|
||||||
that uniquely identifies a pair of COMMAND and RESPONSE messages.
|
|
||||||
The other remote part will reply with a corresponding RESPONSE with
|
|
||||||
the same message ID.
|
|
||||||
|
|
||||||
command
|
|
||||||
A string identifying the RPC method or command to execute.
|
|
||||||
|
|
||||||
parameters
|
|
||||||
An arbitrary JSON serialisable object.
|
|
||||||
|
|
||||||
RESPONSE
|
|
||||||
|
|
||||||
The response message is also a four element array as shown below,
|
|
||||||
and must always be sent after receiving a COMMAND:
|
|
||||||
|
|
||||||
[type, message ID, error, result]
|
|
||||||
|
|
||||||
type
|
|
||||||
Must be 1 (integer). This indicates that the message is the RESPONSE
|
|
||||||
message.
|
|
||||||
|
|
||||||
message ID
|
|
||||||
A 32-bit unsigned integer. This corresponds to the COMMAND
|
|
||||||
message’s message ID.
|
|
||||||
|
|
||||||
error
|
|
||||||
If the command executed correctly, this field is null. If the error
|
|
||||||
occurre on the server-side, then this field is an ERROR object.
|
|
||||||
|
|
||||||
result
|
|
||||||
The result object associated with the COMMAND, if it executed
|
|
||||||
correctly. If an error occurred on the server-side, this field
|
|
||||||
is null.
|
|
||||||
|
|
||||||
The structure of the result entry can vary, but is documented
|
|
||||||
individually for each command in ./driver.js.
|
|
||||||
|
|
||||||
ERROR OBJECTS
|
|
||||||
|
|
||||||
An ERROR object is a serialisation of JavaScript error types, and is
|
|
||||||
structured like this:
|
|
||||||
|
|
||||||
{
|
|
||||||
"error": "invalid session id",
|
|
||||||
"message": "No active session with ID 1234",
|
|
||||||
"stacktrace": ""
|
|
||||||
}
|
|
||||||
|
|
||||||
All the fields of the error object are required, so the stacktrace and
|
|
||||||
message fields may be empty strings. The error field is on the other
|
|
||||||
hand guaranteed to be one of the JSON error codes as laid out by the
|
|
||||||
WebDriver standard:
|
|
||||||
|
|
||||||
https://w3c.github.io/webdriver/webdriver-spec.html#handling-errors
|
|
||||||
|
|
||||||
CLIENTS
|
|
||||||
|
|
||||||
Clients may be implemented in any language that is capable of writing
|
|
||||||
and receiving data over TCP socket. A reference client is provided in
|
|
||||||
tree (under ./client). Clients may be implemented both synchronously
|
|
||||||
and asynchronously, although the latter is impossible in protocol
|
|
||||||
levels 2 and earlier due to the lack of message indexing.
|
|
||||||
|
|
||||||
DOCUMENTATION
|
|
||||||
|
|
||||||
General introduction:
|
|
||||||
|
|
||||||
https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette
|
|
||||||
|
|
||||||
Protocol definition:
|
|
||||||
|
|
||||||
https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/Protocol
|
|
||||||
|
|
||||||
Generated Python client API documentation:
|
|
||||||
|
|
||||||
https://marionette-client.readthedocs.org/
|
|
||||||
|
|
||||||
BUGS
|
|
||||||
|
|
||||||
Server and Python client bugs are tracked in the Testing :: Marionette
|
|
||||||
component in Bugzilla:
|
|
||||||
|
|
||||||
https://bugzilla.mozilla.org/buglist.cgi?product=Testing&component=Marionette
|
|
||||||
|
|
||||||
geckodriver (found in ../geckodriver), the HTTP proxy for using W3C
|
|
||||||
WebDriver-compatible clients with Marionette, tracks its bugs on GitHub:
|
|
||||||
|
|
||||||
https://github.com/mozilla/geckodriver/issues
|
|
|
@ -25,27 +25,15 @@ const PREF_FORCE_LOCAL_FALLBACK = "marionette.force-local";
|
||||||
|
|
||||||
const DEFAULT_PORT = 2828;
|
const DEFAULT_PORT = 2828;
|
||||||
const DEFAULT_LOG_LEVEL = "info";
|
const DEFAULT_LOG_LEVEL = "info";
|
||||||
const LOG_LEVELS = new class extends Map {
|
const LOG_LEVELS = new Map([
|
||||||
constructor () {
|
["fatal", Log.Level.Fatal],
|
||||||
super([
|
["error", Log.Level.Error],
|
||||||
["fatal", Log.Level.Fatal],
|
["warn", Log.Level.Warn],
|
||||||
["error", Log.Level.Error],
|
["info", Log.Level.Info],
|
||||||
["warn", Log.Level.Warn],
|
["config", Log.Level.Config],
|
||||||
["info", Log.Level.Info],
|
["debug", Log.Level.Debug],
|
||||||
["config", Log.Level.Config],
|
["trace", Log.Level.Trace],
|
||||||
["debug", Log.Level.Debug],
|
]);
|
||||||
["trace", Log.Level.Trace],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
get (level) {
|
|
||||||
let s = new String(level).toLowerCase();
|
|
||||||
if (!this.has(s)) {
|
|
||||||
return DEFAULT_LOG_LEVEL;
|
|
||||||
}
|
|
||||||
return super.get(s);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Besides starting based on existing prefs in a profile and a command
|
// Besides starting based on existing prefs in a profile and a command
|
||||||
// line flag, we also support inheriting prefs out of an env var, and to
|
// line flag, we also support inheriting prefs out of an env var, and to
|
||||||
|
@ -65,15 +53,6 @@ const ServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||||
"nsIServerSocket",
|
"nsIServerSocket",
|
||||||
"initSpecialConnection");
|
"initSpecialConnection");
|
||||||
|
|
||||||
// Get preference value of |preferred|, falling back to |fallback|
|
|
||||||
// if |preferred| is not user-modified and |fallback| exists.
|
|
||||||
function getPref (preferred, fallback) {
|
|
||||||
if (!Preferences.isSet(preferred) && Preferences.has(fallback)) {
|
|
||||||
return Preferences.get(fallback, Preferences.get(preferred));
|
|
||||||
}
|
|
||||||
return Preferences.get(preferred);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marionette preferences recently changed names. This is an abstraction
|
// Marionette preferences recently changed names. This is an abstraction
|
||||||
// that first looks for the new name, but falls back to using the old name
|
// that first looks for the new name, but falls back to using the old name
|
||||||
// if the new does not exist.
|
// if the new does not exist.
|
||||||
|
@ -81,16 +60,38 @@ function getPref (preferred, fallback) {
|
||||||
// This shim can be removed when Firefox 55 ships.
|
// This shim can be removed when Firefox 55 ships.
|
||||||
const prefs = {
|
const prefs = {
|
||||||
get port () {
|
get port () {
|
||||||
return getPref(PREF_PORT, PREF_PORT_FALLBACK);
|
let fallback = Preferences.get(PREF_PORT_FALLBACK, DEFAULT_PORT);
|
||||||
|
return Preferences.get(PREF_PORT, fallback);
|
||||||
},
|
},
|
||||||
|
|
||||||
get logLevel () {
|
get logLevel () {
|
||||||
let s = getPref(PREF_LOG_LEVEL, PREF_LOG_LEVEL_FALLBACK);
|
let level = DEFAULT_LOG_LEVEL;
|
||||||
return LOG_LEVELS.get(s);
|
let fallback = Preferences.get(PREF_LOG_LEVEL_FALLBACK, level);
|
||||||
|
let p = Preferences.get(PREF_LOG_LEVEL, fallback);
|
||||||
|
|
||||||
|
switch (typeof p) {
|
||||||
|
// Gecko >= 46
|
||||||
|
case "string":
|
||||||
|
let s = p.toLowerCase();
|
||||||
|
if (LOG_LEVELS.has(s)) {
|
||||||
|
level = LOG_LEVELS.get(s);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Gecko <= 45
|
||||||
|
case "boolean":
|
||||||
|
if (p) {
|
||||||
|
level = Log.Level.Trace;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return level;
|
||||||
},
|
},
|
||||||
|
|
||||||
get forceLocal () {
|
get forceLocal () {
|
||||||
return getPref(PREF_FORCE_LOCAL, PREF_FORCE_LOCAL_FALLBACK);
|
let fallback = Preferences.get(PREF_FORCE_LOCAL_FALLBACK, true);
|
||||||
|
return Preferences.get(PREF_FORCE_LOCAL, fallback);
|
||||||
},
|
},
|
||||||
|
|
||||||
readFromEnvironment (key) {
|
readFromEnvironment (key) {
|
||||||
|
@ -287,7 +288,7 @@ MarionetteComponent.prototype.init = function () {
|
||||||
// This allows the following attempt by Marionette to open a socket
|
// This allows the following attempt by Marionette to open a socket
|
||||||
// to succeed.
|
// to succeed.
|
||||||
let insaneSacrificialGoat =
|
let insaneSacrificialGoat =
|
||||||
new ServerSocket(0, Ci.nsIServerSocket.KeepWhenOffline, 4);
|
new ServerSocket(666, Ci.nsIServerSocket.KeepWhenOffline, 4);
|
||||||
insaneSacrificialGoat.asyncListen(this);
|
insaneSacrificialGoat.asyncListen(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,6 +298,9 @@ MarionetteComponent.prototype.init = function () {
|
||||||
s = new server.TCPListener(prefs.port, prefs.forceLocal);
|
s = new server.TCPListener(prefs.port, prefs.forceLocal);
|
||||||
s.start();
|
s.start();
|
||||||
this.logger.info(`Listening on port ${s.port}`);
|
this.logger.info(`Listening on port ${s.port}`);
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`Error on starting server: ${e}`);
|
||||||
|
dump(`${e.toString()}\n${e.stack}\n`);
|
||||||
} finally {
|
} finally {
|
||||||
if (s) {
|
if (s) {
|
||||||
this.server = s;
|
this.server = s;
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
DIRS += ["components"]
|
DIRS += ["components"]
|
||||||
|
|
||||||
JAR_MANIFESTS += ["jar.mn"]
|
JS_PREFERENCE_FILES += ["prefs.js"]
|
||||||
JS_PREFERENCE_FILES += ["prefs/marionette.js"]
|
|
||||||
|
|
||||||
|
JAR_MANIFESTS += ["jar.mn"]
|
||||||
MARIONETTE_UNIT_MANIFESTS += ["harness/marionette_harness/tests/unit/unit-tests.ini"]
|
MARIONETTE_UNIT_MANIFESTS += ["harness/marionette_harness/tests/unit/unit-tests.ini"]
|
||||||
MARIONETTE_WEBAPI_MANIFESTS += ["harness/marionette_harness/tests/webapi-tests.ini"]
|
MARIONETTE_WEBAPI_MANIFESTS += ["harness/marionette_harness/tests/webapi-tests.ini"]
|
||||||
XPCSHELL_TESTS_MANIFESTS += ["unit.ini"]
|
XPCSHELL_TESTS_MANIFESTS += ["unit.ini"]
|
||||||
|
|
|
@ -2,13 +2,6 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
// Marionette is the remote protocol that lets OOP programs communicate
|
|
||||||
// with, instrument, and control Gecko.
|
|
||||||
//
|
|
||||||
// It is included in Firefox, but not enabled by default unless the
|
|
||||||
// --marionette flag is passed or the marionette.enabled preference is
|
|
||||||
// set to true.
|
|
||||||
|
|
||||||
// Whether or not Marionette is enabled.
|
// Whether or not Marionette is enabled.
|
||||||
pref("marionette.enabled", false);
|
pref("marionette.enabled", false);
|
||||||
|
|
|
@ -324,8 +324,6 @@ server.TCPListener = class {
|
||||||
let flags = Ci.nsIServerSocket.KeepWhenOffline;
|
let flags = Ci.nsIServerSocket.KeepWhenOffline;
|
||||||
if (this.forceLocal) {
|
if (this.forceLocal) {
|
||||||
flags |= Ci.nsIServerSocket.LoopbackOnly;
|
flags |= Ci.nsIServerSocket.LoopbackOnly;
|
||||||
} else {
|
|
||||||
logger.warn("Server socket is not limited to loopback connections");
|
|
||||||
}
|
}
|
||||||
this.listener = new ServerSocket(this.port, flags, 1);
|
this.listener = new ServerSocket(this.port, flags, 1);
|
||||||
this.listener.asyncListen(this);
|
this.listener.asyncListen(this);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче