Bug 1007062 - Fix SpecialPower API doesn't work on Marionette test-container. r=mdas,jmaher
authorEdgar Chen <echen@mozilla.com>
Sun, 28 Sep 2014 22:43:32 +0800
changeset 231628 36107e095754c73be4cd5665ff8326565d9b121d
parent 231627 7a1b7d7eba12c1f68ccd74a2c3ed7ea2a9e48a75
child 231629 0da68b363d49813258990ccf1c6070685fd9a66d
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmdas, jmaher
bugs1007062
milestone35.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 1007062 - Fix SpecialPower API doesn't work on Marionette test-container. r=mdas,jmaher
dom/tests/mochitest/notification/NotificationTest.js
testing/marionette/client/marionette/tests/unit/test_specialpowers.py
testing/marionette/marionette-frame-manager.js
testing/marionette/marionette-server.js
testing/mochitest/b2g_start_script.js
testing/specialpowers/components/SpecialPowersObserver.js
--- a/dom/tests/mochitest/notification/NotificationTest.js
+++ b/dom/tests/mochitest/notification/NotificationTest.js
@@ -4,16 +4,17 @@ var NotificationTest = (function () {
   function info(msg, name) {
     SimpleTest.info("::Notification Tests::" + (name || ""), msg);
   }
 
   function setup_testing_env() {
     SimpleTest.waitForExplicitFinish();
     // turn on testing pref (used by notification.cpp, and mock the alerts
     SpecialPowers.setBoolPref("notification.prompt.testing", true);
+    SpecialPowers.setAllAppsLaunchable(true);
   }
 
   function teardown_testing_env() {
     SimpleTest.finish();
   }
 
   function executeTests(tests, callback) {
     // context is `this` object in test functions
--- a/testing/marionette/client/marionette/tests/unit/test_specialpowers.py
+++ b/testing/marionette/client/marionette/tests/unit/test_specialpowers.py
@@ -1,22 +1,20 @@
 # 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/.
 
-from marionette_test import MarionetteTestCase, skip_if_b2g
+from marionette_test import MarionetteTestCase
 from errors import JavascriptException, MarionetteException
 
 class TestSpecialPowersContent(MarionetteTestCase):
 
     testpref = "testing.marionette.contentcharpref"
     testvalue = "blabla"
 
-    # fails in b2g's test-container: "Error getting pref", Bug 1060061
-    @skip_if_b2g
     def test_prefs(self):
         result = self.marionette.execute_script("""
         SpecialPowers.setCharPref("%(pref)s", "%(value)s");
         return SpecialPowers.getCharPref("%(pref)s")
         """ % {'pref': self.testpref, 'value': self.testvalue}, special_powers=True);
         self.assertEqual(result, self.testvalue) 
 
     def test_prefs_after_navigate(self):
--- a/testing/marionette/marionette-frame-manager.js
+++ b/testing/marionette/marionette-frame-manager.js
@@ -8,16 +8,22 @@ this.EXPORTED_SYMBOLS = [
 
 let FRAME_SCRIPT = "chrome://marionette/content/marionette-listener.js";
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 Cu.import("resource://gre/modules/Log.jsm");
 let logger = Log.repository.getLogger("Marionette");
 
+let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
+               .getService(Ci.mozIJSSubScriptLoader);
+let specialpowers = {};
+loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.js",
+                     specialpowers);
+
 //list of OOP frames that has the frame script loaded
 let remoteFrames = [];
 
 /**
  * An object representing a frame that Marionette has loaded a
  * frame script in.
  */
 function MarionetteRemoteFrame(windowId, frameId) {
@@ -116,46 +122,68 @@ FrameManager.prototype = {
           logger.info("deleting frame");
           remoteFrames.splice(i, 1);
           continue;
         }
       }
       if (frameMessageManager == mm) {
         this.currentRemoteFrame = frame;
         this.addMessageManagerListeners(mm);
+        if (!frame.specialPowersObserver) {
+          frame.specialPowersObserver = new specialpowers.SpecialPowersObserver();
+          frame.specialPowersObserver.init(mm);
+        }
+
         mm.sendAsyncMessage("Marionette:restart", {});
         return;
       }
     }
 
     // If we get here, then we need to load the frame script in this frame,
     // and set the frame's ChromeMessageSender as the active message manager the server will listen to
     this.addMessageManagerListeners(mm);
     logger.info("frame-manager load script: " + mm.toString());
     mm.loadFrameScript(FRAME_SCRIPT, true, true);
     let aFrame = new MarionetteRemoteFrame(message.json.win, message.json.frame);
     aFrame.messageManager = Cu.getWeakReference(mm);
     remoteFrames.push(aFrame);
     this.currentRemoteFrame = aFrame;
+
+    aFrame.specialPowersObserver = new specialpowers.SpecialPowersObserver();
+    aFrame.specialPowersObserver.init(mm);
   },
 
   /*
    * This function handles switching back to the frame that was interrupted by the modal dialog.
    * This function gets called by the interrupted frame once the dialog is dismissed and the frame resumes its process
    */
   switchToModalOrigin: function FM_switchToModalOrigin() {
     //only handle this if we indeed switched out of the modal's originating frame
     if (this.previousRemoteFrame != null) {
       this.currentRemoteFrame = this.previousRemoteFrame;
       this.addMessageManagerListeners(this.currentRemoteFrame.messageManager.get());
     }
     this.handledModal = false;
   },
 
   /**
+   * This function removes any SpecialPowersObservers from OOP frames.
+   */
+  removeSpecialPowers: function FM_removeSpecialPowers() {
+    for (let i = 0; i < remoteFrames.length; i++) {
+      let frame = remoteFrames[i];
+
+      if (frame.specialPowersObserver) {
+        frame.specialPowersObserver.uninit();
+        frame.specialPowersObserver = null;
+      }
+    }
+  },
+
+  /**
    * Adds message listeners to the server, listening for messages from content frame scripts.
    * It also adds a "MarionetteFrame:getInterruptedState" message listener to the FrameManager,
    * so the frame manager's state can be checked by the frame
    *
    * @param object messageManager
    *        The messageManager object (ChromeMessageBroadcaster or ChromeMessageSender)
    *        to which the listeners should be added.
    */
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -2210,16 +2210,17 @@ MarionetteServerConnection.prototype = {
         for (let i in this.browsers[win].knownFrames) {
           this.globalMessageManager.broadcastAsyncMessage("Marionette:deleteSession" + this.browsers[win].knownFrames[i], {});
         }
       }
       let winEnum = this.getWinEnumerator();
       while (winEnum.hasMoreElements()) {
         winEnum.getNext().messageManager.removeDelayedFrameScript(FRAME_SCRIPT);
       }
+      this.curBrowser.frameManager.removeSpecialPowers();
       this.curBrowser.frameManager.removeMessageManagerListeners(this.globalMessageManager);
     }
     this.switchToGlobalMessageManager();
     // reset frame to the top-most frame
     this.curFrame = null;
     if (this.mainFrame) {
       this.mainFrame.focus();
     }
