]> git.parisson.com Git - pdf.js.git/commitdiff
Add SpecialPowers extension to allow the browser to quit from content, and a bunch...
authorRob Sayre <sayrer@gmail.com>
Thu, 23 Jun 2011 20:12:22 +0000 (13:12 -0700)
committerRob Sayre <sayrer@gmail.com>
Thu, 23 Jun 2011 20:12:22 +0000 (13:12 -0700)
test/browser_manifest.json
test/resources/firefox/extensions/special-powers@mozilla.org/chrome.manifest [new file with mode: 0644]
test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowers.js [new file with mode: 0644]
test/resources/firefox/extensions/special-powers@mozilla.org/components/SpecialPowersObserver.js [new symlink]
test/resources/firefox/extensions/special-powers@mozilla.org/install.rdf [new file with mode: 0644]
test/resources/firefox/user.js
test/test.py
test/test_slave.html

index f11c97c11b4b36f1b76d8c8f62d156272ebba0ec..a396b01ce8fcc0094a450dc70c2119f1860dd17d 100644 (file)
@@ -3,5 +3,10 @@
     "name":"firefox5",
     "path":"/Applications/Firefox.app",
     "type":"firefox"
+   },
+   {
+    "name":"firefox6",
+    "path":"/Users/sayrer/firefoxen/Aurora.app",
+    "type":"firefox"
    }
 ]
