Bug 1169290 - Convert MarionetteComponent to a class. r?maja_zf draft
authorAndreas Tolfsen <ato@sny.no>
Sat, 27 Jan 2018 18:39:47 +0000
changeset 753891 f49e626aac8b73bdb2f1ba53eb4c90cbb6deb4a0
parent 753890 7e664c78991e82af54cee3470cc7f970a19dc5f1
child 753892 b7bc98d4dcadb71e7b8c312fa2b20a638048d94c
push id98715
push userbmo:ato@sny.no
push dateMon, 12 Feb 2018 16:37:16 +0000
reviewersmaja_zf
bugs1169290
milestone60.0a1
Bug 1169290 - Convert MarionetteComponent to a class. r?maja_zf Separate MarionetteComponent from the XPCOM component so it can be made a class, as XPCOM descriptions must override the prototype. This patch makes no behavioural changes to MarionetteComponent as such, apart from converting it to a class. It introduces a new _xpcom_factory called MarionetteFactory, which only job currently is to construct the MarionetteComponent class. We will later in this patch series need the factory to decide what type of nsIMarionette implementation to provide depending on whether Marionette is loaded in the main- or the child process. MozReview-Commit-ID: 72Zb6QEFMK
testing/marionette/components/marionette.js
--- a/testing/marionette/components/marionette.js
+++ b/testing/marionette/components/marionette.js
@@ -14,19 +14,16 @@ ChromeUtils.defineModuleGetter(this, "Lo
 ChromeUtils.defineModuleGetter(this, "Preferences",
     "resource://gre/modules/Preferences.jsm");
 XPCOMUtils.defineLazyGetter(this, "log", () => {
   let log = Log.repository.getLogger("Marionette");
   log.addAppender(new Log.DumpAppender());
   return log;
 });
 
-const MARIONETTE_CONTRACT_ID = "@mozilla.org/remote/marionette;1";
-const MARIONETTE_CID = Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}");
-
 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 DEFAULT_LOG_LEVEL = "info";
 
 // Complements -marionette flag for starting the Marionette server.
@@ -133,176 +130,199 @@ const prefs = {
         for (let prefName of Object.keys(prefs)) {
           Preferences.set(prefName, prefs[prefName]);
         }
       }
     }
   },
 };
 
