1""" 2A simple testing framework for lldb using python's unit testing framework. 3 4Tests for lldb are written as python scripts which take advantage of the script 5bridging provided by LLDB.framework to interact with lldb core. 6 7A specific naming pattern is followed by the .py script to be recognized as 8a module which implements a test scenario, namely, Test*.py. 9 10To specify the directories where "Test*.py" python test scripts are located, 11you need to pass in a list of directory names. By default, the current 12working directory is searched if nothing is specified on the command line. 13 14Type: 15 16./dotest.py -h 17 18for available options. 19""" 20 21from __future__ import absolute_import 22from __future__ import print_function 23 24# System modules 25import atexit 26import datetime 27import errno 28import logging 29import os 30import platform 31import re 32import signal 33import subprocess 34import sys 35import tempfile 36 37# Third-party modules 38import six 39import unittest2 40 41# LLDB Modules 42import lldbsuite 43from . import configuration 44from . import dotest_args 45from . import lldbtest_config 46from . import test_categories 47from lldbsuite.test_event import formatter 48from . import test_result 49from lldbsuite.test_event.event_builder import EventBuilder 50from ..support import seven 51 52 53def is_exe(fpath): 54 """Returns true if fpath is an executable.""" 55 if fpath == None: 56 return False 57 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 58 59 60def which(program): 61 """Returns the full path to a program; None otherwise.""" 62 fpath, _ = os.path.split(program) 63 if fpath: 64 if is_exe(program): 65 return program 66 else: 67 for path in os.environ["PATH"].split(os.pathsep): 68 exe_file = os.path.join(path, program) 69 if is_exe(exe_file): 70 return exe_file 71 return None 72 73 74def usage(parser): 75 parser.print_help() 76 if configuration.verbose > 0: 77 print(""" 78Examples: 79 80This is an example of using the -f option to pinpoint to a specific test class 81and test method to be run: 82 83$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command 84---------------------------------------------------------------------- 85Collected 1 test 86 87test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase) 88Test 'frame variable this' when stopped on a class constructor. ... ok 89 90---------------------------------------------------------------------- 91Ran 1 test in 1.396s 92 93OK 94 95And this is an example of using the -p option to run a single file (the filename 96matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'): 97 98$ ./dotest.py -v -p ObjC 99---------------------------------------------------------------------- 100Collected 4 tests 101 102test_break_with_dsym (TestObjCMethods.FoundationTestCase) 103Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok 104test_break_with_dwarf (TestObjCMethods.FoundationTestCase) 105Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok 106test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase) 107Lookup objective-c data types and evaluate expressions. ... ok 108test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase) 109Lookup objective-c data types and evaluate expressions. ... ok 110 111---------------------------------------------------------------------- 112Ran 4 tests in 16.661s 113 114OK 115 116Running of this script also sets up the LLDB_TEST environment variable so that 117individual test cases can locate their supporting files correctly. The script 118tries to set up Python's search paths for modules by looking at the build tree 119relative to this script. See also the '-i' option in the following example. 120 121Finally, this is an example of using the lldb.py module distributed/installed by 122Xcode4 to run against the tests under the 'forward' directory, and with the '-w' 123option to add some delay between two tests. It uses ARCH=x86_64 to specify that 124as the architecture and CC=clang to specify the compiler used for the test run: 125 126$ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward 127 128Session logs for test failures/errors will go into directory '2010-11-11-13_56_16' 129---------------------------------------------------------------------- 130Collected 2 tests 131 132test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase) 133Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok 134test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase) 135Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok 136 137---------------------------------------------------------------------- 138Ran 2 tests in 5.659s 139 140OK 141 142The 'Session ...' verbiage is recently introduced (see also the '-s' option) to 143notify the directory containing the session logs for test failures or errors. 144In case there is any test failure/error, a similar message is appended at the 145end of the stderr output for your convenience. 146 147ENABLING LOGS FROM TESTS 148 149Option 1: 150 151Writing logs into different files per test case:: 152 153$ ./dotest.py --channel "lldb all" 154 155$ ./dotest.py --channel "lldb all" --channel "gdb-remote packets" 156 157These log files are written to: 158 159<session-dir>/<test-id>-host.log (logs from lldb host process) 160<session-dir>/<test-id>-server.log (logs from debugserver/lldb-server) 161<session-dir>/<test-id>-<test-result>.log (console logs) 162 163By default, logs from successful runs are deleted. Use the --log-success flag 164to create reference logs for debugging. 165 166$ ./dotest.py --log-success 167 168""") 169 sys.exit(0) 170 171 172def parseExclusion(exclusion_file): 173 """Parse an exclusion file, of the following format, where 174 'skip files', 'skip methods', 'xfail files', and 'xfail methods' 175 are the possible list heading values: 176 177 skip files 178 <file name> 179 <file name> 180 181 xfail methods 182 <method name> 183 """ 184 excl_type = None 185 186 with open(exclusion_file) as f: 187 for line in f: 188 line = line.strip() 189 if not excl_type: 190 excl_type = line 191 continue 192 193 if not line: 194 excl_type = None 195 elif excl_type == 'skip': 196 if not configuration.skip_tests: 197 configuration.skip_tests = [] 198 configuration.skip_tests.append(line) 199 elif excl_type == 'xfail': 200 if not configuration.xfail_tests: 201 configuration.xfail_tests = [] 202 configuration.xfail_tests.append(line) 203 204 205def parseOptionsAndInitTestdirs(): 206 """Initialize the list of directories containing our unittest scripts. 207 208 '-h/--help as the first option prints out usage info and exit the program. 209 """ 210 211 do_help = False 212 213 platform_system = platform.system() 214 platform_machine = platform.machine() 215 216 try: 217 parser = dotest_args.create_parser() 218 args = parser.parse_args() 219 except: 220 raise 221 222 if args.unset_env_varnames: 223 for env_var in args.unset_env_varnames: 224 if env_var in os.environ: 225 # From Python Doc: When unsetenv() is supported, deletion of items in os.environ 226 # is automatically translated into a corresponding call to 227 # unsetenv(). 228 del os.environ[env_var] 229 # os.unsetenv(env_var) 230 231 if args.set_env_vars: 232 for env_var in args.set_env_vars: 233 parts = env_var.split('=', 1) 234 if len(parts) == 1: 235 os.environ[parts[0]] = "" 236 else: 237 os.environ[parts[0]] = parts[1] 238 239 if args.set_inferior_env_vars: 240 lldbtest_config.inferior_env = ' '.join(args.set_inferior_env_vars) 241 242 if args.h: 243 do_help = True 244 245 if args.compiler: 246 configuration.compiler = os.path.realpath(args.compiler) 247 if not is_exe(configuration.compiler): 248 configuration.compiler = which(args.compiler) 249 if not is_exe(configuration.compiler): 250 logging.error( 251 '%s is not a valid compiler executable; aborting...', 252 args.compiler) 253 sys.exit(-1) 254 else: 255 # Use a compiler appropriate appropriate for the Apple SDK if one was 256 # specified 257 if platform_system == 'Darwin' and args.apple_sdk: 258 configuration.compiler = seven.get_command_output( 259 'xcrun -sdk "%s" -find clang 2> /dev/null' % 260 (args.apple_sdk)) 261 else: 262 # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first 263 candidateCompilers = ['clang-3.5', 'clang', 'gcc'] 264 for candidate in candidateCompilers: 265 if which(candidate): 266 configuration.compiler = candidate 267 break 268 269 if args.dsymutil: 270 configuration.dsymutil = args.dsymutil 271 elif platform_system == 'Darwin': 272 configuration.dsymutil = seven.get_command_output( 273 'xcrun -find -toolchain default dsymutil') 274 275 if args.filecheck: 276 # The lldb-dotest script produced by the CMake build passes in a path 277 # to a working FileCheck binary. So does one specific Xcode project 278 # target. However, when invoking dotest.py directly, a valid --filecheck 279 # option needs to be given. 280 configuration.filecheck = os.path.abspath(args.filecheck) 281 282 if not configuration.get_filecheck_path(): 283 logging.warning('No valid FileCheck executable; some tests may fail...') 284 logging.warning('(Double-check the --filecheck argument to dotest.py)') 285 286 if args.channels: 287 lldbtest_config.channels = args.channels 288 289 if args.log_success: 290 lldbtest_config.log_success = args.log_success 291 292 if args.out_of_tree_debugserver: 293 lldbtest_config.out_of_tree_debugserver = args.out_of_tree_debugserver 294 295 # Set SDKROOT if we are using an Apple SDK 296 if platform_system == 'Darwin' and args.apple_sdk: 297 configuration.sdkroot = seven.get_command_output( 298 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % 299 (args.apple_sdk)) 300 301 if args.arch: 302 configuration.arch = args.arch 303 else: 304 configuration.arch = platform_machine 305 306 if args.categories_list: 307 configuration.categories_list = set( 308 test_categories.validate( 309 args.categories_list, False)) 310 configuration.use_categories = True 311 else: 312 configuration.categories_list = [] 313 314 if args.skip_categories: 315 configuration.skip_categories += test_categories.validate( 316 args.skip_categories, False) 317 318 if args.xfail_categories: 319 configuration.xfail_categories += test_categories.validate( 320 args.xfail_categories, False) 321 322 if args.E: 323 os.environ['CFLAGS_EXTRAS'] = args.E 324 325 if args.dwarf_version: 326 configuration.dwarf_version = args.dwarf_version 327 # We cannot modify CFLAGS_EXTRAS because they're used in test cases 328 # that explicitly require no debug info. 329 os.environ['CFLAGS'] = '-gdwarf-{}'.format(configuration.dwarf_version) 330 331 if args.settings: 332 for setting in args.settings: 333 if not len(setting) == 1 or not setting[0].count('='): 334 logging.error('"%s" is not a setting in the form "key=value"', 335 setting[0]) 336 sys.exit(-1) 337 setting_list = setting[0].split('=', 1) 338 configuration.settings.append((setting_list[0], setting_list[1])) 339 340 if args.d: 341 sys.stdout.write( 342 "Suspending the process %d to wait for debugger to attach...\n" % 343 os.getpid()) 344 sys.stdout.flush() 345 os.kill(os.getpid(), signal.SIGSTOP) 346 347 if args.f: 348 if any([x.startswith('-') for x in args.f]): 349 usage(parser) 350 configuration.filters.extend(args.f) 351 352 if args.framework: 353 configuration.lldb_framework_path = args.framework 354 355 if args.executable: 356 # lldb executable is passed explicitly 357 lldbtest_config.lldbExec = os.path.realpath(args.executable) 358 if not is_exe(lldbtest_config.lldbExec): 359 lldbtest_config.lldbExec = which(args.executable) 360 if not is_exe(lldbtest_config.lldbExec): 361 logging.error( 362 '%s is not a valid executable to test; aborting...', 363 args.executable) 364 sys.exit(-1) 365 366 if args.server: 367 os.environ['LLDB_DEBUGSERVER_PATH'] = args.server 368 369 if args.excluded: 370 for excl_file in args.excluded: 371 parseExclusion(excl_file) 372 373 if args.p: 374 if args.p.startswith('-'): 375 usage(parser) 376 configuration.regexp = args.p 377 378 if args.s: 379 configuration.sdir_name = args.s 380 else: 381 timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S") 382 configuration.sdir_name = os.path.join(os.getcwd(), timestamp_started) 383 384 configuration.session_file_format = args.session_file_format 385 386 if args.t: 387 os.environ['LLDB_COMMAND_TRACE'] = 'YES' 388 389 if args.v: 390 configuration.verbose = 2 391 392 # argparse makes sure we have a number 393 if args.sharp: 394 configuration.count = args.sharp 395 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) 400 401 if do_help: 402 usage(parser) 403 404 if args.results_file: 405 configuration.results_filename = args.results_file 406 407 if args.results_formatter: 408 configuration.results_formatter_name = args.results_formatter 409 if args.results_formatter_options: 410 configuration.results_formatter_options = args.results_formatter_options 411 412 # Default to using the BasicResultsFormatter if no formatter is specified. 413 if configuration.results_formatter_name is None: 414 configuration.results_formatter_name = ( 415 "lldbsuite.test_event.formatter.results_formatter.ResultsFormatter") 416 417 # Reproducer arguments 418 if args.capture_path and args.replay_path: 419 logging.error('Cannot specify both a capture and a replay path.') 420 sys.exit(-1) 421 422 if args.capture_path: 423 configuration.capture_path = args.capture_path 424 425 if args.replay_path: 426 configuration.replay_path = args.replay_path 427 428 # rerun-related arguments 429 configuration.rerun_all_issues = args.rerun_all_issues 430 431 if args.lldb_platform_name: 432 configuration.lldb_platform_name = args.lldb_platform_name 433 if args.lldb_platform_url: 434 configuration.lldb_platform_url = args.lldb_platform_url 435 if args.lldb_platform_working_dir: 436 configuration.lldb_platform_working_dir = args.lldb_platform_working_dir 437 if args.test_build_dir: 438 configuration.test_build_dir = args.test_build_dir 439 if args.lldb_module_cache_dir: 440 configuration.lldb_module_cache_dir = args.lldb_module_cache_dir 441 else: 442 configuration.lldb_module_cache_dir = os.path.join( 443 configuration.test_build_dir, 'module-cache-lldb') 444 if args.clang_module_cache_dir: 445 configuration.clang_module_cache_dir = args.clang_module_cache_dir 446 else: 447 configuration.clang_module_cache_dir = os.path.join( 448 configuration.test_build_dir, 'module-cache-clang') 449 450 if args.lldb_libs_dir: 451 configuration.lldb_libs_dir = args.lldb_libs_dir 452 453 if args.enabled_plugins: 454 configuration.enabled_plugins = args.enabled_plugins 455 456 # Gather all the dirs passed on the command line. 457 if len(args.args) > 0: 458 configuration.testdirs = [os.path.realpath(os.path.abspath(x)) for x in args.args] 459 460 lldbtest_config.codesign_identity = args.codesign_identity 461 462 463def setupTestResults(): 464 """Sets up test results-related objects based on arg settings.""" 465 # Setup the results formatter configuration. 466 formatter_config = formatter.FormatterConfig() 467 formatter_config.filename = configuration.results_filename 468 formatter_config.formatter_name = configuration.results_formatter_name 469 formatter_config.formatter_options = ( 470 configuration.results_formatter_options) 471 472 # Create the results formatter. 473 formatter_spec = formatter.create_results_formatter( 474 formatter_config) 475 if formatter_spec is not None and formatter_spec.formatter is not None: 476 configuration.results_formatter_object = formatter_spec.formatter 477 478 # Send an initialize message to the formatter. 479 initialize_event = EventBuilder.bare_event("initialize") 480 initialize_event["worker_count"] = 1 481 482 formatter_spec.formatter.handle_event(initialize_event) 483 484 # Make sure we clean up the formatter on shutdown. 485 if formatter_spec.cleanup_func is not None: 486 atexit.register(formatter_spec.cleanup_func) 487 488 489def setupSysPath(): 490 """ 491 Add LLDB.framework/Resources/Python to the search paths for modules. 492 As a side effect, we also discover the 'lldb' executable and export it here. 493 """ 494 495 # Get the directory containing the current script. 496 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ: 497 scriptPath = os.environ["DOTEST_SCRIPT_DIR"] 498 else: 499 scriptPath = os.path.dirname(os.path.realpath(__file__)) 500 if not scriptPath.endswith('test'): 501 print("This script expects to reside in lldb's test directory.") 502 sys.exit(-1) 503 504 os.environ["LLDB_TEST"] = scriptPath 505 os.environ["LLDB_TEST_SRC"] = lldbsuite.lldb_test_root 506 507 # Set up the root build directory. 508 if not configuration.test_build_dir: 509 raise Exception("test_build_dir is not set") 510 configuration.test_build_dir = os.path.abspath(configuration.test_build_dir) 511 512 # Set up the LLDB_SRC environment variable, so that the tests can locate 513 # the LLDB source code. 514 os.environ["LLDB_SRC"] = lldbsuite.lldb_root 515 516 pluginPath = os.path.join(scriptPath, 'plugins') 517 toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode') 518 toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server') 519 520 # Insert script dir, plugin dir and lldb-server dir to the sys.path. 521 sys.path.insert(0, pluginPath) 522 # Adding test/tools/lldb-vscode to the path makes it easy to 523 # "import lldb_vscode_testcase" from the VSCode tests 524 sys.path.insert(0, toolsLLDBVSCode) 525 # Adding test/tools/lldb-server to the path makes it easy 526 sys.path.insert(0, toolsLLDBServerPath) 527 # to "import lldbgdbserverutils" from the lldb-server tests 528 529 # This is the root of the lldb git/svn checkout 530 # When this changes over to a package instead of a standalone script, this 531 # will be `lldbsuite.lldb_root` 532 lldbRootDirectory = lldbsuite.lldb_root 533 534 # Some of the tests can invoke the 'lldb' command directly. 535 # We'll try to locate the appropriate executable right here. 536 537 # The lldb executable can be set from the command line 538 # if it's not set, we try to find it now 539 # first, we try the environment 540 if not lldbtest_config.lldbExec: 541 # First, you can define an environment variable LLDB_EXEC specifying the 542 # full pathname of the lldb executable. 543 if "LLDB_EXEC" in os.environ: 544 lldbtest_config.lldbExec = os.environ["LLDB_EXEC"] 545 546 if not lldbtest_config.lldbExec: 547 # Last, check the path 548 lldbtest_config.lldbExec = which('lldb') 549 550 if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec): 551 print( 552 "'{}' is not a path to a valid executable".format( 553 lldbtest_config.lldbExec)) 554 lldbtest_config.lldbExec = None 555 556 if not lldbtest_config.lldbExec: 557 print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.") 558 sys.exit(-1) 559 560 # confusingly, this is the "bin" directory 561 lldbLibDir = os.path.dirname(lldbtest_config.lldbExec) 562 os.environ["LLDB_LIB_DIR"] = lldbLibDir 563 lldbImpLibDir = configuration.lldb_libs_dir 564 os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir 565 print("LLDB library dir:", os.environ["LLDB_LIB_DIR"]) 566 print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"]) 567 os.system('%s -v' % lldbtest_config.lldbExec) 568 569 lldbDir = os.path.dirname(lldbtest_config.lldbExec) 570 571 lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode") 572 if is_exe(lldbVSCodeExec): 573 os.environ["LLDBVSCODE_EXEC"] = lldbVSCodeExec 574 else: 575 if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]): 576 print( 577 "The 'lldb-vscode' executable cannot be located. The lldb-vscode tests can not be run as a result.") 578 configuration.skip_categories.append("lldb-vscode") 579 580 lldbPythonDir = None # The directory that contains 'lldb/__init__.py' 581 if not configuration.lldb_framework_path and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")): 582 configuration.lldb_framework_path = os.path.join(lldbLibDir, "LLDB.framework") 583 if configuration.lldb_framework_path: 584 lldbtest_config.lldb_framework_path = configuration.lldb_framework_path 585 candidatePath = os.path.join( 586 configuration.lldb_framework_path, 'Resources', 'Python') 587 if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')): 588 lldbPythonDir = candidatePath 589 if not lldbPythonDir: 590 print( 591 'Resources/Python/lldb/__init__.py was not found in ' + 592 configuration.lldb_framework_path) 593 sys.exit(-1) 594 else: 595 # If our lldb supports the -P option, use it to find the python path: 596 init_in_python_dir = os.path.join('lldb', '__init__.py') 597 598 lldb_dash_p_result = subprocess.check_output( 599 [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True) 600 601 if lldb_dash_p_result and not lldb_dash_p_result.startswith( 602 ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"): 603 lines = lldb_dash_p_result.splitlines() 604 605 # Workaround for readline vs libedit issue on FreeBSD. If stdout 606 # is not a terminal Python executes 607 # rl_variable_bind ("enable-meta-key", "off"); 608 # This produces a warning with FreeBSD's libedit because the 609 # enable-meta-key variable is unknown. Not an issue on Apple 610 # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__ 611 # around the call. See http://bugs.python.org/issue19884 for more 612 # information. For now we just discard the warning output. 613 if len(lines) >= 1 and lines[0].startswith( 614 "bind: Invalid command"): 615 lines.pop(0) 616 617 # Taking the last line because lldb outputs 618 # 'Cannot read termcap database;\nusing dumb terminal settings.\n' 619 # before the path 620 if len(lines) >= 1 and os.path.isfile( 621 os.path.join(lines[-1], init_in_python_dir)): 622 lldbPythonDir = lines[-1] 623 if "freebsd" in sys.platform or "linux" in sys.platform: 624 os.environ['LLDB_LIB_DIR'] = os.path.join( 625 lldbPythonDir, '..', '..') 626 627 if not lldbPythonDir: 628 print( 629 "Unable to load lldb extension module. Possible reasons for this include:") 630 print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") 631 print( 632 " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") 633 print( 634 " the version of Python that LLDB built and linked against, and PYTHONPATH") 635 print( 636 " should contain the Lib directory for the same python distro, as well as the") 637 print(" location of LLDB\'s site-packages folder.") 638 print( 639 " 3) A different version of Python than that which was built against is exported in") 640 print(" the system\'s PATH environment variable, causing conflicts.") 641 print( 642 " 4) The executable '%s' could not be found. Please check " % 643 lldbtest_config.lldbExec) 644 print(" that it exists and is executable.") 645 646 if lldbPythonDir: 647 lldbPythonDir = os.path.normpath(lldbPythonDir) 648 # Some of the code that uses this path assumes it hasn't resolved the Versions... link. 649 # If the path we've constructed looks like that, then we'll strip out 650 # the Versions/A part. 651 (before, frameWithVersion, after) = lldbPythonDir.rpartition( 652 "LLDB.framework/Versions/A") 653 if frameWithVersion != "": 654 lldbPythonDir = before + "LLDB.framework" + after 655 656 lldbPythonDir = os.path.abspath(lldbPythonDir) 657 658 # If tests need to find LLDB_FRAMEWORK, now they can do it 659 os.environ["LLDB_FRAMEWORK"] = os.path.dirname( 660 os.path.dirname(lldbPythonDir)) 661 662 # This is to locate the lldb.py module. Insert it right after 663 # sys.path[0]. 664 sys.path[1:1] = [lldbPythonDir] 665 666 667def visit_file(dir, name): 668 # Try to match the regexp pattern, if specified. 669 if configuration.regexp: 670 if not re.search(configuration.regexp, name): 671 # We didn't match the regex, we're done. 672 return 673 674 if configuration.skip_tests: 675 for file_regexp in configuration.skip_tests: 676 if re.search(file_regexp, name): 677 return 678 679 # We found a match for our test. Add it to the suite. 680 681 # Update the sys.path first. 682 if not sys.path.count(dir): 683 sys.path.insert(0, dir) 684 base = os.path.splitext(name)[0] 685 686 # Thoroughly check the filterspec against the base module and admit 687 # the (base, filterspec) combination only when it makes sense. 688 689 def check(obj, parts): 690 for part in parts: 691 try: 692 parent, obj = obj, getattr(obj, part) 693 except AttributeError: 694 # The filterspec has failed. 695 return False 696 return True 697 698 module = __import__(base) 699 700 def iter_filters(): 701 for filterspec in configuration.filters: 702 parts = filterspec.split('.') 703 if check(module, parts): 704 yield filterspec 705 elif parts[0] == base and len(parts) > 1 and check(module, parts[1:]): 706 yield '.'.join(parts[1:]) 707 else: 708 for key,value in module.__dict__.items(): 709 if check(value, parts): 710 yield key + '.' + filterspec 711 712 filtered = False 713 for filterspec in iter_filters(): 714 filtered = True 715 print("adding filter spec %s to module %s" % (filterspec, repr(module))) 716 tests = unittest2.defaultTestLoader.loadTestsFromName(filterspec, module) 717 configuration.suite.addTests(tests) 718 719 # Forgo this module if the (base, filterspec) combo is invalid 720 if configuration.filters and not filtered: 721 return 722 723 if not filtered: 724 # Add the entire file's worth of tests since we're not filtered. 725 # Also the fail-over case when the filterspec branch 726 # (base, filterspec) combo doesn't make sense. 727 configuration.suite.addTests( 728 unittest2.defaultTestLoader.loadTestsFromName(base)) 729 730 731def visit(prefix, dir, names): 732 """Visitor function for os.path.walk(path, visit, arg).""" 733 734 dir_components = set(dir.split(os.sep)) 735 excluded_components = set(['.svn', '.git']) 736 if dir_components.intersection(excluded_components): 737 return 738 739 # Gather all the Python test file names that follow the Test*.py pattern. 740 python_test_files = [ 741 name 742 for name in names 743 if name.endswith('.py') and name.startswith(prefix)] 744 745 # Visit all the python test files. 746 for name in python_test_files: 747 try: 748 # Ensure we error out if we have multiple tests with the same 749 # base name. 750 # Future improvement: find all the places where we work with base 751 # names and convert to full paths. We have directory structure 752 # to disambiguate these, so we shouldn't need this constraint. 753 if name in configuration.all_tests: 754 raise Exception("Found multiple tests with the name %s" % name) 755 configuration.all_tests.add(name) 756 757 # Run the relevant tests in the python file. 758 visit_file(dir, name) 759 except Exception as ex: 760 # Convert this exception to a test event error for the file. 761 test_filename = os.path.abspath(os.path.join(dir, name)) 762 if configuration.results_formatter_object is not None: 763 # Grab the backtrace for the exception. 764 import traceback 765 backtrace = traceback.format_exc() 766 767 # Generate the test event. 768 configuration.results_formatter_object.handle_event( 769 EventBuilder.event_for_job_test_add_error( 770 test_filename, ex, backtrace)) 771 raise 772 773 774# ======================================== # 775# # 776# Execution of the test driver starts here # 777# # 778# ======================================== # 779 780 781def checkDsymForUUIDIsNotOn(): 782 cmd = ["defaults", "read", "com.apple.DebugSymbols"] 783 process = subprocess.Popen( 784 cmd, 785 stdout=subprocess.PIPE, 786 stderr=subprocess.STDOUT) 787 cmd_output = process.stdout.read() 788 output_str = cmd_output.decode("utf-8") 789 if "DBGFileMappedPaths = " in output_str: 790 print("%s =>" % ' '.join(cmd)) 791 print(output_str) 792 print( 793 "Disable automatic lookup and caching of dSYMs before running the test suite!") 794 print("Exiting...") 795 sys.exit(0) 796 797 798def exitTestSuite(exitCode=None): 799 # lldb.py does SBDebugger.Initialize(). 800 # Call SBDebugger.Terminate() on exit. 801 import lldb 802 lldb.SBDebugger.Terminate() 803 if exitCode: 804 sys.exit(exitCode) 805 806 807def getVersionForSDK(sdk): 808 sdk = str.lower(sdk) 809 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk) 810 basename = os.path.basename(full_path) 811 basename = os.path.splitext(basename)[0] 812 basename = str.lower(basename) 813 ver = basename.replace(sdk, '') 814 return ver 815 816 817def setDefaultTripleForPlatform(): 818 if configuration.lldb_platform_name == 'ios-simulator': 819 triple_str = 'x86_64-apple-ios%s' % ( 820 getVersionForSDK('iphonesimulator')) 821 os.environ['TRIPLE'] = triple_str 822 return {'TRIPLE': triple_str} 823 return {} 824 825 826def checkCompiler(): 827 # Add some intervention here to sanity check that the compiler requested is sane. 828 # If found not to be an executable program, we abort. 829 c = configuration.compiler 830 if which(c): 831 return 832 833 if not sys.platform.startswith("darwin"): 834 raise Exception(c + " is not a valid compiler") 835 836 pipe = subprocess.Popen( 837 ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 838 cmd_output = pipe.stdout.read() 839 if not cmd_output or "not found" in cmd_output: 840 raise Exception(c + " is not a valid compiler") 841 842 configuration.compiler = cmd_output.split('\n')[0] 843 print("'xcrun -find %s' returning %s" % (c, configuration.compiler)) 844 845def canRunLibcxxTests(): 846 from lldbsuite.test import lldbplatformutil 847 848 platform = lldbplatformutil.getPlatform() 849 850 if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin(): 851 return True, "libc++ always present" 852 853 if platform == "linux": 854 if os.path.isdir("/usr/include/c++/v1"): 855 return True, "Headers found, let's hope they work" 856 with tempfile.NamedTemporaryFile() as f: 857 cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.name, "-"] 858 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 859 _, stderr = p.communicate("#include <algorithm>\nint main() {}") 860 if not p.returncode: 861 return True, "Compiling with -stdlib=libc++ works" 862 return False, "Compiling with -stdlib=libc++ fails with the error: %s" % stderr 863 864 return False, "Don't know how to build with libc++ on %s" % platform 865 866def checkLibcxxSupport(): 867 result, reason = canRunLibcxxTests() 868 if result: 869 return # libc++ supported 870 if "libc++" in configuration.categories_list: 871 return # libc++ category explicitly requested, let it run. 872 print("Libc++ tests will not be run because: " + reason) 873 configuration.skip_categories.append("libc++") 874 875def canRunLibstdcxxTests(): 876 from lldbsuite.test import lldbplatformutil 877 878 platform = lldbplatformutil.getPlatform() 879 if lldbplatformutil.target_is_android(): 880 platform = "android" 881 if platform == "linux": 882 return True, "libstdcxx always present" 883 return False, "Don't know how to build with libstdcxx on %s" % platform 884 885def checkLibstdcxxSupport(): 886 result, reason = canRunLibstdcxxTests() 887 if result: 888 return # libstdcxx supported 889 if "libstdcxx" in configuration.categories_list: 890 return # libstdcxx category explicitly requested, let it run. 891 print("libstdcxx tests will not be run because: " + reason) 892 configuration.skip_categories.append("libstdcxx") 893 894def canRunWatchpointTests(): 895 from lldbsuite.test import lldbplatformutil 896 897 platform = lldbplatformutil.getPlatform() 898 if platform == "netbsd": 899 if os.geteuid() == 0: 900 return True, "root can always write dbregs" 901 try: 902 output = subprocess.check_output(["/sbin/sysctl", "-n", 903 "security.models.extensions.user_set_dbregs"]).decode().strip() 904 if output == "1": 905 return True, "security.models.extensions.user_set_dbregs enabled" 906 except subprocess.CalledProcessError: 907 pass 908 return False, "security.models.extensions.user_set_dbregs disabled" 909 return True, "watchpoint support available" 910 911def checkWatchpointSupport(): 912 result, reason = canRunWatchpointTests() 913 if result: 914 return # watchpoints supported 915 if "watchpoint" in configuration.categories_list: 916 return # watchpoint category explicitly requested, let it run. 917 print("watchpoint tests will not be run because: " + reason) 918 configuration.skip_categories.append("watchpoint") 919 920def checkDebugInfoSupport(): 921 import lldb 922 923 platform = lldb.selected_platform.GetTriple().split('-')[2] 924 compiler = configuration.compiler 925 skipped = [] 926 for cat in test_categories.debug_info_categories: 927 if cat in configuration.categories_list: 928 continue # Category explicitly requested, let it run. 929 if test_categories.is_supported_on_platform(cat, platform, compiler): 930 continue 931 configuration.skip_categories.append(cat) 932 skipped.append(cat) 933 if skipped: 934 print("Skipping following debug info categories:", skipped) 935 936def run_suite(): 937 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults 938 # does not exist before proceeding to running the test suite. 939 if sys.platform.startswith("darwin"): 940 checkDsymForUUIDIsNotOn() 941 942 # Start the actions by first parsing the options while setting up the test 943 # directories, followed by setting up the search paths for lldb utilities; 944 # then, we walk the directory trees and collect the tests into our test suite. 945 # 946 parseOptionsAndInitTestdirs() 947 948 # Setup test results (test results formatter and output handling). 949 setupTestResults() 950 951 setupSysPath() 952 953 import lldbconfig 954 if configuration.capture_path or configuration.replay_path: 955 lldbconfig.INITIALIZE = False 956 import lldb 957 958 if configuration.capture_path: 959 lldb.SBReproducer.Capture(configuration.capture_path) 960 lldb.SBReproducer.SetAutoGenerate(True) 961 elif configuration.replay_path: 962 lldb.SBReproducer.PassiveReplay(configuration.replay_path) 963 964 if not lldbconfig.INITIALIZE: 965 lldb.SBDebugger.Initialize() 966 967 # Use host platform by default. 968 lldb.selected_platform = lldb.SBPlatform.GetHostPlatform() 969 970 # Now we can also import lldbutil 971 from lldbsuite.test import lldbutil 972 973 if configuration.lldb_platform_name: 974 print("Setting up remote platform '%s'" % 975 (configuration.lldb_platform_name)) 976 lldb.remote_platform = lldb.SBPlatform( 977 configuration.lldb_platform_name) 978 if not lldb.remote_platform.IsValid(): 979 print( 980 "error: unable to create the LLDB platform named '%s'." % 981 (configuration.lldb_platform_name)) 982 exitTestSuite(1) 983 if configuration.lldb_platform_url: 984 # We must connect to a remote platform if a LLDB platform URL was 985 # specified 986 print( 987 "Connecting to remote platform '%s' at '%s'..." % 988 (configuration.lldb_platform_name, configuration.lldb_platform_url)) 989 platform_connect_options = lldb.SBPlatformConnectOptions( 990 configuration.lldb_platform_url) 991 err = lldb.remote_platform.ConnectRemote(platform_connect_options) 992 if err.Success(): 993 print("Connected.") 994 else: 995 print("error: failed to connect to remote platform using URL '%s': %s" % ( 996 configuration.lldb_platform_url, err)) 997 exitTestSuite(1) 998 else: 999 configuration.lldb_platform_url = None 1000 1001 platform_changes = setDefaultTripleForPlatform() 1002 first = True 1003 for key in platform_changes: 1004 if first: 1005 print("Environment variables setup for platform support:") 1006 first = False 1007 print("%s = %s" % (key, platform_changes[key])) 1008 1009 if configuration.lldb_platform_working_dir: 1010 print("Setting remote platform working directory to '%s'..." % 1011 (configuration.lldb_platform_working_dir)) 1012 error = lldb.remote_platform.MakeDirectory( 1013 configuration.lldb_platform_working_dir, 448) # 448 = 0o700 1014 if error.Fail(): 1015 raise Exception("making remote directory '%s': %s" % ( 1016 configuration.lldb_platform_working_dir, error)) 1017 1018 if not lldb.remote_platform.SetWorkingDirectory( 1019 configuration.lldb_platform_working_dir): 1020 raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir) 1021 lldb.selected_platform = lldb.remote_platform 1022 else: 1023 lldb.remote_platform = None 1024 configuration.lldb_platform_working_dir = None 1025 configuration.lldb_platform_url = None 1026 1027 # Set up the working directory. 1028 # Note that it's not dotest's job to clean this directory. 1029 lldbutil.mkdir_p(configuration.test_build_dir) 1030 1031 target_platform = lldb.selected_platform.GetTriple().split('-')[2] 1032 1033 checkLibcxxSupport() 1034 checkLibstdcxxSupport() 1035 checkWatchpointSupport() 1036 checkDebugInfoSupport() 1037 1038 # Don't do debugserver tests on anything except OS X. 1039 configuration.dont_do_debugserver_test = ( 1040 "linux" in target_platform or 1041 "freebsd" in target_platform or 1042 "netbsd" in target_platform or 1043 "windows" in target_platform) 1044 1045 # Don't do lldb-server (llgs) tests on anything except Linux and Windows. 1046 configuration.dont_do_llgs_test = not ( 1047 "linux" in target_platform or 1048 "netbsd" in target_platform or 1049 "windows" in target_platform) 1050 1051 for testdir in configuration.testdirs: 1052 for (dirpath, dirnames, filenames) in os.walk(testdir): 1053 visit('Test', dirpath, filenames) 1054 1055 # 1056 # Now that we have loaded all the test cases, run the whole test suite. 1057 # 1058 1059 # Install the control-c handler. 1060 unittest2.signals.installHandler() 1061 1062 lldbutil.mkdir_p(configuration.sdir_name) 1063 os.environ["LLDB_SESSION_DIRNAME"] = configuration.sdir_name 1064 1065 sys.stderr.write( 1066 "\nSession logs for test failures/errors/unexpected successes" 1067 " will go into directory '%s'\n" % 1068 configuration.sdir_name) 1069 1070 # 1071 # Invoke the default TextTestRunner to run the test suite 1072 # 1073 checkCompiler() 1074 1075 if configuration.verbose: 1076 print("compiler=%s" % configuration.compiler) 1077 1078 # Iterating over all possible architecture and compiler combinations. 1079 configString = "arch=%s compiler=%s" % (configuration.arch, 1080 configuration.compiler) 1081 1082 # Output the configuration. 1083 if configuration.verbose: 1084 sys.stderr.write("\nConfiguration: " + configString + "\n") 1085 1086 # First, write out the number of collected test cases. 1087 if configuration.verbose: 1088 sys.stderr.write(configuration.separator + "\n") 1089 sys.stderr.write( 1090 "Collected %d test%s\n\n" % 1091 (configuration.suite.countTestCases(), 1092 configuration.suite.countTestCases() != 1 and "s" or "")) 1093 1094 # Invoke the test runner. 1095 if configuration.count == 1: 1096 result = unittest2.TextTestRunner( 1097 stream=sys.stderr, 1098 verbosity=configuration.verbose, 1099 resultclass=test_result.LLDBTestResult).run( 1100 configuration.suite) 1101 else: 1102 # We are invoking the same test suite more than once. In this case, 1103 # mark __ignore_singleton__ flag as True so the signleton pattern is 1104 # not enforced. 1105 test_result.LLDBTestResult.__ignore_singleton__ = True 1106 for i in range(configuration.count): 1107 1108 result = unittest2.TextTestRunner( 1109 stream=sys.stderr, 1110 verbosity=configuration.verbose, 1111 resultclass=test_result.LLDBTestResult).run( 1112 configuration.suite) 1113 1114 configuration.failed = not result.wasSuccessful() 1115 1116 if configuration.sdir_has_content and configuration.verbose: 1117 sys.stderr.write( 1118 "Session logs for test failures/errors/unexpected successes" 1119 " can be found in directory '%s'\n" % 1120 configuration.sdir_name) 1121 1122 if configuration.use_categories and len( 1123 configuration.failures_per_category) > 0: 1124 sys.stderr.write("Failures per category:\n") 1125 for category in configuration.failures_per_category: 1126 sys.stderr.write( 1127 "%s - %d\n" % 1128 (category, configuration.failures_per_category[category])) 1129 1130 # Exiting. 1131 exitTestSuite(configuration.failed) 1132 1133if __name__ == "__main__": 1134 print( 1135 __file__ + 1136 " is for use as a module only. It should not be run as a standalone script.") 1137 sys.exit(-1) 1138