Bug 1355888 - Add env var MOZ_MARIONETTE to start server; r?whimboo,maja_zf
This patch introduces a new environment variable, MOZ_MARIONETTE, which
if set will start the Marionette remote control server. This is meant
to be analogous to passing the -marionette flag to the Firefox binary.
When the server is started, we set the environment variable to
preserve Marionette's enabled state across internal restarts.
When Services.startup.quit(eRestart) is called, Firefox is restarted
without the original command line flags it was started with, which means
we lose track of whether Marionette was enabled. By setting
MOZ_MARIONETTE in-process, we preserve the knowledge of this state.
This approach is in line with how state is preserved across in-app
restarts in toolkit/xre/nsAppRunner.cpp:4761 (XRE_PROFILE_*), and for
how MOZ_APP_RESTART and XUL_APP_FILE works.
MozReview-Commit-ID: Dcb34m6FoZh
--- a/testing/marionette/components/marionette.js
+++ b/testing/marionette/components/marionette.js
@@ -6,16 +6,19 @@
const {Constructor: CC, interfaces: Ci, utils: Cu, classes: Cc} = Components;
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyServiceGetter(
+ this, "env", "@mozilla.org/process/environment;1", "nsIEnvironment");
+
const MARIONETTE_CONTRACT_ID = "@mozilla.org/marionette;1";
const MARIONETTE_CID = Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}");
const PREF_ENABLED = "marionette.enabled";
const PREF_ENABLED_FALLBACK = "marionette.defaultPrefs.enabled";
const PREF_PORT = "marionette.port";
const PREF_PORT_FALLBACK = "marionette.defaultPrefs.port";
const PREF_LOG_LEVEL = "marionette.log.level";
@@ -40,29 +43,34 @@ const LOG_LEVELS = new class extends Map
let s = new String(level).toLowerCase();
if (!this.has(s)) {
return DEFAULT_LOG_LEVEL;
}
return super.get(s);
}
};
+// Complements -marionette flag for starting the Marionette server.
+// We also set this if Marionette is running in order to start the server
+// again after a Firefox restart.
+const ENV_ENABLED = "MOZ_MARIONETTE";
+
// 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
// start Marionette that way.
//
// This allows marionette prefs to persist when we do a restart into
// a different profile in order to test things like Firefox refresh.
// The environment variable itself, if present, is interpreted as a
// JSON structure, with the keys mapping to preference names in the
// "marionette." branch, and the values to the values of those prefs. So
// something like {"enabled": true} would result in the marionette.enabled
// pref being set to true, thus triggering marionette being enabled for
// that startup.
-const ENV_PREF_VAR = "MOZ_MARIONETTE_PREF_STATE_ACROSS_RESTARTS";
+const ENV_PRESERVE_PREFS = "MOZ_MARIONETTE_PREF_STATE_ACROSS_RESTARTS";
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
"nsIServerSocket",
"initSpecialConnection");
// Get preference value of |preferred|, falling back to |fallback|
// if |preferred| is not user-modified and |fallback| exists.
function getPref (preferred, fallback) {
@@ -107,18 +115,17 @@ const prefs = {
Preferences.set("marionette." + prefName, prefs[prefName]);
}
}
}
},
};
function MarionetteComponent() {
- // guards against this component
- // being initialised multiple times
+ this.enabled = env.exists(ENV_ENABLED);
this.running = false;
// holds a reference to server.TCPListener
this.server = null;
// holds reference to ChromeWindow
// used to run GFX sanity tests on Windows
this.gfxWindow = null;
@@ -188,17 +195,17 @@ MarionetteComponent.prototype.observe =
}
break;
case "profile-after-change":
// Using sessionstore-windows-restored as the xpcom category doesn't
// seem to work, so we wait for that by adding an observer here.
Services.obs.addObserver(this, "sessionstore-windows-restored");
- prefs.readFromEnvironment(ENV_PREF_VAR);
+ prefs.readFromEnvironment(ENV_PRESERVE_PREFS);
if (this.enabled) {
// We want to suppress the modal dialog that's shown
// when starting up in safe-mode to enable testing.
if (Services.appinfo.inSafeMode) {
Services.obs.addObserver(this, "domwindowopened");
}
}
--- a/testing/marionette/server.js
+++ b/testing/marionette/server.js
@@ -1,40 +1,49 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
"use strict";
const {Constructor: CC, classes: Cc, interfaces: Ci, utils: Cu} = Components;
-const loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
-const ServerSocket = CC("@mozilla.org/network/server-socket;1", "nsIServerSocket", "initSpecialConnection");
+const loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
+ .getService(Ci.mozIJSSubScriptLoader);
+const ServerSocket = CC(
+ "@mozilla.org/network/server-socket;1",
+ "nsIServerSocket",
+ "initSpecialConnection");
Cu.import("resource://gre/modules/Log.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("chrome://marionette/content/assert.js");
Cu.import("chrome://marionette/content/driver.js");
Cu.import("chrome://marionette/content/error.js");
Cu.import("chrome://marionette/content/message.js");
+Cu.import("chrome://marionette/content/transport.js");
-Cu.import("chrome://marionette/content/transport.js");
+XPCOMUtils.defineLazyServiceGetter(
+ this, "env", "@mozilla.org/process/environment;1", "nsIEnvironment");
const logger = Log.repository.getLogger("Marionette");
const {KeepWhenOffline, LoopbackOnly} = Ci.nsIServerSocket;
this.EXPORTED_SYMBOLS = ["server"];
this.server = {};
const PROTOCOL_VERSION = 3;
+const ENV_ENABLED = "MOZ_MARIONETTE";
+
const PREF_CONTENT_LISTENER = "marionette.contentListener";
const PREF_PORT = "marionette.port";
const PREF_RECOMMENDED = "marionette.prefs.recommended";
// Marionette sets preferences recommended for automation when it starts,
// unless |marionette.prefs.recommended| has been set to false.
// Where noted, some prefs should also be set in the profile passed to
// Marionette to prevent them from affecting startup, since some of these
@@ -328,16 +337,17 @@ server.TCPListener = class {
const backlog = 1;
this.socket = new ServerSocket(this.port, flags, backlog);
this.socket.asyncListen(this);
this.port = this.socket.port;
Preferences.set(PREF_PORT, this.port);
this.alive = true;
this._acceptConnections = true;
+ env.set(ENV_ENABLED, "1");
}
stop () {
if (!this.alive) {
return;
}
this._acceptConnections = false;