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