Bug 907770 - Part 1: Making ssltunnel run for android and b2g mochitests. r=jmaher

This commit is contained in:
Martin Thomson 2014-03-14 11:25:41 -07:00
Родитель d1212d39f6
Коммит 2739930979
4 изменённых файлов: 352 добавлений и 336 удалений

Просмотреть файл

@ -409,6 +409,13 @@ class MochitestOptions(optparse.OptionParser):
"dest": "quiet",
"help": "Do not print test log lines unless a failure occurs."
}],
[["--pidfile"],
{ "action": "store",
"type": "string",
"dest": "pidFile",
"help": "name of the pidfile to generate",
"default": "",
}],
]
def __init__(self, **kwargs):
@ -669,13 +676,6 @@ class B2GOptions(MochitestOptions):
"help": "ip address where the remote web server is hosted at",
"default": None,
}],
[["--pidfile"],
{ "action": "store",
"type": "string",
"dest": "pidFile",
"help": "name of the pidfile to generate",
"default": "",
}],
[["--gecko-path"],
{ "action": "store",
"type": "string",

Просмотреть файл

@ -262,6 +262,10 @@ class MochitestUtilsMixin(object):
def __init__(self):
self.update_mozinfo()
self.server = None
self.wsserver = None
self.sslTunnel = None
self._locations = None
def update_mozinfo(self):
"""walk up directories to find mozinfo.json update the info"""
@ -287,6 +291,14 @@ class MochitestUtilsMixin(object):
"""
return self.getFullPath(logFile)
@property
def locations(self):
if self._locations is not None:
return self._locations
locations_file = os.path.join(SCRIPT_DIR, 'server-locations.txt')
self._locations = ServerLocations(locations_file)
return self._locations
def buildURLOptions(self, options, env):
""" Add test control options from the command line to the url
@ -507,43 +519,71 @@ class MochitestUtilsMixin(object):
def startWebSocketServer(self, options, debuggerInfo):
""" Launch the websocket server """
if options.webServer != '127.0.0.1':
return
self.wsserver = WebSocketServer(options, SCRIPT_DIR, debuggerInfo)
self.wsserver.start()
def stopWebSocketServer(self, options):
if options.webServer != '127.0.0.1':
return
log.info('Stopping web socket server')
self.wsserver.stop()
def startWebServer(self, options):
"""Create the webserver and start it up"""
if options.webServer != '127.0.0.1':
return
self.server = MochitestServer(options)
self.server.start()
if options.pidFile != "":
with open(options.pidFile + ".xpcshell.pid", 'w') as f:
f.write("%s" % self.server._process.pid)
def startServers(self, options, debuggerInfo):
# start servers and set ports
# TODO: pass these values, don't set on `self`
self.webServer = options.webServer
self.httpPort = options.httpPort
self.sslPort = options.sslPort
self.webSocketPort = options.webSocketPort
# httpd-path is specified by standard makefile targets and may be specified
# on the command line to select a particular version of httpd.js. If not
# specified, try to select the one from hostutils.zip, as required in bug 882932.
if not options.httpdPath:
options.httpdPath = os.path.join(options.utilityPath, "components")
self.startWebServer(options)
self.startWebSocketServer(options, debuggerInfo)
# start SSL pipe
self.sslTunnel = SSLTunnel(options)
self.sslTunnel.buildConfig(self.locations)
self.sslTunnel.start()
# If we're lucky, the server has fully started by now, and all paths are
# ready, etc. However, xpcshell cold start times suck, at least for debug
# builds. We'll try to connect to the server for awhile, and if we fail,
# we'll try to kill the server and exit with an error.
self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
if self.server is not None:
self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
def stopWebServer(self, options):
""" Server's no longer needed, and perhaps more importantly, anything it might
spew to console shouldn't disrupt the leak information table we print next.
"""
if options.webServer != '127.0.0.1':
return
def stopServers(self):
"""Servers are no longer needed, and perhaps more importantly, anything they
might spew to console might confuse things."""
if self.server is not None:
try:
log.info('Stopping web server')
self.server.stop()
except Exception:
log.exception('Exception when stopping web server')
log.info('Stopping web server')
self.server.stop()
if self.wsserver is not None:
try:
log.info('Stopping web socket server')
self.wsserver.stop()
except Exception:
log.exception('Exception when stopping web socket server');
if self.sslTunnel is not None:
try:
log.info('Stopping ssltunnel')
self.sslTunnel.stop()
except Exception:
log.exception('Exception stopping ssltunnel');
def copyExtraFilesToProfile(self, options):
"Copy extra files or dirs specified on the command line to the testing profile."
@ -642,9 +682,81 @@ overlay chrome://webapprt/content/webapp.xul chrome://mochikit/content/browser-t
extensions.append(os.path.join(SCRIPT_DIR, self.jarDir))
return extensions
class SSLTunnel:
def __init__(self, options):
self.process = None
self.utilityPath = options.utilityPath
self.xrePath = options.xrePath
self.certPath = options.certPath
self.sslPort = options.sslPort
self.httpPort = options.httpPort
self.webServer = options.webServer
self.webSocketPort = options.webSocketPort
self.customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
self.clientAuthRE = re.compile("^clientauth=(?P<clientauth>[a-z]+)")
self.redirRE = re.compile("^redir=(?P<redirhost>[0-9a-zA-Z_ .]+)")
def writeLocation(self, config, loc):
for option in loc.options:
match = self.customCertRE.match(option)
if match:
customcert = match.group("nickname");
config.write("listen:%s:%s:%s:%s\n" %
(loc.host, loc.port, self.sslPort, customcert))
match = self.clientAuthRE.match(option)
if match:
clientauth = match.group("clientauth");
config.write("clientauth:%s:%s:%s:%s\n" %
(loc.host, loc.port, self.sslPort, clientauth))
match = self.redirRE.match(option)
if match:
redirhost = match.group("redirhost")
config.write("redirhost:%s:%s:%s:%s\n" %
(loc.host, loc.port, self.sslPort, redirhost))
def buildConfig(self, locations):
"""Create the ssltunnel configuration file"""
configFd, self.configFile = tempfile.mkstemp(prefix="ssltunnel", suffix=".cfg")
with os.fdopen(configFd, "w") as config:
config.write("httpproxy:1\n")
config.write("certdbdir:%s\n" % self.certPath)
config.write("forward:127.0.0.1:%s\n" % self.httpPort)
config.write("websocketserver:%s:%s\n" % (self.webServer, self.webSocketPort))
config.write("listen:*:%s:pgo server certificate\n" % self.sslPort)
for loc in locations:
if loc.scheme == "https" and "nocert" not in loc.options:
self.writeLocation(config, loc)
def start(self):
""" Starts the SSL Tunnel """
# start ssltunnel to provide https:// URLs capability
bin_suffix = mozinfo.info.get('bin_suffix', '')
ssltunnel = os.path.join(self.utilityPath, "ssltunnel" + bin_suffix)
if not os.path.exists(ssltunnel):
log.error("INFO | runtests.py | expected to find ssltunnel at %s", ssltunnel)
exit(1)
env = environment(xrePath=self.xrePath)
self.process = mozprocess.ProcessHandler([ssltunnel, self.configFile],
env=env)
self.process.run()
log.info("INFO | runtests.py | SSL tunnel pid: %d", self.process.pid)
def stop(self):
""" Stops the SSL Tunnel and cleans up """
if self.process is not None:
self.process.kill()
if os.path.exists(self.configFile):
os.remove(self.configFile)
class Mochitest(MochitestUtilsMixin):
runSSLTunnel = True
certdbNew = False
sslTunnel = None
vmwareHelper = None
DEFAULT_TIMEOUT = 60.0
@ -666,8 +778,6 @@ class Mochitest(MochitestUtilsMixin):
# metro browser sub process id
self.browserProcessId = None
# cached server locations
self._locations = {}
self.haveDumpedScreen = False
@ -680,6 +790,50 @@ class Mochitest(MochitestUtilsMixin):
print str(e)
sys.exit(1)
def fillCertificateDB(self, options):
# TODO: move -> mozprofile:
# https://bugzilla.mozilla.org/show_bug.cgi?id=746243#c35
pwfilePath = os.path.join(options.profilePath, ".crtdbpw")
with open(pwfilePath, "w") as pwfile:
pwfile.write("\n")
# Pre-create the certification database for the profile
env = self.environment(xrePath=options.xrePath)
bin_suffix = mozinfo.info.get('bin_suffix', '')
certutil = os.path.join(options.utilityPath, "certutil" + bin_suffix)
pk12util = os.path.join(options.utilityPath, "pk12util" + bin_suffix)
if self.certdbNew:
# android and b2g use the new DB formats exclusively
certdbPath = "sql:" + options.profilePath
else:
# desktop seems to use the old
certdbPath = options.profilePath
status = call([certutil, "-N", "-d", certdbPath, "-f", pwfilePath], env=env)
if status:
return status
# Walk the cert directory and add custom CAs and client certs
files = os.listdir(options.certPath)
for item in files:
root, ext = os.path.splitext(item)
if ext == ".ca":
trustBits = "CT,,"
if root.endswith("-object"):
trustBits = "CT,,CT"
call([certutil, "-A", "-i", os.path.join(options.certPath, item),
"-d", certdbPath, "-f", pwfilePath, "-n", root, "-t", trustBits],
env=env)
elif ext == ".client":
call([pk12util, "-i", os.path.join(options.certPath, item),
"-w", pwfilePath, "-d", certdbPath],
env=env)
os.unlink(pwfilePath)
return 0
def buildProfile(self, options):
""" create the profile and add optional chrome bits and files if requested """
if options.browserChrome and options.timeout:
@ -698,10 +852,6 @@ class Mochitest(MochitestUtilsMixin):
else:
apps = None
# locations
locations_file = os.path.join(SCRIPT_DIR, 'server-locations.txt')
locations = ServerLocations(locations_file)
# preferences
prefsPath = os.path.join(SCRIPT_DIR, 'profile_data', 'prefs_general.js')
prefs = dict(Preferences.read_prefs(prefsPath))
@ -727,10 +877,11 @@ class Mochitest(MochitestUtilsMixin):
'ws': options.sslPort
}
# create a profile
self.profile = Profile(profile=options.profilePath,
addons=extensions,
locations=locations,
locations=self.locations,
preferences=prefs,
apps=apps,
proxy=proxy
@ -741,6 +892,14 @@ class Mochitest(MochitestUtilsMixin):
manifest = self.addChromeToProfile(options)
self.copyExtraFilesToProfile(options)
# create certificate database for the profile
# TODO: this should really be upstreamed somewhere, maybe mozprofile
certificateStatus = self.fillCertificateDB(options)
if certificateStatus:
log.info("TEST-UNEXPECTED-FAIL | runtests.py | Certificate integration failed")
return None
return manifest
def buildBrowserEnv(self, options, debugger=False):
@ -782,6 +941,13 @@ class Mochitest(MochitestUtilsMixin):
""" remove temporary files and profile """
os.remove(manifest)
del self.profile
if options.pidFile != "":
try:
os.remove(options.pidFile)
if os.path.exists(options.pidFile + ".xpcshell.pid"):
os.remove(options.pidFile + ".xpcshell.pid")
except:
log.warn("cleaning up pidfile '%s' was unsuccessful from the test harness", options.pidFile)
def dumpScreen(self, utilityPath):
if self.haveDumpedScreen:
@ -868,15 +1034,17 @@ class Mochitest(MochitestUtilsMixin):
def stopVMwareRecording(self):
""" stops recording inside VMware VM using the recording helper dll """
assert mozinfo.isWin
if self.vmwareHelper is not None:
log.info("runtests.py | Stopping VMware recording.")
try:
try:
assert mozinfo.isWin
if self.vmwareHelper is not None:
log.info("runtests.py | Stopping VMware recording.")
self.vmwareHelper.StopRecording()
except Exception, e:
log.warning("runtests.py | Failed to stop "
"VMware recording: (%s)" % str(e))
self.vmwareHelper = None
except Exception, e:
log.warning("runtests.py | Failed to stop "
"VMware recording: (%s)" % str(e))
log.exception('Error stopping VMWare recording')
self.vmwareHelper = None
def runApp(self,
testUrl,
@ -885,8 +1053,6 @@ class Mochitest(MochitestUtilsMixin):
profile,
extraArgs,
utilityPath,
xrePath,
certPath,
debuggerInfo=None,
symbolsPath=None,
timeout=-1,
@ -906,16 +1072,6 @@ class Mochitest(MochitestUtilsMixin):
interactive = debuggerInfo['interactive']
debug_args = [debuggerInfo['path']] + debuggerInfo['args']
# ensure existence of required paths
required_paths = ('utilityPath', 'xrePath', 'certPath')
missing = [(path, locals()[path])
for path in required_paths
if not os.path.exists(locals()[path])]
if missing:
log.error("runtests.py | runApp called with missing paths: %s" % (
', '.join([("%s->%s" % (key, value)) for key, value in missing])))
return 1
# fix default timeout
if timeout == -1:
timeout = self.DEFAULT_TIMEOUT
@ -934,28 +1090,6 @@ class Mochitest(MochitestUtilsMixin):
os.close(tmpfd)
env["MOZ_PROCESS_LOG"] = processLog
if self.runSSLTunnel:
# create certificate database for the profile
# TODO: this should really be upstreamed somewhere, maybe mozprofile
certificateStatus = self.fillCertificateDB(self.profile.profile,
certPath,
utilityPath,
xrePath)
if certificateStatus:
log.info("TEST-UNEXPECTED-FAIL | runtests.py | Certificate integration failed")
return certificateStatus
# start ssltunnel to provide https:// URLs capability
ssltunnel = os.path.join(utilityPath, "ssltunnel" + bin_suffix)
ssltunnel_cfg = os.path.join(self.profile.profile, "ssltunnel.cfg")
ssltunnelProcess = mozprocess.ProcessHandler([ssltunnel, ssltunnel_cfg], cwd=SCRIPT_DIR,
env=environment(xrePath=xrePath))
ssltunnelProcess.run()
log.info("INFO | runtests.py | SSL tunnel pid: %d", ssltunnelProcess.pid)
else:
ssltunnelProcess = None
if interactive:
# If an interactive debugger is attached,
# don't use timeouts, and don't capture ctrl-c.
@ -1074,8 +1208,6 @@ class Mochitest(MochitestUtilsMixin):
# cleanup
if os.path.exists(processLog):
os.remove(processLog)
if ssltunnelProcess:
ssltunnelProcess.kill()
return status
@ -1106,104 +1238,82 @@ class Mochitest(MochitestUtilsMixin):
if manifest is None:
return 1
# start servers and set ports
# TODO: pass these values, don't set on `self`
self.webServer = options.webServer
self.httpPort = options.httpPort
self.sslPort = options.sslPort
self.webSocketPort = options.webSocketPort
try:
self.startWebServer(options)
self.startWebSocketServer(options, debuggerInfo)
self.startServers(options, debuggerInfo)
testURL = self.buildTestPath(options)
self.buildURLOptions(options, browserEnv)
if self.urlOpts:
testURL += "?" + "&".join(self.urlOpts)
testURL = self.buildTestPath(options)
self.buildURLOptions(options, browserEnv)
if self.urlOpts:
testURL += "?" + "&".join(self.urlOpts)
if options.webapprtContent:
options.browserArgs.extend(('-test-mode', testURL))
testURL = None
if options.webapprtContent:
options.browserArgs.extend(('-test-mode', testURL))
testURL = None
if options.immersiveMode:
options.browserArgs.extend(('-firefoxpath', options.app))
options.app = self.immersiveHelperPath
if options.immersiveMode:
options.browserArgs.extend(('-firefoxpath', options.app))
options.app = self.immersiveHelperPath
if options.jsdebugger:
options.browserArgs.extend(['-jsdebugger'])
if options.jsdebugger:
options.browserArgs.extend(['-jsdebugger'])
# Remove the leak detection file so it can't "leak" to the tests run.
# The file is not there if leak logging was not enabled in the application build.
if os.path.exists(self.leak_report_file):
os.remove(self.leak_report_file)
# Remove the leak detection file so it can't "leak" to the tests run.
# The file is not there if leak logging was not enabled in the application build.
if os.path.exists(self.leak_report_file):
os.remove(self.leak_report_file)
# then again to actually run mochitest
if options.timeout:
timeout = options.timeout + 30
elif options.debugger or not options.autorun:
timeout = None
else:
timeout = 330.0 # default JS harness timeout is 300 seconds
# then again to actually run mochitest
if options.timeout:
timeout = options.timeout + 30
elif options.debugger or not options.autorun:
timeout = None
else:
timeout = 330.0 # default JS harness timeout is 300 seconds
if options.vmwareRecording:
self.startVMwareRecording(options);
if options.vmwareRecording:
self.startVMwareRecording(options);
log.info("runtests.py | Running tests: start.\n")
try:
status = self.runApp(testURL,
browserEnv,
options.app,
profile=self.profile,
extraArgs=options.browserArgs,
utilityPath=options.utilityPath,
xrePath=options.xrePath,
certPath=options.certPath,
debuggerInfo=debuggerInfo,
symbolsPath=options.symbolsPath,
timeout=timeout,
onLaunch=onLaunch,
webapprtChrome=options.webapprtChrome,
hide_subtests=options.hide_subtests,
screenshotOnFail=options.screenshotOnFail
)
except KeyboardInterrupt:
log.info("runtests.py | Received keyboard interrupt.\n");
status = -1
except:
traceback.print_exc()
log.error("Automation Error: Received unexpected exception while running application\n")
status = 1
log.info("runtests.py | Running tests: start.\n")
try:
status = self.runApp(testURL,
browserEnv,
options.app,
profile=self.profile,
extraArgs=options.browserArgs,
utilityPath=options.utilityPath,
debuggerInfo=debuggerInfo,
symbolsPath=options.symbolsPath,
timeout=timeout,
onLaunch=onLaunch,
webapprtChrome=options.webapprtChrome,
hide_subtests=options.hide_subtests,
screenshotOnFail=options.screenshotOnFail
)
except KeyboardInterrupt:
log.info("runtests.py | Received keyboard interrupt.\n");
status = -1
except:
traceback.print_exc()
log.error("Automation Error: Received unexpected exception while running application\n")
status = 1
finally:
if options.vmwareRecording:
try:
self.stopVMwareRecording();
except Exception:
log.exception('Error stopping VMWare recording')
if options.vmwareRecording:
self.stopVMwareRecording();
self.stopServers()
try:
self.stopWebServer(options)
except Exception:
log.exception('Exception when stopping web server')
processLeakLog(self.leak_report_file, options.leakThreshold)
try:
self.stopWebSocketServer(options)
except Exception:
log.exception('Exception when stopping websocket server')
if self.nsprLogs:
with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip:
for logfile in glob.glob("%s/nspr*.log*" % tempfile.gettempdir()):
logzip.write(logfile)
os.remove(logfile)
processLeakLog(self.leak_report_file, options.leakThreshold)
log.info("runtests.py | Running tests: end.")
if self.nsprLogs:
with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip:
for logfile in glob.glob("%s/nspr*.log*" % tempfile.gettempdir()):
logzip.write(logfile)
os.remove(logfile)
log.info("runtests.py | Running tests: end.")
if manifest is not None:
self.cleanup(manifest, options)
if manifest is not None:
self.cleanup(manifest, options)
return status
@ -1428,93 +1538,6 @@ class Mochitest(MochitestUtilsMixin):
for path in self.getExtensionsToInstall(options):
self.installExtensionFromPath(options, path)
def readLocations(self, locations_file):
"""
Reads the locations at which the Mochitest HTTP server is available from
`locations_file`.
"""
path = os.path.realpath(locations_file)
return self._locations.setdefault(path, ServerLocations(path))
def fillCertificateDB(self, profileDir, certPath, utilityPath, xrePath):
# TODO: move -> mozprofile:
# https://bugzilla.mozilla.org/show_bug.cgi?id=746243#c35
pwfilePath = os.path.join(profileDir, ".crtdbpw")
with open(pwfilePath, "w") as pwfile:
pwfile.write("\n")
# Create head of the ssltunnel configuration file
sslTunnelConfigPath = os.path.join(profileDir, "ssltunnel.cfg")
sslTunnelConfig = open(sslTunnelConfigPath, "w")
sslTunnelConfig.write("httpproxy:1\n")
sslTunnelConfig.write("certdbdir:%s\n" % certPath)
sslTunnelConfig.write("forward:127.0.0.1:%s\n" % self.httpPort)
sslTunnelConfig.write("websocketserver:%s:%s\n" % (self.webServer, self.webSocketPort))
sslTunnelConfig.write("listen:*:%s:pgo server certificate\n" % self.sslPort)
# Configure automatic certificate and bind custom certificates, client authentication
locations = self.readLocations(os.path.join(SCRIPT_DIR, 'server-locations.txt'))
for loc in locations:
if loc.scheme == "https" and "nocert" not in loc.options:
customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
clientAuthRE = re.compile("^clientauth=(?P<clientauth>[a-z]+)")
redirRE = re.compile("^redir=(?P<redirhost>[0-9a-zA-Z_ .]+)")
for option in loc.options:
match = customCertRE.match(option)
if match:
customcert = match.group("nickname");
sslTunnelConfig.write("listen:%s:%s:%s:%s\n" %
(loc.host, loc.port, self.sslPort, customcert))
match = clientAuthRE.match(option)
if match:
clientauth = match.group("clientauth");
sslTunnelConfig.write("clientauth:%s:%s:%s:%s\n" %
(loc.host, loc.port, self.sslPort, clientauth))
match = redirRE.match(option)
if match:
redirhost = match.group("redirhost")
sslTunnelConfig.write("redirhost:%s:%s:%s:%s\n" %
(loc.host, loc.port, self.sslPort, redirhost))
sslTunnelConfig.close()
# Pre-create the certification database for the profile
env = self.environment(xrePath=xrePath)
bin_suffix = mozinfo.info.get('bin_suffix', '')
certutil = os.path.join(utilityPath, "certutil" + bin_suffix)
pk12util = os.path.join(utilityPath, "pk12util" + bin_suffix)
status = call([certutil, "-N", "-d", profileDir, "-f", pwfilePath], env=env)
printstatus(status, "certutil")
if status:
return status
# Walk the cert directory and add custom CAs and client certs
files = os.listdir(certPath)
for item in files:
root, ext = os.path.splitext(item)
if ext == ".ca":
trustBits = "CT,,"
if root.endswith("-object"):
trustBits = "CT,,CT"
status = call([certutil, "-A", "-i", os.path.join(certPath, item),
"-d", profileDir, "-f", pwfilePath, "-n", root, "-t", trustBits],
env=env)
printstatus(status, "certutil")
elif ext == ".client":
status = call([pk12util, "-i", os.path.join(certPath, item), "-w",
pwfilePath, "-d", profileDir],
env=env)
printstatus(status, "pk2util")
os.unlink(pwfilePath)
return 0
def main():

Просмотреть файл

@ -40,7 +40,7 @@ class B2GMochitest(MochitestUtilsMixin):
super(B2GMochitest, self).__init__()
self.marionette = marionette
self.out_of_process = out_of_process
self.locations = locations
self.locations_file = locations
self.preferences = []
self.webapps = None
self.test_script = os.path.join(here, 'b2g_start_script.js')
@ -92,7 +92,7 @@ class B2GMochitest(MochitestUtilsMixin):
kwargs = {
'addons': self.getExtensionsToInstall(options),
'apps': self.webapps,
'locations': self.locations,
'locations': self.locations_file,
'preferences': prefs,
'proxy': {"remote": options.webServer}
}
@ -114,8 +114,7 @@ class B2GMochitest(MochitestUtilsMixin):
self.leak_report_file = os.path.join(options.profilePath, "runtests_leaks.log")
manifest = self.build_profile(options)
self.startWebServer(options)
self.startWebSocketServer(options, None)
self.startServers(options, None)
self.buildURLOptions(options, {'MOZ_HIDE_RESULTS_TABLE': '1'})
self.test_script_args.append(not options.emulator)
self.test_script_args.append(options.wifi)
@ -155,8 +154,7 @@ class B2GMochitest(MochitestUtilsMixin):
self.runner.check_for_crashes()
status = 1
self.stopWebServer(options)
self.stopWebSocketServer(options)
self.stopServers()
log.info("runtestsb2g.py | Running tests: end.")
@ -199,26 +197,20 @@ class B2GDeviceMochitest(B2GMochitest):
self.runner.cleanup()
self.runner = None
def startWebServer(self, options):
""" Create the webserver on the host and start it up """
d = vars(options).copy()
d['xrePath'] = self.local_binary_dir
d['utilityPath'] = self.local_binary_dir
d['profilePath'] = tempfile.mkdtemp()
if d.get('httpdPath') is None:
d['httpdPath'] = os.path.abspath(os.path.join(self.local_binary_dir, 'components'))
self.server = MochitestServer(d)
self.server.start()
def startServers(self, options, debuggerInfo):
""" Create the servers on the host and start them up """
savedXre = options.xrePath
savedUtility = options.utilityPath
savedProfie = options.profilePath
options.xrePath = self.local_binary_dir
options.utilityPath = self.local_binary_dir
options.profilePath = tempfile.mkdtemp()
if (options.pidFile != ""):
f = open(options.pidFile + ".xpcshell.pid", 'w')
f.write("%s" % self.server._process.pid)
f.close()
self.server.ensureReady(90)
MochitestUtilsMixin.startServers(self, options, debuggerInfo)
def stopWebServer(self, options):
if hasattr(self, 'server'):
self.server.stop()
options.xrePath = savedXre
options.utilityPath = savedUtility
options.profilePath = savedProfie
def buildURLOptions(self, options, env):
self.local_log = options.logFile
@ -238,6 +230,7 @@ class B2GDesktopMochitest(B2GMochitest, Mochitest):
def __init__(self, marionette, profile_data_dir):
B2GMochitest.__init__(self, marionette, out_of_process=False, profile_data_dir=profile_data_dir)
Mochitest.__init__(self)
self.certdbNew = True
def runMarionetteScript(self, marionette, test_script, test_script_args):
assert(marionette.wait_for_port())
@ -340,8 +333,7 @@ def run_remote_mochitests(parser, options):
except:
print "Automation Error: Exception caught while running tests"
traceback.print_exc()
mochitest.stopWebServer(options)
mochitest.stopWebSocketServer(options)
mochitest.stopServers()
try:
mochitest.cleanup(None, options)
except:

Просмотреть файл

@ -82,11 +82,6 @@ class RemoteOptions(MochitestOptions):
help = "ssl port of the remote web server")
defaults["sslPort"] = automation.DEFAULT_SSL_PORT
self.add_option("--pidfile", action = "store",
type = "string", dest = "pidFile",
help = "name of the pidfile to generate")
defaults["pidFile"] = ""
self.add_option("--robocop-ini", action = "store",
type = "string", dest = "robocopIni",
help = "name of the .ini file containing the list of tests to run")
@ -223,7 +218,7 @@ class RemoteOptions(MochitestOptions):
options.sslPort = tempSSL
options.httpPort = tempPort
return options
return options
class MochiRemote(Mochitest):
@ -236,13 +231,13 @@ class MochiRemote(Mochitest):
self._automation = automation
Mochitest.__init__(self)
self._dm = devmgr
self.runSSLTunnel = False
self.environment = self._automation.environment
self.remoteProfile = options.remoteTestRoot + "/profile"
self._automation.setRemoteProfile(self.remoteProfile)
self.remoteLog = options.remoteLogFile
self.localLog = options.logFile
self._automation.deleteANRs()
self.certdbNew = True
def cleanup(self, manifest, options):
if self._dm.fileExists(self.remoteLog):
@ -252,13 +247,7 @@ class MochiRemote(Mochitest):
log.warn("Unable to retrieve log file (%s) from remote device",
self.remoteLog)
self._dm.removeDir(self.remoteProfile)
if (options.pidFile != ""):
try:
os.remove(options.pidFile)
os.remove(options.pidFile + ".xpcshell.pid")
except:
log.warn("cleaning up pidfile '%s' was unsuccessful from the test harness", options.pidFile)
Mochitest.cleanup(self, manifest, options)
def findPath(self, paths, filename = None):
for path in paths:
@ -269,11 +258,7 @@ class MochiRemote(Mochitest):
return path
return None
def startWebServer(self, options):
""" Create the webserver on the host and start it up """
remoteXrePath = options.xrePath
remoteProfilePath = options.profilePath
remoteUtilityPath = options.utilityPath
def makeLocalAutomation(self):
localAutomation = Automation()
localAutomation.IS_WIN32 = False
localAutomation.IS_LINUX = False
@ -281,15 +266,33 @@ class MochiRemote(Mochitest):
localAutomation.UNIXISH = False
hostos = sys.platform
if (hostos == 'mac' or hostos == 'darwin'):
localAutomation.IS_MAC = True
localAutomation.IS_MAC = True
elif (hostos == 'linux' or hostos == 'linux2'):
localAutomation.IS_LINUX = True
localAutomation.UNIXISH = True
localAutomation.IS_LINUX = True
localAutomation.UNIXISH = True
elif (hostos == 'win32' or hostos == 'win64'):
localAutomation.BIN_SUFFIX = ".exe"
localAutomation.IS_WIN32 = True
localAutomation.BIN_SUFFIX = ".exe"
localAutomation.IS_WIN32 = True
return localAutomation
paths = [options.xrePath, localAutomation.DIST_BIN, self._automation._product, os.path.join('..', self._automation._product)]
# This seems kludgy, but this class uses paths from the remote host in the
# options, except when calling up to the base class, which doesn't
# understand the distinction. This switches out the remote values for local
# ones that the base class understands. This is necessary for the web
# server, SSL tunnel and profile building functions.
def switchToLocalPaths(self, options):
""" Set local paths in the options, return a function that will restore remote values """
remoteXrePath = options.xrePath
remoteProfilePath = options.profilePath
remoteUtilityPath = options.utilityPath
localAutomation = self.makeLocalAutomation()
paths = [
options.xrePath,
localAutomation.DIST_BIN,
self._automation._product,
os.path.join('..', self._automation._product)
]
options.xrePath = self.findPath(paths)
if options.xrePath == None:
log.error("unable to find xulrunner path for %s, please specify with --xre-path", os.name)
@ -298,20 +301,16 @@ class MochiRemote(Mochitest):
xpcshell = "xpcshell"
if (os.name == "nt"):
xpcshell += ".exe"
if options.utilityPath:
paths = [options.utilityPath, options.xrePath]
else:
paths = [options.xrePath]
options.utilityPath = self.findPath(paths, xpcshell)
if options.utilityPath == None:
log.error("unable to find utility path for %s, please specify with --utility-path", os.name)
sys.exit(1)
# httpd-path is specified by standard makefile targets and may be specified
# on the command line to select a particular version of httpd.js. If not
# specified, try to select the one from hostutils.zip, as required in bug 882932.
if not options.httpdPath:
options.httpdPath = os.path.join(options.utilityPath, "components")
xpcshell_path = os.path.join(options.utilityPath, xpcshell)
if localAutomation.elf_arm(xpcshell_path):
@ -320,27 +319,26 @@ class MochiRemote(Mochitest):
'to a desktop version.' % xpcshell_path)
sys.exit(1)
options.profilePath = tempfile.mkdtemp()
self.server = MochitestServer(options)
self.server.start()
if (options.pidFile != ""):
f = open(options.pidFile + ".xpcshell.pid", 'w')
f.write("%s" % self.server._process.pid)
f.close()
self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
options.xrePath = remoteXrePath
options.utilityPath = remoteUtilityPath
options.profilePath = remoteProfilePath
def stopWebServer(self, options):
if hasattr(self, 'server'):
self.server.stop()
def buildProfile(self, options):
if self.localProfile:
options.profilePath = self.localProfile
else:
options.profilePath = tempfile.mkdtemp()
def fixup():
options.xrePath = remoteXrePath
options.utilityPath = remoteUtilityPath
options.profilePath = remoteProfilePath
return fixup
def startServers(self, options, debuggerInfo):
""" Create the servers on the host and start them up """
restoreRemotePaths = self.switchToLocalPaths(options)
Mochitest.startServers(self, options, debuggerInfo)
restoreRemotePaths()
def buildProfile(self, options):
restoreRemotePaths = self.switchToLocalPaths(options)
manifest = Mochitest.buildProfile(self, options)
self.localProfile = options.profilePath
self._dm.removeDir(self.remoteProfile)
@ -359,9 +357,10 @@ class MochiRemote(Mochitest):
log.error("Automation Error: Unable to copy profile to device.")
raise
restoreRemotePaths()
options.profilePath = self.remoteProfile
return manifest
def buildURLOptions(self, options, env):
self.localLog = options.logFile
options.logFile = self.remoteLog
@ -403,7 +402,7 @@ class MochiRemote(Mochitest):
return manifest
def getLogFilePath(self, logFile):
def getLogFilePath(self, logFile):
return logFile
# In the future we could use LogParser: http://hg.mozilla.org/automation/logparser/
@ -444,7 +443,7 @@ class MochiRemote(Mochitest):
failed = 0
todo = 0
incr = 1
logFile = []
logFile = []
logFile.append("0 INFO SimpleTest START")
for line in self.logLines:
if line.startswith("INFO TEST-PASS"):
@ -548,6 +547,10 @@ class MochiRemote(Mochitest):
if 'profileDir' not in kwargs and 'profile' in kwargs:
kwargs['profileDir'] = kwargs.pop('profile').profile
# We're handling ssltunnel, so we should lie to automation.py to avoid
# it trying to set up ssltunnel as well
kwargs['runSSLTunnel'] = False
return self._automation.runApp(*args, **kwargs)
def main():
@ -580,7 +583,7 @@ def main():
options = parser.verifyOptions(options, mochitest)
if (options == None):
sys.exit(1)
logParent = os.path.dirname(options.remoteLogFile)
dm.mkDir(logParent);
auto.setRemoteLog(options.remoteLogFile)
@ -668,7 +671,7 @@ def main():
# If the test is for checking the import from bookmarks then make sure there is data to import
if test['name'] == "testImportFromAndroid":
# Get the OS so we can run the insert in the apropriate database and following the correct table schema
osInfo = dm.getInfo("os")
devOS = " ".join(osInfo['os'])
@ -706,8 +709,7 @@ def main():
except:
log.error("Automation Error: Exception caught while running tests")
traceback.print_exc()
mochitest.stopWebServer(options)
mochitest.stopWebSocketServer(options)
mochitest.stopServers()
try:
mochitest.cleanup(None, options)
except devicemanager.DMError:
@ -742,8 +744,7 @@ def main():
except:
log.error("Automation Error: Exception caught while running tests")
traceback.print_exc()
mochitest.stopWebServer(options)
mochitest.stopWebSocketServer(options)
mochitest.stopServers()
try:
mochitest.cleanup(None, options)
except devicemanager.DMError: