Home | History | Annotate | Download | only in test_defs
      1 #!/usr/bin/python2.4
      2 #
      3 #
      4 # Copyright 2009, The Android Open Source Project
      5 #
      6 # Licensed under the Apache License, Version 2.0 (the "License");
      7 # you may not use this file except in compliance with the License.
      8 # You may obtain a copy of the License at
      9 #
     10 #     http://www.apache.org/licenses/LICENSE-2.0
     11 #
     12 # Unless required by applicable law or agreed to in writing, software
     13 # distributed under the License is distributed on an "AS IS" BASIS,
     14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 # See the License for the specific language governing permissions and
     16 # limitations under the License.
     17 
     18 """TestSuite for running native Android tests."""
     19 
     20 # python imports
     21 import os
     22 import re
     23 
     24 # local imports
     25 import android_build
     26 import logger
     27 import run_command
     28 import test_suite
     29 
     30 
     31 class NativeTestSuite(test_suite.AbstractTestSuite):
     32   """A test suite for running native aka C/C++ tests on device."""
     33 
     34   def Run(self, options, adb):
     35     """Run the provided *native* test suite.
     36 
     37     The test_suite must contain a build path where the native test
     38     files are. Subdirectories are automatically scanned as well.
     39 
     40     Each test's name must have a .cc or .cpp extension and match one
     41     of the following patterns:
     42       - test_*
     43       - *_test.[cc|cpp]
     44       - *_unittest.[cc|cpp]
     45     A successful test must return 0. Any other value will be considered
     46     as an error.
     47 
     48     Args:
     49       options: command line options
     50       adb: adb interface
     51     """
     52     # find all test files, convert unicode names to ascii, take the basename
     53     # and drop the .cc/.cpp  extension.
     54     source_list = []
     55     build_path = os.path.join(android_build.GetTop(), self.GetBuildPath())
     56     os.path.walk(build_path, self._CollectTestSources, source_list)
     57     logger.SilentLog("Tests source %s" % source_list)
     58 
     59     # Host tests are under out/host/<os>-<arch>/bin.
     60     host_list = self._FilterOutMissing(android_build.GetHostBin(), source_list)
     61     logger.SilentLog("Host tests %s" % host_list)
     62 
     63     # Target tests are under $ANDROID_PRODUCT_OUT/system/bin.
     64     target_list = self._FilterOutMissing(android_build.GetTargetSystemBin(),
     65                                          source_list)
     66     logger.SilentLog("Target tests %s" % target_list)
     67 
     68     # Run on the host
     69     logger.Log("\nRunning on host")
     70     for f in host_list:
     71       if run_command.RunHostCommand(f) != 0:
     72         logger.Log("%s... failed" % f)
     73       else:
     74         if run_command.HasValgrind():
     75           if run_command.RunHostCommand(f, valgrind=True) == 0:
     76             logger.Log("%s... ok\t\t[valgrind: ok]" % f)
     77           else:
     78             logger.Log("%s... ok\t\t[valgrind: failed]" % f)
     79         else:
     80           logger.Log("%s... ok\t\t[valgrind: missing]" % f)
     81 
     82     # Run on the device
     83     logger.Log("\nRunning on target")
     84     for f in target_list:
     85       full_path = os.path.join(os.sep, "system", "bin", f)
     86 
     87       # Single quotes are needed to prevent the shell splitting it.
     88       output = adb.SendShellCommand("'%s 2>&1;echo -n exit code:$?'" %
     89                                     "(cd /sdcard;%s)" % full_path,
     90                                     int(options.timeout))
     91       success = output.endswith("exit code:0")
     92       logger.Log("%s... %s" % (f, success and "ok" or "failed"))
     93       # Print the captured output when the test failed.
     94       if not success or options.verbose:
     95         pos = output.rfind("exit code")
     96         output = output[0:pos]
     97         logger.Log(output)
     98 
     99       # Cleanup
    100       adb.SendShellCommand("rm %s" % full_path)
    101 
    102   def _CollectTestSources(self, test_list, dirname, files):
    103     """For each directory, find tests source file and add them to the list.
    104 
    105     Test files must match one of the following pattern:
    106       - test_*.[cc|cpp]
    107       - *_test.[cc|cpp]
    108       - *_unittest.[cc|cpp]
    109 
    110     This method is a callback for os.path.walk.
    111 
    112     Args:
    113       test_list: Where new tests should be inserted.
    114       dirname: Current directory.
    115       files: List of files in the current directory.
    116     """
    117     for f in files:
    118       (name, ext) = os.path.splitext(f)
    119       if ext == ".cc" or ext == ".cpp" or ext == ".c":
    120         if re.search("_test$|_test_$|_unittest$|_unittest_$|^test_", name):
    121           logger.SilentLog("Found %s" % f)
    122           test_list.append(str(os.path.join(dirname, f)))
    123 
    124   def _FilterOutMissing(self, path, sources):
    125     """Filter out from the sources list missing tests.
    126 
    127     Sometimes some test source are not built for the target, i.e there
    128     is no binary corresponding to the source file. We need to filter
    129     these out.
    130 
    131     Args:
    132       path: Where the binaries should be.
    133       sources: List of tests source path.
    134     Returns:
    135       A list of test binaries built from the sources.
    136     """
    137     binaries = []
    138     for f in sources:
    139       binary = os.path.basename(f)
    140       binary = os.path.splitext(binary)[0]
    141       full_path = os.path.join(path, binary)
    142       if os.path.exists(full_path):
    143         binaries.append(binary)
    144     return binaries
    145 
    146   def _RunHostCommand(self, binary, valgrind=False):
    147     """Run a command on the host (opt using valgrind).
    148 
    149     Runs the host binary and returns the exit code.
    150     If successfull, the output (stdout and stderr) are discarded,
    151     but printed in case of error.
    152     The command can be run under valgrind in which case all the
    153     output are always discarded.
    154 
    155     Args:
    156       binary: basename of the file to be run. It is expected to be under
    157             out/host/<os>-<arch>/bin.
    158       valgrind: If True the command will be run under valgrind.
    159 
    160     Returns:
    161       The command exit code (int)
    162     """
    163     full_path = os.path.join(android_build.GetHostBin(), binary)
    164     return run_command.RunHostCommand(full_path, valgrind=valgrind)
    165