2 A simple testing framework for lldb using python's unit testing framework.
4 Tests for lldb are written as python scripts which take advantage of the script
5 bridging provided by LLDB.framework to interact with lldb core.
7 A specific naming pattern is followed by the .py script to be recognized as
8 a module which implements a test scenario, namely, Test*.py.
10 To specify the directories where "Test*.py" python test scripts are located,
11 you need to pass in a list of directory names. By default, the current
12 working directory is searched if nothing is specified on the command line.
18 for available options.
21 from __future__ import absolute_import
22 from __future__ import print_function
41 from . import configuration
42 from . import dotest_args
43 from . import lldbtest_config
44 from . import test_categories
45 from lldbsuite.test_event import formatter
46 from . import test_result
47 from lldbsuite.test_event.event_builder import EventBuilder
48 from ..support import seven
52 """Returns true if fpath is an executable."""
53 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
57 """Returns the full path to a program; None otherwise."""
58 fpath, fname = os.path.split(program)
63 for path in os.environ["PATH"].split(os.pathsep):
64 exe_file = os.path.join(path, program)
70 class _WritelnDecorator(object):
71 """Used to decorate file-like objects with a handy 'writeln' method"""
73 def __init__(self, stream):
76 def __getattr__(self, attr):
77 if attr in ('stream', '__getstate__'):
78 raise AttributeError(attr)
79 return getattr(self.stream, attr)
81 def writeln(self, arg=None):
84 self.write('\n') # text-mode streams translate to \r\n if needed
93 if configuration.verbose > 0:
97 This is an example of using the -f option to pinpoint to a specific test class
98 and test method to be run:
100 $ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command
101 ----------------------------------------------------------------------
104 test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
105 Test 'frame variable this' when stopped on a class constructor. ... ok
107 ----------------------------------------------------------------------
112 And this is an example of using the -p option to run a single file (the filename
113 matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
115 $ ./dotest.py -v -p ObjC
116 ----------------------------------------------------------------------
119 test_break_with_dsym (TestObjCMethods.FoundationTestCase)
120 Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
121 test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
122 Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
123 test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
124 Lookup objective-c data types and evaluate expressions. ... ok
125 test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
126 Lookup objective-c data types and evaluate expressions. ... ok
128 ----------------------------------------------------------------------
129 Ran 4 tests in 16.661s
133 Running of this script also sets up the LLDB_TEST environment variable so that
134 individual test cases can locate their supporting files correctly. The script
135 tries to set up Python's search paths for modules by looking at the build tree
136 relative to this script. See also the '-i' option in the following example.
138 Finally, this is an example of using the lldb.py module distributed/installed by
139 Xcode4 to run against the tests under the 'forward' directory, and with the '-w'
140 option to add some delay between two tests. It uses ARCH=x86_64 to specify that
141 as the architecture and CC=clang to specify the compiler used for the test run:
143 $ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward
145 Session logs for test failures/errors will go into directory '2010-11-11-13_56_16'
146 ----------------------------------------------------------------------
149 test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
150 Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
151 test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
152 Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
154 ----------------------------------------------------------------------
155 Ran 2 tests in 5.659s
159 The 'Session ...' verbiage is recently introduced (see also the '-s' option) to
160 notify the directory containing the session logs for test failures or errors.
161 In case there is any test failure/error, a similar message is appended at the
162 end of the stderr output for your convenience.
164 ENABLING LOGS FROM TESTS
168 Writing logs into different files per test case::
170 This option is particularly useful when multiple dotest instances are created
173 $ ./dotest.py --channel "lldb all"
175 $ ./dotest.py --channel "lldb all" --channel "gdb-remote packets"
177 These log files are written to:
179 <session-dir>/<test-id>-host.log (logs from lldb host process)
180 <session-dir>/<test-id>-server.log (logs from debugserver/lldb-server)
181 <session-dir>/<test-id>-<test-result>.log (console logs)
183 By default, logs from successful runs are deleted. Use the --log-success flag
184 to create reference logs for debugging.
186 $ ./dotest.py --log-success
188 Option 2: (DEPRECATED)
190 The following options can only enable logs from the host lldb process.
191 Only categories from the "lldb" or "gdb-remote" channels can be enabled
192 They also do not automatically enable logs in locally running debug servers.
193 Also, logs from all test case are written into each log file
195 o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
196 with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
198 o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
199 'process.gdb-remote' subsystem with a default option of 'packets' if
200 GDB_REMOTE_LOG_OPTION is not defined.
206 def parseExclusion(exclusion_file):
207 """Parse an exclusion file, of the following format, where
208 'skip files', 'skip methods', 'xfail files', and 'xfail methods'
209 are the possible list heading values:
220 with open(exclusion_file) as f:
229 elif excl_type == 'skip':
230 if not configuration.skip_tests:
231 configuration.skip_tests = []
232 configuration.skip_tests.append(line)
233 elif excl_type == 'xfail':
234 if not configuration.xfail_tests:
235 configuration.xfail_tests = []
236 configuration.xfail_tests.append(line)
239 def parseOptionsAndInitTestdirs():
240 """Initialize the list of directories containing our unittest scripts.
242 '-h/--help as the first option prints out usage info and exit the program.
247 platform_system = platform.system()
248 platform_machine = platform.machine()
250 parser = dotest_args.create_parser()
251 args = dotest_args.parse_args(parser, sys.argv[1:])
253 if args.unset_env_varnames:
254 for env_var in args.unset_env_varnames:
255 if env_var in os.environ:
256 # From Python Doc: When unsetenv() is supported, deletion of items in os.environ
257 # is automatically translated into a corresponding call to
259 del os.environ[env_var]
260 # os.unsetenv(env_var)
262 if args.set_env_vars:
263 for env_var in args.set_env_vars:
264 parts = env_var.split('=', 1)
266 os.environ[parts[0]] = ""
268 os.environ[parts[0]] = parts[1]
270 # only print the args if being verbose (and parsable is off)
271 if args.v and not args.q:
278 configuration.compilers = args.compilers
280 # Use a compiler appropriate appropriate for the Apple SDK if one was
282 if platform_system == 'Darwin' and args.apple_sdk:
283 configuration.compilers = [
284 seven.get_command_output(
285 'xcrun -sdk "%s" -find clang 2> /dev/null' %
288 # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first
289 candidateCompilers = ['clang-3.5', 'clang', 'gcc']
290 for candidate in candidateCompilers:
292 configuration.compilers = [candidate]
296 lldbtest_config.channels = args.channels
299 lldbtest_config.log_success = args.log_success
301 # Set SDKROOT if we are using an Apple SDK
302 if platform_system == 'Darwin' and args.apple_sdk:
303 os.environ['SDKROOT'] = seven.get_command_output(
304 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' %
308 configuration.archs = args.archs
309 for arch in configuration.archs:
311 'arm') and platform_system == 'Darwin' and not args.apple_sdk:
312 os.environ['SDKROOT'] = seven.get_command_output(
313 'xcrun --sdk iphoneos.internal --show-sdk-path 2> /dev/null')
314 if not os.path.exists(os.environ['SDKROOT']):
315 os.environ['SDKROOT'] = seven.get_command_output(
316 'xcrun --sdk iphoneos --show-sdk-path 2> /dev/null')
318 configuration.archs = [platform_machine]
320 if args.categoriesList:
321 configuration.categoriesList = set(
322 test_categories.validate(
323 args.categoriesList, False))
324 configuration.useCategories = True
326 configuration.categoriesList = []
328 if args.skipCategories:
329 configuration.skipCategories = test_categories.validate(
330 args.skipCategories, False)
333 cflags_extras = args.E
334 os.environ['CFLAGS_EXTRAS'] = cflags_extras
338 "Suspending the process %d to wait for debugger to attach...\n" %
341 os.kill(os.getpid(), signal.SIGSTOP)
344 if any([x.startswith('-') for x in args.f]):
346 configuration.filters.extend(args.f)
347 # Shut off multiprocessing mode when additional filters are specified.
348 # The rational is that the user is probably going after a very specific
349 # test and doesn't need a bunch of parallel test runners all looking for
350 # it in a frenzy. Also, '-v' now spits out all test run output even
351 # on success, so the standard recipe for redoing a failing test (with -v
352 # and a -f to filter to the specific test) now causes all test scanning
353 # (in parallel) to print results for do-nothing runs in a very distracting
354 # manner. If we really need filtered parallel runs in the future, consider
355 # adding a --no-output-on-success that prevents -v from setting
357 configuration.no_multiprocess_test_runner = True
360 configuration.skip_long_running_test = False
363 configuration.lldbFrameworkPath = args.framework
366 lldbtest_config.lldbExec = os.path.realpath(args.executable)
369 for excl_file in args.excluded:
370 parseExclusion(excl_file)
373 if args.p.startswith('-'):
375 configuration.regexp = args.p
378 configuration.parsable = True
381 if args.s.startswith('-'):
383 configuration.sdir_name = args.s
384 configuration.session_file_format = args.session_file_format
387 os.environ['LLDB_COMMAND_TRACE'] = 'YES'
390 configuration.verbose = 2
392 # argparse makes sure we have a number
394 configuration.count = args.sharp
396 if sys.platform.startswith('win32'):
397 os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str(
398 args.disable_crash_dialog)
399 os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True)
404 if args.no_multiprocess:
405 configuration.no_multiprocess_test_runner = True
408 configuration.is_inferior_test_runner = True
411 configuration.num_threads = args.num_threads
414 configuration.multiprocess_test_subdir = args.test_subdir
416 if args.test_runner_name:
417 configuration.test_runner_name = args.test_runner_name
419 # Capture test results-related args.
420 if args.curses and not args.inferior:
421 # Act as if the following args were set.
422 args.results_formatter = "lldbsuite.test_event.formatter.curses.Curses"
423 args.results_file = "stdout"
425 if args.results_file:
426 configuration.results_filename = args.results_file
428 if args.results_port:
429 configuration.results_port = args.results_port
431 if args.results_file and args.results_port:
433 "only one of --results-file and --results-port should "
437 if args.results_formatter:
438 configuration.results_formatter_name = args.results_formatter
439 if args.results_formatter_options:
440 configuration.results_formatter_options = args.results_formatter_options
442 # Default to using the BasicResultsFormatter if no formatter is specified
443 # and we're not a test inferior.
444 if not args.inferior and configuration.results_formatter_name is None:
445 configuration.results_formatter_name = (
446 "lldbsuite.test_event.formatter.results_formatter.ResultsFormatter")
448 # rerun-related arguments
449 configuration.rerun_all_issues = args.rerun_all_issues
450 configuration.rerun_max_file_threshold = args.rerun_max_file_threshold
452 if args.lldb_platform_name:
453 configuration.lldb_platform_name = args.lldb_platform_name
454 if args.lldb_platform_url:
455 configuration.lldb_platform_url = args.lldb_platform_url
456 if args.lldb_platform_working_dir:
457 configuration.lldb_platform_working_dir = args.lldb_platform_working_dir
459 if args.event_add_entries and len(args.event_add_entries) > 0:
461 # Parse out key=val pairs, separated by comma
462 for keyval in args.event_add_entries.split(","):
463 key_val_entry = keyval.split("=")
464 if len(key_val_entry) == 2:
465 (key, val) = key_val_entry
466 val_parts = val.split(':')
467 if len(val_parts) > 1:
468 (val, val_type) = val_parts
469 if val_type == 'int':
472 # Tell the event builder to create all events with these
473 # key/val pairs in them.
475 EventBuilder.add_entries_to_all_events(entries)
477 # Gather all the dirs passed on the command line.
478 if len(args.args) > 0:
479 configuration.testdirs = list(
480 map(lambda x: os.path.realpath(os.path.abspath(x)), args.args))
481 # Shut off multiprocessing mode when test directories are specified.
482 configuration.no_multiprocess_test_runner = True
484 lldbtest_config.codesign_identity = args.codesign_identity
486 #print("testdirs:", testdirs)
489 def getXcodeOutputPaths(lldbRootDirectory):
492 # These are for xcode build directories.
493 xcode3_build_dir = ['build']
494 xcode4_build_dir = ['build', 'lldb', 'Build', 'Products']
500 ['BuildAndIntegration']]
501 xcode_build_dirs = [xcode3_build_dir, xcode4_build_dir]
502 for configuration in configurations:
503 for xcode_build_dir in xcode_build_dirs:
504 outputPath = os.path.join(
505 lldbRootDirectory, *(xcode_build_dir + configuration))
506 result.append(outputPath)
511 def createSocketToLocalPort(port):
512 def socket_closer(s):
513 """Close down an opened socket properly."""
514 s.shutdown(socket.SHUT_RDWR)
517 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
518 sock.connect(("localhost", port))
519 return (sock, lambda: socket_closer(sock))
522 def setupTestResults():
523 """Sets up test results-related objects based on arg settings."""
524 # Setup the results formatter configuration.
525 formatter_config = formatter.FormatterConfig()
526 formatter_config.filename = configuration.results_filename
527 formatter_config.formatter_name = configuration.results_formatter_name
528 formatter_config.formatter_options = (
529 configuration.results_formatter_options)
530 formatter_config.port = configuration.results_port
532 # Create the results formatter.
533 formatter_spec = formatter.create_results_formatter(
535 if formatter_spec is not None and formatter_spec.formatter is not None:
536 configuration.results_formatter_object = formatter_spec.formatter
538 # Send an initialize message to the formatter.
539 initialize_event = EventBuilder.bare_event("initialize")
540 if isMultiprocessTestRunner():
541 if (configuration.test_runner_name is not None and
542 configuration.test_runner_name == "serial"):
543 # Only one worker queue here.
546 # Workers will be the number of threads specified.
547 worker_count = configuration.num_threads
550 initialize_event["worker_count"] = worker_count
552 formatter_spec.formatter.handle_event(initialize_event)
554 # Make sure we clean up the formatter on shutdown.
555 if formatter_spec.cleanup_func is not None:
556 atexit.register(formatter_spec.cleanup_func)
559 def getOutputPaths(lldbRootDirectory):
561 Returns typical build output paths for the lldb executable
563 lldbDirectory - path to the root of the lldb svn/git repo
567 if sys.platform == 'darwin':
568 result.extend(getXcodeOutputPaths(lldbRootDirectory))
570 # cmake builds? look for build or build/host folder next to llvm directory
571 # lldb is located in llvm/tools/lldb so we need to go up three levels
572 llvmParentDir = os.path.abspath(
578 result.append(os.path.join(llvmParentDir, 'build', 'bin'))
579 result.append(os.path.join(llvmParentDir, 'build', 'host', 'bin'))
581 # some cmake developers keep their build directory beside their lldb
583 lldbParentDir = os.path.abspath(os.path.join(lldbRootDirectory, os.pardir))
584 result.append(os.path.join(lldbParentDir, 'build', 'bin'))
585 result.append(os.path.join(lldbParentDir, 'build', 'host', 'bin'))
592 Add LLDB.framework/Resources/Python to the search paths for modules.
593 As a side effect, we also discover the 'lldb' executable and export it here.
596 # Get the directory containing the current script.
597 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ:
598 scriptPath = os.environ["DOTEST_SCRIPT_DIR"]
600 scriptPath = os.path.dirname(os.path.realpath(__file__))
601 if not scriptPath.endswith('test'):
602 print("This script expects to reside in lldb's test directory.")
605 os.environ["LLDB_TEST"] = scriptPath
607 # Set up the LLDB_SRC environment variable, so that the tests can locate
608 # the LLDB source code.
609 os.environ["LLDB_SRC"] = lldbsuite.lldb_root
611 pluginPath = os.path.join(scriptPath, 'plugins')
612 toolsLLDBMIPath = os.path.join(scriptPath, 'tools', 'lldb-mi')
613 toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server')
615 # Insert script dir, plugin dir, lldb-mi dir and lldb-server dir to the
617 sys.path.insert(0, pluginPath)
618 # Adding test/tools/lldb-mi to the path makes it easy
619 sys.path.insert(0, toolsLLDBMIPath)
620 # to "import lldbmi_testcase" from the MI tests
621 # Adding test/tools/lldb-server to the path makes it easy
622 sys.path.insert(0, toolsLLDBServerPath)
623 # to "import lldbgdbserverutils" from the lldb-server tests
625 # This is the root of the lldb git/svn checkout
626 # When this changes over to a package instead of a standalone script, this
627 # will be `lldbsuite.lldb_root`
628 lldbRootDirectory = lldbsuite.lldb_root
630 # Some of the tests can invoke the 'lldb' command directly.
631 # We'll try to locate the appropriate executable right here.
633 # The lldb executable can be set from the command line
634 # if it's not set, we try to find it now
635 # first, we try the environment
636 if not lldbtest_config.lldbExec:
637 # First, you can define an environment variable LLDB_EXEC specifying the
638 # full pathname of the lldb executable.
639 if "LLDB_EXEC" in os.environ:
640 lldbtest_config.lldbExec = os.environ["LLDB_EXEC"]
642 if not lldbtest_config.lldbExec:
643 outputPaths = getOutputPaths(lldbRootDirectory)
644 for outputPath in outputPaths:
645 candidatePath = os.path.join(outputPath, 'lldb')
646 if is_exe(candidatePath):
647 lldbtest_config.lldbExec = candidatePath
650 if not lldbtest_config.lldbExec:
651 # Last, check the path
652 lldbtest_config.lldbExec = which('lldb')
654 if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec):
656 "'{}' is not a path to a valid executable".format(
657 lldbtest_config.lldbExec))
658 lldbtest_config.lldbExec = None
660 if not lldbtest_config.lldbExec:
661 print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.")
664 # confusingly, this is the "bin" directory
665 lldbLibDir = os.path.dirname(lldbtest_config.lldbExec)
666 os.environ["LLDB_LIB_DIR"] = lldbLibDir
667 lldbImpLibDir = os.path.join(
670 'lib') if sys.platform.startswith('win32') else lldbLibDir
671 os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir
672 print("LLDB library dir:", os.environ["LLDB_LIB_DIR"])
673 print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"])
674 os.system('%s -v' % lldbtest_config.lldbExec)
676 # Assume lldb-mi is in same place as lldb
677 # If not found, disable the lldb-mi tests
678 # TODO: Append .exe on Windows
679 # - this will be in a separate commit in case the mi tests fail horribly
680 lldbDir = os.path.dirname(lldbtest_config.lldbExec)
681 lldbMiExec = os.path.join(lldbDir, "lldb-mi")
682 if is_exe(lldbMiExec):
683 os.environ["LLDBMI_EXEC"] = lldbMiExec
685 if not configuration.shouldSkipBecauseOfCategories(["lldb-mi"]):
687 "The 'lldb-mi' executable cannot be located. The lldb-mi tests can not be run as a result.")
688 configuration.skipCategories.append("lldb-mi")
690 lldbPythonDir = None # The directory that contains 'lldb/__init__.py'
691 if not configuration.lldbFrameworkPath and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")):
692 configuration.lldbFrameworkPath = os.path.join(lldbLibDir, "LLDB.framework")
693 if configuration.lldbFrameworkPath:
694 lldbtest_config.lldbFrameworkPath = configuration.lldbFrameworkPath
695 candidatePath = os.path.join(
696 configuration.lldbFrameworkPath, 'Resources', 'Python')
697 if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')):
698 lldbPythonDir = candidatePath
699 if not lldbPythonDir:
701 'Resources/Python/lldb/__init__.py was not found in ' +
702 configuration.lldbFrameworkPath)
705 # If our lldb supports the -P option, use it to find the python path:
706 init_in_python_dir = os.path.join('lldb', '__init__.py')
708 lldb_dash_p_result = subprocess.check_output(
709 [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True)
711 if lldb_dash_p_result and not lldb_dash_p_result.startswith(
712 ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"):
713 lines = lldb_dash_p_result.splitlines()
715 # Workaround for readline vs libedit issue on FreeBSD. If stdout
716 # is not a terminal Python executes
717 # rl_variable_bind ("enable-meta-key", "off");
718 # This produces a warning with FreeBSD's libedit because the
719 # enable-meta-key variable is unknown. Not an issue on Apple
720 # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__
721 # around the call. See http://bugs.python.org/issue19884 for more
722 # information. For now we just discard the warning output.
723 if len(lines) >= 1 and lines[0].startswith(
724 "bind: Invalid command"):
727 # Taking the last line because lldb outputs
728 # 'Cannot read termcap database;\nusing dumb terminal settings.\n'
730 if len(lines) >= 1 and os.path.isfile(
731 os.path.join(lines[-1], init_in_python_dir)):
732 lldbPythonDir = lines[-1]
733 if "freebsd" in sys.platform or "linux" in sys.platform:
734 os.environ['LLDB_LIB_DIR'] = os.path.join(
735 lldbPythonDir, '..', '..')
737 if not lldbPythonDir:
738 if platform.system() == "Darwin":
739 python_resource_dir = ['LLDB.framework', 'Resources', 'Python']
740 outputPaths = getXcodeOutputPaths(lldbRootDirectory)
741 for outputPath in outputPaths:
742 candidatePath = os.path.join(
743 outputPath, *python_resource_dir)
747 init_in_python_dir)):
748 lldbPythonDir = candidatePath
751 if not lldbPythonDir:
752 print("lldb.py is not found, some tests may fail.")
755 "Unable to load lldb extension module. Possible reasons for this include:")
756 print(" 1) LLDB was built with LLDB_DISABLE_PYTHON=1")
758 " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to")
760 " the version of Python that LLDB built and linked against, and PYTHONPATH")
762 " should contain the Lib directory for the same python distro, as well as the")
763 print(" location of LLDB\'s site-packages folder.")
765 " 3) A different version of Python than that which was built against is exported in")
766 print(" the system\'s PATH environment variable, causing conflicts.")
768 " 4) The executable '%s' could not be found. Please check " %
769 lldbtest_config.lldbExec)
770 print(" that it exists and is executable.")
773 lldbPythonDir = os.path.normpath(lldbPythonDir)
774 # Some of the code that uses this path assumes it hasn't resolved the Versions... link.
775 # If the path we've constructed looks like that, then we'll strip out
776 # the Versions/A part.
777 (before, frameWithVersion, after) = lldbPythonDir.rpartition(
778 "LLDB.framework/Versions/A")
779 if frameWithVersion != "":
780 lldbPythonDir = before + "LLDB.framework" + after
782 lldbPythonDir = os.path.abspath(lldbPythonDir)
784 # If tests need to find LLDB_FRAMEWORK, now they can do it
785 os.environ["LLDB_FRAMEWORK"] = os.path.dirname(
786 os.path.dirname(lldbPythonDir))
788 # This is to locate the lldb.py module. Insert it right after
790 sys.path[1:1] = [lldbPythonDir]
793 def visit_file(dir, name):
794 # Try to match the regexp pattern, if specified.
795 if configuration.regexp:
796 if not re.search(configuration.regexp, name):
797 # We didn't match the regex, we're done.
800 if configuration.skip_tests:
801 for file_regexp in configuration.skip_tests:
802 if re.search(file_regexp, name):
805 # We found a match for our test. Add it to the suite.
807 # Update the sys.path first.
808 if not sys.path.count(dir):
809 sys.path.insert(0, dir)
810 base = os.path.splitext(name)[0]
812 # Thoroughly check the filterspec against the base module and admit
813 # the (base, filterspec) combination only when it makes sense.
815 for filterspec in configuration.filters:
816 # Optimistically set the flag to True.
818 module = __import__(base)
819 parts = filterspec.split('.')
823 parent, obj = obj, getattr(obj, part)
824 except AttributeError:
825 # The filterspec has failed.
829 # If filtered, we have a good filterspec. Add it.
831 # print("adding filter spec %s to module %s" % (filterspec, module))
832 configuration.suite.addTests(
833 unittest2.defaultTestLoader.loadTestsFromName(
837 # Forgo this module if the (base, filterspec) combo is invalid
838 if configuration.filters and not filtered:
841 if not filterspec or not filtered:
842 # Add the entire file's worth of tests since we're not filtered.
843 # Also the fail-over case when the filterspec branch
844 # (base, filterspec) combo doesn't make sense.
845 configuration.suite.addTests(
846 unittest2.defaultTestLoader.loadTestsFromName(base))
849 def visit(prefix, dir, names):
850 """Visitor function for os.path.walk(path, visit, arg)."""
852 dir_components = set(dir.split(os.sep))
853 excluded_components = set(['.svn', '.git'])
854 if dir_components.intersection(excluded_components):
857 # Gather all the Python test file names that follow the Test*.py pattern.
858 python_test_files = [
861 if name.endswith('.py') and name.startswith(prefix)]
863 # Visit all the python test files.
864 for name in python_test_files:
866 # Ensure we error out if we have multiple tests with the same
868 # Future improvement: find all the places where we work with base
869 # names and convert to full paths. We have directory structure
870 # to disambiguate these, so we shouldn't need this constraint.
871 if name in configuration.all_tests:
872 raise Exception("Found multiple tests with the name %s" % name)
873 configuration.all_tests.add(name)
875 # Run the relevant tests in the python file.
876 visit_file(dir, name)
877 except Exception as ex:
878 # Convert this exception to a test event error for the file.
879 test_filename = os.path.abspath(os.path.join(dir, name))
880 if configuration.results_formatter_object is not None:
881 # Grab the backtrace for the exception.
883 backtrace = traceback.format_exc()
885 # Generate the test event.
886 configuration.results_formatter_object.handle_event(
887 EventBuilder.event_for_job_test_add_error(
888 test_filename, ex, backtrace))
892 def disabledynamics():
894 ci = lldb.DBG.GetCommandInterpreter()
895 res = lldb.SBCommandReturnObject()
897 "setting set target.prefer-dynamic-value no-dynamic-values",
900 if not res.Succeeded():
901 raise Exception('disabling dynamic type support failed')
906 """Check and do lldb loggings if necessary."""
908 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
909 # defined. Use ${LLDB_LOG} to specify the log file.
910 ci = lldb.DBG.GetCommandInterpreter()
911 res = lldb.SBCommandReturnObject()
912 if ("LLDB_LOG" in os.environ):
913 open(os.environ["LLDB_LOG"], 'w').close()
914 if ("LLDB_LOG_OPTION" in os.environ):
915 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
917 lldb_log_option = "event process expr state api"
919 "log enable -n -f " +
920 os.environ["LLDB_LOG"] +
924 if not res.Succeeded():
925 raise Exception('log enable failed (check LLDB_LOG env variable)')
927 if ("LLDB_LINUX_LOG" in os.environ):
928 open(os.environ["LLDB_LINUX_LOG"], 'w').close()
929 if ("LLDB_LINUX_LOG_OPTION" in os.environ):
930 lldb_log_option = os.environ["LLDB_LINUX_LOG_OPTION"]
932 lldb_log_option = "event process expr state api"
934 "log enable -n -f " +
935 os.environ["LLDB_LINUX_LOG"] +
939 if not res.Succeeded():
941 'log enable failed (check LLDB_LINUX_LOG env variable)')
943 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
944 # Use ${GDB_REMOTE_LOG} to specify the log file.
945 if ("GDB_REMOTE_LOG" in os.environ):
946 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
947 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
949 gdb_remote_log_option = "packets process"
951 "log enable -n -f " + os.environ["GDB_REMOTE_LOG"] + " gdb-remote "
952 + gdb_remote_log_option,
954 if not res.Succeeded():
956 'log enable failed (check GDB_REMOTE_LOG env variable)')
959 def getMyCommandLine():
960 return ' '.join(sys.argv)
962 # ======================================== #
964 # Execution of the test driver starts here #
966 # ======================================== #
969 def checkDsymForUUIDIsNotOn():
970 cmd = ["defaults", "read", "com.apple.DebugSymbols"]
971 pipe = subprocess.Popen(
973 stdout=subprocess.PIPE,
974 stderr=subprocess.STDOUT)
975 cmd_output = pipe.stdout.read()
976 if cmd_output and "DBGFileMappedPaths = " in cmd_output:
977 print("%s =>" % ' '.join(cmd))
980 "Disable automatic lookup and caching of dSYMs before running the test suite!")
985 def exitTestSuite(exitCode=None):
987 lldb.SBDebugger.Terminate()
992 def isMultiprocessTestRunner():
993 # We're not multiprocess when we're either explicitly
994 # the inferior (as specified by the multiprocess test
995 # runner) OR we've been told to skip using the multiprocess
998 configuration.is_inferior_test_runner or configuration.no_multiprocess_test_runner)
1001 def getVersionForSDK(sdk):
1002 sdk = str.lower(sdk)
1003 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk)
1004 basename = os.path.basename(full_path)
1005 basename = os.path.splitext(basename)[0]
1006 basename = str.lower(basename)
1007 ver = basename.replace(sdk, '')
1011 def getPathForSDK(sdk):
1012 sdk = str.lower(sdk)
1013 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk)
1014 if os.path.exists(full_path):
1019 def setDefaultTripleForPlatform():
1020 if configuration.lldb_platform_name == 'ios-simulator':
1021 triple_str = 'x86_64-apple-ios%s' % (
1022 getVersionForSDK('iphonesimulator'))
1023 os.environ['TRIPLE'] = triple_str
1024 return {'TRIPLE': triple_str}
1029 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults
1030 # does not exist before proceeding to running the test suite.
1031 if sys.platform.startswith("darwin"):
1032 checkDsymForUUIDIsNotOn()
1035 # Start the actions by first parsing the options while setting up the test
1036 # directories, followed by setting up the search paths for lldb utilities;
1037 # then, we walk the directory trees and collect the tests into our test suite.
1039 parseOptionsAndInitTestdirs()
1041 # Setup test results (test results formatter and output handling).
1044 # If we are running as the multiprocess test runner, kick off the
1045 # multiprocess test runner here.
1046 if isMultiprocessTestRunner():
1049 configuration.num_threads,
1050 configuration.multiprocess_test_subdir,
1051 configuration.test_runner_name,
1052 configuration.results_formatter_object)
1053 raise Exception("should never get here")
1054 elif configuration.is_inferior_test_runner:
1055 # Shut off Ctrl-C processing in inferiors. The parallel
1056 # test runner handles this more holistically.
1057 signal.signal(signal.SIGINT, signal.SIG_IGN)
1060 configuration.setupCrashInfoHook()
1063 # If '-l' is specified, do not skip the long running tests.
1064 if not configuration.skip_long_running_test:
1065 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
1067 # For the time being, let's bracket the test runner within the
1068 # lldb.SBDebugger.Initialize()/Terminate() pair.
1071 # Create a singleton SBDebugger in the lldb namespace.
1072 lldb.DBG = lldb.SBDebugger.Create()
1074 if configuration.lldb_platform_name:
1075 print("Setting up remote platform '%s'" %
1076 (configuration.lldb_platform_name))
1077 lldb.remote_platform = lldb.SBPlatform(
1078 configuration.lldb_platform_name)
1079 if not lldb.remote_platform.IsValid():
1081 "error: unable to create the LLDB platform named '%s'." %
1082 (configuration.lldb_platform_name))
1084 if configuration.lldb_platform_url:
1085 # We must connect to a remote platform if a LLDB platform URL was
1088 "Connecting to remote platform '%s' at '%s'..." %
1089 (configuration.lldb_platform_name, configuration.lldb_platform_url))
1090 platform_connect_options = lldb.SBPlatformConnectOptions(
1091 configuration.lldb_platform_url)
1092 err = lldb.remote_platform.ConnectRemote(platform_connect_options)
1096 print("error: failed to connect to remote platform using URL '%s': %s" % (
1097 configuration.lldb_platform_url, err))
1100 configuration.lldb_platform_url = None
1102 platform_changes = setDefaultTripleForPlatform()
1104 for key in platform_changes:
1106 print("Environment variables setup for platform support:")
1108 print("%s = %s" % (key, platform_changes[key]))
1110 if configuration.lldb_platform_working_dir:
1111 print("Setting remote platform working directory to '%s'..." %
1112 (configuration.lldb_platform_working_dir))
1113 lldb.remote_platform.SetWorkingDirectory(
1114 configuration.lldb_platform_working_dir)
1115 lldb.DBG.SetSelectedPlatform(lldb.remote_platform)
1117 lldb.remote_platform = None
1118 configuration.lldb_platform_working_dir = None
1119 configuration.lldb_platform_url = None
1121 target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2]
1123 # Don't do debugserver tests on everything except OS X.
1124 configuration.dont_do_debugserver_test = "linux" in target_platform or "freebsd" in target_platform or "windows" in target_platform
1126 # Don't do lldb-server (llgs) tests on anything except Linux.
1127 configuration.dont_do_llgs_test = not ("linux" in target_platform)
1130 # Walk through the testdirs while collecting tests.
1132 for testdir in configuration.testdirs:
1133 for (dirpath, dirnames, filenames) in os.walk(testdir):
1134 visit('Test', dirpath, filenames)
1137 # Now that we have loaded all the test cases, run the whole test suite.
1140 # Turn on lldb loggings if necessary.
1143 # Disable default dynamic types for testing purposes
1146 # Install the control-c handler.
1147 unittest2.signals.installHandler()
1149 # If sdir_name is not specified through the '-s sdir_name' option, get a
1150 # timestamp string and export it as LLDB_SESSION_DIR environment var. This will
1151 # be used when/if we want to dump the session info of individual test cases
1154 # See also TestBase.dumpSessionInfo() in lldbtest.py.
1156 # The windows platforms don't like ':' in the pathname.
1157 timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
1158 if not configuration.sdir_name:
1159 configuration.sdir_name = timestamp_started
1160 os.environ["LLDB_SESSION_DIRNAME"] = os.path.join(
1161 os.getcwd(), configuration.sdir_name)
1164 "\nSession logs for test failures/errors/unexpected successes"
1165 " will go into directory '%s'\n" %
1166 configuration.sdir_name)
1167 sys.stderr.write("Command invoked: %s\n" % getMyCommandLine())
1169 if not os.path.isdir(configuration.sdir_name):
1171 os.mkdir(configuration.sdir_name)
1172 except OSError as exception:
1173 if exception.errno != errno.EEXIST:
1177 # Invoke the default TextTestRunner to run the test suite, possibly iterating
1178 # over different configurations.
1182 iterCompilers = False
1184 if isinstance(configuration.archs, list) and len(configuration.archs) >= 1:
1188 # Add some intervention here to sanity check that the compilers requested are sane.
1189 # If found not to be an executable program, the invalid one is dropped
1191 for i in range(len(configuration.compilers)):
1192 c = configuration.compilers[i]
1196 if sys.platform.startswith("darwin"):
1197 pipe = subprocess.Popen(
1198 ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
1199 cmd_output = pipe.stdout.read()
1201 if "not found" in cmd_output:
1202 print("dropping %s from the compilers used" % c)
1203 configuration.compilers.remove(i)
1205 configuration.compilers[i] = cmd_output.split('\n')[0]
1207 "'xcrun -find %s' returning %s" %
1208 (c, configuration.compilers[i]))
1210 if not configuration.parsable:
1211 print("compilers=%s" % str(configuration.compilers))
1213 if not configuration.compilers or len(configuration.compilers) == 0:
1214 print("No eligible compiler found, exiting.")
1218 configuration.compilers,
1220 configuration.compilers) >= 1:
1221 iterCompilers = True
1223 # If we iterate on archs or compilers, there is a chance we want to split
1225 if iterArchs or iterCompilers:
1226 old_stderr = sys.stderr
1227 old_stdout = sys.stdout
1231 # Iterating over all possible architecture and compiler combinations.
1232 for ia in range(len(configuration.archs) if iterArchs else 1):
1235 os.environ["ARCH"] = configuration.archs[ia]
1236 archConfig = "arch=%s" % configuration.archs[ia]
1237 for ic in range(len(configuration.compilers) if iterCompilers else 1):
1239 os.environ["CC"] = configuration.compilers[ic]
1240 configString = "%s compiler=%s" % (
1241 archConfig, configuration.compilers[ic])
1243 configString = archConfig
1245 if iterArchs or iterCompilers:
1246 # Translate ' ' to '-' for pathname component.
1249 tbl = string.maketrans(' ', '-')
1251 tbl = str.maketrans(' ', '-')
1252 configPostfix = configString.translate(tbl)
1254 # Output the configuration.
1255 if not configuration.parsable:
1256 sys.stderr.write("\nConfiguration: " + configString + "\n")
1258 #print("sys.stderr name is", sys.stderr.name)
1259 #print("sys.stdout name is", sys.stdout.name)
1261 # First, write out the number of collected test cases.
1262 if not configuration.parsable:
1263 sys.stderr.write(configuration.separator + "\n")
1265 "Collected %d test%s\n\n" %
1266 (configuration.suite.countTestCases(),
1267 configuration.suite.countTestCases() != 1 and "s" or ""))
1269 if configuration.parsable:
1272 v = configuration.verbose
1274 # Invoke the test runner.
1275 if configuration.count == 1:
1276 result = unittest2.TextTestRunner(
1279 resultclass=test_result.LLDBTestResult).run(
1280 configuration.suite)
1282 # We are invoking the same test suite more than once. In this case,
1283 # mark __ignore_singleton__ flag as True so the signleton pattern is
1285 test_result.LLDBTestResult.__ignore_singleton__ = True
1286 for i in range(configuration.count):
1288 result = unittest2.TextTestRunner(
1291 resultclass=test_result.LLDBTestResult).run(
1292 configuration.suite)
1294 configuration.failed = configuration.failed or not result.wasSuccessful()
1296 if configuration.sdir_has_content and not configuration.parsable:
1298 "Session logs for test failures/errors/unexpected successes"
1299 " can be found in directory '%s'\n" %
1300 configuration.sdir_name)
1302 if configuration.useCategories and len(
1303 configuration.failuresPerCategory) > 0:
1304 sys.stderr.write("Failures per category:\n")
1305 for category in configuration.failuresPerCategory:
1308 (category, configuration.failuresPerCategory[category]))
1310 # Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
1311 # This should not be necessary now.
1312 if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
1313 print("Terminating Test suite...")
1314 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
1317 exitTestSuite(configuration.failed)
1319 if __name__ == "__main__":
1322 " is for use as a module only. It should not be run as a standalone script.")