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