зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1440714 - Convert Android browser test harnesses to adb.py; r=bc
This affects Android robocop, mochitest (all flavors) and reftests (all flavors).
This commit is contained in:
Родитель
3341d77b2f
Коммит
6083932cff
|
@ -13,7 +13,6 @@ import shutil
|
|||
import sys
|
||||
|
||||
from automation import Automation
|
||||
from mozdevice import DMError, DeviceManager
|
||||
from mozlog import get_default_logger
|
||||
from mozscreenshot import dump_screen
|
||||
import mozcrash
|
||||
|
@ -24,31 +23,18 @@ fennecLogcatFilters = [ "The character encoding of the HTML document was not dec
|
|||
"Unexpected value from nativeGetEnabledTags: 0" ]
|
||||
|
||||
class RemoteAutomation(Automation):
|
||||
_devicemanager = None
|
||||
|
||||
def __init__(self, deviceManager, appName = '', remoteLog = None,
|
||||
def __init__(self, device, appName = '', remoteProfile = None, remoteLog = None,
|
||||
processArgs=None):
|
||||
self._dm = deviceManager
|
||||
self._device = device
|
||||
self._appName = appName
|
||||
self._remoteProfile = None
|
||||
self._remoteProfile = remoteProfile
|
||||
self._remoteLog = remoteLog
|
||||
self._processArgs = processArgs or {};
|
||||
|
||||
self.lastTestSeen = "remoteautomation.py"
|
||||
Automation.__init__(self)
|
||||
|
||||
def setDeviceManager(self, deviceManager):
|
||||
self._dm = deviceManager
|
||||
|
||||
def setAppName(self, appName):
|
||||
self._appName = appName
|
||||
|
||||
def setRemoteProfile(self, remoteProfile):
|
||||
self._remoteProfile = remoteProfile
|
||||
|
||||
def setRemoteLog(self, logfile):
|
||||
self._remoteLog = logfile
|
||||
|
||||
# Set up what we need for the remote environment
|
||||
def environment(self, env=None, xrePath=None, crashreporter=True, debugger=False, lsanPath=None, ubsanPath=None):
|
||||
# Because we are running remote, we don't want to mimic the local env
|
||||
|
@ -56,12 +42,6 @@ class RemoteAutomation(Automation):
|
|||
if env is None:
|
||||
env = {}
|
||||
|
||||
# Except for the mochitest results table hiding option, which isn't
|
||||
# passed to runtestsremote.py as an actual option, but through the
|
||||
# MOZ_HIDE_RESULTS_TABLE environment variable.
|
||||
if 'MOZ_HIDE_RESULTS_TABLE' in os.environ:
|
||||
env['MOZ_HIDE_RESULTS_TABLE'] = os.environ['MOZ_HIDE_RESULTS_TABLE']
|
||||
|
||||
if crashreporter and not debugger:
|
||||
env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
|
||||
env['MOZ_CRASHREPORTER'] = '1'
|
||||
|
@ -101,7 +81,7 @@ class RemoteAutomation(Automation):
|
|||
status = proc.wait(timeout = maxTime, noOutputTimeout = timeout)
|
||||
self.lastTestSeen = proc.getLastTestSeen
|
||||
|
||||
topActivity = self._dm.getTopActivity()
|
||||
topActivity = self._device.get_top_activity(timeout=60)
|
||||
if topActivity == proc.procName:
|
||||
print "Browser unexpectedly found running. Killing..."
|
||||
proc.kill(True)
|
||||
|
@ -123,19 +103,16 @@ class RemoteAutomation(Automation):
|
|||
# we make it empty and writable so we can test the ANR reporter later
|
||||
traces = "/data/anr/traces.txt"
|
||||
try:
|
||||
self._dm.shellCheckOutput(['echo', '', '>', traces], root=True,
|
||||
timeout=DeviceManager.short_timeout)
|
||||
self._dm.shellCheckOutput(['chmod', '666', traces], root=True,
|
||||
timeout=DeviceManager.short_timeout)
|
||||
except DMError:
|
||||
print "Error deleting %s" % traces
|
||||
pass
|
||||
self._device.shell_output('echo > %s' % traces, root=True)
|
||||
self._device.shell_output('chmod 666 %s' % traces, root=True)
|
||||
except Exception as e:
|
||||
print "Error deleting %s: %s" % (traces, str(e))
|
||||
|
||||
def checkForANRs(self):
|
||||
traces = "/data/anr/traces.txt"
|
||||
if self._dm.fileExists(traces):
|
||||
if self._device.is_file(traces):
|
||||
try:
|
||||
t = self._dm.pullFile(traces)
|
||||
t = self._device.get_file(traces)
|
||||
if t:
|
||||
stripped = t.strip()
|
||||
if len(stripped) > 0:
|
||||
|
@ -143,22 +120,14 @@ class RemoteAutomation(Automation):
|
|||
print t
|
||||
# Once reported, delete traces
|
||||
self.deleteANRs()
|
||||
except DMError:
|
||||
print "Error pulling %s" % traces
|
||||
except IOError:
|
||||
print "Error pulling %s" % traces
|
||||
except Exception as e:
|
||||
print "Error pulling %s: %s" % (traces, str(e))
|
||||
else:
|
||||
print "%s not found" % traces
|
||||
|
||||
def deleteTombstones(self):
|
||||
# delete any tombstone files from device
|
||||
tombstones = "/data/tombstones/*"
|
||||
try:
|
||||
self._dm.shellCheckOutput(['rm', '-r', tombstones], root=True,
|
||||
timeout=DeviceManager.short_timeout)
|
||||
except DMError:
|
||||
# This may just indicate that the tombstone directory is missing
|
||||
pass
|
||||
self._device.rm("/data/tombstones", force=True, recursive=True, root=True)
|
||||
|
||||
def checkForTombstones(self):
|
||||
# pull any tombstones from device and move to MOZ_UPLOAD_DIR
|
||||
|
@ -167,17 +136,10 @@ class RemoteAutomation(Automation):
|
|||
if uploadDir:
|
||||
if not os.path.exists(uploadDir):
|
||||
os.mkdir(uploadDir)
|
||||
if self._dm.dirExists(remoteDir):
|
||||
if self._device.is_dir(remoteDir):
|
||||
# copy tombstone files from device to local upload directory
|
||||
try:
|
||||
self._dm.shellCheckOutput(['chmod', '777', remoteDir], root=True,
|
||||
timeout=DeviceManager.short_timeout)
|
||||
self._dm.shellCheckOutput(['chmod', '666', os.path.join(remoteDir, '*')],
|
||||
root=True, timeout=DeviceManager.short_timeout)
|
||||
self._dm.getDirectory(remoteDir, uploadDir, False)
|
||||
except DMError:
|
||||
# This may just indicate that no tombstone files are present
|
||||
pass
|
||||
self._device.chmod(remoteDir, recursive=True, root=True)
|
||||
self._device.pull(remoteDir, uploadDir)
|
||||
self.deleteTombstones()
|
||||
for f in glob.glob(os.path.join(uploadDir, "tombstone_??")):
|
||||
# add a unique integer to the file name, in case there are
|
||||
|
@ -197,7 +159,7 @@ class RemoteAutomation(Automation):
|
|||
self.checkForANRs()
|
||||
self.checkForTombstones()
|
||||
|
||||
logcat = self._dm.getLogcat(filterOutRegexps=fennecLogcatFilters)
|
||||
logcat = self._device.get_logcat(filter_out_regexps=fennecLogcatFilters)
|
||||
|
||||
javaException = mozcrash.check_for_java_exception(logcat, test_name=self.lastTestSeen)
|
||||
if javaException:
|
||||
|
@ -211,14 +173,14 @@ class RemoteAutomation(Automation):
|
|||
try:
|
||||
dumpDir = tempfile.mkdtemp()
|
||||
remoteCrashDir = posixpath.join(self._remoteProfile, 'minidumps')
|
||||
if not self._dm.dirExists(remoteCrashDir):
|
||||
if not self._device.is_dir(remoteCrashDir):
|
||||
# If crash reporting is enabled (MOZ_CRASHREPORTER=1), the
|
||||
# minidumps directory is automatically created when Fennec
|
||||
# (first) starts, so its lack of presence is a hint that
|
||||
# something went wrong.
|
||||
print "Automation Error: No crash directory (%s) found on remote device" % remoteCrashDir
|
||||
return True
|
||||
self._dm.getDirectory(remoteCrashDir, dumpDir)
|
||||
self._device.pull(remoteCrashDir, dumpDir)
|
||||
|
||||
logger = get_default_logger()
|
||||
crashed = mozcrash.log_crashes(logger, dumpDir, symbolsPath, test=self.lastTestSeen)
|
||||
|
@ -226,8 +188,8 @@ class RemoteAutomation(Automation):
|
|||
finally:
|
||||
try:
|
||||
shutil.rmtree(dumpDir)
|
||||
except:
|
||||
print "WARNING: unable to remove directory: %s" % dumpDir
|
||||
except Exception as e:
|
||||
print "WARNING: unable to remove directory %s: %s" % (dumpDir, str(e))
|
||||
return crashed
|
||||
|
||||
def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
|
||||
|
@ -235,7 +197,7 @@ class RemoteAutomation(Automation):
|
|||
if self._remoteProfile:
|
||||
profileDir = self._remoteProfile
|
||||
|
||||
# Hack for robocop, if app & testURL == None and extraArgs contains the rest of the stuff, lets
|
||||
# Hack for robocop, if app is "am" and extraArgs contains the rest of the stuff, lets
|
||||
# assume extraArgs is all we need
|
||||
if app == "am" and extraArgs[0] in ('instrument', 'start'):
|
||||
return app, extraArgs
|
||||
|
@ -248,18 +210,18 @@ class RemoteAutomation(Automation):
|
|||
return app, args
|
||||
|
||||
def Process(self, cmd, stdout = None, stderr = None, env = None, cwd = None):
|
||||
return self.RProcess(self._dm, cmd, self._remoteLog, env, cwd, self._appName,
|
||||
return self.RProcess(self._device, cmd, self._remoteLog, env, cwd, self._appName,
|
||||
**self._processArgs)
|
||||
|
||||
class RProcess(object):
|
||||
dm = None
|
||||
def __init__(self, dm, cmd, stdout=None, env=None, cwd=None, app=None,
|
||||
def __init__(self, device, cmd, stdout=None, env=None, cwd=None, app=None,
|
||||
messageLogger=None, counts=None):
|
||||
self.dm = dm
|
||||
self.stdoutlen = 0
|
||||
self.device = device
|
||||
self.lastTestSeen = "remoteautomation.py"
|
||||
self.proc = dm.launchProcess(cmd, stdout, cwd, env, True)
|
||||
self.messageLogger = messageLogger
|
||||
self.proc = stdout
|
||||
self.procName = cmd[0].split(posixpath.sep)[-1]
|
||||
self.stdoutlen = 0
|
||||
self.utilityPath = None
|
||||
|
||||
self.counts = counts
|
||||
|
@ -268,11 +230,25 @@ class RemoteAutomation(Automation):
|
|||
self.counts['fail'] = 0
|
||||
self.counts['todo'] = 0
|
||||
|
||||
if self.proc is None:
|
||||
self.proc = stdout
|
||||
self.procName = cmd[0].split(posixpath.sep)[-1]
|
||||
if cmd[0] == 'am' and cmd[1] in ('instrument', 'start'):
|
||||
if cmd[0] == 'am':
|
||||
cmd = ' '.join(cmd)
|
||||
self.procName = app
|
||||
if not self.device.shell_bool(cmd):
|
||||
print "remote_automation.py failed to launch %s" % cmd
|
||||
else:
|
||||
args = cmd
|
||||
if args[0] == app:
|
||||
args = args[1:]
|
||||
url = args[-1:][0]
|
||||
if url.startswith('/'):
|
||||
# this is probably a reftest profile directory, not a url
|
||||
url = None
|
||||
else:
|
||||
args = args[:-1]
|
||||
if 'geckoview' in app:
|
||||
self.device.launch_geckoview_example(app, moz_env=env, extra_args=args, url=url)
|
||||
else:
|
||||
self.device.launch_fennec(app, moz_env=env, extra_args=args, url=url)
|
||||
|
||||
# Setting timeout at 1 hour since on a remote device this takes much longer.
|
||||
# Temporarily increased to 90 minutes because no more chunks can be created.
|
||||
|
@ -283,25 +259,25 @@ class RemoteAutomation(Automation):
|
|||
|
||||
@property
|
||||
def pid(self):
|
||||
pid = self.dm.processExist(self.procName)
|
||||
# HACK: we should probably be more sophisticated about monitoring
|
||||
# running processes for the remote case, but for now we'll assume
|
||||
# that this method can be called when nothing exists and it is not
|
||||
# an error
|
||||
if pid is None:
|
||||
procs = self.device.get_process_list()
|
||||
# limit the comparison to the first 75 characters due to a
|
||||
# limitation in processname length in android.
|
||||
pids = [proc[0] for proc in procs if proc[1] == self.procName[:75]]
|
||||
|
||||
if pids is None or len(pids) < 1:
|
||||
return 0
|
||||
return pid
|
||||
return pids[0]
|
||||
|
||||
def read_stdout(self):
|
||||
"""
|
||||
Fetch the full remote log file using devicemanager, process them and
|
||||
return whether there were any new log entries since the last call.
|
||||
Fetch the full remote log file, log any new content and return True if new
|
||||
content processed.
|
||||
"""
|
||||
if not self.dm.fileExists(self.proc):
|
||||
if not self.device.is_file(self.proc):
|
||||
return False
|
||||
try:
|
||||
newLogContent = self.dm.pullFile(self.proc, self.stdoutlen)
|
||||
except DMError:
|
||||
newLogContent = self.device.get_file(self.proc, offset=self.stdoutlen)
|
||||
except Exception:
|
||||
return False
|
||||
if not newLogContent:
|
||||
return False
|
||||
|
@ -375,7 +351,7 @@ class RemoteAutomation(Automation):
|
|||
top = self.procName
|
||||
slowLog = False
|
||||
endTime = datetime.datetime.now() + datetime.timedelta(seconds = timeout)
|
||||
while (top == self.procName):
|
||||
while top == self.procName:
|
||||
# Get log updates on each interval, but if it is taking
|
||||
# too long, only do it every 60 seconds
|
||||
hasOutput = False
|
||||
|
@ -398,10 +374,10 @@ class RemoteAutomation(Automation):
|
|||
status = 2
|
||||
break
|
||||
if not hasOutput:
|
||||
top = self.dm.getTopActivity()
|
||||
if top == "":
|
||||
top = self.device.get_top_activity(timeout=60)
|
||||
if top is None:
|
||||
print "Failed to get top activity, retrying, once..."
|
||||
top = self.dm.getTopActivity()
|
||||
top = self.device.get_top_activity(timeout=60)
|
||||
# Flush anything added to stdout during the sleep
|
||||
self.read_stdout()
|
||||
return status
|
||||
|
@ -416,23 +392,30 @@ class RemoteAutomation(Automation):
|
|||
dump_screen(self.utilityPath, get_default_logger())
|
||||
if stagedShutdown:
|
||||
# Trigger an ANR report with "kill -3" (SIGQUIT)
|
||||
self.dm.killProcess(self.procName, 3)
|
||||
try:
|
||||
self.device.pkill(self.procName, sig=3, attempts=1)
|
||||
except:
|
||||
pass
|
||||
time.sleep(3)
|
||||
# Trigger a breakpad dump with "kill -6" (SIGABRT)
|
||||
self.dm.killProcess(self.procName, 6)
|
||||
try:
|
||||
self.device.pkill(self.procName, sig=6, attempts=1)
|
||||
except:
|
||||
pass
|
||||
# Wait for process to end
|
||||
retries = 0
|
||||
while retries < 3:
|
||||
pid = self.dm.processExist(self.procName)
|
||||
if pid and pid > 0:
|
||||
if self.device.process_exist(self.procName):
|
||||
print "%s still alive after SIGABRT: waiting..." % self.procName
|
||||
time.sleep(5)
|
||||
else:
|
||||
return
|
||||
retries += 1
|
||||
self.dm.killProcess(self.procName, 9)
|
||||
pid = self.dm.processExist(self.procName)
|
||||
if pid and pid > 0:
|
||||
self.dm.killProcess(self.procName)
|
||||
try:
|
||||
self.device.pkill(self.procName, sig=9, attempts=1)
|
||||
except:
|
||||
print "%s still alive after SIGKILL!" % self.procName
|
||||
if self.device.process_exist(self.procName):
|
||||
self.device.pkill(self.procName)
|
||||
else:
|
||||
self.dm.killProcess(self.procName)
|
||||
self.device.pkill(self.procName)
|
||||
|
|
|
@ -406,40 +406,19 @@ class RemoteArgumentsParser(ReftestArgumentsParser):
|
|||
utilityPath="",
|
||||
localLogName=None)
|
||||
|
||||
self.add_argument("--remote-app-path",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="remoteAppPath",
|
||||
help="Path to remote executable relative to device root using only "
|
||||
"forward slashes. Either this or app must be specified, "
|
||||
"but not both.")
|
||||
|
||||
self.add_argument("--adbpath",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="adb_path",
|
||||
default=None,
|
||||
default="adb",
|
||||
help="path to adb")
|
||||
|
||||
self.add_argument("--deviceIP",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="deviceIP",
|
||||
help="ip address of remote device to test")
|
||||
|
||||
self.add_argument("--deviceSerial",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="deviceSerial",
|
||||
help="adb serial number of remote device to test")
|
||||
|
||||
self.add_argument("--devicePort",
|
||||
action="store",
|
||||
type=str,
|
||||
default="20701",
|
||||
dest="devicePort",
|
||||
help="port of remote device to test")
|
||||
|
||||
self.add_argument("--remote-webserver",
|
||||
action="store",
|
||||
type=str,
|
||||
|
@ -458,21 +437,6 @@ class RemoteArgumentsParser(ReftestArgumentsParser):
|
|||
dest="sslPort",
|
||||
help="Port for https traffic to the web server")
|
||||
|
||||
self.add_argument("--remote-logfile",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="remoteLogFile",
|
||||
default="reftest.log",
|
||||
help="Name of log file on the device relative to device root. "
|
||||
"PLEASE USE ONLY A FILENAME.")
|
||||
|
||||
self.add_argument("--pidfile",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="pidFile",
|
||||
default="",
|
||||
help="name of the pidfile to generate")
|
||||
|
||||
self.add_argument("--remoteTestRoot",
|
||||
action="store",
|
||||
type=str,
|
||||
|
@ -493,16 +457,9 @@ class RemoteArgumentsParser(ReftestArgumentsParser):
|
|||
help="do not display verbose diagnostics about the remote device")
|
||||
|
||||
def validate_remote(self, options, automation):
|
||||
# Ensure our defaults are set properly for everything we can infer
|
||||
if not options.remoteTestRoot:
|
||||
options.remoteTestRoot = automation._dm.deviceRoot + \
|
||||
'/reftest'
|
||||
options.remoteProfile = options.remoteTestRoot + "/profile"
|
||||
|
||||
if options.remoteWebServer is None:
|
||||
options.remoteWebServer = self.get_ip()
|
||||
|
||||
# Verify that our remotewebserver is set properly
|
||||
if options.remoteWebServer == '127.0.0.1':
|
||||
self.error("ERROR: Either you specified the loopback for the remote webserver or ",
|
||||
"your local IP cannot be detected. "
|
||||
|
@ -514,19 +471,6 @@ class RemoteArgumentsParser(ReftestArgumentsParser):
|
|||
if not options.sslPort:
|
||||
options.sslPort = automation.DEFAULT_SSL_PORT
|
||||
|
||||
# One of remoteAppPath (relative path to application) or the app (executable) must be
|
||||
# set, but not both. If both are set, we destroy the user's selection for app
|
||||
# so instead of silently destroying a user specificied setting, we
|
||||
# error.
|
||||
if options.remoteAppPath and options.app:
|
||||
self.error(
|
||||
"ERROR: You cannot specify both the remoteAppPath and the app")
|
||||
elif options.remoteAppPath:
|
||||
options.app = options.remoteTestRoot + "/" + options.remoteAppPath
|
||||
elif options.app is None:
|
||||
# Neither remoteAppPath nor app are set -- error
|
||||
self.error("ERROR: You must specify either appPath or app")
|
||||
|
||||
if options.xrePath is None:
|
||||
self.error(
|
||||
"ERROR: You must specify the path to the controller xre directory")
|
||||
|
@ -534,24 +478,6 @@ class RemoteArgumentsParser(ReftestArgumentsParser):
|
|||
# Ensure xrepath is a full path
|
||||
options.xrePath = os.path.abspath(options.xrePath)
|
||||
|
||||
options.localLogName = options.remoteLogFile
|
||||
options.remoteLogFile = options.remoteTestRoot + \
|
||||
'/' + options.remoteLogFile
|
||||
|
||||
# Ensure that the options.logfile (which the base class uses) is set to
|
||||
# the remote setting when running remote. Also, if the user set the
|
||||
# log file name there, use that instead of reusing the remotelogfile as
|
||||
# above.
|
||||
if options.logFile:
|
||||
# If the user specified a local logfile name use that
|
||||
options.localLogName = options.logFile
|
||||
|
||||
options.logFile = options.remoteLogFile
|
||||
|
||||
if options.pidFile != "":
|
||||
with open(options.pidFile, 'w') as f:
|
||||
f.write(str(os.getpid()))
|
||||
|
||||
# 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
|
||||
|
@ -559,16 +485,6 @@ class RemoteArgumentsParser(ReftestArgumentsParser):
|
|||
if not options.httpdPath:
|
||||
options.httpdPath = os.path.join(options.utilityPath, "components")
|
||||
|
||||
if not options.ignoreWindowSize:
|
||||
parts = automation._dm.getInfo(
|
||||
'screen')['screen'][0].split()
|
||||
width = int(parts[0].split(':')[1])
|
||||
height = int(parts[1].split(':')[1])
|
||||
if (width < 1366 or height < 1050):
|
||||
self.error("ERROR: Invalid screen resolution %sx%s, "
|
||||
"please adjust to 1366x1050 or higher" % (
|
||||
width, height))
|
||||
|
||||
# Disable e10s by default on Android because we don't run Android
|
||||
# e10s jobs anywhere yet.
|
||||
options.e10s = False
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import logging
|
||||
import os
|
||||
import posixpath
|
||||
import psutil
|
||||
import signal
|
||||
import sys
|
||||
|
@ -13,7 +13,7 @@ import traceback
|
|||
import urllib2
|
||||
from contextlib import closing
|
||||
|
||||
import mozdevice
|
||||
from mozdevice import ADBAndroid
|
||||
import mozinfo
|
||||
from automation import Automation
|
||||
from remoteautomation import RemoteAutomation, fennecLogcatFilters
|
||||
|
@ -54,14 +54,13 @@ class ReftestServer:
|
|||
|
||||
def __init__(self, automation, options, scriptDir):
|
||||
self.automation = automation
|
||||
self._utilityPath = options.utilityPath
|
||||
self._xrePath = options.xrePath
|
||||
self._profileDir = options.serverProfilePath
|
||||
self.utilityPath = options.utilityPath
|
||||
self.xrePath = options.xrePath
|
||||
self.profileDir = options.serverProfilePath
|
||||
self.webServer = options.remoteWebServer
|
||||
self.httpPort = options.httpPort
|
||||
self.scriptDir = scriptDir
|
||||
self.pidFile = options.pidFile
|
||||
self._httpdPath = os.path.abspath(options.httpdPath)
|
||||
self.httpdPath = os.path.abspath(options.httpdPath)
|
||||
if options.remoteWebServer == "10.0.2.2":
|
||||
# probably running an Android emulator and 10.0.2.2 will
|
||||
# not be visible from host
|
||||
|
@ -74,20 +73,20 @@ class ReftestServer:
|
|||
def start(self):
|
||||
"Run the Refest server, returning the process ID of the server."
|
||||
|
||||
env = self.automation.environment(xrePath=self._xrePath)
|
||||
env = self.automation.environment(xrePath=self.xrePath)
|
||||
env["XPCOM_DEBUG_BREAK"] = "warn"
|
||||
if self.automation.IS_WIN32:
|
||||
env["PATH"] = env["PATH"] + ";" + self._xrePath
|
||||
env["PATH"] = env["PATH"] + ";" + self.xrePath
|
||||
|
||||
args = ["-g", self._xrePath,
|
||||
"-f", os.path.join(self._httpdPath, "httpd.js"),
|
||||
args = ["-g", self.xrePath,
|
||||
"-f", os.path.join(self.httpdPath, "httpd.js"),
|
||||
"-e", "const _PROFILE_PATH = '%(profile)s';const _SERVER_PORT = "
|
||||
"'%(port)s'; const _SERVER_ADDR ='%(server)s';" % {
|
||||
"profile": self._profileDir.replace('\\', '\\\\'), "port": self.httpPort,
|
||||
"profile": self.profileDir.replace('\\', '\\\\'), "port": self.httpPort,
|
||||
"server": self.webServer},
|
||||
"-f", os.path.join(self.scriptDir, "server.js")]
|
||||
|
||||
xpcshell = os.path.join(self._utilityPath,
|
||||
xpcshell = os.path.join(self.utilityPath,
|
||||
"xpcshell" + self.automation.BIN_SUFFIX)
|
||||
|
||||
if not os.access(xpcshell, os.F_OK):
|
||||
|
@ -104,15 +103,10 @@ class ReftestServer:
|
|||
return 2
|
||||
self.automation.log.info("INFO | remotereftests.py | Server pid: %d", pid)
|
||||
|
||||
if (self.pidFile != ""):
|
||||
f = open(self.pidFile + ".xpcshell.pid", 'w')
|
||||
f.write("%s" % pid)
|
||||
f.close()
|
||||
|
||||
def ensureReady(self, timeout):
|
||||
assert timeout >= 0
|
||||
|
||||
aliveFile = os.path.join(self._profileDir, "server_alive.txt")
|
||||
aliveFile = os.path.join(self.profileDir, "server_alive.txt")
|
||||
i = 0
|
||||
while i < timeout:
|
||||
if os.path.exists(aliveFile):
|
||||
|
@ -143,37 +137,74 @@ class ReftestServer:
|
|||
|
||||
class RemoteReftest(RefTest):
|
||||
use_marionette = False
|
||||
remoteApp = ''
|
||||
resolver_cls = RemoteReftestResolver
|
||||
|
||||
def __init__(self, automation, devicemanager, options, scriptDir):
|
||||
def __init__(self, options, scriptDir):
|
||||
RefTest.__init__(self, options.suite)
|
||||
self.run_by_manifest = False
|
||||
self.automation = automation
|
||||
self._devicemanager = devicemanager
|
||||
self.scriptDir = scriptDir
|
||||
self.remoteApp = options.app
|
||||
self.localLogName = options.localLogName
|
||||
|
||||
verbose = False
|
||||
if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
|
||||
verbose = True
|
||||
print "set verbose!"
|
||||
self.device = ADBAndroid(adb=options.adb_path,
|
||||
device=options.deviceSerial,
|
||||
test_root=options.remoteTestRoot,
|
||||
verbose=verbose)
|
||||
|
||||
if options.remoteTestRoot is None:
|
||||
options.remoteTestRoot = posixpath.join(self.device.test_root, "reftest")
|
||||
options.remoteProfile = posixpath.join(options.remoteTestRoot, "profile")
|
||||
options.remoteLogFile = posixpath.join(options.remoteTestRoot, "reftest.log")
|
||||
options.logFile = options.remoteLogFile
|
||||
self.remoteProfile = options.remoteProfile
|
||||
self.remoteTestRoot = options.remoteTestRoot
|
||||
self.remoteLogFile = options.remoteLogFile
|
||||
self.remoteCache = os.path.join(options.remoteTestRoot, "cache/")
|
||||
self.localLogName = options.localLogName
|
||||
self.pidFile = options.pidFile
|
||||
if self.automation.IS_DEBUG_BUILD:
|
||||
self.SERVER_STARTUP_TIMEOUT = 180
|
||||
else:
|
||||
self.SERVER_STARTUP_TIMEOUT = 90
|
||||
self.automation.deleteANRs()
|
||||
self.automation.deleteTombstones()
|
||||
self._devicemanager.removeDir(self.remoteCache)
|
||||
|
||||
if not options.ignoreWindowSize:
|
||||
parts = self.device.get_info(
|
||||
'screen')['screen'][0].split()
|
||||
width = int(parts[0].split(':')[1])
|
||||
height = int(parts[1].split(':')[1])
|
||||
if (width < 1366 or height < 1050):
|
||||
self.error("ERROR: Invalid screen resolution %sx%s, "
|
||||
"please adjust to 1366x1050 or higher" % (
|
||||
width, height))
|
||||
|
||||
self._populate_logger(options)
|
||||
self.outputHandler = OutputHandler(self.log, options.utilityPath, options.symbolsPath)
|
||||
# RemoteAutomation.py's 'messageLogger' is also used by mochitest. Mimic a mochitest
|
||||
# MessageLogger object to re-use this code path.
|
||||
self.outputHandler.write = self.outputHandler.__call__
|
||||
self.automation = RemoteAutomation(self.device, options.app, self.remoteProfile,
|
||||
options.remoteLogFile, processArgs=None)
|
||||
self.automation._processArgs['messageLogger'] = self.outputHandler
|
||||
|
||||
self.environment = self.automation.environment
|
||||
if self.automation.IS_DEBUG_BUILD:
|
||||
self.SERVER_STARTUP_TIMEOUT = 180
|
||||
else:
|
||||
self.SERVER_STARTUP_TIMEOUT = 90
|
||||
|
||||
self.remoteCache = os.path.join(options.remoteTestRoot, "cache/")
|
||||
|
||||
# Check that Firefox is installed
|
||||
expected = options.app.split('/')[-1]
|
||||
if not self.device.is_app_installed(expected):
|
||||
raise Exception("%s is not installed on this device" % expected)
|
||||
|
||||
self.automation.deleteANRs()
|
||||
self.automation.deleteTombstones()
|
||||
self.device.clear_logcat()
|
||||
|
||||
self.device.rm(self.remoteCache, force=True, recursive=True)
|
||||
|
||||
procName = options.app.split('/')[-1]
|
||||
self.device.pkill(procName)
|
||||
if self.device.process_exist(procName):
|
||||
self.log.error("unable to kill %s before starting tests!" % procName)
|
||||
|
||||
def findPath(self, paths, filename=None):
|
||||
for path in paths:
|
||||
p = path
|
||||
|
@ -283,9 +314,9 @@ class RemoteReftest(RefTest):
|
|||
profile.set_preferences(prefs)
|
||||
|
||||
try:
|
||||
self._devicemanager.pushDir(profileDir, options.remoteProfile)
|
||||
self._devicemanager.chmodDir(options.remoteProfile)
|
||||
except mozdevice.DMError:
|
||||
self.device.push(profileDir, options.remoteProfile)
|
||||
self.device.chmod(options.remoteProfile, recursive=True)
|
||||
except Exception:
|
||||
print "Automation Error: Failed to copy profiledir to device"
|
||||
raise
|
||||
|
||||
|
@ -294,20 +325,21 @@ class RemoteReftest(RefTest):
|
|||
def copyExtraFilesToProfile(self, options, profile):
|
||||
profileDir = profile.profile
|
||||
RefTest.copyExtraFilesToProfile(self, options, profile)
|
||||
try:
|
||||
self._devicemanager.pushDir(profileDir, options.remoteProfile)
|
||||
self._devicemanager.chmodDir(options.remoteProfile)
|
||||
except mozdevice.DMError:
|
||||
print "Automation Error: Failed to copy extra files to device"
|
||||
raise
|
||||
if len(os.listdir(profileDir)) > 0:
|
||||
try:
|
||||
self.device.push(profileDir, options.remoteProfile)
|
||||
self.device.chmod(options.remoteProfile, recursive=True)
|
||||
except Exception:
|
||||
print "Automation Error: Failed to copy extra files to device"
|
||||
raise
|
||||
|
||||
def printDeviceInfo(self, printLogcat=False):
|
||||
try:
|
||||
if printLogcat:
|
||||
logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
|
||||
logcat = self.device.get_logcat(filter_out_regexps=fennecLogcatFilters)
|
||||
print ''.join(logcat)
|
||||
print "Device info:"
|
||||
devinfo = self._devicemanager.getInfo()
|
||||
devinfo = self.device.get_info()
|
||||
for category in devinfo:
|
||||
if type(devinfo[category]) is list:
|
||||
print " %s:" % category
|
||||
|
@ -315,9 +347,9 @@ class RemoteReftest(RefTest):
|
|||
print " %s" % item
|
||||
else:
|
||||
print " %s: %s" % (category, devinfo[category])
|
||||
print "Test root: %s" % self._devicemanager.deviceRoot
|
||||
except mozdevice.DMError:
|
||||
print "WARNING: Error getting device information"
|
||||
print "Test root: %s" % self.device.test_root
|
||||
except Exception as e:
|
||||
print "WARNING: Error getting device information: %s" % str(e)
|
||||
|
||||
def environment(self, **kwargs):
|
||||
return self.automation.environment(**kwargs)
|
||||
|
@ -358,64 +390,15 @@ class RemoteReftest(RefTest):
|
|||
return status
|
||||
|
||||
def cleanup(self, profileDir):
|
||||
# Pull results back from device
|
||||
if self.remoteLogFile and \
|
||||
self._devicemanager.fileExists(self.remoteLogFile):
|
||||
self._devicemanager.getFile(self.remoteLogFile, self.localLogName)
|
||||
else:
|
||||
print "WARNING: Unable to retrieve log file (%s) from remote " \
|
||||
"device" % self.remoteLogFile
|
||||
self._devicemanager.removeDir(self.remoteProfile)
|
||||
self._devicemanager.removeDir(self.remoteCache)
|
||||
self._devicemanager.removeDir(self.remoteTestRoot)
|
||||
self.device.rm(self.remoteTestRoot, force=True, recursive=True)
|
||||
self.device.rm(self.remoteProfile, force=True, recursive=True)
|
||||
self.device.rm(self.remoteCache, force=True, recursive=True)
|
||||
RefTest.cleanup(self, profileDir)
|
||||
if (self.pidFile != ""):
|
||||
try:
|
||||
os.remove(self.pidFile)
|
||||
os.remove(self.pidFile + ".xpcshell.pid")
|
||||
except Exception:
|
||||
print ("Warning: cleaning up pidfile '%s' was unsuccessful "
|
||||
"from the test harness" % self.pidFile)
|
||||
|
||||
|
||||
def run_test_harness(parser, options):
|
||||
dm_args = {
|
||||
'deviceRoot': options.remoteTestRoot,
|
||||
'host': options.deviceIP,
|
||||
'port': options.devicePort,
|
||||
}
|
||||
|
||||
dm_args['adbPath'] = options.adb_path
|
||||
if not dm_args['host']:
|
||||
dm_args['deviceSerial'] = options.deviceSerial
|
||||
if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
|
||||
dm_args['logLevel'] = logging.DEBUG
|
||||
|
||||
try:
|
||||
dm = mozdevice.DroidADB(**dm_args)
|
||||
except mozdevice.DMError:
|
||||
traceback.print_exc()
|
||||
print ("Automation Error: exception while initializing devicemanager. "
|
||||
"Most likely the device is not in a testable state.")
|
||||
return 1
|
||||
|
||||
automation = RemoteAutomation(None)
|
||||
automation.setDeviceManager(dm)
|
||||
|
||||
# Set up the defaults and ensure options are set
|
||||
parser.validate_remote(options, automation)
|
||||
|
||||
# Check that Firefox is installed
|
||||
expected = options.app.split('/')[-1]
|
||||
installed = dm.shellCheckOutput(['pm', 'list', 'packages', expected])
|
||||
if expected not in installed:
|
||||
print "%s is not installed on this device" % expected
|
||||
return 1
|
||||
|
||||
automation.setAppName(options.app)
|
||||
automation.setRemoteProfile(options.remoteProfile)
|
||||
automation.setRemoteLog(options.remoteLogFile)
|
||||
reftest = RemoteReftest(automation, dm, options, SCRIPT_DIRECTORY)
|
||||
reftest = RemoteReftest(options, SCRIPT_DIRECTORY)
|
||||
parser.validate_remote(options, reftest.automation)
|
||||
parser.validate(options, reftest)
|
||||
|
||||
if mozinfo.info['debug']:
|
||||
|
@ -438,20 +421,11 @@ def run_test_harness(parser, options):
|
|||
if retVal:
|
||||
return retVal
|
||||
|
||||
procName = options.app.split('/')[-1]
|
||||
dm.killProcess(procName)
|
||||
if dm.processExist(procName):
|
||||
print "unable to kill %s before starting tests!" % procName
|
||||
|
||||
if options.printDeviceInfo:
|
||||
reftest.printDeviceInfo()
|
||||
|
||||
# an example manifest name to use on the cli
|
||||
# manifest = "http://" + options.remoteWebServer +
|
||||
# "/reftests/layout/reftests/reftest-sanity/reftest.list"
|
||||
retVal = 0
|
||||
try:
|
||||
dm.recordLogcat()
|
||||
if options.verify:
|
||||
retVal = reftest.verifyTests(options.tests, options)
|
||||
else:
|
||||
|
|
|
@ -8,12 +8,10 @@ from distutils.util import strtobool
|
|||
from distutils import spawn
|
||||
from itertools import chain
|
||||
from urlparse import urlparse
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from mozdevice import DroidADB
|
||||
from mozprofile import DEFAULT_PORTS
|
||||
import mozinfo
|
||||
import mozlog
|
||||
|
@ -850,18 +848,6 @@ class AndroidArguments(ArgumentContainer):
|
|||
"""Android specific arguments."""
|
||||
|
||||
args = [
|
||||
[["--remote-app-path"],
|
||||
{"dest": "remoteAppPath",
|
||||
"help": "Path to remote executable relative to device root using \
|
||||
only forward slashes. Either this or app must be specified \
|
||||
but not both.",
|
||||
"default": None,
|
||||
}],
|
||||
[["--deviceIP"],
|
||||
{"dest": "deviceIP",
|
||||
"help": "ip address of remote device to test",
|
||||
"default": None,
|
||||
}],
|
||||
[["--deviceSerial"],
|
||||
{"dest": "deviceSerial",
|
||||
"help": "ip address of remote device to test",
|
||||
|
@ -869,22 +855,10 @@ class AndroidArguments(ArgumentContainer):
|
|||
}],
|
||||
[["--adbpath"],
|
||||
{"dest": "adbPath",
|
||||
"default": None,
|
||||
"default": "adb",
|
||||
"help": "Path to adb binary.",
|
||||
"suppress": True,
|
||||
}],
|
||||
[["--devicePort"],
|
||||
{"dest": "devicePort",
|
||||
"type": int,
|
||||
"default": 20701,
|
||||
"help": "port of remote device to test",
|
||||
}],
|
||||
[["--remote-logfile"],
|
||||
{"dest": "remoteLogFile",
|
||||
"default": None,
|
||||
"help": "Name of log file on the device relative to the device \
|
||||
root. PLEASE ONLY USE A FILENAME.",
|
||||
}],
|
||||
[["--remote-webserver"],
|
||||
{"dest": "remoteWebServer",
|
||||
"default": None,
|
||||
|
@ -902,11 +876,6 @@ class AndroidArguments(ArgumentContainer):
|
|||
"help": "ssl port of the remote web server",
|
||||
"suppress": True,
|
||||
}],
|
||||
[["--robocop-ini"],
|
||||
{"dest": "robocopIni",
|
||||
"default": "",
|
||||
"help": "name of the .ini file containing the list of tests to run",
|
||||
}],
|
||||
[["--robocop-apk"],
|
||||
{"dest": "robocopApk",
|
||||
"default": "",
|
||||
|
@ -922,7 +891,6 @@ class AndroidArguments(ArgumentContainer):
|
|||
]
|
||||
|
||||
defaults = {
|
||||
'dm': None,
|
||||
# we don't want to exclude specialpowers on android just yet
|
||||
'extensionsToExclude': [],
|
||||
# mochijar doesn't get installed via marionette on android
|
||||
|
@ -937,21 +905,6 @@ class AndroidArguments(ArgumentContainer):
|
|||
if build_obj:
|
||||
options.log_mach = '-'
|
||||
|
||||
device_args = {'deviceRoot': options.remoteTestRoot}
|
||||
device_args['adbPath'] = options.adbPath
|
||||
if options.deviceIP:
|
||||
device_args['host'] = options.deviceIP
|
||||
device_args['port'] = options.devicePort
|
||||
elif options.deviceSerial:
|
||||
device_args['deviceSerial'] = options.deviceSerial
|
||||
|
||||
if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
|
||||
device_args['logLevel'] = logging.DEBUG
|
||||
options.dm = DroidADB(**device_args)
|
||||
|
||||
if not options.remoteTestRoot:
|
||||
options.remoteTestRoot = options.dm.deviceRoot
|
||||
|
||||
if options.remoteWebServer is None:
|
||||
if os.name != "nt":
|
||||
options.remoteWebServer = moznetwork.get_ip()
|
||||
|
@ -961,24 +914,10 @@ class AndroidArguments(ArgumentContainer):
|
|||
|
||||
options.webServer = options.remoteWebServer
|
||||
|
||||
if options.remoteLogFile is None:
|
||||
options.remoteLogFile = options.remoteTestRoot + \
|
||||
'/logs/mochitest.log'
|
||||
|
||||
if options.remoteLogFile.count('/') < 1:
|
||||
options.remoteLogFile = options.remoteTestRoot + \
|
||||
'/' + options.remoteLogFile
|
||||
|
||||
if options.remoteAppPath and options.app:
|
||||
parser.error(
|
||||
"You cannot specify both the remoteAppPath and the app setting")
|
||||
elif options.remoteAppPath:
|
||||
options.app = options.remoteTestRoot + "/" + options.remoteAppPath
|
||||
elif options.app is None:
|
||||
if options.app is None:
|
||||
if build_obj:
|
||||
options.app = build_obj.substs['ANDROID_PACKAGE_NAME']
|
||||
else:
|
||||
# Neither remoteAppPath nor app are set -- error
|
||||
parser.error("You must specify either appPath or app")
|
||||
|
||||
if build_obj and 'MOZ_HOST_BIN' in os.environ:
|
||||
|
@ -996,16 +935,8 @@ class AndroidArguments(ArgumentContainer):
|
|||
f.write("%s" % os.getpid())
|
||||
f.close()
|
||||
|
||||
# Robocop specific options
|
||||
if options.robocopIni != "":
|
||||
if not os.path.exists(options.robocopIni):
|
||||
parser.error(
|
||||
"Unable to find specified robocop .ini manifest '%s'" %
|
||||
options.robocopIni)
|
||||
options.robocopIni = os.path.abspath(options.robocopIni)
|
||||
|
||||
if not options.robocopApk and build_obj:
|
||||
options.robocopApk = build_obj.substs.get('GRADLE_ANDROID_APP_ANDROIDTEST_APK')
|
||||
if not options.robocopApk and build_obj:
|
||||
options.robocopApk = build_obj.substs.get('GRADLE_ANDROID_APP_ANDROIDTEST_APK')
|
||||
|
||||
if options.robocopApk != "":
|
||||
if not os.path.exists(options.robocopApk):
|
||||
|
|
|
@ -225,7 +225,7 @@ def run_test_harness(log, parser, options):
|
|||
runner.cleanup()
|
||||
except Exception:
|
||||
# ignore device error while cleaning up
|
||||
pass
|
||||
traceback.print_exc()
|
||||
return result
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import json
|
||||
import os
|
||||
import posixpath
|
||||
import sys
|
||||
import tempfile
|
||||
import traceback
|
||||
|
@ -21,7 +22,8 @@ from mochitest_options import MochitestArgumentParser
|
|||
|
||||
from manifestparser import TestManifest
|
||||
from manifestparser.filters import chunk_by_slice
|
||||
import mozdevice
|
||||
from mozdevice import ADBAndroid
|
||||
import mozfile
|
||||
import mozinfo
|
||||
|
||||
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
|
||||
|
@ -33,40 +35,50 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
based on the Robotium test framework. This harness leverages some functionality
|
||||
from mochitest, for convenience.
|
||||
"""
|
||||
auto = None
|
||||
dm = None
|
||||
# Some robocop tests run for >60 seconds without generating any output.
|
||||
NO_OUTPUT_TIMEOUT = 180
|
||||
|
||||
def __init__(self, automation, devmgr, options):
|
||||
def __init__(self, options, message_logger):
|
||||
"""
|
||||
Simple one-time initialization.
|
||||
"""
|
||||
MochitestDesktop.__init__(self, options.flavor, vars(options))
|
||||
|
||||
self.auto = automation
|
||||
self.dm = devmgr
|
||||
self.dm.default_timeout = 320
|
||||
verbose = False
|
||||
if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
|
||||
verbose = True
|
||||
self.device = ADBAndroid(adb=options.adbPath,
|
||||
device=options.deviceSerial,
|
||||
test_root=options.remoteTestRoot,
|
||||
verbose=verbose)
|
||||
|
||||
# Check that Firefox is installed
|
||||
expected = options.app.split('/')[-1]
|
||||
if not self.device.is_app_installed(expected):
|
||||
raise Exception("%s is not installed on this device" % expected)
|
||||
|
||||
options.logFile = "robocop.log"
|
||||
if options.remoteTestRoot is None:
|
||||
options.remoteTestRoot = self.device.test_root
|
||||
self.remoteProfile = posixpath.join(options.remoteTestRoot, "profile")
|
||||
self.remoteProfileCopy = posixpath.join(options.remoteTestRoot, "profile-copy")
|
||||
|
||||
self.remoteConfigFile = posixpath.join(options.remoteTestRoot, "robotium.config")
|
||||
self.remoteLogFile = posixpath.join(options.remoteTestRoot, "logs", "robocop.log")
|
||||
|
||||
self.options = options
|
||||
self.options.logFile = "robocop.log"
|
||||
|
||||
process_args = {'messageLogger': message_logger}
|
||||
self.auto = RemoteAutomation(self.device, options.remoteappname, self.remoteProfile,
|
||||
self.remoteLogFile, processArgs=process_args)
|
||||
self.environment = self.auto.environment
|
||||
self.deviceRoot = self.dm.getDeviceRoot()
|
||||
self.remoteProfile = options.remoteTestRoot + "/profile"
|
||||
self.remoteProfileCopy = options.remoteTestRoot + "/profile-copy"
|
||||
self.auto.setRemoteProfile(self.remoteProfile)
|
||||
self.remoteConfigFile = os.path.join(
|
||||
self.deviceRoot, "robotium.config")
|
||||
self.remoteLog = options.remoteLogFile
|
||||
self.auto.setRemoteLog(self.remoteLog)
|
||||
|
||||
self.remoteScreenshots = "/mnt/sdcard/Robotium-Screenshots"
|
||||
self.remoteMozLog = os.path.join(options.remoteTestRoot, "mozlog")
|
||||
self.auto.setServerInfo(
|
||||
self.options.webServer, self.options.httpPort, self.options.sslPort)
|
||||
self.remoteMozLog = posixpath.join(options.remoteTestRoot, "mozlog")
|
||||
|
||||
self.localLog = options.logFile
|
||||
self.localProfile = None
|
||||
self.auto.setAppName(self.options.remoteappname)
|
||||
self.certdbNew = True
|
||||
self.remoteCopyAvailable = True
|
||||
self.passed = 0
|
||||
self.failed = 0
|
||||
self.todo = 0
|
||||
|
@ -85,23 +97,23 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
self.auto.deleteANRs()
|
||||
self.auto.deleteTombstones()
|
||||
procName = self.options.app.split('/')[-1]
|
||||
self.dm.killProcess(procName)
|
||||
if self.dm.processExist(procName):
|
||||
self.device.pkill(procName)
|
||||
if self.device.process_exist(procName):
|
||||
self.log.warning("unable to kill %s before running tests!" % procName)
|
||||
self.dm.removeDir(self.remoteScreenshots)
|
||||
self.dm.removeDir(self.remoteMozLog)
|
||||
self.dm.mkDir(self.remoteMozLog)
|
||||
self.dm.mkDir(os.path.dirname(self.options.remoteLogFile))
|
||||
self.device.rm(self.remoteScreenshots, force=True, recursive=True)
|
||||
self.device.rm(self.remoteMozLog, force=True, recursive=True)
|
||||
self.device.mkdir(self.remoteMozLog)
|
||||
logParent = posixpath.dirname(self.remoteLogFile)
|
||||
self.device.rm(logParent, force=True, recursive=True)
|
||||
self.device.mkdir(logParent)
|
||||
# Add Android version (SDK level) to mozinfo so that manifest entries
|
||||
# can be conditional on android_version.
|
||||
androidVersion = self.dm.shellCheckOutput(
|
||||
['getprop', 'ro.build.version.sdk'])
|
||||
self.log.info(
|
||||
"Android sdk version '%s'; will use this to filter manifests" %
|
||||
str(androidVersion))
|
||||
mozinfo.info['android_version'] = androidVersion
|
||||
str(self.device.version))
|
||||
mozinfo.info['android_version'] = str(self.device.version)
|
||||
if self.options.robocopApk:
|
||||
self.dm._checkCmd(["install", "-r", self.options.robocopApk])
|
||||
self.device.install_app(self.options.robocopApk, replace=True)
|
||||
self.log.debug("Robocop APK %s installed" %
|
||||
self.options.robocopApk)
|
||||
# Display remote diagnostics; if running in mach, keep output terse.
|
||||
|
@ -122,23 +134,22 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
"""
|
||||
self.log.debug("Cleaning up...")
|
||||
self.stopServers()
|
||||
self.dm.killProcess(self.options.app.split('/')[-1])
|
||||
blobberUploadDir = os.environ.get('MOZ_UPLOAD_DIR', None)
|
||||
if blobberUploadDir:
|
||||
self.device.pkill(self.options.app.split('/')[-1])
|
||||
uploadDir = os.environ.get('MOZ_UPLOAD_DIR', None)
|
||||
if uploadDir:
|
||||
self.log.debug("Pulling any remote moz logs and screenshots to %s." %
|
||||
blobberUploadDir)
|
||||
self.dm.getDirectory(self.remoteMozLog, blobberUploadDir)
|
||||
self.dm.getDirectory(self.remoteScreenshots, blobberUploadDir)
|
||||
uploadDir)
|
||||
self.device.pull(self.remoteMozLog, uploadDir)
|
||||
self.device.pull(self.remoteScreenshots, uploadDir)
|
||||
MochitestDesktop.cleanup(self, self.options)
|
||||
if self.localProfile:
|
||||
os.system("rm -Rf %s" % self.localProfile)
|
||||
self.dm.removeDir(self.remoteProfile)
|
||||
self.dm.removeDir(self.remoteProfileCopy)
|
||||
self.dm.removeDir(self.remoteScreenshots)
|
||||
self.dm.removeDir(self.remoteMozLog)
|
||||
self.dm.removeFile(self.remoteConfigFile)
|
||||
if self.dm.fileExists(self.remoteLog):
|
||||
self.dm.removeFile(self.remoteLog)
|
||||
mozfile.remove(self.localProfile)
|
||||
self.device.rm(self.remoteProfile, force=True, recursive=True)
|
||||
self.device.rm(self.remoteProfileCopy, force=True, recursive=True)
|
||||
self.device.rm(self.remoteScreenshots, force=True, recursive=True)
|
||||
self.device.rm(self.remoteMozLog, force=True, recursive=True)
|
||||
self.device.rm(self.remoteConfigFile, force=True)
|
||||
self.device.rm(self.remoteLogFile, force=True)
|
||||
self.log.debug("Cleanup complete.")
|
||||
|
||||
def findPath(self, paths, filename=None):
|
||||
|
@ -236,8 +247,8 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
# some files are not needed for robocop; save time by not pushing
|
||||
os.remove(os.path.join(self.localProfile, 'userChrome.css'))
|
||||
try:
|
||||
self.dm.pushDir(self.localProfile, self.remoteProfileCopy)
|
||||
except mozdevice.DMError:
|
||||
self.device.push(self.localProfile, self.remoteProfileCopy)
|
||||
except Exception:
|
||||
self.log.error(
|
||||
"Automation Error: Unable to copy profile to device.")
|
||||
raise
|
||||
|
@ -249,20 +260,8 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
Remove any remote profile and re-create it.
|
||||
"""
|
||||
self.log.debug("Updating remote profile at %s" % self.remoteProfile)
|
||||
self.dm.removeDir(self.remoteProfile)
|
||||
if self.remoteCopyAvailable:
|
||||
try:
|
||||
self.dm.shellCheckOutput(
|
||||
['cp', '-r', self.remoteProfileCopy, self.remoteProfile],
|
||||
root=True, timeout=60)
|
||||
except mozdevice.DMError:
|
||||
# For instance, cp is not available on some older versions of
|
||||
# Android.
|
||||
self.log.info(
|
||||
"Unable to copy remote profile; falling back to push.")
|
||||
self.remoteCopyAvailable = False
|
||||
if not self.remoteCopyAvailable:
|
||||
self.dm.pushDir(self.localProfile, self.remoteProfile)
|
||||
self.device.rm(self.remoteProfile, force=True, recursive=True)
|
||||
self.device.cp(self.remoteProfileCopy, self.remoteProfile, recursive=True)
|
||||
|
||||
def parseLocalLog(self):
|
||||
"""
|
||||
|
@ -328,7 +327,7 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
"""
|
||||
try:
|
||||
if printLogcat:
|
||||
logcat = self.dm.getLogcat(
|
||||
logcat = self.device.get_logcat(
|
||||
filterOutRegexps=fennecLogcatFilters)
|
||||
self.log.info(
|
||||
'\n' +
|
||||
|
@ -336,7 +335,7 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
'utf-8',
|
||||
'replace'))
|
||||
self.log.info("Device info:")
|
||||
devinfo = self.dm.getInfo()
|
||||
devinfo = self.device.get_info()
|
||||
for category in devinfo:
|
||||
if type(devinfo[category]) is list:
|
||||
self.log.info(" %s:" % category)
|
||||
|
@ -344,9 +343,9 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
self.log.info(" %s" % item)
|
||||
else:
|
||||
self.log.info(" %s: %s" % (category, devinfo[category]))
|
||||
self.log.info("Test root: %s" % self.dm.deviceRoot)
|
||||
except mozdevice.DMError:
|
||||
self.log.warning("Error getting device information")
|
||||
self.log.info("Test root: %s" % self.device.test_root)
|
||||
except Exception as e:
|
||||
self.log.warning("Error getting device information: %s" % str(e))
|
||||
|
||||
def setupRobotiumConfig(self, browserEnv):
|
||||
"""
|
||||
|
@ -356,8 +355,8 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
prefix='robotium-',
|
||||
dir=os.getcwd(),
|
||||
delete=False)
|
||||
fHandle.write("profile=%s\n" % (self.remoteProfile))
|
||||
fHandle.write("logfile=%s\n" % (self.options.remoteLogFile))
|
||||
fHandle.write("profile=%s\n" % self.remoteProfile)
|
||||
fHandle.write("logfile=%s\n" % self.remoteLogFile)
|
||||
fHandle.write("host=http://mochi.test:8888/tests\n")
|
||||
fHandle.write(
|
||||
"rawhost=http://%s:%s/tests\n" %
|
||||
|
@ -377,8 +376,8 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
delim = ","
|
||||
fHandle.write("envvars=%s\n" % envstr)
|
||||
fHandle.close()
|
||||
self.dm.removeFile(self.remoteConfigFile)
|
||||
self.dm.pushFile(fHandle.name, self.remoteConfigFile)
|
||||
self.device.rm(self.remoteConfigFile, force=True)
|
||||
self.device.push(fHandle.name, self.remoteConfigFile)
|
||||
os.unlink(fHandle.name)
|
||||
|
||||
def buildBrowserEnv(self):
|
||||
|
@ -419,15 +418,15 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
self.setupRobotiumConfig(browserEnv)
|
||||
self.setupRemoteProfile()
|
||||
self.options.app = "am"
|
||||
timeout = None
|
||||
if self.options.autorun:
|
||||
# This launches a test (using "am instrument") and instructs
|
||||
# Fennec to /quit/ the browser (using Robocop:Quit) and to
|
||||
# /finish/ all opened activities.
|
||||
browserArgs = [
|
||||
"instrument",
|
||||
"-w",
|
||||
"-e", "quit_and_finish", "1",
|
||||
"-e", "deviceroot", self.deviceRoot,
|
||||
"-e", "deviceroot", self.device.test_root,
|
||||
"-e", "class",
|
||||
"org.mozilla.gecko.tests.%s" % test['name'].split('/')[-1].split('.java')[0],
|
||||
"org.mozilla.roboexample.test/org.mozilla.gecko.FennecInstrumentationTestRunner"]
|
||||
|
@ -438,7 +437,8 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
browserArgs = ["start", "-n",
|
||||
"org.mozilla.roboexample.test/org.mozilla."
|
||||
"gecko.LaunchFennecWithConfigurationActivity", "&&", "cat"]
|
||||
self.dm.default_timeout = sys.maxint # Forever.
|
||||
timeout = sys.maxint # Forever.
|
||||
|
||||
self.log.info("")
|
||||
self.log.info("Serving mochi.test Robocop root at http://%s:%s/tests/robocop/" %
|
||||
(self.options.remoteWebServer, self.options.httpPort))
|
||||
|
@ -446,8 +446,9 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
result = -1
|
||||
log_result = -1
|
||||
try:
|
||||
self.dm.recordLogcat()
|
||||
timeout = self.options.timeout
|
||||
self.device.clear_logcat()
|
||||
if not timeout:
|
||||
timeout = self.options.timeout
|
||||
if not timeout:
|
||||
timeout = self.NO_OUTPUT_TIMEOUT
|
||||
result, _ = self.auto.runApp(
|
||||
|
@ -456,15 +457,9 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
self.log.debug("runApp completes with status %d" % result)
|
||||
if result != 0:
|
||||
self.log.error("runApp() exited with code %s" % result)
|
||||
if self.dm.fileExists(self.remoteLog):
|
||||
self.dm.getFile(self.remoteLog, self.localLog)
|
||||
self.dm.removeFile(self.remoteLog)
|
||||
self.log.debug("Remote log %s retrieved to %s" %
|
||||
(self.remoteLog, self.localLog))
|
||||
else:
|
||||
self.log.warning(
|
||||
"Unable to retrieve log file (%s) from remote device" %
|
||||
self.remoteLog)
|
||||
if self.device.is_file(self.remoteLogFile):
|
||||
self.device.pull(self.remoteLogFile, self.localLog)
|
||||
self.device.rm(self.remoteLogFile)
|
||||
log_result = self.parseLocalLog()
|
||||
if result != 0 or log_result != 0:
|
||||
# Display remote diagnostics; if running in mach, keep output
|
||||
|
@ -486,7 +481,7 @@ class RobocopTestRunner(MochitestDesktop):
|
|||
mp = self.options.manifestFile
|
||||
else:
|
||||
mp = TestManifest(strict=False)
|
||||
mp.read(self.options.robocopIni)
|
||||
mp.read("robocop.ini")
|
||||
filters = []
|
||||
if self.options.totalChunks:
|
||||
filters.append(
|
||||
|
@ -537,18 +532,8 @@ def run_test_harness(parser, options):
|
|||
raise ValueError(
|
||||
"Invalid options specified, use --help for a list of valid options")
|
||||
message_logger = MessageLogger(logger=None)
|
||||
process_args = {'messageLogger': message_logger}
|
||||
auto = RemoteAutomation(None, "fennec", processArgs=process_args)
|
||||
auto.setDeviceManager(options.dm)
|
||||
runResult = -1
|
||||
robocop = RobocopTestRunner(auto, options.dm, options)
|
||||
|
||||
# Check that Firefox is installed
|
||||
expected = options.app.split('/')[-1]
|
||||
installed = options.dm.shellCheckOutput(['pm', 'list', 'packages', expected])
|
||||
if expected not in installed:
|
||||
robocop.log.error("%s is not installed on this device" % expected)
|
||||
return 1
|
||||
robocop = RobocopTestRunner(options, message_logger)
|
||||
|
||||
try:
|
||||
message_logger.logger = robocop.log
|
||||
|
@ -567,9 +552,9 @@ def run_test_harness(parser, options):
|
|||
finally:
|
||||
try:
|
||||
robocop.cleanup()
|
||||
except mozdevice.DMError:
|
||||
except Exception:
|
||||
# ignore device error while cleaning up
|
||||
pass
|
||||
traceback.print_exc()
|
||||
message_logger.finish()
|
||||
return runResult
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import os
|
||||
import posixpath
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
|
@ -16,67 +17,102 @@ from remoteautomation import RemoteAutomation, fennecLogcatFilters
|
|||
from runtests import MochitestDesktop, MessageLogger
|
||||
from mochitest_options import MochitestArgumentParser
|
||||
|
||||
import mozdevice
|
||||
from mozdevice import ADBAndroid
|
||||
import mozinfo
|
||||
|
||||
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
|
||||
|
||||
|
||||
class MochiRemote(MochitestDesktop):
|
||||
_automation = None
|
||||
_dm = None
|
||||
localProfile = None
|
||||
logMessages = []
|
||||
|
||||
def __init__(self, automation, devmgr, options):
|
||||
def __init__(self, options):
|
||||
MochitestDesktop.__init__(self, options.flavor, vars(options))
|
||||
|
||||
verbose = False
|
||||
if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
|
||||
verbose = True
|
||||
if hasattr(options, 'log'):
|
||||
delattr(options, 'log')
|
||||
|
||||
self._automation = automation
|
||||
self._dm = devmgr
|
||||
self.chromePushed = False
|
||||
self.environment = self._automation.environment
|
||||
self.remoteProfile = os.path.join(options.remoteTestRoot, "profile/")
|
||||
self.remoteModulesDir = os.path.join(options.remoteTestRoot, "modules/")
|
||||
self.remoteCache = os.path.join(options.remoteTestRoot, "cache/")
|
||||
self._automation.setRemoteProfile(self.remoteProfile)
|
||||
self.remoteLog = options.remoteLogFile
|
||||
self.localLog = options.logFile
|
||||
self._automation.deleteANRs()
|
||||
self._automation.deleteTombstones()
|
||||
self.certdbNew = True
|
||||
self.remoteMozLog = os.path.join(options.remoteTestRoot, "mozlog")
|
||||
self._dm.removeDir(self.remoteMozLog)
|
||||
self._dm.mkDir(self.remoteMozLog)
|
||||
self.remoteChromeTestDir = os.path.join(
|
||||
options.remoteTestRoot,
|
||||
"chrome")
|
||||
self._dm.removeDir(self.remoteChromeTestDir)
|
||||
self._dm.mkDir(self.remoteChromeTestDir)
|
||||
self._dm.removeDir(self.remoteProfile)
|
||||
self._dm.removeDir(self.remoteCache)
|
||||
self.chromePushed = False
|
||||
self.mozLogName = "moz.log"
|
||||
|
||||
self.device = ADBAndroid(adb=options.adbPath,
|
||||
device=options.deviceSerial,
|
||||
test_root=options.remoteTestRoot,
|
||||
verbose=verbose)
|
||||
|
||||
if options.remoteTestRoot is None:
|
||||
options.remoteTestRoot = self.device.test_root
|
||||
options.dumpOutputDirectory = options.remoteTestRoot
|
||||
self.remoteLogFile = posixpath.join(options.remoteTestRoot, "logs", "mochitest.log")
|
||||
logParent = posixpath.dirname(self.remoteLogFile)
|
||||
self.device.rm(logParent, force=True, recursive=True)
|
||||
self.device.mkdir(logParent)
|
||||
|
||||
self.remoteProfile = posixpath.join(options.remoteTestRoot, "profile/")
|
||||
self.device.rm(self.remoteProfile, force=True, recursive=True)
|
||||
|
||||
self.counts = dict()
|
||||
self.message_logger = MessageLogger(logger=None)
|
||||
self.message_logger.logger = self.log
|
||||
process_args = {'messageLogger': self.message_logger, 'counts': self.counts}
|
||||
self.automation = RemoteAutomation(self.device, options.remoteappname, self.remoteProfile,
|
||||
self.remoteLogFile, processArgs=process_args)
|
||||
self.environment = self.automation.environment
|
||||
|
||||
# Check that Firefox is installed
|
||||
expected = options.app.split('/')[-1]
|
||||
if not self.device.is_app_installed(expected):
|
||||
raise Exception("%s is not installed on this device" % expected)
|
||||
|
||||
self.automation.deleteANRs()
|
||||
self.automation.deleteTombstones()
|
||||
self.device.clear_logcat()
|
||||
|
||||
self.remoteModulesDir = posixpath.join(options.remoteTestRoot, "modules/")
|
||||
|
||||
self.remoteCache = posixpath.join(options.remoteTestRoot, "cache/")
|
||||
self.device.rm(self.remoteCache, force=True, recursive=True)
|
||||
|
||||
# move necko cache to a location that can be cleaned up
|
||||
options.extraPrefs += ["browser.cache.disk.parent_directory=%s" % self.remoteCache]
|
||||
|
||||
self.remoteMozLog = posixpath.join(options.remoteTestRoot, "mozlog")
|
||||
self.device.rm(self.remoteMozLog, force=True, recursive=True)
|
||||
self.device.mkdir(self.remoteMozLog)
|
||||
|
||||
self.remoteChromeTestDir = posixpath.join(
|
||||
options.remoteTestRoot,
|
||||
"chrome")
|
||||
self.device.rm(self.remoteChromeTestDir, force=True, recursive=True)
|
||||
self.device.mkdir(self.remoteChromeTestDir)
|
||||
|
||||
procName = options.app.split('/')[-1]
|
||||
self.device.pkill(procName)
|
||||
if self.device.process_exist(procName):
|
||||
self.log.warning("unable to kill %s before running tests!" % procName)
|
||||
|
||||
# Add Android version (SDK level) to mozinfo so that manifest entries
|
||||
# can be conditional on android_version.
|
||||
self.log.info(
|
||||
"Android sdk version '%s'; will use this to filter manifests" %
|
||||
str(self.device.version))
|
||||
mozinfo.info['android_version'] = str(self.device.version)
|
||||
|
||||
def cleanup(self, options, final=False):
|
||||
if final:
|
||||
self._dm.removeDir(self.remoteChromeTestDir)
|
||||
self.device.rm(self.remoteChromeTestDir, force=True, recursive=True)
|
||||
self.chromePushed = False
|
||||
blobberUploadDir = os.environ.get('MOZ_UPLOAD_DIR', None)
|
||||
if blobberUploadDir:
|
||||
self._dm.getDirectory(self.remoteMozLog, blobberUploadDir)
|
||||
else:
|
||||
if self._dm.fileExists(self.remoteLog):
|
||||
self._dm.getFile(self.remoteLog, self.localLog)
|
||||
self._dm.removeFile(self.remoteLog)
|
||||
else:
|
||||
self.log.warning(
|
||||
"Unable to retrieve log file (%s) from remote device" %
|
||||
self.remoteLog)
|
||||
self._dm.removeDir(self.remoteProfile)
|
||||
self._dm.removeDir(self.remoteCache)
|
||||
uploadDir = os.environ.get('MOZ_UPLOAD_DIR', None)
|
||||
if uploadDir:
|
||||
self.device.pull(self.remoteMozLog, uploadDir)
|
||||
self.device.rm(self.remoteLogFile, force=True)
|
||||
self.device.rm(self.remoteProfile, force=True, recursive=True)
|
||||
self.device.rm(self.remoteCache, force=True, recursive=True)
|
||||
MochitestDesktop.cleanup(self, options, final)
|
||||
self.localProfile = None
|
||||
|
||||
|
@ -179,9 +215,9 @@ class MochiRemote(MochitestDesktop):
|
|||
restoreRemotePaths = self.switchToLocalPaths(options)
|
||||
if options.testingModulesDir:
|
||||
try:
|
||||
self._dm.pushDir(options.testingModulesDir, self.remoteModulesDir)
|
||||
self._dm.chmodDir(self.remoteModulesDir)
|
||||
except mozdevice.DMError:
|
||||
self.device.push(options.testingModulesDir, self.remoteModulesDir)
|
||||
self.device.chmod(self.remoteModulesDir, recursive=True)
|
||||
except Exception:
|
||||
self.log.error(
|
||||
"Automation Error: Unable to copy test modules to device.")
|
||||
raise
|
||||
|
@ -199,24 +235,22 @@ class MochiRemote(MochitestDesktop):
|
|||
return manifest
|
||||
|
||||
def buildURLOptions(self, options, env):
|
||||
self.localLog = options.logFile
|
||||
options.logFile = self.remoteLog
|
||||
options.fileLevel = 'INFO'
|
||||
saveLogFile = options.logFile
|
||||
options.logFile = self.remoteLogFile
|
||||
options.profilePath = self.localProfile
|
||||
env["MOZ_HIDE_RESULTS_TABLE"] = "1"
|
||||
retVal = MochitestDesktop.buildURLOptions(self, options, env)
|
||||
|
||||
# we really need testConfig.js (for browser chrome)
|
||||
try:
|
||||
self._dm.pushDir(options.profilePath, self.remoteProfile)
|
||||
self._dm.chmodDir(self.remoteProfile)
|
||||
except mozdevice.DMError:
|
||||
self.log.error(
|
||||
"Automation Error: Unable to copy profile to device.")
|
||||
self.device.push(options.profilePath, self.remoteProfile)
|
||||
self.device.chmod(self.remoteProfile, recursive=True)
|
||||
except Exception:
|
||||
self.log.error("Automation Error: Unable to copy profile to device.")
|
||||
raise
|
||||
|
||||
options.profilePath = self.remoteProfile
|
||||
options.logFile = self.localLog
|
||||
options.logFile = saveLogFile
|
||||
return retVal
|
||||
|
||||
def getChromeTestDir(self, options):
|
||||
|
@ -225,7 +259,7 @@ class MochiRemote(MochitestDesktop):
|
|||
if options.flavor == 'chrome' and not self.chromePushed:
|
||||
self.log.info("pushing %s to %s on device..." % (local, remote))
|
||||
local = os.path.join(local, "chrome")
|
||||
self._dm.pushDir(local, remote)
|
||||
self.device.push(local, remote)
|
||||
self.chromePushed = True
|
||||
return remote
|
||||
|
||||
|
@ -235,7 +269,7 @@ class MochiRemote(MochitestDesktop):
|
|||
def printDeviceInfo(self, printLogcat=False):
|
||||
try:
|
||||
if printLogcat:
|
||||
logcat = self._dm.getLogcat(
|
||||
logcat = self.device.get_logcat(
|
||||
filterOutRegexps=fennecLogcatFilters)
|
||||
self.log.info(
|
||||
'\n' +
|
||||
|
@ -243,7 +277,7 @@ class MochiRemote(MochitestDesktop):
|
|||
'utf-8',
|
||||
'replace'))
|
||||
self.log.info("Device info:")
|
||||
devinfo = self._dm.getInfo()
|
||||
devinfo = self.device.get_info()
|
||||
for category in devinfo:
|
||||
if type(devinfo[category]) is list:
|
||||
self.log.info(" %s:" % category)
|
||||
|
@ -251,9 +285,9 @@ class MochiRemote(MochitestDesktop):
|
|||
self.log.info(" %s" % item)
|
||||
else:
|
||||
self.log.info(" %s: %s" % (category, devinfo[category]))
|
||||
self.log.info("Test root: %s" % self._dm.deviceRoot)
|
||||
except mozdevice.DMError:
|
||||
self.log.warning("Error getting device information")
|
||||
self.log.info("Test root: %s" % self.device.test_root)
|
||||
except Exception as e:
|
||||
self.log.warning("Error getting device information: %s" % str(e))
|
||||
|
||||
def getGMPPluginPath(self, options):
|
||||
# TODO: bug 1149374
|
||||
|
@ -287,7 +321,7 @@ class MochiRemote(MochitestDesktop):
|
|||
# remove args not supported by automation.py
|
||||
kwargs.pop('marionette_args', None)
|
||||
|
||||
ret, _ = self._automation.runApp(*args, **kwargs)
|
||||
ret, _ = self.automation.runApp(*args, **kwargs)
|
||||
self.countpass += self.counts['pass']
|
||||
self.countfail += self.counts['fail']
|
||||
self.counttodo += self.counts['todo']
|
||||
|
@ -298,11 +332,6 @@ class MochiRemote(MochitestDesktop):
|
|||
def run_test_harness(parser, options):
|
||||
parser.validate(options)
|
||||
|
||||
message_logger = MessageLogger(logger=None)
|
||||
counts = dict()
|
||||
process_args = {'messageLogger': message_logger, 'counts': counts}
|
||||
auto = RemoteAutomation(None, options.app, processArgs=process_args)
|
||||
|
||||
if options is None:
|
||||
raise ValueError("Invalid options specified, use --help for a list of valid options")
|
||||
|
||||
|
@ -312,72 +341,30 @@ def run_test_harness(parser, options):
|
|||
if options.flavor != 'chrome':
|
||||
options.extensionsToExclude.append('roboextender@mozilla.org')
|
||||
|
||||
dm = options.dm
|
||||
auto.setDeviceManager(dm)
|
||||
mochitest = MochiRemote(auto, dm, options)
|
||||
options.dm = None
|
||||
|
||||
log = mochitest.log
|
||||
message_logger.logger = log
|
||||
mochitest.message_logger = message_logger
|
||||
mochitest.counts = counts
|
||||
|
||||
# Check that Firefox is installed
|
||||
expected = options.app.split('/')[-1]
|
||||
installed = dm.shellCheckOutput(['pm', 'list', 'packages', expected])
|
||||
if expected not in installed:
|
||||
log.error("%s is not installed on this device" % expected)
|
||||
return 1
|
||||
|
||||
auto.setAppName(options.remoteappname)
|
||||
|
||||
logParent = os.path.dirname(options.remoteLogFile)
|
||||
dm.removeDir(logParent)
|
||||
dm.mkDir(logParent)
|
||||
auto.setRemoteLog(options.remoteLogFile)
|
||||
auto.setServerInfo(options.webServer, options.httpPort, options.sslPort)
|
||||
mochitest = MochiRemote(options)
|
||||
|
||||
if options.log_mach is None:
|
||||
mochitest.printDeviceInfo()
|
||||
|
||||
# Add Android version (SDK level) to mozinfo so that manifest entries
|
||||
# can be conditional on android_version.
|
||||
androidVersion = dm.shellCheckOutput(['getprop', 'ro.build.version.sdk'])
|
||||
log.info(
|
||||
"Android sdk version '%s'; will use this to filter manifests" %
|
||||
str(androidVersion))
|
||||
mozinfo.info['android_version'] = androidVersion
|
||||
|
||||
deviceRoot = dm.deviceRoot
|
||||
options.dumpOutputDirectory = deviceRoot
|
||||
|
||||
procName = options.app.split('/')[-1]
|
||||
dm.killProcess(procName)
|
||||
if dm.processExist(procName):
|
||||
log.warning("unable to kill %s before running tests!" % procName)
|
||||
|
||||
mochitest.mozLogName = "moz.log"
|
||||
try:
|
||||
dm.recordLogcat()
|
||||
if options.verify:
|
||||
retVal = mochitest.verifyTests(options)
|
||||
else:
|
||||
retVal = mochitest.runTests(options)
|
||||
except Exception:
|
||||
log.error("Automation Error: Exception caught while running tests")
|
||||
mochitest.log.error("Automation Error: Exception caught while running tests")
|
||||
traceback.print_exc()
|
||||
mochitest.stopServers()
|
||||
try:
|
||||
mochitest.cleanup(options)
|
||||
except mozdevice.DMError:
|
||||
except Exception:
|
||||
# device error cleaning up... oh well!
|
||||
pass
|
||||
traceback.print_exc()
|
||||
retVal = 1
|
||||
|
||||
if options.log_mach is None:
|
||||
mochitest.printDeviceInfo(printLogcat=True)
|
||||
|
||||
message_logger.finish()
|
||||
mochitest.message_logger.finish()
|
||||
|
||||
return retVal
|
||||
|
||||
|
|
|
@ -148,7 +148,6 @@ config = {
|
|||
"--log-raw=%(raw_log_file)s",
|
||||
"--log-errorsummary=%(error_summary_file)s",
|
||||
"--robocop-apk=../../robocop.apk",
|
||||
"--robocop-ini=robocop.ini",
|
||||
],
|
||||
},
|
||||
"reftest": {
|
||||
|
|
|
@ -248,8 +248,7 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
|
|||
self.remoteTestRoot = posixpath.join(self.device.test_root, "xpc")
|
||||
# Add Android version (SDK level) to mozinfo so that manifest entries
|
||||
# can be conditional on android_version.
|
||||
androidVersion = self.device.get_prop('ro.build.version.sdk')
|
||||
mozinfo.info['android_version'] = androidVersion
|
||||
mozinfo.info['android_version'] = self.device.version
|
||||
|
||||
self.localLib = options['localLib']
|
||||
self.localBin = options['localBin']
|
||||
|
|
Загрузка…
Ссылка в новой задаче