Home | History | Annotate | Download | only in test
      1 #!/usr/bin/env python
      2 
      3 """
      4 A simple testing framework for lldb using python's unit testing framework.
      5 
      6 Tests for lldb are written as python scripts which take advantage of the script
      7 bridging provided by LLDB.framework to interact with lldb core.
      8 
      9 A specific naming pattern is followed by the .py script to be recognized as
     10 a module which implements a test scenario, namely, Test*.py.
     11 
     12 To specify the directories where "Test*.py" python test scripts are located,
     13 you need to pass in a list of directory names.  By default, the current
     14 working directory is searched if nothing is specified on the command line.
     15 
     16 Type:
     17 
     18 ./dotest.py -h
     19 
     20 for available options.
     21 """
     22 
     23 import os
     24 import platform
     25 import signal
     26 import subprocess
     27 import sys
     28 import textwrap
     29 import time
     30 import unittest2
     31 import progress
     32 
     33 if sys.version_info >= (2, 7):
     34     argparse = __import__('argparse')
     35 else:
     36     argparse = __import__('argparse_compat')
     37 
     38 def parse_args(parser):
     39     """ Returns an argument object. LLDB_TEST_ARGUMENTS environment variable can
     40         be used to pass additional arguments if a compatible (>=2.7) argparse
     41         library is available.
     42     """
     43     if sys.version_info >= (2, 7):
     44         args = ArgParseNamespace()
     45 
     46         if ('LLDB_TEST_ARGUMENTS' in os.environ):
     47             print "Arguments passed through environment: '%s'" % os.environ['LLDB_TEST_ARGUMENTS']
     48             args = parser.parse_args([sys.argv[0]].__add__(os.environ['LLDB_TEST_ARGUMENTS'].split()),namespace=args)
     49 
     50         return parser.parse_args(namespace=args)
     51     else:
     52         return parser.parse_args()
     53 
     54 def is_exe(fpath):
     55     """Returns true if fpath is an executable."""
     56     return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
     57 
     58 def which(program):
     59     """Returns the full path to a program; None otherwise."""
     60     fpath, fname = os.path.split(program)
     61     if fpath:
     62         if is_exe(program):
     63             return program
     64     else:
     65         for path in os.environ["PATH"].split(os.pathsep):
     66             exe_file = os.path.join(path, program)
     67             if is_exe(exe_file):
     68                 return exe_file
     69     return None
     70 
     71 class _WritelnDecorator(object):
     72     """Used to decorate file-like objects with a handy 'writeln' method"""
     73     def __init__(self,stream):
     74         self.stream = stream
     75 
     76     def __getattr__(self, attr):
     77         if attr in ('stream', '__getstate__'):
     78             raise AttributeError(attr)
     79         return getattr(self.stream,attr)
     80 
     81     def writeln(self, arg=None):
     82         if arg:
     83             self.write(arg)
     84         self.write('\n') # text-mode streams translate to \r\n if needed
     85 
     86 #
     87 # Global variables:
     88 #
     89 
     90 # Dictionary of categories
     91 # When you define a new category for your testcases, be sure to add it here, or the test suite
     92 # will gladly complain as soon as you try to use it. This allows us to centralize which categories
     93 # exist, and to provide a description for each one
     94 validCategories = {
     95 'dataformatters':'Tests related to the type command and the data formatters subsystem',
     96 'expression':'Tests related to the expression parser',
     97 'objc':'Tests related to the Objective-C programming language support',
     98 'pyapi':'Tests related to the Python API',
     99 'basic_process': 'Basic process execution sniff tests.',
    100 'cmdline' : 'Tests related to the LLDB command-line interface'
    101 }
    102 
    103 # The test suite.
    104 suite = unittest2.TestSuite()
    105 
    106 # By default, both command line and Python API tests are performed.
    107 # Use @python_api_test decorator, defined in lldbtest.py, to mark a test as
    108 # a Python API test.
    109 dont_do_python_api_test = False
    110 
    111 # By default, both command line and Python API tests are performed.
    112 just_do_python_api_test = False
    113 
    114 # By default, benchmarks tests are not run.
    115 just_do_benchmarks_test = False
    116 
    117 # By default, both dsym and dwarf tests are performed.
    118 # Use @dsym_test or @dwarf_test decorators, defined in lldbtest.py, to mark a test
    119 # as a dsym or dwarf test.  Use '-N dsym' or '-N dwarf' to exclude dsym or dwarf
    120 # tests from running.
    121 dont_do_dsym_test = "linux" in sys.platform or "freebsd" in sys.platform
    122 dont_do_dwarf_test = False
    123 
    124 # The blacklist is optional (-b blacklistFile) and allows a central place to skip
    125 # testclass's and/or testclass.testmethod's.
    126 blacklist = None
    127 
    128 # The dictionary as a result of sourcing blacklistFile.
    129 blacklistConfig = {}
    130 
    131 # The list of categories we said we care about
    132 categoriesList = None
    133 # set to true if we are going to use categories for cherry-picking test cases
    134 useCategories = False
    135 # Categories we want to skip
    136 skipCategories = []
    137 # use this to track per-category failures
    138 failuresPerCategory = {}
    139 
    140 # The path to LLDB.framework is optional.
    141 lldbFrameworkPath = None
    142 
    143 # The path to lldb is optional
    144 lldbExecutablePath = None
    145 
    146 # The config file is optional.
    147 configFile = None
    148 
    149 # Test suite repeat count.  Can be overwritten with '-# count'.
    150 count = 1
    151 
    152 # The dictionary as a result of sourcing configFile.
    153 config = {}
    154 # The pre_flight and post_flight functions come from reading a config file.
    155 pre_flight = None
    156 post_flight = None
    157 
    158 # The 'archs' and 'compilers' can be specified via either command line or configFile,
    159 # with the command line overriding the configFile.  The corresponding options can be
    160 # specified more than once. For example, "-A x86_64 -A i386" => archs=['x86_64', 'i386']
    161 # and "-C gcc -C clang" => compilers=['gcc', 'clang'].
    162 archs = None        # Must be initialized after option parsing
    163 compilers = None    # Must be initialized after option parsing
    164 
    165 # The arch might dictate some specific CFLAGS to be passed to the toolchain to build
    166 # the inferior programs.  The global variable cflags_extras provides a hook to do
    167 # just that.
    168 cflags_extras = ''
    169 
    170 # Delay startup in order for the debugger to attach.
    171 delay = False
    172 
    173 # Dump the Python sys.path variable.  Use '-D' to dump sys.path.
    174 dumpSysPath = False
    175 
    176 # Full path of the benchmark executable, as specified by the '-e' option.
    177 bmExecutable = None
    178 # The breakpoint specification of bmExecutable, as specified by the '-x' option.
    179 bmBreakpointSpec = None
    180 # The benchamrk iteration count, as specified by the '-y' option.
    181 bmIterationCount = -1
    182 
    183 # By default, don't exclude any directories.  Use '-X' to add one excluded directory.
    184 excluded = set(['.svn', '.git'])
    185 
    186 # By default, failfast is False.  Use '-F' to overwrite it.
    187 failfast = False
    188 
    189 # The filters (testclass.testmethod) used to admit tests into our test suite.
    190 filters = []
    191 
    192 # The runhooks is a list of lldb commands specifically for the debugger.
    193 # Use '-k' to specify a runhook.
    194 runHooks = []
    195 
    196 # If '-g' is specified, the filterspec is not exclusive.  If a test module does
    197 # not contain testclass.testmethod which matches the filterspec, the whole test
    198 # module is still admitted into our test suite.  fs4all flag defaults to True.
    199 fs4all = True
    200 
    201 # Ignore the build search path relative to this script to locate the lldb.py module.
    202 ignore = False
    203 
    204 # By default, we do not skip build and cleanup.  Use '-S' option to override.
    205 skip_build_and_cleanup = False
    206 
    207 # By default, we skip long running test case.  Use '-l' option to override.
    208 skip_long_running_test = True
    209 
    210 # By default, we print the build dir, lldb version, and svn info.  Use '-n' option to
    211 # turn it off.
    212 noHeaders = False
    213 
    214 # Parsable mode silences headers, and any other output this script might generate, and instead
    215 # prints machine-readable output similar to what clang tests produce.
    216 parsable = False
    217 
    218 # The regular expression pattern to match against eligible filenames as our test cases.
    219 regexp = None
    220 
    221 # By default, tests are executed in place and cleanups are performed afterwards.
    222 # Use '-r dir' option to relocate the tests and their intermediate files to a
    223 # different directory and to forgo any cleanups.  The directory specified must
    224 # not exist yet.
    225 rdir = None
    226 
    227 # By default, recorded session info for errored/failed test are dumped into its
    228 # own file under a session directory named after the timestamp of the test suite
    229 # run.  Use '-s session-dir-name' to specify a specific dir name.
    230 sdir_name = None
    231 
    232 # Set this flag if there is any session info dumped during the test run.
    233 sdir_has_content = False
    234 
    235 # svn_info stores the output from 'svn info lldb.base.dir'.
    236 svn_info = ''
    237 
    238 # svn_silent means do not try to obtain svn status
    239 svn_silent = True
    240 
    241 # Default verbosity is 0.
    242 verbose = 1
    243 
    244 # Set to True only if verbose is 0 and LLDB trace mode is off.
    245 progress_bar = False
    246 
    247 # By default, search from the script directory.
    248 testdirs = [ sys.path[0] ]
    249 
    250 # Separator string.
    251 separator = '-' * 70
    252 
    253 failed = False
    254 
    255 def usage(parser):
    256     parser.print_help()
    257     if verbose > 0:
    258         print """
    259 Examples:
    260 
    261 This is an example of using the -f option to pinpoint to a specfic test class
    262 and test method to be run:
    263 
    264 $ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command
    265 ----------------------------------------------------------------------
    266 Collected 1 test
    267 
    268 test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
    269 Test 'frame variable this' when stopped on a class constructor. ... ok
    270 
    271 ----------------------------------------------------------------------
    272 Ran 1 test in 1.396s
    273 
    274 OK
    275 
    276 And this is an example of using the -p option to run a single file (the filename
    277 matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
    278 
    279 $ ./dotest.py -v -p ObjC
    280 ----------------------------------------------------------------------
    281 Collected 4 tests
    282 
    283 test_break_with_dsym (TestObjCMethods.FoundationTestCase)
    284 Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
    285 test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
    286 Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
    287 test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
    288 Lookup objective-c data types and evaluate expressions. ... ok
    289 test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
    290 Lookup objective-c data types and evaluate expressions. ... ok
    291 
    292 ----------------------------------------------------------------------
    293 Ran 4 tests in 16.661s
    294 
    295 OK
    296 
    297 Running of this script also sets up the LLDB_TEST environment variable so that
    298 individual test cases can locate their supporting files correctly.  The script
    299 tries to set up Python's search paths for modules by looking at the build tree
    300 relative to this script.  See also the '-i' option in the following example.
    301 
    302 Finally, this is an example of using the lldb.py module distributed/installed by
    303 Xcode4 to run against the tests under the 'forward' directory, and with the '-w'
    304 option to add some delay between two tests.  It uses ARCH=x86_64 to specify that
    305 as the architecture and CC=clang to specify the compiler used for the test run:
    306 
    307 $ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward
    308 
    309 Session logs for test failures/errors will go into directory '2010-11-11-13_56_16'
    310 ----------------------------------------------------------------------
    311 Collected 2 tests
    312 
    313 test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
    314 Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
    315 test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
    316 Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
    317 
    318 ----------------------------------------------------------------------
    319 Ran 2 tests in 5.659s
    320 
    321 OK
    322 
    323 The 'Session ...' verbiage is recently introduced (see also the '-s' option) to
    324 notify the directory containing the session logs for test failures or errors.
    325 In case there is any test failure/error, a similar message is appended at the
    326 end of the stderr output for your convenience.
    327 
    328 Environment variables related to loggings:
    329 
    330 o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
    331   with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
    332 
    333 o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
    334   'process.gdb-remote' subsystem with a default option of 'packets' if
    335   GDB_REMOTE_LOG_OPTION is not defined.
    336 """
    337     sys.exit(0)
    338 
    339 
    340 def unique_string_match(yourentry,list):
    341 	candidate = None
    342 	for item in list:
    343 		if item.startswith(yourentry):
    344 			if candidate:
    345 				return None
    346 			candidate = item
    347 	return candidate
    348 
    349 class ArgParseNamespace(object):
    350     pass
    351 
    352 def validate_categories(categories):
    353     """For each category in categories, ensure that it's a valid category (or a prefix thereof).
    354        If a category is invalid, print a message and quit.
    355        If all categories are valid, return the list of categories. Prefixes are expanded in the
    356        returned list.
    357     """
    358     global validCategories
    359     result = []
    360     for category in categories:
    361         origCategory = category
    362         if category not in validCategories:
    363             category = unique_string_match(category, validCategories)
    364         if (category not in validCategories) or category == None:
    365             print "fatal error: category '" + origCategory + "' is not a valid category"
    366             print "if you have added a new category, please edit dotest.py, adding your new category to validCategories"
    367             print "else, please specify one or more of the following: " + str(validCategories.keys())
    368             sys.exit(1)
    369         result.append(category)
    370     return result
    371 
    372 def parseOptionsAndInitTestdirs():
    373     """Initialize the list of directories containing our unittest scripts.
    374 
    375     '-h/--help as the first option prints out usage info and exit the program.
    376     """
    377 
    378     global dont_do_python_api_test
    379     global just_do_python_api_test
    380     global just_do_benchmarks_test
    381     global dont_do_dsym_test
    382     global dont_do_dwarf_test
    383     global blacklist
    384     global blacklistConfig
    385     global categoriesList
    386     global validCategories
    387     global useCategories
    388     global skipCategories
    389     global lldbFrameworkPath
    390     global lldbExecutablePath
    391     global configFile
    392     global archs
    393     global compilers
    394     global count
    395     global delay
    396     global dumpSysPath
    397     global bmExecutable
    398     global bmBreakpointSpec
    399     global bmIterationCount
    400     global failfast
    401     global filters
    402     global fs4all
    403     global ignore
    404     global progress_bar
    405     global runHooks
    406     global skip_build_and_cleanup
    407     global skip_long_running_test
    408     global noHeaders
    409     global parsable
    410     global regexp
    411     global rdir
    412     global sdir_name
    413     global svn_silent
    414     global verbose
    415     global testdirs
    416 
    417     do_help = False
    418 
    419     parser = argparse.ArgumentParser(description='description', prefix_chars='+-', add_help=False)
    420     group = None
    421 
    422     # Helper function for boolean options (group will point to the current group when executing X)
    423     X = lambda optstr, helpstr, **kwargs: group.add_argument(optstr, help=helpstr, action='store_true', **kwargs)
    424 
    425     group = parser.add_argument_group('Help')
    426     group.add_argument('-h', '--help', dest='h', action='store_true', help="Print this help message and exit.  Add '-v' for more detailed help.")
    427 
    428     # C and Python toolchain options
    429     group = parser.add_argument_group('Toolchain options')
    430     group.add_argument('-A', '--arch', metavar='arch', action='append', dest='archs', help=textwrap.dedent('''Specify the architecture(s) to test. This option can be specified more than once'''))
    431     group.add_argument('-C', '--compiler', metavar='compiler', dest='compilers', action='append', help=textwrap.dedent('''Specify the compiler(s) used to build the inferior executables. The compiler path can be an executable basename or a full path to a compiler executable. This option can be specified multiple times.'''))
    432     # FIXME? This won't work for different extra flags according to each arch.
    433     group.add_argument('-E', metavar='extra-flags', help=textwrap.dedent('''Specify the extra flags to be passed to the toolchain when building the inferior programs to be debugged
    434                                                            suggestions: do not lump the "-A arch1 -A arch2" together such that the -E option applies to only one of the architectures'''))
    435     X('-D', 'Dump the Python sys.path variable')
    436 
    437     # Test filtering options
    438     group = parser.add_argument_group('Test filtering options')
    439     group.add_argument('-N', choices=['dwarf', 'dsym'], help="Don't do test cases marked with the @dsym decorator by passing 'dsym' as the option arg, or don't do test cases marked with the @dwarf decorator by passing 'dwarf' as the option arg")
    440     X('-a', "Don't do lldb Python API tests")
    441     X('+a', "Just do lldb Python API tests. Do not specify along with '+a'", dest='plus_a')
    442     X('+b', 'Just do benchmark tests', dest='plus_b')
    443     group.add_argument('-b', metavar='blacklist', help='Read a blacklist file specified after this option')
    444     group.add_argument('-f', metavar='filterspec', action='append', help='Specify a filter, which consists of the test class name, a dot, followed by the test method, to only admit such test into the test suite')  # FIXME: Example?
    445     X('-g', 'If specified, the filterspec by -f is not exclusive, i.e., if a test module does not match the filterspec (testclass.testmethod), the whole module is still admitted to the test suite')
    446     X('-l', "Don't skip long running tests")
    447     group.add_argument('-p', metavar='pattern', help='Specify a regexp filename pattern for inclusion in the test suite')
    448     group.add_argument('-X', metavar='directory', help="Exclude a directory from consideration for test discovery. -X types => if 'types' appear in the pathname components of a potential testfile, it will be ignored")
    449     group.add_argument('-G', '--category', metavar='category', action='append', dest='categoriesList', help=textwrap.dedent('''Specify categories of test cases of interest. Can be specified more than once.'''))
    450     group.add_argument('--skip-category', metavar='category', action='append', dest='skipCategories', help=textwrap.dedent('''Specify categories of test cases to skip. Takes precedence over -G. Can be specified more than once.'''))
    451 
    452     # Configuration options
    453     group = parser.add_argument_group('Configuration options')
    454     group.add_argument('-c', metavar='config-file', help='Read a config file specified after this option')  # FIXME: additional doc.
    455     group.add_argument('--framework', metavar='framework-path', help='The path to LLDB.framework')
    456     group.add_argument('--executable', metavar='executable-path', help='The path to the lldb executable')
    457     group.add_argument('--libcxx', metavar='directory', help='The path to custom libc++ library')
    458     group.add_argument('-e', metavar='benchmark-exe', help='Specify the full path of an executable used for benchmark purposes (see also: -x)')
    459     group.add_argument('-k', metavar='command', action='append', help="Specify a runhook, which is an lldb command to be executed by the debugger; The option can occur multiple times. The commands are executed one after the other to bring the debugger to a desired state, so that, for example, further benchmarking can be done")
    460     group.add_argument('-R', metavar='dir', help='Specify a directory to relocate the tests and their intermediate files to. BE WARNED THAT the directory, if exists, will be deleted before running this test driver. No cleanup of intermediate test files is performed in this case')
    461     group.add_argument('-r', metavar='dir', help="Similar to '-R', except that the directory must not exist before running this test driver")
    462     group.add_argument('-s', metavar='name', help='Specify the name of the dir created to store the session files of tests with errored or failed status. If not specified, the test driver uses the timestamp as the session dir name')
    463     group.add_argument('-x', metavar='breakpoint-spec', help='Specify the breakpoint specification for the benchmark executable')
    464     group.add_argument('-y', type=int, metavar='count', help="Specify the iteration count used to collect our benchmarks. An example is the number of times to do 'thread step-over' to measure stepping speed.")
    465     group.add_argument('-#', type=int, metavar='sharp', dest='sharp', help='Repeat the test suite for a specified number of times')
    466 
    467     # Test-suite behaviour
    468     group = parser.add_argument_group('Runtime behaviour options')
    469     X('-d', 'Delay startup for 10 seconds (in order for the debugger to attach)')
    470     X('-F', 'Fail fast. Stop the test suite on the first error/failure')
    471     X('-i', "Ignore (don't bailout) if 'lldb.py' module cannot be located in the build tree relative to this script; use PYTHONPATH to locate the module")
    472     X('-n', "Don't print the headers like build dir, lldb version, and svn info at all")
    473     X('-P', "Use the graphic progress bar.")
    474     X('-q', "Don't print extra output from this script.")
    475     X('-S', "Skip the build and cleanup while running the test. Use this option with care as you would need to build the inferior(s) by hand and build the executable(s) with the correct name(s). This can be used with '-# n' to stress test certain test cases for n number of times")
    476     X('-t', 'Turn on tracing of lldb command and other detailed test executions')
    477     group.add_argument('-u', dest='unset_env_varnames', metavar='variable', action='append', help='Specify an environment variable to unset before running the test cases. e.g., -u DYLD_INSERT_LIBRARIES -u MallocScribble')
    478     X('-v', 'Do verbose mode of unittest framework (print out each test case invocation)')
    479     X('-w', 'Insert some wait time (currently 0.5 sec) between consecutive test cases')
    480     X('-T', 'Obtain and dump svn information for this checkout of LLDB (off by default)')
    481 
    482     # Remove the reference to our helper function
    483     del X
    484 
    485     group = parser.add_argument_group('Test directories')
    486     group.add_argument('args', metavar='test-dir', nargs='*', help='Specify a list of directory names to search for test modules named after Test*.py (test discovery). If empty, search from the current working directory instead.')
    487 
    488     args = parse_args(parser)
    489     platform_system = platform.system()
    490     platform_machine = platform.machine()
    491     
    492     if args.unset_env_varnames:
    493         for env_var in args.unset_env_varnames:
    494             if env_var in os.environ:
    495                 # From Python Doc: When unsetenv() is supported, deletion of items in os.environ
    496                 # is automatically translated into a corresponding call to unsetenv().
    497                 del os.environ[env_var]
    498                 #os.unsetenv(env_var)
    499     
    500     # only print the args if being verbose (and parsable is off)
    501     if args.v and not args.q:
    502         print sys.argv
    503 
    504     if args.h:
    505         do_help = True
    506 
    507     if args.archs:
    508         archs = args.archs
    509     else:
    510         if platform_system == 'Darwin' and platform_machine == 'x86_64':
    511             archs = ['x86_64', 'i386']
    512         else:
    513             archs = [platform_machine]
    514 
    515     if args.categoriesList:
    516         categoriesList = set(validate_categories(args.categoriesList))
    517         useCategories = True
    518     else:
    519         categoriesList = []
    520 
    521     if args.skipCategories:
    522         skipCategories = validate_categories(args.skipCategories)
    523 
    524     if args.compilers:
    525         compilers = args.compilers
    526     else:
    527         compilers = ['clang']
    528 
    529     if args.D:
    530         dumpSysPath = True
    531 
    532     if args.E:
    533         cflags_extras = args.E
    534         os.environ['CFLAGS_EXTRAS'] = cflags_extras
    535 
    536     # argparse makes sure we have correct options
    537     if args.N == 'dwarf':
    538         dont_do_dwarf_test = True
    539     elif args.N == 'dsym':
    540         dont_do_dsym_test = True
    541 
    542     if args.a:
    543         dont_do_python_api_test = True
    544 
    545     if args.plus_a:
    546         if dont_do_python_api_test:
    547             print "Warning: -a and +a can't both be specified! Using only -a"
    548         else:
    549             just_do_python_api_test = True
    550 
    551     if args.plus_b:
    552         just_do_benchmarks_test = True
    553 
    554     if args.b:
    555         if args.b.startswith('-'):
    556             usage(parser)
    557         blacklistFile = args.b
    558         if not os.path.isfile(blacklistFile):
    559             print 'Blacklist file:', blacklistFile, 'does not exist!'
    560             usage(parser)
    561         # Now read the blacklist contents and assign it to blacklist.
    562         execfile(blacklistFile, globals(), blacklistConfig)
    563         blacklist = blacklistConfig.get('blacklist')
    564 
    565     if args.c:
    566         if args.c.startswith('-'):
    567             usage(parser)
    568         configFile = args.c
    569         if not os.path.isfile(configFile):
    570             print 'Config file:', configFile, 'does not exist!'
    571             usage(parser)
    572 
    573     if args.d:
    574         delay = True
    575 
    576     if args.e:
    577         if args.e.startswith('-'):
    578             usage(parser)
    579         bmExecutable = args.e
    580         if not is_exe(bmExecutable):
    581             usage(parser)
    582 
    583     if args.F:
    584         failfast = True
    585 
    586     if args.f:
    587         if any([x.startswith('-') for x in args.f]):
    588             usage(parser)
    589         filters.extend(args.f)
    590 
    591     if args.g:
    592         fs4all = False
    593 
    594     if args.i:
    595         ignore = True
    596 
    597     if args.k:
    598         runHooks.extend(args.k)
    599 
    600     if args.l:
    601         skip_long_running_test = False
    602 
    603     if args.framework:
    604         lldbFrameworkPath = args.framework
    605 
    606     if args.executable:
    607         lldbExecutablePath = args.executable
    608 
    609     if args.libcxx:
    610         os.environ["LIBCXX_PATH"] = args.libcxx
    611 
    612     if args.n:
    613         noHeaders = True
    614 
    615     if args.p:
    616         if args.p.startswith('-'):
    617             usage(parser)
    618         regexp = args.p
    619 
    620     if args.q:
    621         noHeaders = True
    622         parsable = True
    623 
    624     if args.P:
    625         progress_bar = True
    626         verbose = 0
    627 
    628     if args.R:
    629         if args.R.startswith('-'):
    630             usage(parser)
    631         rdir = os.path.abspath(args.R)
    632         if os.path.exists(rdir):
    633             import shutil
    634             print 'Removing tree:', rdir
    635             shutil.rmtree(rdir)
    636 
    637     if args.r:
    638         if args.r.startswith('-'):
    639             usage(parser)
    640         rdir = os.path.abspath(args.r)
    641         if os.path.exists(rdir):
    642             print 'Relocated directory:', rdir, 'must not exist!'
    643             usage(parser)
    644 
    645     if args.S:
    646         skip_build_and_cleanup = True
    647 
    648     if args.s:
    649         if args.s.startswith('-'):
    650             usage(parser)
    651         sdir_name = args.s
    652 
    653     if args.t:
    654         os.environ['LLDB_COMMAND_TRACE'] = 'YES'
    655 
    656     if args.T:
    657         svn_silent = False
    658 
    659     if args.v:
    660         verbose = 2
    661 
    662     if args.w:
    663         os.environ['LLDB_WAIT_BETWEEN_TEST_CASES'] = 'YES'
    664 
    665     if args.X:
    666         if args.X.startswith('-'):
    667             usage(parser)
    668         excluded.add(args.X)
    669 
    670     if args.x:
    671         if args.x.startswith('-'):
    672             usage(parser)
    673         bmBreakpointSpec = args.x
    674 
    675     # argparse makes sure we have a number
    676     if args.y:
    677         bmIterationCount = args.y
    678 
    679     # argparse makes sure we have a number
    680     if args.sharp:
    681         count = args.sharp
    682 
    683     if do_help == True:
    684         usage(parser)
    685 
    686     # Do not specify both '-a' and '+a' at the same time.
    687     if dont_do_python_api_test and just_do_python_api_test:
    688         usage(parser)
    689 
    690     # Gather all the dirs passed on the command line.
    691     if len(args.args) > 0:
    692         testdirs = map(os.path.abspath, args.args)
    693 
    694     # If '-r dir' is specified, the tests should be run under the relocated
    695     # directory.  Let's copy the testdirs over.
    696     if rdir:
    697         from shutil import copytree, ignore_patterns
    698 
    699         tmpdirs = []
    700         orig_testdirs = testdirs[:]
    701         for srcdir in testdirs:
    702             # For example, /Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/hello_watchpoint
    703             # shall be split into ['/Volumes/data/lldb/svn/ToT/', 'functionalities/watchpoint/hello_watchpoint'].
    704             # Utilize the relative path to the 'test' directory to make our destination dir path.
    705             if ("test" + os.sep) in srcdir:
    706                 to_split_on = "test" + os.sep
    707             else:
    708                 to_split_on = "test"
    709             dstdir = os.path.join(rdir, srcdir.split(to_split_on)[1])
    710             dstdir = dstdir.rstrip(os.sep)
    711             # Don't copy the *.pyc and .svn stuffs.
    712             copytree(srcdir, dstdir, ignore=ignore_patterns('*.pyc', '.svn'))
    713             tmpdirs.append(dstdir)
    714 
    715         # This will be our modified testdirs.
    716         testdirs = tmpdirs
    717 
    718         # With '-r dir' specified, there's no cleanup of intermediate test files.
    719         os.environ["LLDB_DO_CLEANUP"] = 'NO'
    720 
    721         # If the original testdirs is ['test'], the make directory has already been copied
    722         # recursively and is contained within the rdir/test dir.  For anything
    723         # else, we would need to copy over the make directory and its contents,
    724         # so that, os.listdir(rdir) looks like, for example:
    725         #
    726         #     array_types conditional_break make
    727         #
    728         # where the make directory contains the Makefile.rules file.
    729         if len(testdirs) != 1 or os.path.basename(orig_testdirs[0]) != 'test':
    730             scriptdir = os.path.dirname(__file__)
    731             # Don't copy the .svn stuffs.
    732             copytree(os.path.join(scriptdir, 'make'), os.path.join(rdir, 'make'),
    733                      ignore=ignore_patterns('.svn'))
    734 
    735     #print "testdirs:", testdirs
    736 
    737     # Source the configFile if specified.
    738     # The side effect, if any, will be felt from this point on.  An example
    739     # config file may be these simple two lines:
    740     #
    741     # sys.stderr = open("/tmp/lldbtest-stderr", "w")
    742     # sys.stdout = open("/tmp/lldbtest-stdout", "w")
    743     #
    744     # which will reassign the two file objects to sys.stderr and sys.stdout,
    745     # respectively.
    746     #
    747     # See also lldb-trunk/examples/test/usage-config.
    748     global config, pre_flight, post_flight
    749     if configFile:
    750         # Pass config (a dictionary) as the locals namespace for side-effect.
    751         execfile(configFile, globals(), config)
    752         print "config:", config
    753         if "pre_flight" in config:
    754             pre_flight = config["pre_flight"]
    755             if not callable(pre_flight):
    756                 print "fatal error: pre_flight is not callable, exiting."
    757                 sys.exit(1)
    758         if "post_flight" in config:
    759             post_flight = config["post_flight"]
    760             if not callable(post_flight):
    761                 print "fatal error: post_flight is not callable, exiting."
    762                 sys.exit(1)
    763         #print "sys.stderr:", sys.stderr
    764         #print "sys.stdout:", sys.stdout
    765 
    766 
    767 def setupSysPath():
    768     """
    769     Add LLDB.framework/Resources/Python to the search paths for modules.
    770     As a side effect, we also discover the 'lldb' executable and export it here.
    771     """
    772 
    773     global rdir
    774     global testdirs
    775     global dumpSysPath
    776     global noHeaders
    777     global svn_info
    778     global svn_silent
    779     global lldbFrameworkPath
    780     global lldbExecutablePath
    781 
    782     # Get the directory containing the current script.
    783     if ("DOTEST_PROFILE" in os.environ or "DOTEST_PDB" in os.environ) and "DOTEST_SCRIPT_DIR" in os.environ:
    784         scriptPath = os.environ["DOTEST_SCRIPT_DIR"]
    785     else:
    786         scriptPath = sys.path[0]
    787     if not scriptPath.endswith('test'):
    788         print "This script expects to reside in lldb's test directory."
    789         sys.exit(-1)
    790 
    791     if rdir:
    792         # Set up the LLDB_TEST environment variable appropriately, so that the
    793         # individual tests can be located relatively.
    794         #
    795         # See also lldbtest.TestBase.setUpClass(cls).
    796         if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
    797             os.environ["LLDB_TEST"] = os.path.join(rdir, 'test')
    798         else:
    799             os.environ["LLDB_TEST"] = rdir
    800     else:
    801         os.environ["LLDB_TEST"] = scriptPath
    802 
    803     # Set up the LLDB_SRC environment variable, so that the tests can locate
    804     # the LLDB source code.
    805     os.environ["LLDB_SRC"] = os.path.join(sys.path[0], os.pardir)
    806 
    807     pluginPath = os.path.join(scriptPath, 'plugins')
    808     pexpectPath = os.path.join(scriptPath, 'pexpect-2.4')
    809 
    810     # Append script dir, plugin dir, and pexpect dir to the sys.path.
    811     sys.path.append(scriptPath)
    812     sys.path.append(pluginPath)
    813     sys.path.append(pexpectPath)
    814 
    815     # This is our base name component.
    816     base = os.path.abspath(os.path.join(scriptPath, os.pardir))
    817 
    818     # These are for xcode build directories.
    819     xcode3_build_dir = ['build']
    820     xcode4_build_dir = ['build', 'lldb', 'Build', 'Products']
    821     dbg = ['Debug']
    822     dbc = ['DebugClang']
    823     rel = ['Release']
    824     bai = ['BuildAndIntegration']
    825     python_resource_dir = ['LLDB.framework', 'Resources', 'Python']
    826 
    827     # Some of the tests can invoke the 'lldb' command directly.
    828     # We'll try to locate the appropriate executable right here.
    829 
    830     lldbExec = None
    831     if lldbExecutablePath:
    832         if is_exe(lldbExecutablePath):
    833             lldbExec = lldbExecutablePath
    834             lldbHere = lldbExec
    835         else:
    836             print lldbExecutablePath + " is not an executable"
    837             sys.exit(-1)
    838     else:
    839         # First, you can define an environment variable LLDB_EXEC specifying the
    840         # full pathname of the lldb executable.
    841         if "LLDB_EXEC" in os.environ and is_exe(os.environ["LLDB_EXEC"]):
    842             lldbExec = os.environ["LLDB_EXEC"]
    843         else:
    844             lldbExec = None
    845     
    846         executable = ['lldb']
    847         dbgExec  = os.path.join(base, *(xcode3_build_dir + dbg + executable))
    848         dbgExec2 = os.path.join(base, *(xcode4_build_dir + dbg + executable))
    849         dbcExec  = os.path.join(base, *(xcode3_build_dir + dbc + executable))
    850         dbcExec2 = os.path.join(base, *(xcode4_build_dir + dbc + executable))
    851         relExec  = os.path.join(base, *(xcode3_build_dir + rel + executable))
    852         relExec2 = os.path.join(base, *(xcode4_build_dir + rel + executable))
    853         baiExec  = os.path.join(base, *(xcode3_build_dir + bai + executable))
    854         baiExec2 = os.path.join(base, *(xcode4_build_dir + bai + executable))
    855     
    856         # The 'lldb' executable built here in the source tree.
    857         lldbHere = None
    858         if is_exe(dbgExec):
    859             lldbHere = dbgExec
    860         elif is_exe(dbgExec2):
    861             lldbHere = dbgExec2
    862         elif is_exe(dbcExec):
    863             lldbHere = dbcExec
    864         elif is_exe(dbcExec2):
    865             lldbHere = dbcExec2
    866         elif is_exe(relExec):
    867             lldbHere = relExec
    868         elif is_exe(relExec2):
    869             lldbHere = relExec2
    870         elif is_exe(baiExec):
    871             lldbHere = baiExec
    872         elif is_exe(baiExec2):
    873             lldbHere = baiExec2
    874         elif lldbExec:
    875             lldbHere = lldbExec
    876 
    877         # One last chance to locate the 'lldb' executable.
    878         if not lldbExec:
    879             lldbExec = which('lldb')
    880             if lldbHere and not lldbExec:
    881                 lldbExec = lldbHere
    882             if lldbExec and not lldbHere:
    883                 lldbHere = lldbExec
    884     
    885     if lldbHere:
    886         os.environ["LLDB_HERE"] = lldbHere
    887         os.environ["LLDB_LIB_DIR"] = os.path.split(lldbHere)[0]
    888         if not noHeaders:
    889             print "LLDB library dir:", os.environ["LLDB_LIB_DIR"]
    890             os.system('%s -v' % lldbHere)
    891 
    892     if not lldbExec:
    893         print "The 'lldb' executable cannot be located.  Some of the tests may not be run as a result."
    894     else:
    895         os.environ["LLDB_EXEC"] = lldbExec
    896         #print "The 'lldb' from PATH env variable", lldbExec
    897 
    898     # Skip printing svn/git information when running in parsable (lit-test compatibility) mode
    899     if not svn_silent and not parsable:
    900         if os.path.isdir(os.path.join(base, '.svn')) and which("svn") is not None:
    901             pipe = subprocess.Popen([which("svn"), "info", base], stdout = subprocess.PIPE)
    902             svn_info = pipe.stdout.read()
    903         elif os.path.isdir(os.path.join(base, '.git')) and which("git") is not None:
    904             pipe = subprocess.Popen([which("git"), "svn", "info", base], stdout = subprocess.PIPE)
    905             svn_info = pipe.stdout.read()
    906         if not noHeaders:
    907             print svn_info
    908 
    909     global ignore
    910 
    911     lldbPath = None
    912     if lldbFrameworkPath:
    913         candidatePath = os.path.join(lldbFrameworkPath, 'Resources', 'Python')
    914         if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')):
    915             lldbPath = candidatePath
    916         if not lldbPath:
    917             print 'Resources/Python/lldb/__init__.py was not found in ' + lldbFrameworkPath
    918             sys.exit(-1)
    919     else:
    920         # The '-i' option is used to skip looking for lldb.py in the build tree.
    921         if ignore:
    922             return
    923         
    924         # If our lldb supports the -P option, use it to find the python path:
    925         init_in_python_dir = 'lldb/__init__.py'
    926         import pexpect
    927         lldb_dash_p_result = None
    928 
    929         if lldbHere:
    930             lldb_dash_p_result = pexpect.run("%s -P"%(lldbHere))
    931         elif lldbExec:
    932             lldb_dash_p_result = pexpect.run("%s -P"%(lldbExec))
    933 
    934         if lldb_dash_p_result and not lldb_dash_p_result.startswith(("<", "lldb: invalid option:")):
    935             lines = lldb_dash_p_result.splitlines()
    936             if len(lines) == 1 and os.path.isfile(os.path.join(lines[0], init_in_python_dir)):
    937                 lldbPath = lines[0]
    938                 if "linux" in sys.platform:
    939                     os.environ['LLDB_LIB_DIR'] = os.path.join(lldbPath, '..', '..')
    940         
    941         if not lldbPath: 
    942             dbgPath  = os.path.join(base, *(xcode3_build_dir + dbg + python_resource_dir))
    943             dbgPath2 = os.path.join(base, *(xcode4_build_dir + dbg + python_resource_dir))
    944             dbcPath  = os.path.join(base, *(xcode3_build_dir + dbc + python_resource_dir))
    945             dbcPath2 = os.path.join(base, *(xcode4_build_dir + dbc + python_resource_dir))
    946             relPath  = os.path.join(base, *(xcode3_build_dir + rel + python_resource_dir))
    947             relPath2 = os.path.join(base, *(xcode4_build_dir + rel + python_resource_dir))
    948             baiPath  = os.path.join(base, *(xcode3_build_dir + bai + python_resource_dir))
    949             baiPath2 = os.path.join(base, *(xcode4_build_dir + bai + python_resource_dir))
    950     
    951             if os.path.isfile(os.path.join(dbgPath, init_in_python_dir)):
    952                 lldbPath = dbgPath
    953             elif os.path.isfile(os.path.join(dbgPath2, init_in_python_dir)):
    954                 lldbPath = dbgPath2
    955             elif os.path.isfile(os.path.join(dbcPath, init_in_python_dir)):
    956                 lldbPath = dbcPath
    957             elif os.path.isfile(os.path.join(dbcPath2, init_in_python_dir)):
    958                 lldbPath = dbcPath2
    959             elif os.path.isfile(os.path.join(relPath, init_in_python_dir)):
    960                 lldbPath = relPath
    961             elif os.path.isfile(os.path.join(relPath2, init_in_python_dir)):
    962                 lldbPath = relPath2
    963             elif os.path.isfile(os.path.join(baiPath, init_in_python_dir)):
    964                 lldbPath = baiPath
    965             elif os.path.isfile(os.path.join(baiPath2, init_in_python_dir)):
    966                 lldbPath = baiPath2
    967 
    968         if not lldbPath:
    969             print 'This script requires lldb.py to be in either ' + dbgPath + ',',
    970             print relPath + ', or ' + baiPath
    971             sys.exit(-1)
    972 
    973     # Some of the code that uses this path assumes it hasn't resolved the Versions... link.  
    974     # If the path we've constructed looks like that, then we'll strip out the Versions/A part.
    975     (before, frameWithVersion, after) = lldbPath.rpartition("LLDB.framework/Versions/A")
    976     if frameWithVersion != "" :
    977         lldbPath = before + "LLDB.framework" + after
    978 
    979     lldbPath = os.path.abspath(lldbPath)
    980 
    981     # If tests need to find LLDB_FRAMEWORK, now they can do it
    982     os.environ["LLDB_FRAMEWORK"] = os.path.dirname(os.path.dirname(lldbPath))
    983 
    984     # This is to locate the lldb.py module.  Insert it right after sys.path[0].
    985     sys.path[1:1] = [lldbPath]
    986     if dumpSysPath:
    987         print "sys.path:", sys.path
    988 
    989 
    990 def doDelay(delta):
    991     """Delaying startup for delta-seconds to facilitate debugger attachment."""
    992     def alarm_handler(*args):
    993         raise Exception("timeout")
    994 
    995     signal.signal(signal.SIGALRM, alarm_handler)
    996     signal.alarm(delta)
    997     sys.stdout.write("pid=%d\n" % os.getpid())
    998     sys.stdout.write("Enter RET to proceed (or timeout after %d seconds):" %
    999                      delta)
   1000     sys.stdout.flush()
   1001     try:
   1002         text = sys.stdin.readline()
   1003     except:
   1004         text = ""
   1005     signal.alarm(0)
   1006     sys.stdout.write("proceeding...\n")
   1007     pass
   1008 
   1009 
   1010 def visit(prefix, dir, names):
   1011     """Visitor function for os.path.walk(path, visit, arg)."""
   1012 
   1013     global suite
   1014     global regexp
   1015     global filters
   1016     global fs4all
   1017     global excluded
   1018 
   1019     if set(dir.split(os.sep)).intersection(excluded):
   1020         #print "Detected an excluded dir component: %s" % dir
   1021         return
   1022 
   1023     for name in names:
   1024         if os.path.isdir(os.path.join(dir, name)):
   1025             continue
   1026 
   1027         if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
   1028             # Try to match the regexp pattern, if specified.
   1029             if regexp:
   1030                 import re
   1031                 if re.search(regexp, name):
   1032                     #print "Filename: '%s' matches pattern: '%s'" % (name, regexp)
   1033                     pass
   1034                 else:
   1035                     #print "Filename: '%s' does not match pattern: '%s'" % (name, regexp)
   1036                     continue
   1037 
   1038             # We found a match for our test.  Add it to the suite.
   1039 
   1040             # Update the sys.path first.
   1041             if not sys.path.count(dir):
   1042                 sys.path.insert(0, dir)
   1043             base = os.path.splitext(name)[0]
   1044 
   1045             # Thoroughly check the filterspec against the base module and admit
   1046             # the (base, filterspec) combination only when it makes sense.
   1047             filterspec = None
   1048             for filterspec in filters:
   1049                 # Optimistically set the flag to True.
   1050                 filtered = True
   1051                 module = __import__(base)
   1052                 parts = filterspec.split('.')
   1053                 obj = module
   1054                 for part in parts:
   1055                     try:
   1056                         parent, obj = obj, getattr(obj, part)
   1057                     except AttributeError:
   1058                         # The filterspec has failed.
   1059                         filtered = False
   1060                         break
   1061 
   1062                 # If filtered, we have a good filterspec.  Add it.
   1063                 if filtered:
   1064                     #print "adding filter spec %s to module %s" % (filterspec, module)
   1065                     suite.addTests(
   1066                         unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
   1067                     continue
   1068 
   1069             # Forgo this module if the (base, filterspec) combo is invalid
   1070             # and no '-g' option is specified
   1071             if filters and fs4all and not filtered:
   1072                 continue
   1073 
   1074             # Add either the filtered test case(s) (which is done before) or the entire test class.
   1075             if not filterspec or not filtered:
   1076                 # A simple case of just the module name.  Also the failover case
   1077                 # from the filterspec branch when the (base, filterspec) combo
   1078                 # doesn't make sense.
   1079                 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
   1080 
   1081 
   1082 def lldbLoggings():
   1083     """Check and do lldb loggings if necessary."""
   1084 
   1085     # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
   1086     # defined.  Use ${LLDB_LOG} to specify the log file.
   1087     ci = lldb.DBG.GetCommandInterpreter()
   1088     res = lldb.SBCommandReturnObject()
   1089     if ("LLDB_LOG" in os.environ):
   1090         if ("LLDB_LOG_OPTION" in os.environ):
   1091             lldb_log_option = os.environ["LLDB_LOG_OPTION"]
   1092         else:
   1093             lldb_log_option = "event process expr state api"
   1094         ci.HandleCommand(
   1095             "log enable -n -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
   1096             res)
   1097         if not res.Succeeded():
   1098             raise Exception('log enable failed (check LLDB_LOG env variable.')
   1099     # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
   1100     # Use ${GDB_REMOTE_LOG} to specify the log file.
   1101     if ("GDB_REMOTE_LOG" in os.environ):
   1102         if ("GDB_REMOTE_LOG_OPTION" in os.environ):
   1103             gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
   1104         else:
   1105             gdb_remote_log_option = "packets process"
   1106         ci.HandleCommand(
   1107             "log enable -n -f " + os.environ["GDB_REMOTE_LOG"] + " gdb-remote "
   1108             + gdb_remote_log_option,
   1109             res)
   1110         if not res.Succeeded():
   1111             raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
   1112 
   1113 def getMyCommandLine():
   1114     ps = subprocess.Popen([which('ps'), '-o', "command=CMD", str(os.getpid())], stdout=subprocess.PIPE).communicate()[0]
   1115     lines = ps.split('\n')
   1116     cmd_line = lines[1]
   1117     return cmd_line
   1118 
   1119 # ======================================== #
   1120 #                                          #
   1121 # Execution of the test driver starts here #
   1122 #                                          #
   1123 # ======================================== #
   1124 
   1125 def checkDsymForUUIDIsNotOn():
   1126     cmd = ["defaults", "read", "com.apple.DebugSymbols"]
   1127     pipe = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
   1128     cmd_output = pipe.stdout.read()
   1129     if cmd_output and "DBGFileMappedPaths = " in cmd_output:
   1130         print "%s =>" % ' '.join(cmd)
   1131         print cmd_output
   1132         print "Disable automatic lookup and caching of dSYMs before running the test suite!"
   1133         print "Exiting..."
   1134         sys.exit(0)
   1135 
   1136 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults
   1137 # does not exist before proceeding to running the test suite.
   1138 if sys.platform.startswith("darwin"):
   1139     checkDsymForUUIDIsNotOn()
   1140 
   1141 #
   1142 # Start the actions by first parsing the options while setting up the test
   1143 # directories, followed by setting up the search paths for lldb utilities;
   1144 # then, we walk the directory trees and collect the tests into our test suite.
   1145 #
   1146 parseOptionsAndInitTestdirs()
   1147 setupSysPath()
   1148 
   1149 #
   1150 # If '-d' is specified, do a delay of 10 seconds for the debugger to attach.
   1151 #
   1152 if delay:
   1153     doDelay(10)
   1154 
   1155 #
   1156 # If '-l' is specified, do not skip the long running tests.
   1157 if not skip_long_running_test:
   1158     os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
   1159 
   1160 #
   1161 # Walk through the testdirs while collecting tests.
   1162 #
   1163 for testdir in testdirs:
   1164     os.path.walk(testdir, visit, 'Test')
   1165 
   1166 #
   1167 # Now that we have loaded all the test cases, run the whole test suite.
   1168 #
   1169 
   1170 # For the time being, let's bracket the test runner within the
   1171 # lldb.SBDebugger.Initialize()/Terminate() pair.
   1172 import lldb, atexit
   1173 # Update: the act of importing lldb now executes lldb.SBDebugger.Initialize(),
   1174 # there's no need to call it a second time.
   1175 #lldb.SBDebugger.Initialize()
   1176 atexit.register(lambda: lldb.SBDebugger.Terminate())
   1177 
   1178 # Create a singleton SBDebugger in the lldb namespace.
   1179 lldb.DBG = lldb.SBDebugger.Create()
   1180 
   1181 # Put the blacklist in the lldb namespace, to be used by lldb.TestBase.
   1182 lldb.blacklist = blacklist
   1183 
   1184 # The pre_flight and post_flight come from reading a config file.
   1185 lldb.pre_flight = pre_flight
   1186 lldb.post_flight = post_flight
   1187 def getsource_if_available(obj):
   1188     """
   1189     Return the text of the source code for an object if available.  Otherwise,
   1190     a print representation is returned.
   1191     """
   1192     import inspect
   1193     try:
   1194         return inspect.getsource(obj)
   1195     except:
   1196         return repr(obj)
   1197 
   1198 if not noHeaders:
   1199     print "lldb.pre_flight:", getsource_if_available(lldb.pre_flight)
   1200     print "lldb.post_flight:", getsource_if_available(lldb.post_flight)
   1201 
   1202 # Put all these test decorators in the lldb namespace.
   1203 lldb.dont_do_python_api_test = dont_do_python_api_test
   1204 lldb.just_do_python_api_test = just_do_python_api_test
   1205 lldb.just_do_benchmarks_test = just_do_benchmarks_test
   1206 lldb.dont_do_dsym_test = dont_do_dsym_test
   1207 lldb.dont_do_dwarf_test = dont_do_dwarf_test
   1208 
   1209 # Do we need to skip build and cleanup?
   1210 lldb.skip_build_and_cleanup = skip_build_and_cleanup
   1211 
   1212 # Put bmExecutable, bmBreakpointSpec, and bmIterationCount into the lldb namespace, too.
   1213 lldb.bmExecutable = bmExecutable
   1214 lldb.bmBreakpointSpec = bmBreakpointSpec
   1215 lldb.bmIterationCount = bmIterationCount
   1216 
   1217 # And don't forget the runHooks!
   1218 lldb.runHooks = runHooks
   1219 
   1220 # Turn on lldb loggings if necessary.
   1221 lldbLoggings()
   1222 
   1223 # Install the control-c handler.
   1224 unittest2.signals.installHandler()
   1225 
   1226 # If sdir_name is not specified through the '-s sdir_name' option, get a
   1227 # timestamp string and export it as LLDB_SESSION_DIR environment var.  This will
   1228 # be used when/if we want to dump the session info of individual test cases
   1229 # later on.
   1230 #
   1231 # See also TestBase.dumpSessionInfo() in lldbtest.py.
   1232 import datetime
   1233 # The windows platforms don't like ':' in the pathname.
   1234 timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
   1235 if not sdir_name:
   1236     sdir_name = timestamp_started
   1237 os.environ["LLDB_SESSION_DIRNAME"] = os.path.join(os.getcwd(), sdir_name)
   1238 
   1239 if not noHeaders:
   1240     sys.stderr.write("\nSession logs for test failures/errors/unexpected successes"
   1241                      " will go into directory '%s'\n" % sdir_name)
   1242     sys.stderr.write("Command invoked: %s\n" % getMyCommandLine())
   1243 
   1244 if not os.path.isdir(sdir_name):
   1245     os.mkdir(sdir_name)
   1246 where_to_save_session = os.getcwd()
   1247 fname = os.path.join(sdir_name, "TestStarted")
   1248 with open(fname, "w") as f:
   1249     print >> f, "Test started at: %s\n" % timestamp_started
   1250     print >> f, svn_info
   1251     print >> f, "Command invoked: %s\n" % getMyCommandLine()
   1252 
   1253 #
   1254 # Invoke the default TextTestRunner to run the test suite, possibly iterating
   1255 # over different configurations.
   1256 #
   1257 
   1258 iterArchs = False
   1259 iterCompilers = False
   1260 
   1261 if not archs and "archs" in config:
   1262     archs = config["archs"]
   1263 
   1264 if isinstance(archs, list) and len(archs) >= 1:
   1265     iterArchs = True
   1266 
   1267 if not compilers and "compilers" in config:
   1268     compilers = config["compilers"]
   1269 
   1270 #
   1271 # Add some intervention here to sanity check that the compilers requested are sane.
   1272 # If found not to be an executable program, the invalid one is dropped from the list.
   1273 for i in range(len(compilers)):
   1274     c = compilers[i]
   1275     if which(c):
   1276         continue
   1277     else:
   1278         if sys.platform.startswith("darwin"):
   1279             pipe = subprocess.Popen(['xcrun', '-find', c], stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
   1280             cmd_output = pipe.stdout.read()
   1281             if cmd_output:
   1282                 if "not found" in cmd_output:
   1283                     print "dropping %s from the compilers used" % c
   1284                     compilers.remove(i)
   1285                 else:
   1286                     compilers[i] = cmd_output.split('\n')[0]
   1287                     print "'xcrun -find %s' returning %s" % (c, compilers[i])
   1288 
   1289 if not parsable:
   1290     print "compilers=%s" % str(compilers)
   1291 
   1292 if not compilers or len(compilers) == 0:
   1293     print "No eligible compiler found, exiting."
   1294     sys.exit(1)
   1295 
   1296 if isinstance(compilers, list) and len(compilers) >= 1:
   1297     iterCompilers = True
   1298 
   1299 # Make a shallow copy of sys.path, we need to manipulate the search paths later.
   1300 # This is only necessary if we are relocated and with different configurations.
   1301 if rdir:
   1302     old_sys_path = sys.path[:]
   1303 # If we iterate on archs or compilers, there is a chance we want to split stderr/stdout.
   1304 if iterArchs or iterCompilers:
   1305     old_stderr = sys.stderr
   1306     old_stdout = sys.stdout
   1307     new_stderr = None
   1308     new_stdout = None
   1309 
   1310 # Iterating over all possible architecture and compiler combinations.
   1311 for ia in range(len(archs) if iterArchs else 1):
   1312     archConfig = ""
   1313     if iterArchs:
   1314         os.environ["ARCH"] = archs[ia]
   1315         archConfig = "arch=%s" % archs[ia]
   1316     for ic in range(len(compilers) if iterCompilers else 1):
   1317         if iterCompilers:
   1318             os.environ["CC"] = compilers[ic]
   1319             configString = "%s compiler=%s" % (archConfig, compilers[ic])
   1320         else:
   1321             configString = archConfig
   1322 
   1323         if iterArchs or iterCompilers:
   1324             # Translate ' ' to '-' for pathname component.
   1325             from string import maketrans
   1326             tbl = maketrans(' ', '-')
   1327             configPostfix = configString.translate(tbl)
   1328 
   1329             # Check whether we need to split stderr/stdout into configuration
   1330             # specific files.
   1331             if old_stderr.name != '<stderr>' and config.get('split_stderr'):
   1332                 if new_stderr:
   1333                     new_stderr.close()
   1334                 new_stderr = open("%s.%s" % (old_stderr.name, configPostfix), "w")
   1335                 sys.stderr = new_stderr
   1336             if old_stdout.name != '<stdout>' and config.get('split_stdout'):
   1337                 if new_stdout:
   1338                     new_stdout.close()
   1339                 new_stdout = open("%s.%s" % (old_stdout.name, configPostfix), "w")
   1340                 sys.stdout = new_stdout
   1341 
   1342             # If we specified a relocated directory to run the test suite, do
   1343             # the extra housekeeping to copy the testdirs to a configStringified
   1344             # directory and to update sys.path before invoking the test runner.
   1345             # The purpose is to separate the configuration-specific directories
   1346             # from each other.
   1347             if rdir:
   1348                 from shutil import copytree, rmtree, ignore_patterns
   1349 
   1350                 newrdir = "%s.%s" % (rdir, configPostfix)
   1351 
   1352                 # Copy the tree to a new directory with postfix name configPostfix.
   1353                 if os.path.exists(newrdir):
   1354                     rmtree(newrdir)
   1355                 copytree(rdir, newrdir, ignore=ignore_patterns('*.pyc', '*.o', '*.d'))
   1356 
   1357                 # Update the LLDB_TEST environment variable to reflect new top
   1358                 # level test directory.
   1359                 #
   1360                 # See also lldbtest.TestBase.setUpClass(cls).
   1361                 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
   1362                     os.environ["LLDB_TEST"] = os.path.join(newrdir, 'test')
   1363                 else:
   1364                     os.environ["LLDB_TEST"] = newrdir
   1365 
   1366                 # And update the Python search paths for modules.
   1367                 sys.path = [x.replace(rdir, newrdir, 1) for x in old_sys_path]
   1368 
   1369             # Output the configuration.
   1370             if not parsable:
   1371                 sys.stderr.write("\nConfiguration: " + configString + "\n")
   1372 
   1373         #print "sys.stderr name is", sys.stderr.name
   1374         #print "sys.stdout name is", sys.stdout.name
   1375 
   1376         # First, write out the number of collected test cases.
   1377         if not parsable:
   1378             sys.stderr.write(separator + "\n")
   1379             sys.stderr.write("Collected %d test%s\n\n"
   1380                              % (suite.countTestCases(),
   1381                                 suite.countTestCases() != 1 and "s" or ""))
   1382 
   1383         class LLDBTestResult(unittest2.TextTestResult):
   1384             """
   1385             Enforce a singleton pattern to allow introspection of test progress.
   1386 
   1387             Overwrite addError(), addFailure(), and addExpectedFailure() methods
   1388             to enable each test instance to track its failure/error status.  It
   1389             is used in the LLDB test framework to emit detailed trace messages
   1390             to a log file for easier human inspection of test failres/errors.
   1391             """
   1392             __singleton__ = None
   1393             __ignore_singleton__ = False
   1394 
   1395             @staticmethod
   1396             def getTerminalSize():
   1397                 import os
   1398                 env = os.environ
   1399                 def ioctl_GWINSZ(fd):
   1400                     try:
   1401                         import fcntl, termios, struct, os
   1402                         cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
   1403                     '1234'))
   1404                     except:
   1405                         return
   1406                     return cr
   1407                 cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
   1408                 if not cr:
   1409                     try:
   1410                         fd = os.open(os.ctermid(), os.O_RDONLY)
   1411                         cr = ioctl_GWINSZ(fd)
   1412                         os.close(fd)
   1413                     except:
   1414                         pass
   1415                 if not cr:
   1416                     cr = (env.get('LINES', 25), env.get('COLUMNS', 80))
   1417                 return int(cr[1]), int(cr[0])
   1418 
   1419             def __init__(self, *args):
   1420                 if not LLDBTestResult.__ignore_singleton__ and LLDBTestResult.__singleton__:
   1421                     raise Exception("LLDBTestResult instantiated more than once")
   1422                 super(LLDBTestResult, self).__init__(*args)
   1423                 LLDBTestResult.__singleton__ = self
   1424                 # Now put this singleton into the lldb module namespace.
   1425                 lldb.test_result = self
   1426                 # Computes the format string for displaying the counter.
   1427                 global suite
   1428                 counterWidth = len(str(suite.countTestCases()))
   1429                 self.fmt = "%" + str(counterWidth) + "d: "
   1430                 self.indentation = ' ' * (counterWidth + 2)
   1431                 # This counts from 1 .. suite.countTestCases().
   1432                 self.counter = 0
   1433                 (width, height) = LLDBTestResult.getTerminalSize()
   1434                 self.progressbar = None
   1435                 global progress_bar
   1436                 if width > 10 and not parsable and progress_bar:
   1437                     try:
   1438                         self.progressbar = progress.ProgressWithEvents(stdout=self.stream,start=0,end=suite.countTestCases(),width=width-10)
   1439                     except:
   1440                         self.progressbar = None
   1441 
   1442             def _config_string(self, test):
   1443               compiler = getattr(test, "getCompiler", None)
   1444               arch = getattr(test, "getArchitecture", None)
   1445               return "%s-%s" % (compiler() if compiler else "", arch() if arch else "")
   1446 
   1447             def _exc_info_to_string(self, err, test):
   1448                 """Overrides superclass TestResult's method in order to append
   1449                 our test config info string to the exception info string."""
   1450                 if hasattr(test, "getArchitecture") and hasattr(test, "getCompiler"):
   1451                     return '%sConfig=%s-%s' % (super(LLDBTestResult, self)._exc_info_to_string(err, test),
   1452                                                               test.getArchitecture(),
   1453                                                               test.getCompiler())
   1454                 else:
   1455                     return super(LLDBTestResult, self)._exc_info_to_string(err, test)
   1456 
   1457             def getDescription(self, test):
   1458                 doc_first_line = test.shortDescription()
   1459                 if self.descriptions and doc_first_line:
   1460                     return '\n'.join((str(test), self.indentation + doc_first_line))
   1461                 else:
   1462                     return str(test)
   1463 
   1464             def getCategoriesForTest(self,test):
   1465                 if hasattr(test,"_testMethodName"):
   1466                     test_method = getattr(test,"_testMethodName")
   1467                     test_method = getattr(test,test_method)
   1468                 else:
   1469                     test_method = None
   1470                 if test_method != None and hasattr(test_method,"getCategories"):
   1471                     test_categories = test_method.getCategories(test)
   1472                 elif hasattr(test,"getCategories"):
   1473                     test_categories = test.getCategories()
   1474                 elif inspect.ismethod(test) and test.__self__ != None and hasattr(test.__self__,"getCategories"):
   1475                     test_categories = test.__self__.getCategories()
   1476                 else:
   1477                     test_categories = []
   1478                 if test_categories == None:
   1479                     test_categories = []
   1480                 return test_categories
   1481 
   1482             def shouldSkipBecauseOfCategories(self,test):
   1483                 global useCategories
   1484                 import inspect
   1485                 if useCategories:
   1486                     global categoriesList
   1487                     test_categories = self.getCategoriesForTest(test)
   1488                     if len(test_categories) == 0 or len(categoriesList & set(test_categories)) == 0:
   1489                         return True
   1490 
   1491                 global skipCategories
   1492                 for category in skipCategories:
   1493                     if category in self.getCategoriesForTest(test):
   1494                         return True
   1495 
   1496                 return False
   1497 
   1498             def hardMarkAsSkipped(self,test):
   1499                 getattr(test, test._testMethodName).__func__.__unittest_skip__ = True
   1500                 getattr(test, test._testMethodName).__func__.__unittest_skip_why__ = "test case does not fall in any category of interest for this run"
   1501                 test.__class__.__unittest_skip__ = True
   1502                 test.__class__.__unittest_skip_why__ = "test case does not fall in any category of interest for this run"
   1503 
   1504             def startTest(self, test):
   1505                 if self.shouldSkipBecauseOfCategories(test):
   1506                     self.hardMarkAsSkipped(test)
   1507                 self.counter += 1
   1508                 if self.showAll:
   1509                     self.stream.write(self.fmt % self.counter)
   1510                 super(LLDBTestResult, self).startTest(test)
   1511 
   1512             def addSuccess(self, test):
   1513                 global parsable
   1514                 super(LLDBTestResult, self).addSuccess(test)
   1515                 if parsable:
   1516                     self.stream.write("PASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
   1517 
   1518             def addError(self, test, err):
   1519                 global sdir_has_content
   1520                 global parsable
   1521                 sdir_has_content = True
   1522                 super(LLDBTestResult, self).addError(test, err)
   1523                 method = getattr(test, "markError", None)
   1524                 if method:
   1525                     method()
   1526                 if parsable:
   1527                     self.stream.write("FAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
   1528 
   1529             def addFailure(self, test, err):
   1530                 global sdir_has_content
   1531                 global failuresPerCategory
   1532                 global parsable
   1533                 sdir_has_content = True
   1534                 super(LLDBTestResult, self).addFailure(test, err)
   1535                 method = getattr(test, "markFailure", None)
   1536                 if method:
   1537                     method()
   1538                 if parsable:
   1539                     self.stream.write("FAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
   1540                 if useCategories:
   1541                     test_categories = self.getCategoriesForTest(test)
   1542                     for category in test_categories:
   1543                         if category in failuresPerCategory:
   1544                             failuresPerCategory[category] = failuresPerCategory[category] + 1
   1545                         else:
   1546                             failuresPerCategory[category] = 1
   1547 
   1548             def addExpectedFailure(self, test, err, bugnumber):
   1549                 global sdir_has_content
   1550                 global parsable
   1551                 sdir_has_content = True
   1552                 super(LLDBTestResult, self).addExpectedFailure(test, err, bugnumber)
   1553                 method = getattr(test, "markExpectedFailure", None)
   1554                 if method:
   1555                     method(err, bugnumber)
   1556                 if parsable:
   1557                     self.stream.write("XFAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
   1558 
   1559             def addSkip(self, test, reason):
   1560                 global sdir_has_content
   1561                 global parsable
   1562                 sdir_has_content = True
   1563                 super(LLDBTestResult, self).addSkip(test, reason)
   1564                 method = getattr(test, "markSkippedTest", None)
   1565                 if method:
   1566                     method()
   1567                 if parsable:
   1568                     self.stream.write("UNSUPPORTED: LLDB (%s) :: %s (%s) \n" % (self._config_string(test), str(test), reason))
   1569 
   1570             def addUnexpectedSuccess(self, test, bugnumber):
   1571                 global sdir_has_content
   1572                 global parsable
   1573                 sdir_has_content = True
   1574                 super(LLDBTestResult, self).addUnexpectedSuccess(test, bugnumber)
   1575                 method = getattr(test, "markUnexpectedSuccess", None)
   1576                 if method:
   1577                     method(bugnumber)
   1578                 if parsable:
   1579                     self.stream.write("XPASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
   1580 
   1581         if parsable:
   1582             v = 0
   1583         elif progress_bar:
   1584             v = 1
   1585         else:
   1586             v = verbose
   1587 
   1588         # Invoke the test runner.
   1589         if count == 1:
   1590             result = unittest2.TextTestRunner(stream=sys.stderr,
   1591                                               verbosity=v,
   1592                                               failfast=failfast,
   1593                                               resultclass=LLDBTestResult).run(suite)
   1594         else:
   1595             # We are invoking the same test suite more than once.  In this case,
   1596             # mark __ignore_singleton__ flag as True so the signleton pattern is
   1597             # not enforced.
   1598             LLDBTestResult.__ignore_singleton__ = True
   1599             for i in range(count):
   1600                
   1601                 result = unittest2.TextTestRunner(stream=sys.stderr,
   1602                                                   verbosity=v,
   1603                                                   failfast=failfast,
   1604                                                   resultclass=LLDBTestResult).run(suite)
   1605 
   1606         failed = failed or not result.wasSuccessful()
   1607 
   1608 if sdir_has_content and not parsable:
   1609     sys.stderr.write("Session logs for test failures/errors/unexpected successes"
   1610                      " can be found in directory '%s'\n" % sdir_name)
   1611 
   1612 if useCategories and len(failuresPerCategory) > 0:
   1613     sys.stderr.write("Failures per category:\n")
   1614     for category in failuresPerCategory:
   1615         sys.stderr.write("%s - %d\n" % (category,failuresPerCategory[category]))
   1616 
   1617 os.chdir(where_to_save_session)
   1618 fname = os.path.join(sdir_name, "TestFinished")
   1619 with open(fname, "w") as f:
   1620     print >> f, "Test finished at: %s\n" % datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
   1621 
   1622 # Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
   1623 # This should not be necessary now.
   1624 if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
   1625     print "Terminating Test suite..."
   1626     subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
   1627 
   1628 # Exiting.
   1629 sys.exit(failed)
   1630