--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -2,16 +2,17 @@
# 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/.
import datetime
import glob
import time
import re
import os
+import posixpath
import tempfile
import shutil
import subprocess
import sys
from automation import Automation
from devicemanager import DMError, DeviceManager
from mozlog import get_default_logger
@@ -209,17 +210,17 @@ class RemoteAutomation(Automation):
# If crash reporting is disabled (MOZ_CRASHREPORTER!=1), we can't say
# anything.
if not self.CRASHREPORTER:
return False
try:
dumpDir = tempfile.mkdtemp()
- remoteCrashDir = self._remoteProfile + '/minidumps/'
+ remoteCrashDir = posixpath.join(self._remoteProfile, 'minidumps')
if not self._devicemanager.dirExists(remoteCrashDir):
# If crash reporting is enabled (MOZ_CRASHREPORTER=1), the
# minidumps directory is automatically created when Fennec
# (first) starts, so its lack of presence is a hint that
# something went wrong.
print "Automation Error: No crash directory (%s) found on remote device" % remoteCrashDir
# Whilst no crash was found, the run should still display as a failure
return True
--- a/testing/marionette/driver/marionette_driver/marionette.py
+++ b/testing/marionette/driver/marionette_driver/marionette.py
@@ -1144,18 +1144,21 @@ class Marionette(object):
if returncode is not None:
# We're managing a binary which has terminated, so restart it.
self.instance.restart()
self.client = transport.TcpTransport(
self.host,
self.port,
self.socket_timeout)
+
+ # Call wait_for_port() before attempting to connect in
+ # the event gecko hasn't started yet.
+ self.wait_for_port(timeout=timeout)
self.protocol, _ = self.client.connect()
- self.wait_for_port(timeout=timeout)
body = {"capabilities": desired_capabilities, "sessionId": session_id}
resp = self._send_message("newSession", body)
self.session_id = resp["sessionId"]
self.session = resp["value"] if self.protocol == 1 else resp["capabilities"]
self.b2g = "b2g" in self.session
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/bootstrap.js
@@ -0,0 +1,84 @@
+/* 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/. */
+
+const { utils: Cu, interfaces: Ci, classes: Cc } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+var WindowListener = {
+ // browser-test.js is only loaded into the first window. Setup that
+ // needs to happen in all navigator:browser windows should go here.
+ setupWindow: function(win) {
+ win.nativeConsole = win.console;
+ XPCOMUtils.defineLazyModuleGetter(win, "console",
+ "resource://gre/modules/Console.jsm");
+ },
+
+ tearDownWindow: function(win) {
+ if (win.nativeConsole) {
+ win.console = win.nativeConsole;
+ win.nativeConsole = undefined;
+ }
+ },
+
+ onOpenWindow: function (win) {
+ win = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+
+ win.addEventListener("load", function listener() {
+ win.removeEventListener("load", listener, false);
+ if (win.document.documentElement.getAttribute("windowtype") == "navigator:browser") {
+ WindowListener.setupWindow(win);
+ }
+ }, false);
+ }
+}
+
+function loadMochitest(e) {
+ let flavor = e.detail[0];
+ let url = e.detail[1];
+
+ let win = Services.wm.getMostRecentWindow("navigator:browser");
+ win.removeEventListener('mochitest-load', loadMochitest);
+
+ // for mochitest-plain, navigating to the url is all we need
+ win.loadURI(url);
+ if (flavor == "mochitest") {
+ return;
+ }
+
+ WindowListener.setupWindow(win);
+ Services.wm.addListener(WindowListener);
+
+ let overlay;
+ if (flavor == "jetpack-addon") {
+ overlay = "chrome://mochikit/content/jetpack-addon-overlay.xul";
+ } else if (flavor == "jetpack-package") {
+ overlay = "chrome://mochikit/content/jetpack-package-overlay.xul";
+ } else {
+ overlay = "chrome://mochikit/content/browser-test-overlay.xul";
+ }
+
+ win.document.loadOverlay(overlay, null);
+}
+
+function startup(data, reason) {
+ let win = Services.wm.getMostRecentWindow("navigator:browser");
+ // wait for event fired from start_desktop.js containing the
+ // suite and url to load
+ win.addEventListener('mochitest-load', loadMochitest);
+}
+
+function shutdown(data, reason) {
+ let windows = Services.wm.getEnumerator("navigator:browser");
+ while (windows.hasMoreElements()) {
+ let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
+ WindowListener.tearDownWindow(win);
+ }
+
+ Services.wm.removeListener(WindowListener);
+}
+
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/testing/mochitest/browser-harness.xul
+++ b/testing/mochitest/browser-harness.xul
@@ -246,17 +246,17 @@
// It's possible that the test harness window is not yet focused when this
// function runs (in which case testWin is already focused, and focusing it
// will be a no-op, and then the test harness window will steal focus later,
// which will mess up tests). So wait for the test harness window to be
// focused before trying to focus testWin.
waitForFocus(() => {
// Focus the test window and start tests.
waitForFocus(() => {
- var Tester = new testWin.Tester(links, gDumper, testsFinished);
+ var Tester = new testWin.Tester(links, gDumper.structuredLogger, testsFinished);
Tester.start();
}, testWin);
}, window);
}
function executeSoon(callback) {
let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
--- a/testing/mochitest/browser-test-overlay.xul
+++ b/testing/mochitest/browser-test-overlay.xul
@@ -2,12 +2,12 @@
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<!-- 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/. -->
<overlay id="browserTestOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"/>
+ <script type="application/javascript" src="chrome://mochikit/content/mochitest-e10s-utils.js"/>
<script type="application/javascript" src="chrome://mochikit/content/browser-test.js"/>
<script type="application/javascript" src="chrome://mochikit/content/cc-analyzer.js"/>
- <script type="application/javascript" src="chrome://mochikit/content/mochitest-e10s-utils.js"/>
</overlay>
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -1,53 +1,42 @@
/* -*- js-indent-level: 2; tab-width: 2; indent-tabs-mode: nil -*- */
// Test timeout (seconds)
var gTimeoutSeconds = 45;
var gConfig;
-if (Cc === undefined) {
- var Cc = Components.classes;
-}
-if (Ci === undefined) {
- var Ci = Components.interfaces;
-}
-if (Cu === undefined) {
- var Cu = Components.utils;
-}
-
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
- "resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
"resource:///modules/CustomizationTabPreloader.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
"resource:///modules/ContentSearch.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SelfSupportBackend",
"resource:///modules/SelfSupportBackend.jsm");
-var nativeConsole = console;
-XPCOMUtils.defineLazyModuleGetter(this, "console",
- "resource://gre/modules/Console.jsm");
-
const SIMPLETEST_OVERRIDES =
["ok", "is", "isnot", "todo", "todo_is", "todo_isnot", "info", "expectAssertions", "requestCompleteLog"];
-window.addEventListener("load", function testOnLoad() {
- window.removeEventListener("load", testOnLoad);
- window.addEventListener("MozAfterPaint", function testOnMozAfterPaint() {
- window.removeEventListener("MozAfterPaint", testOnMozAfterPaint);
- setTimeout(testInit, 0);
+// non-android is bootstrapped by marionette
+if (Services.appinfo.OS == 'Android') {
+ window.addEventListener("load", function testOnLoad() {
+ window.removeEventListener("load", testOnLoad);
+ window.addEventListener("MozAfterPaint", function testOnMozAfterPaint() {
+ window.removeEventListener("MozAfterPaint", testOnMozAfterPaint);
+ setTimeout(testInit, 0);
+ });
});
-});
+} else {
+ setTimeout(testInit, 0);
+}
function b2gStart() {
let homescreen = document.getElementById('systemapp');
var webNav = homescreen.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation);
var url = "chrome://mochikit/content/harness.xul?manifestFile=tests.json";
webNav.loadURI(url, null, null, null, null);
@@ -135,18 +124,18 @@ function testInit() {
// In non-e10s, only run the ShutdownLeaksCollector in the parent process.
Components.utils.import("chrome://mochikit/content/ShutdownLeaksCollector.jsm");
}
let gmm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
gmm.loadFrameScript("chrome://mochikit/content/tests/SimpleTest/AsyncUtilsContent.js", true);
}
-function Tester(aTests, aDumper, aCallback) {
- this.dumper = aDumper;
+function Tester(aTests, structuredLogger, aCallback) {
+ this.structuredLogger = structuredLogger;
this.tests = aTests;
this.callback = aCallback;
this.openedWindows = {};
this.openedURLs = {};
this._scriptLoader = Services.scriptloader;
this.EventUtils = {};
this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", this.EventUtils);
@@ -252,17 +241,17 @@ Tester.prototype = {
if (gConfig.jscovDirPrefix) {
let coveragePath = gConfig.jscovDirPrefix;
let {CoverageCollector} = Cu.import("resource://testing-common/CoverageUtils.jsm",
{});
this._coverageCollector = new CoverageCollector(coveragePath);
}
- this.dumper.structuredLogger.info("*** Start BrowserChrome Test Results ***");
+ this.structuredLogger.info("*** Start BrowserChrome Test Results ***");
Services.console.registerListener(this);
Services.obs.addObserver(this, "chrome-document-global-created", false);
Services.obs.addObserver(this, "content-document-global-created", false);
this._globalProperties = Object.keys(window);
this._globalPropertyWhitelist = [
"navigator", "constructor", "top",
"Application",
"__SS_tabsToRestore", "__SSi",
@@ -313,17 +302,17 @@ Tester.prototype = {
// Replace the last tab with a fresh one
if (window.gBrowser) {
gBrowser.addTab("about:blank", { skipAnimation: true });
gBrowser.removeTab(gBrowser.selectedTab, { skipPermitUnload: true });
gBrowser.stop();
}
// Remove stale windows
- this.dumper.structuredLogger.info("checking window state");
+ this.structuredLogger.info("checking window state");
let windowsEnum = Services.wm.getEnumerator(null);
let createdFakeTestForLogging = false;
while (windowsEnum.hasMoreElements()) {
let win = windowsEnum.getNext();
if (win != window && !win.closed &&
win.document.documentElement.getAttribute("id") != "browserTestHarness") {
let type = win.document.documentElement.getAttribute("windowtype");
switch (type) {
@@ -336,32 +325,32 @@ Tester.prototype = {
break;
}
let msg = baseMsg.replace("{elt}", type);
if (this.currentTest) {
this.currentTest.addResult(new testResult(false, msg, "", false));
} else {
if (!createdFakeTestForLogging) {
createdFakeTestForLogging = true;
- this.dumper.structuredLogger.testStart("browser-test.js");
+ this.structuredLogger.testStart("browser-test.js");
}
this.failuresFromInitialWindowState++;
- this.dumper.structuredLogger.testStatus("browser-test.js",
- msg, "FAIL", false, "");
+ this.structuredLogger.testStatus("browser-test.js",
+ msg, "FAIL", false, "");
}
win.close();
}
}
if (createdFakeTestForLogging) {
let time = Date.now() - startTime;
- this.dumper.structuredLogger.testEnd("browser-test.js",
- "OK",
- undefined,
- "finished window state check in " + time + "ms");
+ this.structuredLogger.testEnd("browser-test.js",
+ "OK",
+ undefined,
+ "finished window state check in " + time + "ms");
}
// Make sure the window is raised before each test.
this.SimpleTest.waitForFocus(aCallback);
},
finish: function Tester_finish(aSkipSummary) {
this.Promise.Debugging.flushUncaughtErrors();
@@ -385,32 +374,30 @@ Tester.prototype = {
Services.obs.removeObserver(this, "content-document-global-created");
this.Promise.Debugging.clearUncaughtErrorObservers();
this._treatUncaughtRejectionsAsFailures = false;
// In the main process, we print the ShutdownLeaksCollector message here.
let pid = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).processID;
dump("Completed ShutdownLeaks collections in process " + pid + "\n");
- this.dumper.structuredLogger.info("TEST-START | Shutdown");
+ this.structuredLogger.info("TEST-START | Shutdown");
if (this.tests.length) {
- this.dumper.structuredLogger.info("Browser Chrome Test Summary");
- this.dumper.structuredLogger.info("Passed: " + passCount);
- this.dumper.structuredLogger.info("Failed: " + failCount);
- this.dumper.structuredLogger.info("Todo: " + todoCount);
+ this.structuredLogger.info("Browser Chrome Test Summary");
+ this.structuredLogger.info("Passed: " + passCount);
+ this.structuredLogger.info("Failed: " + failCount);
+ this.structuredLogger.info("Todo: " + todoCount);
} else {
- this.dumper.structuredLogger.testEnd("browser-test.js",
- "FAIL",
- "PASS",
- "No tests to run. Did you pass invalid test_paths?");
+ this.structuredLogger.testEnd("browser-test.js",
+ "FAIL",
+ "PASS",
+ "No tests to run. Did you pass invalid test_paths?");
}
- this.dumper.structuredLogger.info("*** End BrowserChrome Test Results ***");
-
- this.dumper.done();
+ this.structuredLogger.info("*** End BrowserChrome Test Results ***");
// Tests complete, notify the callback and return
this.callback(this.tests);
this.callback = null;
this.tests = null;
this.openedWindows = null;
}
},
@@ -449,17 +436,17 @@ Tester.prototype = {
if (!aConsoleMessage.message)
return;
try {
var msg = "Console message: " + aConsoleMessage.message;
if (this.currentTest)
this.currentTest.addResult(new testMessage(msg));
else
- this.dumper.dump("TEST-INFO | (browser-test.js) | " + msg.replace(/\n$/, "") + "\n");
+ this.structuredLogger.info("TEST-INFO | (browser-test.js) | " + msg.replace(/\n$/, "") + "\n");
} catch (ex) {
// Swallow exception so we don't lead to another error being reported,
// throwing us into an infinite loop
}
},
nextTest: Task.async(function*() {
if (this.currentTest) {
@@ -576,17 +563,17 @@ Tester.prototype = {
this.currentTest.path,
gConfig.dumpOutputDirectory,
gConfig.dumpAboutMemoryAfterTest,
gConfig.dumpDMDAfterTest);
}
// Note the test run time
let time = Date.now() - this.lastStartTime;
- this.dumper.structuredLogger.testEnd(this.currentTest.path,
+ this.structuredLogger.testEnd(this.currentTest.path,
"OK",
undefined,
"finished in " + time + "ms");
this.currentTest.setDuration(time);
if (this.runUntilFailure && this.currentTest.failCount > 0) {
this.haltTests();
}
@@ -720,17 +707,17 @@ Tester.prototype = {
}
this.currentTestIndex++;
this.execTest();
}).bind(this));
}),
execTest: function Tester_execTest() {
- this.dumper.structuredLogger.testStart(this.currentTest.path);
+ this.structuredLogger.testStart(this.currentTest.path);
this.SimpleTest.reset();
// Load the tests into a testscope
let currentScope = this.currentTest.scope = new testScope(this, this.currentTest, this.currentTest.expected);
let currentTest = this.currentTest;
// Import utils in the test scope.
@@ -1073,19 +1060,19 @@ function testScope(aTester, aTest, expec
self.__waitTimer = null;
self.__tester.nextTest();
}
});
}
};
this.requestCompleteLog = function test_requestCompleteLog() {
- self.__tester.dumper.structuredLogger.deactivateBuffering();
+ self.__tester.structuredLogger.deactivateBuffering();
self.registerCleanupFunction(function() {
- self.__tester.dumper.structuredLogger.activateBuffering();
+ self.__tester.structuredLogger.activateBuffering();
})
};
}
testScope.prototype = {
__done: true,
__tasks: null,
__waitTimer: null,
__cleanupFunctions: [],
--- a/testing/mochitest/install.rdf
+++ b/testing/mochitest/install.rdf
@@ -1,15 +1,18 @@
<?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>mochikit@mozilla.org</em:id>
<em:version>1.0</em:version>
+#ifdef MOCHITEST_BOOTSTRAP
+ <em:bootstrap>true</em:bootstrap>
+#endif
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
#expand <em:minVersion>__MOZILLA_VERSION_U__</em:minVersion>
#expand <em:maxVersion>__MOZILLA_VERSION_U__</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
--- a/testing/mochitest/jetpack-addon-harness.js
+++ b/testing/mochitest/jetpack-addon-harness.js
@@ -11,24 +11,17 @@ Cu.import("resource://gre/modules/XPCOMU
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
-// Start the tests after the window has been displayed
-window.addEventListener("load", function testOnLoad() {
- window.removeEventListener("load", testOnLoad);
- window.addEventListener("MozAfterPaint", function testOnMozAfterPaint() {
- window.removeEventListener("MozAfterPaint", testOnMozAfterPaint);
- setTimeout(testInit, 0);
- });
-});
+setTimeout(testInit, 0);
var sdkpath = null;
// Strip off the chrome prefix to get the actual path of the test directory
function realPath(chrome) {
return chrome.substring("chrome://mochitests/content/jetpack-addon/".length)
.replace(".xpi", "");
}
--- a/testing/mochitest/jetpack-package-harness.js
+++ b/testing/mochitest/jetpack-package-harness.js
@@ -13,24 +13,17 @@ if (Cc === undefined) {
}
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
-// Start the tests after the window has been displayed
-window.addEventListener("load", function testOnLoad() {
- window.removeEventListener("load", testOnLoad);
- window.addEventListener("MozAfterPaint", function testOnMozAfterPaint() {
- window.removeEventListener("MozAfterPaint", testOnMozAfterPaint);
- setTimeout(testInit, 0);
- });
-});
+setTimeout(testInit, 0);
// Tests a single module
function testModule(require, { url, expected }) {
return new Promise(resolve => {
let path = url.substring(TEST_PACKAGE.length);
const { stdout } = require("sdk/system");
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -540,23 +540,27 @@ class MochitestArguments(ArgumentContain
"times in which case the test must contain at least one of the given tags.",
}],
[["--enable-cpow-warnings"],
{"action": "store_true",
"dest": "enableCPOWWarnings",
"help": "Enable logging of unsafe CPOW usage, which is disabled by default for tests",
"suppress": True,
}],
+ [["--marionette"],
+ {"default": None,
+ "help": "host:port to use when connecting to Marionette",
+ }],
]
defaults = {
# Bug 1065098 - The geckomediaplugin process fails to produce a leak
# log for some reason.
'ignoreMissingLeaks': ["geckomediaplugin"],
-
+ 'extensionsToExclude': ['specialpowers'],
# Set server information on the args object
'webServer': '127.0.0.1',
'httpPort': DEFAULT_PORTS['http'],
'sslPort': DEFAULT_PORTS['https'],
'webSocketPort': '9988',
# The default websocket port is incorrect in mozprofile; it is
# set to the SSL proxy setting. See:
# see https://bugzilla.mozilla.org/show_bug.cgi?id=916517
@@ -804,20 +808,16 @@ class B2GArguments(ArgumentContainer):
args = [
[["--b2gpath"],
{"dest": "b2gPath",
"default": None,
"help": "Path to B2G repo or QEMU directory.",
"suppress": True,
}],
- [["--marionette"],
- {"default": None,
- "help": "host:port to use when connecting to Marionette",
- }],
[["--emulator"],
{"default": None,
"help": "Architecture of emulator to use, x86 or arm",
"suppress": True,
}],
[["--wifi"],
{"default": False,
"help": "Devine wifi configuration for on device mochitest",
@@ -901,16 +901,18 @@ class B2GArguments(ArgumentContainer):
}],
]
defaults = {
'logFile': 'mochitest.log',
# Specialpowers is integrated with marionette for b2g,
# see marionette's jar.mn.
'extensionsToExclude': ['specialpowers'],
+ # mochijar doesn't get installed via marionette on android
+ 'extensionsToInstall': [os.path.join(here, 'mochijar')],
# See dependencies of bug 1038943.
'defaultLeakThreshold': 5536,
}
def validate(self, parser, options, context):
"""Validate b2g options."""
if options.remoteWebServer is None:
@@ -1053,16 +1055,20 @@ class AndroidArguments(ArgumentContainer
"help": "remote directory to use as test root \
(eg. /mnt/sdcard/tests or /data/local/tests)",
"suppress": True,
}],
]
defaults = {
'dm': None,
+ # we don't want to exclude specialpowers on android just yet
+ 'extensionsToExclude': [],
+ # mochijar doesn't get installed via marionette on android
+ 'extensionsToInstall': [os.path.join(here, 'mochijar')],
'logFile': 'mochitest.log',
'utilityPath': None,
}
def validate(self, parser, options, context):
"""Validate android options."""
if build_obj:
--- a/testing/mochitest/moz.build
+++ b/testing/mochitest/moz.build
@@ -14,16 +14,20 @@ DIRS += [
XPI_NAME = 'mochijar'
JAR_MANIFESTS += ['jar.mn']
USE_EXTENSION_MANIFEST = True
FINAL_TARGET_PP_FILES += ['install.rdf']
+if CONFIG['MOZ_BUILD_APP'] != 'mobile/android' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
+ DEFINES['MOCHITEST_BOOTSTRAP'] = True
+ FINAL_TARGET_FILES += ['bootstrap.js']
+
MOCHITEST_MANIFESTS += [
'tests/MochiKit-1.4.2/tests/mochitest.ini',
]
MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini']
TEST_HARNESS_FILES.testing.mochitest += [
'!automation.py',
'/build/mobile/remoteautomation.py',
@@ -32,17 +36,16 @@ TEST_HARNESS_FILES.testing.mochitest +=
'/netwerk/test/httpserver/httpd.js',
'/testing/mozbase/mozdevice/mozdevice/devicemanager.py',
'/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py',
'/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py',
'/testing/mozbase/mozdevice/mozdevice/droid.py',
'/testing/mozbase/mozdevice/mozdevice/version_codes.py',
'/testing/mozbase/mozdevice/mozdevice/Zeroconf.py',
'/testing/mozbase/moznetwork/moznetwork/moznetwork.py',
- 'b2g_start_script.js',
'bisection.py',
'browser-harness.xul',
'browser-test-overlay.xul',
'browser-test.js',
'cc-analyzer.js',
'chrome-harness.js',
'chunkifyTests.js',
'gen_template.pl',
@@ -59,16 +62,18 @@ TEST_HARNESS_FILES.testing.mochitest +=
'nested_setup.js',
'pywebsocket_wrapper.py',
'redirect.html',
'runrobocop.py',
'runtests.py',
'runtestsb2g.py',
'runtestsremote.py',
'server.js',
+ 'start_b2g.js',
+ 'start_desktop.js',
]
TEST_HARNESS_FILES.testing.mochitest.pywebsocket += [
'pywebsocket/standalone.py',
]
TEST_HARNESS_FILES.testing.mochitest.pywebsocket.mod_pywebsocket += [
'pywebsocket/mod_pywebsocket/__init__.py',
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -39,16 +39,25 @@ from manifestparser import TestManifest
from manifestparser.filters import (
chunk_by_dir,
chunk_by_runtime,
chunk_by_slice,
pathprefix,
subsuite,
tags,
)
+
+try:
+ from marionette import Marionette
+ from marionette_driver.addons import Addons
+
+except ImportError:
+ # Marionette not needed nor supported on android
+ Marionette = None
+
from leaks import ShutdownLeaks, LSANLeaks
from mochitest_options import (
MochitestArgumentParser, build_obj, get_default_valgrind_suppression_files
)
from mozprofile import Profile, Preferences
from mozprofile.permissions import ServerLocations
from urllib import quote_plus as encodeURIComponent
from mozlog.formatters import TbplFormatter
@@ -493,46 +502,51 @@ class WebSocketServer(object):
class MochitestBase(object):
"""
Base mochitest class for both desktop and b2g.
"""
oldcwd = os.getcwd()
- jarDir = 'mochijar'
+ mochijar = os.path.join(SCRIPT_DIR, 'mochijar')
# Path to the test script on the server
TEST_PATH = "tests"
NESTED_OOP_TEST_PATH = "nested_oop"
CHROME_PATH = "redirect.html"
urlOpts = []
log = None
def __init__(self, logger_options):
self.update_mozinfo()
self.server = None
self.wsserver = None
self.sslTunnel = None
self._active_tests = None
self._locations = None
+ self.marionette = None
+ self.start_script = None
+ self.start_script_args = []
+
if self.log is None:
commandline.log_formatters["tbpl"] = (
MochitestFormatter,
"Mochitest specific tbpl formatter")
self.log = commandline.setup_logging("mochitest",
logger_options,
{
"tbpl": sys.stdout
})
MochitestBase.log = self.log
self.message_logger = MessageLogger(logger=self.log)
+
def update_mozinfo(self):
"""walk up directories to find mozinfo.json update the info"""
# TODO: This should go in a more generic place, e.g. mozinfo
path = SCRIPT_DIR
dirs = set()
while path != os.path.expanduser('~'):
if path in dirs:
@@ -866,24 +880,16 @@ class MochitestBase(object):
options.profilePath,
os.path.basename(abspath))
shutil.copytree(abspath, dest)
else:
self.log.warning(
"runtests.py | Failed to copy %s to profile" %
abspath)
- def installChromeJar(self, chrome, options):
- """
- copy mochijar directory to profile as an extension so we have chrome://mochikit for all harness code
- """
- # Write chrome.manifest.
- with open(os.path.join(options.profilePath, "extensions", "staged", "mochikit@mozilla.org", "chrome.manifest"), "a") as mfile:
- mfile.write(chrome)
-
def getChromeTestDir(self, options):
dir = os.path.join(os.path.abspath("."), SCRIPT_DIR) + "/"
if mozinfo.isWin:
dir = "file:///" + dir.replace("\\", "/")
return dir
def writeChromeManifest(self, options):
manifest = os.path.join(options.profilePath, "tests.manifest")
@@ -925,49 +931,26 @@ toolbar#nav-bar {
background-image: none !important;
}
"""
with open(os.path.join(options.profilePath, "userChrome.css"), "a") as chromeFile:
chromeFile.write(chrome)
manifest = self.writeChromeManifest(options)
- # Call installChromeJar().
- if not os.path.isdir(os.path.join(SCRIPT_DIR, self.jarDir)):
+ if not os.path.isdir(self.mochijar):
self.log.info(
"TEST-UNEXPECTED-FAIL | invalid setup: missing mochikit extension")
return None
- # Support Firefox (browser), B2G (shell), SeaMonkey (navigator), and Webapp
- # Runtime (webapp).
- chrome = ""
- if options.browserChrome or options.chrome or options.a11y or options.webapprtChrome:
- chrome += """
-overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul
-overlay chrome://browser/content/shell.xhtml chrome://mochikit/content/browser-test-overlay.xul
-overlay chrome://navigator/content/navigator.xul chrome://mochikit/content/browser-test-overlay.xul
-overlay chrome://webapprt/content/webapp.xul chrome://mochikit/content/browser-test-overlay.xul
-"""
-
- if options.jetpackPackage:
- chrome += """
-overlay chrome://browser/content/browser.xul chrome://mochikit/content/jetpack-package-overlay.xul
-"""
-
- if options.jetpackAddon:
- chrome += """
-overlay chrome://browser/content/browser.xul chrome://mochikit/content/jetpack-addon-overlay.xul
-"""
-
- self.installChromeJar(chrome, options)
return manifest
def getExtensionsToInstall(self, options):
"Return a list of extensions to install in the profile"
- extensions = options.extensionsToInstall or []
+ extensions = []
appDir = options.app[
:options.app.rfind(
os.sep)] if options.app else options.utilityPath
extensionDirs = [
# Extensions distributed with the test harness.
os.path.normpath(os.path.join(SCRIPT_DIR, "extensions")),
]
@@ -982,19 +965,17 @@ overlay chrome://browser/content/browser
for extensionDir in extensionDirs:
if os.path.isdir(extensionDir):
for dirEntry in os.listdir(extensionDir):
if dirEntry not in options.extensionsToExclude:
path = os.path.join(extensionDir, dirEntry)
if os.path.isdir(path) or (
os.path.isfile(path) and path.endswith(".xpi")):
extensions.append(path)
-
- # append mochikit
- extensions.append(os.path.join(SCRIPT_DIR, self.jarDir))
+ extensions.extend(options.extensionsToInstall)
return extensions
def logPreamble(self, tests):
"""Logs a suite_start message and test_start/test_end at the beginning of a run.
"""
self.log.suite_start([t['path'] for t in tests])
for test in tests:
if 'disabled' in test:
@@ -1256,16 +1237,30 @@ overlay chrome://browser/content/browser
if parts[2] == pname and parts[1] == '1':
self.log.info("killing %s orphan with pid %d" % (pname, pid))
killPid(pid, self.log)
process = mozprocess.ProcessHandler(['ps', '-o', 'pid,ppid,comm'],
processOutputLine=_psKill)
process.run()
process.wait()
+ def execute_start_script(self):
+ if not self.start_script or not self.marionette:
+ return
+
+ if os.path.isfile(self.start_script):
+ with open(self.start_script, 'r') as fh:
+ script = fh.read()
+ else:
+ script = self.start_script
+
+ with self.marionette.using_context('chrome'):
+ return self.marionette.execute_script(script,
+ script_args=self.start_script_args)
+
class SSLTunnel:
def __init__(self, options, logger, ignoreSSLTunnelExts=False):
self.log = logger
self.process = None
self.utilityPath = options.utilityPath
self.xrePath = options.xrePath
@@ -1500,18 +1495,18 @@ class MochitestDesktop(MochitestBase):
sslTunnel = None
DEFAULT_TIMEOUT = 60.0
mediaDevices = None
# XXX use automation.py for test name to avoid breaking legacy
# TODO: replace this with 'runtests.py' or 'mochitest' or the like
test_name = 'automation.py'
- def __init__(self, logger_options):
- MochitestBase.__init__(self, logger_options)
+ def __init__(self, *args, **kwargs):
+ MochitestBase.__init__(self, *args, **kwargs)
# Max time in seconds to wait for server startup before tests will fail -- if
# this seems big, it's mostly for debug machines where cold startup
# (particularly after a build) takes forever.
self.SERVER_STARTUP_TIMEOUT = 180 if mozinfo.info.get('debug') else 90
# metro browser sub process id
self.browserProcessId = None
@@ -1520,16 +1515,18 @@ class MochitestDesktop(MochitestBase):
# Create variables to count the number of passes, fails, todos.
self.countpass = 0
self.countfail = 0
self.counttodo = 0
self.expectedError = {}
self.result = {}
+ self.start_script = os.path.join(here, 'start_desktop.js')
+
def extraPrefs(self, extraPrefs):
"""interpolate extra preferences from option strings"""
try:
return dict(parseKeyValue(extraPrefs, context='--setpref='))
except KeyValueParseError as e:
print str(e)
sys.exit(1)
@@ -1834,21 +1831,21 @@ class MochitestDesktop(MochitestBase):
extraArgs,
utilityPath,
debuggerInfo=None,
valgrindPath=None,
valgrindArgs=None,
valgrindSuppFiles=None,
symbolsPath=None,
timeout=-1,
- onLaunch=None,
detectShutdownLeaks=False,
screenshotOnFail=False,
bisectChunk=None,
- quiet=False):
+ quiet=False,
+ marionette_args=None):
"""
Run the app, log the duration it took to execute, return the status code.
Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
"""
# configure the message logger buffering
self.message_logger.buffering = quiet
@@ -1902,23 +1899,26 @@ class MochitestDesktop(MochitestBase):
# If a debugger is attached, don't use timeouts, and don't
# capture ctrl-c.
timeout = None
signal.signal(signal.SIGINT, lambda sigid, frame: None)
# build command line
cmd = os.path.abspath(app)
args = list(extraArgs)
+ args.append('-marionette')
# TODO: mozrunner should use -foreground at least for mac
# https://bugzilla.mozilla.org/show_bug.cgi?id=916512
args.append('-foreground')
if testUrl:
if debuggerInfo and debuggerInfo.requiresEscapedArgs:
testUrl = testUrl.replace("&", "\\&")
- args.append(testUrl)
+ self.start_script_args.append(testUrl)
+ else:
+ self.start_script_args.append('about:blank')
if detectShutdownLeaks:
shutdownLeaks = ShutdownLeaks(self.log)
else:
shutdownLeaks = None
if mozinfo.info["asan"] and (mozinfo.isLinux or mozinfo.isMac):
lsanLeaks = LSANLeaks(self.log)
@@ -1958,37 +1958,50 @@ class MochitestDesktop(MochitestBase):
'toolkit') != 'gonk':
runner_cls = mozrunner.Runner
else:
runner_cls = mozrunner.runners.get(
mozinfo.info.get(
'appname',
'firefox'),
mozrunner.Runner)
+
runner = runner_cls(profile=self.profile,
binary=cmd,
cmdargs=args,
env=env,
process_class=mozprocess.ProcessHandlerMixin,
process_args=kp_kwargs)
# start the runner
runner.start(debug_args=debug_args,
interactive=interactive,
outputTimeout=timeout)
proc = runner.process_handler
self.log.info("runtests.py | Application pid: %d" % proc.pid)
self.log.process_start("Main app process")
- if onLaunch is not None:
- # Allow callers to specify an onLaunch callback to be fired after the
- # app is launched.
- # We call onLaunch for b2g desktop mochitests so that we can
- # run a Marionette script after gecko has completed startup.
- onLaunch()
+ # start marionette and kick off the tests
+ marionette_args = marionette_args or {}
+ self.marionette = Marionette(**marionette_args)
+ self.marionette.start_session()
+
+ # install specialpowers and mochikit as temporary addons
+ addons = Addons(self.marionette)
+
+ if mozinfo.info.get('toolkit') != 'gonk':
+ addons.install(os.path.join(here, 'extensions', 'specialpowers'), temp=True)
+ addons.install(self.mochijar, temp=True)
+
+ self.execute_start_script()
+
+ # an open marionette session interacts badly with mochitest,
+ # delete it until we figure out why.
+ self.marionette.delete_session()
+ del self.marionette
# wait until app is finished
# XXX copy functionality from
# https://github.com/mozilla/mozbase/blob/master/mozrunner/mozrunner/runner.py#L61
# until bug 913970 is fixed regarding mozrunner `wait` not returning status
# see https://bugzilla.mozilla.org/show_bug.cgi?id=913970
status = proc.wait()
self.log.process_exit("Main app process", status)
@@ -2081,34 +2094,34 @@ class MochitestDesktop(MochitestBase):
testsToRun = []
for test in tests:
if 'disabled' in test:
continue
testsToRun.append(test['path'])
return testsToRun
- def runMochitests(self, options, testsToRun, onLaunch=None):
+ def runMochitests(self, options, testsToRun):
"This is a base method for calling other methods in this class for --bisect-chunk."
# Making an instance of bisect class for --bisect-chunk option.
bisect = bisection.Bisect(self)
finished = False
status = 0
bisection_log = 0
while not finished:
if options.bisectChunk:
testsToRun = bisect.pre_test(options, testsToRun, status)
# To inform that we are in the process of bisection, and to
# look for bleedthrough
if options.bisectChunk != "default" and not bisection_log:
self.log.info(
"TEST-UNEXPECTED-FAIL | Bisection | Please ignore repeats and look for 'Bleedthrough' (if any) at the end of the failure list")
bisection_log = 1
- result = self.doTests(options, onLaunch, testsToRun)
+ result = self.doTests(options, testsToRun)
if options.bisectChunk:
status = bisect.post_test(
options,
self.expectedError,
self.result)
else:
status = -1
@@ -2118,17 +2131,17 @@ class MochitestDesktop(MochitestBase):
# We need to print the summary only if options.bisectChunk has a value.
# Also we need to make sure that we do not print the summary in between
# running tests via --run-by-dir.
if options.bisectChunk and options.bisectChunk in self.result:
bisect.print_summary()
return result
- def runTests(self, options, onLaunch=None):
+ def runTests(self, options):
""" Prepare, configure, run tests and cleanup """
self.setTestRoot(options)
# Despite our efforts to clean up servers started by this script, in practice
# we still see infrequent cases where a process is orphaned and interferes
# with future tests, typically because the old server is keeping the port in use.
# Try to avoid those failures by checking for and killing orphan servers before
@@ -2136,30 +2149,30 @@ class MochitestDesktop(MochitestBase):
self.killNamedOrphans('ssltunnel')
self.killNamedOrphans('xpcshell')
# Until we have all green, this only runs on bc*/dt*/mochitest-chrome
# jobs, not webapprt*, jetpack*, a11yr (for perf reasons), or plain
testsToRun = self.getTestsToRun(options)
if not options.runByDir:
- return self.runMochitests(options, testsToRun, onLaunch)
+ return self.runMochitests(options, testsToRun)
# code for --run-by-dir
dirs = self.getDirectories(options)
result = 1 # default value, if no tests are run.
for d in dirs:
print "dir: %s" % d
tests_in_dir = [t for t in testsToRun if os.path.dirname(t) == d]
# If we are using --run-by-dir, we should not use the profile path (if) provided
# by the user, since we need to create a new directory for each run. We would face problems
# if we use the directory provided by the user.
- result = self.runMochitests(options, tests_in_dir, onLaunch)
+ result = self.runMochitests(options, tests_in_dir)
# Dump the logging buffer
self.message_logger.dump_buffered()
if result == -1:
break
# printing total number of tests
@@ -2174,17 +2187,17 @@ class MochitestDesktop(MochitestBase):
print "0 INFO TEST-START | Shutdown"
print "1 INFO Passed: %s" % self.countpass
print "2 INFO Failed: %s" % self.countfail
print "3 INFO Todo: %s" % self.counttodo
print "4 INFO SimpleTest FINISHED"
return result
- def doTests(self, options, onLaunch=None, testsToFilter=None):
+ def doTests(self, options, testsToFilter=None):
# A call to initializeLooping method is required in case of --run-by-dir or --bisect-chunk
# since we need to initialize variables for each loop.
if options.bisectChunk or options.runByDir:
self.initializeLooping(options)
# get debugger info, a dict of:
# {'path': path to the debugger (string),
# 'interactive': whether the debugger is interactive or not (bool)
@@ -2312,35 +2325,45 @@ class MochitestDesktop(MochitestBase):
timeout = None
else:
timeout = 330.0 # default JS harness timeout is 300 seconds
# detect shutdown leaks for m-bc runs
detectShutdownLeaks = mozinfo.info[
"debug"] and options.browserChrome and not options.webapprtChrome
+ self.start_script_args.append(self.getTestFlavor(options))
+ marionette_args = {
+ 'symbols_path': options.symbolsPath,
+ }
+
+ if options.marionette:
+ host, port = options.marionette.split(':')
+ marionette_args['host'] = host
+ marionette_args['port'] = int(port)
+
self.log.info("runtests.py | Running tests: start.\n")
try:
status = self.runApp(testURL,
self.browserEnv,
options.app,
profile=self.profile,
extraArgs=options.browserArgs,
utilityPath=options.utilityPath,
debuggerInfo=debuggerInfo,
valgrindPath=valgrindPath,
valgrindArgs=valgrindArgs,
valgrindSuppFiles=valgrindSuppFiles,
symbolsPath=options.symbolsPath,
timeout=timeout,
- onLaunch=onLaunch,
detectShutdownLeaks=detectShutdownLeaks,
screenshotOnFail=options.screenshotOnFail,
bisectChunk=options.bisectChunk,
- quiet=options.quiet
+ quiet=options.quiet,
+ marionette_args=marionette_args,
)
except KeyboardInterrupt:
self.log.info("runtests.py | Received keyboard interrupt.\n")
status = -1
except:
traceback.print_exc()
self.log.error(
"Automation Error: Received unexpected exception while running application\n")
@@ -2573,16 +2596,17 @@ class MochitestDesktop(MochitestBase):
return dirlist
def run_test_harness(options):
logger_options = {
key: value for key, value in vars(options).iteritems()
if key.startswith('log') or key == 'valgrind'}
+
runner = MochitestDesktop(logger_options)
options.runByDir = False
if runner.getTestFlavor(options) == 'mochitest':
options.runByDir = True
if runner.getTestFlavor(options) == 'browser-chrome':
--- a/testing/mochitest/runtestsb2g.py
+++ b/testing/mochitest/runtestsb2g.py
@@ -37,18 +37,18 @@ class MochitestB2G(MochitestBase):
remote_test_root=None,
remote_log_file=None):
MochitestBase.__init__(self, logger_options)
self.marionette_args = marionette_args
self.out_of_process = out_of_process
self.locations_file = locations
self.preferences = []
self.webapps = None
- self.test_script = os.path.join(here, 'b2g_start_script.js')
- self.test_script_args = [self.out_of_process]
+ self.start_script = os.path.join(here, 'start_b2g.js')
+ self.start_script_args = [self.out_of_process]
self.product = 'b2g'
self.remote_chrome_test_dir = None
self.local_log = None
self.local_binary_dir = local_binary_dir
self.preferences = [
os.path.join(
profile_data_dir,
@@ -193,19 +193,19 @@ class MochitestB2G(MochitestBase):
# style manifest. Not so with B2G, that conversion along with updating the URL
# option will happen later. So backup and restore options.manifestFile to
# prevent us from trying to pass in an instance of TestManifest via url param.
manifestFile = options.manifestFile
options.manifestFile = None
self.buildURLOptions(options, {'MOZ_HIDE_RESULTS_TABLE': '1'})
options.manifestFile = manifestFile
- self.test_script_args.append(not options.emulator)
- self.test_script_args.append(options.wifi)
- self.test_script_args.append(options.chrome)
+ self.start_script_args.append(not options.emulator)
+ self.start_script_args.append(options.wifi)
+ self.start_script_args.append(options.chrome)
self.runner.start(outputTimeout=timeout)
self.marionette.wait_for_port()
self.marionette.start_session()
self.marionette.set_context(self.marionette.CONTEXT_CHROME)
# Disable offline status management (bug 777145), otherwise the network
@@ -238,25 +238,17 @@ class MochitestB2G(MochitestBase):
local = MochitestBase.getChromeTestDir(self, options)
local = os.path.join(local, "chrome")
remote = self.remote_chrome_test_dir
self.log.info(
"pushing %s to %s on device..." %
(local, remote))
self.app_ctx.dm.pushDir(local, remote)
- if os.path.isfile(self.test_script):
- with open(self.test_script, 'r') as script:
- self.marionette.execute_script(
- script.read(),
- script_args=self.test_script_args)
- else:
- self.marionette.execute_script(
- self.test_script,
- script_args=self.test_script_args)
+ self.execute_start_script()
status = self.runner.wait()
if status is None:
# the runner has timed out
status = 124
local_leak_file = tempfile.NamedTemporaryFile()
self.app_ctx.dm.getFile(
@@ -357,17 +349,17 @@ class MochitestB2G(MochitestBase):
# For B2G emulators buildURLOptions has been called
# without calling buildTestPath first and that
# causes manifestFile not to be set
if "manifestFile=tests.json" not in self.urlOpts:
self.urlOpts.append("manifestFile=%s" % options.manifestFile)
if len(self.urlOpts) > 0:
test_url += "?" + "&".join(self.urlOpts)
- self.test_script_args.append(test_url)
+ self.start_script_args.append(test_url)
options.profilePath = self.app_ctx.remote_profile
options.logFile = self.local_log
def run_test_harness(options):
# create our Marionette instance
marionette_args = {
--- a/testing/mochitest/runtestsremote.py
+++ b/testing/mochitest/runtestsremote.py
@@ -191,16 +191,30 @@ class MochiRemote(MochitestDesktop):
self.log.error(
"Automation Error: Unable to copy profile to device.")
raise
restoreRemotePaths()
options.profilePath = self.remoteProfile
return manifest
+ def addChromeToProfile(self, options):
+ manifest = MochitestDesktop.addChromeToProfile(self, options)
+
+ # Support Firefox (browser), B2G (shell), SeaMonkey (navigator), and Webapp
+ # Runtime (webapp).
+ if options.chrome:
+ # append overlay to chrome.manifest
+ chrome = "overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul"
+ path = os.path.join(options.profilePath, 'extensions', 'staged',
+ 'mochikit@mozilla.org', 'chrome.manifest')
+ with open(path, "a") as f:
+ f.write(chrome)
+ return manifest
+
def buildURLOptions(self, options, env):
self.localLog = options.logFile
options.logFile = self.remoteLog
options.fileLevel = 'INFO'
options.profilePath = self.localProfile
env["MOZ_HIDE_RESULTS_TABLE"] = "1"
retVal = MochitestDesktop.buildURLOptions(self, options, env)
@@ -276,18 +290,19 @@ class MochiRemote(MochitestDesktop):
def runApp(self, *args, **kwargs):
"""front-end automation.py's `runApp` functionality until FennecRunner is written"""
# automation.py/remoteautomation `runApp` takes the profile path,
# whereas runtest.py's `runApp` takes a mozprofile object.
if 'profileDir' not in kwargs and 'profile' in kwargs:
kwargs['profileDir'] = kwargs.pop('profile').profile
- if 'quiet' in kwargs:
- kwargs.pop('quiet')
+ # remove args not supported by automation.py
+ kwargs.pop('marionette_args', None)
+ kwargs.pop('quiet', None)
return self._automation.runApp(*args, **kwargs)
def run_test_harness(options):
message_logger = MessageLogger(logger=None)
process_args = {'messageLogger': message_logger}
auto = RemoteAutomation(None, "fennec", processArgs=process_args)
rename from testing/mochitest/b2g_start_script.js
rename to testing/mochitest/start_b2g.js
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/start_desktop.js
@@ -0,0 +1,15 @@
+/* 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/. */
+
+const flavor = __marionetteParams[0]
+const url = __marionetteParams[1]
+
+let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
+ .getService(Ci.nsIWindowMediator);
+let win = wm.getMostRecentWindow("navigator:browser");
+
+// mochikit's bootstrap.js has set up a listener for this event. It's
+// used so bootstrap.js knows which flavor and url to load.
+let ev = new CustomEvent('mochitest-load', {'detail': [flavor, url]});
+win.dispatchEvent(ev);
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -88,16 +88,18 @@ user_pref("browser.safebrowsing.download
user_pref("browser.safebrowsing.provider.google.gethashURL", "http://%(server)s/safebrowsing-dummy/gethash");
user_pref("browser.safebrowsing.provider.google.updateURL", "http://%(server)s/safebrowsing-dummy/update");
user_pref("browser.safebrowsing.provider.mozilla.gethashURL", "http://%(server)s/safebrowsing-dummy/gethash");
user_pref("browser.safebrowsing.provider.mozilla.updateURL", "http://%(server)s/safebrowsing-dummy/update");
user_pref("privacy.trackingprotection.introURL", "http://%(server)s/trackingprotection/tour");
// Point update checks to the local testing server for fast failures
user_pref("extensions.update.url", "http://%(server)s/extensions-dummy/updateURL");
user_pref("extensions.update.background.url", "http://%(server)s/extensions-dummy/updateBackgroundURL");
+user_pref("extensions.blocklist.detailsURL", "http://%(server)s/extensions-dummy/blocklistDetailsURL");
+user_pref("extensions.blocklist.itemURL", "http://%(server)s/extensions-dummy/blocklistItemURL");
user_pref("extensions.blocklist.url", "http://%(server)s/extensions-dummy/blocklistURL");
user_pref("extensions.hotfix.url", "http://%(server)s/extensions-dummy/hotfixURL");
user_pref("extensions.systemAddon.update.url", "http://%(server)s/dummy-system-addons.xml");
// Turn off extension updates so they don't bother tests
user_pref("extensions.update.enabled", false);
// Bug 1235627 Turn off pocket add-on so it doesn't bother tests
user_pref("extensions.pocket.enabled", false);
// Make sure opening about:addons won't hit the network
@@ -338,8 +340,9 @@ user_pref("browser.urlbar.suggest.search
// Turn off the location bar search suggestions opt-in. It interferes with
// tests that don't expect it to be there.
user_pref("browser.urlbar.userMadeSearchSuggestionsChoice", true);
user_pref("dom.audiochannel.mutedByDefault", false);
user_pref("webextensions.tests", true);
+user_pref("startup.homepage_welcome_url", "about:blank");