Bug 418772. PGO scripts and input. r=ted.mielczarek.
This commit is contained in:
Родитель
ca4f38116b
Коммит
bbaca81ed1
|
@ -54,6 +54,8 @@ ifeq (WINNT,$(OS_ARCH))
|
|||
DIRS = win32
|
||||
endif
|
||||
|
||||
DIRS += pgo
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
|
|
|
@ -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)
|
|
@ -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 <sayrer@gmail.com>
|
||||
# Jeff Walden <jwalden+bmo@mit.edu>
|
||||
#
|
||||
# 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
|
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>PGO</title>
|
||||
<script src="quit.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Just going to quit after a timeout for now...
|
||||
|
||||
<script>
|
||||
setTimeout(goQuitApplication, 2000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -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 <sayrer@gmail.com>
|
||||
# Jeff Walden <jwalden+bmo@mit.edu>
|
||||
#
|
||||
# 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)
|
|
@ -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 <bob@bclary.com>
|
||||
* Jeff Walden <jwalden+code@mit.edu>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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 #
|
||||
#########
|
||||
|
|
Загрузка…
Ссылка в новой задаче