testing/remotecppunittests.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 os, sys
     8 import subprocess
     9 import tempfile
    10 from zipfile import ZipFile
    11 import runcppunittests as cppunittests
    12 import mozcrash, mozlog
    13 import mozfile
    14 import StringIO
    15 import posixpath
    16 from mozdevice import devicemanager, devicemanagerADB, devicemanagerSUT
    18 try:
    19     from mozbuild.base import MozbuildObject
    20     build_obj = MozbuildObject.from_environment()
    21 except ImportError:
    22     build_obj = None
    24 log = mozlog.getLogger('remotecppunittests')
    26 class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
    27     def __init__(self, devmgr, options, progs):
    28         cppunittests.CPPUnitTests.__init__(self)
    29         self.options = options
    30         self.device = devmgr
    31         self.remote_test_root = self.device.getDeviceRoot() + "/cppunittests"
    32         self.remote_bin_dir = posixpath.join(self.remote_test_root, "b")
    33         self.remote_tmp_dir = posixpath.join(self.remote_test_root, "tmp")
    34         self.remote_home_dir = posixpath.join(self.remote_test_root, "h")
    35         if options.setup:
    36             self.setup_bin(progs)
    38     def setup_bin(self, progs):
    39         if not self.device.dirExists(self.remote_test_root):
    40             self.device.mkDir(self.remote_test_root)
    41         if self.device.dirExists(self.remote_tmp_dir):
    42             self.device.removeDir(self.remote_tmp_dir)
    43         self.device.mkDir(self.remote_tmp_dir)
    44         if self.device.dirExists(self.remote_bin_dir):
    45             self.device.removeDir(self.remote_bin_dir)
    46         self.device.mkDir(self.remote_bin_dir)
    47         if self.device.dirExists(self.remote_home_dir):
    48             self.device.removeDir(self.remote_home_dir)
    49         self.device.mkDir(self.remote_home_dir)
    50         self.push_libs()
    51         self.push_progs(progs)
    52         self.device.chmodDir(self.remote_bin_dir)
    54     def push_libs(self):
    55         if self.options.local_apk:
    56             with mozfile.TemporaryDirectory() as tmpdir:
    57                 apk_contents = ZipFile(self.options.local_apk)
    58                 szip = os.path.join(self.options.local_bin, '..', 'host', 'bin', 'szip')
    59                 if not os.path.exists(szip):
    60                     # Tinderbox builds must run szip from the test package
    61                     szip = os.path.join(self.options.local_bin, 'host', 'szip')
    62                 if not os.path.exists(szip):
    63                     # If the test package doesn't contain szip, it means files
    64                     # are not szipped in the test package.
    65                     szip = None
    67                 for info in apk_contents.infolist():
    68                     if info.filename.endswith(".so"):
    69                         print >> sys.stderr, "Pushing %s.." % info.filename
    70                         remote_file = posixpath.join(self.remote_bin_dir, os.path.basename(info.filename))
    71                         apk_contents.extract(info, tmpdir)
    72                         file = os.path.join(tmpdir, info.filename)
    73                         if szip:
    74                             out = subprocess.check_output([szip, '-d', file], stderr=subprocess.STDOUT)
    75                         self.device.pushFile(os.path.join(tmpdir, info.filename), remote_file)
    76             return
    78         for file in os.listdir(self.options.local_lib):
    79             if file.endswith(".so"):
    80                 print >> sys.stderr, "Pushing %s.." % file
    81                 remote_file = posixpath.join(self.remote_bin_dir, file)
    82                 self.device.pushFile(os.path.join(self.options.local_lib, file), remote_file)
    83         # Additional libraries may be found in a sub-directory such as "lib/armeabi-v7a"
    84         local_arm_lib = os.path.join(self.options.local_lib, "lib")
    85         if os.path.isdir(local_arm_lib):
    86             for root, dirs, files in os.walk(local_arm_lib):
    87                 for file in files:
    88                     if (file.endswith(".so")):
    89                         remote_file = posixpath.join(self.remote_bin_dir, file)
    90                         self.device.pushFile(os.path.join(root, file), remote_file)
    92     def push_progs(self, progs):
    93         for local_file in progs:
    94             remote_file = posixpath.join(self.remote_bin_dir, os.path.basename(local_file))
    95             self.device.pushFile(local_file, remote_file)
    97     def build_environment(self):
    98         env = self.build_core_environment()
    99         env['LD_LIBRARY_PATH'] = self.remote_bin_dir
   100         env["TMPDIR"]=self.remote_tmp_dir
   101         env["HOME"]=self.remote_home_dir
   102         env["MOZILLA_FIVE_HOME"] = self.remote_home_dir
   103         env["MOZ_XRE_DIR"] = self.remote_bin_dir
   104         if self.options.add_env:
   105             for envdef in self.options.add_env:
   106                 envdef_parts = envdef.split("=", 1)
   107                 if len(envdef_parts) == 2:
   108                     env[envdef_parts[0]] = envdef_parts[1]
   109                 elif len(envdef_parts) == 1:
   110                     env[envdef_parts[0]] = ""
   111                 else:
   112                     print >> sys.stderr, "warning: invalid --addEnv option skipped: "+envdef
   114         return env
   116     def run_one_test(self, prog, env, symbols_path=None):
   117         """
   118         Run a single C++ unit test program remotely.
   120         Arguments:
   121         * prog: The path to the test program to run.
   122         * env: The environment to use for running the program.
   123         * symbols_path: A path to a directory containing Breakpad-formatted
   124                         symbol files for producing stack traces on crash.
   126         Return True if the program exits with a zero status, False otherwise.
   127         """
   128         basename = os.path.basename(prog)
   129         remote_bin = posixpath.join(self.remote_bin_dir, basename)
   130         log.info("Running test %s", basename)
   131         buf = StringIO.StringIO()
   132         returncode = self.device.shell([remote_bin], buf, env=env, cwd=self.remote_home_dir,
   133                                        timeout=cppunittests.CPPUnitTests.TEST_PROC_TIMEOUT)
   134         print >> sys.stdout, buf.getvalue()
   135         with mozfile.TemporaryDirectory() as tempdir:
   136             self.device.getDirectory(self.remote_home_dir, tempdir)
   137             if mozcrash.check_for_crashes(tempdir, symbols_path,
   138                                           test_name=basename):
   139                 log.testFail("%s | test crashed", basename)
   140                 return False
   141         result = returncode == 0
   142         if not result:
   143             log.testFail("%s | test failed with return code %s",
   144                          basename, returncode)
   145         return result
   147 class RemoteCPPUnittestOptions(cppunittests.CPPUnittestOptions):
   148     def __init__(self):
   149         cppunittests.CPPUnittestOptions.__init__(self)
   150         defaults = {}
   152         self.add_option("--deviceIP", action="store",
   153                         type = "string", dest = "device_ip",
   154                         help = "ip address of remote device to test")
   155         defaults["device_ip"] = None
   157         self.add_option("--devicePort", action="store",
   158                         type = "string", dest = "device_port",
   159                         help = "port of remote device to test")
   160         defaults["device_port"] = 20701
   162         self.add_option("--dm_trans", action="store",
   163                         type = "string", dest = "dm_trans",
   164                         help = "the transport to use to communicate with device: [adb|sut]; default=sut")
   165         defaults["dm_trans"] = "sut"
   167         self.add_option("--noSetup", action="store_false",
   168                         dest = "setup",
   169                         help = "do not copy any files to device (to be used only if device is already setup)")
   170         defaults["setup"] = True
   172         self.add_option("--localLib", action="store",
   173                         type = "string", dest = "local_lib",
   174                         help = "location of libraries to push -- preferably stripped")
   175         defaults["local_lib"] = None
   177         self.add_option("--apk", action="store",
   178                         type = "string", dest = "local_apk",
   179                         help = "local path to Fennec APK")
   180         defaults["local_apk"] = None
   182         self.add_option("--localBinDir", action="store",
   183                         type = "string", dest = "local_bin",
   184                         help = "local path to bin directory")
   185         defaults["local_bin"] = build_obj.bindir if build_obj is not None else None
   187         self.add_option("--remoteTestRoot", action = "store",
   188                     type = "string", dest = "remote_test_root",
   189                     help = "remote directory to use as test root (eg. /data/local/tests)")
   190         # /data/local/tests is used because it is usually not possible to set +x permissions
   191         # on binaries on /mnt/sdcard
   192         defaults["remote_test_root"] = "/data/local/tests"
   194         self.add_option("--addEnv", action = "append",
   195                     type = "string", dest = "add_env",
   196                     help = "additional remote environment variable definitions (eg. --addEnv \"somevar=something\")")
   197         defaults["add_env"] = None
   199         self.set_defaults(**defaults)
   201 def main():
   202     parser = RemoteCPPUnittestOptions()
   203     options, args = parser.parse_args()
   204     if not args:
   205         print >>sys.stderr, """Usage: %s <test binary> [<test binary>...]""" % sys.argv[0]
   206         sys.exit(1)
   207     if options.local_lib is None and options.local_apk is None:
   208         print >>sys.stderr, """Error: --localLib or --apk is required"""
   209         sys.exit(1)
   210     if options.local_lib is not None and not os.path.isdir(options.local_lib):
   211         print >>sys.stderr, """Error: --localLib directory %s not found""" % options.local_lib
   212         sys.exit(1)
   213     if options.local_apk is not None and not os.path.isfile(options.local_apk):
   214         print >>sys.stderr, """Error: --apk file %s not found""" % options.local_apk
   215         sys.exit(1)
   216     if not options.xre_path:
   217         print >>sys.stderr, """Error: --xre-path is required"""
   218         sys.exit(1)
   219     if options.dm_trans == "adb":
   220         if options.device_ip:
   221             dm = devicemanagerADB.DeviceManagerADB(options.device_ip, options.device_port, packageName=None, deviceRoot=options.remote_test_root)
   222         else:
   223             dm = devicemanagerADB.DeviceManagerADB(packageName=None, deviceRoot=options.remote_test_root)
   224     else:
   225         dm = devicemanagerSUT.DeviceManagerSUT(options.device_ip, options.device_port, deviceRoot=options.remote_test_root)
   226         if not options.device_ip:
   227             print "Error: you must provide a device IP to connect to via the --deviceIP option"
   228             sys.exit(1)
   229     options.xre_path = os.path.abspath(options.xre_path)
   230     progs = cppunittests.extract_unittests_from_args(args, options.manifest_file)
   231     tester = RemoteCPPUnitTests(dm, options, progs)
   232     try:
   233         result = tester.run_tests(progs, options.xre_path, options.symbols_path)
   234     except Exception, e:
   235         log.error(str(e))
   236         result = False
   237     sys.exit(0 if result else 1)
   239 if __name__ == '__main__':
   240     main()

mercurial