2012-07-17 09:56:26 -07:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import os
|
2012-11-27 08:04:46 -08:00
|
|
|
sys.path.insert(0, os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))))
|
|
|
|
|
2012-07-17 09:56:26 -07:00
|
|
|
import traceback
|
2013-07-19 19:27:14 -07:00
|
|
|
from remotexpcshelltests import RemoteXPCShellTestThread, XPCShellRemote, RemoteXPCShellOptions
|
2012-12-05 07:53:03 -08:00
|
|
|
from mozdevice import devicemanagerADB, DMError
|
2012-07-17 09:56:26 -07:00
|
|
|
|
|
|
|
DEVICE_TEST_ROOT = '/data/local/tests'
|
|
|
|
|
|
|
|
|
|
|
|
from marionette import Marionette
|
|
|
|
|
2013-07-19 19:27:14 -07:00
|
|
|
class B2GXPCShellTestThread(RemoteXPCShellTestThread):
|
|
|
|
# Overridden
|
|
|
|
def launchProcess(self, cmd, stdout, stderr, env, cwd):
|
|
|
|
try:
|
|
|
|
# This returns 1 even when tests pass - hardcode returncode to 0 (bug 773703)
|
|
|
|
outputFile = RemoteXPCShellTestThread.launchProcess(self, cmd, stdout, stderr, env, cwd)
|
|
|
|
self.shellReturnCode = 0
|
|
|
|
except DMError:
|
|
|
|
self.shellReturnCode = -1
|
|
|
|
outputFile = "xpcshelloutput"
|
|
|
|
f = open(outputFile, "a")
|
|
|
|
f.write("\n%s" % traceback.format_exc())
|
|
|
|
f.close()
|
|
|
|
return outputFile
|
2012-07-17 09:56:26 -07:00
|
|
|
|
2013-07-19 19:27:14 -07:00
|
|
|
class B2GXPCShellRemote(XPCShellRemote):
|
2013-09-05 17:58:54 -07:00
|
|
|
# Overridden
|
|
|
|
def setLD_LIBRARY_PATH(self):
|
|
|
|
self.env['LD_LIBRARY_PATH'] = '/system/b2g'
|
|
|
|
if not self.options.use_device_libs:
|
|
|
|
# overwrite /system/b2g if necessary
|
|
|
|
XPCShellRemote.setLD_LIBRARY_PATH(self)
|
|
|
|
|
2012-07-17 09:56:26 -07:00
|
|
|
# Overridden
|
|
|
|
def setupUtilities(self):
|
2012-09-14 16:44:29 -07:00
|
|
|
if self.options.clean:
|
|
|
|
# Ensure a fresh directory structure for our tests
|
|
|
|
self.clean()
|
2012-12-20 08:11:11 -08:00
|
|
|
self.device.mkDir(self.options.remoteTestRoot)
|
2012-07-17 09:56:26 -07:00
|
|
|
|
|
|
|
XPCShellRemote.setupUtilities(self)
|
|
|
|
|
|
|
|
def clean(self):
|
2012-07-30 12:04:45 -07:00
|
|
|
print >>sys.stderr, "\nCleaning files from previous run.."
|
2012-12-20 08:11:11 -08:00
|
|
|
self.device.removeDir(self.options.remoteTestRoot)
|
2012-07-17 09:56:26 -07:00
|
|
|
|
2012-11-28 12:27:04 -08:00
|
|
|
# Overriden
|
|
|
|
def setupTestDir(self):
|
|
|
|
if self.device._useZip:
|
|
|
|
return XPCShellRemote.setupTestDir(self)
|
|
|
|
|
|
|
|
for root, dirs, files in os.walk(self.xpcDir):
|
|
|
|
for filename in files:
|
|
|
|
rel_path = os.path.relpath(os.path.join(root, filename), self.xpcDir)
|
|
|
|
test_file = os.path.join(self.remoteScriptsDir, rel_path)
|
2013-01-04 11:07:48 -08:00
|
|
|
print 'pushing %s' % test_file
|
|
|
|
self.device.pushFile(os.path.join(root, filename), test_file, retryLimit=10)
|
2012-11-28 12:27:04 -08:00
|
|
|
|
2012-07-30 12:04:45 -07:00
|
|
|
# Overridden
|
|
|
|
def pushLibs(self):
|
|
|
|
if not self.options.use_device_libs:
|
2013-09-05 17:58:54 -07:00
|
|
|
count = XPCShellRemote.pushLibs(self)
|
|
|
|
if not count:
|
|
|
|
# couldn't find any libs, fallback to device libs
|
|
|
|
self.env['LD_LIBRARY_PATH'] = '/system/b2g'
|
|
|
|
self.options.use_device_libs = True
|
2012-07-30 12:04:45 -07:00
|
|
|
|
2012-07-17 09:56:26 -07:00
|
|
|
class B2GOptions(RemoteXPCShellOptions):
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
RemoteXPCShellOptions.__init__(self)
|
|
|
|
defaults = {}
|
|
|
|
|
|
|
|
self.add_option('--b2gpath', action='store',
|
|
|
|
type='string', dest='b2g_path',
|
|
|
|
help="Path to B2G repo or qemu dir")
|
|
|
|
defaults['b2g_path'] = None
|
|
|
|
|
2012-07-30 12:04:45 -07:00
|
|
|
self.add_option('--emupath', action='store',
|
|
|
|
type='string', dest='emu_path',
|
|
|
|
help="Path to emulator folder (if different "
|
|
|
|
"from b2gpath")
|
2012-09-14 16:44:29 -07:00
|
|
|
|
|
|
|
self.add_option('--no-clean', action='store_false',
|
|
|
|
dest='clean',
|
|
|
|
help="Do not clean TESTROOT. Saves [lots of] time")
|
|
|
|
defaults['clean'] = True
|
|
|
|
|
2012-07-30 12:04:45 -07:00
|
|
|
defaults['emu_path'] = None
|
2012-07-17 09:56:26 -07:00
|
|
|
|
|
|
|
self.add_option('--emulator', action='store',
|
|
|
|
type='string', dest='emulator',
|
|
|
|
help="Architecture of emulator to use: x86 or arm")
|
|
|
|
defaults['emulator'] = None
|
|
|
|
|
|
|
|
self.add_option('--no-window', action='store_true',
|
|
|
|
dest='no_window',
|
|
|
|
help="Pass --no-window to the emulator")
|
|
|
|
defaults['no_window'] = False
|
|
|
|
|
|
|
|
self.add_option('--adbpath', action='store',
|
|
|
|
type='string', dest='adb_path',
|
|
|
|
help="Path to adb")
|
|
|
|
defaults['adb_path'] = 'adb'
|
|
|
|
|
2012-07-30 12:04:45 -07:00
|
|
|
self.add_option('--address', action='store',
|
|
|
|
type='string', dest='address',
|
|
|
|
help="host:port of running Gecko instance to connect to")
|
|
|
|
defaults['address'] = None
|
|
|
|
|
|
|
|
self.add_option('--use-device-libs', action='store_true',
|
|
|
|
dest='use_device_libs',
|
|
|
|
help="Don't push .so's")
|
|
|
|
defaults['use_device_libs'] = False
|
2012-11-28 11:32:34 -08:00
|
|
|
self.add_option("--gecko-path", action="store",
|
|
|
|
type="string", dest="geckoPath",
|
|
|
|
help="the path to a gecko distribution that should "
|
|
|
|
"be installed on the emulator prior to test")
|
|
|
|
defaults["geckoPath"] = None
|
|
|
|
self.add_option("--logcat-dir", action="store",
|
|
|
|
type="string", dest="logcat_dir",
|
|
|
|
help="directory to store logcat dump files")
|
|
|
|
defaults["logcat_dir"] = None
|
2012-11-28 12:27:04 -08:00
|
|
|
self.add_option('--busybox', action='store',
|
|
|
|
type='string', dest='busybox',
|
|
|
|
help="Path to busybox binary to install on device")
|
|
|
|
defaults['busybox'] = None
|
2012-07-30 12:04:45 -07:00
|
|
|
|
2012-12-20 08:11:11 -08:00
|
|
|
defaults["remoteTestRoot"] = DEVICE_TEST_ROOT
|
2012-07-17 09:56:26 -07:00
|
|
|
defaults['dm_trans'] = 'adb'
|
|
|
|
defaults['debugger'] = None
|
|
|
|
defaults['debuggerArgs'] = None
|
|
|
|
|
|
|
|
self.set_defaults(**defaults)
|
|
|
|
|
2012-11-30 08:25:40 -08:00
|
|
|
def verifyRemoteOptions(self, options):
|
|
|
|
if options.b2g_path is None:
|
|
|
|
self.error("Need to specify a --b2gpath")
|
|
|
|
|
|
|
|
if options.geckoPath and not options.emulator:
|
|
|
|
self.error("You must specify --emulator if you specify --gecko-path")
|
|
|
|
|
|
|
|
if options.logcat_dir and not options.emulator:
|
|
|
|
self.error("You must specify --emulator if you specify --logcat-dir")
|
|
|
|
return RemoteXPCShellOptions.verifyRemoteOptions(self, options)
|
2012-07-17 09:56:26 -07:00
|
|
|
|
|
|
|
def main():
|
|
|
|
parser = B2GOptions()
|
|
|
|
options, args = parser.parse_args()
|
2012-11-30 08:25:40 -08:00
|
|
|
options = parser.verifyRemoteOptions(options)
|
2012-11-28 11:32:34 -08:00
|
|
|
|
2012-07-17 09:56:26 -07:00
|
|
|
# Create the Marionette instance
|
|
|
|
kwargs = {}
|
|
|
|
if options.emulator:
|
|
|
|
kwargs['emulator'] = options.emulator
|
|
|
|
if options.no_window:
|
|
|
|
kwargs['noWindow'] = True
|
2012-11-28 11:32:34 -08:00
|
|
|
if options.geckoPath:
|
|
|
|
kwargs['gecko_path'] = options.geckoPath
|
|
|
|
if options.logcat_dir:
|
|
|
|
kwargs['logcat_dir'] = options.logcat_dir
|
2012-11-28 12:27:04 -08:00
|
|
|
if options.busybox:
|
|
|
|
kwargs['busybox'] = options.busybox
|
2013-03-26 06:50:00 -07:00
|
|
|
if options.symbolsPath:
|
|
|
|
kwargs['symbols_path'] = options.symbolsPath
|
2012-07-17 09:56:26 -07:00
|
|
|
if options.b2g_path:
|
2012-07-30 12:04:45 -07:00
|
|
|
kwargs['homedir'] = options.emu_path or options.b2g_path
|
|
|
|
if options.address:
|
|
|
|
host, port = options.address.split(':')
|
2012-07-17 09:56:26 -07:00
|
|
|
kwargs['host'] = host
|
|
|
|
kwargs['port'] = int(port)
|
2012-07-30 12:04:45 -07:00
|
|
|
kwargs['baseurl'] = 'http://%s:%d/' % (host, int(port))
|
|
|
|
if options.emulator:
|
|
|
|
kwargs['connectToRunningEmulator'] = True
|
2012-07-17 09:56:26 -07:00
|
|
|
marionette = Marionette(**kwargs)
|
|
|
|
|
2014-02-20 13:56:57 -08:00
|
|
|
if options.emulator:
|
|
|
|
dm = marionette.emulator.dm
|
|
|
|
else:
|
|
|
|
# Create the DeviceManager instance
|
|
|
|
kwargs = {'adbPath': options.adb_path}
|
|
|
|
if options.deviceIP:
|
|
|
|
kwargs['host'] = options.deviceIP
|
|
|
|
kwargs['port'] = options.devicePort
|
|
|
|
kwargs['deviceRoot'] = options.remoteTestRoot
|
|
|
|
dm = devicemanagerADB.DeviceManagerADB(**kwargs)
|
2012-07-17 09:56:26 -07:00
|
|
|
|
2012-12-20 08:11:11 -08:00
|
|
|
if not options.remoteTestRoot:
|
|
|
|
options.remoteTestRoot = dm.getDeviceRoot()
|
2012-07-17 09:56:26 -07:00
|
|
|
xpcsh = B2GXPCShellRemote(dm, options, args)
|
|
|
|
|
2013-07-19 19:27:14 -07:00
|
|
|
# we don't run concurrent tests on mobile
|
|
|
|
options.sequential = True
|
|
|
|
|
2012-07-17 09:56:26 -07:00
|
|
|
try:
|
2013-08-29 10:13:56 -07:00
|
|
|
if not xpcsh.runTests(xpcshell='xpcshell', testdirs=args[0:],
|
2013-07-19 19:27:14 -07:00
|
|
|
testClass=B2GXPCShellTestThread,
|
|
|
|
mobileArgs=xpcsh.mobileArgs,
|
2013-08-29 10:13:56 -07:00
|
|
|
**options.__dict__):
|
|
|
|
sys.exit(1)
|
2012-07-17 09:56:26 -07:00
|
|
|
except:
|
2012-11-05 05:03:55 -08:00
|
|
|
print "Automation Error: Exception caught while running tests"
|
2012-07-17 09:56:26 -07:00
|
|
|
traceback.print_exc()
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
# You usually run this like :
|
2012-11-27 08:04:46 -08:00
|
|
|
# python runtestsb2g.py --emulator arm --b2gpath $B2GPATH --manifest $MANIFEST [--xre-path $MOZ_HOST_BIN
|
|
|
|
# --adbpath $ADB_PATH
|
2012-07-17 09:56:26 -07:00
|
|
|
# ...]
|
|
|
|
#
|
|
|
|
# For xUnit output you should also pass in --tests-root-dir ..objdir-gecko/_tests
|
|
|
|
# --xunit-file ..objdir_gecko/_tests/results.xml
|
|
|
|
# --xunit-suite-name xpcshell-tests
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|