Bug 1558298: Part 8 - Convert SpecialPowersObserverAPI and sub-classes to ES6 classes. r=nika
☠☠ backed out by f9bf5e4b0b4f ☠ ☠
authorKris Maglione <maglione.k@gmail.com>
Mon, 10 Jun 2019 15:42:36 -0700
changeset 543719 6ccaa25367f28c27c27746593db3bd5cfaed5f57
parent 543718 d27574cfbb0ed580612d7f468f804aa7819fed21
child 543720 0f6b382f06261055566d91b84866a51a80e474bd
push id2131
push userffxbld-merge
push dateMon, 26 Aug 2019 18:30:20 +0000
treeherdermozilla-release@b19ffb3ca153 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1558298
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1558298: Part 8 - Convert SpecialPowersObserverAPI and sub-classes to ES6 classes. r=nika Differential Revision: https://phabricator.services.mozilla.com/D34597
testing/specialpowers/content/SpecialPowersObserver.jsm
testing/specialpowers/content/SpecialPowersObserverAPI.js
--- a/testing/specialpowers/content/SpecialPowersObserver.jsm
+++ b/testing/specialpowers/content/SpecialPowersObserver.jsm
@@ -47,151 +47,233 @@ const FRAME_SCRIPTS = [
   "resource://specialpowers/specialpowersFrameScript.js",
   "resource://specialpowers/MozillaLogger.js",
 ];
 
 
 // Glue to add in the observer API to this object.  This allows us to share code with chrome tests
 Services.scriptloader.loadSubScript("resource://specialpowers/SpecialPowersObserverAPI.js");
 
