Bug 1355888 - Add env var MOZ_MARIONETTE to start server; r?whimboo,maja_zf draft
authorAndreas Tolfsen <ato@mozilla.com>
Sat, 15 Apr 2017 01:50:29 +0100
changeset 571909 639c79dbbb6c8f8943cb4e781889869c3abe85d4
parent 571808 82c2d17e74ef9cdf38a5d5ac4eb3ae846ec30ba4
child 571910 ef7dcffe78ca40f880ade13f7cfaadabffdaed9f
push id56952
push userbmo:ato@mozilla.com
push dateWed, 03 May 2017 13:42:09 +0000
reviewerswhimboo, maja_zf
bugs1355888
milestone55.0a1
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
testing/marionette/components/marionette.js
testing/marionette/server.js
--- 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;