diff --git a/mozilla/build/Makefile.in b/mozilla/build/Makefile.in index 1a02324459b..f24f6f64d59 100644 --- a/mozilla/build/Makefile.in +++ b/mozilla/build/Makefile.in @@ -54,6 +54,8 @@ ifeq (WINNT,$(OS_ARCH)) DIRS = win32 endif +DIRS += pgo + include $(topsrcdir)/config/rules.mk ifdef ENABLE_TESTS diff --git a/mozilla/build/pgo/Makefile.in b/mozilla/build/pgo/Makefile.in new file mode 100644 index 00000000000..4a54d75cc40 --- /dev/null +++ b/mozilla/build/pgo/Makefile.in @@ -0,0 +1,101 @@ +# +# ***** 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 Communicator client code, released +# March 31, 1998. +# +# The Initial Developer of the Original Code is +# Mozilla Corporation. +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +relativesrcdir = build/pgo + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/rules.mk + +# Stuff to make a build with a profile +_PROFILE_DIR = $(DEPTH)/_profile/pgo + +_PGO_FILES = \ + automation.py \ + profileserver.py \ + index.html \ + quit.js \ + $(NULL) + + +ifeq ($(USE_SHORT_LIBNAME), 1) +PROGRAM = $(MOZ_APP_NAME)$(BIN_SUFFIX) +else +PROGRAM = $(MOZ_APP_NAME)-bin$(BIN_SUFFIX) +endif + +ifeq ($(OS_ARCH),Darwin) +ifdef MOZ_DEBUG +browser_path = \"$(DIST)/$(MOZ_APP_DISPLAYNAME)Debug.app/Contents/MacOS/$(PROGRAM)\" +else +browser_path = \"$(DIST)/$(MOZ_APP_DISPLAYNAME).app/Contents/MacOS/$(PROGRAM)\" +endif +else +browser_path = \"$(DIST)/bin/$(PROGRAM)\" +endif + +AUTOMATION_PPARGS = \ + -DBROWSER_PATH=$(browser_path) \ + -DXPC_BIN_PATH=\"$(DIST)/bin\" \ + $(NULL) + +ifeq ($(OS_ARCH),Darwin) +AUTOMATION_PPARGS += -DIS_MAC=1 +else +AUTOMATION_PPARGS += -DIS_MAC=0 +endif + +ifeq ($(host_os), cygwin) +AUTOMATION_PPARGS += -DIS_CYGWIN=1 +endif + +automation.py: automation.py.in + $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ + $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@ + +profileserver.py: profileserver.py.in + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $^ > $@ + chmod +x $@ + +GARBAGE += automation.py profileserver.py + +libs:: $(_PGO_FILES) + $(INSTALL) $^ $(_PROFILE_DIR) diff --git a/mozilla/build/pgo/automation.py.in b/mozilla/build/pgo/automation.py.in new file mode 100644 index 00000000000..28d00b39360 --- /dev/null +++ b/mozilla/build/pgo/automation.py.in @@ -0,0 +1,275 @@ +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Robert Sayre +# Jeff Walden +# +# 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 ***** + +from datetime import datetime +import itertools +import shutil +import os +import sys + +""" +Runs the browser from a script, and provides useful utilities +for setting up the browser environment. +""" + +# Since some tests require cross-domain support in Mochitest, across ports, +# domains, subdomains, etc. we use a proxy autoconfig hack to map a bunch of +# servers onto localhost:8888. We have to grant them the same privileges as +# localhost:8888 here, since the browser only knows them as the URLs they're +# pretending to be. We also have two servers which are set up but don't have +# privileges, for testing privilege functionality. +# +# These lists must be kept in sync with the following list: +# +# http://developer.mozilla.org/en/docs/Mochitest#How_do_I_test_issues_which_only_show_up_when_tests_are_run_across_domains.3F +# +servers = [ + "localhost:8888", # MUST be first -- see PAC pref-setting code + "example.org:80", + "test1.example.org:80", + "test2.example.org:80", + "sub1.test1.example.org:80", + "sub1.test2.example.org:80", + "sub2.test1.example.org:80", + "sub2.test2.example.org:80", + "example.org:8000", + "test1.example.org:8000", + "test2.example.org:8000", + "sub1.test1.example.org:8000", + "sub1.test2.example.org:8000", + "sub2.test1.example.org:8000", + "sub2.test2.example.org:8000", + "example.com:80", + "test1.example.com:80", + "test2.example.com:80", + "sub1.test1.example.com:80", + "sub1.test2.example.com:80", + "sub2.test1.example.com:80", + "sub2.test2.example.com:80", + "sectest1.example.org:80", + "sub.sectest2.example.org:80", + "sub1.xn--lt-uia.example.org:8000", # U+00E4 U+006C U+0074 + "sub2.xn--lt-uia.example.org:80", # U+00E4 U+006C U+0074 + "xn--exmple-cua.test:80", + "sub1.xn--exmple-cua.test:80", + "xn--hxajbheg2az3al.xn--jxalpdlp:80", # Greek IDN for example.test + "sub1.xn--hxajbheg2az3al.xn--jxalpdlp:80", + ] + +unprivilegedServers = [ + "sectest2.example.org:80", + "sub.sectest1.example.org:80", + ] + + +# These are generated in mozilla/build/Makefile.in +#expand DIST_BIN = "./" + __XPC_BIN_PATH__ +#expand IS_WIN32 = len("__WIN32__") != 0 +#expand IS_MAC = __IS_MAC__ != 0 +#ifdef IS_CYGWIN +#expand IS_CYGWIN = __IS_CYGWIN__ == 1 +#else +IS_CYGWIN = False +#endif + +UNIXISH = not IS_WIN32 and not IS_MAC + +#expand DEFAULT_APP = "./" + __BROWSER_PATH__ + +################# +# SUBPROCESSING # +################# + +class Process: + """ + Represents a subprocess of this process. We don't just directly use the + subprocess module here because we want compatibility with Python 2.3 on + non-Windows platforms. :-( + """ + + def __init__(self, command, args, env): + """ + Executes the given command, which must be an absolute path, with the given + arguments in the given environment. + """ + command = os.path.abspath(command) + if IS_WIN32: + import subprocess + cmd = [command] + cmd.extend(args) + self._process = subprocess.Popen(cmd, env = env) + else: + import popen2 + cmd = [] + for (k, v) in env.iteritems(): + cmd.append(k + "='" + v + "' ") + cmd.append("'" + command + "'") + cmd.extend(map(lambda x: "'" + x + "'", args)) + cmd = " ".join(cmd) + self._process = popen2.Popen4(cmd) + self.pid = self._process.pid + + def wait(self): + "Waits for this process to finish, then returns the process's status." + if IS_WIN32: + return self._process.wait() + # popen2 is a bit harder to work with because we have to manually redirect + # output to stdout + p = self._process + stdout = sys.stdout + out = p.fromchild + while p.poll() == -1: + line = out.readline().rstrip() + if len(line) > 0: + print >> stdout, line + # read in the last lines that happened between the last -1 poll and the + # process finishing + for line in out: + line = line.rstrip() + if len(line) > 0: + print >> stdout, line + return p.poll() + + +####################### +# PROFILE SETUP # +####################### + +def initializeProfile(profileDir): + "Sets up the standard testing profile." + + # Start with a clean slate. + shutil.rmtree(profileDir, True) + os.mkdir(profileDir) + + prefs = [] + + part = """\ +user_pref("browser.dom.window.dump.enabled", true); +user_pref("dom.disable_open_during_load", false); +user_pref("dom.max_script_run_time", 0); // no slow script dialogs +user_pref("signed.applets.codebase_principal_support", true); +user_pref("security.warn_submit_insecure", false); +user_pref("browser.shell.checkDefaultBrowser", false); +user_pref("browser.warnOnQuit", false); +""" + prefs.append(part) + + # Grant God-power to all the servers on which tests can run. + for (i, server) in itertools.izip(itertools.count(1), servers): + part = """ +user_pref("capability.principal.codebase.p%(i)d.granted", + "UniversalXPConnect UniversalBrowserRead UniversalBrowserWrite \ + UniversalPreferencesRead UniversalPreferencesWrite \ + UniversalFileRead"); +user_pref("capability.principal.codebase.p%(i)d.id", "http://%(server)s"); +user_pref("capability.principal.codebase.p%(i)d.subjectName", ""); +""" % {"i": i, "server": server} + prefs.append(part) + + # Now add the two servers that do NOT have God-power so we can properly test + # the granting and receiving of God-power. Strip off the first server because + # we proxy all the others to it. + allServers = servers[1:] + unprivilegedServers + + + # Now actually create the preference to make the proxying happen. + quotedServers = ", ".join(map(lambda x: "'" + x + "'", allServers)) + + pacURL = """data:text/plain, +function FindProxyForURL(url, host) +{ + var servers = [%(quotedServers)s]; + var regex = new RegExp('http://(.*?(:\\\\\\\\d+)?)/'); + var matches = regex.exec(url); + if (!matches) + return 'DIRECT'; + var hostport = matches[1], port = matches[2]; + if (!port) + hostport += ':80'; + if (servers.indexOf(hostport) >= 0) + return 'PROXY localhost:8888'; + return 'DIRECT'; +}""" % {"quotedServers": quotedServers} + pacURL = "".join(pacURL.splitlines()) + + part = """ +user_pref("network.proxy.type", 2); +user_pref("network.proxy.autoconfig_url", "%(pacURL)s"); +""" % {"pacURL": pacURL} + prefs.append(part) + + # write the preferences + prefsFile = open(profileDir + "/" + "user.js", "a") + prefsFile.write("".join(prefs)) + prefsFile.close() + + +####################### +# RUN THE APP # +####################### + +def runApp(testURL, env, app, profileDir): + "Run the app, returning the time at which it was started." + # mark the start + start = datetime.now() + + # now run with the profile we created + cmd = app + if IS_MAC and not cmd.endswith("-bin"): + cmd += "-bin" + cmd = os.path.abspath(cmd) + + args = [] + if IS_MAC: + args.append("-foreground") + + if IS_CYGWIN: + profileDirectory = commands.getoutput("cygpath -w \"" + profileDir + "/\"") + else: + profileDirectory = profileDir + "/" + + args.extend(("-no-remote", "-profile", profileDirectory, testURL)) + proc = Process(cmd, args, env = env) + print "Application pid: " + str(proc.pid) + status = proc.wait() + if status != 0: + print "FAIL Exited with code " + str(status) + " during test run" + + return start \ No newline at end of file diff --git a/mozilla/build/pgo/index.html b/mozilla/build/pgo/index.html new file mode 100644 index 00000000000..118ced6ee55 --- /dev/null +++ b/mozilla/build/pgo/index.html @@ -0,0 +1,14 @@ + + +PGO + + + + +Just going to quit after a timeout for now... + + + + \ No newline at end of file diff --git a/mozilla/build/pgo/profileserver.py.in b/mozilla/build/pgo/profileserver.py.in new file mode 100644 index 00000000000..5c008a51f3f --- /dev/null +++ b/mozilla/build/pgo/profileserver.py.in @@ -0,0 +1,77 @@ +#literal #!/usr/bin/python +# +# ***** 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.org code. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Robert Sayre +# Jeff Walden +# +# 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 ***** + +import SimpleHTTPServer +import SocketServer +import socket +import threading +import os +import sys +import shutil +from datetime import datetime +import automation + +PORT = 8888 +SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))) +PROFILE_DIRECTORY = os.path.abspath(os.path.join(SCRIPT_DIR, "./pgoprofile")) +os.chdir(SCRIPT_DIR) + +class EasyServer(SocketServer.TCPServer): + allow_reuse_address = True + +if __name__ == '__main__': + httpd = EasyServer(("", PORT), SimpleHTTPServer.SimpleHTTPRequestHandler) + t = threading.Thread(target=httpd.serve_forever) + t.setDaemon(True) # don't hang on exit + t.start() + + automation.initializeProfile(PROFILE_DIRECTORY) + browserEnv = dict(os.environ) + + # These variables are necessary for correct application startup; change + # via the commandline at your own risk. + browserEnv["NO_EM_RESTART"] = "1" + browserEnv["XPCOM_DEBUG_BREAK"] = "warn" + if automation.UNIXISH: + browserEnv["LD_LIBRARY_PATH"] = os.path.join(SCRIPT_DIR, automation.DIST_BIN) + browserEnv["MOZILLA_FIVE_HOME"] = os.path.join(SCRIPT_DIR, automation.DIST_BIN) + + automation.runApp("http://localhost:%d/index.html" % PORT, browserEnv, + os.path.join(SCRIPT_DIR, automation.DEFAULT_APP), PROFILE_DIRECTORY) diff --git a/mozilla/build/pgo/quit.js b/mozilla/build/pgo/quit.js new file mode 100644 index 00000000000..360ba2df56f --- /dev/null +++ b/mozilla/build/pgo/quit.js @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; -*- */ +/* ***** 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 Automated Testing Code. + * + * The Initial Developer of the Original Code is + * Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bob Clary + * Jeff Walden + * + * 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 ***** */ + +/* + From mozilla/toolkit/content + These files did not have a license +*/ + +function quitHook() +{ + var xhr = new XMLHttpRequest(); + xhr.open("GET", "http://" + location.host + "/server/shutdown", true); + xhr.onreadystatechange = function (event) + { + if (xhr.readyState == 4) + goQuitApplication(); + }; + xhr.send(null); +} + +function canQuitApplication() +{ + var os = Components.classes["@mozilla.org/observer-service;1"] + .getService(Components.interfaces.nsIObserverService); + if (!os) + { + return true; + } + + try + { + var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"] + .createInstance(Components.interfaces.nsISupportsPRBool); + os.notifyObservers(cancelQuit, "quit-application-requested", null); + + // Something aborted the quit process. + if (cancelQuit.data) + { + return false; + } + } + catch (ex) + { + } + return true; +} + +function goQuitApplication() +{ + const privs = 'UniversalXPConnect'; + + try + { + netscape.security.PrivilegeManager.enablePrivilege(privs); + } + catch(ex) + { + throw('goQuitApplication: privilege failure ' + ex); + } + + if (!canQuitApplication()) + { + return false; + } + + const kAppStartup = '@mozilla.org/toolkit/app-startup;1'; + const kAppShell = '@mozilla.org/appshell/appShellService;1'; + var appService; + var forceQuit; + + if (kAppStartup in Components.classes) + { + appService = Components.classes[kAppStartup]. + getService(Components.interfaces.nsIAppStartup); + forceQuit = Components.interfaces.nsIAppStartup.eForceQuit; + + } + else if (kAppShell in Components.classes) + { + appService = Components.classes[kAppShell]. + getService(Components.interfaces.nsIAppShellService); + forceQuit = Components.interfaces.nsIAppShellService.eForceQuit; + } + else + { + throw 'goQuitApplication: no AppStartup/appShell'; + } + + try + { + appService.quit(forceQuit); + } + catch(ex) + { + throw('goQuitApplication: ' + ex); + } + + return true; +} + diff --git a/mozilla/testing/mochitest/Makefile.in b/mozilla/testing/mochitest/Makefile.in index 86718cecf8c..a79ceb058a4 100644 --- a/mozilla/testing/mochitest/Makefile.in +++ b/mozilla/testing/mochitest/Makefile.in @@ -55,6 +55,7 @@ include $(topsrcdir)/config/rules.mk _SERV_FILES = \ runtests.pl \ runtests.py \ + automation.py \ gen_template.pl \ server.js \ harness-a11y.xul \ @@ -105,14 +106,18 @@ TEST_DRIVER_PPARGS += -DIS_CYGWIN=1 endif runtests.pl: runtests.pl.in - $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \ + $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ $(TEST_DRIVER_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@ runtests.py: runtests.py.in - $(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \ + $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ $(TEST_DRIVER_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@ -GARBAGE += runtests.pl runtests.py +automation.py: $(topsrcdir)/build/pgo/automation.py.in + $(PYTHON) $(topsrcdir)/config/Preprocessor.py \ + $(TEST_DRIVER_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@ + +GARBAGE += runtests.pl runtests.py automation.py libs:: $(_SERV_FILES) $(INSTALL) $^ $(_DEST_DIR) diff --git a/mozilla/testing/mochitest/runtests.py.in b/mozilla/testing/mochitest/runtests.py.in index 13a35b91ec8..78eadffdd72 100644 --- a/mozilla/testing/mochitest/runtests.py.in +++ b/mozilla/testing/mochitest/runtests.py.in @@ -42,18 +42,16 @@ Runs the Mochitest test harness. """ from datetime import datetime -import itertools import optparse import os import os.path -import shutil import signal import sys import time from urllib import quote_plus as encodeURIComponent import urllib2 import commands - +import automation # Path to the test script on the server TEST_SERVER_HOST = "localhost:8888" @@ -70,73 +68,8 @@ SERVER_SHUTDOWN_URL = "http://" + TEST_SERVER_HOST + "/server/shutdown" # (particularly after a build) takes forever. SERVER_STARTUP_TIMEOUT = 45 -# Since some tests require cross-domain support in Mochitest, across ports, -# domains, subdomains, etc. we use a proxy autoconfig hack to map a bunch of -# servers onto localhost:8888. We have to grant them the same privileges as -# localhost:8888 here, since the browser only knows them as the URLs they're -# pretending to be. We also have two servers which are set up but don't have -# privileges, for testing privilege functionality. -# -# These lists must be kept in sync with the following list: -# -# http://developer.mozilla.org/en/docs/Mochitest#How_do_I_test_issues_which_only_show_up_when_tests_are_run_across_domains.3F -# -servers = [ - "localhost:8888", # MUST be first -- see PAC pref-setting code - "example.org:80", - "test1.example.org:80", - "test2.example.org:80", - "sub1.test1.example.org:80", - "sub1.test2.example.org:80", - "sub2.test1.example.org:80", - "sub2.test2.example.org:80", - "example.org:8000", - "test1.example.org:8000", - "test2.example.org:8000", - "sub1.test1.example.org:8000", - "sub1.test2.example.org:8000", - "sub2.test1.example.org:8000", - "sub2.test2.example.org:8000", - "example.com:80", - "test1.example.com:80", - "test2.example.com:80", - "sub1.test1.example.com:80", - "sub1.test2.example.com:80", - "sub2.test1.example.com:80", - "sub2.test2.example.com:80", - "sectest1.example.org:80", - "sub.sectest2.example.org:80", - "sub1.xn--lt-uia.example.org:8000", # U+00E4 U+006C U+0074 - "sub2.xn--lt-uia.example.org:80", # U+00E4 U+006C U+0074 - "xn--exmple-cua.test:80", - "sub1.xn--exmple-cua.test:80", - "xn--hxajbheg2az3al.xn--jxalpdlp:80", # Greek IDN for example.test - "sub1.xn--hxajbheg2az3al.xn--jxalpdlp:80", - ] - -unprivilegedServers = [ - "sectest2.example.org:80", - "sub.sectest1.example.org:80", - ] - PROFILE_DIRECTORY = os.path.abspath("./mochitesttestingprofile") - # These are generated in mozilla/testing/mochitest/Makefile.in -#expand DIST_BIN = "./" + __XPC_BIN_PATH__ -#expand IS_WIN32 = len("__WIN32__") != 0 -#expand IS_MAC = __IS_MAC__ != 0 -#ifdef IS_CYGWIN -#expand IS_CYGWIN = __IS_CYGWIN__ == 1 -#else -IS_CYGWIN = False -#endif - -UNIXISH = not IS_WIN32 and not IS_MAC - - -#expand DEFAULT_APP = "./" + __BROWSER_PATH__ - - ####################### # COMMANDLINE OPTIONS # ####################### @@ -155,7 +88,7 @@ class MochitestOptions(optparse.OptionParser): self.add_option("--appname", action = "store", type = "string", dest = "app", help = "absolute path to application, overriding default") - defaults["app"] = DEFAULT_APP + defaults["app"] = automation.DEFAULT_APP self.add_option("--log-file", action = "store", type = "string", dest = "logFile", @@ -242,16 +175,17 @@ class MochitestServer: "Run the Mochitest server, returning the process ID of the server." env = dict(os.environ) - if UNIXISH: - env["LD_LIBRARY_PATH"] = DIST_BIN - env["MOZILLA_FIVE_HOME"] = DIST_BIN + if automation.UNIXISH: + env["LD_LIBRARY_PATH"] = automation.DIST_BIN + env["MOZILLA_FIVE_HOME"] = automation.DIST_BIN env["XPCOM_DEBUG_BREAK"] = "warn" args = ["-v", "170", "-f", "./" + "httpd.js", "-f", "./" + "server.js"] - self._process = Process(DIST_BIN + "/" + "xpcshell", args, env = env) + xpcshell = automation.DIST_BIN + "/" + "xpcshell"; + self._process = automation.Process(xpcshell, args, env = env) pid = self._process.pid if pid < 0: print "Error starting server." @@ -282,68 +216,12 @@ class MochitestServer: c.close() os.waitpid(pid, 0) except: - if IS_WIN32: + if automation.IS_WIN32: pass # XXX do something here! else: os.kill(pid, signal.SIGKILL) - -################# -# SUBPROCESSING # -################# - -class Process: - """ - Represents a subprocess of this process. We don't just directly use the - subprocess module here because we want compatibility with Python 2.3 on - non-Windows platforms. :-( - """ - - def __init__(self, command, args, env): - """ - Executes the given command, which must be an absolute path, with the given - arguments in the given environment. - """ - command = os.path.abspath(command) - if IS_WIN32: - import subprocess - cmd = [command] - cmd.extend(args) - self._process = subprocess.Popen(cmd, env = env) - else: - import popen2 - cmd = [] - for (k, v) in env.iteritems(): - cmd.append(k + "='" + v + "' ") - cmd.append("'" + command + "'") - cmd.extend(map(lambda x: "'" + x + "'", args)) - cmd = " ".join(cmd) - self._process = popen2.Popen4(cmd) - self.pid = self._process.pid - - def wait(self): - "Waits for this process to finish, then returns the process's status." - if IS_WIN32: - return self._process.wait() - # popen2 is a bit harder to work with because we have to manually redirect - # output to stdout - p = self._process - stdout = sys.stdout - out = p.fromchild - while p.poll() == -1: - line = out.readline().rstrip() - if len(line) > 0: - print >> stdout, line - # read in the last lines that happened between the last -1 poll and the - # process finishing - for line in out: - line = line.rstrip() - if len(line) > 0: - print >> stdout, line - return p.poll() - - ################# # MAIN FUNCTION # ################# @@ -366,9 +244,9 @@ Are you executing $objdir/_tests/testing/mochitest/runtests.py?""" # via the commandline at your own risk. browserEnv["NO_EM_RESTART"] = "1" browserEnv["XPCOM_DEBUG_BREAK"] = "warn" - if UNIXISH: - browserEnv["LD_LIBRARY_PATH"] = DIST_BIN - browserEnv["MOZILLA_FIVE_HOME"] = DIST_BIN + if automation.UNIXISH: + browserEnv["LD_LIBRARY_PATH"] = automation.DIST_BIN + browserEnv["MOZILLA_FIVE_HOME"] = automation.DIST_BIN for v in options.environment: ix = v.find("=") @@ -377,7 +255,8 @@ Are you executing $objdir/_tests/testing/mochitest/runtests.py?""" sys.exit(1) browserEnv[v[:ix]] = v[ix + 1:] - manifest = initializeProfile(options) + automation.initializeProfile(PROFILE_DIRECTORY) + manifest = addChromeToProfile(options) server = MochitestServer(options) server.start() @@ -425,7 +304,7 @@ Are you executing $objdir/_tests/testing/mochitest/runtests.py?""" testURL += "?" + "&".join(urlOpts) - start = runTests(testURL, browserEnv, options) + start = automation.runApp(testURL, browserEnv, options.app, PROFILE_DIRECTORY) server.stop() @@ -468,78 +347,8 @@ def makeTestConfig(options): config.close() -def initializeProfile(options): - "Sets up the standard Mochitest profile." - - # Start with a clean slate. - shutil.rmtree(PROFILE_DIRECTORY, True) - os.mkdir(PROFILE_DIRECTORY) - - - prefs = [] - - part = """\ -user_pref("browser.dom.window.dump.enabled", true); -user_pref("dom.disable_open_during_load", false); -user_pref("dom.max_script_run_time", 0); // no slow script dialogs -user_pref("signed.applets.codebase_principal_support", true); -user_pref("security.warn_submit_insecure", false); -user_pref("browser.shell.checkDefaultBrowser", false); -user_pref("browser.warnOnQuit", false); -""" - prefs.append(part) - - # Grant God-power to all the servers on which tests can run. - for (i, server) in itertools.izip(itertools.count(1), servers): - part = """ -user_pref("capability.principal.codebase.p%(i)d.granted", - "UniversalXPConnect UniversalBrowserRead UniversalBrowserWrite \ - UniversalPreferencesRead UniversalPreferencesWrite \ - UniversalFileRead"); -user_pref("capability.principal.codebase.p%(i)d.id", "http://%(server)s"); -user_pref("capability.principal.codebase.p%(i)d.subjectName", ""); -""" % {"i": i, "server": server} - prefs.append(part) - - # Now add the two servers that do NOT have God-power so we can properly test - # the granting and receiving of God-power. Strip off the first server because - # we proxy all the others to it. - allServers = servers[1:] + unprivilegedServers - - - # Now actually create the preference to make the proxying happen. - quotedServers = ", ".join(map(lambda x: "'" + x + "'", allServers)) - - pacURL = """data:text/plain, -function FindProxyForURL(url, host) -{ - var servers = [%(quotedServers)s]; - var regex = new RegExp('http://(.*?(:\\\\\\\\d+)?)/'); - var matches = regex.exec(url); - if (!matches) - return 'DIRECT'; - var hostport = matches[1], port = matches[2]; - if (!port) - hostport += ':80'; - if (servers.indexOf(hostport) >= 0) - return 'PROXY localhost:8888'; - return 'DIRECT'; -}""" % {"quotedServers": quotedServers} - pacURL = "".join(pacURL.splitlines()) - - part = """ -user_pref("network.proxy.type", 2); -user_pref("network.proxy.autoconfig_url", "%(pacURL)s"); -""" % {"pacURL": pacURL} - prefs.append(part) - - # write the preferences - prefsFile = open(PROFILE_DIRECTORY + "/" + "user.js", "a") - prefsFile.write("".join(prefs)) - prefsFile.close() - - - # Now onto chrome config changes +def addChromeToProfile(options): + "Adds MochiKit chrome tests to the profile." chromedir = PROFILE_DIRECTORY + "/" + "chrome" os.mkdir(chromedir) @@ -568,7 +377,7 @@ toolbar#nav-bar { # register our chrome dir chrometestDir = os.path.abspath(".") + "/" - if IS_WIN32: + if automation.IS_WIN32: chrometestDir = "file:///" + chrometestDir.replace("\\", "/") @@ -584,45 +393,6 @@ toolbar#nav-bar { return manifest - - - ################## - # TEST EXECUTION # - ################## - -def runTests(testURL, env, options): - "Run the tests, returning the time at which the tests were started." - - # mark the start - start = datetime.now() - - # now run with the profile we created - cmd = options.app - if IS_MAC and not cmd.endswith("-bin"): - cmd += "-bin" - cmd = os.path.abspath(cmd) - - args = [] - if IS_MAC: - args.append("-foreground") - - if IS_CYGWIN: - profileDirectory = commands.getoutput("cygpath -w \"" + PROFILE_DIRECTORY + "/\"") - else: - profileDirectory = PROFILE_DIRECTORY + "/" - - args.extend(("-no-remote", "-profile", profileDirectory, testURL)) - - proc = Process(cmd, args, env = env) - print "Application pid: " + str(proc.pid) - status = proc.wait() - if status != 0: - print "FAIL Exited with code " + str(status) + " during test run" - - return start - - - ######### # DO IT # #########