diff --git a/testing/mochitest/jar.mn b/testing/mochitest/jar.mn index 7748cd568cf..cdb08af3523 100644 --- a/testing/mochitest/jar.mn +++ b/testing/mochitest/jar.mn @@ -15,6 +15,7 @@ mochikit.jar: content/server.js (server.js) content/chunkifyTests.js (chunkifyTests.js) content/manifestLibrary.js (manifestLibrary.js) + content/nested_setup.js (nested_setup.js) content/dynamic/getMyDirectory.sjs (dynamic/getMyDirectory.sjs) content/static/harness.css (static/harness.css) content/tests/SimpleTest/ChromePowers.js (tests/SimpleTest/ChromePowers.js) diff --git a/testing/mochitest/mach_commands.py b/testing/mochitest/mach_commands.py index a8df2ef54cf..8f6b3e2f8ec 100644 --- a/testing/mochitest/mach_commands.py +++ b/testing/mochitest/mach_commands.py @@ -191,7 +191,7 @@ class MochitestRunner(MozbuildObject): rerun_failures=False, no_autorun=False, repeat=0, run_until_failure=False, slow=False, chunk_by_dir=0, total_chunks=None, this_chunk=None, extraPrefs=[], jsdebugger=False, debug_on_failure=False, start_at=None, end_at=None, - e10s=False, strict_content_sandbox=False, dmd=False, dump_output_directory=None, + e10s=False, strict_content_sandbox=False, nested_oop=False, dmd=False, dump_output_directory=None, dump_about_memory_after_test=False, dump_dmd_after_test=False, install_extension=None, quiet=False, environment=[], app_override=None, bisectChunk=None, runByDir=False, useTestMediaDevices=False, timeout=None, **kwargs): @@ -314,6 +314,7 @@ class MochitestRunner(MozbuildObject): options.endAt = end_at options.e10s = e10s options.strictContentSandbox = strict_content_sandbox + options.nested_oop = nested_oop options.dumpAboutMemoryAfterTest = dump_about_memory_after_test options.dumpDMDAfterTest = dump_dmd_after_test options.dumpOutputDirectory = dump_output_directory @@ -508,6 +509,10 @@ def MochitestCommand(func): help='Run tests with a more strict content sandbox (Windows only).') func = strict_content_sandbox(func) + this_chunk = CommandArgument('--nested-oop', action='store_true', + help='Run tests with nested oop preferences and test filtering enabled.') + func = this_chunk(func) + dmd = CommandArgument('--dmd', action='store_true', help='Run tests with DMD active.') func = dmd(func) diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py index 309a816c266..6da11fb3722 100644 --- a/testing/mochitest/mochitest_options.py +++ b/testing/mochitest/mochitest_options.py @@ -369,6 +369,12 @@ class MochitestOptions(optparse.OptionParser): "dest": "strictContentSandbox", "help": "Run tests with a more strict content sandbox (Windows only).", }], + [["--nested-oop"], + { "action": "store_true", + "default": False, + "dest": "nested_oop", + "help": "Run tests with nested-oop preferences and test filtering enabled.", + }], [["--dmd-path"], { "action": "store", "default": None, @@ -481,6 +487,7 @@ class MochitestOptions(optparse.OptionParser): mozinfo.update({"e10s": options.e10s}) # for test manifest parsing. mozinfo.update({"strictContentSandbox": options.strictContentSandbox}) # for test manifest parsing. + mozinfo.update({"nested_oop": options.nested_oop}) # for test manifest parsing. if options.app is None: if build_obj is not None: diff --git a/testing/mochitest/moz.build b/testing/mochitest/moz.build index 2b7f0f8398c..99c43193121 100644 --- a/testing/mochitest/moz.build +++ b/testing/mochitest/moz.build @@ -61,6 +61,7 @@ TEST_HARNESS_FILES.testing.mochitest += [ 'manifest.webapp', 'manifestLibrary.js', 'mochitest_options.py', + 'nested_setup.js', 'pywebsocket_wrapper.py', 'redirect.html', 'runtests.py', diff --git a/testing/mochitest/nested_setup.js b/testing/mochitest/nested_setup.js new file mode 100644 index 00000000000..f7fc13e1fbf --- /dev/null +++ b/testing/mochitest/nested_setup.js @@ -0,0 +1,30 @@ + +var gTestURL = ''; + +function addPermissions() +{ + SpecialPowers.pushPermissions( + [{ type: "browser", allow: true, context: document }], + addPreferences); +} + +function addPreferences() +{ + SpecialPowers.pushPrefEnv( + {"set": [["dom.mozBrowserFramesEnabled", true]]}, + insertFrame); +} + + +function insertFrame() +{ + var iframe = document.createElement('iframe'); + iframe.id = 'nested-parent-frame'; + iframe.width = "100%"; + iframe.height = "100%"; + iframe.scoring = "no"; + iframe.setAttribute("remote", "true"); + iframe.setAttribute("mozbrowser", "true"); + iframe.src = gTestURL; + document.getElementById("holder-div").appendChild(iframe); +} \ No newline at end of file diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index 8967e949291..72f97f458b8 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -421,6 +421,7 @@ class MochitestUtilsMixin(object): # Path to the test script on the server TEST_PATH = "tests" + NESTED_OOP_TEST_PATH = "nested_oop" CHROME_PATH = "redirect.html" urlOpts = [] log = None @@ -652,6 +653,8 @@ class MochitestUtilsMixin(object): testURL = "/".join([testHost, self.CHROME_PATH]) elif options.browserChrome or options.jetpackPackage or options.jetpackAddon: testURL = "about:blank" + if options.nested_oop: + testURL = "/".join([testHost, self.NESTED_OOP_TEST_PATH]) return testURL def buildTestPath(self, options, testsToFilter=None, disabled=True): @@ -1161,6 +1164,7 @@ class Mochitest(MochitestUtilsMixin): options.extraPrefs.append("browser.tabs.remote.autostart=%s" % ('true' if options.e10s else 'false')) if options.strictContentSandbox: options.extraPrefs.append("security.sandbox.windows.content.moreStrict=true") + options.extraPrefs.append("dom.ipc.tabs.nested.enabled=%s" % ('true' if options.nested_oop else 'false')) # get extensions to install extensions = self.getExtensionsToInstall(options) diff --git a/testing/mochitest/server.js b/testing/mochitest/server.js index c2a2b62fa98..98b605de29f 100644 --- a/testing/mochitest/server.js +++ b/testing/mochitest/server.js @@ -210,6 +210,7 @@ function createMochitestServer(serverBasePath) server.registerDirectory("/", serverBasePath); server.registerPathHandler("/server/shutdown", serverShutdown); server.registerPathHandler("/server/debug", serverDebug); + server.registerPathHandler("/nested_oop", nestedTest); server.registerContentType("sjs", "sjs"); // .sjs == CGI-like functionality server.registerContentType("jar", "application/x-jar"); server.registerContentType("ogg", "application/ogg"); @@ -598,6 +599,31 @@ function convertManifestToTestLinks(root, manifest) paths.length]; } +/** + * Produce a test harness page that has one remote iframe + */ +function nestedTest(metadata, response) +{ + response.setStatusLine("1.1", 200, "OK"); + response.setHeader("Content-type", "text/html;charset=utf-8", false); + response.write( + HTML( + HEAD( + TITLE("Mochitest | ", metadata.path), + LINK({rel: "stylesheet", + type: "text/css", href: "/static/harness.css"}), + SCRIPT({type: "text/javascript", + src: "/nested_setup.js"}), + SCRIPT({type: "text/javascript"}, + "window.onload = addPermissions; gTestURL = '/tests?" + metadata.queryString + "';") + ), + BODY( + DIV({class: "container"}, + DIV({class: "frameholder", id: "holder-div"}) + ) + ))); +} + /** * Produce a test harness page containing all the test cases * below it, recursively. diff --git a/testing/specialpowers/content/specialpowers.js b/testing/specialpowers/content/specialpowers.js index b728cedfdad..589899cb7b5 100644 --- a/testing/specialpowers/content/specialpowers.js +++ b/testing/specialpowers/content/specialpowers.js @@ -5,6 +5,31 @@ * order to be used as a replacement for UniversalXPConnect */ +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/Services.jsm"); + +const Cc = Components.classes; +const Ci = Components.interfaces; + +const CHILD_SCRIPT = "chrome://specialpowers/content/specialpowers.js"; +const CHILD_SCRIPT_API = "chrome://specialpowers/content/specialpowersAPI.js"; +const CHILD_LOGGER_SCRIPT = "chrome://specialpowers/content/MozillaLogger.js"; + +// All messages sent to observer should be listed here. +const SP_SYNC_MESSAGES = ["SPChromeScriptMessage", + "SPLoadChromeScript", + "SPObserverService", + "SPPermissionManager", + "SPPrefService", + "SPProcessCrashService", + "SPSetTestPluginEnabledState", + "SPWebAppService"]; + +const SP_ASYNC_MESSAGES = ["SpecialPowers.Focus", + "SpecialPowers.Quit", + "SPPingService", + "SPQuotaManager"]; + function SpecialPowers(window) { this.window = Components.utils.getWeakReference(window); this._windowID = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) @@ -23,6 +48,8 @@ function SpecialPowers(window) { }}); this._pongHandlers = []; this._messageListener = this._messageReceived.bind(this); + this._nestedFrameInjected = false; + this._grandChildFrameMM = null; addMessageListener("SPPingService", this._messageListener); let (self = this) { Services.obs.addObserver(function onInnerWindowDestroyed(subject, topic, data) { @@ -37,6 +64,40 @@ function SpecialPowers(window) { } } }, "inner-window-destroyed", false); + Services.obs.addObserver(function onRemoteBrowserShown(subject, topic, data) { + let frameLoader = subject; + + // get a ref to the app