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.t: 392 os.environ['LLDB_COMMAND_TRACE'] = 'YES' 393 394 if args.v: 395 configuration.verbose = 2 396 397 # argparse makes sure we have a number 398 if args.sharp: 399 configuration.count = args.sharp 400 401 if sys.platform.startswith('win32'): 402 os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str( 403 args.disable_crash_dialog) 404 os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True) 405 406 if do_help: 407 usage(parser) 408 409 # Reproducer arguments 410 if args.capture_path and args.replay_path: 411 logging.error('Cannot specify both a capture and a replay path.') 412 sys.exit(-1) 413 414 if args.capture_path: 415 configuration.capture_path = args.capture_path 416 417 if args.replay_path: 418 configuration.replay_path = args.replay_path 419 if args.lldb_platform_name: 420 configuration.lldb_platform_name = args.lldb_platform_name 421 if args.lldb_platform_url: 422 configuration.lldb_platform_url = args.lldb_platform_url 423 if args.lldb_platform_working_dir: 424 configuration.lldb_platform_working_dir = args.lldb_platform_working_dir 425 if platform_system == 'Darwin' and args.apple_sdk: 426 configuration.apple_sdk = args.apple_sdk 427 if args.test_build_dir: 428 configuration.test_build_dir = args.test_build_dir 429 if args.lldb_module_cache_dir: 430 configuration.lldb_module_cache_dir = args.lldb_module_cache_dir 431 else: 432 configuration.lldb_module_cache_dir = os.path.join( 433 configuration.test_build_dir, 'module-cache-lldb') 434 if args.clang_module_cache_dir: 435 configuration.clang_module_cache_dir = args.clang_module_cache_dir 436 else: 437 configuration.clang_module_cache_dir = os.path.join( 438 configuration.test_build_dir, 'module-cache-clang') 439 440 if args.lldb_libs_dir: 441 configuration.lldb_libs_dir = args.lldb_libs_dir 442 443 if args.enabled_plugins: 444 configuration.enabled_plugins = args.enabled_plugins 445 446 # Gather all the dirs passed on the command line. 447 if len(args.args) > 0: 448 configuration.testdirs = [os.path.realpath(os.path.abspath(x)) for x in args.args] 449 450 lldbtest_config.codesign_identity = args.codesign_identity 451 452def registerFaulthandler(): 453 try: 454 import faulthandler 455 except ImportError: 456 # faulthandler is not available until python3 457 return 458 459 faulthandler.enable() 460 # faulthandler.register is not available on Windows. 461 if getattr(faulthandler, 'register', None): 462 faulthandler.register(signal.SIGTERM, chain=True) 463 464def setupSysPath(): 465 """ 466 Add LLDB.framework/Resources/Python to the search paths for modules. 467 As a side effect, we also discover the 'lldb' executable and export it here. 468 """ 469 470 # Get the directory containing the current script. 471 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ: 472 scriptPath = os.environ["DOTEST_SCRIPT_DIR"] 473 else: 474 scriptPath = os.path.dirname(os.path.abspath(__file__)) 475 if not scriptPath.endswith('test'): 476 print("This script expects to reside in lldb's test directory.") 477 sys.exit(-1) 478 479 os.environ["LLDB_TEST"] = scriptPath 480 481 # Set up the root build directory. 482 if not configuration.test_build_dir: 483 raise Exception("test_build_dir is not set") 484 configuration.test_build_dir = os.path.abspath(configuration.test_build_dir) 485 486 # Set up the LLDB_SRC environment variable, so that the tests can locate 487 # the LLDB source code. 488 os.environ["LLDB_SRC"] = lldbsuite.lldb_root 489 490 pluginPath = os.path.join(scriptPath, 'plugins') 491 toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode') 492 toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server') 493 494 # Insert script dir, plugin dir and lldb-server dir to the sys.path. 495 sys.path.insert(0, pluginPath) 496 # Adding test/tools/lldb-vscode to the path makes it easy to 497 # "import lldb_vscode_testcase" from the VSCode tests 498 sys.path.insert(0, toolsLLDBVSCode) 499 # Adding test/tools/lldb-server to the path makes it easy 500 sys.path.insert(0, toolsLLDBServerPath) 501 # to "import lldbgdbserverutils" from the lldb-server tests 502 503 # This is the root of the lldb git/svn checkout 504 # When this changes over to a package instead of a standalone script, this 505 # will be `lldbsuite.lldb_root` 506 lldbRootDirectory = lldbsuite.lldb_root 507 508 # Some of the tests can invoke the 'lldb' command directly. 509 # We'll try to locate the appropriate executable right here. 510 511 # The lldb executable can be set from the command line 512 # if it's not set, we try to find it now 513 # first, we try the environment 514 if not lldbtest_config.lldbExec: 515 # First, you can define an environment variable LLDB_EXEC specifying the 516 # full pathname of the lldb executable. 517 if "LLDB_EXEC" in os.environ: 518 lldbtest_config.lldbExec = os.environ["LLDB_EXEC"] 519 520 if not lldbtest_config.lldbExec: 521 # Last, check the path 522 lldbtest_config.lldbExec = which('lldb') 523 524 if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec): 525 print( 526 "'{}' is not a path to a valid executable".format( 527 lldbtest_config.lldbExec)) 528 lldbtest_config.lldbExec = None 529 530 if not lldbtest_config.lldbExec: 531 print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.") 532 sys.exit(-1) 533 534 os.system('%s -v' % lldbtest_config.lldbExec) 535 536 lldbDir = os.path.dirname(lldbtest_config.lldbExec) 537 538 lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode") 539 if is_exe(lldbVSCodeExec): 540 os.environ["LLDBVSCODE_EXEC"] = lldbVSCodeExec 541 else: 542 if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]): 543 print( 544 "The 'lldb-vscode' executable cannot be located. The lldb-vscode tests can not be run as a result.") 545 configuration.skip_categories.append("lldb-vscode") 546 547 lldbPythonDir = None # The directory that contains 'lldb/__init__.py' 548 549 # If our lldb supports the -P option, use it to find the python path: 550 lldb_dash_p_result = subprocess.check_output([lldbtest_config.lldbExec, "-P"], universal_newlines=True) 551 if lldb_dash_p_result: 552 for line in lldb_dash_p_result.splitlines(): 553 if os.path.isdir(line) and os.path.exists(os.path.join(line, 'lldb', '__init__.py')): 554 lldbPythonDir = line 555 break 556 557 if not lldbPythonDir: 558 print( 559 "Unable to load lldb extension module. Possible reasons for this include:") 560 print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") 561 print( 562 " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") 563 print( 564 " the version of Python that LLDB built and linked against, and PYTHONPATH") 565 print( 566 " should contain the Lib directory for the same python distro, as well as the") 567 print(" location of LLDB\'s site-packages folder.") 568 print( 569 " 3) A different version of Python than that which was built against is exported in") 570 print(" the system\'s PATH environment variable, causing conflicts.") 571 print( 572 " 4) The executable '%s' could not be found. Please check " % 573 lldbtest_config.lldbExec) 574 print(" that it exists and is executable.") 575 576 if lldbPythonDir: 577 lldbPythonDir = os.path.normpath(lldbPythonDir) 578 # Some of the code that uses this path assumes it hasn't resolved the Versions... link. 579 # If the path we've constructed looks like that, then we'll strip out 580 # the Versions/A part. 581 (before, frameWithVersion, after) = lldbPythonDir.rpartition( 582 "LLDB.framework/Versions/A") 583 if frameWithVersion != "": 584 lldbPythonDir = before + "LLDB.framework" + after 585 586 lldbPythonDir = os.path.abspath(lldbPythonDir) 587 588 if "freebsd" in sys.platform or "linux" in sys.platform: 589 os.environ['LLDB_LIB_DIR'] = os.path.join(lldbPythonDir, '..', '..') 590 591 # If tests need to find LLDB_FRAMEWORK, now they can do it 592 os.environ["LLDB_FRAMEWORK"] = os.path.dirname( 593 os.path.dirname(lldbPythonDir)) 594 595 # This is to locate the lldb.py module. Insert it right after 596 # sys.path[0]. 597 sys.path[1:1] = [lldbPythonDir] 598 599 600def visit_file(dir, name): 601 # Try to match the regexp pattern, if specified. 602 if configuration.regexp: 603 if not re.search(configuration.regexp, name): 604 # We didn't match the regex, we're done. 605 return 606 607 if configuration.skip_tests: 608 for file_regexp in configuration.skip_tests: 609 if re.search(file_regexp, name): 610 return 611 612 # We found a match for our test. Add it to the suite. 613 614 # Update the sys.path first. 615 if not sys.path.count(dir): 616 sys.path.insert(0, dir) 617 base = os.path.splitext(name)[0] 618 619 # Thoroughly check the filterspec against the base module and admit 620 # the (base, filterspec) combination only when it makes sense. 621 622 def check(obj, parts): 623 for part in parts: 624 try: 625 parent, obj = obj, getattr(obj, part) 626 except AttributeError: 627 # The filterspec has failed. 628 return False 629 return True 630 631 module = __import__(base) 632 633 def iter_filters(): 634 for filterspec in configuration.filters: 635 parts = filterspec.split('.') 636 if check(module, parts): 637 yield filterspec 638 elif parts[0] == base and len(parts) > 1 and check(module, parts[1:]): 639 yield '.'.join(parts[1:]) 640 else: 641 for key,value in module.__dict__.items(): 642 if check(value, parts): 643 yield key + '.' + filterspec 644 645 filtered = False 646 for filterspec in iter_filters(): 647 filtered = True 648 print("adding filter spec %s to module %s" % (filterspec, repr(module))) 649 tests = unittest2.defaultTestLoader.loadTestsFromName(filterspec, module) 650 configuration.suite.addTests(tests) 651 652 # Forgo this module if the (base, filterspec) combo is invalid 653 if configuration.filters and not filtered: 654 return 655 656 if not filtered: 657 # Add the entire file's worth of tests since we're not filtered. 658 # Also the fail-over case when the filterspec branch 659 # (base, filterspec) combo doesn't make sense. 660 configuration.suite.addTests( 661 unittest2.defaultTestLoader.loadTestsFromName(base)) 662 663 664def visit(prefix, dir, names): 665 """Visitor function for os.path.walk(path, visit, arg).""" 666 667 dir_components = set(dir.split(os.sep)) 668 excluded_components = set(['.svn', '.git']) 669 if dir_components.intersection(excluded_components): 670 return 671 672 # Gather all the Python test file names that follow the Test*.py pattern. 673 python_test_files = [ 674 name 675 for name in names 676 if name.endswith('.py') and name.startswith(prefix)] 677 678 # Visit all the python test files. 679 for name in python_test_files: 680 # Ensure we error out if we have multiple tests with the same 681 # base name. 682 # Future improvement: find all the places where we work with base 683 # names and convert to full paths. We have directory structure 684 # to disambiguate these, so we shouldn't need this constraint. 685 if name in configuration.all_tests: 686 raise Exception("Found multiple tests with the name %s" % name) 687 configuration.all_tests.add(name) 688 689 # Run the relevant tests in the python file. 690 visit_file(dir, name) 691 692 693# ======================================== # 694# # 695# Execution of the test driver starts here # 696# # 697# ======================================== # 698 699 700def checkDsymForUUIDIsNotOn(): 701 cmd = ["defaults", "read", "com.apple.DebugSymbols"] 702 process = subprocess.Popen( 703 cmd, 704 stdout=subprocess.PIPE, 705 stderr=subprocess.STDOUT) 706 cmd_output = process.stdout.read() 707 output_str = cmd_output.decode("utf-8") 708 if "DBGFileMappedPaths = " in output_str: 709 print("%s =>" % ' '.join(cmd)) 710 print(output_str) 711 print( 712 "Disable automatic lookup and caching of dSYMs before running the test suite!") 713 print("Exiting...") 714 sys.exit(0) 715 716 717def exitTestSuite(exitCode=None): 718 # lldb.py does SBDebugger.Initialize(). 719 # Call SBDebugger.Terminate() on exit. 720 import lldb 721 lldb.SBDebugger.Terminate() 722 if exitCode: 723 sys.exit(exitCode) 724 725 726def getVersionForSDK(sdk): 727 sdk = str.lower(sdk) 728 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk) 729 basename = os.path.basename(full_path) 730 basename = os.path.splitext(basename)[0] 731 basename = str.lower(basename) 732 ver = basename.replace(sdk, '') 733 return ver 734 735 736def checkCompiler(): 737 # Add some intervention here to sanity check that the compiler requested is sane. 738 # If found not to be an executable program, we abort. 739 c = configuration.compiler 740 if which(c): 741 return 742 743 if not sys.platform.startswith("darwin"): 744 raise Exception(c + " is not a valid compiler") 745 746 pipe = subprocess.Popen( 747 ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 748 cmd_output = pipe.stdout.read() 749 if not cmd_output or "not found" in cmd_output: 750 raise Exception(c + " is not a valid compiler") 751 752 configuration.compiler = cmd_output.split('\n')[0] 753 print("'xcrun -find %s' returning %s" % (c, configuration.compiler)) 754 755def canRunLibcxxTests(): 756 from lldbsuite.test import lldbplatformutil 757 758 platform = lldbplatformutil.getPlatform() 759 760 if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin(): 761 return True, "libc++ always present" 762 763 if platform == "linux": 764 if os.path.isdir("/usr/include/c++/v1"): 765 return True, "Headers found, let's hope they work" 766 with tempfile.NamedTemporaryFile() as f: 767 cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.name, "-"] 768 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 769 _, stderr = p.communicate("#include <algorithm>\nint main() {}") 770 if not p.returncode: 771 return True, "Compiling with -stdlib=libc++ works" 772 return False, "Compiling with -stdlib=libc++ fails with the error: %s" % stderr 773 774 return False, "Don't know how to build with libc++ on %s" % platform 775 776def checkLibcxxSupport(): 777 result, reason = canRunLibcxxTests() 778 if result: 779 return # libc++ supported 780 if "libc++" in configuration.categories_list: 781 return # libc++ category explicitly requested, let it run. 782 print("Libc++ tests will not be run because: " + reason) 783 configuration.skip_categories.append("libc++") 784 785def canRunLibstdcxxTests(): 786 from lldbsuite.test import lldbplatformutil 787 788 platform = lldbplatformutil.getPlatform() 789 if lldbplatformutil.target_is_android(): 790 platform = "android" 791 if platform == "linux": 792 return True, "libstdcxx always present" 793 return False, "Don't know how to build with libstdcxx on %s" % platform 794 795def checkLibstdcxxSupport(): 796 result, reason = canRunLibstdcxxTests() 797 if result: 798 return # libstdcxx supported 799 if "libstdcxx" in configuration.categories_list: 800 return # libstdcxx category explicitly requested, let it run. 801 print("libstdcxx tests will not be run because: " + reason) 802 configuration.skip_categories.append("libstdcxx") 803 804def canRunWatchpointTests(): 805 from lldbsuite.test import lldbplatformutil 806 807 platform = lldbplatformutil.getPlatform() 808 if platform == "netbsd": 809 if os.geteuid() == 0: 810 return True, "root can always write dbregs" 811 try: 812 output = subprocess.check_output(["/sbin/sysctl", "-n", 813 "security.models.extensions.user_set_dbregs"]).decode().strip() 814 if output == "1": 815 return True, "security.models.extensions.user_set_dbregs enabled" 816 except subprocess.CalledProcessError: 817 pass 818 return False, "security.models.extensions.user_set_dbregs disabled" 819 return True, "watchpoint support available" 820 821def checkWatchpointSupport(): 822 result, reason = canRunWatchpointTests() 823 if result: 824 return # watchpoints supported 825 if "watchpoint" in configuration.categories_list: 826 return # watchpoint category explicitly requested, let it run. 827 print("watchpoint tests will not be run because: " + reason) 828 configuration.skip_categories.append("watchpoint") 829 830def checkObjcSupport(): 831 from lldbsuite.test import lldbplatformutil 832 833 if not lldbplatformutil.platformIsDarwin(): 834 print("objc tests will be skipped because of unsupported platform") 835 configuration.skip_categories.append("objc") 836 837def checkDebugInfoSupport(): 838 import lldb 839 840 platform = lldb.selected_platform.GetTriple().split('-')[2] 841 compiler = configuration.compiler 842 skipped = [] 843 for cat in test_categories.debug_info_categories: 844 if cat in configuration.categories_list: 845 continue # Category explicitly requested, let it run. 846 if test_categories.is_supported_on_platform(cat, platform, compiler): 847 continue 848 configuration.skip_categories.append(cat) 849 skipped.append(cat) 850 if skipped: 851 print("Skipping following debug info categories:", skipped) 852 853def checkDebugServerSupport(): 854 from lldbsuite.test import lldbplatformutil 855 856 if lldbplatformutil.platformIsDarwin(): 857 configuration.skip_categories.append("llgs") 858 else: 859 configuration.skip_categories.append("debugserver") 860 861def run_suite(): 862 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults 863 # does not exist before proceeding to running the test suite. 864 if sys.platform.startswith("darwin"): 865 checkDsymForUUIDIsNotOn() 866 867 # Start the actions by first parsing the options while setting up the test 868 # directories, followed by setting up the search paths for lldb utilities; 869 # then, we walk the directory trees and collect the tests into our test suite. 870 # 871 parseOptionsAndInitTestdirs() 872 873 # Print a stack trace if the test hangs or is passed SIGTERM. 874 registerFaulthandler() 875 876 setupSysPath() 877 878 import lldbconfig 879 if configuration.capture_path or configuration.replay_path: 880 lldbconfig.INITIALIZE = False 881 import lldb 882 883 if configuration.capture_path: 884 lldb.SBReproducer.Capture(configuration.capture_path) 885 lldb.SBReproducer.SetAutoGenerate(True) 886 elif configuration.replay_path: 887 lldb.SBReproducer.PassiveReplay(configuration.replay_path) 888 889 if not lldbconfig.INITIALIZE: 890 lldb.SBDebugger.Initialize() 891 892 # Use host platform by default. 893 lldb.selected_platform = lldb.SBPlatform.GetHostPlatform() 894 895 # Now we can also import lldbutil 896 from lldbsuite.test import lldbutil 897 898 if configuration.lldb_platform_name: 899 print("Setting up remote platform '%s'" % 900 (configuration.lldb_platform_name)) 901 lldb.remote_platform = lldb.SBPlatform( 902 configuration.lldb_platform_name) 903 if not lldb.remote_platform.IsValid(): 904 print( 905 "error: unable to create the LLDB platform named '%s'." % 906 (configuration.lldb_platform_name)) 907 exitTestSuite(1) 908 if configuration.lldb_platform_url: 909 # We must connect to a remote platform if a LLDB platform URL was 910 # specified 911 print( 912 "Connecting to remote platform '%s' at '%s'..." % 913 (configuration.lldb_platform_name, configuration.lldb_platform_url)) 914 platform_connect_options = lldb.SBPlatformConnectOptions( 915 configuration.lldb_platform_url) 916 err = lldb.remote_platform.ConnectRemote(platform_connect_options) 917 if err.Success(): 918 print("Connected.") 919 else: 920 print("error: failed to connect to remote platform using URL '%s': %s" % ( 921 configuration.lldb_platform_url, err)) 922 exitTestSuite(1) 923 else: 924 configuration.lldb_platform_url = None 925 926 if configuration.lldb_platform_working_dir: 927 print("Setting remote platform working directory to '%s'..." % 928 (configuration.lldb_platform_working_dir)) 929 error = lldb.remote_platform.MakeDirectory( 930 configuration.lldb_platform_working_dir, 448) # 448 = 0o700 931 if error.Fail(): 932 raise Exception("making remote directory '%s': %s" % ( 933 configuration.lldb_platform_working_dir, error)) 934 935 if not lldb.remote_platform.SetWorkingDirectory( 936 configuration.lldb_platform_working_dir): 937 raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir) 938 lldb.selected_platform = lldb.remote_platform 939 else: 940 lldb.remote_platform = None 941 configuration.lldb_platform_working_dir = None 942 configuration.lldb_platform_url = None 943 944 # Set up the working directory. 945 # Note that it's not dotest's job to clean this directory. 946 lldbutil.mkdir_p(configuration.test_build_dir) 947 948 from . import lldbplatformutil 949 target_platform = lldbplatformutil.getPlatform() 950 951 checkLibcxxSupport() 952 checkLibstdcxxSupport() 953 checkWatchpointSupport() 954 checkDebugInfoSupport() 955 checkDebugServerSupport() 956 checkObjcSupport() 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