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