Bug 1344748 - Rename and register Marionette prefs; r?maja_zf
This change renames the following Marionette preferences:
marionette.defaultPrefs.enabled marionette.enabled
marionette.defaultPrefs.port marionette.port
marionette.force-local marionette.forcelocal
marionette.logging marionette.log.level
The old preference names are still usable, but are henceforth considered
deprecated. They will be removed when Firefox 55 ships.
It also registers these preferences in Firefox so that they are
discoverable through about:config.
This patch also refactors testing/marionette/components/marionette.js.
MozReview-Commit-ID: 1dAMQS2e0og
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -66,17 +66,17 @@ class GeckoInstance(object):
"geo.provider.testing": True,
# Do not scan Wifi
"geo.wifi.scan": False,
# No hang monitor
"hangmonitor.timeout": 0,
"javascript.options.showInConsole": True,
- "marionette.defaultPrefs.enabled": True,
+ "marionette.enabled": True,
"media.volume_scale": "0.01",
# Make sure the disk cache doesn't get auto disabled
"network.http.bypass-cachelock-threshold": 200000,
# Do not prompt for temporary redirects
"network.http.prompt-temp-redirect": False,
# Disable speculative connections so they aren"t reported as leaking when they"re
# hanging around
--- a/testing/marionette/components/marionette.js
+++ b/testing/marionette/components/marionette.js
@@ -1,265 +1,288 @@
/* 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, interfaces: Ci, utils: Cu, classes: Cc} = Components;
-const MARIONETTE_CONTRACTID = "@mozilla.org/marionette;1";
+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");
+
+const MARIONETTE_CONTRACT_ID = "@mozilla.org/marionette;1";
const MARIONETTE_CID = Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}");
const DEFAULT_PORT = 2828;
-const ENABLED_PREF = "marionette.defaultPrefs.enabled";
-const PORT_PREF = "marionette.defaultPrefs.port";
-const FORCELOCAL_PREF = "marionette.force-local";
-const LOG_PREF = "marionette.logging";
+const DEFAULT_LOG_LEVEL = "info";
+const LOG_LEVELS = new Map([
+ ["fatal", Log.Level.Fatal],
+ ["error", Log.Level.Error],
+ ["warn", Log.Level.Warn],
+ ["info", Log.Level.Info],
+ ["config", Log.Level.Config],
+ ["debug", Log.Level.Debug],
+ ["trace", Log.Level.Trace],
+]);
-/**
- * Besides starting based on existing prefs in a profile and a commandline 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 env var 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 {"defaultPrefs.enabled": true}
- * in the env var would result in the marionette.defaultPrefs.enabled pref being
- * set to true, thus triggering marionette being enabled for that startup.
- */
+// 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 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/XPCOMUtils.jsm");
-
-function MarionetteComponent() {
- this.loaded_ = false;
- this.observerService = Services.obs;
- this.logger = this.setupLogger_(this.determineLoggingLevel_());
-}
+// Marionette preferences recently changed names. This is an abstraction
+// that first looks for the new name, but falls back to using the old name
+// if the new does not exist.
+//
+// This shim can be removed when Firefox 55 ships.
+const prefs = {
+ get enabled () {
+#ifdef ENABLE_MARIONETTE
+ let fallback = Preferences.get("marionette.defaultPrefs.enabled", false);
+ return Preferences.get("marionette.enabled", fallback);
+#else
+ return false;
+#endif
+ },
-MarionetteComponent.prototype = {
- classDescription: "Marionette component",
- classID: MARIONETTE_CID,
- contractID: MARIONETTE_CONTRACTID,
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler, Ci.nsIObserver]),
- _xpcom_categories: [
- {category: "command-line-handler", entry: "b-marionette"},
- {category: "profile-after-change", service: true}
- ],
- enabled: false,
- finalUiStartup: false,
- gfxWindow: null,
- server: null,
-};
+ get port () {
+ let fallback = Preferences.get("marionette.defaultPrefs.port", DEFAULT_PORT);
+ return Preferences.get("marionette.port", fallback);
+ },
-MarionetteComponent.prototype.setupLogger_ = function (level) {
- let log = Log.repository.getLogger("Marionette");
- log.level = level;
- log.addAppender(new Log.DumpAppender());
- return log;
-};
-
-MarionetteComponent.prototype.determineLoggingLevel_ = function() {
- let level = Log.Level.Info;
-
- // marionette.logging pref can override default
- // with an entry from the Log.Level enum
- if (Preferences.has(LOG_PREF)) {
- let p = Preferences.get(LOG_PREF);
+ get logLevel () {
+ let level = DEFAULT_LOG_LEVEL;
+ let fallback = Preferences.get("marionette.logging", level);
+ let p = Preferences.get("marionette.log.level", fallback);
switch (typeof p) {
// Gecko >= 46
case "string":
let s = p.toLowerCase();
- s = s.charAt(0).toUpperCase() + s.slice(1);
- level = Log.Level[s];
+ 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 () {
+ let fallback = Preferences.get("marionette.force-local", true);
+ return Preferences.get("marionette.forcelocal", fallback);
+ },
+
+ readFromEnvironment (key) {
+ const env = Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment);
- return level;
+ if (env.exists(key)) {
+ let prefs;
+ try {
+ prefs = JSON.parse(env.get(key));
+ } catch (e) {
+ Cu.reportError(
+ "Invalid Marionette preferences in environment; " +
+ "preferences will not have been applied");
+ Cu.reportError(e);
+ }
+
+ if (prefs) {
+ for (let prefName of Object.keys(prefs)) {
+ Preferences.set("marionette." + prefName, prefs[prefName]);
+ }
+ }
+ }
+ },
};
-MarionetteComponent.prototype.onSocketAccepted = function(
- socket, transport) {
+function MarionetteComponent() {
+ this.enabled = prefs.enabled;
+ this.loaded = false;
+ this.logger = this.setupLogger(prefs.logLevel);
+ this.server = null;
+ this.gfxWindow = null;
+ this.finalUIStartup = false;
+}
+
+MarionetteComponent.prototype = {
+ classDescription: "Marionette component",
+ classID: MARIONETTE_CID,
+ contractID: MARIONETTE_CONTRACT_ID,
+ QueryInterface: XPCOMUtils.generateQI(
+ [Ci.nsICommandLineHandler, Ci.nsIObserver]),
+ _xpcom_categories: [
+ {category: "command-line-handler", entry: "b-marionette"},
+ {category: "profile-after-change", service: true}
+ ],
+};
+
+MarionetteComponent.prototype.onSocketAccepted = function (socket, transport) {
this.logger.info("onSocketAccepted for Marionette dummy socket");
};
MarionetteComponent.prototype.onStopListening = function (socket, status) {
this.logger.info(`onStopListening for Marionette dummy socket, code ${status}`);
socket.close();
};
-/** Check cmdLine argument for {@code --marionette}. */
+/** Checks |cmdLine| for the --marionette flag. */
MarionetteComponent.prototype.handle = function (cmdLine) {
- // if the CLI is there then lets do work otherwise nothing to see
if (cmdLine.handleFlag("marionette", false)) {
this.enabled = true;
this.logger.debug("Marionette enabled via command-line flag");
this.init();
}
};
MarionetteComponent.prototype.observe = function (subject, topic, data) {
switch (topic) {
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.
- this.observerService.addObserver(this, "sessionstore-windows-restored", false);
+ // 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", false);
- this.maybeReadPrefsFromEnvironment();
+ prefs.readFromEnvironment(ENV_PREF_VAR);
-#ifdef ENABLE_MARIONETTE
- this.enabled = Preferences.get(ENABLED_PREF, false);
if (this.enabled) {
- this.logger.debug("Marionette enabled via build flag and pref");
+ this.logger.debug("Marionette is enabled");
// We want to suppress the modal dialog that's shown
// when starting up in safe-mode to enable testing.
if (Services.appinfo.inSafeMode) {
- this.observerService.addObserver(this, "domwindowopened", false);
+ Services.obs.addObserver(this, "domwindowopened", false);
}
}
-#endif
break;
case "domwindowclosed":
if (this.gfxWindow === null || subject === this.gfxWindow) {
- this.observerService.removeObserver(this, topic);
+ Services.obs.removeObserver(this, topic);
- this.observerService.addObserver(this, "xpcom-shutdown", false);
- this.finalUiStartup = true;
+ Services.obs.addObserver(this, "xpcom-shutdown", false);
+ this.finalUIStartup = true;
this.init();
}
break;
case "domwindowopened":
- this.observerService.removeObserver(this, topic);
- this.suppressSafeModeDialog_(subj);
+ Services.obs.removeObserver(this, topic);
+ this.suppressSafeModeDialog(subject);
break;
case "sessionstore-windows-restored":
- this.observerService.removeObserver(this, topic);
+ Services.obs.removeObserver(this, topic);
- // When Firefox starts on Windows, an additional GFX sanity test window
- // may appear off-screen. Marionette should wait for it to close.
+ // When Firefox starts on Windows, an additional GFX sanity test
+ // window may appear off-screen. Marionette should wait for it
+ // to close.
let winEn = Services.wm.getEnumerator(null);
while (winEn.hasMoreElements()) {
let win = winEn.getNext();
if (win.document.documentURI == "chrome://gfxsanity/content/sanityparent.html") {
this.gfxWindow = win;
break;
}
}
if (this.gfxWindow) {
- this.observerService.addObserver(this, "domwindowclosed", false);
+ Services.obs.addObserver(this, "domwindowclosed", false);
} else {
- this.observerService.addObserver(this, "xpcom-shutdown", false);
- this.finalUiStartup = true;
+ Services.obs.addObserver(this, "xpcom-shutdown", false);
+ this.finalUIStartup = true;
this.init();
}
break;
case "xpcom-shutdown":
- this.observerService.removeObserver(this, "xpcom-shutdown");
+ Services.obs.removeObserver(this, "xpcom-shutdown");
this.uninit();
break;
}
};
-MarionetteComponent.prototype.maybeReadPrefsFromEnvironment = function() {
- let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
- if (env.exists(ENV_PREF_VAR)) {
- let prefStr = env.get(ENV_PREF_VAR);
- let prefs;
- try {
- prefs = JSON.parse(prefStr);
- } catch (ex) {
- Cu.reportError("Invalid marionette prefs in environment; prefs won't have been applied.");
- Cu.reportError(ex);
- }
- if (prefs) {
- for (let prefName of Object.keys(prefs)) {
- Preferences.set("marionette." + prefName, prefs[prefName]);
- }
- }
- }
-}
+MarionetteComponent.prototype.setupLogger = function (level) {
+ let logger = Log.repository.getLogger("Marionette");
+ logger.level = level;
+ logger.addAppender(new Log.DumpAppender());
+ return logger;
+};
-MarionetteComponent.prototype.suppressSafeModeDialog_ = function (win) {
- // Wait for the modal dialog to finish loading.
+/** Wait for the modal dialogue to finish loading. */
+MarionetteComponent.prototype.suppressSafeModeDialog = function (win) {
win.addEventListener("load", function() {
if (win.document.getElementById("safeModeDialog")) {
// Accept the dialog to start in safe-mode
win.setTimeout(() => {
win.document.documentElement.getButton("accept").click();
});
}
}, {once: true});
};
-MarionetteComponent.prototype.init = function() {
- if (this.loaded_ || !this.enabled || !this.finalUiStartup) {
+MarionetteComponent.prototype.init = function () {
+ if (this.loaded || !this.enabled || !this.finalUIStartup) {
return;
}
- this.loaded_ = true;
+ this.loaded = true;
- let forceLocal = Preferences.get(FORCELOCAL_PREF,
- Services.appinfo.name == "B2G" ? false : true);
- Preferences.set(FORCELOCAL_PREF, forceLocal);
-
- if (!forceLocal) {
+ if (!prefs.forceLocal) {
// See bug 800138. Because the first socket that opens with
// force-local=false fails, we open a dummy socket that will fail.
// keepWhenOffline=true so that it still work when offline (local).
// This allows the following attempt by Marionette to open a socket
// to succeed.
let insaneSacrificialGoat =
new ServerSocket(666, Ci.nsIServerSocket.KeepWhenOffline, 4);
insaneSacrificialGoat.asyncListen(this);
}
- let port = Preferences.get(PORT_PREF, DEFAULT_PORT);
-
- let s;
+ let so;
try {
Cu.import("chrome://marionette/content/server.js");
- s = new server.TCPListener(port, forceLocal);
- s.start();
- this.logger.info(`Listening on port ${s.port}`);
+ so = new server.TCPListener(prefs.port, prefs.forceLocal);
+ so.start();
+ this.logger.info(`Listening on port ${so.port}`);
} catch (e) {
this.logger.error(`Error on starting server: ${e}`);
dump(e.toString() + "\n" + e.stack + "\n");
} finally {
- if (s) {
- this.server = s;
+ if (so) {
+ this.server = so;
}
}
};
-MarionetteComponent.prototype.uninit = function() {
- if (!this.loaded_) {
+MarionetteComponent.prototype.uninit = function () {
+ if (!this.loaded) {
return;
}
this.server.stop();
- this.loaded_ = false;
+ this.loaded = false;
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MarionetteComponent]);
--- a/testing/marionette/moz.build
+++ b/testing/marionette/moz.build
@@ -1,13 +1,15 @@
# 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/.
DIRS += ["components"]
+JS_PREFERENCE_FILES += ["prefs.js"]
+
JAR_MANIFESTS += ["jar.mn"]
MARIONETTE_UNIT_MANIFESTS += ["harness/marionette_harness/tests/unit/unit-tests.ini"]
MARIONETTE_WEBAPI_MANIFESTS += ["harness/marionette_harness/tests/webapi-tests.ini"]
XPCSHELL_TESTS_MANIFESTS += ["unit.ini"]
with Files("**"):
BUG_COMPONENT = ("Testing", "Marionette")
new file mode 100644
--- /dev/null
+++ b/testing/marionette/prefs.js
@@ -0,0 +1,16 @@
+/* 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/. */
+
+// Whether or not Marionette is enabled.
+pref("marionette.enabled", false);
+
+// Port to start Marionette server on.
+pref("marionette.port", 2828);
+
+// Forces client connections to come from a loopback device.
+pref("marionette.forcelocal", true);
+
+// Marionette logging verbosity. Allowed values are "fatal", "error",
+// "warn", "info", "config", "debug", and "trace".
+pref("marionette.log.level", "info");
--- a/testing/web-platform/harness/wptrunner/browsers/firefox.py
+++ b/testing/web-platform/harness/wptrunner/browsers/firefox.py
@@ -143,18 +143,18 @@ class FirefoxBrowser(Browser):
env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
locations = ServerLocations(filename=os.path.join(here, "server-locations.txt"))
preferences = self.load_prefs()
self.profile = FirefoxProfile(locations=locations,
preferences=preferences)
- self.profile.set_preferences({"marionette.defaultPrefs.enabled": True,
- "marionette.defaultPrefs.port": self.marionette_port,
+ self.profile.set_preferences({"marionette.enabled": True,
+ "marionette.port": self.marionette_port,
"dom.disable_open_during_load": False,
"network.dns.localDomains": ",".join(hostnames),
"network.proxy.type": 0,
"places.history.enabled": False})
if self.e10s:
self.profile.set_preferences({"browser.tabs.remote.autostart": True})
# Bug 1262954: winxp + e10s, disable hwaccel
--- a/tools/lint/eslint/modules.json
+++ b/tools/lint/eslint/modules.json
@@ -50,17 +50,17 @@
"controller.js": ["MozMillController", "globalEventRegistry", "sleep", "windowMap"],
"cookies.js": ["Cookies"],
"CoverageUtils.jsm": ["CoverageCollector"],
"CrashManagerTest.jsm": ["configureLogging", "getManager", "sleep", "TestingCrashManager"],
"dbg-client.jsm": ["DebuggerTransport", "DebuggerClient", "RootClient", "LongStringClient", "EnvironmentClient", "ObjectClient"],
"dbg-server.jsm": ["DebuggerServer", "ActorPool", "OriginalLocation"],
"debug.js": ["NS_ASSERT"],
"declined.js": ["DeclinedEngines"],
- "dispatcher.js": ["Dispatcher"],
+ "dispatcher.js": ["dispatcher"],
"distribution.js": ["DistributionCustomizer"],
"DNSTypes.jsm": ["DNS_QUERY_RESPONSE_CODES", "DNS_AUTHORITATIVE_ANSWER_CODES", "DNS_CLASS_CODES", "DNS_RECORD_TYPES"],
"doctor.js": ["Doctor"],
"dom.js": ["getAttributes"],
"DOMRequestHelper.jsm": ["DOMRequestIpcHelper"],
"DownloadCore.jsm": ["Download", "DownloadSource", "DownloadTarget", "DownloadError", "DownloadSaver", "DownloadCopySaver", "DownloadLegacySaver", "DownloadPDFSaver"],
"DownloadList.jsm": ["DownloadList", "DownloadCombinedList", "DownloadSummary"],
"E10SAddonsRollout.jsm": ["isAddonPartOfE10SRollout"],