-/* XPCOM gunk */
-function SpecialPowersObserver() {
-  this._initialized = false;
-  this._messageManager = Services.mm;
-  this._serviceWorkerListener = null;
-}
+class SpecialPowersObserver extends SpecialPowersObserverAPI {
+  constructor() {
+    super();
+    this._initialized = false;
+    this._messageManager = Services.mm;
+    this._serviceWorkerListener = null;
+  }
 
-
-SpecialPowersObserver.prototype = new SpecialPowersObserverAPI();
-
-SpecialPowersObserver.prototype.QueryInterface = ChromeUtils.generateQI([Ci.nsIObserver]);
+  observe(aSubject, aTopic, aData) {
+    if (aTopic == "http-on-modify-request") {
+      if (aSubject instanceof Ci.nsIChannel) {
+        let uri = aSubject.URI.spec;
+        this._sendAsyncMessage("specialpowers-http-notify-request", { uri });
+      }
+    } else {
+      this._observe(aSubject, aTopic, aData);
+    }
+  }
 
-SpecialPowersObserver.prototype.observe = function(aSubject, aTopic, aData) {
-  if (aTopic == "http-on-modify-request") {
-    if (aSubject instanceof Ci.nsIChannel) {
-      let uri = aSubject.URI.spec;
-      this._sendAsyncMessage("specialpowers-http-notify-request", { uri });
+  _loadFrameScript() {
+    // Register for any messages our API needs us to handle
+    for (let name of MESSAGE_NAMES) {
+      this._messageManager.addMessageListener(name, this);
+    }
+
+    for (let script of FRAME_SCRIPTS) {
+      this._messageManager.loadFrameScript(script, true);
     }
-  } else {
-    this._observe(aSubject, aTopic, aData);
+    this._createdFiles = null;
   }
-};
+
+  _unloadFrameScript() {
+    for (let name of MESSAGE_NAMES) {
+      this._messageManager.removeMessageListener(name, this);
+    }
 
-SpecialPowersObserver.prototype._loadFrameScript = function() {
-  // Register for any messages our API needs us to handle
-  for (let name of MESSAGE_NAMES) {
-    this._messageManager.addMessageListener(name, this);
+    for (let script of FRAME_SCRIPTS) {
+      this._messageManager.removeDelayedFrameScript(script);
+    }
+  }
+
+  _sendAsyncMessage(msgname, msg) {
+    this._messageManager.broadcastAsyncMessage(msgname, msg);
   }
 
-  for (let script of FRAME_SCRIPTS) {
-    this._messageManager.loadFrameScript(script, true);
-  }
-  this._createdFiles = null;
-};
-
-SpecialPowersObserver.prototype._unloadFrameScript = function() {
-  for (let name of MESSAGE_NAMES) {
-    this._messageManager.removeMessageListener(name, this);
+  _receiveMessage(aMessage) {
+    return this._receiveMessageAPI(aMessage);
   }
 
-  for (let script of FRAME_SCRIPTS) {
-    this._messageManager.removeDelayedFrameScript(script);
-  }
-};
+  init() {
+    if (this._initialized) {
+      throw new Error("Already initialized");
+    }
+
+    // Register special testing modules.
+    var testsURI = Services.dirsvc.get("ProfD", Ci.nsIFile);
+    testsURI.append("tests.manifest");
+    var manifestFile = Services.io.newFileURI(testsURI).
+                         QueryInterface(Ci.nsIFileURL).file;
+
+    Components.manager.QueryInterface(Ci.nsIComponentRegistrar).
+                   autoRegister(manifestFile);
+
+    Services.obs.addObserver(this, "http-on-modify-request");
 
-SpecialPowersObserver.prototype._sendAsyncMessage = function(msgname, msg) {
-  this._messageManager.broadcastAsyncMessage(msgname, msg);
-};
+    // We would like to check that tests don't leave service workers around
+    // after they finish, but that information lives in the parent process.
+    // Ideally, we'd be able to tell the child processes whenever service
+    // workers are registered or unregistered so they would know at all times,
+    // but service worker lifetimes are complicated enough to make that
+    // difficult. For the time being, let the child process know when a test
+    // registers a service worker so it can ask, synchronously, at the end if
+    // the service worker had unregister called on it.
+    let swm = Cc["@mozilla.org/serviceworkers/manager;1"]
+                .getService(Ci.nsIServiceWorkerManager);
+    let self = this;
+    this._serviceWorkerListener = {
+      onRegister() {
+        self.onRegister();
+      },
 
-SpecialPowersObserver.prototype._receiveMessage = function(aMessage) {
-  return this._receiveMessageAPI(aMessage);
-};
+      onUnregister() {
+        // no-op
+      },
+    };
+    swm.addListener(this._serviceWorkerListener);
 
-SpecialPowersObserver.prototype.init = function() {
-  if (this._initialized) {
-    throw new Error("Already initialized");
+    this._loadFrameScript();
+
+    this._initialized = true;
   }
 
-  // Register special testing modules.
-  var testsURI = Services.dirsvc.get("ProfD", Ci.nsIFile);
-  testsURI.append("tests.manifest");
-  var manifestFile = Services.io.newFileURI(testsURI).
-                       QueryInterface(Ci.nsIFileURL).file;
-
-  Components.manager.QueryInterface(Ci.nsIComponentRegistrar).
-                 autoRegister(manifestFile);
-
-  Services.obs.addObserver(this, "http-on-modify-request");
+  uninit() {
+    if (!this._initialized) {
+      throw new Error("Not initialized");
+    }
+    this._initialized = false;
 
-  // We would like to check that tests don't leave service workers around
-  // after they finish, but that information lives in the parent process.
-  // Ideally, we'd be able to tell the child processes whenever service
-  // workers are registered or unregistered so they would know at all times,
-  // but service worker lifetimes are complicated enough to make that
-  // difficult. For the time being, let the child process know when a test
-  // registers a service worker so it can ask, synchronously, at the end if
-  // the service worker had unregister called on it.
-  let swm = Cc["@mozilla.org/serviceworkers/manager;1"]
-              .getService(Ci.nsIServiceWorkerManager);
-  let self = this;
-  this._serviceWorkerListener = {
-    onRegister() {
-      self.onRegister();
-    },
+    var obs = Services.obs;
+    obs.removeObserver(this, "http-on-modify-request");
+    this._registerObservers._topics.forEach((element) => {
+      obs.removeObserver(this._registerObservers, element);
+    });
+    this._removeProcessCrashObservers();
+
+    let swm = Cc["@mozilla.org/serviceworkers/manager;1"]
+                .getService(Ci.nsIServiceWorkerManager);
+    swm.removeListener(this._serviceWorkerListener);
 
-    onUnregister() {
-      // no-op
-    },
-  };
-  swm.addListener(this._serviceWorkerListener);
-
-  this._loadFrameScript();
+    this._unloadFrameScript();
+  }
 
-  this._initialized = true;
-};
-
-SpecialPowersObserver.prototype.uninit = function() {
-  if (!this._initialized) {
-    throw new Error("Not initialized");
-  }
-  this._initialized = false;
+  _addProcessCrashObservers() {
+    if (this._processCrashObserversRegistered) {
+      return;
+    }
 
-  var obs = Services.obs;
-  obs.removeObserver(this, "http-on-modify-request");
-  this._registerObservers._topics.forEach((element) => {
-    obs.removeObserver(this._registerObservers, element);
-  });
-  this._removeProcessCrashObservers();
+    Services.obs.addObserver(this, "plugin-crashed");
+    Services.obs.addObserver(this, "ipc:content-shutdown");
+    this._processCrashObserversRegistered = true;
+  }
 
-  let swm = Cc["@mozilla.org/serviceworkers/manager;1"]
-              .getService(Ci.nsIServiceWorkerManager);
-  swm.removeListener(this._serviceWorkerListener);
+  _removeProcessCrashObservers() {
+    if (!this._processCrashObserversRegistered) {
+      return;
+    }
 
-  this._unloadFrameScript();
-};
-
-SpecialPowersObserver.prototype._addProcessCrashObservers = function() {
-  if (this._processCrashObserversRegistered) {
-    return;
+    Services.obs.removeObserver(this, "plugin-crashed");
+    Services.obs.removeObserver(this, "ipc:content-shutdown");
+    this._processCrashObserversRegistered = false;
   }
 
-  Services.obs.addObserver(this, "plugin-crashed");
-  Services.obs.addObserver(this, "ipc:content-shutdown");
-  this._processCrashObserversRegistered = true;
-};
+  /**
+   * messageManager callback function
+   * This will get requests from our API in the window and process them in chrome for it
+   **/
+  receiveMessage(aMessage) {
+    switch (aMessage.name) {
+      case "SPPingService":
+        if (aMessage.json.op == "ping") {
+          aMessage.target.frameLoader
+                  .messageManager
+                  .sendAsyncMessage("SPPingService", { op: "pong" });
+        }
+        break;
+      case "SpecialPowers.Quit":
+        Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
+        break;
+      case "SpecialPowers.Focus":
+        aMessage.target.focus();
+        break;
+      case "SpecialPowers.CreateFiles":
+        let filePaths = [];
+        if (!this._createdFiles) {
+          this._createdFiles = [];
+        }
+        let createdFiles = this._createdFiles;
+        try {
+          let promises = [];
+          aMessage.data.forEach(function(request) {
+            const filePerms = 0o666;
+            let testFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
+            if (request.name) {
+              testFile.appendRelativePath(request.name);
+            } else {
+              testFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, filePerms);
+            }
+            let outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
+            outStream.init(testFile, 0x02 | 0x08 | 0x20, // PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE
+                           filePerms, 0);
+            if (request.data) {
+              outStream.write(request.data, request.data.length);
+            }
+            outStream.close();
+            promises.push(File.createFromFileName(testFile.path, request.options).then(function(file) {
+              filePaths.push(file);
+            }));
+            createdFiles.push(testFile);
+          });
 
-SpecialPowersObserver.prototype._removeProcessCrashObservers = function() {
-  if (!this._processCrashObserversRegistered) {
-    return;
+          Promise.all(promises).then(function() {
+            aMessage.target.frameLoader
+                    .messageManager
+                    .sendAsyncMessage("SpecialPowers.FilesCreated", filePaths);
+          }, function(e) {
+            aMessage.target.frameLoader
+                    .messageManager
+                    .sendAsyncMessage("SpecialPowers.FilesError", e.toString());
+          });
+        } catch (e) {
+            aMessage.target.frameLoader
+                    .messageManager
+                    .sendAsyncMessage("SpecialPowers.FilesError", e.toString());
+        }
+
+        break;
+      case "SpecialPowers.RemoveFiles":
+        if (this._createdFiles) {
+          this._createdFiles.forEach(function(testFile) {
+            try {
+              testFile.remove(false);
+            } catch (e) {}
+          });
+          this._createdFiles = null;
+        }
+        break;
+      default:
+        return this._receiveMessage(aMessage);
+    }
+    return undefined;
   }
 
-  Services.obs.removeObserver(this, "plugin-crashed");
-  Services.obs.removeObserver(this, "ipc:content-shutdown");
-  this._processCrashObserversRegistered = false;
-};
+  onRegister() {
+    this._sendAsyncMessage("SPServiceWorkerRegistered",
+      { registered: true });
+  }
+}
 
 SpecialPowersObserver.prototype._registerObservers = {
   _self: null,
   _topics: [],
   _add(topic) {
     if (!this._topics.includes(topic)) {
       this._topics.push(topic);
       Services.obs.addObserver(this, topic);
@@ -214,93 +296,8 @@ SpecialPowersObserver.prototype._registe
           },
           type: permission.type,
         };
       default:
         this._self._sendAsyncMessage("specialpowers-" + aTopic, msg);
     }
   },
 };
-
-/**
- * messageManager callback function
- * This will get requests from our API in the window and process them in chrome for it
- **/
-SpecialPowersObserver.prototype.receiveMessage = function(aMessage) {
-  switch (aMessage.name) {
-    case "SPPingService":
-      if (aMessage.json.op == "ping") {
-        aMessage.target.frameLoader
-                .messageManager
-                .sendAsyncMessage("SPPingService", { op: "pong" });
-      }
-      break;
-    case "SpecialPowers.Quit":
-      Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
-      break;
-    case "SpecialPowers.Focus":
-      aMessage.target.focus();
-      break;
-    case "SpecialPowers.CreateFiles":
-      let filePaths = [];
-      if (!this._createdFiles) {
-        this._createdFiles = [];
-      }
-      let createdFiles = this._createdFiles;
-      try {
-        let promises = [];
-        aMessage.data.forEach(function(request) {
-          const filePerms = 0o666;
-          let testFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
-          if (request.name) {
-            testFile.appendRelativePath(request.name);
-          } else {
-            testFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, filePerms);
-          }
-          let outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
-          outStream.init(testFile, 0x02 | 0x08 | 0x20, // PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE
-                         filePerms, 0);
-          if (request.data) {
-            outStream.write(request.data, request.data.length);
-          }
-          outStream.close();
-          promises.push(File.createFromFileName(testFile.path, request.options).then(function(file) {
-            filePaths.push(file);
-          }));
-          createdFiles.push(testFile);
-        });
-
-        Promise.all(promises).then(function() {
-          aMessage.target.frameLoader
-                  .messageManager
-                  .sendAsyncMessage("SpecialPowers.FilesCreated", filePaths);
-        }, function(e) {
-          aMessage.target.frameLoader
-                  .messageManager
-                  .sendAsyncMessage("SpecialPowers.FilesError", e.toString());
-        });
-      } catch (e) {
-          aMessage.target.frameLoader
-                  .messageManager
-                  .sendAsyncMessage("SpecialPowers.FilesError", e.toString());
-      }
-
-      break;
-    case "SpecialPowers.RemoveFiles":
-      if (this._createdFiles) {
-        this._createdFiles.forEach(function(testFile) {
-          try {
-            testFile.remove(false);
-          } catch (e) {}
-        });
-        this._createdFiles = null;
-      }
-      break;
-    default:
-      return this._receiveMessage(aMessage);
-  }
-  return undefined;
-};
-
-SpecialPowersObserver.prototype.onRegister = function() {
-  this._sendAsyncMessage("SPServiceWorkerRegistered",
-    { registered: true });
-};
--- a/testing/specialpowers/content/SpecialPowersObserverAPI.js
+++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js
@@ -22,23 +22,16 @@ this.SpecialPowersError = function(aMsg)
   this.name = "SpecialPowersError";
 };
 SpecialPowersError.prototype = Object.create(Error.prototype);
 
 SpecialPowersError.prototype.toString = function() {
   return `${this.name}: ${this.message}`;
 };
 
-this.SpecialPowersObserverAPI = function SpecialPowersObserverAPI() {
-  this._crashDumpDir = null;
-  this._processCrashObserversRegistered = false;
-  this._chromeScriptListeners = [];
-  this._extensions = new Map();
-};
-
 function parseKeyValuePairs(text) {
   var lines = text.split("\n");
   var data = {};
   for (let i = 0; i < lines.length; i++) {
     if (lines[i] == "")
       continue;
 
     // can't just .split() because the value might contain = characters
@@ -79,17 +72,23 @@ function getTestPlugin(pluginName) {
     if (tag.name == name) {
       return tag;
     }
   }
 
   return null;
 }
 
-SpecialPowersObserverAPI.prototype = {
+class SpecialPowersObserverAPI {
+  constructor() {
+    this._crashDumpDir = null;
+    this._processCrashObserversRegistered = false;
+    this._chromeScriptListeners = [];
+    this._extensions = new Map();
+  }
 
   _observe(aSubject, aTopic, aData) {
     function addDumpIDToMessage(propertyName) {
       try {
         var id = aSubject.getPropertyAsAString(propertyName);
       } catch (ex) {
         id = null;
       }
@@ -121,43 +120,43 @@ SpecialPowersObserverAPI.prototype = {
             return; // This is a normal shutdown, ignore it
           }
 
           addDumpIDToMessage("dumpID");
         }
         this._sendAsyncMessage("SPProcessCrashService", message);
         break;
     }
-  },
+  }
 
   _getCrashDumpDir() {
     if (!this._crashDumpDir) {
       this._crashDumpDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
       this._crashDumpDir.append("minidumps");
     }
     return this._crashDumpDir;
-  },
+  }
 
   _getPendingCrashDumpDir() {
     if (!this._pendingCrashDumpDir) {
       this._pendingCrashDumpDir = Services.dirsvc.get("UAppData", Ci.nsIFile);
       this._pendingCrashDumpDir.append("Crash Reports");
       this._pendingCrashDumpDir.append("pending");
     }
     return this._pendingCrashDumpDir;
-  },
+  }
 
   _getExtraData(dumpId) {
     let extraFile = this._getCrashDumpDir().clone();
     extraFile.append(dumpId + ".extra");
     if (!extraFile.exists()) {
       return null;
     }
     return parseKeyValuePairsFromFile(extraFile);
-  },
+  }
 
   _deleteCrashDumpFiles(aFilenames) {
     var crashDumpDir = this._getCrashDumpDir();
     if (!crashDumpDir.exists()) {
       return false;
     }
 
     var success = aFilenames.length != 0;
@@ -166,17 +165,17 @@ SpecialPowersObserverAPI.prototype = {
       file.append(crashFilename);
       if (file.exists()) {
         file.remove(false);
       } else {
         success = false;
       }
     });
     return success;
