diff --git a/testing/mochitest/Makefile.in b/testing/mochitest/Makefile.in index fd832d89a7c1..e2017013ecc5 100644 --- a/testing/mochitest/Makefile.in +++ b/testing/mochitest/Makefile.in @@ -74,6 +74,8 @@ _SERV_FILES = \ harness.xul \ browser-test-overlay.xul \ browser-test.js \ + ipc-overlay.xul \ + ipc.js \ browser-harness.xul \ redirect-a11y.html \ redirect.html \ diff --git a/testing/mochitest/ipc-overlay.xul b/testing/mochitest/ipc-overlay.xul new file mode 100644 index 000000000000..c3480415b468 --- /dev/null +++ b/testing/mochitest/ipc-overlay.xul @@ -0,0 +1,75 @@ + + + + + + + + + + + diff --git a/testing/mochitest/ipc.js b/testing/mochitest/ipc.js new file mode 100644 index 000000000000..0a95b6f43d6a --- /dev/null +++ b/testing/mochitest/ipc.js @@ -0,0 +1,215 @@ +/* ***** 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 Mozilla's layout acceptance tests. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Joel Maher , Mozilla Corporation (original author) + * + * 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 ***** */ + +if (Cc === undefined) { + var Cc = Components.classes; + var Ci = Components.interfaces; +} + +function ipcEvent(e) { + var sync = e.getData("sync"); + var type = e.getData("type"); + var data = JSON.parse(e.getData("data")); + + switch(type) { + case 'LoggerInit': + MozillaFileLogger.init(data.filename); + break; + case 'Logger': + var logger = MozillaFileLogger.getLogCallback(); + logger({"num":data.num, "level":data.level, "info": Array(data.info)}); + break; + case 'LoggerClose': + MozillaFileLogger.close(); + break; + case 'waitForFocus': + if (content) + var wrapper = content.wrappedJSObject.frames[0].SimpleTest; + else + var wrapper = SimpleTest; + ipctest.waitForFocus(wrapper[data.callback], data.targetWindow, data.expectBlankPage); + break; + default: + if (type == 'QuitApplication') { + removeEventListener("contentEvent", function (e) { ipcEvent(e); }, false, true); + } + + if (sync == 1) { + return sendSyncMessage("chromeEvent", {"type":type, "data":data}); + } else { + sendAsyncMessage("chromeEvent", {"type":type, "data":data}); + } + } +}; + +var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"] + .getService(Components.interfaces.nsIXULRuntime); + +//check if we are in content process +if (xulRuntime.processType == 2) { + addEventListener("contentEvent", function (e) { ipcEvent(e); }, false, true); +} + +var ipctest = {}; + +ipctest.waitForFocus_started = false; +ipctest.waitForFocus_loaded = false; +ipctest.waitForFocus_focused = false; + +ipctest.waitForFocus = function (callback, targetWindow, expectBlankPage) { + + if (targetWindow && targetWindow != undefined) { + var tempID = targetWindow; + targetWindow = null; + var wm = Cc["@mozilla.org/appshell/window-mediator;1"] + .getService(Ci.nsIWindowMediator); + var wm_enum = wm.getXULWindowEnumerator(null); + + while(wm_enum.hasMoreElements()) { + var win = wm_enum.getNext().QueryInterface(Ci.nsIXULWindow) + .docShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow) + .content.wrappedJSObject; + + var domutils = win.QueryInterface(Ci.nsIInterfaceRequestor). + getInterface(Ci.nsIDOMWindowUtils); + + if (domutils.outerWindowID == tempID) { + targetWindow = win; + } + } + } + + if (targetWindow == null || targetWindow == undefined) + if (content) + targetWindow = content.document.defaultView; + else + targetWindow = window; + + ipctest.waitForFocus_started = false; + expectBlankPage = !!expectBlankPage; + + var fm = Cc["@mozilla.org/focus-manager;1"]. + getService(Ci.nsIFocusManager); + + var childTargetWindow = { }; + fm.getFocusedElementForWindow(targetWindow, true, childTargetWindow); + childTargetWindow = childTargetWindow.value; + + function debugFocusLog(prefix) { + if (content) + var wrapper = content.wrappedJSObject.frames[0].SimpleTest; + else + var wrapper = SimpleTest; + wrapper.ok(true, prefix + " -- loaded: " + targetWindow.document.readyState + + " active window: " + + (fm.activeWindow ? "(" + fm.activeWindow + ") " + fm.activeWindow.location : "") + + " focused window: " + + (fm.focusedWindow ? "(" + fm.focusedWindow + ") " + fm.focusedWindow.location : "") + + " desired window: (" + targetWindow + ") " + targetWindow.location + + " child window: (" + childTargetWindow + ") " + childTargetWindow.location); + } + + debugFocusLog("before wait for focus"); + + function maybeRunTests() { + debugFocusLog("maybe run tests "); + if (ipctest.waitForFocus_loaded && + ipctest.waitForFocus_focused && + !ipctest.waitForFocus_started) { + ipctest.waitForFocus_started = true; + if (content) + content.setTimeout(function() { callback(); }, 0, targetWindow); + else + setTimeout(function() { callback(); }, 0, targetWindow); + } + } + + function waitForEvent(event) { + try { + debugFocusLog("waitForEvent called "); + + // Check to make sure that this isn't a load event for a blank or + // non-blank page that wasn't desired. + if (event.type == "load" && (expectBlankPage != (event.target.location == "about:blank"))) + return; + + ipctest["waitForFocus_" + event.type + "ed"] = true; + var win = (event.type == "load") ? targetWindow : childTargetWindow; + win.removeEventListener(event.type, waitForEvent, true); + maybeRunTests(); + } catch (e) { + } + } + + // If the current document is about:blank and we are not expecting a blank + // page (or vice versa), and the document has not yet loaded, wait for the + // page to load. A common situation is to wait for a newly opened window + // to load its content, and we want to skip over any intermediate blank + // pages that load. This issue is described in bug 554873. + ipctest.waitForFocus_loaded = + (expectBlankPage == (targetWindow.location == "about:blank")) && + targetWindow.document.readyState == "complete"; + if (!ipctest.waitForFocus_loaded) { + targetWindow.addEventListener("load", waitForEvent, true); + } + + // Check if the desired window is already focused. + var focusedChildWindow = { }; + if (fm.activeWindow) { + fm.getFocusedElementForWindow(fm.activeWindow, true, focusedChildWindow); + focusedChildWindow = focusedChildWindow.value; + } + + // If this is a child frame, ensure that the frame is focused. + ipctest.waitForFocus_focused = (focusedChildWindow == childTargetWindow); + if (ipctest.waitForFocus_focused) { + maybeRunTests(); + } + else { + //TODO: is this really the childTargetWindow + // and are we really doing something with it here? + if (content) { + var wr = childTargetWindow.wrappedJSObject; + wr.addEventListener("focus", waitForEvent, true); + sendAsyncMessage("chromeEvent", {"type":"Focus", "data":{}}); + wr.focus(); + } else { + childTargetWindow.addEventListener("focus", waitForEvent, true); + childTargetWindow.focus(); + } + } +}; diff --git a/testing/mochitest/runtests.py.in b/testing/mochitest/runtests.py.in index 7626efb7dd77..0936a40b21f9 100644 --- a/testing/mochitest/runtests.py.in +++ b/testing/mochitest/runtests.py.in @@ -167,6 +167,7 @@ class MochitestOptions(optparse.OptionParser): self.add_option("--a11y", action = "store_true", dest = "a11y", help = "run accessibility Mochitests"); + defaults["a11y"] = False self.add_option("--setenv", action = "append", type = "string", @@ -695,6 +696,11 @@ toolbar#nav-bar { manifestFile.write("""overlay chrome://navigator/content/navigator.xul chrome://mochikit/content/browser-test-overlay.xul overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul """) + elif ((options.chrome == False) and (options.a11y == False)): + #only do the ipc-overlay.xul for mochitest-plain. + #Currently there are focus issues in chrome tests and issues with new windows and dialogs when using ipc + manifestFile.write("overlay chrome://browser/content/browser.xul chrome://mochikit/content/ipc-overlay.xul") + manifestFile.close() return self.installChromeFile(temp_file, options) diff --git a/testing/mochitest/tests/SimpleTest/MozillaFileLogger.js b/testing/mochitest/tests/SimpleTest/MozillaFileLogger.js index 4bc1cff9ceef..76322351ec58 100644 --- a/testing/mochitest/tests/SimpleTest/MozillaFileLogger.js +++ b/testing/mochitest/tests/SimpleTest/MozillaFileLogger.js @@ -1,10 +1,17 @@ /** * MozillaFileLogger, a log listener that can write to a local file. */ + try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); - const Cc = Components.classes; - const Ci = Components.interfaces; + + if (Cc === undefined) { + var Cc = Components.classes; + var Ci = Components.interfaces; + } +} catch (ex) {} //running in ipcMode-chrome + +try { const FOSTREAM_CID = "@mozilla.org/network/file-output-stream;1"; const LF_CID = "@mozilla.org/file/local;1"; @@ -32,15 +39,29 @@ try { // exists, no action and NULL is returned. const PR_EXCL = 0x80; } catch (ex) { - // probably not running in the test harness + // probably not running in the test harness } /** Init the file logger with the absolute path to the file. It will create and append if the file already exists **/ -var MozillaFileLogger = {} +var MozillaFileLogger = {}; + +var ipcMode = false; +try { + if (typeof(TestRunner) != undefined) + ipcMode = TestRunner.ipcMode; +} catch(e) { }; MozillaFileLogger.init = function(path) { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + if (ipcMode) { + contentAsyncEvent("LoggerInit", {"filename": path}); + return; + } + + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch (ex) {} //running in ipcMode-chrome + MozillaFileLogger._file = Cc[LF_CID].createInstance(Ci.nsILocalFile); MozillaFileLogger._file.initWithPath(path); MozillaFileLogger._foStream = Cc[FOSTREAM_CID].createInstance(Ci.nsIFileOutputStream); @@ -49,8 +70,17 @@ MozillaFileLogger.init = function(path) { } MozillaFileLogger.getLogCallback = function() { + if (ipcMode) { + return function(msg) { + contentAsyncEvent("Logger", {"num": msg.num, "level": msg.level, "info": msg.info.join(' ')}); + } + } + return function (msg) { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch(ex) {} //running in ipcMode-chrome + var data = msg.num + " " + msg.level + " " + msg.info.join(' ') + "\n"; MozillaFileLogger._foStream.write(data, data.length); if (data.indexOf("SimpleTest FINISH") >= 0) { @@ -60,7 +90,15 @@ MozillaFileLogger.getLogCallback = function() { } MozillaFileLogger.close = function() { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + if (ipcMode) { + contentAsyncEvent("LoggerClose"); + return; + } + + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } catch(ex) {} //running in ipcMode-chrome + MozillaFileLogger._foStream.close(); MozillaFileLogger._foStream = null; MozillaFileLogger._file = null; diff --git a/testing/mochitest/tests/SimpleTest/SimpleTest.js b/testing/mochitest/tests/SimpleTest/SimpleTest.js index 753a4cf0f58d..8991a211e94d 100644 --- a/testing/mochitest/tests/SimpleTest/SimpleTest.js +++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js @@ -26,6 +26,12 @@ if (typeof(parent) != "undefined" && parent.TestRunner) { parentRunner = parent.wrappedJSObject.TestRunner; } +//Simple test to see if we are running in e10s IPC +var ipcMode = false; +if (parentRunner) { + ipcMode = parentRunner.ipcMode; +} + // Check to see if the TestRunner is present and has logging if (parentRunner) { SimpleTest._logEnabled = parentRunner.logEnabled; @@ -258,6 +264,17 @@ SimpleTest.waitForFocus = function (callback, targetWindow, expectBlankPage) { if (!targetWindow) targetWindow = window; + if (ipcMode) { + var domutils = targetWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor). + getInterface(Components.interfaces.nsIDOMWindowUtils); + + //TODO: make this support scenarios where we run test standalone and not inside of TestRunner only + if (parent && parent.ipcWaitForFocus != undefined) { + parent.contentAsyncEvent("waitForFocus", {"callback":callback, "targetWindow":domutils.outerWindowID}); + } + return; + } + SimpleTest.waitForFocus_started = false; expectBlankPage = !!expectBlankPage; @@ -372,6 +389,12 @@ SimpleTest.waitForClipboard_polls = 0; * within 5s. It can also be called if the known value can't be found. */ SimpleTest.waitForClipboard = function(aExpectedVal, aSetupFn, aSuccessFn, aFailureFn) { + if (ipcMode) { + //TODO: support waitForClipboard via events to chrome + dump("E10S_TODO: bug 573735 addresses adding support for this"); + return; + } + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var cbSvc = Components.classes["@mozilla.org/widget/clipboard;1"]. diff --git a/testing/mochitest/tests/SimpleTest/TestRunner.js b/testing/mochitest/tests/SimpleTest/TestRunner.js index 73641f64bf3e..ef27592303e6 100644 --- a/testing/mochitest/tests/SimpleTest/TestRunner.js +++ b/testing/mochitest/tests/SimpleTest/TestRunner.js @@ -1,3 +1,30 @@ +/* + * e10s event dispatcher from content->chrome + * + * type = eventName (QuitApplication, LoggerInit, LoggerClose, Logger, GetPref, SetPref) + * data = json object {"filename":filename} <- for LoggerInit + */ +function contentDispatchEvent(type, data, sync) { + if (typeof(data) == "undefined") { + data = {}; + } + + var element = document.createEvent("datacontainerevent"); + element.initEvent("contentEvent", true, false); + element.setData("sync", sync); + element.setData("type", type); + element.setData("data", JSON.stringify(data)); + document.dispatchEvent(element); +} + +function contentSyncEvent(type, data) { + contentDispatchEvent(type, data, 1); +} + +function contentAsyncEvent(type, data) { + contentDispatchEvent(type, data, 0); +} + /** * TestRunner: A test runner for SimpleTest * TODO: @@ -15,6 +42,16 @@ TestRunner._urls = []; TestRunner.timeout = 5 * 60 * 1000; // 5 minutes. TestRunner.maxTimeouts = 4; // halt testing after too many timeouts +TestRunner.ipcMode = false; // running in e10s build and need to use IPC? +try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + var ipcsanity = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + ipcsanity.setIntPref("mochitest.ipcmode", 0); +} catch (e) { + TestRunner.ipcMode = true; +} + /** * Make sure the tests don't hang indefinitely. **/ @@ -89,6 +126,10 @@ TestRunner._makeIframe = function (url, retry) { ("activeElement" in document && document.activeElement != iframe))) { // typically calling ourselves from setTimeout is sufficient // but we'll try focus() just in case that's needed + + if (TestRunner.ipcMode) { + contentAsyncEvent("Focus"); + } window.focus(); iframe.focus(); if (retry < 3) { diff --git a/testing/mochitest/tests/SimpleTest/quit.js b/testing/mochitest/tests/SimpleTest/quit.js index 360ba2df56f8..ebb62ae2b9c4 100644 --- a/testing/mochitest/tests/SimpleTest/quit.js +++ b/testing/mochitest/tests/SimpleTest/quit.js @@ -42,6 +42,12 @@ These files did not have a license */ +//Simple test to see if we are running in e10s IPC +var ipcMode = false; +if (typeof(TestRunner) != "undefined") { + ipcMode = TestRunner.ipcMode; +} + function quitHook() { var xhr = new XMLHttpRequest(); @@ -83,6 +89,11 @@ function canQuitApplication() function goQuitApplication() { + if (ipcMode) { + contentAsyncEvent("QuitApplication"); + return; + } + const privs = 'UniversalXPConnect'; try @@ -109,7 +120,6 @@ function goQuitApplication() appService = Components.classes[kAppStartup]. getService(Components.interfaces.nsIAppStartup); forceQuit = Components.interfaces.nsIAppStartup.eForceQuit; - } else if (kAppShell in Components.classes) {