\ No newline at end of file
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome.manifest b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome.manifest
new file mode 100644 (file)
index 0000000..614f31c
--- /dev/null
@@ -0,0 +1,4 @@
+content specialpowers chrome/specialpowers/content/
+component {59a52458-13e0-4d93-9d85-a637344f29a1} components/SpecialPowersObserver.js
+contract @mozilla.org/special-powers-observer;1 {59a52458-13e0-4d93-9d85-a637344f29a1}
+category profile-after-change @mozilla.org/special-powers-observer;1 @mozilla.org/special-powers-observer;1
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowers.js b/test/resources/firefox/extensions/special-powers@mozilla.org/chrome/specialpowers/content/specialpowers.js
new file mode 100644 (file)
index 0000000..538b104
--- /dev/null
@@ -0,0 +1,372 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Special Powers code
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Clint Talbert cmtalbert@gmail.com
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK *****/
+/* This code is loaded in every child process that is started by mochitest in
+ * order to be used as a replacement for UniversalXPConnect
+ */
+
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+
+function SpecialPowers(window) {
+  this.window = window;
+  bindDOMWindowUtils(this, window);
+  this._encounteredCrashDumpFiles = [];
+  this._unexpectedCrashDumpFiles = { };
+  this._crashDumpDir = null;
+  this._pongHandlers = [];
+  this._messageListener = this._messageReceived.bind(this);
+  addMessageListener("SPPingService", this._messageListener);
+}
+
+function bindDOMWindowUtils(sp, window) {
+  var util = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                   .getInterface(Ci.nsIDOMWindowUtils);
+  // This bit of magic brought to you by the letters
+  // B Z, and E, S and the number 5.
+  //
+  // Take all of the properties on the nsIDOMWindowUtils-implementing
+  // object, and rebind them onto a new object with a stub that uses
+  // apply to call them from this privileged scope. This way we don't
+  // have to explicitly stub out new methods that appear on
+  // nsIDOMWindowUtils.
+  var proto = Object.getPrototypeOf(util);
+  var target = {};
+  function rebind(desc, prop) {
+    if (prop in desc && typeof(desc[prop]) == "function") {
+      var oldval = desc[prop];
+      desc[prop] = function() { return oldval.apply(util, arguments); };
+    }
+  }
+  for (var i in proto) {
+    var desc = Object.getOwnPropertyDescriptor(proto, i);
+    rebind(desc, "get");
+    rebind(desc, "set");
+    rebind(desc, "value");
+    Object.defineProperty(target, i, desc);
+  }
+  sp.DOMWindowUtils = target;
+}
+
+SpecialPowers.prototype = {
+  toString: function() { return "[SpecialPowers]"; },
+  sanityCheck: function() { return "foo"; },
+
+  // This gets filled in in the constructor.
+  DOMWindowUtils: undefined,
+
+  // Mimic the get*Pref API
+  getBoolPref: function(aPrefName) {
+    return (this._getPref(aPrefName, 'BOOL'));
+  },
+  getIntPref: function(aPrefName) {
+    return (this._getPref(aPrefName, 'INT'));
+  },
+  getCharPref: function(aPrefName) {
+    return (this._getPref(aPrefName, 'CHAR'));
+  },
+  getComplexValue: function(aPrefName, aIid) {
+    return (this._getPref(aPrefName, 'COMPLEX', aIid));
+  },
+
+  // Mimic the set*Pref API
+  setBoolPref: function(aPrefName, aValue) {
+    return (this._setPref(aPrefName, 'BOOL', aValue));
+  },
+  setIntPref: function(aPrefName, aValue) {
+    return (this._setPref(aPrefName, 'INT', aValue));
+  },
+  setCharPref: function(aPrefName, aValue) {
+    return (this._setPref(aPrefName, 'CHAR', aValue));
+  },
+  setComplexValue: function(aPrefName, aIid, aValue) {
+    return (this._setPref(aPrefName, 'COMPLEX', aValue, aIid));
+  },
+
+  // Mimic the clearUserPref API
+  clearUserPref: function(aPrefName) {
+    var msg = {'op':'clear', 'prefName': aPrefName, 'prefType': ""};
+    sendSyncMessage('SPPrefService', msg);
+  },
+
+  // Private pref functions to communicate to chrome
+  _getPref: function(aPrefName, aPrefType, aIid) {
+    var msg = {};
+    if (aIid) {
+      // Overloading prefValue to handle complex prefs
+      msg = {'op':'get', 'prefName': aPrefName, 'prefType':aPrefType, 'prefValue':[aIid]};
+    } else {
+      msg = {'op':'get', 'prefName': aPrefName,'prefType': aPrefType};
+    }
+    return(sendSyncMessage('SPPrefService', msg)[0]);
+  },
+  _setPref: function(aPrefName, aPrefType, aValue, aIid) {
+    var msg = {};
+    if (aIid) {
+      msg = {'op':'set','prefName':aPrefName, 'prefType': aPrefType, 'prefValue': [aIid,aValue]};
+    } else {
+      msg = {'op':'set', 'prefName': aPrefName, 'prefType': aPrefType, 'prefValue': aValue};
+    }
+    return(sendSyncMessage('SPPrefService', msg)[0]);
+  },
+
+  //XXX: these APIs really ought to be removed, they're not e10s-safe.
+  // (also they're pretty Firefox-specific)
+  _getTopChromeWindow: function(window) {
+    return window.QueryInterface(Ci.nsIInterfaceRequestor)
+                 .getInterface(Ci.nsIWebNavigation)
+                 .QueryInterface(Ci.nsIDocShellTreeItem)
+                 .rootTreeItem
+                 .QueryInterface(Ci.nsIInterfaceRequestor)
+                 .getInterface(Ci.nsIDOMWindow)
+                 .QueryInterface(Ci.nsIDOMChromeWindow);
+  },
+  _getDocShell: function(window) {
+    return window.QueryInterface(Ci.nsIInterfaceRequestor)
+                 .getInterface(Ci.nsIWebNavigation)
+                 .QueryInterface(Ci.nsIDocShell);
+  },
+  _getMUDV: function(window) {
+    return this._getDocShell(window).contentViewer
+               .QueryInterface(Ci.nsIMarkupDocumentViewer);
+  },
+  _getAutoCompletePopup: function(window) {
+    return this._getTopChromeWindow(window).document
+                                           .getElementById("PopupAutoComplete");
+  },
+  addAutoCompletePopupEventListener: function(window, listener) {
+    this._getAutoCompletePopup(window).addEventListener("popupshowing",
+                                                        listener,
+                                                        false);
+  },
+  removeAutoCompletePopupEventListener: function(window, listener) {
+    this._getAutoCompletePopup(window).removeEventListener("popupshowing",
+                                                           listener,
+                                                           false);
+  },
+  isBackButtonEnabled: function(window) {
+    return !this._getTopChromeWindow(window).document
+                                      .getElementById("Browser:Back")
+                                      .hasAttribute("disabled");
+  },
+
+  addChromeEventListener: function(type, listener, capture, allowUntrusted) {
+    addEventListener(type, listener, capture, allowUntrusted);
+  },
+  removeChromeEventListener: function(type, listener, capture) {
+    removeEventListener(type, listener, capture);
+  },
+
+  getFullZoom: function(window) {
+    return this._getMUDV(window).fullZoom;
+  },
+  setFullZoom: function(window, zoom) {
+    this._getMUDV(window).fullZoom = zoom;
+  },
+  getTextZoom: function(window) {
+    return this._getMUDV(window).textZoom;
+  },
+  setTextZoom: function(window, zoom) {
+    this._getMUDV(window).textZoom = zoom;
+  },
+
+  createSystemXHR: function() {
+    return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+             .createInstance(Ci.nsIXMLHttpRequest);
+  },
+
+  gc: function() {
+    this.DOMWindowUtils.garbageCollect();
+  },
+
+  hasContentProcesses: function() {
+    try {
+      var rt = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
+      return rt.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+    } catch (e) {
+      return true;
+    }
+  },
+
+  registerProcessCrashObservers: function() {
+    addMessageListener("SPProcessCrashService", this._messageListener);
+    sendSyncMessage("SPProcessCrashService", { op: "register-observer" });
+  },
+
+  _messageReceived: function(aMessage) {
+    switch (aMessage.name) {
+      case "SPProcessCrashService":
+        if (aMessage.json.type == "crash-observed") {
+          var self = this;
+          aMessage.json.dumpIDs.forEach(function(id) {
+            self._encounteredCrashDumpFiles.push(id + ".dmp");
+            self._encounteredCrashDumpFiles.push(id + ".extra");
+          });
+        }
+        break;
+
+      case "SPPingService":
+        if (aMessage.json.op == "pong") {
+          var handler = this._pongHandlers.shift();
+          if (handler) {
+            handler();
+          }
+        }
+        break;
+    }
+    return true;
+  },
+
+  removeExpectedCrashDumpFiles: function(aExpectingProcessCrash) {
+    var success = true;
+    if (aExpectingProcessCrash) {
+      var message = {
+        op: "delete-crash-dump-files",
+        filenames: this._encounteredCrashDumpFiles 
+      };
+      if (!sendSyncMessage("SPProcessCrashService", message)[0]) {
+        success = false;
+      }
+    }
+    this._encounteredCrashDumpFiles.length = 0;
+    return success;
+  },
+
+  findUnexpectedCrashDumpFiles: function() {
+    var self = this;
+    var message = {
+      op: "find-crash-dump-files",
+      crashDumpFilesToIgnore: this._unexpectedCrashDumpFiles
+    };
+    var crashDumpFiles = sendSyncMessage("SPProcessCrashService", message)[0];
+    crashDumpFiles.forEach(function(aFilename) {
+      self._unexpectedCrashDumpFiles[aFilename] = true;
+    });
+    return crashDumpFiles;
+  },
+
+  executeAfterFlushingMessageQueue: function(aCallback) {
+    this._pongHandlers.push(aCallback);
+    sendAsyncMessage("SPPingService", { op: "ping" });
+  },
+
+  executeSoon: function(aFunc) {
+    var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
+    tm.mainThread.dispatch({
+      run: function() {
+        aFunc();
+      }
+    }, Ci.nsIThread.DISPATCH_NORMAL);
+  },
+
+  /* from http://mxr.mozilla.org/mozilla-central/source/testing/mochitest/tests/SimpleTest/quit.js
+   * by Bob Clary, Jeff Walden, and Robert Sayre.
+   */
+  quitApplication: function() {
+      function canQuitApplication()
+      {
+         var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+         if (!os)
+             return true;
+  
+         try {
+             var cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
+             os.notifyObservers(cancelQuit, "quit-application-requested", null);
+    
+             // Something aborted the quit process. 
+             if (cancelQuit.data)
+                 return false;
+         } catch (ex) {}
+         return true;
+      }
+
+      if (!canQuitApplication())
+         return false;
+         
+      var appService = Cc['@mozilla.org/toolkit/app-startup;1'].getService(Ci.nsIAppStartup);
+      appService.quit(Ci.nsIAppStartup.eForceQuit);
+      return true;
+  }
+};
+
+// Expose everything but internal APIs (starting with underscores) to
+// web content.
+SpecialPowers.prototype.__exposedProps__ = {};
+for each (i in Object.keys(SpecialPowers.prototype).filter(function(v) {return v.charAt(0) != "_";})) {
+  SpecialPowers.prototype.__exposedProps__[i] = "r";
+}
+
+// Attach our API to the window.
+function attachSpecialPowersToWindow(aWindow) {
+  try {
+    if ((aWindow !== null) &&
+        (aWindow !== undefined) &&
+        (aWindow.wrappedJSObject) &&
+        !(aWindow.wrappedJSObject.SpecialPowers)) {
+      aWindow.wrappedJSObject.SpecialPowers = new SpecialPowers(aWindow);
+    }
+  } catch(ex) {
+    dump("TEST-INFO | specialpowers.js |  Failed to attach specialpowers to window exception: " + ex + "\n");
+  }
+}
+
+// This is a frame script, so it may be running in a content process.
+// In any event, it is targeted at a specific "tab", so we listen for
+// the DOMWindowCreated event to be notified about content windows
+// being created in this context.
+
+function SpecialPowersManager() {
+  addEventListener("DOMWindowCreated", this, false);
+}
+
+SpecialPowersManager.prototype = {
+  handleEvent: function handleEvent(aEvent) {
+    var window = aEvent.target.defaultView;
+
+    // Need to make sure we are called on what we care about -
+    // content windows. DOMWindowCreated is called on *all* HTMLDocuments,
+    // some of which belong to chrome windows or other special content.
+    //
+    var uri = window.document.documentURIObject;
+    if (uri.scheme === "chrome" || uri.spec.split(":")[0] == "about") {
+      return;
+    }
+
+    attachSpecialPowersToWindow(window);
+  }
+};
+
+var specialpowersmanager = new SpecialPowersManager();
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/components/SpecialPowersObserver.js b/test/resources/firefox/extensions/special-powers@mozilla.org/components/SpecialPowersObserver.js
new file mode 120000 (symlink)
index 0000000..6f90832
--- /dev/null
@@ -0,0 +1 @@
+/Users/sayrer/dev/mozilla-central/testing/mochitest/specialpowers/components/SpecialPowersObserver.js
\ No newline at end of file
diff --git a/test/resources/firefox/extensions/special-powers@mozilla.org/install.rdf b/test/resources/firefox/extensions/special-powers@mozilla.org/install.rdf
new file mode 100644 (file)
index 0000000..db8de98
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>special-powers@mozilla.org</em:id>
+    <em:version>2010.07.23</em:version>
+    <em:type>2</em:type>
+
+    <!-- Target Application this extension can install into, 
+         with minimum and maximum supported versions. -->
+    <em:targetApplication>
+      <Description>
+        <em:id>toolkit@mozilla.org</em:id>
+       <em:minVersion>3.0</em:minVersion>
+       <em:maxVersion>7.0a1</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <!-- Front End MetaData -->
+    <em:name>Special Powers</em:name>
+    <em:description>Special powers for use in testing.</em:description>
+    <em:creator>Mozilla</em:creator>
+  </Description>      
+</RDF>
index 55d9ced3337f05c2aebee2f43488b93038a416af..2085bcbefa5741353d0827177b40bd942b8fca20 100644 (file)
@@ -30,4 +30,5 @@ user_pref("media.cache_size", 100);
 user_pref("security.warn_viewing_mixed", false);
 user_pref("app.update.enabled", false);
 user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
