Bug 1344748 - Make Marionette respect marionette.enabled pref; r?whimboo draft
authorAndreas Tolfsen <ato@mozilla.com>
Thu, 09 Mar 2017 20:15:32 +0000
changeset 504649 1ed994b38f4ad1e0ccb0ea90cd0bc5c730187648
parent 504648 0a05278baa47e54188126c03589a211cee9f01c3
child 504650 5aacfaaa4c4683b997a34d7256cb32c295d69286
push id50832
push userbmo:ato@mozilla.com
push dateFri, 24 Mar 2017 14:10:32 +0000
reviewerswhimboo
bugs1344748
milestone55.0a1
Bug 1344748 - Make Marionette respect marionette.enabled pref; r?whimboo This removes the internal enabledness state tracking in MarionetteComponent in favour of the marionette.enabled preference. When the marionette.enabled preference changes, Marionette is enabled or disabled. Depending on whether all the initialisation conditions have been met, Marionette is started. If it is running, it is stopped when toggling the preference back off. MozReview-Commit-ID: jQFYZhULqO
testing/marionette/components/marionette.js
--- a/testing/marionette/components/marionette.js
+++ b/testing/marionette/components/marionette.js
@@ -9,16 +9,25 @@ const {Constructor: CC, interfaces: Ci, 
 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 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";
+const PREF_LOG_LEVEL_FALLBACK = "marionette.logging";
+const PREF_FORCE_LOCAL = "marionette.forcelocal";
+const PREF_FORCE_LOCAL_FALLBACK = "marionette.force-local";
+
 const DEFAULT_PORT = 2828;
 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],
@@ -45,30 +54,25 @@ const ServerSocket = CC("@mozilla.org/ne
     "initSpecialConnection");
 
 // 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 () {
-    let fallback = Preferences.get("marionette.defaultPrefs.enabled", false);
-    return Preferences.get("marionette.enabled", fallback);
-  },
-
   get port () {
-    let fallback = Preferences.get("marionette.defaultPrefs.port", DEFAULT_PORT);
-    return Preferences.get("marionette.port", fallback);
+    let fallback = Preferences.get(PREF_PORT_FALLBACK, DEFAULT_PORT);
+    return Preferences.get(PREF_PORT, fallback);
   },
 
   get logLevel () {
     let level = DEFAULT_LOG_LEVEL;
-    let fallback = Preferences.get("marionette.logging", level);
-    let p = Preferences.get("marionette.log.level", fallback);
+    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);
         }
@@ -81,18 +85,18 @@ const prefs = {
         }
         break;
     }
 
     return level;
   },
 
   get forceLocal () {
-    let fallback = Preferences.get("marionette.force-local", true);
-    return Preferences.get("marionette.forcelocal", fallback);
+    let fallback = Preferences.get(PREF_FORCE_LOCAL_FALLBACK, true);
+    return Preferences.get(PREF_FORCE_LOCAL, fallback);
   },
 
   readFromEnvironment (key) {
     const env = Cc["@mozilla.org/process/environment;1"]
         .getService(Ci.nsIEnvironment);
 
     if (env.exists(key)) {
       let prefs;
@@ -110,37 +114,39 @@ const prefs = {
           Preferences.set("marionette." + prefName, prefs[prefName]);
         }
       }
     }
   },
 };
 
 function MarionetteComponent() {
-  // keeps track of whether Marionette is available,
-  // either as a result of the marionette.enabled pref
-  // or by use of the --marionette flag
-  this.enabled = prefs.enabled;
-
   // guards against this component
   // being initialised multiple times
   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;
 
   // indicates that all pending window checks have been completed
   // and that we are ready to start the Marionette server
   this.finalUIStartup = false;
 
   this.logger = this.setupLogger(prefs.logLevel);
+  Services.prefs.addObserver(PREF_ENABLED, this, false);
+
+  if (Preferences.isSet(PREF_ENABLED_FALLBACK)) {
+    this.logger.warn(`Deprecated preference ${PREF_ENABLED_FALLBACK} detected, ` +
+        `please use ${PREF_ENABLED}`);
+    Preferences.set(PREF_ENABLED, Preferences.get(PREF_ENABLED_FALLBACK));
+  }
 }
 
 MarionetteComponent.prototype = {
   classDescription: "Marionette component",
   classID: MARIONETTE_CID,
   contractID: MARIONETTE_CONTRACT_ID,
   QueryInterface: XPCOMUtils.generateQI(
       [Ci.nsICommandLineHandler, Ci.nsIObserver]),
@@ -158,23 +164,39 @@ MarionetteComponent.prototype.onStopList
   this.logger.info(`onStopListening for Marionette dummy socket, code ${status}`);
   socket.close();
 };
 
 // Handle --marionette flag
 MarionetteComponent.prototype.handle = function (cmdLine) {
   if (cmdLine.handleFlag("marionette", false)) {
     this.enabled = true;
-    this.logger.debug("Marionette enabled via command-line flag");
-    this.init();
   }
 };
 
+Object.defineProperty(MarionetteComponent.prototype, "enabled", {
+  set (value) {
+    Preferences.set(PREF_ENABLED, value);
+  },
+
+  get () {
+    return Preferences.get(PREF_ENABLED);
+  },
+});
+
 MarionetteComponent.prototype.observe = function (subject, topic, data) {
   switch (topic) {
+    case "nsPref:changed":
+      if (Preferences.get(PREF_ENABLED)) {
+        this.init();
+      } else {
+        this.uninit();
+      }
+      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", false);
 
       prefs.readFromEnvironment(ENV_PREF_VAR);
 
       if (this.enabled) {
@@ -251,18 +273,16 @@ MarionetteComponent.prototype.suppressSa
   }, {once: true});
 };
 
 MarionetteComponent.prototype.init = function () {
   if (this.running || !this.enabled || !this.finalUIStartup) {
     return;
   }
 
-  this.running = true;
-
   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);
@@ -276,21 +296,23 @@ MarionetteComponent.prototype.init = fun
     s.start();
     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 {
     if (s) {
       this.server = s;
+      this.running = true;
     }
   }
 };
 
 MarionetteComponent.prototype.uninit = function () {
   if (!this.running) {
     return;
   }
   this.server.stop();
+  this.logger.info("Ceased listening");
   this.running = false;
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MarionetteComponent]);