4 A simple testing framework for lldb using python's unit testing framework.
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.
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.
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.
20 for available options.
23 import os, signal, sys, time
28 """Returns true if fpath is an executable."""
29 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
32 """Returns the full path to a program; None otherwise."""
33 fpath, fname = os.path.split(program)
38 for path in os.environ["PATH"].split(os.pathsep):
39 exe_file = os.path.join(path, program)
44 class _WritelnDecorator(object):
45 """Used to decorate file-like objects with a handy 'writeln' method"""
46 def __init__(self,stream):
49 def __getattr__(self, attr):
50 if attr in ('stream', '__getstate__'):
51 raise AttributeError(attr)
52 return getattr(self.stream,attr)
54 def writeln(self, arg=None):
57 self.write('\n') # text-mode streams translate to \r\n if needed
64 suite = unittest2.TestSuite()
66 # By default, both command line and Python API tests are performed.
67 # Use @python_api_test decorator, defined in lldbtest.py, to mark a test as
69 dont_do_python_api_test = False
71 # By default, both command line and Python API tests are performed.
72 just_do_python_api_test = False
74 # By default, benchmarks tests are not run.
75 just_do_benchmarks_test = False
77 # By default, both dsym and dwarf tests are performed.
78 # Use @dsym_test or @dwarf_test decorators, defined in lldbtest.py, to mark a test
79 # as a dsym or dwarf test. Use '-N dsym' or '-N dwarf' to exclude dsym or dwarf
81 dont_do_dsym_test = False
82 dont_do_dwarf_test = False
84 # The blacklist is optional (-b blacklistFile) and allows a central place to skip
85 # testclass's and/or testclass.testmethod's.
88 # The dictionary as a result of sourcing blacklistFile.
91 # The config file is optional.
94 # Test suite repeat count. Can be overwritten with '-# count'.
97 # The dictionary as a result of sourcing configFile.
99 # The pre_flight and post_flight functions come from reading a config file.
103 # The 'archs' and 'compilers' can be specified via either command line or configFile,
104 # with the command line overriding the configFile. When specified, they should be
105 # of the list type. For example, "-A x86_64^i386" => archs=['x86_64', 'i386'] and
106 # "-C gcc^clang" => compilers=['gcc', 'clang'].
107 archs = ['x86_64', 'i386']
108 compilers = ['clang']
110 # The arch might dictate some specific CFLAGS to be passed to the toolchain to build
111 # the inferior programs. The global variable cflags_extras provides a hook to do
115 # Delay startup in order for the debugger to attach.
118 # Dump the Python sys.path variable. Use '-D' to dump sys.path.
121 # Full path of the benchmark executable, as specified by the '-e' option.
123 # The breakpoint specification of bmExecutable, as specified by the '-x' option.
124 bmBreakpointSpec = None
125 # The benchamrk iteration count, as specified by the '-y' option.
126 bmIterationCount = -1
128 # By default, don't exclude any directories. Use '-X' to add one excluded directory.
129 excluded = set(['.svn', '.git'])
131 # By default, failfast is False. Use '-F' to overwrite it.
134 # The filters (testclass.testmethod) used to admit tests into our test suite.
137 # The runhooks is a list of lldb commands specifically for the debugger.
138 # Use '-k' to specify a runhook.
141 # If '-g' is specified, the filterspec is not exclusive. If a test module does
142 # not contain testclass.testmethod which matches the filterspec, the whole test
143 # module is still admitted into our test suite. fs4all flag defaults to True.
146 # Ignore the build search path relative to this script to locate the lldb.py module.
149 # By default, we do not skip build and cleanup. Use '-S' option to override.
150 skip_build_and_cleanup = False
152 # By default, we skip long running test case. Use '-l' option to override.
153 skip_long_running_test = True
155 # By default, we print the build dir, lldb version, and svn info. Use '-n' option to
159 # The regular expression pattern to match against eligible filenames as our test cases.
162 # By default, tests are executed in place and cleanups are performed afterwards.
163 # Use '-r dir' option to relocate the tests and their intermediate files to a
164 # different directory and to forgo any cleanups. The directory specified must
168 # By default, recorded session info for errored/failed test are dumped into its
169 # own file under a session directory named after the timestamp of the test suite
170 # run. Use '-s session-dir-name' to specify a specific dir name.
173 # Set this flag if there is any session info dumped during the test run.
174 sdir_has_content = False
176 # svn_info stores the output from 'svn info lldb.base.dir'.
179 # The environment variables to unset before running the test cases.
182 # Default verbosity is 0.
185 # Set to True only if verbose is 0 and LLDB trace mode is off.
188 # By default, search from the script directory.
189 testdirs = [ sys.path[0] ]
197 Usage: dotest.py [option] [args]
199 -h : print this help message and exit. Add '-v' for more detailed help.
200 -A : specify the architecture(s) to launch for the inferior process
201 -A i386 => launch inferior with i386 architecture
202 -A x86_64^i386 => launch inferior with x86_64 and i386 architectures
203 -C : specify the compiler(s) used to build the inferior executable
204 -C clang => build debuggee using clang compiler
205 -C /my/full/path/to/clang => specify a full path to the clang binary
206 -C clang^gcc => build debuggee using clang and gcc compilers
207 -D : dump the Python sys.path variable
208 -E : specify the extra flags to be passed to the toolchain when building the
209 inferior programs to be debugged
210 suggestions: do not lump the -A arch1^arch2 together such that the -E
211 option applies to only one of the architectures
212 -N : don't do test cases marked with the @dsym decorator by passing 'dsym' as the option arg, or
213 don't do test cases marked with the @dwarf decorator by passing 'dwarf' as the option arg
214 -a : don't do lldb Python API tests
215 use @python_api_test to decorate a test case as lldb Python API test
216 +a : just do lldb Python API tests
217 do not specify both '-a' and '+a' at the same time
218 +b : just do benchmark tests
219 use @benchmark_test to decorate a test case as such
220 -b : read a blacklist file specified after this option
221 -c : read a config file specified after this option
222 the architectures and compilers (note the plurals) specified via '-A' and '-C'
223 will override those specified via a config file
224 (see also lldb-trunk/example/test/usage-config)
225 -d : delay startup for 10 seconds (in order for the debugger to attach)
226 -e : specify the full path of an executable used for benchmark purpose;
227 see also '-x', which provides the breakpoint sepcification
228 -F : failfast, stop the test suite on the first error/failure
229 -f : specify a filter, which consists of the test class name, a dot, followed by
230 the test method, to only admit such test into the test suite
231 e.g., -f 'ClassTypesTestCase.test_with_dwarf_and_python_api'
232 -g : if specified, the filterspec by -f is not exclusive, i.e., if a test module
233 does not match the filterspec (testclass.testmethod), the whole module is
234 still admitted to the test suite
235 -i : ignore (don't bailout) if 'lldb.py' module cannot be located in the build
236 tree relative to this script; use PYTHONPATH to locate the module
237 -k : specify a runhook, which is an lldb command to be executed by the debugger;
238 '-k' option can occur multiple times, the commands are executed one after the
239 other to bring the debugger to a desired state, so that, for example, further
240 benchmarking can be done
241 -l : don't skip long running test
242 -n : don't print the headers like build dir, lldb version, and svn info at all
243 -p : specify a regexp filename pattern for inclusion in the test suite
244 -r : specify a dir to relocate the tests and their intermediate files to;
245 the directory must not exist before running this test driver;
246 no cleanup of intermediate test files is performed in this case
247 -S : skip the build and cleanup while running the test
248 use this option with care as you would need to build the inferior(s) by hand
249 and build the executable(s) with the correct name(s)
250 this can be used with '-# n' to stress test certain test cases for n number of
252 -s : specify the name of the dir created to store the session files of tests
253 with errored or failed status; if not specified, the test driver uses the
254 timestamp as the session dir name
255 -t : turn on tracing of lldb command and other detailed test executions
256 -u : specify an environment variable to unset before running the test cases
257 e.g., -u DYLD_INSERT_LIBRARIES -u MallocScribble'
258 -v : do verbose mode of unittest framework (print out each test case invocation)
259 -X : exclude a directory from consideration for test discovery
260 -X types => if 'types' appear in the pathname components of a potential testfile
262 -x : specify the breakpoint specification for the benchmark executable;
263 see also '-e', which provides the full path of the executable
264 -y : specify the iteration count used to collect our benchmarks; an example is
265 the number of times to do 'thread step-over' to measure stepping speed
266 see also '-e' and '-x' options
267 -w : insert some wait time (currently 0.5 sec) between consecutive test cases
268 -# : Repeat the test suite for a specified number of times
271 args : specify a list of directory names to search for test modules named after
272 Test*.py (test discovery)
273 if empty, search from the current working directory, instead
280 This is an example of using the -f option to pinpoint to a specfic test class
281 and test method to be run:
283 $ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command
284 ----------------------------------------------------------------------
287 test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
288 Test 'frame variable this' when stopped on a class constructor. ... ok
290 ----------------------------------------------------------------------
295 And this is an example of using the -p option to run a single file (the filename
296 matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
298 $ ./dotest.py -v -p ObjC
299 ----------------------------------------------------------------------
302 test_break_with_dsym (TestObjCMethods.FoundationTestCase)
303 Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
304 test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
305 Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
306 test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
307 Lookup objective-c data types and evaluate expressions. ... ok
308 test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
309 Lookup objective-c data types and evaluate expressions. ... ok
311 ----------------------------------------------------------------------
312 Ran 4 tests in 16.661s
316 Running of this script also sets up the LLDB_TEST environment variable so that
317 individual test cases can locate their supporting files correctly. The script
318 tries to set up Python's search paths for modules by looking at the build tree
319 relative to this script. See also the '-i' option in the following example.
321 Finally, this is an example of using the lldb.py module distributed/installed by
322 Xcode4 to run against the tests under the 'forward' directory, and with the '-w'
323 option to add some delay between two tests. It uses ARCH=x86_64 to specify that
324 as the architecture and CC=clang to specify the compiler used for the test run:
326 $ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward
328 Session logs for test failures/errors will go into directory '2010-11-11-13_56_16'
329 ----------------------------------------------------------------------
332 test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
333 Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
334 test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
335 Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
337 ----------------------------------------------------------------------
338 Ran 2 tests in 5.659s
342 The 'Session ...' verbiage is recently introduced (see also the '-s' option) to
343 notify the directory containing the session logs for test failures or errors.
344 In case there is any test failure/error, a similar message is appended at the
345 end of the stderr output for your convenience.
347 Environment variables related to loggings:
349 o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
350 with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
352 o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
353 'process.gdb-remote' subsystem with a default option of 'packets' if
354 GDB_REMOTE_LOG_OPTION is not defined.
359 def parseOptionsAndInitTestdirs():
360 """Initialize the list of directories containing our unittest scripts.
362 '-h/--help as the first option prints out usage info and exit the program.
365 global dont_do_python_api_test
366 global just_do_python_api_test
367 global just_do_benchmarks_test
368 global dont_do_dsym_test
369 global dont_do_dwarf_test
371 global blacklistConfig
379 global bmBreakpointSpec
380 global bmIterationCount
387 global skip_build_and_cleanup
388 global skip_long_running_test
399 if len(sys.argv) == 1:
402 # Process possible trace and/or verbose flag, among other things.
404 while index < len(sys.argv):
405 if sys.argv[index].startswith('-') or sys.argv[index].startswith('+'):
406 # We should continue processing...
409 # End of option processing.
412 if sys.argv[index].find('-h') != -1:
415 elif sys.argv[index].startswith('-A'):
416 # Increment by 1 to fetch the ARCH spec.
418 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
420 archs = sys.argv[index].split('^')
422 elif sys.argv[index].startswith('-C'):
423 # Increment by 1 to fetch the CC spec.
425 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
427 compilers = sys.argv[index].split('^')
429 elif sys.argv[index].startswith('-D'):
432 elif sys.argv[index].startswith('-E'):
433 # Increment by 1 to fetch the CFLAGS_EXTRAS spec.
435 if index >= len(sys.argv):
437 cflags_extras = sys.argv[index]
438 os.environ["CFLAGS_EXTRAS"] = cflags_extras
440 elif sys.argv[index].startswith('-N'):
441 # Increment by 1 to fetch 'dsym' or 'dwarf'.
443 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
445 dont_do = sys.argv[index]
446 if dont_do.lower() == 'dsym':
447 dont_do_dsym_test = True
448 elif dont_do.lower() == 'dwarf':
449 dont_do_dwarf_test = True
452 print "Warning: -N only accepts either 'dsym' or 'dwarf' as the option arg; you passed in '%s'?" % dont_do
455 elif sys.argv[index].startswith('-a'):
456 dont_do_python_api_test = True
458 elif sys.argv[index].startswith('+a'):
459 just_do_python_api_test = True
461 elif sys.argv[index].startswith('+b'):
462 just_do_benchmarks_test = True
464 elif sys.argv[index].startswith('-b'):
465 # Increment by 1 to fetch the blacklist file name option argument.
467 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
469 blacklistFile = sys.argv[index]
470 if not os.path.isfile(blacklistFile):
471 print "Blacklist file:", blacklistFile, "does not exist!"
474 # Now read the blacklist contents and assign it to blacklist.
475 execfile(blacklistFile, globals(), blacklistConfig)
476 blacklist = blacklistConfig.get('blacklist')
477 elif sys.argv[index].startswith('-c'):
478 # Increment by 1 to fetch the config file name option argument.
480 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
482 configFile = sys.argv[index]
483 if not os.path.isfile(configFile):
484 print "Config file:", configFile, "does not exist!"
487 elif sys.argv[index].startswith('-d'):
490 elif sys.argv[index].startswith('-e'):
491 # Increment by 1 to fetch the full path of the benchmark executable.
493 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
495 bmExecutable = sys.argv[index]
496 if not is_exe(bmExecutable):
499 elif sys.argv[index].startswith('-F'):
502 elif sys.argv[index].startswith('-f'):
503 # Increment by 1 to fetch the filter spec.
505 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
507 filters.append(sys.argv[index])
509 elif sys.argv[index].startswith('-g'):
512 elif sys.argv[index].startswith('-i'):
515 elif sys.argv[index].startswith('-k'):
516 # Increment by 1 to fetch the runhook lldb command.
518 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
520 runHooks.append(sys.argv[index])
522 elif sys.argv[index].startswith('-l'):
523 skip_long_running_test = False
525 elif sys.argv[index].startswith('-n'):
528 elif sys.argv[index].startswith('-p'):
529 # Increment by 1 to fetch the reg exp pattern argument.
531 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
533 regexp = sys.argv[index]
535 elif sys.argv[index].startswith('-r'):
536 # Increment by 1 to fetch the relocated directory argument.
538 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
540 rdir = os.path.abspath(sys.argv[index])
541 if os.path.exists(rdir):
542 print "Relocated directory:", rdir, "must not exist!"
545 elif sys.argv[index].startswith('-S'):
546 skip_build_and_cleanup = True
548 elif sys.argv[index].startswith('-s'):
549 # Increment by 1 to fetch the session dir name.
551 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
553 sdir_name = sys.argv[index]
555 elif sys.argv[index].startswith('-t'):
556 os.environ["LLDB_COMMAND_TRACE"] = "YES"
558 elif sys.argv[index].startswith('-u'):
559 # Increment by 1 to fetch the environment variable to unset.
561 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
563 unsets.append(sys.argv[index])
565 elif sys.argv[index].startswith('-v'):
568 elif sys.argv[index].startswith('-w'):
569 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] = 'YES'
571 elif sys.argv[index].startswith('-X'):
572 # Increment by 1 to fetch an excluded directory.
574 if index >= len(sys.argv):
576 excluded.add(sys.argv[index])
578 elif sys.argv[index].startswith('-x'):
579 # Increment by 1 to fetch the breakpoint specification of the benchmark executable.
581 if index >= len(sys.argv):
583 bmBreakpointSpec = sys.argv[index]
585 elif sys.argv[index].startswith('-y'):
586 # Increment by 1 to fetch the the benchmark iteration count.
588 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
590 bmIterationCount = int(sys.argv[index])
592 elif sys.argv[index].startswith('-#'):
593 # Increment by 1 to fetch the repeat count argument.
595 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
597 count = int(sys.argv[index])
600 print "Unknown option: ", sys.argv[index]
606 # Do not specify both '-a' and '+a' at the same time.
607 if dont_do_python_api_test and just_do_python_api_test:
610 # The simple progress bar is turned on only if verbose == 0 and LLDB_COMMAND_TRACE is not 'YES'
611 if ("LLDB_COMMAND_TRACE" not in os.environ or os.environ["LLDB_COMMAND_TRACE"]!="YES") and verbose==0:
614 # Gather all the dirs passed on the command line.
615 if len(sys.argv) > index:
616 testdirs = map(os.path.abspath, sys.argv[index:])
618 # If '-r dir' is specified, the tests should be run under the relocated
619 # directory. Let's copy the testdirs over.
621 from shutil import copytree, ignore_patterns
624 for srcdir in testdirs:
625 # For example, /Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/hello_watchpoint
626 # shall be split into ['/Volumes/data/lldb/svn/ToT/', 'functionalities/watchpoint/hello_watchpoint'].
627 # Utilize the relative path to the 'test' directory to make our destination dir path.
628 dstdir = os.path.join(rdir, srcdir.split("test"+os.sep)[1])
629 #print "(srcdir, dstdir)=(%s, %s)" % (srcdir, dstdir)
630 # Don't copy the *.pyc and .svn stuffs.
631 copytree(srcdir, dstdir, ignore=ignore_patterns('*.pyc', '.svn'))
632 tmpdirs.append(dstdir)
634 # This will be our modified testdirs.
637 # With '-r dir' specified, there's no cleanup of intermediate test files.
638 os.environ["LLDB_DO_CLEANUP"] = 'NO'
640 # If testdirs is ['test'], the make directory has already been copied
641 # recursively and is contained within the rdir/test dir. For anything
642 # else, we would need to copy over the make directory and its contents,
643 # so that, os.listdir(rdir) looks like, for example:
645 # array_types conditional_break make
647 # where the make directory contains the Makefile.rules file.
648 if len(testdirs) != 1 or os.path.basename(testdirs[0]) != 'test':
649 # Don't copy the .svn stuffs.
650 copytree('make', os.path.join(rdir, 'make'),
651 ignore=ignore_patterns('.svn'))
653 #print "testdirs:", testdirs
655 # Source the configFile if specified.
656 # The side effect, if any, will be felt from this point on. An example
657 # config file may be these simple two lines:
659 # sys.stderr = open("/tmp/lldbtest-stderr", "w")
660 # sys.stdout = open("/tmp/lldbtest-stdout", "w")
662 # which will reassign the two file objects to sys.stderr and sys.stdout,
665 # See also lldb-trunk/example/test/usage-config.
666 global config, pre_flight, post_flight
668 # Pass config (a dictionary) as the locals namespace for side-effect.
669 execfile(configFile, globals(), config)
670 print "config:", config
671 if "pre_flight" in config:
672 pre_flight = config["pre_flight"]
673 if not callable(pre_flight):
674 print "fatal error: pre_flight is not callable, exiting."
676 if "post_flight" in config:
677 post_flight = config["post_flight"]
678 if not callable(post_flight):
679 print "fatal error: post_flight is not callable, exiting."
681 #print "sys.stderr:", sys.stderr
682 #print "sys.stdout:", sys.stdout
687 Add LLDB.framework/Resources/Python to the search paths for modules.
688 As a side effect, we also discover the 'lldb' executable and export it here.
697 # Get the directory containing the current script.
698 if ("DOTEST_PROFILE" in os.environ or "DOTEST_PDB" in os.environ) and "DOTEST_SCRIPT_DIR" in os.environ:
699 scriptPath = os.environ["DOTEST_SCRIPT_DIR"]
701 scriptPath = sys.path[0]
702 if not scriptPath.endswith('test'):
703 print "This script expects to reside in lldb's test directory."
707 # Set up the LLDB_TEST environment variable appropriately, so that the
708 # individual tests can be located relatively.
710 # See also lldbtest.TestBase.setUpClass(cls).
711 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
712 os.environ["LLDB_TEST"] = os.path.join(rdir, 'test')
714 os.environ["LLDB_TEST"] = rdir
716 os.environ["LLDB_TEST"] = scriptPath
718 # Set up the LLDB_SRC environment variable, so that the tests can locate
719 # the LLDB source code.
720 os.environ["LLDB_SRC"] = os.path.join(sys.path[0], os.pardir)
722 pluginPath = os.path.join(scriptPath, 'plugins')
723 pexpectPath = os.path.join(scriptPath, 'pexpect-2.4')
725 # Append script dir, plugin dir, and pexpect dir to the sys.path.
726 sys.path.append(scriptPath)
727 sys.path.append(pluginPath)
728 sys.path.append(pexpectPath)
730 # This is our base name component.
731 base = os.path.abspath(os.path.join(scriptPath, os.pardir))
733 # These are for xcode build directories.
734 xcode3_build_dir = ['build']
735 xcode4_build_dir = ['build', 'lldb', 'Build', 'Products']
738 bai = ['BuildAndIntegration']
739 python_resource_dir = ['LLDB.framework', 'Resources', 'Python']
741 # Some of the tests can invoke the 'lldb' command directly.
742 # We'll try to locate the appropriate executable right here.
744 # First, you can define an environment variable LLDB_EXEC specifying the
745 # full pathname of the lldb executable.
746 if "LLDB_EXEC" in os.environ and is_exe(os.environ["LLDB_EXEC"]):
747 lldbExec = os.environ["LLDB_EXEC"]
751 executable = ['lldb']
752 dbgExec = os.path.join(base, *(xcode3_build_dir + dbg + executable))
753 dbgExec2 = os.path.join(base, *(xcode4_build_dir + dbg + executable))
754 relExec = os.path.join(base, *(xcode3_build_dir + rel + executable))
755 relExec2 = os.path.join(base, *(xcode4_build_dir + rel + executable))
756 baiExec = os.path.join(base, *(xcode3_build_dir + bai + executable))
757 baiExec2 = os.path.join(base, *(xcode4_build_dir + bai + executable))
759 # The 'lldb' executable built here in the source tree.
763 elif is_exe(dbgExec2):
765 elif is_exe(relExec):
767 elif is_exe(relExec2):
769 elif is_exe(baiExec):
771 elif is_exe(baiExec2):
777 os.environ["LLDB_HERE"] = lldbHere
778 os.environ["LLDB_BUILD_DIR"] = os.path.split(lldbHere)[0]
780 print "LLDB build dir:", os.environ["LLDB_BUILD_DIR"]
781 os.system('%s -v' % lldbHere)
783 # One last chance to locate the 'lldb' executable.
785 lldbExec = which('lldb')
786 if lldbHere and not lldbExec:
791 print "The 'lldb' executable cannot be located. Some of the tests may not be run as a result."
793 os.environ["LLDB_EXEC"] = lldbExec
794 #print "The 'lldb' from PATH env variable", lldbExec
796 if os.path.isdir(os.path.join(base, '.svn')):
797 pipe = subprocess.Popen(["svn", "info", base], stdout = subprocess.PIPE)
798 svn_info = pipe.stdout.read()
799 elif os.path.isdir(os.path.join(base, '.git')):
800 pipe = subprocess.Popen(["git", "svn", "info", base], stdout = subprocess.PIPE)
801 svn_info = pipe.stdout.read()
807 # The '-i' option is used to skip looking for lldb.py in the build tree.
811 dbgPath = os.path.join(base, *(xcode3_build_dir + dbg + python_resource_dir))
812 dbgPath2 = os.path.join(base, *(xcode4_build_dir + dbg + python_resource_dir))
813 relPath = os.path.join(base, *(xcode3_build_dir + rel + python_resource_dir))
814 relPath2 = os.path.join(base, *(xcode4_build_dir + rel + python_resource_dir))
815 baiPath = os.path.join(base, *(xcode3_build_dir + bai + python_resource_dir))
816 baiPath2 = os.path.join(base, *(xcode4_build_dir + bai + python_resource_dir))
819 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
821 elif os.path.isfile(os.path.join(dbgPath2, 'lldb.py')):
823 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
825 elif os.path.isfile(os.path.join(relPath2, 'lldb.py')):
827 elif os.path.isfile(os.path.join(baiPath, 'lldb.py')):
829 elif os.path.isfile(os.path.join(baiPath2, 'lldb.py')):
833 print 'This script requires lldb.py to be in either ' + dbgPath + ',',
834 print relPath + ', or ' + baiPath
837 # This is to locate the lldb.py module. Insert it right after sys.path[0].
838 sys.path[1:1] = [lldbPath]
840 print "sys.path:", sys.path
844 """Delaying startup for delta-seconds to facilitate debugger attachment."""
845 def alarm_handler(*args):
846 raise Exception("timeout")
848 signal.signal(signal.SIGALRM, alarm_handler)
850 sys.stdout.write("pid=%d\n" % os.getpid())
851 sys.stdout.write("Enter RET to proceed (or timeout after %d seconds):" %
855 text = sys.stdin.readline()
859 sys.stdout.write("proceeding...\n")
863 def visit(prefix, dir, names):
864 """Visitor function for os.path.walk(path, visit, arg)."""
872 if set(dir.split(os.sep)).intersection(excluded):
873 #print "Detected an excluded dir component: %s" % dir
877 if os.path.isdir(os.path.join(dir, name)):
880 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
881 # Try to match the regexp pattern, if specified.
884 if re.search(regexp, name):
885 #print "Filename: '%s' matches pattern: '%s'" % (name, regexp)
888 #print "Filename: '%s' does not match pattern: '%s'" % (name, regexp)
891 # We found a match for our test. Add it to the suite.
893 # Update the sys.path first.
894 if not sys.path.count(dir):
895 sys.path.insert(0, dir)
896 base = os.path.splitext(name)[0]
898 # Thoroughly check the filterspec against the base module and admit
899 # the (base, filterspec) combination only when it makes sense.
901 for filterspec in filters:
902 # Optimistically set the flag to True.
904 module = __import__(base)
905 parts = filterspec.split('.')
909 parent, obj = obj, getattr(obj, part)
910 except AttributeError:
911 # The filterspec has failed.
915 # If filtered, we have a good filterspec. Add it.
917 #print "adding filter spec %s to module %s" % (filterspec, module)
919 unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
922 # Forgo this module if the (base, filterspec) combo is invalid
923 # and no '-g' option is specified
924 if filters and fs4all and not filtered:
927 # Add either the filtered test case(s) (which is done before) or the entire test class.
928 if not filterspec or not filtered:
929 # A simple case of just the module name. Also the failover case
930 # from the filterspec branch when the (base, filterspec) combo
931 # doesn't make sense.
932 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
936 """Check and do lldb loggings if necessary."""
938 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
939 # defined. Use ${LLDB_LOG} to specify the log file.
940 ci = lldb.DBG.GetCommandInterpreter()
941 res = lldb.SBCommandReturnObject()
942 if ("LLDB_LOG" in os.environ):
943 if ("LLDB_LOG_OPTION" in os.environ):
944 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
946 lldb_log_option = "event process expr state api"
948 "log enable -n -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
950 if not res.Succeeded():
951 raise Exception('log enable failed (check LLDB_LOG env variable.')
952 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
953 # Use ${GDB_REMOTE_LOG} to specify the log file.
954 if ("GDB_REMOTE_LOG" in os.environ):
955 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
956 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
958 gdb_remote_log_option = "packets process"
960 "log enable -n -f " + os.environ["GDB_REMOTE_LOG"] + " gdb-remote "
961 + gdb_remote_log_option,
963 if not res.Succeeded():
964 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
966 def getMyCommandLine():
967 ps = subprocess.Popen(['ps', '-o', "command=CMD", str(os.getpid())], stdout=subprocess.PIPE).communicate()[0]
968 lines = ps.split('\n')
972 # ======================================== #
974 # Execution of the test driver starts here #
976 # ======================================== #
978 def checkDsymForUUIDIsNotOn():
979 cmd = ["defaults", "read", "com.apple.DebugSymbols"]
980 pipe = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
981 cmd_output = pipe.stdout.read()
982 if cmd_output and "DBGFileMappedPaths = " in cmd_output:
983 print "%s =>" % ' '.join(cmd)
985 print "Disable automatic lookup and caching of dSYMs before running the test suite!"
989 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults
990 # does not exist before proceeding to running the test suite.
991 if sys.platform.startswith("darwin"):
992 checkDsymForUUIDIsNotOn()
995 # Start the actions by first parsing the options while setting up the test
996 # directories, followed by setting up the search paths for lldb utilities;
997 # then, we walk the directory trees and collect the tests into our test suite.
999 parseOptionsAndInitTestdirs()
1003 # If '-d' is specified, do a delay of 10 seconds for the debugger to attach.
1009 # If '-l' is specified, do not skip the long running tests.
1010 if not skip_long_running_test:
1011 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
1014 # Walk through the testdirs while collecting tests.
1016 for testdir in testdirs:
1017 os.path.walk(testdir, visit, 'Test')
1020 # Now that we have loaded all the test cases, run the whole test suite.
1023 # For the time being, let's bracket the test runner within the
1024 # lldb.SBDebugger.Initialize()/Terminate() pair.
1026 # Update: the act of importing lldb now executes lldb.SBDebugger.Initialize(),
1027 # there's no need to call it a second time.
1028 #lldb.SBDebugger.Initialize()
1029 atexit.register(lambda: lldb.SBDebugger.Terminate())
1031 # Create a singleton SBDebugger in the lldb namespace.
1032 lldb.DBG = lldb.SBDebugger.Create()
1034 # Put the blacklist in the lldb namespace, to be used by lldb.TestBase.
1035 lldb.blacklist = blacklist
1037 # The pre_flight and post_flight come from reading a config file.
1038 lldb.pre_flight = pre_flight
1039 lldb.post_flight = post_flight
1040 def getsource_if_available(obj):
1042 Return the text of the source code for an object if available. Otherwise,
1043 a print representation is returned.
1047 return inspect.getsource(obj)
1051 print "lldb.pre_flight:", getsource_if_available(lldb.pre_flight)
1052 print "lldb.post_flight:", getsource_if_available(lldb.post_flight)
1054 # Put all these test decorators in the lldb namespace.
1055 lldb.dont_do_python_api_test = dont_do_python_api_test
1056 lldb.just_do_python_api_test = just_do_python_api_test
1057 lldb.just_do_benchmarks_test = just_do_benchmarks_test
1058 lldb.dont_do_dsym_test = dont_do_dsym_test
1059 lldb.dont_do_dwarf_test = dont_do_dwarf_test
1061 # Do we need to skip build and cleanup?
1062 lldb.skip_build_and_cleanup = skip_build_and_cleanup
1064 # Put bmExecutable, bmBreakpointSpec, and bmIterationCount into the lldb namespace, too.
1065 lldb.bmExecutable = bmExecutable
1066 lldb.bmBreakpointSpec = bmBreakpointSpec
1067 lldb.bmIterationCount = bmIterationCount
1069 # And don't forget the runHooks!
1070 lldb.runHooks = runHooks
1072 # Turn on lldb loggings if necessary.
1075 # Install the control-c handler.
1076 unittest2.signals.installHandler()
1078 # If sdir_name is not specified through the '-s sdir_name' option, get a
1079 # timestamp string and export it as LLDB_SESSION_DIR environment var. This will
1080 # be used when/if we want to dump the session info of individual test cases
1083 # See also TestBase.dumpSessionInfo() in lldbtest.py.
1086 # The windows platforms don't like ':' in the pathname.
1087 timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
1088 sdir_name = timestamp
1089 os.environ["LLDB_SESSION_DIRNAME"] = os.path.join(os.getcwd(), sdir_name)
1092 sys.stderr.write("\nSession logs for test failures/errors/unexpected successes"
1093 " will go into directory '%s'\n" % sdir_name)
1094 sys.stderr.write("Command invoked: %s\n" % getMyCommandLine())
1096 if not os.path.isdir(sdir_name):
1098 fname = os.path.join(sdir_name, "svn-info")
1099 with open(fname, "w") as f:
1100 print >> f, svn_info
1101 print >> f, "Command invoked: %s\n" % getMyCommandLine()
1104 # If we have environment variables to unset, do it here before we invoke the test runner.
1106 for env_var in unsets :
1107 if env_var in os.environ:
1108 # From Python Doc: When unsetenv() is supported, deletion of items in os.environ
1109 # is automatically translated into a corresponding call to unsetenv().
1110 del os.environ[env_var]
1111 #os.unsetenv(env_var)
1114 # Invoke the default TextTestRunner to run the test suite, possibly iterating
1115 # over different configurations.
1119 iterCompilers = False
1121 if not archs and "archs" in config:
1122 archs = config["archs"]
1124 if isinstance(archs, list) and len(archs) >= 1:
1127 if not compilers and "compilers" in config:
1128 compilers = config["compilers"]
1131 # Add some intervention here to sanity check that the compilers requested are sane.
1132 # If found not to be an executable program, the invalid one is dropped from the list.
1133 for i in range(len(compilers)):
1138 if sys.platform.startswith("darwin"):
1139 pipe = subprocess.Popen(['xcrun', '-find', c], stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
1140 cmd_output = pipe.stdout.read()
1142 if "not found" in cmd_output:
1143 print "dropping %s from the compilers used" % c
1146 compilers[i] = cmd_output.split('\n')[0]
1147 print "'xcrun -find %s' returning %s" % (c, compilers[i])
1149 print "compilers=%s" % str(compilers)
1151 if not compilers or len(compilers) == 0:
1152 print "No eligible compiler found, exiting."
1155 if isinstance(compilers, list) and len(compilers) >= 1:
1156 iterCompilers = True
1158 # Make a shallow copy of sys.path, we need to manipulate the search paths later.
1159 # This is only necessary if we are relocated and with different configurations.
1161 old_sys_path = sys.path[:]
1162 # If we iterate on archs or compilers, there is a chance we want to split stderr/stdout.
1163 if iterArchs or iterCompilers:
1164 old_stderr = sys.stderr
1165 old_stdout = sys.stdout
1169 # Iterating over all possible architecture and compiler combinations.
1170 for ia in range(len(archs) if iterArchs else 1):
1173 os.environ["ARCH"] = archs[ia]
1174 archConfig = "arch=%s" % archs[ia]
1175 for ic in range(len(compilers) if iterCompilers else 1):
1177 os.environ["CC"] = compilers[ic]
1178 configString = "%s compiler=%s" % (archConfig, compilers[ic])
1180 configString = archConfig
1182 if iterArchs or iterCompilers:
1183 # Translate ' ' to '-' for pathname component.
1184 from string import maketrans
1185 tbl = maketrans(' ', '-')
1186 configPostfix = configString.translate(tbl)
1188 # Check whether we need to split stderr/stdout into configuration
1190 if old_stderr.name != '<stderr>' and config.get('split_stderr'):
1193 new_stderr = open("%s.%s" % (old_stderr.name, configPostfix), "w")
1194 sys.stderr = new_stderr
1195 if old_stdout.name != '<stdout>' and config.get('split_stdout'):
1198 new_stdout = open("%s.%s" % (old_stdout.name, configPostfix), "w")
1199 sys.stdout = new_stdout
1201 # If we specified a relocated directory to run the test suite, do
1202 # the extra housekeeping to copy the testdirs to a configStringified
1203 # directory and to update sys.path before invoking the test runner.
1204 # The purpose is to separate the configuration-specific directories
1207 from shutil import copytree, ignore_patterns
1209 newrdir = "%s.%s" % (rdir, configPostfix)
1211 # Copy the tree to a new directory with postfix name configPostfix.
1212 copytree(rdir, newrdir, ignore=ignore_patterns('*.pyc', '*.o', '*.d'))
1214 # Update the LLDB_TEST environment variable to reflect new top
1215 # level test directory.
1217 # See also lldbtest.TestBase.setUpClass(cls).
1218 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
1219 os.environ["LLDB_TEST"] = os.path.join(newrdir, 'test')
1221 os.environ["LLDB_TEST"] = newrdir
1223 # And update the Python search paths for modules.
1224 sys.path = [x.replace(rdir, newrdir, 1) for x in old_sys_path]
1226 # Output the configuration.
1227 sys.stderr.write("\nConfiguration: " + configString + "\n")
1229 #print "sys.stderr name is", sys.stderr.name
1230 #print "sys.stdout name is", sys.stdout.name
1232 # First, write out the number of collected test cases.
1233 sys.stderr.write(separator + "\n")
1234 sys.stderr.write("Collected %d test%s\n\n"
1235 % (suite.countTestCases(),
1236 suite.countTestCases() != 1 and "s" or ""))
1238 class LLDBTestResult(unittest2.TextTestResult):
1240 Enforce a singleton pattern to allow introspection of test progress.
1242 Overwrite addError(), addFailure(), and addExpectedFailure() methods
1243 to enable each test instance to track its failure/error status. It
1244 is used in the LLDB test framework to emit detailed trace messages
1245 to a log file for easier human inspection of test failres/errors.
1247 __singleton__ = None
1248 __ignore_singleton__ = False
1250 def __init__(self, *args):
1251 if not LLDBTestResult.__ignore_singleton__ and LLDBTestResult.__singleton__:
1252 raise Exception("LLDBTestResult instantiated more than once")
1253 super(LLDBTestResult, self).__init__(*args)
1254 LLDBTestResult.__singleton__ = self
1255 # Now put this singleton into the lldb module namespace.
1256 lldb.test_result = self
1257 # Computes the format string for displaying the counter.
1259 counterWidth = len(str(suite.countTestCases()))
1260 self.fmt = "%" + str(counterWidth) + "d: "
1261 self.indentation = ' ' * (counterWidth + 2)
1262 # This counts from 1 .. suite.countTestCases().
1265 def getDescription(self, test):
1266 doc_first_line = test.shortDescription()
1267 if self.descriptions and doc_first_line:
1268 return '\n'.join((str(test), self.indentation + doc_first_line))
1272 def startTest(self, test):
1275 self.stream.write(self.fmt % self.counter)
1276 super(LLDBTestResult, self).startTest(test)
1278 def stopTest(self, test):
1279 """Called when the given test has been run"""
1281 sys.__stdout__.write('.')
1282 sys.__stdout__.flush()
1283 if self.counter == suite.countTestCases():
1284 sys.__stdout__.write('\n')
1286 super(LLDBTestResult, self).stopTest(test)
1288 def addError(self, test, err):
1289 global sdir_has_content
1290 sdir_has_content = True
1291 super(LLDBTestResult, self).addError(test, err)
1292 method = getattr(test, "markError", None)
1296 def addFailure(self, test, err):
1297 global sdir_has_content
1298 sdir_has_content = True
1299 super(LLDBTestResult, self).addFailure(test, err)
1300 method = getattr(test, "markFailure", None)
1304 def addExpectedFailure(self, test, err):
1305 global sdir_has_content
1306 sdir_has_content = True
1307 super(LLDBTestResult, self).addExpectedFailure(test, err)
1308 method = getattr(test, "markExpectedFailure", None)
1312 def addSkip(self, test, reason):
1313 global sdir_has_content
1314 sdir_has_content = True
1315 super(LLDBTestResult, self).addSkip(test, reason)
1316 method = getattr(test, "markSkippedTest", None)
1320 def addUnexpectedSuccess(self, test):
1321 global sdir_has_content
1322 sdir_has_content = True
1323 super(LLDBTestResult, self).addUnexpectedSuccess(test)
1324 method = getattr(test, "markUnexpectedSuccess", None)
1328 # Invoke the test runner.
1330 result = unittest2.TextTestRunner(stream=sys.stderr,
1333 resultclass=LLDBTestResult).run(suite)
1335 # We are invoking the same test suite more than once. In this case,
1336 # mark __ignore_singleton__ flag as True so the signleton pattern is
1338 LLDBTestResult.__ignore_singleton__ = True
1339 for i in range(count):
1340 result = unittest2.TextTestRunner(stream=sys.stderr,
1343 resultclass=LLDBTestResult).run(suite)
1346 if sdir_has_content:
1347 sys.stderr.write("Session logs for test failures/errors/unexpected successes"
1348 " can be found in directory '%s'\n" % sdir_name)
1350 # Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
1351 # This should not be necessary now.
1352 if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
1353 print "Terminating Test suite..."
1354 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
1357 sys.exit(not result.wasSuccessful)