-user_pref("dom.w3c_touch_events.enabled", true);
\ No newline at end of file
+user_pref("dom.w3c_touch_events.enabled", true);
+user_pref("extensions.checkCompatibility", false);
\ No newline at end of file
index c6bb637a263a3fe91f5b199d76a0a14ba24f4d21..5a869530e748b6acf3e9b8d3b0fe0e92ffb19289 100644 (file)
@@ -33,7 +33,8 @@ class TestOptions(OptionParser):
     def verifyOptions(self, options):
         if options.masterMode and options.manifestFile:
             self.error("--masterMode and --manifestFile must not be specified at the same time.")
-        options.manifestFile = DEFAULT_MANIFEST_FILE
+        if not options.manifestFile:
+            options.manifestFile = DEFAULT_MANIFEST_FILE
         return options
         
 def prompt(question):
@@ -149,6 +150,7 @@ class BrowserCommand():
     def setup(self):
         self.tempDir = tempfile.mkdtemp()
         self.profileDir = os.path.join(self.tempDir, "profile")
+        print self.profileDir
         shutil.copytree(os.path.join(DOC_ROOT, "test", "resources", "firefox"),
                         self.profileDir)
 
index 6ab84e52f50856935ef43ade186675aabebe0979..1053025e17c4ae0a7f196fdd6bb4b1701bba77c6 100644 (file)
@@ -151,7 +151,10 @@ function done() {
   log("Done!\n");
   setTimeout(function() {
       document.body.innerHTML = "Tests are finished.  <h1>CLOSE ME!</h1>";
-      window.close();
+      if (window.SpecialPowers)
+        SpecialPowers.quitApplication();
+      else
+        window.close();
     },
     100
   );