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 configuration.hermetic_libcxx = args.hermetic_libcxx 285 if configuration.hermetic_libcxx and args.lldb_platform_name: 286 configuration.hermetic_libcxx = False 287 logging.warning('Hermetic libc++ is not supported for remote runs: ignoring --hermetic-libcxx') 288 289 if args.channels: 290 lldbtest_config.channels = args.channels 291 292 if args.log_success: 293 lldbtest_config.log_success = args.log_success 294 295 if args.out_of_tree_debugserver: 296 lldbtest_config.out_of_tree_debugserver = args.out_of_tree_debugserver 297 298 # Set SDKROOT if we are using an Apple SDK 299 if platform_system == 'Darwin' and args.apple_sdk: 300 configuration.sdkroot = seven.get_command_output( 301 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % 302 (args.apple_sdk)) 303 if not configuration.sdkroot: 304 logging.error( 305 'No SDK found with the name %s; aborting...', 306 args.apple_sdk) 307 sys.exit(-1) 308 309 if args.arch: 310 configuration.arch = args.arch 311 else: 312 configuration.arch = platform_machine 313 314 if args.categories_list: 315 configuration.categories_list = set( 316 test_categories.validate( 317 args.categories_list, False)) 318 configuration.use_categories = True 319 else: 320 configuration.categories_list = [] 321 322 if args.skip_categories: 323 configuration.skip_categories += test_categories.validate( 324 args.skip_categories, False) 325 326 if args.xfail_categories: 327 configuration.xfail_categories += test_categories.validate( 328 args.xfail_categories, False) 329 330 if args.E: 331 os.environ['CFLAGS_EXTRAS'] = args.E 332 333 if args.dwarf_version: 334 configuration.dwarf_version = args.dwarf_version 335 # We cannot modify CFLAGS_EXTRAS because they're used in test cases 336 # that explicitly require no debug info. 337 os.environ['CFLAGS'] = '-gdwarf-{}'.format(configuration.dwarf_version) 338 339 if args.settings: 340 for setting in args.settings: 341 if not len(setting) == 1 or not setting[0].count('='): 342 logging.error('"%s" is not a setting in the form "key=value"', 343 setting[0]) 344 sys.exit(-1) 345 setting_list = setting[0].split('=', 1) 346 configuration.settings.append((setting_list[0], setting_list[1])) 347 348 if args.d: 349 sys.stdout.write( 350 "Suspending the process %d to wait for debugger to attach...\n" % 351 os.getpid()) 352 sys.stdout.flush() 353 os.kill(os.getpid(), signal.SIGSTOP) 354 355 if args.f: 356 if any([x.startswith('-') for x in args.f]): 357 usage(parser) 358 configuration.filters.extend(args.f) 359 360 if args.framework: 361 configuration.lldb_framework_path = args.framework 362 363 if args.executable: 364 # lldb executable is passed explicitly 365 lldbtest_config.lldbExec = os.path.abspath(args.executable) 366 if not is_exe(lldbtest_config.lldbExec): 367 lldbtest_config.lldbExec = which(args.executable) 368 if not is_exe(lldbtest_config.lldbExec): 369 logging.error( 370 '%s is not a valid executable to test; aborting...', 371 args.executable) 372 sys.exit(-1) 373 374 if args.excluded: 375 for excl_file in args.excluded: 376 parseExclusion(excl_file) 377 378 if args.p: 379 if args.p.startswith('-'): 380 usage(parser) 381 configuration.regexp = args.p 382 383 if args.t: 384 os.environ['LLDB_COMMAND_TRACE'] = 'YES' 385 386 if args.v: 387 configuration.verbose = 2 388 389 # argparse makes sure we have a number 390 if args.sharp: 391 configuration.count = args.sharp 392 393 if sys.platform.startswith('win32'): 394 os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str( 395 args.disable_crash_dialog) 396 os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True) 397 398 if do_help: 399 usage(parser) 400 401 if args.lldb_platform_name: 402 configuration.lldb_platform_name = args.lldb_platform_name 403 if args.lldb_platform_url: 404 configuration.lldb_platform_url = args.lldb_platform_url 405 if args.lldb_platform_working_dir: 406 configuration.lldb_platform_working_dir = args.lldb_platform_working_dir 407 if platform_system == 'Darwin' and args.apple_sdk: 408 configuration.apple_sdk = args.apple_sdk 409 if args.test_build_dir: 410 configuration.test_build_dir = args.test_build_dir 411 if args.lldb_module_cache_dir: 412 configuration.lldb_module_cache_dir = args.lldb_module_cache_dir 413 else: 414 configuration.lldb_module_cache_dir = os.path.join( 415 configuration.test_build_dir, 'module-cache-lldb') 416 if args.clang_module_cache_dir: 417 configuration.clang_module_cache_dir = args.clang_module_cache_dir 418 else: 419 configuration.clang_module_cache_dir = os.path.join( 420 configuration.test_build_dir, 'module-cache-clang') 421 422 if args.lldb_libs_dir: 423 configuration.lldb_libs_dir = args.lldb_libs_dir 424 425 if args.enabled_plugins: 426 configuration.enabled_plugins = args.enabled_plugins 427 428 # Gather all the dirs passed on the command line. 429 if len(args.args) > 0: 430 configuration.testdirs = [os.path.realpath(os.path.abspath(x)) for x in args.args] 431 432 lldbtest_config.codesign_identity = args.codesign_identity 433 434def registerFaulthandler(): 435 try: 436 import faulthandler 437 except ImportError: 438 # faulthandler is not available until python3 439 return 440 441 faulthandler.enable() 442 # faulthandler.register is not available on Windows. 443 if getattr(faulthandler, 'register', None): 444 faulthandler.register(signal.SIGTERM, chain=True) 445 446def setupSysPath(): 447 """ 448 Add LLDB.framework/Resources/Python to the search paths for modules. 449 As a side effect, we also discover the 'lldb' executable and export it here. 450 """ 451 452 # Get the directory containing the current script. 453 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ: 454 scriptPath = os.environ["DOTEST_SCRIPT_DIR"] 455 else: 456 scriptPath = os.path.dirname(os.path.abspath(__file__)) 457 if not scriptPath.endswith('test'): 458 print("This script expects to reside in lldb's test directory.") 459 sys.exit(-1) 460 461 os.environ["LLDB_TEST"] = scriptPath 462 463 # Set up the root build directory. 464 if not configuration.test_build_dir: 465 raise Exception("test_build_dir is not set") 466 configuration.test_build_dir = os.path.abspath(configuration.test_build_dir) 467 468 # Set up the LLDB_SRC environment variable, so that the tests can locate 469 # the LLDB source code. 470 os.environ["LLDB_SRC"] = lldbsuite.lldb_root 471 472 pluginPath = os.path.join(scriptPath, 'plugins') 473 toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode') 474 toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server') 475 intelpt = os.path.join(scriptPath, 'tools', 'intelpt') 476 477 # Insert script dir, plugin dir and lldb-server dir to the sys.path. 478 sys.path.insert(0, pluginPath) 479 # Adding test/tools/lldb-vscode to the path makes it easy to 480 # "import lldb_vscode_testcase" from the VSCode tests 481 sys.path.insert(0, toolsLLDBVSCode) 482 # Adding test/tools/lldb-server to the path makes it easy 483 # to "import lldbgdbserverutils" from the lldb-server tests 484 sys.path.insert(0, toolsLLDBServerPath) 485 # Adding test/tools/intelpt to the path makes it easy 486 # to "import intelpt_testcase" from the lldb-server tests 487 sys.path.insert(0, intelpt) 488 489 # This is the root of the lldb git/svn checkout 490 # When this changes over to a package instead of a standalone script, this 491 # will be `lldbsuite.lldb_root` 492 lldbRootDirectory = lldbsuite.lldb_root 493 494 # Some of the tests can invoke the 'lldb' command directly. 495 # We'll try to locate the appropriate executable right here. 496 497 # The lldb executable can be set from the command line 498 # if it's not set, we try to find it now 499 # first, we try the environment 500 if not lldbtest_config.lldbExec: 501 # First, you can define an environment variable LLDB_EXEC specifying the 502 # full pathname of the lldb executable. 503 if "LLDB_EXEC" in os.environ: 504 lldbtest_config.lldbExec = os.environ["LLDB_EXEC"] 505 506 if not lldbtest_config.lldbExec: 507 # Last, check the path 508 lldbtest_config.lldbExec = which('lldb') 509 510 if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec): 511 print( 512 "'{}' is not a path to a valid executable".format( 513 lldbtest_config.lldbExec)) 514 lldbtest_config.lldbExec = None 515 516 if not lldbtest_config.lldbExec: 517 print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.") 518 sys.exit(-1) 519 520 os.system('%s -v' % lldbtest_config.lldbExec) 521 522 lldbDir = os.path.dirname(lldbtest_config.lldbExec) 523 524 lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode") 525 if is_exe(lldbVSCodeExec): 526 os.environ["LLDBVSCODE_EXEC"] = lldbVSCodeExec 527 else: 528 if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]): 529 print( 530 "The 'lldb-vscode' executable cannot be located. The lldb-vscode tests can not be run as a result.") 531 configuration.skip_categories.append("lldb-vscode") 532 533 lldbPythonDir = None # The directory that contains 'lldb/__init__.py' 534 535 # If our lldb supports the -P option, use it to find the python path: 536 lldb_dash_p_result = subprocess.check_output([lldbtest_config.lldbExec, "-P"], universal_newlines=True) 537 if lldb_dash_p_result: 538 for line in lldb_dash_p_result.splitlines(): 539 if os.path.isdir(line) and os.path.exists(os.path.join(line, 'lldb', '__init__.py')): 540 lldbPythonDir = line 541 break 542 543 if not lldbPythonDir: 544 print( 545 "Unable to load lldb extension module. Possible reasons for this include:") 546 print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") 547 print( 548 " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") 549 print( 550 " the version of Python that LLDB built and linked against, and PYTHONPATH") 551 print( 552 " should contain the Lib directory for the same python distro, as well as the") 553 print(" location of LLDB\'s site-packages folder.") 554 print( 555 " 3) A different version of Python than that which was built against is exported in") 556 print(" the system\'s PATH environment variable, causing conflicts.") 557 print( 558 " 4) The executable '%s' could not be found. Please check " % 559 lldbtest_config.lldbExec) 560 print(" that it exists and is executable.") 561 562 if lldbPythonDir: 563 lldbPythonDir = os.path.normpath(lldbPythonDir) 564 # Some of the code that uses this path assumes it hasn't resolved the Versions... link. 565 # If the path we've constructed looks like that, then we'll strip out 566 # the Versions/A part. 567 (before, frameWithVersion, after) = lldbPythonDir.rpartition( 568 "LLDB.framework/Versions/A") 569 if frameWithVersion != "": 570 lldbPythonDir = before + "LLDB.framework" + after 571 572 lldbPythonDir = os.path.abspath(lldbPythonDir) 573 574 if "freebsd" in sys.platform or "linux" in sys.platform: 575 os.environ['LLDB_LIB_DIR'] = os.path.join(lldbPythonDir, '..', '..') 576 577 # If tests need to find LLDB_FRAMEWORK, now they can do it 578 os.environ["LLDB_FRAMEWORK"] = os.path.dirname( 579 os.path.dirname(lldbPythonDir)) 580 581 # This is to locate the lldb.py module. Insert it right after 582 # sys.path[0]. 583 sys.path[1:1] = [lldbPythonDir] 584 585 586def visit_file(dir, name): 587 # Try to match the regexp pattern, if specified. 588 if configuration.regexp: 589 if not re.search(configuration.regexp, name): 590 # We didn't match the regex, we're done. 591 return 592 593 if configuration.skip_tests: 594 for file_regexp in configuration.skip_tests: 595 if re.search(file_regexp, name): 596 return 597 598 # We found a match for our test. Add it to the suite. 599 600 # Update the sys.path first. 601 if not sys.path.count(dir): 602 sys.path.insert(0, dir) 603 base = os.path.splitext(name)[0] 604 605 # Thoroughly check the filterspec against the base module and admit 606 # the (base, filterspec) combination only when it makes sense. 607 608 def check(obj, parts): 609 for part in parts: 610 try: 611 parent, obj = obj, getattr(obj, part) 612 except AttributeError: 613 # The filterspec has failed. 614 return False 615 return True 616 617 module = __import__(base) 618 619 def iter_filters(): 620 for filterspec in configuration.filters: 621 parts = filterspec.split('.') 622 if check(module, parts): 623 yield filterspec 624 elif parts[0] == base and len(parts) > 1 and check(module, parts[1:]): 625 yield '.'.join(parts[1:]) 626 else: 627 for key,value in module.__dict__.items(): 628 if check(value, parts): 629 yield key + '.' + filterspec 630 631 filtered = False 632 for filterspec in iter_filters(): 633 filtered = True 634 print("adding filter spec %s to module %s" % (filterspec, repr(module))) 635 tests = unittest2.defaultTestLoader.loadTestsFromName(filterspec, module) 636 configuration.suite.addTests(tests) 637 638 # Forgo this module if the (base, filterspec) combo is invalid 639 if configuration.filters and not filtered: 640 return 641 642 if not filtered: 643 # Add the entire file's worth of tests since we're not filtered. 644 # Also the fail-over case when the filterspec branch 645 # (base, filterspec) combo doesn't make sense. 646 configuration.suite.addTests( 647 unittest2.defaultTestLoader.loadTestsFromName(base)) 648 649 650def visit(prefix, dir, names): 651 """Visitor function for os.path.walk(path, visit, arg).""" 652 653 dir_components = set(dir.split(os.sep)) 654 excluded_components = set(['.svn', '.git']) 655 if dir_components.intersection(excluded_components): 656 return 657 658 # Gather all the Python test file names that follow the Test*.py pattern. 659 python_test_files = [ 660 name 661 for name in names 662 if name.endswith('.py') and name.startswith(prefix)] 663 664 # Visit all the python test files. 665 for name in python_test_files: 666 # Ensure we error out if we have multiple tests with the same 667 # base name. 668 # Future improvement: find all the places where we work with base 669 # names and convert to full paths. We have directory structure 670 # to disambiguate these, so we shouldn't need this constraint. 671 if name in configuration.all_tests: 672 raise Exception("Found multiple tests with the name %s" % name) 673 configuration.all_tests.add(name) 674 675 # Run the relevant tests in the python file. 676 visit_file(dir, name) 677 678 679# ======================================== # 680# # 681# Execution of the test driver starts here # 682# # 683# ======================================== # 684 685 686def checkDsymForUUIDIsNotOn(): 687 cmd = ["defaults", "read", "com.apple.DebugSymbols"] 688 process = subprocess.Popen( 689 cmd, 690 stdout=subprocess.PIPE, 691 stderr=subprocess.STDOUT) 692 cmd_output = process.stdout.read() 693 output_str = cmd_output.decode("utf-8") 694 if "DBGFileMappedPaths = " in output_str: 695 print("%s =>" % ' '.join(cmd)) 696 print(output_str) 697 print( 698 "Disable automatic lookup and caching of dSYMs before running the test suite!") 699 print("Exiting...") 700 sys.exit(0) 701 702 703def exitTestSuite(exitCode=None): 704 # lldb.py does SBDebugger.Initialize(). 705 # Call SBDebugger.Terminate() on exit. 706 import lldb 707 lldb.SBDebugger.Terminate() 708 if exitCode: 709 sys.exit(exitCode) 710 711 712def getVersionForSDK(sdk): 713 sdk = str.lower(sdk) 714 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk) 715 basename = os.path.basename(full_path) 716 basename = os.path.splitext(basename)[0] 717 basename = str.lower(basename) 718 ver = basename.replace(sdk, '') 719 return ver 720 721 722def checkCompiler(): 723 # Add some intervention here to sanity check that the compiler requested is sane. 724 # If found not to be an executable program, we abort. 725 c = configuration.compiler 726 if which(c): 727 return 728 729 if not sys.platform.startswith("darwin"): 730 raise Exception(c + " is not a valid compiler") 731 732 pipe = subprocess.Popen( 733 ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 734 cmd_output = pipe.stdout.read() 735 if not cmd_output or "not found" in cmd_output: 736 raise Exception(c + " is not a valid compiler") 737 738 configuration.compiler = cmd_output.split('\n')[0] 739 print("'xcrun -find %s' returning %s" % (c, configuration.compiler)) 740 741def canRunLibcxxTests(): 742 from lldbsuite.test import lldbplatformutil 743 744 platform = lldbplatformutil.getPlatform() 745 746 if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin(): 747 return True, "libc++ always present" 748 749 if platform == "linux": 750 with tempfile.NamedTemporaryFile() as f: 751 cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.name, "-"] 752 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 753 _, stderr = p.communicate("#include <cassert>\nint main() {}") 754 if not p.returncode: 755 return True, "Compiling with -stdlib=libc++ works" 756 return False, "Compiling with -stdlib=libc++ fails with the error: %s" % stderr 757 758 return False, "Don't know how to build with libc++ on %s" % platform 759 760def checkLibcxxSupport(): 761 result, reason = canRunLibcxxTests() 762 if result: 763 return # libc++ supported 764 if "libc++" in configuration.categories_list: 765 return # libc++ category explicitly requested, let it run. 766 if configuration.verbose: 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 if configuration.verbose: 787 print("libstdcxx tests will not be run because: " + reason) 788 configuration.skip_categories.append("libstdcxx") 789 790def canRunWatchpointTests(): 791 from lldbsuite.test import lldbplatformutil 792 793 platform = lldbplatformutil.getPlatform() 794 if platform == "netbsd": 795 if os.geteuid() == 0: 796 return True, "root can always write dbregs" 797 try: 798 output = subprocess.check_output(["/sbin/sysctl", "-n", 799 "security.models.extensions.user_set_dbregs"]).decode().strip() 800 if output == "1": 801 return True, "security.models.extensions.user_set_dbregs enabled" 802 except subprocess.CalledProcessError: 803 pass 804 return False, "security.models.extensions.user_set_dbregs disabled" 805 elif platform == "freebsd" and configuration.arch == "aarch64": 806 import lldb 807 if lldb.SBPlatform.GetHostPlatform().GetOSMajorVersion() < 13: 808 return False, "Watchpoint support on arm64 requires FreeBSD 13.0" 809 return True, "watchpoint support available" 810 811def checkWatchpointSupport(): 812 result, reason = canRunWatchpointTests() 813 if result: 814 return # watchpoints supported 815 if "watchpoint" in configuration.categories_list: 816 return # watchpoint category explicitly requested, let it run. 817 if configuration.verbose: 818 print("watchpoint tests will not be run because: " + reason) 819 configuration.skip_categories.append("watchpoint") 820 821def checkObjcSupport(): 822 from lldbsuite.test import lldbplatformutil 823 824 if not lldbplatformutil.platformIsDarwin(): 825 if configuration.verbose: 826 print("objc tests will be skipped because of unsupported platform") 827 configuration.skip_categories.append("objc") 828 829def checkDebugInfoSupport(): 830 from lldbsuite.test import lldbplatformutil 831 832 platform = lldbplatformutil.getPlatform() 833 compiler = configuration.compiler 834 for cat in test_categories.debug_info_categories: 835 if cat in configuration.categories_list: 836 continue # Category explicitly requested, let it run. 837 if test_categories.is_supported_on_platform(cat, platform, compiler): 838 continue 839 configuration.skip_categories.append(cat) 840 841def checkDebugServerSupport(): 842 from lldbsuite.test import lldbplatformutil 843 import lldb 844 845 skip_msg = "Skipping %s tests, as they are not compatible with remote testing on this platform" 846 if lldbplatformutil.platformIsDarwin(): 847 configuration.skip_categories.append("llgs") 848 if configuration.lldb_platform_name: 849 # <rdar://problem/34539270> 850 configuration.skip_categories.append("debugserver") 851 if configuration.verbose: 852 print(skip_msg%"debugserver"); 853 else: 854 configuration.skip_categories.append("debugserver") 855 if configuration.lldb_platform_name and lldbplatformutil.getPlatform() == "windows": 856 configuration.skip_categories.append("llgs") 857 if configuration.verbose: 858 print(skip_msg%"lldb-server"); 859 860 861def checkForkVForkSupport(): 862 from lldbsuite.test import lldbplatformutil 863 864 platform = lldbplatformutil.getPlatform() 865 if platform not in ["freebsd", "linux", "netbsd"]: 866 configuration.skip_categories.append("fork") 867 868 869def run_suite(): 870 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults 871 # does not exist before proceeding to running the test suite. 872 if sys.platform.startswith("darwin"): 873 checkDsymForUUIDIsNotOn() 874 875 # Start the actions by first parsing the options while setting up the test 876 # directories, followed by setting up the search paths for lldb utilities; 877 # then, we walk the directory trees and collect the tests into our test suite. 878 # 879 parseOptionsAndInitTestdirs() 880 881 # Print a stack trace if the test hangs or is passed SIGTERM. 882 registerFaulthandler() 883 884 setupSysPath() 885 886 import lldb 887 lldb.SBDebugger.Initialize() 888 lldb.SBDebugger.PrintStackTraceOnError() 889 890 checkLibcxxSupport() 891 checkLibstdcxxSupport() 892 checkWatchpointSupport() 893 checkDebugInfoSupport() 894 checkDebugServerSupport() 895 checkObjcSupport() 896 checkForkVForkSupport() 897 898 # Use host platform by default. 899 lldb.remote_platform = None 900 lldb.selected_platform = lldb.SBPlatform.GetHostPlatform() 901 902 # Now we can also import lldbutil 903 from lldbsuite.test import lldbutil 904 905 if configuration.lldb_platform_name: 906 print("Setting up remote platform '%s'" % 907 (configuration.lldb_platform_name)) 908 lldb.remote_platform = lldb.SBPlatform( 909 configuration.lldb_platform_name) 910 lldb.selected_platform = lldb.remote_platform 911 if not lldb.remote_platform.IsValid(): 912 print( 913 "error: unable to create the LLDB platform named '%s'." % 914 (configuration.lldb_platform_name)) 915 exitTestSuite(1) 916 if configuration.lldb_platform_url: 917 # We must connect to a remote platform if a LLDB platform URL was 918 # specified 919 print( 920 "Connecting to remote platform '%s' at '%s'..." % 921 (configuration.lldb_platform_name, configuration.lldb_platform_url)) 922 platform_connect_options = lldb.SBPlatformConnectOptions( 923 configuration.lldb_platform_url) 924 err = lldb.remote_platform.ConnectRemote(platform_connect_options) 925 if err.Success(): 926 print("Connected.") 927 else: 928 print("error: failed to connect to remote platform using URL '%s': %s" % ( 929 configuration.lldb_platform_url, err)) 930 exitTestSuite(1) 931 else: 932 configuration.lldb_platform_url = None 933 934 if configuration.lldb_platform_working_dir: 935 print("Setting remote platform working directory to '%s'..." % 936 (configuration.lldb_platform_working_dir)) 937 error = lldb.remote_platform.MakeDirectory( 938 configuration.lldb_platform_working_dir, 448) # 448 = 0o700 939 if error.Fail(): 940 raise Exception("making remote directory '%s': %s" % ( 941 configuration.lldb_platform_working_dir, error)) 942 943 if not lldb.remote_platform.SetWorkingDirectory( 944 configuration.lldb_platform_working_dir): 945 raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir) 946 lldb.selected_platform = lldb.remote_platform 947 else: 948 lldb.remote_platform = None 949 configuration.lldb_platform_working_dir = None 950 configuration.lldb_platform_url = None 951 952 # Set up the working directory. 953 # Note that it's not dotest's job to clean this directory. 954 lldbutil.mkdir_p(configuration.test_build_dir) 955 956 print("Skipping the following test categories: {}".format(configuration.skip_categories)) 957 958 for testdir in configuration.testdirs: 959 for (dirpath, dirnames, filenames) in os.walk(testdir): 960 visit('Test', dirpath, filenames) 961 962 # 963 # Now that we have loaded all the test cases, run the whole test suite. 964 # 965 966 # Install the control-c handler. 967 unittest2.signals.installHandler() 968 969 # 970 # Invoke the default TextTestRunner to run the test suite 971 # 972 checkCompiler() 973 974 if configuration.verbose: 975 print("compiler=%s" % configuration.compiler) 976 977 # Iterating over all possible architecture and compiler combinations. 978 configString = "arch=%s compiler=%s" % (configuration.arch, 979 configuration.compiler) 980 981 # Output the configuration. 982 if configuration.verbose: 983 sys.stderr.write("\nConfiguration: " + configString + "\n") 984 985 # First, write out the number of collected test cases. 986 if configuration.verbose: 987 sys.stderr.write(configuration.separator + "\n") 988 sys.stderr.write( 989 "Collected %d test%s\n\n" % 990 (configuration.suite.countTestCases(), 991 configuration.suite.countTestCases() != 1 and "s" or "")) 992 993 if configuration.suite.countTestCases() == 0: 994 logging.error("did not discover any matching tests") 995 exitTestSuite(1) 996 997 # Invoke the test runner. 998 if configuration.count == 1: 999 result = unittest2.TextTestRunner( 1000 stream=sys.stderr, 1001 verbosity=configuration.verbose, 1002 resultclass=test_result.LLDBTestResult).run( 1003 configuration.suite) 1004 else: 1005 # We are invoking the same test suite more than once. In this case, 1006 # mark __ignore_singleton__ flag as True so the signleton pattern is 1007 # not enforced. 1008 test_result.LLDBTestResult.__ignore_singleton__ = True 1009 for i in range(configuration.count): 1010 1011 result = unittest2.TextTestRunner( 1012 stream=sys.stderr, 1013 verbosity=configuration.verbose, 1014 resultclass=test_result.LLDBTestResult).run( 1015 configuration.suite) 1016 1017 configuration.failed = not result.wasSuccessful() 1018 1019 if configuration.sdir_has_content and configuration.verbose: 1020 sys.stderr.write( 1021 "Session logs for test failures/errors/unexpected successes" 1022 " can be found in the test build directory\n") 1023 1024 if configuration.use_categories and len( 1025 configuration.failures_per_category) > 0: 1026 sys.stderr.write("Failures per category:\n") 1027 for category in configuration.failures_per_category: 1028 sys.stderr.write( 1029 "%s - %d\n" % 1030 (category, configuration.failures_per_category[category])) 1031 1032 # Exiting. 1033 exitTestSuite(configuration.failed) 1034 1035if __name__ == "__main__": 1036 print( 1037 __file__ + 1038 " is for use as a module only. It should not be run as a standalone script.") 1039 sys.exit(-1) 1040