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
43 from . import configuration
44 from . import dotest_args
45 from . import lldbtest_config
46 from . import test_categories
47 from lldbsuite
.test_event
import formatter
48 from . import test_result
49 from lldbsuite
.test_event
.event_builder
import EventBuilder
50 from ..support
import seven
52 def get_dotest_invocation():
53 return ' '.join(sys
.argv
)
57 """Returns true if fpath is an executable."""
60 return os
.path
.isfile(fpath
) and os
.access(fpath
, os
.X_OK
)
64 """Returns the full path to a program; None otherwise."""
65 fpath
, _
= os
.path
.split(program
)
70 for path
in os
.environ
["PATH"].split(os
.pathsep
):
71 exe_file
= os
.path
.join(path
, program
)
79 if configuration
.verbose
> 0:
83 This is an example of using the -f option to pinpoint to a specific test class
84 and test method to be run:
86 $ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command
87 ----------------------------------------------------------------------
90 test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
91 Test 'frame variable this' when stopped on a class constructor. ... ok
93 ----------------------------------------------------------------------
98 And this is an example of using the -p option to run a single file (the filename
99 matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
101 $ ./dotest.py -v -p ObjC
102 ----------------------------------------------------------------------
105 test_break_with_dsym (TestObjCMethods.FoundationTestCase)
106 Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
107 test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
108 Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
109 test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
110 Lookup objective-c data types and evaluate expressions. ... ok
111 test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
112 Lookup objective-c data types and evaluate expressions. ... ok
114 ----------------------------------------------------------------------
115 Ran 4 tests in 16.661s
119 Running of this script also sets up the LLDB_TEST environment variable so that
120 individual test cases can locate their supporting files correctly. The script
121 tries to set up Python's search paths for modules by looking at the build tree
122 relative to this script. See also the '-i' option in the following example.
124 Finally, this is an example of using the lldb.py module distributed/installed by
125 Xcode4 to run against the tests under the 'forward' directory, and with the '-w'
126 option to add some delay between two tests. It uses ARCH=x86_64 to specify that
127 as the architecture and CC=clang to specify the compiler used for the test run:
129 $ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward
131 Session logs for test failures/errors will go into directory '2010-11-11-13_56_16'
132 ----------------------------------------------------------------------
135 test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
136 Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
137 test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
138 Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
140 ----------------------------------------------------------------------
141 Ran 2 tests in 5.659s
145 The 'Session ...' verbiage is recently introduced (see also the '-s' option) to
146 notify the directory containing the session logs for test failures or errors.
147 In case there is any test failure/error, a similar message is appended at the
148 end of the stderr output for your convenience.
150 ENABLING LOGS FROM TESTS
154 Writing logs into different files per test case::
156 $ ./dotest.py --channel "lldb all"
158 $ ./dotest.py --channel "lldb all" --channel "gdb-remote packets"
160 These log files are written to:
162 <session-dir>/<test-id>-host.log (logs from lldb host process)
163 <session-dir>/<test-id>-server.log (logs from debugserver/lldb-server)
164 <session-dir>/<test-id>-<test-result>.log (console logs)
166 By default, logs from successful runs are deleted. Use the --log-success flag
167 to create reference logs for debugging.
169 $ ./dotest.py --log-success
175 def parseExclusion(exclusion_file
):
176 """Parse an exclusion file, of the following format, where
177 'skip files', 'skip methods', 'xfail files', and 'xfail methods'
178 are the possible list heading values:
189 with
open(exclusion_file
) as f
:
198 elif excl_type
== 'skip':
199 if not configuration
.skip_tests
:
200 configuration
.skip_tests
= []
201 configuration
.skip_tests
.append(line
)
202 elif excl_type
== 'xfail':
203 if not configuration
.xfail_tests
:
204 configuration
.xfail_tests
= []
205 configuration
.xfail_tests
.append(line
)
208 def parseOptionsAndInitTestdirs():
209 """Initialize the list of directories containing our unittest scripts.
211 '-h/--help as the first option prints out usage info and exit the program.
216 platform_system
= platform
.system()
217 platform_machine
= platform
.machine()
220 parser
= dotest_args
.create_parser()
221 args
= parser
.parse_args()
223 print(get_dotest_invocation())
226 if args
.unset_env_varnames
:
227 for env_var
in args
.unset_env_varnames
:
228 if env_var
in os
.environ
:
229 # From Python Doc: When unsetenv() is supported, deletion of items in os.environ
230 # is automatically translated into a corresponding call to
232 del os
.environ
[env_var
]
233 # os.unsetenv(env_var)
235 if args
.set_env_vars
:
236 for env_var
in args
.set_env_vars
:
237 parts
= env_var
.split('=', 1)
239 os
.environ
[parts
[0]] = ""
241 os
.environ
[parts
[0]] = parts
[1]
243 if args
.set_inferior_env_vars
:
244 lldbtest_config
.inferior_env
= ' '.join(args
.set_inferior_env_vars
)
246 # Only print the args if being verbose.
248 print(get_dotest_invocation())
254 configuration
.compiler
= os
.path
.realpath(args
.compiler
)
255 if not is_exe(configuration
.compiler
):
256 configuration
.compiler
= which(args
.compiler
)
257 if not is_exe(configuration
.compiler
):
259 '%s is not a valid compiler executable; aborting...',
263 # Use a compiler appropriate appropriate for the Apple SDK if one was
265 if platform_system
== 'Darwin' and args
.apple_sdk
:
266 configuration
.compiler
= seven
.get_command_output(
267 'xcrun -sdk "%s" -find clang 2> /dev/null' %
270 # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first
271 candidateCompilers
= ['clang-3.5', 'clang', 'gcc']
272 for candidate
in candidateCompilers
:
274 configuration
.compiler
= candidate
278 os
.environ
['DSYMUTIL'] = args
.dsymutil
279 elif platform_system
== 'Darwin':
280 os
.environ
['DSYMUTIL'] = seven
.get_command_output(
281 'xcrun -find -toolchain default dsymutil')
284 # The lldb-dotest script produced by the CMake build passes in a path
285 # to a working FileCheck binary. So does one specific Xcode project
286 # target. However, when invoking dotest.py directly, a valid --filecheck
287 # option needs to be given.
288 configuration
.filecheck
= os
.path
.abspath(args
.filecheck
)
290 if not configuration
.get_filecheck_path():
291 logging
.warning('No valid FileCheck executable; some tests may fail...')
292 logging
.warning('(Double-check the --filecheck argument to dotest.py)')
295 lldbtest_config
.channels
= args
.channels
298 lldbtest_config
.log_success
= args
.log_success
300 if args
.out_of_tree_debugserver
:
301 lldbtest_config
.out_of_tree_debugserver
= args
.out_of_tree_debugserver
303 # Set SDKROOT if we are using an Apple SDK
304 if platform_system
== 'Darwin' and args
.apple_sdk
:
305 os
.environ
['SDKROOT'] = seven
.get_command_output(
306 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' %
310 configuration
.arch
= args
.arch
311 if configuration
.arch
.startswith(
312 'arm') and platform_system
== 'Darwin' and not args
.apple_sdk
:
313 os
.environ
['SDKROOT'] = seven
.get_command_output(
314 'xcrun --sdk iphoneos.internal --show-sdk-path 2> /dev/null')
315 if not os
.path
.exists(os
.environ
['SDKROOT']):
316 os
.environ
['SDKROOT'] = seven
.get_command_output(
317 'xcrun --sdk iphoneos --show-sdk-path 2> /dev/null')
319 configuration
.arch
= platform_machine
321 if args
.categories_list
:
322 configuration
.categories_list
= set(
323 test_categories
.validate(
324 args
.categories_list
, False))
325 configuration
.use_categories
= True
327 configuration
.categories_list
= []
329 if args
.skip_categories
:
330 configuration
.skip_categories
+= test_categories
.validate(
331 args
.skip_categories
, False)
333 if args
.xfail_categories
:
334 configuration
.xfail_categories
+= test_categories
.validate(
335 args
.xfail_categories
, False)
338 os
.environ
['CFLAGS_EXTRAS'] = args
.E
340 if args
.dwarf_version
:
341 configuration
.dwarf_version
= args
.dwarf_version
342 # We cannot modify CFLAGS_EXTRAS because they're used in test cases
343 # that explicitly require no debug info.
344 os
.environ
['CFLAGS'] = '-gdwarf-{}'.format(configuration
.dwarf_version
)
347 for setting
in args
.settings
:
348 if not len(setting
) == 1 or not setting
[0].count('='):
349 logging
.error('"%s" is not a setting in the form "key=value"',
352 configuration
.settings
.append(setting
[0].split('=', 1))
356 "Suspending the process %d to wait for debugger to attach...\n" %
359 os
.kill(os
.getpid(), signal
.SIGSTOP
)
362 if any([x
.startswith('-') for x
in args
.f
]):
364 configuration
.filters
.extend(args
.f
)
367 configuration
.lldb_framework_path
= args
.framework
370 # lldb executable is passed explicitly
371 lldbtest_config
.lldbExec
= os
.path
.realpath(args
.executable
)
372 if not is_exe(lldbtest_config
.lldbExec
):
373 lldbtest_config
.lldbExec
= which(args
.executable
)
374 if not is_exe(lldbtest_config
.lldbExec
):
376 '%s is not a valid executable to test; aborting...',
381 os
.environ
['LLDB_DEBUGSERVER_PATH'] = args
.server
384 for excl_file
in args
.excluded
:
385 parseExclusion(excl_file
)
388 if args
.p
.startswith('-'):
390 configuration
.regexp
= args
.p
393 configuration
.sdir_name
= args
.s
395 timestamp_started
= datetime
.datetime
.now().strftime("%Y-%m-%d-%H_%M_%S")
396 configuration
.sdir_name
= os
.path
.join(os
.getcwd(), timestamp_started
)
398 configuration
.session_file_format
= args
.session_file_format
401 os
.environ
['LLDB_COMMAND_TRACE'] = 'YES'
404 configuration
.verbose
= 2
406 # argparse makes sure we have a number
408 configuration
.count
= args
.sharp
410 if sys
.platform
.startswith('win32'):
411 os
.environ
['LLDB_DISABLE_CRASH_DIALOG'] = str(
412 args
.disable_crash_dialog
)
413 os
.environ
['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True)
418 if args
.results_file
:
419 configuration
.results_filename
= args
.results_file
421 if args
.results_formatter
:
422 configuration
.results_formatter_name
= args
.results_formatter
423 if args
.results_formatter_options
:
424 configuration
.results_formatter_options
= args
.results_formatter_options
426 # Default to using the BasicResultsFormatter if no formatter is specified.
427 if configuration
.results_formatter_name
is None:
428 configuration
.results_formatter_name
= (
429 "lldbsuite.test_event.formatter.results_formatter.ResultsFormatter")
431 # rerun-related arguments
432 configuration
.rerun_all_issues
= args
.rerun_all_issues
434 if args
.lldb_platform_name
:
435 configuration
.lldb_platform_name
= args
.lldb_platform_name
436 if args
.lldb_platform_url
:
437 configuration
.lldb_platform_url
= args
.lldb_platform_url
438 if args
.lldb_platform_working_dir
:
439 configuration
.lldb_platform_working_dir
= args
.lldb_platform_working_dir
440 if args
.test_build_dir
:
441 configuration
.test_build_dir
= args
.test_build_dir
442 if args
.lldb_module_cache_dir
:
443 configuration
.lldb_module_cache_dir
= args
.lldb_module_cache_dir
445 configuration
.lldb_module_cache_dir
= os
.path
.join(
446 configuration
.test_build_dir
, 'module-cache-lldb')
447 if args
.clang_module_cache_dir
:
448 configuration
.clang_module_cache_dir
= args
.clang_module_cache_dir
450 configuration
.clang_module_cache_dir
= os
.path
.join(
451 configuration
.test_build_dir
, 'module-cache-clang')
453 os
.environ
['CLANG_MODULE_CACHE_DIR'] = configuration
.clang_module_cache_dir
455 # Gather all the dirs passed on the command line.
456 if len(args
.args
) > 0:
457 configuration
.testdirs
= [os
.path
.realpath(os
.path
.abspath(x
)) for x
in args
.args
]
459 lldbtest_config
.codesign_identity
= args
.codesign_identity
462 def setupTestResults():
463 """Sets up test results-related objects based on arg settings."""
464 # Setup the results formatter configuration.
465 formatter_config
= formatter
.FormatterConfig()
466 formatter_config
.filename
= configuration
.results_filename
467 formatter_config
.formatter_name
= configuration
.results_formatter_name
468 formatter_config
.formatter_options
= (
469 configuration
.results_formatter_options
)
471 # Create the results formatter.
472 formatter_spec
= formatter
.create_results_formatter(
474 if formatter_spec
is not None and formatter_spec
.formatter
is not None:
475 configuration
.results_formatter_object
= formatter_spec
.formatter
477 # Send an initialize message to the formatter.
478 initialize_event
= EventBuilder
.bare_event("initialize")
479 initialize_event
["worker_count"] = 1
481 formatter_spec
.formatter
.handle_event(initialize_event
)
483 # Make sure we clean up the formatter on shutdown.
484 if formatter_spec
.cleanup_func
is not None:
485 atexit
.register(formatter_spec
.cleanup_func
)
490 Add LLDB.framework/Resources/Python to the search paths for modules.
491 As a side effect, we also discover the 'lldb' executable and export it here.
494 # Get the directory containing the current script.
495 if "DOTEST_PROFILE" in os
.environ
and "DOTEST_SCRIPT_DIR" in os
.environ
:
496 scriptPath
= os
.environ
["DOTEST_SCRIPT_DIR"]
498 scriptPath
= os
.path
.dirname(os
.path
.realpath(__file__
))
499 if not scriptPath
.endswith('test'):
500 print("This script expects to reside in lldb's test directory.")
503 os
.environ
["LLDB_TEST"] = scriptPath
505 # Set up the root build directory.
506 builddir
= configuration
.test_build_dir
507 if not configuration
.test_build_dir
:
508 raise Exception("test_build_dir is not set")
509 os
.environ
["LLDB_BUILD"] = os
.path
.abspath(configuration
.test_build_dir
)
511 # Set up the LLDB_SRC environment variable, so that the tests can locate
512 # the LLDB source code.
513 os
.environ
["LLDB_SRC"] = lldbsuite
.lldb_root
515 pluginPath
= os
.path
.join(scriptPath
, 'plugins')
516 toolsLLDBVSCode
= os
.path
.join(scriptPath
, 'tools', 'lldb-vscode')
517 toolsLLDBServerPath
= os
.path
.join(scriptPath
, 'tools', 'lldb-server')
519 # Insert script dir, plugin dir and lldb-server dir to the sys.path.
520 sys
.path
.insert(0, pluginPath
)
521 # Adding test/tools/lldb-vscode to the path makes it easy to
522 # "import lldb_vscode_testcase" from the VSCode tests
523 sys
.path
.insert(0, toolsLLDBVSCode
)
524 # Adding test/tools/lldb-server to the path makes it easy
525 sys
.path
.insert(0, toolsLLDBServerPath
)
526 # to "import lldbgdbserverutils" from the lldb-server tests
528 # This is the root of the lldb git/svn checkout
529 # When this changes over to a package instead of a standalone script, this
530 # will be `lldbsuite.lldb_root`
531 lldbRootDirectory
= lldbsuite
.lldb_root
533 # Some of the tests can invoke the 'lldb' command directly.
534 # We'll try to locate the appropriate executable right here.
536 # The lldb executable can be set from the command line
537 # if it's not set, we try to find it now
538 # first, we try the environment
539 if not lldbtest_config
.lldbExec
:
540 # First, you can define an environment variable LLDB_EXEC specifying the
541 # full pathname of the lldb executable.
542 if "LLDB_EXEC" in os
.environ
:
543 lldbtest_config
.lldbExec
= os
.environ
["LLDB_EXEC"]
545 if not lldbtest_config
.lldbExec
:
546 # Last, check the path
547 lldbtest_config
.lldbExec
= which('lldb')
549 if lldbtest_config
.lldbExec
and not is_exe(lldbtest_config
.lldbExec
):
551 "'{}' is not a path to a valid executable".format(
552 lldbtest_config
.lldbExec
))
553 lldbtest_config
.lldbExec
= None
555 if not lldbtest_config
.lldbExec
:
556 print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.")
559 # confusingly, this is the "bin" directory
560 lldbLibDir
= os
.path
.dirname(lldbtest_config
.lldbExec
)
561 os
.environ
["LLDB_LIB_DIR"] = lldbLibDir
562 lldbImpLibDir
= os
.path
.join(
565 'lib') if sys
.platform
.startswith('win32') else lldbLibDir
566 os
.environ
["LLDB_IMPLIB_DIR"] = lldbImpLibDir
567 print("LLDB library dir:", os
.environ
["LLDB_LIB_DIR"])
568 print("LLDB import library dir:", os
.environ
["LLDB_IMPLIB_DIR"])
569 os
.system('%s -v' % lldbtest_config
.lldbExec
)
571 lldbDir
= os
.path
.dirname(lldbtest_config
.lldbExec
)
573 lldbVSCodeExec
= os
.path
.join(lldbDir
, "lldb-vscode")
574 if is_exe(lldbVSCodeExec
):
575 os
.environ
["LLDBVSCODE_EXEC"] = lldbVSCodeExec
577 if not configuration
.shouldSkipBecauseOfCategories(["lldb-vscode"]):
579 "The 'lldb-vscode' executable cannot be located. The lldb-vscode tests can not be run as a result.")
580 configuration
.skip_categories
.append("lldb-vscode")
582 lldbPythonDir
= None # The directory that contains 'lldb/__init__.py'
583 if not configuration
.lldb_framework_path
and os
.path
.exists(os
.path
.join(lldbLibDir
, "LLDB.framework")):
584 configuration
.lldb_framework_path
= os
.path
.join(lldbLibDir
, "LLDB.framework")
585 if configuration
.lldb_framework_path
:
586 lldbtest_config
.lldb_framework_path
= configuration
.lldb_framework_path
587 candidatePath
= os
.path
.join(
588 configuration
.lldb_framework_path
, 'Resources', 'Python')
589 if os
.path
.isfile(os
.path
.join(candidatePath
, 'lldb/__init__.py')):
590 lldbPythonDir
= candidatePath
591 if not lldbPythonDir
:
593 'Resources/Python/lldb/__init__.py was not found in ' +
594 configuration
.lldb_framework_path
)
597 # If our lldb supports the -P option, use it to find the python path:
598 init_in_python_dir
= os
.path
.join('lldb', '__init__.py')
600 lldb_dash_p_result
= subprocess
.check_output(
601 [lldbtest_config
.lldbExec
, "-P"], stderr
=subprocess
.STDOUT
, universal_newlines
=True)
603 if lldb_dash_p_result
and not lldb_dash_p_result
.startswith(
604 ("<", "lldb: invalid option:")) and not lldb_dash_p_result
.startswith("Traceback"):
605 lines
= lldb_dash_p_result
.splitlines()
607 # Workaround for readline vs libedit issue on FreeBSD. If stdout
608 # is not a terminal Python executes
609 # rl_variable_bind ("enable-meta-key", "off");
610 # This produces a warning with FreeBSD's libedit because the
611 # enable-meta-key variable is unknown. Not an issue on Apple
612 # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__
613 # around the call. See http://bugs.python.org/issue19884 for more
614 # information. For now we just discard the warning output.
615 if len(lines
) >= 1 and lines
[0].startswith(
616 "bind: Invalid command"):
619 # Taking the last line because lldb outputs
620 # 'Cannot read termcap database;\nusing dumb terminal settings.\n'
622 if len(lines
) >= 1 and os
.path
.isfile(
623 os
.path
.join(lines
[-1], init_in_python_dir
)):
624 lldbPythonDir
= lines
[-1]
625 if "freebsd" in sys
.platform
or "linux" in sys
.platform
:
626 os
.environ
['LLDB_LIB_DIR'] = os
.path
.join(
627 lldbPythonDir
, '..', '..')
629 if not lldbPythonDir
:
631 "Unable to load lldb extension module. Possible reasons for this include:")
632 print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0")
634 " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to")
636 " the version of Python that LLDB built and linked against, and PYTHONPATH")
638 " should contain the Lib directory for the same python distro, as well as the")
639 print(" location of LLDB\'s site-packages folder.")
641 " 3) A different version of Python than that which was built against is exported in")
642 print(" the system\'s PATH environment variable, causing conflicts.")
644 " 4) The executable '%s' could not be found. Please check " %
645 lldbtest_config
.lldbExec
)
646 print(" that it exists and is executable.")
649 lldbPythonDir
= os
.path
.normpath(lldbPythonDir
)
650 # Some of the code that uses this path assumes it hasn't resolved the Versions... link.
651 # If the path we've constructed looks like that, then we'll strip out
652 # the Versions/A part.
653 (before
, frameWithVersion
, after
) = lldbPythonDir
.rpartition(
654 "LLDB.framework/Versions/A")
655 if frameWithVersion
!= "":
656 lldbPythonDir
= before
+ "LLDB.framework" + after
658 lldbPythonDir
= os
.path
.abspath(lldbPythonDir
)
660 # If tests need to find LLDB_FRAMEWORK, now they can do it
661 os
.environ
["LLDB_FRAMEWORK"] = os
.path
.dirname(
662 os
.path
.dirname(lldbPythonDir
))
664 # This is to locate the lldb.py module. Insert it right after
666 sys
.path
[1:1] = [lldbPythonDir
]
669 def visit_file(dir, name
):
670 # Try to match the regexp pattern, if specified.
671 if configuration
.regexp
:
672 if not re
.search(configuration
.regexp
, name
):
673 # We didn't match the regex, we're done.
676 if configuration
.skip_tests
:
677 for file_regexp
in configuration
.skip_tests
:
678 if re
.search(file_regexp
, name
):
681 # We found a match for our test. Add it to the suite.
683 # Update the sys.path first.
684 if not sys
.path
.count(dir):
685 sys
.path
.insert(0, dir)
686 base
= os
.path
.splitext(name
)[0]
688 # Thoroughly check the filterspec against the base module and admit
689 # the (base, filterspec) combination only when it makes sense.
691 def check(obj
, parts
):
694 parent
, obj
= obj
, getattr(obj
, part
)
695 except AttributeError:
696 # The filterspec has failed.
700 module
= __import__(base
)
703 for filterspec
in configuration
.filters
:
704 parts
= filterspec
.split('.')
705 if check(module
, parts
):
707 elif parts
[0] == base
and len(parts
) > 1 and check(module
, parts
[1:]):
708 yield '.'.join(parts
[1:])
710 for key
,value
in module
.__dict
__.items():
711 if check(value
, parts
):
712 yield key
+ '.' + filterspec
715 for filterspec
in iter_filters():
717 print("adding filter spec %s to module %s" % (filterspec
, repr(module
)))
718 tests
= unittest2
.defaultTestLoader
.loadTestsFromName(filterspec
, module
)
719 configuration
.suite
.addTests(tests
)
721 # Forgo this module if the (base, filterspec) combo is invalid
722 if configuration
.filters
and not filtered
:
726 # Add the entire file's worth of tests since we're not filtered.
727 # Also the fail-over case when the filterspec branch
728 # (base, filterspec) combo doesn't make sense.
729 configuration
.suite
.addTests(
730 unittest2
.defaultTestLoader
.loadTestsFromName(base
))
733 def visit(prefix
, dir, names
):
734 """Visitor function for os.path.walk(path, visit, arg)."""
736 dir_components
= set(dir.split(os
.sep
))
737 excluded_components
= set(['.svn', '.git'])
738 if dir_components
.intersection(excluded_components
):
741 # Gather all the Python test file names that follow the Test*.py pattern.
742 python_test_files
= [
745 if name
.endswith('.py') and name
.startswith(prefix
)]
747 # Visit all the python test files.
748 for name
in python_test_files
:
750 # Ensure we error out if we have multiple tests with the same
752 # Future improvement: find all the places where we work with base
753 # names and convert to full paths. We have directory structure
754 # to disambiguate these, so we shouldn't need this constraint.
755 if name
in configuration
.all_tests
:
756 raise Exception("Found multiple tests with the name %s" % name
)
757 configuration
.all_tests
.add(name
)
759 # Run the relevant tests in the python file.
760 visit_file(dir, name
)
761 except Exception as ex
:
762 # Convert this exception to a test event error for the file.
763 test_filename
= os
.path
.abspath(os
.path
.join(dir, name
))
764 if configuration
.results_formatter_object
is not None:
765 # Grab the backtrace for the exception.
767 backtrace
= traceback
.format_exc()
769 # Generate the test event.
770 configuration
.results_formatter_object
.handle_event(
771 EventBuilder
.event_for_job_test_add_error(
772 test_filename
, ex
, backtrace
))
776 def setSetting(setting
, value
):
778 ci
= lldb
.DBG
.GetCommandInterpreter()
779 res
= lldb
.SBCommandReturnObject()
780 cmd
= 'setting set %s %s'%(setting
, value
)
782 ci
.HandleCommand(cmd
, res
, False)
783 if not res
.Succeeded():
784 raise Exception('failed to run "%s"'%cmd
)
786 # ======================================== #
788 # Execution of the test driver starts here #
790 # ======================================== #
793 def checkDsymForUUIDIsNotOn():
794 cmd
= ["defaults", "read", "com.apple.DebugSymbols"]
795 process
= subprocess
.Popen(
797 stdout
=subprocess
.PIPE
,
798 stderr
=subprocess
.STDOUT
)
799 cmd_output
= process
.stdout
.read()
800 output_str
= cmd_output
.decode("utf-8")
801 if "DBGFileMappedPaths = " in output_str
:
802 print("%s =>" % ' '.join(cmd
))
805 "Disable automatic lookup and caching of dSYMs before running the test suite!")
810 def exitTestSuite(exitCode
=None):
812 lldb
.SBDebugger
.Terminate()
817 def getVersionForSDK(sdk
):
819 full_path
= seven
.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk
)
820 basename
= os
.path
.basename(full_path
)
821 basename
= os
.path
.splitext(basename
)[0]
822 basename
= str.lower(basename
)
823 ver
= basename
.replace(sdk
, '')
827 def setDefaultTripleForPlatform():
828 if configuration
.lldb_platform_name
== 'ios-simulator':
829 triple_str
= 'x86_64-apple-ios%s' % (
830 getVersionForSDK('iphonesimulator'))
831 os
.environ
['TRIPLE'] = triple_str
832 return {'TRIPLE': triple_str
}
837 # Add some intervention here to sanity check that the compiler requested is sane.
838 # If found not to be an executable program, we abort.
839 c
= configuration
.compiler
843 if not sys
.platform
.startswith("darwin"):
844 raise Exception(c
+ " is not a valid compiler")
846 pipe
= subprocess
.Popen(
847 ['xcrun', '-find', c
], stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
848 cmd_output
= pipe
.stdout
.read()
849 if not cmd_output
or "not found" in cmd_output
:
850 raise Exception(c
+ " is not a valid compiler")
852 configuration
.compiler
= cmd_output
.split('\n')[0]
853 print("'xcrun -find %s' returning %s" % (c
, configuration
.compiler
))
855 def canRunLibcxxTests():
856 from lldbsuite
.test
import lldbplatformutil
858 platform
= lldbplatformutil
.getPlatform()
860 if lldbplatformutil
.target_is_android() or lldbplatformutil
.platformIsDarwin():
861 return True, "libc++ always present"
863 if platform
== "linux":
864 if os
.path
.isdir("/usr/include/c++/v1"):
865 return True, "Headers found, let's hope they work"
866 with tempfile
.NamedTemporaryFile() as f
:
867 cmd
= [configuration
.compiler
, "-xc++", "-stdlib=libc++", "-o", f
.name
, "-"]
868 p
= subprocess
.Popen(cmd
, stdin
=subprocess
.PIPE
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
, universal_newlines
=True)
869 _
, stderr
= p
.communicate("#include <algorithm>\nint main() {}")
871 return True, "Compiling with -stdlib=libc++ works"
872 return False, "Compiling with -stdlib=libc++ fails with the error: %s" % stderr
874 return False, "Don't know how to build with libc++ on %s" % platform
876 def checkLibcxxSupport():
877 result
, reason
= canRunLibcxxTests()
879 return # libc++ supported
880 if "libc++" in configuration
.categories_list
:
881 return # libc++ category explicitly requested, let it run.
882 print("Libc++ tests will not be run because: " + reason
)
883 configuration
.skip_categories
.append("libc++")
885 def canRunLibstdcxxTests():
886 from lldbsuite
.test
import lldbplatformutil
888 platform
= lldbplatformutil
.getPlatform()
889 if lldbplatformutil
.target_is_android():
891 if platform
== "linux":
892 return True, "libstdcxx always present"
893 return False, "Don't know how to build with libstdcxx on %s" % platform
895 def checkLibstdcxxSupport():
896 result
, reason
= canRunLibstdcxxTests()
898 return # libstdcxx supported
899 if "libstdcxx" in configuration
.categories_list
:
900 return # libstdcxx category explicitly requested, let it run.
901 print("libstdcxx tests will not be run because: " + reason
)
902 configuration
.skip_categories
.append("libstdcxx")
904 def canRunWatchpointTests():
905 from lldbsuite
.test
import lldbplatformutil
907 platform
= lldbplatformutil
.getPlatform()
908 if platform
== "netbsd":
909 if os
.geteuid() == 0:
910 return True, "root can always write dbregs"
912 output
= subprocess
.check_output(["/sbin/sysctl", "-n",
913 "security.models.extensions.user_set_dbregs"]).decode().strip()
915 return True, "security.models.extensions.user_set_dbregs enabled"
916 except subprocess
.CalledProcessError
:
918 return False, "security.models.extensions.user_set_dbregs disabled"
919 return True, "watchpoint support available"
921 def checkWatchpointSupport():
922 result
, reason
= canRunWatchpointTests()
924 return # watchpoints supported
925 if "watchpoint" in configuration
.categories_list
:
926 return # watchpoint category explicitly requested, let it run.
927 print("watchpoint tests will not be run because: " + reason
)
928 configuration
.skip_categories
.append("watchpoint")
930 def checkDebugInfoSupport():
933 platform
= lldb
.DBG
.GetSelectedPlatform().GetTriple().split('-')[2]
934 compiler
= configuration
.compiler
936 for cat
in test_categories
.debug_info_categories
:
937 if cat
in configuration
.categories_list
:
938 continue # Category explicitly requested, let it run.
939 if test_categories
.is_supported_on_platform(cat
, platform
, compiler
):
941 configuration
.skip_categories
.append(cat
)
944 print("Skipping following debug info categories:", skipped
)
947 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults
948 # does not exist before proceeding to running the test suite.
949 if sys
.platform
.startswith("darwin"):
950 checkDsymForUUIDIsNotOn()
952 # Start the actions by first parsing the options while setting up the test
953 # directories, followed by setting up the search paths for lldb utilities;
954 # then, we walk the directory trees and collect the tests into our test suite.
956 parseOptionsAndInitTestdirs()
958 # Setup test results (test results formatter and output handling).
964 # For the time being, let's bracket the test runner within the
965 # lldb.SBDebugger.Initialize()/Terminate() pair.
968 # Now we can also import lldbutil
969 from lldbsuite
.test
import lldbutil
971 # Create a singleton SBDebugger in the lldb namespace.
972 lldb
.DBG
= lldb
.SBDebugger
.Create()
974 if configuration
.lldb_platform_name
:
975 print("Setting up remote platform '%s'" %
976 (configuration
.lldb_platform_name
))
977 lldb
.remote_platform
= lldb
.SBPlatform(
978 configuration
.lldb_platform_name
)
979 if not lldb
.remote_platform
.IsValid():
981 "error: unable to create the LLDB platform named '%s'." %
982 (configuration
.lldb_platform_name
))
984 if configuration
.lldb_platform_url
:
985 # We must connect to a remote platform if a LLDB platform URL was
988 "Connecting to remote platform '%s' at '%s'..." %
989 (configuration
.lldb_platform_name
, configuration
.lldb_platform_url
))
990 platform_connect_options
= lldb
.SBPlatformConnectOptions(
991 configuration
.lldb_platform_url
)
992 err
= lldb
.remote_platform
.ConnectRemote(platform_connect_options
)
996 print("error: failed to connect to remote platform using URL '%s': %s" % (
997 configuration
.lldb_platform_url
, err
))
1000 configuration
.lldb_platform_url
= None
1002 platform_changes
= setDefaultTripleForPlatform()
1004 for key
in platform_changes
:
1006 print("Environment variables setup for platform support:")
1008 print("%s = %s" % (key
, platform_changes
[key
]))
1010 if configuration
.lldb_platform_working_dir
:
1011 print("Setting remote platform working directory to '%s'..." %
1012 (configuration
.lldb_platform_working_dir
))
1013 error
= lldb
.remote_platform
.MakeDirectory(
1014 configuration
.lldb_platform_working_dir
, 448) # 448 = 0o700
1016 raise Exception("making remote directory '%s': %s" % (
1017 configuration
.lldb_platform_working_dir
, error
))
1019 if not lldb
.remote_platform
.SetWorkingDirectory(
1020 configuration
.lldb_platform_working_dir
):
1021 raise Exception("failed to set working directory '%s'" % configuration
.lldb_platform_working_dir
)
1022 lldb
.DBG
.SetSelectedPlatform(lldb
.remote_platform
)
1024 lldb
.remote_platform
= None
1025 configuration
.lldb_platform_working_dir
= None
1026 configuration
.lldb_platform_url
= None
1028 # Set up the working directory.
1029 # Note that it's not dotest's job to clean this directory.
1030 build_dir
= configuration
.test_build_dir
1031 lldbutil
.mkdir_p(build_dir
)
1033 target_platform
= lldb
.DBG
.GetSelectedPlatform().GetTriple().split('-')[2]
1035 checkLibcxxSupport()
1036 checkLibstdcxxSupport()
1037 checkWatchpointSupport()
1038 checkDebugInfoSupport()
1040 # Don't do debugserver tests on anything except OS X.
1041 configuration
.dont_do_debugserver_test
= (
1042 "linux" in target_platform
or
1043 "freebsd" in target_platform
or
1044 "netbsd" in target_platform
or
1045 "windows" in target_platform
)
1047 # Don't do lldb-server (llgs) tests on anything except Linux and Windows.
1048 configuration
.dont_do_llgs_test
= not (
1049 "linux" in target_platform
or
1050 "netbsd" in target_platform
or
1051 "windows" in target_platform
)
1053 # Collect tests from the specified testing directories. If a test
1054 # subdirectory filter is explicitly specified, limit the search to that
1056 exclusive_test_subdir
= configuration
.get_absolute_path_to_exclusive_test_subdir()
1057 if exclusive_test_subdir
:
1058 dirs_to_search
= [exclusive_test_subdir
]
1060 dirs_to_search
= configuration
.testdirs
1061 for testdir
in dirs_to_search
:
1062 for (dirpath
, dirnames
, filenames
) in os
.walk(testdir
):
1063 visit('Test', dirpath
, filenames
)
1066 # Now that we have loaded all the test cases, run the whole test suite.
1069 # Set any user-overridden settings.
1070 for key
, value
in configuration
.settings
:
1071 setSetting(key
, value
)
1073 # Install the control-c handler.
1074 unittest2
.signals
.installHandler()
1076 lldbutil
.mkdir_p(configuration
.sdir_name
)
1077 os
.environ
["LLDB_SESSION_DIRNAME"] = configuration
.sdir_name
1080 "\nSession logs for test failures/errors/unexpected successes"
1081 " will go into directory '%s'\n" %
1082 configuration
.sdir_name
)
1083 sys
.stderr
.write("Command invoked: %s\n" % get_dotest_invocation())
1086 # Invoke the default TextTestRunner to run the test suite
1090 if configuration
.verbose
:
1091 print("compiler=%s" % configuration
.compiler
)
1093 # Iterating over all possible architecture and compiler combinations.
1094 os
.environ
["ARCH"] = configuration
.arch
1095 os
.environ
["CC"] = configuration
.compiler
1096 configString
= "arch=%s compiler=%s" % (configuration
.arch
,
1097 configuration
.compiler
)
1099 # Output the configuration.
1100 if configuration
.verbose
:
1101 sys
.stderr
.write("\nConfiguration: " + configString
+ "\n")
1103 # First, write out the number of collected test cases.
1104 if configuration
.verbose
:
1105 sys
.stderr
.write(configuration
.separator
+ "\n")
1107 "Collected %d test%s\n\n" %
1108 (configuration
.suite
.countTestCases(),
1109 configuration
.suite
.countTestCases() != 1 and "s" or ""))
1111 # Invoke the test runner.
1112 if configuration
.count
== 1:
1113 result
= unittest2
.TextTestRunner(
1115 verbosity
=configuration
.verbose
,
1116 resultclass
=test_result
.LLDBTestResult
).run(
1117 configuration
.suite
)
1119 # We are invoking the same test suite more than once. In this case,
1120 # mark __ignore_singleton__ flag as True so the signleton pattern is
1122 test_result
.LLDBTestResult
.__ignore
_singleton
__ = True
1123 for i
in range(configuration
.count
):
1125 result
= unittest2
.TextTestRunner(
1127 verbosity
=configuration
.verbose
,
1128 resultclass
=test_result
.LLDBTestResult
).run(
1129 configuration
.suite
)
1131 configuration
.failed
= not result
.wasSuccessful()
1133 if configuration
.sdir_has_content
and configuration
.verbose
:
1135 "Session logs for test failures/errors/unexpected successes"
1136 " can be found in directory '%s'\n" %
1137 configuration
.sdir_name
)
1139 if configuration
.use_categories
and len(
1140 configuration
.failures_per_category
) > 0:
1141 sys
.stderr
.write("Failures per category:\n")
1142 for category
in configuration
.failures_per_category
:
1145 (category
, configuration
.failures_per_category
[category
]))
1148 exitTestSuite(configuration
.failed
)
1150 if __name__
== "__main__":
1153 " is for use as a module only. It should not be run as a standalone script.")