michael@0: #!/usr/bin/env python michael@0: # michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: import posixpath michael@0: import sys, os michael@0: import subprocess michael@0: import runxpcshelltests as xpcshell michael@0: import tempfile michael@0: from automationutils import replaceBackSlashes michael@0: from mozdevice import devicemanagerADB, devicemanagerSUT, devicemanager michael@0: from zipfile import ZipFile michael@0: import shutil michael@0: import mozfile michael@0: import mozinfo michael@0: michael@0: here = os.path.dirname(os.path.abspath(__file__)) michael@0: michael@0: def remoteJoin(path1, path2): michael@0: return posixpath.join(path1, path2) michael@0: michael@0: class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread): michael@0: def __init__(self, *args, **kwargs): michael@0: xpcshell.XPCShellTestThread.__init__(self, *args, **kwargs) michael@0: michael@0: # embed the mobile params from the harness into the TestThread michael@0: mobileArgs = kwargs.get('mobileArgs') michael@0: for key in mobileArgs: michael@0: setattr(self, key, mobileArgs[key]) michael@0: michael@0: def buildCmdTestFile(self, name): michael@0: remoteDir = self.remoteForLocal(os.path.dirname(name)) michael@0: if remoteDir == self.remoteHere: michael@0: remoteName = os.path.basename(name) michael@0: else: michael@0: remoteName = remoteJoin(remoteDir, os.path.basename(name)) michael@0: return ['-e', 'const _TEST_FILE = ["%s"];' % michael@0: replaceBackSlashes(remoteName)] michael@0: michael@0: def remoteForLocal(self, local): michael@0: for mapping in self.pathMapping: michael@0: if (os.path.abspath(mapping.local) == os.path.abspath(local)): michael@0: return mapping.remote michael@0: return local michael@0: michael@0: michael@0: def setupTempDir(self): michael@0: # make sure the temp dir exists michael@0: if not self.device.dirExists(self.remoteTmpDir): michael@0: self.device.mkDir(self.remoteTmpDir) michael@0: # env var is set in buildEnvironment michael@0: return self.remoteTmpDir michael@0: michael@0: def setupPluginsDir(self): michael@0: if not os.path.isdir(self.pluginsPath): michael@0: return None michael@0: michael@0: # making sure tmp dir is set up michael@0: self.setupTempDir() michael@0: michael@0: pluginsDir = remoteJoin(self.remoteTmpDir, "plugins") michael@0: self.device.pushDir(self.pluginsPath, pluginsDir) michael@0: if self.interactive: michael@0: self.log.info("TEST-INFO | plugins dir is %s" % pluginsDir) michael@0: return pluginsDir michael@0: michael@0: def setupProfileDir(self): michael@0: self.device.removeDir(self.profileDir) michael@0: self.device.mkDir(self.profileDir) michael@0: if self.interactive or self.singleFile: michael@0: self.log.info("TEST-INFO | profile dir is %s" % self.profileDir) michael@0: return self.profileDir michael@0: michael@0: def logCommand(self, name, completeCmd, testdir): michael@0: self.log.info("TEST-INFO | %s | full command: %r" % (name, completeCmd)) michael@0: self.log.info("TEST-INFO | %s | current directory: %r" % (name, self.remoteHere)) michael@0: self.log.info("TEST-INFO | %s | environment: %s" % (name, self.env)) michael@0: michael@0: def getHeadAndTailFiles(self, test): michael@0: """Override parent method to find files on remote device.""" michael@0: def sanitize_list(s, kind): michael@0: for f in s.strip().split(' '): michael@0: f = f.strip() michael@0: if len(f) < 1: michael@0: continue michael@0: michael@0: path = remoteJoin(self.remoteHere, f) michael@0: if not self.device.fileExists(path): michael@0: raise Exception('%s file does not exist: %s' % ( kind, michael@0: path)) michael@0: michael@0: yield path michael@0: michael@0: self.remoteHere = self.remoteForLocal(test['here']) michael@0: michael@0: return (list(sanitize_list(test['head'], 'head')), michael@0: list(sanitize_list(test['tail'], 'tail'))) michael@0: michael@0: def buildXpcsCmd(self, testdir): michael@0: # change base class' paths to remote paths and use base class to build command michael@0: self.xpcshell = remoteJoin(self.remoteBinDir, "xpcw") michael@0: self.headJSPath = remoteJoin(self.remoteScriptsDir, 'head.js') michael@0: self.httpdJSPath = remoteJoin(self.remoteComponentsDir, 'httpd.js') michael@0: self.httpdManifest = remoteJoin(self.remoteComponentsDir, 'httpd.manifest') michael@0: self.testingModulesDir = self.remoteModulesDir michael@0: self.testharnessdir = self.remoteScriptsDir michael@0: xpcshell.XPCShellTestThread.buildXpcsCmd(self, testdir) michael@0: # remove "-g -a " and add "--greomni " michael@0: del(self.xpcsCmd[1:5]) michael@0: if self.options.localAPK: michael@0: self.xpcsCmd.insert(3, '--greomni') michael@0: self.xpcsCmd.insert(4, self.remoteAPK) michael@0: michael@0: if self.remoteDebugger: michael@0: # for example, "/data/local/gdbserver" "localhost:12345" michael@0: self.xpcsCmd = [ michael@0: self.remoteDebugger, michael@0: self.remoteDebuggerArgs, michael@0: self.xpcsCmd] michael@0: michael@0: def testTimeout(self, test_file, proc): michael@0: self.timedout = True michael@0: if not self.retry: michael@0: self.log.error("TEST-UNEXPECTED-FAIL | %s | Test timed out" % test_file) michael@0: self.kill(proc) michael@0: michael@0: def launchProcess(self, cmd, stdout, stderr, env, cwd): michael@0: self.timedout = False michael@0: cmd.insert(1, self.remoteHere) michael@0: outputFile = "xpcshelloutput" michael@0: with open(outputFile, 'w+') as f: michael@0: try: michael@0: self.shellReturnCode = self.device.shell(cmd, f) michael@0: except devicemanager.DMError as e: michael@0: if self.timedout: michael@0: # If the test timed out, there is a good chance the SUTagent also michael@0: # timed out and failed to return a return code, generating a michael@0: # DMError. Ignore the DMError to simplify the error report. michael@0: self.shellReturnCode = None michael@0: pass michael@0: else: michael@0: raise e michael@0: # The device manager may have timed out waiting for xpcshell. michael@0: # Guard against an accumulation of hung processes by killing michael@0: # them here. Note also that IPC tests may spawn new instances michael@0: # of xpcshell. michael@0: self.device.killProcess(cmd[0]) michael@0: self.device.killProcess("xpcshell") michael@0: return outputFile michael@0: michael@0: def checkForCrashes(self, michael@0: dump_directory, michael@0: symbols_path, michael@0: test_name=None): michael@0: if not self.device.dirExists(self.remoteMinidumpDir): michael@0: # The minidumps directory is automatically created when Fennec michael@0: # (first) starts, so its lack of presence is a hint that michael@0: # something went wrong. michael@0: print "Automation Error: No crash directory (%s) found on remote device" % self.remoteMinidumpDir michael@0: # Whilst no crash was found, the run should still display as a failure michael@0: return True michael@0: with mozfile.TemporaryDirectory() as dumpDir: michael@0: self.device.getDirectory(self.remoteMinidumpDir, dumpDir) michael@0: crashed = xpcshell.XPCShellTestThread.checkForCrashes(self, dumpDir, symbols_path, test_name) michael@0: self.device.removeDir(self.remoteMinidumpDir) michael@0: self.device.mkDir(self.remoteMinidumpDir) michael@0: return crashed michael@0: michael@0: def communicate(self, proc): michael@0: f = open(proc, "r") michael@0: contents = f.read() michael@0: f.close() michael@0: os.remove(proc) michael@0: return contents, "" michael@0: michael@0: def poll(self, proc): michael@0: if self.device.processExist("xpcshell") is None: michael@0: return self.getReturnCode(proc) michael@0: # Process is still running michael@0: return None michael@0: michael@0: def kill(self, proc): michael@0: return self.device.killProcess("xpcshell", True) michael@0: michael@0: def getReturnCode(self, proc): michael@0: if self.shellReturnCode is not None: michael@0: return self.shellReturnCode michael@0: else: michael@0: return -1 michael@0: michael@0: def removeDir(self, dirname): michael@0: self.device.removeDir(dirname) michael@0: michael@0: #TODO: consider creating a separate log dir. We don't have the test file structure, michael@0: # so we use filename.log. Would rather see ./logs/filename.log michael@0: def createLogFile(self, test, stdout): michael@0: try: michael@0: f = None michael@0: filename = test.replace('\\', '/').split('/')[-1] + ".log" michael@0: f = open(filename, "w") michael@0: f.write(stdout) michael@0: michael@0: finally: michael@0: if f is not None: michael@0: f.close() michael@0: michael@0: michael@0: # A specialization of XPCShellTests that runs tests on an Android device michael@0: # via devicemanager. michael@0: class XPCShellRemote(xpcshell.XPCShellTests, object): michael@0: michael@0: def __init__(self, devmgr, options, args, log=None): michael@0: xpcshell.XPCShellTests.__init__(self, log) michael@0: michael@0: # Add Android version (SDK level) to mozinfo so that manifest entries michael@0: # can be conditional on android_version. michael@0: androidVersion = devmgr.shellCheckOutput(['getprop', 'ro.build.version.sdk']) michael@0: mozinfo.info['android_version'] = androidVersion michael@0: michael@0: self.localLib = options.localLib michael@0: self.localBin = options.localBin michael@0: self.options = options michael@0: self.device = devmgr michael@0: self.pathMapping = [] michael@0: self.remoteTestRoot = self.device.getTestRoot("xpcshell") michael@0: # remoteBinDir contains xpcshell and its wrapper script, both of which must michael@0: # be executable. Since +x permissions cannot usually be set on /mnt/sdcard, michael@0: # and the test root may be on /mnt/sdcard, remoteBinDir is set to be on michael@0: # /data/local, always. michael@0: self.remoteBinDir = "/data/local/xpcb" michael@0: # Terse directory names are used here ("c" for the components directory) michael@0: # to minimize the length of the command line used to execute michael@0: # xpcshell on the remote device. adb has a limit to the number michael@0: # of characters used in a shell command, and the xpcshell command michael@0: # line can be quite complex. michael@0: self.remoteTmpDir = remoteJoin(self.remoteTestRoot, "tmp") michael@0: self.remoteScriptsDir = self.remoteTestRoot michael@0: self.remoteComponentsDir = remoteJoin(self.remoteTestRoot, "c") michael@0: self.remoteModulesDir = remoteJoin(self.remoteTestRoot, "m") michael@0: self.remoteMinidumpDir = remoteJoin(self.remoteTestRoot, "minidumps") michael@0: self.profileDir = remoteJoin(self.remoteTestRoot, "p") michael@0: self.remoteDebugger = options.debugger michael@0: self.remoteDebuggerArgs = options.debuggerArgs michael@0: self.testingModulesDir = options.testingModulesDir michael@0: michael@0: self.env = {} michael@0: michael@0: if self.options.objdir: michael@0: self.xpcDir = os.path.join(self.options.objdir, "_tests/xpcshell") michael@0: elif os.path.isdir(os.path.join(here, 'tests')): michael@0: self.xpcDir = os.path.join(here, 'tests') michael@0: else: michael@0: print >> sys.stderr, "Couldn't find local xpcshell test directory" michael@0: sys.exit(1) michael@0: michael@0: if options.localAPK: michael@0: self.localAPKContents = ZipFile(options.localAPK) michael@0: if options.setup: michael@0: self.setupUtilities() michael@0: self.setupModules() michael@0: self.setupTestDir() michael@0: self.setupMinidumpDir() michael@0: self.remoteAPK = None michael@0: if options.localAPK: michael@0: self.remoteAPK = remoteJoin(self.remoteBinDir, os.path.basename(options.localAPK)) michael@0: self.setAppRoot() michael@0: michael@0: # data that needs to be passed to the RemoteXPCShellTestThread michael@0: self.mobileArgs = { michael@0: 'device': self.device, michael@0: 'remoteBinDir': self.remoteBinDir, michael@0: 'remoteScriptsDir': self.remoteScriptsDir, michael@0: 'remoteComponentsDir': self.remoteComponentsDir, michael@0: 'remoteModulesDir': self.remoteModulesDir, michael@0: 'options': self.options, michael@0: 'remoteDebugger': self.remoteDebugger, michael@0: 'pathMapping': self.pathMapping, michael@0: 'profileDir': self.profileDir, michael@0: 'remoteTmpDir': self.remoteTmpDir, michael@0: 'remoteMinidumpDir': self.remoteMinidumpDir, michael@0: } michael@0: if self.remoteAPK: michael@0: self.mobileArgs['remoteAPK'] = self.remoteAPK michael@0: michael@0: def setLD_LIBRARY_PATH(self): michael@0: self.env["LD_LIBRARY_PATH"] = self.remoteBinDir michael@0: michael@0: def pushWrapper(self): michael@0: # Rather than executing xpcshell directly, this wrapper script is michael@0: # used. By setting environment variables and the cwd in the script, michael@0: # the length of the per-test command line is shortened. This is michael@0: # often important when using ADB, as there is a limit to the length michael@0: # of the ADB command line. michael@0: localWrapper = tempfile.mktemp() michael@0: f = open(localWrapper, "w") michael@0: f.write("#!/system/bin/sh\n") michael@0: for envkey, envval in self.env.iteritems(): michael@0: f.write("export %s=%s\n" % (envkey, envval)) michael@0: f.write("cd $1\n") michael@0: f.write("echo xpcw: cd $1\n") michael@0: f.write("shift\n") michael@0: f.write("echo xpcw: xpcshell \"$@\"\n") michael@0: f.write("%s/xpcshell \"$@\"\n" % self.remoteBinDir) michael@0: f.close() michael@0: remoteWrapper = remoteJoin(self.remoteBinDir, "xpcw") michael@0: self.device.pushFile(localWrapper, remoteWrapper) michael@0: os.remove(localWrapper) michael@0: self.device.chmodDir(self.remoteBinDir) michael@0: michael@0: def buildEnvironment(self): michael@0: self.buildCoreEnvironment() michael@0: self.setLD_LIBRARY_PATH() michael@0: self.env["MOZ_LINKER_CACHE"] = self.remoteBinDir michael@0: if self.options.localAPK and self.appRoot: michael@0: self.env["GRE_HOME"] = self.appRoot michael@0: self.env["XPCSHELL_TEST_PROFILE_DIR"] = self.profileDir michael@0: self.env["TMPDIR"] = self.remoteTmpDir michael@0: self.env["HOME"] = self.profileDir michael@0: self.env["XPCSHELL_TEST_TEMP_DIR"] = self.remoteTmpDir michael@0: self.env["XPCSHELL_MINIDUMP_DIR"] = self.remoteMinidumpDir michael@0: if self.options.setup: michael@0: self.pushWrapper() michael@0: michael@0: def setAppRoot(self): michael@0: # Determine the application root directory associated with the package michael@0: # name used by the Fennec APK. michael@0: self.appRoot = None michael@0: packageName = None michael@0: if self.options.localAPK: michael@0: try: michael@0: packageName = self.localAPKContents.read("package-name.txt") michael@0: if packageName: michael@0: self.appRoot = self.device.getAppRoot(packageName.strip()) michael@0: except Exception as detail: michael@0: print "unable to determine app root: " + str(detail) michael@0: pass michael@0: return None michael@0: michael@0: def setupUtilities(self): michael@0: if (not self.device.dirExists(self.remoteBinDir)): michael@0: # device.mkDir may fail here where shellCheckOutput may succeed -- see bug 817235 michael@0: try: michael@0: self.device.shellCheckOutput(["mkdir", self.remoteBinDir]); michael@0: except devicemanager.DMError: michael@0: # Might get a permission error; try again as root, if available michael@0: self.device.shellCheckOutput(["mkdir", self.remoteBinDir], root=True); michael@0: self.device.shellCheckOutput(["chmod", "777", self.remoteBinDir], root=True); michael@0: michael@0: remotePrefDir = remoteJoin(self.remoteBinDir, "defaults/pref") michael@0: if (self.device.dirExists(self.remoteTmpDir)): michael@0: self.device.removeDir(self.remoteTmpDir) michael@0: self.device.mkDir(self.remoteTmpDir) michael@0: if (not self.device.dirExists(remotePrefDir)): michael@0: self.device.mkDirs(remoteJoin(remotePrefDir, "extra")) michael@0: if (not self.device.dirExists(self.remoteScriptsDir)): michael@0: self.device.mkDir(self.remoteScriptsDir) michael@0: if (not self.device.dirExists(self.remoteComponentsDir)): michael@0: self.device.mkDir(self.remoteComponentsDir) michael@0: michael@0: local = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'head.js') michael@0: remoteFile = remoteJoin(self.remoteScriptsDir, "head.js") michael@0: self.device.pushFile(local, remoteFile) michael@0: michael@0: local = os.path.join(self.localBin, "xpcshell") michael@0: remoteFile = remoteJoin(self.remoteBinDir, "xpcshell") michael@0: self.device.pushFile(local, remoteFile) michael@0: michael@0: local = os.path.join(self.localBin, "components/httpd.js") michael@0: remoteFile = remoteJoin(self.remoteComponentsDir, "httpd.js") michael@0: self.device.pushFile(local, remoteFile) michael@0: michael@0: local = os.path.join(self.localBin, "components/httpd.manifest") michael@0: remoteFile = remoteJoin(self.remoteComponentsDir, "httpd.manifest") michael@0: self.device.pushFile(local, remoteFile) michael@0: michael@0: local = os.path.join(self.localBin, "components/test_necko.xpt") michael@0: remoteFile = remoteJoin(self.remoteComponentsDir, "test_necko.xpt") michael@0: self.device.pushFile(local, remoteFile) michael@0: michael@0: if self.options.localAPK: michael@0: remoteFile = remoteJoin(self.remoteBinDir, os.path.basename(self.options.localAPK)) michael@0: self.device.pushFile(self.options.localAPK, remoteFile) michael@0: michael@0: self.pushLibs() michael@0: michael@0: def pushLibs(self): michael@0: pushed_libs_count = 0 michael@0: if self.options.localAPK: michael@0: try: michael@0: dir = tempfile.mkdtemp() michael@0: szip = os.path.join(self.localBin, '..', 'host', 'bin', 'szip') michael@0: if not os.path.exists(szip): michael@0: # Tinderbox builds must run szip from the test package michael@0: szip = os.path.join(self.localBin, 'host', 'szip') michael@0: if not os.path.exists(szip): michael@0: # If the test package doesn't contain szip, it means files michael@0: # are not szipped in the test package. michael@0: szip = None michael@0: for info in self.localAPKContents.infolist(): michael@0: if info.filename.endswith(".so"): michael@0: print >> sys.stderr, "Pushing %s.." % info.filename michael@0: remoteFile = remoteJoin(self.remoteBinDir, os.path.basename(info.filename)) michael@0: self.localAPKContents.extract(info, dir) michael@0: file = os.path.join(dir, info.filename) michael@0: if szip: michael@0: out = subprocess.check_output([szip, '-d', file], stderr=subprocess.STDOUT) michael@0: self.device.pushFile(os.path.join(dir, info.filename), remoteFile) michael@0: pushed_libs_count += 1 michael@0: finally: michael@0: shutil.rmtree(dir) michael@0: return pushed_libs_count michael@0: michael@0: for file in os.listdir(self.localLib): michael@0: if (file.endswith(".so")): michael@0: print >> sys.stderr, "Pushing %s.." % file michael@0: if 'libxul' in file: michael@0: print >> sys.stderr, "This is a big file, it could take a while." michael@0: remoteFile = remoteJoin(self.remoteBinDir, file) michael@0: self.device.pushFile(os.path.join(self.localLib, file), remoteFile) michael@0: pushed_libs_count += 1 michael@0: michael@0: # Additional libraries may be found in a sub-directory such as "lib/armeabi-v7a" michael@0: localArmLib = os.path.join(self.localLib, "lib") michael@0: if os.path.exists(localArmLib): michael@0: for root, dirs, files in os.walk(localArmLib): michael@0: for file in files: michael@0: if (file.endswith(".so")): michael@0: print >> sys.stderr, "Pushing %s.." % file michael@0: remoteFile = remoteJoin(self.remoteBinDir, file) michael@0: self.device.pushFile(os.path.join(root, file), remoteFile) michael@0: pushed_libs_count += 1 michael@0: michael@0: return pushed_libs_count michael@0: michael@0: def setupModules(self): michael@0: if self.testingModulesDir: michael@0: self.device.pushDir(self.testingModulesDir, self.remoteModulesDir) michael@0: michael@0: def setupTestDir(self): michael@0: print 'pushing %s' % self.xpcDir michael@0: try: michael@0: self.device.pushDir(self.xpcDir, self.remoteScriptsDir, retryLimit=10) michael@0: except TypeError: michael@0: # Foopies have an older mozdevice ver without retryLimit michael@0: self.device.pushDir(self.xpcDir, self.remoteScriptsDir) michael@0: michael@0: def setupMinidumpDir(self): michael@0: if self.device.dirExists(self.remoteMinidumpDir): michael@0: self.device.removeDir(self.remoteMinidumpDir) michael@0: self.device.mkDir(self.remoteMinidumpDir) michael@0: michael@0: def buildTestList(self): michael@0: xpcshell.XPCShellTests.buildTestList(self) michael@0: uniqueTestPaths = set([]) michael@0: for test in self.alltests: michael@0: uniqueTestPaths.add(test['here']) michael@0: for testdir in uniqueTestPaths: michael@0: abbrevTestDir = os.path.relpath(testdir, self.xpcDir) michael@0: remoteScriptDir = remoteJoin(self.remoteScriptsDir, abbrevTestDir) michael@0: self.pathMapping.append(PathMapping(testdir, remoteScriptDir)) michael@0: michael@0: class RemoteXPCShellOptions(xpcshell.XPCShellOptions): michael@0: michael@0: def __init__(self): michael@0: xpcshell.XPCShellOptions.__init__(self) michael@0: defaults = {} michael@0: michael@0: self.add_option("--deviceIP", action="store", michael@0: type = "string", dest = "deviceIP", michael@0: help = "ip address of remote device to test") michael@0: defaults["deviceIP"] = None michael@0: michael@0: self.add_option("--devicePort", action="store", michael@0: type = "string", dest = "devicePort", michael@0: help = "port of remote device to test") michael@0: defaults["devicePort"] = 20701 michael@0: michael@0: self.add_option("--dm_trans", action="store", michael@0: type = "string", dest = "dm_trans", michael@0: help = "the transport to use to communicate with device: [adb|sut]; default=sut") michael@0: defaults["dm_trans"] = "sut" michael@0: michael@0: self.add_option("--objdir", action="store", michael@0: type = "string", dest = "objdir", michael@0: help = "local objdir, containing xpcshell binaries") michael@0: defaults["objdir"] = None michael@0: michael@0: self.add_option("--apk", action="store", michael@0: type = "string", dest = "localAPK", michael@0: help = "local path to Fennec APK") michael@0: defaults["localAPK"] = None michael@0: michael@0: self.add_option("--noSetup", action="store_false", michael@0: dest = "setup", michael@0: help = "do not copy any files to device (to be used only if device is already setup)") michael@0: defaults["setup"] = True michael@0: michael@0: self.add_option("--local-lib-dir", action="store", michael@0: type = "string", dest = "localLib", michael@0: help = "local path to library directory") michael@0: defaults["localLib"] = None michael@0: michael@0: self.add_option("--local-bin-dir", action="store", michael@0: type = "string", dest = "localBin", michael@0: help = "local path to bin directory") michael@0: defaults["localBin"] = None michael@0: michael@0: self.add_option("--remoteTestRoot", action = "store", michael@0: type = "string", dest = "remoteTestRoot", michael@0: help = "remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)") michael@0: defaults["remoteTestRoot"] = None michael@0: michael@0: self.set_defaults(**defaults) michael@0: michael@0: def verifyRemoteOptions(self, options): michael@0: if options.localLib is None: michael@0: if options.localAPK and options.objdir: michael@0: for path in ['dist/fennec', 'fennec/lib']: michael@0: options.localLib = os.path.join(options.objdir, path) michael@0: if os.path.isdir(options.localLib): michael@0: break michael@0: else: michael@0: self.error("Couldn't find local library dir, specify --local-lib-dir") michael@0: elif options.objdir: michael@0: options.localLib = os.path.join(options.objdir, 'dist/bin') michael@0: elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')): michael@0: # assume tests are being run from a tests.zip michael@0: options.localLib = os.path.abspath(os.path.join(here, '..', 'bin')) michael@0: else: michael@0: self.error("Couldn't find local library dir, specify --local-lib-dir") michael@0: michael@0: if options.localBin is None: michael@0: if options.objdir: michael@0: for path in ['dist/bin', 'bin']: michael@0: options.localBin = os.path.join(options.objdir, path) michael@0: if os.path.isdir(options.localBin): michael@0: break michael@0: else: michael@0: self.error("Couldn't find local binary dir, specify --local-bin-dir") michael@0: elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')): michael@0: # assume tests are being run from a tests.zip michael@0: options.localBin = os.path.abspath(os.path.join(here, '..', 'bin')) michael@0: else: michael@0: self.error("Couldn't find local binary dir, specify --local-bin-dir") michael@0: return options michael@0: michael@0: class PathMapping: michael@0: michael@0: def __init__(self, localDir, remoteDir): michael@0: self.local = localDir michael@0: self.remote = remoteDir michael@0: michael@0: def main(): michael@0: michael@0: if sys.version_info < (2,7): michael@0: print >>sys.stderr, "Error: You must use python version 2.7 or newer but less than 3.0" michael@0: sys.exit(1) michael@0: michael@0: parser = RemoteXPCShellOptions() michael@0: options, args = parser.parse_args() michael@0: if not options.localAPK: michael@0: for file in os.listdir(os.path.join(options.objdir, "dist")): michael@0: if (file.endswith(".apk") and file.startswith("fennec")): michael@0: options.localAPK = os.path.join(options.objdir, "dist") michael@0: options.localAPK = os.path.join(options.localAPK, file) michael@0: print >>sys.stderr, "using APK: " + options.localAPK michael@0: break michael@0: else: michael@0: print >>sys.stderr, "Error: please specify an APK" michael@0: sys.exit(1) michael@0: michael@0: options = parser.verifyRemoteOptions(options) michael@0: michael@0: if len(args) < 1 and options.manifest is None: michael@0: print >>sys.stderr, """Usage: %s michael@0: or: %s --manifest=test.manifest """ % (sys.argv[0], sys.argv[0]) michael@0: sys.exit(1) michael@0: michael@0: if (options.dm_trans == "adb"): michael@0: if (options.deviceIP): michael@0: dm = devicemanagerADB.DeviceManagerADB(options.deviceIP, options.devicePort, packageName=None, deviceRoot=options.remoteTestRoot) michael@0: else: michael@0: dm = devicemanagerADB.DeviceManagerADB(packageName=None, deviceRoot=options.remoteTestRoot) michael@0: else: michael@0: dm = devicemanagerSUT.DeviceManagerSUT(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot) michael@0: if (options.deviceIP == None): michael@0: print "Error: you must provide a device IP to connect to via the --device option" michael@0: sys.exit(1) michael@0: michael@0: if options.interactive and not options.testPath: michael@0: print >>sys.stderr, "Error: You must specify a test filename in interactive mode!" michael@0: sys.exit(1) michael@0: michael@0: xpcsh = XPCShellRemote(dm, options, args) michael@0: michael@0: # we don't run concurrent tests on mobile michael@0: options.sequential = True michael@0: michael@0: if not xpcsh.runTests(xpcshell='xpcshell', michael@0: testClass=RemoteXPCShellTestThread, michael@0: testdirs=args[0:], michael@0: mobileArgs=xpcsh.mobileArgs, michael@0: **options.__dict__): michael@0: sys.exit(1) michael@0: michael@0: michael@0: if __name__ == '__main__': michael@0: main()