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