-  },
+  }
 
   _findCrashDumpFiles(aToIgnore) {
     var crashDumpDir = this._getCrashDumpDir();
     var entries = crashDumpDir.exists() && crashDumpDir.directoryEntries;
     if (!entries) {
       return [];
     }
 
@@ -184,37 +183,37 @@ SpecialPowersObserverAPI.prototype = {
     while (entries.hasMoreElements()) {
       var file = entries.nextFile;
       var path = String(file.path);
       if (path.match(/\.(dmp|extra)$/) && !aToIgnore[path]) {
         crashDumpFiles.push(path);
       }
     }
     return crashDumpFiles.concat();
-  },
+  }
 
   _deletePendingCrashDumpFiles() {
     var crashDumpDir = this._getPendingCrashDumpDir();
     var removed = false;
     if (crashDumpDir.exists()) {
       let entries = crashDumpDir.directoryEntries;
       while (entries.hasMoreElements()) {
         let file = entries.nextFile;
         if (file.isFile()) {
           file.remove(false);
           removed = true;
         }
       }
     }
     return removed;
-  },
+  }
 
   _getURI(url) {
     return Services.io.newURI(url);
-  },
+  }
 
   _readUrlAsString(aUrl) {
     // Fetch script content as we can't use scriptloader's loadSubScript
     // to evaluate http:// urls...
     var scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
                              .getService(Ci.nsIScriptableInputStream);
 
     var channel = NetUtil.newChannel({
@@ -244,23 +243,23 @@ SpecialPowersObserverAPI.prototype = {
     if (status == 404) {
       throw new SpecialPowersError(
         "Error while executing chrome script '" + aUrl + "':\n" +
         "The script doesn't exists. Ensure you have registered it in " +
         "'support-files' in your mochitest.ini.");
     }
 
     return output;
-  },
+  }
 
   _sendReply(aMessage, aReplyName, aReplyMsg) {
     let mm = aMessage.target.frameLoader
                      .messageManager;
     mm.sendAsyncMessage(aReplyName, aReplyMsg);
-  },
+  }
 
   _notifyCategoryAndObservers(subject, topic, data) {
     const serviceMarker = "service,";
 
     // First create observers from the category manager.
 
     let observers = [];
 
@@ -290,17 +289,17 @@ SpecialPowersObserverAPI.prototype = {
       }
     }
 
     observers.forEach(function(observer) {
       try {
         observer.observe(subject, topic, data);
       } catch (e) { }
     });
-  },
+  }
 
   /**
    * messageManager callback function
    * This will get requests from our API in the window and process them in chrome for it
    **/
   _receiveMessageAPI(aMessage) { // eslint-disable-line complexity
     // We explicitly return values in the below code so that this function
     // doesn't trigger a flurry of warnings about "does not always return
@@ -693,10 +692,10 @@ SpecialPowersObserverAPI.prototype = {
       default:
         throw new SpecialPowersError(`Unrecognized Special Powers API: ${aMessage.name}`);
     }
 
     // We throw an exception before reaching this explicit return because
     // we should never be arriving here anyway.
     throw new SpecialPowersError("Unreached code"); // eslint-disable-line no-unreachable
     return undefined;
-  },
-};
+  }
+}