--- a/testing/mochitest/b2g_start_script.js
+++ b/testing/mochitest/b2g_start_script.js
@@ -70,42 +70,25 @@ if (outOfProcess) {
   let specialpowers = {};
   let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
   loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.js", specialpowers);
   let specialPowersObserver = new specialpowers.SpecialPowersObserver();
 
   let mm = container.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
   specialPowersObserver.init(mm);
 
-  mm.addMessageListener("SPPrefService", specialPowersObserver);
-  mm.addMessageListener("SPProcessCrashService", specialPowersObserver);
-  mm.addMessageListener("SPPingService", specialPowersObserver);
-  mm.addMessageListener("SpecialPowers.Quit", specialPowersObserver);
-  mm.addMessageListener("SpecialPowers.Focus", specialPowersObserver);
-  mm.addMessageListener("SPPermissionManager", specialPowersObserver);
-  mm.addMessageListener("SPObserverService", specialPowersObserver);
-  mm.addMessageListener("SPLoadChromeScript", specialPowersObserver);
-  mm.addMessageListener("SPChromeScriptMessage", specialPowersObserver);
-  mm.addMessageListener("SPQuotaManager", specialPowersObserver);
-
-  mm.loadFrameScript(CHILD_LOGGER_SCRIPT, true);
-  mm.loadFrameScript(CHILD_SCRIPT_API, true);
-  mm.loadFrameScript(CHILD_SCRIPT, true);
-
   //Workaround for bug 848411, once that bug is fixed, the following line can be removed
   function contentScript() {
     addEventListener("DOMWindowCreated", function listener(e) {
       removeEventListener("DOMWindowCreated", listener, false);
       var window = e.target.defaultView;
       window.wrappedJSObject.SpecialPowers.addPermission("allowXULXBL", true, window.document);
     });
   }
   mm.loadFrameScript("data:,(" + encodeURI(contentScript.toSource()) + ")();", true);
-
-  specialPowersObserver._isFrameScriptLoaded = true;
 }
 
 
 if (onDevice) {
   var cpuLock = Cc["@mozilla.org/power/powermanagerservice;1"]
                       .getService(Ci.nsIPowerManagerService)
                       .newWakeLock("cpu");
 
--- a/testing/specialpowers/components/SpecialPowersObserver.js
+++ b/testing/specialpowers/components/SpecialPowersObserver.js
@@ -45,35 +45,17 @@ SpecialPowersObserver.prototype = new Sp
   SpecialPowersObserver.prototype.observe = function(aSubject, aTopic, aData)
   {
     switch (aTopic) {
       case "profile-after-change":
         this.init();
         break;
 
       case "chrome-document-global-created":
-        if (!this._isFrameScriptLoaded) {
-          // Register for any messages our API needs us to handle
-          this._messageManager.addMessageListener("SPPrefService", this);
-          this._messageManager.addMessageListener("SPProcessCrashService", this);
-          this._messageManager.addMessageListener("SPPingService", this);
-          this._messageManager.addMessageListener("SpecialPowers.Quit", this);
-          this._messageManager.addMessageListener("SpecialPowers.Focus", this);
-          this._messageManager.addMessageListener("SPPermissionManager", this);
-          this._messageManager.addMessageListener("SPWebAppService", this);
-          this._messageManager.addMessageListener("SPObserverService", this);
-          this._messageManager.addMessageListener("SPLoadChromeScript", this);
-          this._messageManager.addMessageListener("SPChromeScriptMessage", this);
-          this._messageManager.addMessageListener("SPQuotaManager", this);
-
-          this._messageManager.loadFrameScript(CHILD_LOGGER_SCRIPT, true);
-          this._messageManager.loadFrameScript(CHILD_SCRIPT_API, true);
-          this._messageManager.loadFrameScript(CHILD_SCRIPT, true);
-          this._isFrameScriptLoaded = true;
-        }
+        this._loadFrameScript();
         break;
 
       case "http-on-modify-request":
         if (aSubject instanceof Ci.nsIChannel) {
           let uri = aSubject.URI.spec;
           this._sendAsyncMessage("specialpowers-http-notify-request", { uri: uri });
         }
         break;
@@ -83,16 +65,39 @@ SpecialPowersObserver.prototype = new Sp
         break;
 
       default:
         this._observe(aSubject, aTopic, aData);
         break;
     }
   };
 
+  SpecialPowersObserver.prototype._loadFrameScript = function()
+  {
+    if (!this._isFrameScriptLoaded) {
+      // Register for any messages our API needs us to handle
+      this._messageManager.addMessageListener("SPPrefService", this);
+      this._messageManager.addMessageListener("SPProcessCrashService", this);
+      this._messageManager.addMessageListener("SPPingService", this);
+      this._messageManager.addMessageListener("SpecialPowers.Quit", this);
+      this._messageManager.addMessageListener("SpecialPowers.Focus", this);
+      this._messageManager.addMessageListener("SPPermissionManager", this);
+      this._messageManager.addMessageListener("SPWebAppService", this);
+      this._messageManager.addMessageListener("SPObserverService", this);
+      this._messageManager.addMessageListener("SPLoadChromeScript", this);
+      this._messageManager.addMessageListener("SPChromeScriptMessage", this);
+      this._messageManager.addMessageListener("SPQuotaManager", this);
+
+      this._messageManager.loadFrameScript(CHILD_LOGGER_SCRIPT, true);
+      this._messageManager.loadFrameScript(CHILD_SCRIPT_API, true);
+      this._messageManager.loadFrameScript(CHILD_SCRIPT, true);
+      this._isFrameScriptLoaded = true;
+    }
+  };
+
   SpecialPowersObserver.prototype._sendAsyncMessage = function(msgname, msg)
   {
     if (this._mmIsGlobal) {
       this._messageManager.broadcastAsyncMessage(msgname, msg);
     }
     else {
       this._messageManager.sendAsyncMessage(msgname, msg);
     }
@@ -107,16 +112,18 @@ SpecialPowersObserver.prototype = new Sp
     var obs = Services.obs;
     obs.addObserver(this, "xpcom-shutdown", false);
     obs.addObserver(this, "chrome-document-global-created", false);
     obs.addObserver(this, "http-on-modify-request", false);
 
     if (messageManager) {
       this._messageManager = messageManager;
       this._mmIsGlobal = false;
+
+      this._loadFrameScript();
     }
   };
 
   SpecialPowersObserver.prototype.uninit = function()
   {
     var obs = Services.obs;
     obs.removeObserver(this, "chrome-document-global-created");
     obs.removeObserver(this, "http-on-modify-request");