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 setting_list = setting[0].split('=', 1) 353 configuration.settings.append((setting_list[0], setting_list[1])) 354 355 if args.d: 356 sys.stdout.write( 357 "Suspending the process %d to wait for debugger to attach...\n" % 358 os.getpid()) 359 sys.stdout.flush() 360 os.kill(os.getpid(), signal.SIGSTOP) 361 362 if args.f: 363 if any([x.startswith('-') for x in args.f]): 364 usage(parser) 365 configuration.filters.extend(args.f) 366 367 if args.framework: 368 configuration.lldb_framework_path = args.framework 369 370 if args.executable: 371 # lldb executable is passed explicitly 372 lldbtest_config.lldbExec = os.path.realpath(args.executable) 373 if not is_exe(lldbtest_config.lldbExec): 374 lldbtest_config.lldbExec = which(args.executable) 375 if not is_exe(lldbtest_config.lldbExec): 376 logging.error( 377 '%s is not a valid executable to test; aborting...', 378 args.executable) 379 sys.exit(-1) 380 381 if args.server: 382 os.environ['LLDB_DEBUGSERVER_PATH'] = args.server 383 384 if args.excluded: 385 for excl_file in args.excluded: 386 parseExclusion(excl_file) 387 388 if args.p: 389 if args.p.startswith('-'): 390 usage(parser) 391 configuration.regexp = args.p 392 393 if args.s: 394 configuration.sdir_name = args.s 395 else: 396 timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S") 397 configuration.sdir_name = os.path.join(os.getcwd(), timestamp_started) 398 399 configuration.session_file_format = args.session_file_format 400 401 if args.t: 402 os.environ['LLDB_COMMAND_TRACE'] = 'YES' 403 404 if args.v: 405 configuration.verbose = 2 406 407 # argparse makes sure we have a number 408 if args.sharp: 409 configuration.count = args.sharp 410 411 if sys.platform.startswith('win32'): 412 os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str( 413 args.disable_crash_dialog) 414 os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True) 415 416 if do_help: 417 usage(parser) 418 419 if args.results_file: 420 configuration.results_filename = args.results_file 421 422 if args.results_formatter: 423 configuration.results_formatter_name = args.results_formatter 424 if args.results_formatter_options: 425 configuration.results_formatter_options = args.results_formatter_options 426 427 # Default to using the BasicResultsFormatter if no formatter is specified. 428 if configuration.results_formatter_name is None: 429 configuration.results_formatter_name = ( 430 "lldbsuite.test_event.formatter.results_formatter.ResultsFormatter") 431 432 # rerun-related arguments 433 configuration.rerun_all_issues = args.rerun_all_issues 434 435 if args.lldb_platform_name: 436 configuration.lldb_platform_name = args.lldb_platform_name 437 if args.lldb_platform_url: 438 configuration.lldb_platform_url = args.lldb_platform_url 439 if args.lldb_platform_working_dir: 440 configuration.lldb_platform_working_dir = args.lldb_platform_working_dir 441 if args.test_build_dir: 442 configuration.test_build_dir = args.test_build_dir 443 if args.lldb_module_cache_dir: 444 configuration.lldb_module_cache_dir = args.lldb_module_cache_dir 445 else: 446 configuration.lldb_module_cache_dir = os.path.join( 447 configuration.test_build_dir, 'module-cache-lldb') 448 if args.clang_module_cache_dir: 449 configuration.clang_module_cache_dir = args.clang_module_cache_dir 450 else: 451 configuration.clang_module_cache_dir = os.path.join( 452 configuration.test_build_dir, 'module-cache-clang') 453 454 os.environ['CLANG_MODULE_CACHE_DIR'] = configuration.clang_module_cache_dir 455 456 if args.lldb_libs_dir: 457 configuration.lldb_libs_dir = args.lldb_libs_dir 458 459 # Gather all the dirs passed on the command line. 460 if len(args.args) > 0: 461 configuration.testdirs = [os.path.realpath(os.path.abspath(x)) for x in args.args] 462 463 lldbtest_config.codesign_identity = args.codesign_identity 464 465 466def setupTestResults(): 467 """Sets up test results-related objects based on arg settings.""" 468 # Setup the results formatter configuration. 469 formatter_config = formatter.FormatterConfig() 470 formatter_config.filename = configuration.results_filename 471 formatter_config.formatter_name = configuration.results_formatter_name 472 formatter_config.formatter_options = ( 473 configuration.results_formatter_options) 474 475 # Create the results formatter. 476 formatter_spec = formatter.create_results_formatter( 477 formatter_config) 478 if formatter_spec is not None and formatter_spec.formatter is not None: 479 configuration.results_formatter_object = formatter_spec.formatter 480 481 # Send an initialize message to the formatter. 482 initialize_event = EventBuilder.bare_event("initialize") 483 initialize_event["worker_count"] = 1 484 485 formatter_spec.formatter.handle_event(initialize_event) 486 487 # Make sure we clean up the formatter on shutdown. 488 if formatter_spec.cleanup_func is not None: 489 atexit.register(formatter_spec.cleanup_func) 490 491 492def setupSysPath(): 493 """ 494 Add LLDB.framework/Resources/Python to the search paths for modules. 495 As a side effect, we also discover the 'lldb' executable and export it here. 496 """ 497 498 # Get the directory containing the current script. 499 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ: 500 scriptPath = os.environ["DOTEST_SCRIPT_DIR"] 501 else: 502 scriptPath = os.path.dirname(os.path.realpath(__file__)) 503 if not scriptPath.endswith('test'): 504 print("This script expects to reside in lldb's test directory.") 505 sys.exit(-1) 506 507 os.environ["LLDB_TEST"] = scriptPath 508 os.environ["LLDB_TEST_SRC"] = lldbsuite.lldb_test_root 509 510 # Set up the root build directory. 511 builddir = configuration.test_build_dir 512 if not configuration.test_build_dir: 513 raise Exception("test_build_dir is not set") 514 os.environ["LLDB_BUILD"] = os.path.abspath(configuration.test_build_dir) 515 516 # Set up the LLDB_SRC environment variable, so that the tests can locate 517 # the LLDB source code. 518 os.environ["LLDB_SRC"] = lldbsuite.lldb_root 519 520 pluginPath = os.path.join(scriptPath, 'plugins') 521 toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode') 522 toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server') 523 524 # Insert script dir, plugin dir and lldb-server dir to the sys.path. 525 sys.path.insert(0, pluginPath) 526 # Adding test/tools/lldb-vscode to the path makes it easy to 527 # "import lldb_vscode_testcase" from the VSCode tests 528 sys.path.insert(0, toolsLLDBVSCode) 529 # Adding test/tools/lldb-server to the path makes it easy 530 sys.path.insert(0, toolsLLDBServerPath) 531 # to "import lldbgdbserverutils" from the lldb-server tests 532 533 # This is the root of the lldb git/svn checkout 534 # When this changes over to a package instead of a standalone script, this 535 # will be `lldbsuite.lldb_root` 536 lldbRootDirectory = lldbsuite.lldb_root 537 538 # Some of the tests can invoke the 'lldb' command directly. 539 # We'll try to locate the appropriate executable right here. 540 541 # The lldb executable can be set from the command line 542 # if it's not set, we try to find it now 543 # first, we try the environment 544 if not lldbtest_config.lldbExec: 545 # First, you can define an environment variable LLDB_EXEC specifying the 546 # full pathname of the lldb executable. 547 if "LLDB_EXEC" in os.environ: 548 lldbtest_config.lldbExec = os.environ["LLDB_EXEC"] 549 550 if not lldbtest_config.lldbExec: 551 # Last, check the path 552 lldbtest_config.lldbExec = which('lldb') 553 554 if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec): 555 print( 556 "'{}' is not a path to a valid executable".format( 557 lldbtest_config.lldbExec)) 558 lldbtest_config.lldbExec = None 559 560 if not lldbtest_config.lldbExec: 561 print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.") 562 sys.exit(-1) 563 564 # confusingly, this is the "bin" directory 565 lldbLibDir = os.path.dirname(lldbtest_config.lldbExec) 566 os.environ["LLDB_LIB_DIR"] = lldbLibDir 567 lldbImpLibDir = configuration.lldb_libs_dir 568 os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir 569 print("LLDB library dir:", os.environ["LLDB_LIB_DIR"]) 570 print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"]) 571 os.system('%s -v' % lldbtest_config.lldbExec) 572 573 lldbDir = os.path.dirname(lldbtest_config.lldbExec) 574 575 lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode") 576 if is_exe(lldbVSCodeExec): 577 os.environ["LLDBVSCODE_EXEC"] = lldbVSCodeExec 578 else: 579 if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]): 580 print( 581 "The 'lldb-vscode' executable cannot be located. The lldb-vscode tests can not be run as a result.") 582 configuration.skip_categories.append("lldb-vscode") 583 584 lldbPythonDir = None # The directory that contains 'lldb/__init__.py' 585 if not configuration.lldb_framework_path and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")): 586 configuration.lldb_framework_path = os.path.join(lldbLibDir, "LLDB.framework") 587 if configuration.lldb_framework_path: 588 lldbtest_config.lldb_framework_path = configuration.lldb_framework_path 589 candidatePath = os.path.join( 590 configuration.lldb_framework_path, 'Resources', 'Python') 591 if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')): 592 lldbPythonDir = candidatePath 593 if not lldbPythonDir: 594 print( 595 'Resources/Python/lldb/__init__.py was not found in ' + 596 configuration.lldb_framework_path) 597 sys.exit(-1) 598 else: 599 # If our lldb supports the -P option, use it to find the python path: 600 init_in_python_dir = os.path.join('lldb', '__init__.py') 601 602 lldb_dash_p_result = subprocess.check_output( 603 [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True) 604 605 if lldb_dash_p_result and not lldb_dash_p_result.startswith( 606 ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"): 607 lines = lldb_dash_p_result.splitlines() 608 609 # Workaround for readline vs libedit issue on FreeBSD. If stdout 610 # is not a terminal Python executes 611 # rl_variable_bind ("enable-meta-key", "off"); 612 # This produces a warning with FreeBSD's libedit because the 613 # enable-meta-key variable is unknown. Not an issue on Apple 614 # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__ 615 # around the call. See http://bugs.python.org/issue19884 for more 616 # information. For now we just discard the warning output. 617 if len(lines) >= 1 and lines[0].startswith( 618 "bind: Invalid command"): 619 lines.pop(0) 620 621 # Taking the last line because lldb outputs 622 # 'Cannot read termcap database;\nusing dumb terminal settings.\n' 623 # before the path 624 if len(lines) >= 1 and os.path.isfile( 625 os.path.join(lines[-1], init_in_python_dir)): 626 lldbPythonDir = lines[-1] 627 if "freebsd" in sys.platform or "linux" in sys.platform: 628 os.environ['LLDB_LIB_DIR'] = os.path.join( 629 lldbPythonDir, '..', '..') 630 631 if not lldbPythonDir: 632 print( 633 "Unable to load lldb extension module. Possible reasons for this include:") 634 print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") 635 print( 636 " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") 637 print( 638 " the version of Python that LLDB built and linked against, and PYTHONPATH") 639 print( 640 " should contain the Lib directory for the same python distro, as well as the") 641 print(" location of LLDB\'s site-packages folder.") 642 print( 643 " 3) A different version of Python than that which was built against is exported in") 644 print(" the system\'s PATH environment variable, causing conflicts.") 645 print( 646 " 4) The executable '%s' could not be found. Please check " % 647 lldbtest_config.lldbExec) 648 print(" that it exists and is executable.") 649 650 if lldbPythonDir: 651 lldbPythonDir = os.path.normpath(lldbPythonDir) 652 # Some of the code that uses this path assumes it hasn't resolved the Versions... link. 653 # If the path we've constructed looks like that, then we'll strip out 654 # the Versions/A part. 655 (before, frameWithVersion, after) = lldbPythonDir.rpartition( 656 "LLDB.framework/Versions/A") 657 if frameWithVersion != "": 658 lldbPythonDir = before + "LLDB.framework" + after 659 660 lldbPythonDir = os.path.abspath(lldbPythonDir) 661 662 # If tests need to find LLDB_FRAMEWORK, now they can do it 663 os.environ["LLDB_FRAMEWORK"] = os.path.dirname( 664 os.path.dirname(lldbPythonDir)) 665 666 # This is to locate the lldb.py module. Insert it right after 667 # sys.path[0]. 668 sys.path[1:1] = [lldbPythonDir] 669 670 671def visit_file(dir, name): 672 # Try to match the regexp pattern, if specified. 673 if configuration.regexp: 674 if not re.search(configuration.regexp, name): 675 # We didn't match the regex, we're done. 676 return 677 678 if configuration.skip_tests: 679 for file_regexp in configuration.skip_tests: 680 if re.search(file_regexp, name): 681 return 682 683 # We found a match for our test. Add it to the suite. 684 685 # Update the sys.path first. 686 if not sys.path.count(dir): 687 sys.path.insert(0, dir) 688 base = os.path.splitext(name)[0] 689 690 # Thoroughly check the filterspec against the base module and admit 691 # the (base, filterspec) combination only when it makes sense. 692 693 def check(obj, parts): 694 for part in parts: 695 try: 696 parent, obj = obj, getattr(obj, part) 697 except AttributeError: 698 # The filterspec has failed. 699 return False 700 return True 701 702 module = __import__(base) 703 704 def iter_filters(): 705 for filterspec in configuration.filters: 706 parts = filterspec.split('.') 707 if check(module, parts): 708 yield filterspec 709 elif parts[0] == base and len(parts) > 1 and check(module, parts[1:]): 710 yield '.'.join(parts[1:]) 711 else: 712 for key,value in module.__dict__.items(): 713 if check(value, parts): 714 yield key + '.' + filterspec 715 716 filtered = False 717 for filterspec in iter_filters(): 718 filtered = True 719 print("adding filter spec %s to module %s" % (filterspec, repr(module))) 720 tests = unittest2.defaultTestLoader.loadTestsFromName(filterspec, module) 721 configuration.suite.addTests(tests) 722 723 # Forgo this module if the (base, filterspec) combo is invalid 724 if configuration.filters and not filtered: 725 return 726 727 if not filtered: 728 # Add the entire file's worth of tests since we're not filtered. 729 # Also the fail-over case when the filterspec branch 730 # (base, filterspec) combo doesn't make sense. 731 configuration.suite.addTests( 732 unittest2.defaultTestLoader.loadTestsFromName(base)) 733 734 735def visit(prefix, dir, names): 736 """Visitor function for os.path.walk(path, visit, arg).""" 737 738 dir_components = set(dir.split(os.sep)) 739 excluded_components = set(['.svn', '.git']) 740 if dir_components.intersection(excluded_components): 741 return 742 743 # Gather all the Python test file names that follow the Test*.py pattern. 744 python_test_files = [ 745 name 746 for name in names 747 if name.endswith('.py') and name.startswith(prefix)] 748 749 # Visit all the python test files. 750 for name in python_test_files: 751 try: 752 # Ensure we error out if we have multiple tests with the same 753 # base name. 754 # Future improvement: find all the places where we work with base 755 # names and convert to full paths. We have directory structure 756 # to disambiguate these, so we shouldn't need this constraint. 757 if name in configuration.all_tests: 758 raise Exception("Found multiple tests with the name %s" % name) 759 configuration.all_tests.add(name) 760 761 # Run the relevant tests in the python file. 762 visit_file(dir, name) 763 except Exception as ex: 764 # Convert this exception to a test event error for the file. 765 test_filename = os.path.abspath(os.path.join(dir, name)) 766 if configuration.results_formatter_object is not None: 767 # Grab the backtrace for the exception. 768 import traceback 769 backtrace = traceback.format_exc() 770 771 # Generate the test event. 772 configuration.results_formatter_object.handle_event( 773 EventBuilder.event_for_job_test_add_error( 774 test_filename, ex, backtrace)) 775 raise 776 777 778# ======================================== # 779# # 780# Execution of the test driver starts here # 781# # 782# ======================================== # 783 784 785def checkDsymForUUIDIsNotOn(): 786 cmd = ["defaults", "read", "com.apple.DebugSymbols"] 787 process = subprocess.Popen( 788 cmd, 789 stdout=subprocess.PIPE, 790 stderr=subprocess.STDOUT) 791 cmd_output = process.stdout.read() 792 output_str = cmd_output.decode("utf-8") 793 if "DBGFileMappedPaths = " in output_str: 794 print("%s =>" % ' '.join(cmd)) 795 print(output_str) 796 print( 797 "Disable automatic lookup and caching of dSYMs before running the test suite!") 798 print("Exiting...") 799 sys.exit(0) 800 801 802def exitTestSuite(exitCode=None): 803 # lldb.py does SBDebugger.Initialize(). 804 # Call SBDebugger.Terminate() on exit. 805 import lldb 806 lldb.SBDebugger.Terminate() 807 if exitCode: 808 sys.exit(exitCode) 809 810 811def getVersionForSDK(sdk): 812 sdk = str.lower(sdk) 813 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk) 814 basename = os.path.basename(full_path) 815 basename = os.path.splitext(basename)[0] 816 basename = str.lower(basename) 817 ver = basename.replace(sdk, '') 818 return ver 819 820 821def setDefaultTripleForPlatform(): 822 if configuration.lldb_platform_name == 'ios-simulator': 823 triple_str = 'x86_64-apple-ios%s' % ( 824 getVersionForSDK('iphonesimulator')) 825 os.environ['TRIPLE'] = triple_str 826 return {'TRIPLE': triple_str} 827 return {} 828 829 830def checkCompiler(): 831 # Add some intervention here to sanity check that the compiler requested is sane. 832 # If found not to be an executable program, we abort. 833 c = configuration.compiler 834 if which(c): 835 return 836 837 if not sys.platform.startswith("darwin"): 838 raise Exception(c + " is not a valid compiler") 839 840 pipe = subprocess.Popen( 841 ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 842 cmd_output = pipe.stdout.read() 843 if not cmd_output or "not found" in cmd_output: 844 raise Exception(c + " is not a valid compiler") 845 846 configuration.compiler = cmd_output.split('\n')[0] 847 print("'xcrun -find %s' returning %s" % (c, configuration.compiler)) 848 849def canRunLibcxxTests(): 850 from lldbsuite.test import lldbplatformutil 851 852 platform = lldbplatformutil.getPlatform() 853 854 if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin(): 855 return True, "libc++ always present" 856 857 if platform == "linux": 858 if os.path.isdir("/usr/include/c++/v1"): 859 return True, "Headers found, let's hope they work" 860 with tempfile.NamedTemporaryFile() as f: 861 cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.name, "-"] 862 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 863 _, stderr = p.communicate("#include <algorithm>\nint main() {}") 864 if not p.returncode: 865 return True, "Compiling with -stdlib=libc++ works" 866 return False, "Compiling with -stdlib=libc++ fails with the error: %s" % stderr 867 868 return False, "Don't know how to build with libc++ on %s" % platform 869 870def checkLibcxxSupport(): 871 result, reason = canRunLibcxxTests() 872 if result: 873 return # libc++ supported 874 if "libc++" in configuration.categories_list: 875 return # libc++ category explicitly requested, let it run. 876 print("Libc++ tests will not be run because: " + reason) 877 configuration.skip_categories.append("libc++") 878 879def canRunLibstdcxxTests(): 880 from lldbsuite.test import lldbplatformutil 881 882 platform = lldbplatformutil.getPlatform() 883 if lldbplatformutil.target_is_android(): 884 platform = "android" 885 if platform == "linux": 886 return True, "libstdcxx always present" 887 return False, "Don't know how to build with libstdcxx on %s" % platform 888 889def checkLibstdcxxSupport(): 890 result, reason = canRunLibstdcxxTests() 891 if result: 892 return # libstdcxx supported 893 if "libstdcxx" in configuration.categories_list: 894 return # libstdcxx category explicitly requested, let it run. 895 print("libstdcxx tests will not be run because: " + reason) 896 configuration.skip_categories.append("libstdcxx") 897 898def canRunWatchpointTests(): 899 from lldbsuite.test import lldbplatformutil 900 901 platform = lldbplatformutil.getPlatform() 902 if platform == "netbsd": 903 if os.geteuid() == 0: 904 return True, "root can always write dbregs" 905 try: 906 output = subprocess.check_output(["/sbin/sysctl", "-n", 907 "security.models.extensions.user_set_dbregs"]).decode().strip() 908 if output == "1": 909 return True, "security.models.extensions.user_set_dbregs enabled" 910 except subprocess.CalledProcessError: 911 pass 912 return False, "security.models.extensions.user_set_dbregs disabled" 913 return True, "watchpoint support available" 914 915def checkWatchpointSupport(): 916 result, reason = canRunWatchpointTests() 917 if result: 918 return # watchpoints supported 919 if "watchpoint" in configuration.categories_list: 920 return # watchpoint category explicitly requested, let it run. 921 print("watchpoint tests will not be run because: " + reason) 922 configuration.skip_categories.append("watchpoint") 923 924def checkDebugInfoSupport(): 925 import lldb 926 927 platform = lldb.selected_platform.GetTriple().split('-')[2] 928 compiler = configuration.compiler 929 skipped = [] 930 for cat in test_categories.debug_info_categories: 931 if cat in configuration.categories_list: 932 continue # Category explicitly requested, let it run. 933 if test_categories.is_supported_on_platform(cat, platform, compiler): 934 continue 935 configuration.skip_categories.append(cat) 936 skipped.append(cat) 937 if skipped: 938 print("Skipping following debug info categories:", skipped) 939 940def run_suite(): 941 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults 942 # does not exist before proceeding to running the test suite. 943 if sys.platform.startswith("darwin"): 944 checkDsymForUUIDIsNotOn() 945 946 # Start the actions by first parsing the options while setting up the test 947 # directories, followed by setting up the search paths for lldb utilities; 948 # then, we walk the directory trees and collect the tests into our test suite. 949 # 950 parseOptionsAndInitTestdirs() 951 952 # Setup test results (test results formatter and output handling). 953 setupTestResults() 954 955 setupSysPath() 956 957 import lldb 958 # Use host platform by default. 959 lldb.selected_platform = lldb.SBPlatform.GetHostPlatform() 960 961 # Now we can also import lldbutil 962 from lldbsuite.test import lldbutil 963 964 if configuration.lldb_platform_name: 965 print("Setting up remote platform '%s'" % 966 (configuration.lldb_platform_name)) 967 lldb.remote_platform = lldb.SBPlatform( 968 configuration.lldb_platform_name) 969 if not lldb.remote_platform.IsValid(): 970 print( 971 "error: unable to create the LLDB platform named '%s'." % 972 (configuration.lldb_platform_name)) 973 exitTestSuite(1) 974 if configuration.lldb_platform_url: 975 # We must connect to a remote platform if a LLDB platform URL was 976 # specified 977 print( 978 "Connecting to remote platform '%s' at '%s'..." % 979 (configuration.lldb_platform_name, configuration.lldb_platform_url)) 980 platform_connect_options = lldb.SBPlatformConnectOptions( 981 configuration.lldb_platform_url) 982 err = lldb.remote_platform.ConnectRemote(platform_connect_options) 983 if err.Success(): 984 print("Connected.") 985 else: 986 print("error: failed to connect to remote platform using URL '%s': %s" % ( 987 configuration.lldb_platform_url, err)) 988 exitTestSuite(1) 989 else: 990 configuration.lldb_platform_url = None 991 992 platform_changes = setDefaultTripleForPlatform() 993 first = True 994 for key in platform_changes: 995 if first: 996 print("Environment variables setup for platform support:") 997 first = False 998 print("%s = %s" % (key, platform_changes[key])) 999 1000 if configuration.lldb_platform_working_dir: 1001 print("Setting remote platform working directory to '%s'..." % 1002 (configuration.lldb_platform_working_dir)) 1003 error = lldb.remote_platform.MakeDirectory( 1004 configuration.lldb_platform_working_dir, 448) # 448 = 0o700 1005 if error.Fail(): 1006 raise Exception("making remote directory '%s': %s" % ( 1007 configuration.lldb_platform_working_dir, error)) 1008 1009 if not lldb.remote_platform.SetWorkingDirectory( 1010 configuration.lldb_platform_working_dir): 1011 raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir) 1012 lldb.selected_platform = lldb.remote_platform 1013 else: 1014 lldb.remote_platform = None 1015 configuration.lldb_platform_working_dir = None 1016 configuration.lldb_platform_url = None 1017 1018 # Set up the working directory. 1019 # Note that it's not dotest's job to clean this directory. 1020 build_dir = configuration.test_build_dir 1021 lldbutil.mkdir_p(build_dir) 1022 1023 target_platform = lldb.selected_platform.GetTriple().split('-')[2] 1024 1025 checkLibcxxSupport() 1026 checkLibstdcxxSupport() 1027 checkWatchpointSupport() 1028 checkDebugInfoSupport() 1029 1030 # Don't do debugserver tests on anything except OS X. 1031 configuration.dont_do_debugserver_test = ( 1032 "linux" in target_platform or 1033 "freebsd" in target_platform or 1034 "netbsd" in target_platform or 1035 "windows" in target_platform) 1036 1037 # Don't do lldb-server (llgs) tests on anything except Linux and Windows. 1038 configuration.dont_do_llgs_test = not ( 1039 "linux" in target_platform or 1040 "netbsd" in target_platform or 1041 "windows" in target_platform) 1042 1043 for testdir in configuration.testdirs: 1044 for (dirpath, dirnames, filenames) in os.walk(testdir): 1045 visit('Test', dirpath, filenames) 1046 1047 # 1048 # Now that we have loaded all the test cases, run the whole test suite. 1049 # 1050 1051 # Install the control-c handler. 1052 unittest2.signals.installHandler() 1053 1054 lldbutil.mkdir_p(configuration.sdir_name) 1055 os.environ["LLDB_SESSION_DIRNAME"] = configuration.sdir_name 1056 1057 sys.stderr.write( 1058 "\nSession logs for test failures/errors/unexpected successes" 1059 " will go into directory '%s'\n" % 1060 configuration.sdir_name) 1061 sys.stderr.write("Command invoked: %s\n" % get_dotest_invocation()) 1062 1063 # 1064 # Invoke the default TextTestRunner to run the test suite 1065 # 1066 checkCompiler() 1067 1068 if configuration.verbose: 1069 print("compiler=%s" % configuration.compiler) 1070 1071 # Iterating over all possible architecture and compiler combinations. 1072 os.environ["ARCH"] = configuration.arch 1073 os.environ["CC"] = configuration.compiler 1074 configString = "arch=%s compiler=%s" % (configuration.arch, 1075 configuration.compiler) 1076 1077 # Output the configuration. 1078 if configuration.verbose: 1079 sys.stderr.write("\nConfiguration: " + configString + "\n") 1080 1081 # First, write out the number of collected test cases. 1082 if configuration.verbose: 1083 sys.stderr.write(configuration.separator + "\n") 1084 sys.stderr.write( 1085 "Collected %d test%s\n\n" % 1086 (configuration.suite.countTestCases(), 1087 configuration.suite.countTestCases() != 1 and "s" or "")) 1088 1089 # Invoke the test runner. 1090 if configuration.count == 1: 1091 result = unittest2.TextTestRunner( 1092 stream=sys.stderr, 1093 verbosity=configuration.verbose, 1094 resultclass=test_result.LLDBTestResult).run( 1095 configuration.suite) 1096 else: 1097 # We are invoking the same test suite more than once. In this case, 1098 # mark __ignore_singleton__ flag as True so the signleton pattern is 1099 # not enforced. 1100 test_result.LLDBTestResult.__ignore_singleton__ = True 1101 for i in range(configuration.count): 1102 1103 result = unittest2.TextTestRunner( 1104 stream=sys.stderr, 1105 verbosity=configuration.verbose, 1106 resultclass=test_result.LLDBTestResult).run( 1107 configuration.suite) 1108 1109 configuration.failed = not result.wasSuccessful() 1110 1111 if configuration.sdir_has_content and configuration.verbose: 1112 sys.stderr.write( 1113 "Session logs for test failures/errors/unexpected successes" 1114 " can be found in directory '%s'\n" % 1115 configuration.sdir_name) 1116 1117 if configuration.use_categories and len( 1118 configuration.failures_per_category) > 0: 1119 sys.stderr.write("Failures per category:\n") 1120 for category in configuration.failures_per_category: 1121 sys.stderr.write( 1122 "%s - %d\n" % 1123 (category, configuration.failures_per_category[category])) 1124 1125 # Exiting. 1126 exitTestSuite(configuration.failed) 1127 1128if __name__ == "__main__": 1129 print( 1130 __file__ + 1131 " is for use as a module only. It should not be run as a standalone script.") 1132 sys.exit(-1) 1133