testing/xpcshell/remotexpcshelltests.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 #!/usr/bin/env python
     2 #
     3 # This Source Code Form is subject to the terms of the Mozilla Public
     4 # License, v. 2.0. If a copy of the MPL was not distributed with this
     5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     7 import posixpath
     8 import sys, os
     9 import subprocess
    10 import runxpcshelltests as xpcshell
    11 import tempfile
    12 from automationutils import replaceBackSlashes
    13 from mozdevice import devicemanagerADB, devicemanagerSUT, devicemanager
    14 from zipfile import ZipFile
    15 import shutil
    16 import mozfile
    17 import mozinfo
    19 here = os.path.dirname(os.path.abspath(__file__))
    21 def remoteJoin(path1, path2):
    22     return posixpath.join(path1, path2)
    24 class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
    25     def __init__(self, *args, **kwargs):
    26         xpcshell.XPCShellTestThread.__init__(self, *args, **kwargs)
    28         # embed the mobile params from the harness into the TestThread
    29         mobileArgs = kwargs.get('mobileArgs')
    30         for key in mobileArgs:
    31             setattr(self, key, mobileArgs[key])
    33     def buildCmdTestFile(self, name):
    34         remoteDir = self.remoteForLocal(os.path.dirname(name))
    35         if remoteDir == self.remoteHere:
    36             remoteName = os.path.basename(name)
    37         else:
    38             remoteName = remoteJoin(remoteDir, os.path.basename(name))
    39         return ['-e', 'const _TEST_FILE = ["%s"];' %
    40                  replaceBackSlashes(remoteName)]
    42     def remoteForLocal(self, local):
    43         for mapping in self.pathMapping:
    44             if (os.path.abspath(mapping.local) == os.path.abspath(local)):
    45                 return mapping.remote
    46         return local
    49     def setupTempDir(self):
    50         # make sure the temp dir exists
    51         if not self.device.dirExists(self.remoteTmpDir):
    52             self.device.mkDir(self.remoteTmpDir)
    53         # env var is set in buildEnvironment
    54         return self.remoteTmpDir
    56     def setupPluginsDir(self):
    57         if not os.path.isdir(self.pluginsPath):
    58             return None
    60         # making sure tmp dir is set up
    61         self.setupTempDir()
    63         pluginsDir = remoteJoin(self.remoteTmpDir, "plugins")
    64         self.device.pushDir(self.pluginsPath, pluginsDir)
    65         if self.interactive:
    66             self.log.info("TEST-INFO | plugins dir is %s" % pluginsDir)
    67         return pluginsDir
    69     def setupProfileDir(self):
    70         self.device.removeDir(self.profileDir)
    71         self.device.mkDir(self.profileDir)
    72         if self.interactive or self.singleFile:
    73             self.log.info("TEST-INFO | profile dir is %s" % self.profileDir)
    74         return self.profileDir
    76     def logCommand(self, name, completeCmd, testdir):
    77         self.log.info("TEST-INFO | %s | full command: %r" % (name, completeCmd))
    78         self.log.info("TEST-INFO | %s | current directory: %r" % (name, self.remoteHere))
    79         self.log.info("TEST-INFO | %s | environment: %s" % (name, self.env))
    81     def getHeadAndTailFiles(self, test):
    82         """Override parent method to find files on remote device."""
    83         def sanitize_list(s, kind):
    84             for f in s.strip().split(' '):
    85                 f = f.strip()
    86                 if len(f) < 1:
    87                     continue
    89                 path = remoteJoin(self.remoteHere, f)
    90                 if not self.device.fileExists(path):
    91                     raise Exception('%s file does not exist: %s' % ( kind,
    92                         path))
    94                 yield path
    96         self.remoteHere = self.remoteForLocal(test['here'])
    98         return (list(sanitize_list(test['head'], 'head')),
    99                 list(sanitize_list(test['tail'], 'tail')))
   101     def buildXpcsCmd(self, testdir):
   102         # change base class' paths to remote paths and use base class to build command
   103         self.xpcshell = remoteJoin(self.remoteBinDir, "xpcw")
   104         self.headJSPath = remoteJoin(self.remoteScriptsDir, 'head.js')
   105         self.httpdJSPath = remoteJoin(self.remoteComponentsDir, 'httpd.js')
   106         self.httpdManifest = remoteJoin(self.remoteComponentsDir, 'httpd.manifest')
   107         self.testingModulesDir = self.remoteModulesDir
   108         self.testharnessdir = self.remoteScriptsDir
   109         xpcshell.XPCShellTestThread.buildXpcsCmd(self, testdir)
   110         # remove "-g <dir> -a <dir>" and add "--greomni <apk>"
   111         del(self.xpcsCmd[1:5])
   112         if self.options.localAPK:
   113             self.xpcsCmd.insert(3, '--greomni')
   114             self.xpcsCmd.insert(4, self.remoteAPK)
   116         if self.remoteDebugger:
   117             # for example, "/data/local/gdbserver" "localhost:12345"
   118             self.xpcsCmd = [
   119               self.remoteDebugger,
   120               self.remoteDebuggerArgs,
   121               self.xpcsCmd]
   123     def testTimeout(self, test_file, proc):
   124         self.timedout = True
   125         if not self.retry:
   126             self.log.error("TEST-UNEXPECTED-FAIL | %s | Test timed out" % test_file)
   127         self.kill(proc)
   129     def launchProcess(self, cmd, stdout, stderr, env, cwd):
   130         self.timedout = False
   131         cmd.insert(1, self.remoteHere)
   132         outputFile = "xpcshelloutput"
   133         with open(outputFile, 'w+') as f:
   134             try:
   135                 self.shellReturnCode = self.device.shell(cmd, f)
   136             except devicemanager.DMError as e:
   137                 if self.timedout:
   138                     # If the test timed out, there is a good chance the SUTagent also
   139                     # timed out and failed to return a return code, generating a
   140                     # DMError. Ignore the DMError to simplify the error report.
   141                     self.shellReturnCode = None
   142                     pass
   143                 else:
   144                     raise e
   145         # The device manager may have timed out waiting for xpcshell.
   146         # Guard against an accumulation of hung processes by killing
   147         # them here. Note also that IPC tests may spawn new instances
   148         # of xpcshell.
   149         self.device.killProcess(cmd[0])
   150         self.device.killProcess("xpcshell")
   151         return outputFile
   153     def checkForCrashes(self,
   154                         dump_directory,
   155                         symbols_path,
   156                         test_name=None):
   157         if not self.device.dirExists(self.remoteMinidumpDir):
   158             # The minidumps directory is automatically created when Fennec
   159             # (first) starts, so its lack of presence is a hint that
   160             # something went wrong.
   161             print "Automation Error: No crash directory (%s) found on remote device" % self.remoteMinidumpDir
   162             # Whilst no crash was found, the run should still display as a failure
   163             return True
   164         with mozfile.TemporaryDirectory() as dumpDir:
   165             self.device.getDirectory(self.remoteMinidumpDir, dumpDir)
   166             crashed = xpcshell.XPCShellTestThread.checkForCrashes(self, dumpDir, symbols_path, test_name)
   167             self.device.removeDir(self.remoteMinidumpDir)
   168             self.device.mkDir(self.remoteMinidumpDir)
   169         return crashed
   171     def communicate(self, proc):
   172         f = open(proc, "r")
   173         contents = f.read()
   174         f.close()
   175         os.remove(proc)
   176         return contents, ""
   178     def poll(self, proc):
   179         if self.device.processExist("xpcshell") is None:
   180             return self.getReturnCode(proc)
   181         # Process is still running
   182         return None
   184     def kill(self, proc):
   185         return self.device.killProcess("xpcshell", True)
   187     def getReturnCode(self, proc):
   188         if self.shellReturnCode is not None:
   189             return self.shellReturnCode
   190         else:
   191             return -1
   193     def removeDir(self, dirname):
   194         self.device.removeDir(dirname)
   196     #TODO: consider creating a separate log dir.  We don't have the test file structure,
   197     #      so we use filename.log.  Would rather see ./logs/filename.log
   198     def createLogFile(self, test, stdout):
   199         try:
   200             f = None
   201             filename = test.replace('\\', '/').split('/')[-1] + ".log"
   202             f = open(filename, "w")
   203             f.write(stdout)
   205         finally:
   206             if f is not None:
   207                 f.close()
   210 # A specialization of XPCShellTests that runs tests on an Android device
   211 # via devicemanager.
   212 class XPCShellRemote(xpcshell.XPCShellTests, object):
   214     def __init__(self, devmgr, options, args, log=None):
   215         xpcshell.XPCShellTests.__init__(self, log)
   217         # Add Android version (SDK level) to mozinfo so that manifest entries
   218         # can be conditional on android_version.
   219         androidVersion = devmgr.shellCheckOutput(['getprop', 'ro.build.version.sdk'])
   220         mozinfo.info['android_version'] = androidVersion
   222         self.localLib = options.localLib
   223         self.localBin = options.localBin
   224         self.options = options
   225         self.device = devmgr
   226         self.pathMapping = []
   227         self.remoteTestRoot = self.device.getTestRoot("xpcshell")
   228         # remoteBinDir contains xpcshell and its wrapper script, both of which must
   229         # be executable. Since +x permissions cannot usually be set on /mnt/sdcard,
   230         # and the test root may be on /mnt/sdcard, remoteBinDir is set to be on
   231         # /data/local, always.
   232         self.remoteBinDir = "/data/local/xpcb"
   233         # Terse directory names are used here ("c" for the components directory)
   234         # to minimize the length of the command line used to execute
   235         # xpcshell on the remote device. adb has a limit to the number
   236         # of characters used in a shell command, and the xpcshell command
   237         # line can be quite complex.
   238         self.remoteTmpDir = remoteJoin(self.remoteTestRoot, "tmp")
   239         self.remoteScriptsDir = self.remoteTestRoot
   240         self.remoteComponentsDir = remoteJoin(self.remoteTestRoot, "c")
   241         self.remoteModulesDir = remoteJoin(self.remoteTestRoot, "m")
   242         self.remoteMinidumpDir = remoteJoin(self.remoteTestRoot, "minidumps")
   243         self.profileDir = remoteJoin(self.remoteTestRoot, "p")
   244         self.remoteDebugger = options.debugger
   245         self.remoteDebuggerArgs = options.debuggerArgs
   246         self.testingModulesDir = options.testingModulesDir
   248         self.env = {}
   250         if self.options.objdir:
   251             self.xpcDir = os.path.join(self.options.objdir, "_tests/xpcshell")
   252         elif os.path.isdir(os.path.join(here, 'tests')):
   253             self.xpcDir = os.path.join(here, 'tests')
   254         else:
   255             print >> sys.stderr, "Couldn't find local xpcshell test directory"
   256             sys.exit(1)
   258         if options.localAPK:
   259             self.localAPKContents = ZipFile(options.localAPK)
   260         if options.setup:
   261             self.setupUtilities()
   262             self.setupModules()
   263             self.setupTestDir()
   264         self.setupMinidumpDir()
   265         self.remoteAPK = None
   266         if options.localAPK:
   267             self.remoteAPK = remoteJoin(self.remoteBinDir, os.path.basename(options.localAPK))
   268             self.setAppRoot()
   270         # data that needs to be passed to the RemoteXPCShellTestThread
   271         self.mobileArgs = {
   272             'device': self.device,
   273             'remoteBinDir': self.remoteBinDir,
   274             'remoteScriptsDir': self.remoteScriptsDir,
   275             'remoteComponentsDir': self.remoteComponentsDir,
   276             'remoteModulesDir': self.remoteModulesDir,
   277             'options': self.options,
   278             'remoteDebugger': self.remoteDebugger,
   279             'pathMapping': self.pathMapping,
   280             'profileDir': self.profileDir,
   281             'remoteTmpDir': self.remoteTmpDir,
   282             'remoteMinidumpDir': self.remoteMinidumpDir,
   283         }
   284         if self.remoteAPK:
   285             self.mobileArgs['remoteAPK'] = self.remoteAPK
   287     def setLD_LIBRARY_PATH(self):
   288         self.env["LD_LIBRARY_PATH"] = self.remoteBinDir
   290     def pushWrapper(self):
   291         # Rather than executing xpcshell directly, this wrapper script is
   292         # used. By setting environment variables and the cwd in the script,
   293         # the length of the per-test command line is shortened. This is
   294         # often important when using ADB, as there is a limit to the length
   295         # of the ADB command line.
   296         localWrapper = tempfile.mktemp()
   297         f = open(localWrapper, "w")
   298         f.write("#!/system/bin/sh\n")
   299         for envkey, envval in self.env.iteritems():
   300             f.write("export %s=%s\n" % (envkey, envval))
   301         f.write("cd $1\n")
   302         f.write("echo xpcw: cd $1\n")
   303         f.write("shift\n")
   304         f.write("echo xpcw: xpcshell \"$@\"\n")
   305         f.write("%s/xpcshell \"$@\"\n" % self.remoteBinDir)
   306         f.close()
   307         remoteWrapper = remoteJoin(self.remoteBinDir, "xpcw")
   308         self.device.pushFile(localWrapper, remoteWrapper)
   309         os.remove(localWrapper)
   310         self.device.chmodDir(self.remoteBinDir)
   312     def buildEnvironment(self):
   313         self.buildCoreEnvironment()
   314         self.setLD_LIBRARY_PATH()
   315         self.env["MOZ_LINKER_CACHE"] = self.remoteBinDir
   316         if self.options.localAPK and self.appRoot:
   317             self.env["GRE_HOME"] = self.appRoot
   318         self.env["XPCSHELL_TEST_PROFILE_DIR"] = self.profileDir
   319         self.env["TMPDIR"] = self.remoteTmpDir
   320         self.env["HOME"] = self.profileDir
   321         self.env["XPCSHELL_TEST_TEMP_DIR"] = self.remoteTmpDir
   322         self.env["XPCSHELL_MINIDUMP_DIR"] = self.remoteMinidumpDir
   323         if self.options.setup:
   324             self.pushWrapper()
   326     def setAppRoot(self):
   327         # Determine the application root directory associated with the package
   328         # name used by the Fennec APK.
   329         self.appRoot = None
   330         packageName = None
   331         if self.options.localAPK:
   332             try:
   333                 packageName = self.localAPKContents.read("package-name.txt")
   334                 if packageName:
   335                     self.appRoot = self.device.getAppRoot(packageName.strip())
   336             except Exception as detail:
   337                 print "unable to determine app root: " + str(detail)
   338                 pass
   339         return None
   341     def setupUtilities(self):
   342         if (not self.device.dirExists(self.remoteBinDir)):
   343             # device.mkDir may fail here where shellCheckOutput may succeed -- see bug 817235
   344             try:
   345                 self.device.shellCheckOutput(["mkdir", self.remoteBinDir]);
   346             except devicemanager.DMError:
   347                 # Might get a permission error; try again as root, if available
   348                 self.device.shellCheckOutput(["mkdir", self.remoteBinDir], root=True);
   349                 self.device.shellCheckOutput(["chmod", "777", self.remoteBinDir], root=True);
   351         remotePrefDir = remoteJoin(self.remoteBinDir, "defaults/pref")
   352         if (self.device.dirExists(self.remoteTmpDir)):
   353             self.device.removeDir(self.remoteTmpDir)
   354         self.device.mkDir(self.remoteTmpDir)
   355         if (not self.device.dirExists(remotePrefDir)):
   356             self.device.mkDirs(remoteJoin(remotePrefDir, "extra"))
   357         if (not self.device.dirExists(self.remoteScriptsDir)):
   358             self.device.mkDir(self.remoteScriptsDir)
   359         if (not self.device.dirExists(self.remoteComponentsDir)):
   360             self.device.mkDir(self.remoteComponentsDir)
   362         local = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'head.js')
   363         remoteFile = remoteJoin(self.remoteScriptsDir, "head.js")
   364         self.device.pushFile(local, remoteFile)
   366         local = os.path.join(self.localBin, "xpcshell")
   367         remoteFile = remoteJoin(self.remoteBinDir, "xpcshell")
   368         self.device.pushFile(local, remoteFile)
   370         local = os.path.join(self.localBin, "components/httpd.js")
   371         remoteFile = remoteJoin(self.remoteComponentsDir, "httpd.js")
   372         self.device.pushFile(local, remoteFile)
   374         local = os.path.join(self.localBin, "components/httpd.manifest")
   375         remoteFile = remoteJoin(self.remoteComponentsDir, "httpd.manifest")
   376         self.device.pushFile(local, remoteFile)
   378         local = os.path.join(self.localBin, "components/test_necko.xpt")
   379         remoteFile = remoteJoin(self.remoteComponentsDir, "test_necko.xpt")
   380         self.device.pushFile(local, remoteFile)
   382         if self.options.localAPK:
   383             remoteFile = remoteJoin(self.remoteBinDir, os.path.basename(self.options.localAPK))
   384             self.device.pushFile(self.options.localAPK, remoteFile)
   386         self.pushLibs()
   388     def pushLibs(self):
   389         pushed_libs_count = 0
   390         if self.options.localAPK:
   391             try:
   392                 dir = tempfile.mkdtemp()
   393                 szip = os.path.join(self.localBin, '..', 'host', 'bin', 'szip')
   394                 if not os.path.exists(szip):
   395                     # Tinderbox builds must run szip from the test package
   396                     szip = os.path.join(self.localBin, 'host', 'szip')
   397                 if not os.path.exists(szip):
   398                     # If the test package doesn't contain szip, it means files
   399                     # are not szipped in the test package.
   400                     szip = None
   401                 for info in self.localAPKContents.infolist():
   402                     if info.filename.endswith(".so"):
   403                         print >> sys.stderr, "Pushing %s.." % info.filename
   404                         remoteFile = remoteJoin(self.remoteBinDir, os.path.basename(info.filename))
   405                         self.localAPKContents.extract(info, dir)
   406                         file = os.path.join(dir, info.filename)
   407                         if szip:
   408                             out = subprocess.check_output([szip, '-d', file], stderr=subprocess.STDOUT)
   409                         self.device.pushFile(os.path.join(dir, info.filename), remoteFile)
   410                         pushed_libs_count += 1
   411             finally:
   412                 shutil.rmtree(dir)
   413             return pushed_libs_count
   415         for file in os.listdir(self.localLib):
   416             if (file.endswith(".so")):
   417                 print >> sys.stderr, "Pushing %s.." % file
   418                 if 'libxul' in file:
   419                     print >> sys.stderr, "This is a big file, it could take a while."
   420                 remoteFile = remoteJoin(self.remoteBinDir, file)
   421                 self.device.pushFile(os.path.join(self.localLib, file), remoteFile)
   422                 pushed_libs_count += 1
   424         # Additional libraries may be found in a sub-directory such as "lib/armeabi-v7a"
   425         localArmLib = os.path.join(self.localLib, "lib")
   426         if os.path.exists(localArmLib):
   427             for root, dirs, files in os.walk(localArmLib):
   428                 for file in files:
   429                     if (file.endswith(".so")):
   430                         print >> sys.stderr, "Pushing %s.." % file
   431                         remoteFile = remoteJoin(self.remoteBinDir, file)
   432                         self.device.pushFile(os.path.join(root, file), remoteFile)
   433                         pushed_libs_count += 1
   435         return pushed_libs_count
   437     def setupModules(self):
   438         if self.testingModulesDir:
   439             self.device.pushDir(self.testingModulesDir, self.remoteModulesDir)
   441     def setupTestDir(self):
   442         print 'pushing %s' % self.xpcDir
   443         try:
   444             self.device.pushDir(self.xpcDir, self.remoteScriptsDir, retryLimit=10)
   445         except TypeError:
   446             # Foopies have an older mozdevice ver without retryLimit
   447             self.device.pushDir(self.xpcDir, self.remoteScriptsDir)
   449     def setupMinidumpDir(self):
   450         if self.device.dirExists(self.remoteMinidumpDir):
   451             self.device.removeDir(self.remoteMinidumpDir)
   452         self.device.mkDir(self.remoteMinidumpDir)
   454     def buildTestList(self):
   455         xpcshell.XPCShellTests.buildTestList(self)
   456         uniqueTestPaths = set([])
   457         for test in self.alltests:
   458             uniqueTestPaths.add(test['here'])
   459         for testdir in uniqueTestPaths:
   460             abbrevTestDir = os.path.relpath(testdir, self.xpcDir)
   461             remoteScriptDir = remoteJoin(self.remoteScriptsDir, abbrevTestDir)
   462             self.pathMapping.append(PathMapping(testdir, remoteScriptDir))
   464 class RemoteXPCShellOptions(xpcshell.XPCShellOptions):
   466     def __init__(self):
   467         xpcshell.XPCShellOptions.__init__(self)
   468         defaults = {}
   470         self.add_option("--deviceIP", action="store",
   471                         type = "string", dest = "deviceIP",
   472                         help = "ip address of remote device to test")
   473         defaults["deviceIP"] = None
   475         self.add_option("--devicePort", action="store",
   476                         type = "string", dest = "devicePort",
   477                         help = "port of remote device to test")
   478         defaults["devicePort"] = 20701
   480         self.add_option("--dm_trans", action="store",
   481                         type = "string", dest = "dm_trans",
   482                         help = "the transport to use to communicate with device: [adb|sut]; default=sut")
   483         defaults["dm_trans"] = "sut"
   485         self.add_option("--objdir", action="store",
   486                         type = "string", dest = "objdir",
   487                         help = "local objdir, containing xpcshell binaries")
   488         defaults["objdir"] = None
   490         self.add_option("--apk", action="store",
   491                         type = "string", dest = "localAPK",
   492                         help = "local path to Fennec APK")
   493         defaults["localAPK"] = None
   495         self.add_option("--noSetup", action="store_false",
   496                         dest = "setup",
   497                         help = "do not copy any files to device (to be used only if device is already setup)")
   498         defaults["setup"] = True
   500         self.add_option("--local-lib-dir", action="store",
   501                         type = "string", dest = "localLib",
   502                         help = "local path to library directory")
   503         defaults["localLib"] = None
   505         self.add_option("--local-bin-dir", action="store",
   506                         type = "string", dest = "localBin",
   507                         help = "local path to bin directory")
   508         defaults["localBin"] = None
   510         self.add_option("--remoteTestRoot", action = "store",
   511                     type = "string", dest = "remoteTestRoot",
   512                     help = "remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)")
   513         defaults["remoteTestRoot"] = None
   515         self.set_defaults(**defaults)
   517     def verifyRemoteOptions(self, options):
   518         if options.localLib is None:
   519             if options.localAPK and options.objdir:
   520                 for path in ['dist/fennec', 'fennec/lib']:
   521                     options.localLib = os.path.join(options.objdir, path)
   522                     if os.path.isdir(options.localLib):
   523                         break
   524                 else:
   525                     self.error("Couldn't find local library dir, specify --local-lib-dir")
   526             elif options.objdir:
   527                 options.localLib = os.path.join(options.objdir, 'dist/bin')
   528             elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')):
   529                 # assume tests are being run from a tests.zip
   530                 options.localLib = os.path.abspath(os.path.join(here, '..', 'bin'))
   531             else:
   532                 self.error("Couldn't find local library dir, specify --local-lib-dir")
   534         if options.localBin is None:
   535             if options.objdir:
   536                 for path in ['dist/bin', 'bin']:
   537                     options.localBin = os.path.join(options.objdir, path)
   538                     if os.path.isdir(options.localBin):
   539                         break
   540                 else:
   541                     self.error("Couldn't find local binary dir, specify --local-bin-dir")
   542             elif os.path.isfile(os.path.join(here, '..', 'bin', 'xpcshell')):
   543                 # assume tests are being run from a tests.zip
   544                 options.localBin = os.path.abspath(os.path.join(here, '..', 'bin'))
   545             else:
   546                 self.error("Couldn't find local binary dir, specify --local-bin-dir")
   547         return options
   549 class PathMapping:
   551     def __init__(self, localDir, remoteDir):
   552         self.local = localDir
   553         self.remote = remoteDir
   555 def main():
   557     if sys.version_info < (2,7):
   558         print >>sys.stderr, "Error: You must use python version 2.7 or newer but less than 3.0"
   559         sys.exit(1)
   561     parser = RemoteXPCShellOptions()
   562     options, args = parser.parse_args()
   563     if not options.localAPK:
   564         for file in os.listdir(os.path.join(options.objdir, "dist")):
   565             if (file.endswith(".apk") and file.startswith("fennec")):
   566                 options.localAPK = os.path.join(options.objdir, "dist")
   567                 options.localAPK = os.path.join(options.localAPK, file)
   568                 print >>sys.stderr, "using APK: " + options.localAPK
   569                 break
   570         else:
   571             print >>sys.stderr, "Error: please specify an APK"
   572             sys.exit(1)
   574     options = parser.verifyRemoteOptions(options)
   576     if len(args) < 1 and options.manifest is None:
   577         print >>sys.stderr, """Usage: %s <test dirs>
   578              or: %s --manifest=test.manifest """ % (sys.argv[0], sys.argv[0])
   579         sys.exit(1)
   581     if (options.dm_trans == "adb"):
   582         if (options.deviceIP):
   583             dm = devicemanagerADB.DeviceManagerADB(options.deviceIP, options.devicePort, packageName=None, deviceRoot=options.remoteTestRoot)
   584         else:
   585             dm = devicemanagerADB.DeviceManagerADB(packageName=None, deviceRoot=options.remoteTestRoot)
   586     else:
   587         dm = devicemanagerSUT.DeviceManagerSUT(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot)
   588         if (options.deviceIP == None):
   589             print "Error: you must provide a device IP to connect to via the --device option"
   590             sys.exit(1)
   592     if options.interactive and not options.testPath:
   593         print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
   594         sys.exit(1)
   596     xpcsh = XPCShellRemote(dm, options, args)
   598     # we don't run concurrent tests on mobile
   599     options.sequential = True
   601     if not xpcsh.runTests(xpcshell='xpcshell',
   602                           testClass=RemoteXPCShellTestThread,
   603                           testdirs=args[0:],
   604                           mobileArgs=xpcsh.mobileArgs,
   605                           **options.__dict__):
   606         sys.exit(1)
   609 if __name__ == '__main__':
   610     main()

mercurial