-function MarionetteComponent() {
-  this.running = false;
-  this.server = null;
+class MarionetteComponent {
+  constructor() {
+    this.running = false;
+    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;
+
+    log.level = prefs.logLevel;
+
+    this.enabled = env.exists(ENV_ENABLED);
+    if (this.enabled) {
+      log.info(`Enabled via ${ENV_ENABLED}`);
+    }
+  }
+
+  // Handle -marionette flag
+  handle(cmdLine) {
+    if (!this.enabled && cmdLine.handleFlag("marionette", false)) {
+      this.enabled = true;
+      log.debug("Enabled via flag");
+    }
+  }
+
+  observe(subject, topic) {
+    log.debug(`Received observer notification ${topic}`);
+
+    switch (topic) {
+      case "profile-after-change":
+        Services.obs.addObserver(this, "command-line-startup");
+        Services.obs.addObserver(this, "sessionstore-windows-restored");
 
-  // holds reference to ChromeWindow
-  // used to run GFX sanity tests on Windows
-  this.gfxWindow = null;
+        prefs.readFromEnvironment(ENV_PRESERVE_PREFS);
+        break;
+
+      // In safe mode the command line handlers are getting parsed after the
+      // safe mode dialog has been closed. To allow Marionette to start
+      // earlier, use the CLI startup observer notification for
+      // special-cased handlers, which gets fired before the dialog appears.
+      case "command-line-startup":
+        Services.obs.removeObserver(this, topic);
+        this.handle(subject);
+
+        // We want to suppress the modal dialog that's shown
+        // when starting up in safe-mode to enable testing.
+        if (this.enabled && Services.appinfo.inSafeMode) {
+          Services.obs.addObserver(this, "domwindowopened");
+        }
+
+        break;
+
+      case "domwindowclosed":
+        if (this.gfxWindow === null || subject === this.gfxWindow) {
+          Services.obs.removeObserver(this, topic);
+
+          Services.obs.addObserver(this, "xpcom-shutdown");
+          this.finalUIStartup = true;
+          this.init();
+        }
+        break;
+
+      case "domwindowopened":
+        Services.obs.removeObserver(this, topic);
+        this.suppressSafeModeDialog(subject);
+        break;
+
+      case "sessionstore-windows-restored":
+        Services.obs.removeObserver(this, topic);
 
-  // indicates that all pending window checks have been completed
-  // and that we are ready to start the Marionette server
-  this.finalUIStartup = false;
+        // 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) {
+          Services.obs.addObserver(this, "domwindowclosed");
+        } else {
+          Services.obs.addObserver(this, "xpcom-shutdown");
+          this.finalUIStartup = true;
+          this.init();
+        }
+
+        break;
+
+      case "xpcom-shutdown":
+        Services.obs.removeObserver(this, "xpcom-shutdown");
+        this.uninit();
+        break;
+    }
+  }
+
+  suppressSafeModeDialog(win) {
+    win.addEventListener("load", () => {
+      if (win.document.getElementById("safeModeDialog")) {
+        // accept the dialog to start in safe-mode
+        log.debug("Safe mode detected, supressing dialog");
+        win.setTimeout(() => {
+          win.document.documentElement.getButton("accept").click();
+        });
+      }
+    }, {once: true});
+  }
 
-  log.level = prefs.logLevel;
+  init() {
+    if (this.running || !this.enabled || !this.finalUIStartup) {
+      return;
+    }
+
+    // wait for delayed startup...
+    Services.tm.idleDispatchToMainThread(async () => {
+      // ... and for startup tests
+      let startupRecorder = Promise.resolve();
+      if ("@mozilla.org/test/startuprecorder;1" in Cc) {
+        startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"]
+            .getService().wrappedJSObject.done;
+      }
+      await startupRecorder;
 
-  this.enabled = env.exists(ENV_ENABLED);
-  if (this.enabled) {
-    log.info(`Enabled via ${ENV_ENABLED}`);
+      try {
+        ChromeUtils.import("chrome://marionette/content/server.js");
+        let listener = new server.TCPListener(prefs.port);
+        listener.start();
+        log.info(`Listening on port ${listener.port}`);
+        this.server = listener;
+        this.running = true;
+      } catch (e) {
+        log.fatal("Remote protocol server failed to start", e);
+        Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
+      }
+    });
+  }
+
+  uninit() {
+    if (!this.running) {
+      return;
+    }
+    this.server.stop();
+    this.running = false;
+  }
+
+  get QueryInterface() {
+    return XPCOMUtils.generateQI([
+      Ci.nsICommandLineHandler,
+      Ci.nsIMarionette,
+    ]);
   }
 }
 
-MarionetteComponent.prototype = {
+const MarionetteFactory = {
+  createInstance(outer, iid) {
+    if (outer) {
+      throw Cr.NS_ERROR_NO_AGGREGATION;
+    }
+
+    let marionette = new MarionetteComponent();
+    return marionette.QueryInterface(iid);
+  },
+};
+
+function Marionette() {}
+
+Marionette.prototype = {
   classDescription: "Marionette component",
-  classID: MARIONETTE_CID,
-  contractID: MARIONETTE_CONTRACT_ID,
-  QueryInterface: XPCOMUtils.generateQI([
-    Ci.nsICommandLineHandler,
-    Ci.nsIMarionette,
-  ]),
-  // eslint-disable-next-line camelcase
+  classID: Components.ID("{786a1369-dca5-4adc-8486-33d23c88010a}"),
+  contractID: "@mozilla.org/remote/marionette;1",
+
+  /* eslint-disable camelcase */
+  _xpcom_factory: MarionetteFactory,
+
   _xpcom_categories: [
     {category: "command-line-handler", entry: "b-marionette"},
     {category: "profile-after-change", service: true},
   ],
+  /* eslint-enable camelcase */
+
   helpInfo: "  --marionette       Enable remote control server.\n",
 };
 
-// Handle -marionette flag
-MarionetteComponent.prototype.handle = function(cmdLine) {
-  if (!this.enabled && cmdLine.handleFlag("marionette", false)) {
-    this.enabled = true;
-    log.debug("Enabled via flag");
-  }
-};
-
-MarionetteComponent.prototype.observe = function(subject, topic) {
-  log.debug(`Received observer notification ${topic}`);
-
-  switch (topic) {
-    case "profile-after-change":
-      Services.obs.addObserver(this, "command-line-startup");
-      Services.obs.addObserver(this, "sessionstore-windows-restored");
-
-      prefs.readFromEnvironment(ENV_PRESERVE_PREFS);
-      break;
-
-    // In safe mode the command line handlers are getting parsed after the
-    // safe mode dialog has been closed. To allow Marionette to start
-    // earlier, use the CLI startup observer notification for
-    // special-cased handlers, which gets fired before the dialog appears.
-    case "command-line-startup":
-      Services.obs.removeObserver(this, topic);
-      this.handle(subject);
-
-      // We want to suppress the modal dialog that's shown
-      // when starting up in safe-mode to enable testing.
-      if (this.enabled && Services.appinfo.inSafeMode) {
-        Services.obs.addObserver(this, "domwindowopened");
-      }
-
-      break;
-
-    case "domwindowclosed":
-      if (this.gfxWindow === null || subject === this.gfxWindow) {
-        Services.obs.removeObserver(this, topic);
-
-        Services.obs.addObserver(this, "xpcom-shutdown");
-        this.finalUIStartup = true;
-        this.init();
-      }
-      break;
-
-    case "domwindowopened":
-      Services.obs.removeObserver(this, topic);
-      this.suppressSafeModeDialog(subject);
-      break;
-
-    case "sessionstore-windows-restored":
-      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.
-      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) {
-        Services.obs.addObserver(this, "domwindowclosed");
-      } else {
-        Services.obs.addObserver(this, "xpcom-shutdown");
-        this.finalUIStartup = true;
-        this.init();
-      }
-
-      break;
-
-    case "xpcom-shutdown":
-      Services.obs.removeObserver(this, "xpcom-shutdown");
-      this.uninit();
-      break;
-  }
-};
-
-MarionetteComponent.prototype.suppressSafeModeDialog = function(win) {
-  win.addEventListener("load", () => {
-    if (win.document.getElementById("safeModeDialog")) {
-      // accept the dialog to start in safe-mode
-      log.debug("Safe mode detected, supressing dialog");
-      win.setTimeout(() => {
-        win.document.documentElement.getButton("accept").click();
-      });
-    }
-  }, {once: true});
-};
-
-MarionetteComponent.prototype.init = function() {
-  if (this.running || !this.enabled || !this.finalUIStartup) {
-    return;
-  }
-
-  // wait for delayed startup...
-  Services.tm.idleDispatchToMainThread(async () => {
-    // ... and for startup tests
-    let startupRecorder = Promise.resolve();
-    if ("@mozilla.org/test/startuprecorder;1" in Cc) {
-      startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"]
-          .getService().wrappedJSObject.done;
-    }
-    await startupRecorder;
-
-    try {
-      ChromeUtils.import("chrome://marionette/content/server.js");
-      let listener = new server.TCPListener(prefs.port);
-      listener.start();
-      log.info(`Listening on port ${listener.port}`);
-      this.server = listener;
-      this.running = true;
-    } catch (e) {
-      log.fatal("Remote protocol server failed to start", e);
-      Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
-    }
-  });
-};
-
-MarionetteComponent.prototype.uninit = function() {
-  if (!this.running) {
-    return;
-  }
-  this.server.stop();
-  this.running = false;
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MarionetteComponent]);
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Marionette]);