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 os 27import errno 28import logging 29import platform 30import re 31import signal 32import socket 33import subprocess 34import sys 35 36# Third-party modules 37import six 38import unittest2 39 40# LLDB Modules 41import lldbsuite 42from . import configuration 43from . import dotest_args 44from . import lldbtest_config 45from . import test_categories 46from lldbsuite.test_event import formatter 47from . import test_result 48from lldbsuite.test_event.event_builder import EventBuilder 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 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 57 58 59def which(program): 60 """Returns the full path to a program; None otherwise.""" 61 fpath, fname = os.path.split(program) 62 if fpath: 63 if is_exe(program): 64 return program 65 else: 66 for path in os.environ["PATH"].split(os.pathsep): 67 exe_file = os.path.join(path, program) 68 if is_exe(exe_file): 69 return exe_file 70 return None 71 72 73class _WritelnDecorator(object): 74 """Used to decorate file-like objects with a handy 'writeln' method""" 75 76 def __init__(self, stream): 77 self.stream = stream 78 79 def __getattr__(self, attr): 80 if attr in ('stream', '__getstate__'): 81 raise AttributeError(attr) 82 return getattr(self.stream, attr) 83 84 def writeln(self, arg=None): 85 if arg: 86 self.write(arg) 87 self.write('\n') # text-mode streams translate to \r\n if needed 88 89# 90# Global variables: 91# 92 93 94def usage(parser): 95 parser.print_help() 96 if configuration.verbose > 0: 97 print(""" 98Examples: 99 100This is an example of using the -f option to pinpoint to a specific test class 101and test method to be run: 102 103$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command 104---------------------------------------------------------------------- 105Collected 1 test 106 107test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase) 108Test 'frame variable this' when stopped on a class constructor. ... ok 109 110---------------------------------------------------------------------- 111Ran 1 test in 1.396s 112 113OK 114 115And this is an example of using the -p option to run a single file (the filename 116matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'): 117 118$ ./dotest.py -v -p ObjC 119---------------------------------------------------------------------- 120Collected 4 tests 121 122test_break_with_dsym (TestObjCMethods.FoundationTestCase) 123Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok 124test_break_with_dwarf (TestObjCMethods.FoundationTestCase) 125Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok 126test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase) 127Lookup objective-c data types and evaluate expressions. ... ok 128test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase) 129Lookup objective-c data types and evaluate expressions. ... ok 130 131---------------------------------------------------------------------- 132Ran 4 tests in 16.661s 133 134OK 135 136Running of this script also sets up the LLDB_TEST environment variable so that 137individual test cases can locate their supporting files correctly. The script 138tries to set up Python's search paths for modules by looking at the build tree 139relative to this script. See also the '-i' option in the following example. 140 141Finally, this is an example of using the lldb.py module distributed/installed by 142Xcode4 to run against the tests under the 'forward' directory, and with the '-w' 143option to add some delay between two tests. It uses ARCH=x86_64 to specify that 144as the architecture and CC=clang to specify the compiler used for the test run: 145 146$ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward 147 148Session logs for test failures/errors will go into directory '2010-11-11-13_56_16' 149---------------------------------------------------------------------- 150Collected 2 tests 151 152test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase) 153Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok 154test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase) 155Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok 156 157---------------------------------------------------------------------- 158Ran 2 tests in 5.659s 159 160OK 161 162The 'Session ...' verbiage is recently introduced (see also the '-s' option) to 163notify the directory containing the session logs for test failures or errors. 164In case there is any test failure/error, a similar message is appended at the 165end of the stderr output for your convenience. 166 167ENABLING LOGS FROM TESTS 168 169Option 1: 170 171Writing logs into different files per test case:: 172 173This option is particularly useful when multiple dotest instances are created 174by dosep.py 175 176$ ./dotest.py --channel "lldb all" 177 178$ ./dotest.py --channel "lldb all" --channel "gdb-remote packets" 179 180These log files are written to: 181 182<session-dir>/<test-id>-host.log (logs from lldb host process) 183<session-dir>/<test-id>-server.log (logs from debugserver/lldb-server) 184<session-dir>/<test-id>-<test-result>.log (console logs) 185 186By default, logs from successful runs are deleted. Use the --log-success flag 187to create reference logs for debugging. 188 189$ ./dotest.py --log-success 190 191Option 2: (DEPRECATED) 192 193The following options can only enable logs from the host lldb process. 194Only categories from the "lldb" or "gdb-remote" channels can be enabled 195They also do not automatically enable logs in locally running debug servers. 196Also, logs from all test case are written into each log file 197 198o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem 199 with a default option of 'event process' if LLDB_LOG_OPTION is not defined. 200 201o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the 202 'process.gdb-remote' subsystem with a default option of 'packets' if 203 GDB_REMOTE_LOG_OPTION is not defined. 204 205""") 206 sys.exit(0) 207 208 209def parseExclusion(exclusion_file): 210 """Parse an exclusion file, of the following format, where 211 'skip files', 'skip methods', 'xfail files', and 'xfail methods' 212 are the possible list heading values: 213 214 skip files 215 <file name> 216 <file name> 217 218 xfail methods 219 <method name> 220 """ 221 excl_type = None 222 223 with open(exclusion_file) as f: 224 for line in f: 225 line = line.strip() 226 if not excl_type: 227 excl_type = line 228 continue 229 230 if not line: 231 excl_type = None 232 elif excl_type == 'skip': 233 if not configuration.skip_tests: 234 configuration.skip_tests = [] 235 configuration.skip_tests.append(line) 236 elif excl_type == 'xfail': 237 if not configuration.xfail_tests: 238 configuration.xfail_tests = [] 239 configuration.xfail_tests.append(line) 240 241 242def parseOptionsAndInitTestdirs(): 243 """Initialize the list of directories containing our unittest scripts. 244 245 '-h/--help as the first option prints out usage info and exit the program. 246 """ 247 248 do_help = False 249 250 platform_system = platform.system() 251 platform_machine = platform.machine() 252 253 parser = dotest_args.create_parser() 254 args = dotest_args.parse_args(parser, sys.argv[1:]) 255 256 if args.unset_env_varnames: 257 for env_var in args.unset_env_varnames: 258 if env_var in os.environ: 259 # From Python Doc: When unsetenv() is supported, deletion of items in os.environ 260 # is automatically translated into a corresponding call to 261 # unsetenv(). 262 del os.environ[env_var] 263 # os.unsetenv(env_var) 264 265 if args.set_env_vars: 266 for env_var in args.set_env_vars: 267 parts = env_var.split('=', 1) 268 if len(parts) == 1: 269 os.environ[parts[0]] = "" 270 else: 271 os.environ[parts[0]] = parts[1] 272 273 # only print the args if being verbose (and parsable is off) 274 if args.v and not args.q: 275 print(sys.argv) 276 277 if args.h: 278 do_help = True 279 280 if args.compiler: 281 configuration.compiler = os.path.realpath(args.compiler) 282 if not is_exe(configuration.compiler): 283 configuration.compiler = which(args.compiler) 284 if not is_exe(configuration.compiler): 285 logging.error( 286 '%s is not a valid compiler executable; aborting...', 287 args.compiler) 288 sys.exit(-1) 289 else: 290 # Use a compiler appropriate appropriate for the Apple SDK if one was 291 # specified 292 if platform_system == 'Darwin' and args.apple_sdk: 293 configuration.compiler = seven.get_command_output( 294 'xcrun -sdk "%s" -find clang 2> /dev/null' % 295 (args.apple_sdk)) 296 else: 297 # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first 298 candidateCompilers = ['clang-3.5', 'clang', 'gcc'] 299 for candidate in candidateCompilers: 300 if which(candidate): 301 configuration.compiler = candidate 302 break 303 304 if args.dsymutil: 305 os.environ['DSYMUTIL'] = args.dsymutil 306 elif platform_system == 'Darwin': 307 os.environ['DSYMUTIL'] = seven.get_command_output( 308 'xcrun -find -toolchain default dsymutil') 309 310 if args.filecheck: 311 # The lldb-dotest script produced by the CMake build passes in a path 312 # to a working FileCheck binary. So does one specific Xcode project 313 # target. However, when invoking dotest.py directly, a valid --filecheck 314 # option needs to be given. 315 configuration.filecheck = os.path.abspath(args.filecheck) 316 317 if not configuration.get_filecheck_path(): 318 logging.warning('No valid FileCheck executable; some tests may fail...') 319 logging.warning('(Double-check the --filecheck argument to dotest.py)') 320 321 if args.channels: 322 lldbtest_config.channels = args.channels 323 324 if args.log_success: 325 lldbtest_config.log_success = args.log_success 326 327 if args.out_of_tree_debugserver: 328 lldbtest_config.out_of_tree_debugserver = args.out_of_tree_debugserver 329 330 # Set SDKROOT if we are using an Apple SDK 331 if platform_system == 'Darwin' and args.apple_sdk: 332 os.environ['SDKROOT'] = seven.get_command_output( 333 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % 334 (args.apple_sdk)) 335 336 if args.arch: 337 configuration.arch = args.arch 338 if configuration.arch.startswith( 339 'arm') and platform_system == 'Darwin' and not args.apple_sdk: 340 os.environ['SDKROOT'] = seven.get_command_output( 341 'xcrun --sdk iphoneos.internal --show-sdk-path 2> /dev/null') 342 if not os.path.exists(os.environ['SDKROOT']): 343 os.environ['SDKROOT'] = seven.get_command_output( 344 'xcrun --sdk iphoneos --show-sdk-path 2> /dev/null') 345 else: 346 configuration.arch = platform_machine 347 348 if args.categoriesList: 349 configuration.categoriesList = set( 350 test_categories.validate( 351 args.categoriesList, False)) 352 configuration.useCategories = True 353 else: 354 configuration.categoriesList = [] 355 356 if args.skipCategories: 357 configuration.skipCategories += test_categories.validate( 358 args.skipCategories, False) 359 360 if args.E: 361 cflags_extras = args.E 362 os.environ['CFLAGS_EXTRAS'] = cflags_extras 363 364 if args.d: 365 sys.stdout.write( 366 "Suspending the process %d to wait for debugger to attach...\n" % 367 os.getpid()) 368 sys.stdout.flush() 369 os.kill(os.getpid(), signal.SIGSTOP) 370 371 if args.f: 372 if any([x.startswith('-') for x in args.f]): 373 usage(parser) 374 configuration.filters.extend(args.f) 375 # Shut off multiprocessing mode when additional filters are specified. 376 # The rational is that the user is probably going after a very specific 377 # test and doesn't need a bunch of parallel test runners all looking for 378 # it in a frenzy. Also, '-v' now spits out all test run output even 379 # on success, so the standard recipe for redoing a failing test (with -v 380 # and a -f to filter to the specific test) now causes all test scanning 381 # (in parallel) to print results for do-nothing runs in a very distracting 382 # manner. If we really need filtered parallel runs in the future, consider 383 # adding a --no-output-on-success that prevents -v from setting 384 # output-on-success. 385 configuration.no_multiprocess_test_runner = True 386 387 if args.l: 388 configuration.skip_long_running_test = False 389 390 if args.framework: 391 configuration.lldbFrameworkPath = args.framework 392 393 if args.executable: 394 # lldb executable is passed explicitly 395 lldbtest_config.lldbExec = os.path.realpath(args.executable) 396 if not is_exe(lldbtest_config.lldbExec): 397 lldbtest_config.lldbExec = which(args.executable) 398 if not is_exe(lldbtest_config.lldbExec): 399 logging.error( 400 '%s is not a valid executable to test; aborting...', 401 args.executable) 402 sys.exit(-1) 403 404 if args.server: 405 os.environ['LLDB_DEBUGSERVER_PATH'] = args.server 406 407 if args.excluded: 408 for excl_file in args.excluded: 409 parseExclusion(excl_file) 410 411 if args.p: 412 if args.p.startswith('-'): 413 usage(parser) 414 configuration.regexp = args.p 415 416 if args.q: 417 configuration.parsable = True 418 419 if args.s: 420 if args.s.startswith('-'): 421 usage(parser) 422 configuration.sdir_name = args.s 423 configuration.session_file_format = args.session_file_format 424 425 if args.t: 426 os.environ['LLDB_COMMAND_TRACE'] = 'YES' 427 428 if args.v: 429 configuration.verbose = 2 430 431 # argparse makes sure we have a number 432 if args.sharp: 433 configuration.count = args.sharp 434 435 if sys.platform.startswith('win32'): 436 os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str( 437 args.disable_crash_dialog) 438 os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True) 439 440 if do_help: 441 usage(parser) 442 443 if args.no_multiprocess: 444 configuration.no_multiprocess_test_runner = True 445 446 if args.inferior: 447 configuration.is_inferior_test_runner = True 448 449 if args.num_threads: 450 configuration.num_threads = args.num_threads 451 452 if args.test_subdir: 453 configuration.exclusive_test_subdir = args.test_subdir 454 455 if args.test_runner_name: 456 configuration.test_runner_name = args.test_runner_name 457 458 # Capture test results-related args. 459 if args.curses and not args.inferior: 460 # Act as if the following args were set. 461 args.results_formatter = "lldbsuite.test_event.formatter.curses.Curses" 462 args.results_file = "stdout" 463 464 if args.results_file: 465 configuration.results_filename = args.results_file 466 467 if args.results_port: 468 configuration.results_port = args.results_port 469 470 if args.results_file and args.results_port: 471 sys.stderr.write( 472 "only one of --results-file and --results-port should " 473 "be specified\n") 474 usage(args) 475 476 if args.results_formatter: 477 configuration.results_formatter_name = args.results_formatter 478 if args.results_formatter_options: 479 configuration.results_formatter_options = args.results_formatter_options 480 481 # Default to using the BasicResultsFormatter if no formatter is specified 482 # and we're not a test inferior. 483 if not args.inferior and configuration.results_formatter_name is None: 484 configuration.results_formatter_name = ( 485 "lldbsuite.test_event.formatter.results_formatter.ResultsFormatter") 486 487 # rerun-related arguments 488 configuration.rerun_all_issues = args.rerun_all_issues 489 configuration.rerun_max_file_threshold = args.rerun_max_file_threshold 490 491 if args.lldb_platform_name: 492 configuration.lldb_platform_name = args.lldb_platform_name 493 if args.lldb_platform_url: 494 configuration.lldb_platform_url = args.lldb_platform_url 495 if args.lldb_platform_working_dir: 496 configuration.lldb_platform_working_dir = args.lldb_platform_working_dir 497 if args.test_build_dir: 498 configuration.test_build_dir = args.test_build_dir 499 500 if args.event_add_entries and len(args.event_add_entries) > 0: 501 entries = {} 502 # Parse out key=val pairs, separated by comma 503 for keyval in args.event_add_entries.split(","): 504 key_val_entry = keyval.split("=") 505 if len(key_val_entry) == 2: 506 (key, val) = key_val_entry 507 val_parts = val.split(':') 508 if len(val_parts) > 1: 509 (val, val_type) = val_parts 510 if val_type == 'int': 511 val = int(val) 512 entries[key] = val 513 # Tell the event builder to create all events with these 514 # key/val pairs in them. 515 if len(entries) > 0: 516 EventBuilder.add_entries_to_all_events(entries) 517 518 # Gather all the dirs passed on the command line. 519 if len(args.args) > 0: 520 configuration.testdirs = list( 521 map(lambda x: os.path.realpath(os.path.abspath(x)), args.args)) 522 # Shut off multiprocessing mode when test directories are specified. 523 configuration.no_multiprocess_test_runner = True 524 525 lldbtest_config.codesign_identity = args.codesign_identity 526 527 #print("testdirs:", testdirs) 528 529 530def getXcodeOutputPaths(lldbRootDirectory): 531 result = [] 532 533 # These are for xcode build directories. 534 xcode3_build_dir = ['build'] 535 xcode4_build_dir = ['build', 'lldb', 'Build', 'Products'] 536 537 configurations = [ 538 ['Debug'], 539 ['DebugClang'], 540 ['Release'], 541 ['BuildAndIntegration']] 542 xcode_build_dirs = [xcode3_build_dir, xcode4_build_dir] 543 for configuration in configurations: 544 for xcode_build_dir in xcode_build_dirs: 545 outputPath = os.path.join( 546 lldbRootDirectory, *(xcode_build_dir + configuration)) 547 result.append(outputPath) 548 549 return result 550 551 552def createSocketToLocalPort(port): 553 def socket_closer(s): 554 """Close down an opened socket properly.""" 555 s.shutdown(socket.SHUT_RDWR) 556 s.close() 557 558 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 559 sock.connect(("localhost", port)) 560 return (sock, lambda: socket_closer(sock)) 561 562 563def setupTestResults(): 564 """Sets up test results-related objects based on arg settings.""" 565 # Setup the results formatter configuration. 566 formatter_config = formatter.FormatterConfig() 567 formatter_config.filename = configuration.results_filename 568 formatter_config.formatter_name = configuration.results_formatter_name 569 formatter_config.formatter_options = ( 570 configuration.results_formatter_options) 571 formatter_config.port = configuration.results_port 572 573 # Create the results formatter. 574 formatter_spec = formatter.create_results_formatter( 575 formatter_config) 576 if formatter_spec is not None and formatter_spec.formatter is not None: 577 configuration.results_formatter_object = formatter_spec.formatter 578 579 # Send an initialize message to the formatter. 580 initialize_event = EventBuilder.bare_event("initialize") 581 if isMultiprocessTestRunner(): 582 if (configuration.test_runner_name is not None and 583 configuration.test_runner_name == "serial"): 584 # Only one worker queue here. 585 worker_count = 1 586 else: 587 # Workers will be the number of threads specified. 588 worker_count = configuration.num_threads 589 else: 590 worker_count = 1 591 initialize_event["worker_count"] = worker_count 592 593 formatter_spec.formatter.handle_event(initialize_event) 594 595 # Make sure we clean up the formatter on shutdown. 596 if formatter_spec.cleanup_func is not None: 597 atexit.register(formatter_spec.cleanup_func) 598 599 600def getOutputPaths(lldbRootDirectory): 601 """ 602 Returns typical build output paths for the lldb executable 603 604 lldbDirectory - path to the root of the lldb svn/git repo 605 """ 606 result = [] 607 608 if sys.platform == 'darwin': 609 result.extend(getXcodeOutputPaths(lldbRootDirectory)) 610 611 # cmake builds? look for build or build/host folder next to llvm directory 612 # lldb is located in llvm/tools/lldb so we need to go up three levels 613 llvmParentDir = os.path.abspath( 614 os.path.join( 615 lldbRootDirectory, 616 os.pardir, 617 os.pardir, 618 os.pardir)) 619 result.append(os.path.join(llvmParentDir, 'build', 'bin')) 620 result.append(os.path.join(llvmParentDir, 'build', 'host', 'bin')) 621 622 # some cmake developers keep their build directory beside their lldb 623 # directory 624 lldbParentDir = os.path.abspath(os.path.join(lldbRootDirectory, os.pardir)) 625 result.append(os.path.join(lldbParentDir, 'build', 'bin')) 626 result.append(os.path.join(lldbParentDir, 'build', 'host', 'bin')) 627 628 return result 629 630 631def setupSysPath(): 632 """ 633 Add LLDB.framework/Resources/Python to the search paths for modules. 634 As a side effect, we also discover the 'lldb' executable and export it here. 635 """ 636 637 # Get the directory containing the current script. 638 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ: 639 scriptPath = os.environ["DOTEST_SCRIPT_DIR"] 640 else: 641 scriptPath = os.path.dirname(os.path.realpath(__file__)) 642 if not scriptPath.endswith('test'): 643 print("This script expects to reside in lldb's test directory.") 644 sys.exit(-1) 645 646 os.environ["LLDB_TEST"] = scriptPath 647 648 # Set up the root build directory. 649 builddir = configuration.test_build_dir 650 if not configuration.test_build_dir: 651 raise Exception("test_build_dir is not set") 652 os.environ["LLDB_BUILD"] = os.path.abspath(configuration.test_build_dir) 653 654 # Set up the LLDB_SRC environment variable, so that the tests can locate 655 # the LLDB source code. 656 os.environ["LLDB_SRC"] = lldbsuite.lldb_root 657 658 pluginPath = os.path.join(scriptPath, 'plugins') 659 toolsLLDBMIPath = os.path.join(scriptPath, 'tools', 'lldb-mi') 660 toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode') 661 toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server') 662 663 # Insert script dir, plugin dir, lldb-mi dir and lldb-server dir to the 664 # sys.path. 665 sys.path.insert(0, pluginPath) 666 # Adding test/tools/lldb-mi to the path makes it easy 667 sys.path.insert(0, toolsLLDBMIPath) 668 # to "import lldbmi_testcase" from the MI tests 669 # Adding test/tools/lldb-vscode to the path makes it easy to 670 # "import lldb_vscode_testcase" from the VSCode tests 671 sys.path.insert(0, toolsLLDBVSCode) 672 # Adding test/tools/lldb-server to the path makes it easy 673 sys.path.insert(0, toolsLLDBServerPath) 674 # to "import lldbgdbserverutils" from the lldb-server tests 675 676 # This is the root of the lldb git/svn checkout 677 # When this changes over to a package instead of a standalone script, this 678 # will be `lldbsuite.lldb_root` 679 lldbRootDirectory = lldbsuite.lldb_root 680 681 # Some of the tests can invoke the 'lldb' command directly. 682 # We'll try to locate the appropriate executable right here. 683 684 # The lldb executable can be set from the command line 685 # if it's not set, we try to find it now 686 # first, we try the environment 687 if not lldbtest_config.lldbExec: 688 # First, you can define an environment variable LLDB_EXEC specifying the 689 # full pathname of the lldb executable. 690 if "LLDB_EXEC" in os.environ: 691 lldbtest_config.lldbExec = os.environ["LLDB_EXEC"] 692 693 if not lldbtest_config.lldbExec: 694 outputPaths = getOutputPaths(lldbRootDirectory) 695 for outputPath in outputPaths: 696 candidatePath = os.path.join(outputPath, 'lldb') 697 if is_exe(candidatePath): 698 lldbtest_config.lldbExec = candidatePath 699 break 700 701 if not lldbtest_config.lldbExec: 702 # Last, check the path 703 lldbtest_config.lldbExec = which('lldb') 704 705 if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec): 706 print( 707 "'{}' is not a path to a valid executable".format( 708 lldbtest_config.lldbExec)) 709 lldbtest_config.lldbExec = None 710 711 if not lldbtest_config.lldbExec: 712 print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.") 713 sys.exit(-1) 714 715 # confusingly, this is the "bin" directory 716 lldbLibDir = os.path.dirname(lldbtest_config.lldbExec) 717 os.environ["LLDB_LIB_DIR"] = lldbLibDir 718 lldbImpLibDir = os.path.join( 719 lldbLibDir, 720 '..', 721 'lib') if sys.platform.startswith('win32') else lldbLibDir 722 os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir 723 print("LLDB library dir:", os.environ["LLDB_LIB_DIR"]) 724 print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"]) 725 os.system('%s -v' % lldbtest_config.lldbExec) 726 727 # Assume lldb-mi is in same place as lldb 728 # If not found, disable the lldb-mi tests 729 # TODO: Append .exe on Windows 730 # - this will be in a separate commit in case the mi tests fail horribly 731 lldbDir = os.path.dirname(lldbtest_config.lldbExec) 732 lldbMiExec = os.path.join(lldbDir, "lldb-mi") 733 if is_exe(lldbMiExec): 734 os.environ["LLDBMI_EXEC"] = lldbMiExec 735 else: 736 if not configuration.shouldSkipBecauseOfCategories(["lldb-mi"]): 737 print( 738 "The 'lldb-mi' executable cannot be located. The lldb-mi tests can not be run as a result.") 739 configuration.skipCategories.append("lldb-mi") 740 741 lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode") 742 if is_exe(lldbVSCodeExec): 743 os.environ["LLDBVSCODE_EXEC"] = lldbVSCodeExec 744 else: 745 if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]): 746 print( 747 "The 'lldb-vscode' executable cannot be located. The lldb-vscode tests can not be run as a result.") 748 configuration.skipCategories.append("lldb-vscode") 749 750 lldbPythonDir = None # The directory that contains 'lldb/__init__.py' 751 if not configuration.lldbFrameworkPath and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")): 752 configuration.lldbFrameworkPath = os.path.join(lldbLibDir, "LLDB.framework") 753 if configuration.lldbFrameworkPath: 754 lldbtest_config.lldbFrameworkPath = configuration.lldbFrameworkPath 755 candidatePath = os.path.join( 756 configuration.lldbFrameworkPath, 'Resources', 'Python') 757 if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')): 758 lldbPythonDir = candidatePath 759 if not lldbPythonDir: 760 print( 761 'Resources/Python/lldb/__init__.py was not found in ' + 762 configuration.lldbFrameworkPath) 763 sys.exit(-1) 764 else: 765 # If our lldb supports the -P option, use it to find the python path: 766 init_in_python_dir = os.path.join('lldb', '__init__.py') 767 768 lldb_dash_p_result = subprocess.check_output( 769 [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True) 770 771 if lldb_dash_p_result and not lldb_dash_p_result.startswith( 772 ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"): 773 lines = lldb_dash_p_result.splitlines() 774 775 # Workaround for readline vs libedit issue on FreeBSD. If stdout 776 # is not a terminal Python executes 777 # rl_variable_bind ("enable-meta-key", "off"); 778 # This produces a warning with FreeBSD's libedit because the 779 # enable-meta-key variable is unknown. Not an issue on Apple 780 # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__ 781 # around the call. See http://bugs.python.org/issue19884 for more 782 # information. For now we just discard the warning output. 783 if len(lines) >= 1 and lines[0].startswith( 784 "bind: Invalid command"): 785 lines.pop(0) 786 787 # Taking the last line because lldb outputs 788 # 'Cannot read termcap database;\nusing dumb terminal settings.\n' 789 # before the path 790 if len(lines) >= 1 and os.path.isfile( 791 os.path.join(lines[-1], init_in_python_dir)): 792 lldbPythonDir = lines[-1] 793 if "freebsd" in sys.platform or "linux" in sys.platform: 794 os.environ['LLDB_LIB_DIR'] = os.path.join( 795 lldbPythonDir, '..', '..') 796 797 if not lldbPythonDir: 798 if platform.system() == "Darwin": 799 python_resource_dir = ['LLDB.framework', 'Resources', 'Python'] 800 outputPaths = getXcodeOutputPaths(lldbRootDirectory) 801 for outputPath in outputPaths: 802 candidatePath = os.path.join( 803 outputPath, *python_resource_dir) 804 if os.path.isfile( 805 os.path.join( 806 candidatePath, 807 init_in_python_dir)): 808 lldbPythonDir = candidatePath 809 break 810 811 if not lldbPythonDir: 812 print("lldb.py is not found, some tests may fail.") 813 else: 814 print( 815 "Unable to load lldb extension module. Possible reasons for this include:") 816 print(" 1) LLDB was built with LLDB_DISABLE_PYTHON=1") 817 print( 818 " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") 819 print( 820 " the version of Python that LLDB built and linked against, and PYTHONPATH") 821 print( 822 " should contain the Lib directory for the same python distro, as well as the") 823 print(" location of LLDB\'s site-packages folder.") 824 print( 825 " 3) A different version of Python than that which was built against is exported in") 826 print(" the system\'s PATH environment variable, causing conflicts.") 827 print( 828 " 4) The executable '%s' could not be found. Please check " % 829 lldbtest_config.lldbExec) 830 print(" that it exists and is executable.") 831 832 if lldbPythonDir: 833 lldbPythonDir = os.path.normpath(lldbPythonDir) 834 # Some of the code that uses this path assumes it hasn't resolved the Versions... link. 835 # If the path we've constructed looks like that, then we'll strip out 836 # the Versions/A part. 837 (before, frameWithVersion, after) = lldbPythonDir.rpartition( 838 "LLDB.framework/Versions/A") 839 if frameWithVersion != "": 840 lldbPythonDir = before + "LLDB.framework" + after 841 842 lldbPythonDir = os.path.abspath(lldbPythonDir) 843 844 # If tests need to find LLDB_FRAMEWORK, now they can do it 845 os.environ["LLDB_FRAMEWORK"] = os.path.dirname( 846 os.path.dirname(lldbPythonDir)) 847 848 # This is to locate the lldb.py module. Insert it right after 849 # sys.path[0]. 850 sys.path[1:1] = [lldbPythonDir] 851 852 853def visit_file(dir, name): 854 # Try to match the regexp pattern, if specified. 855 if configuration.regexp: 856 if not re.search(configuration.regexp, name): 857 # We didn't match the regex, we're done. 858 return 859 860 if configuration.skip_tests: 861 for file_regexp in configuration.skip_tests: 862 if re.search(file_regexp, name): 863 return 864 865 # We found a match for our test. Add it to the suite. 866 867 # Update the sys.path first. 868 if not sys.path.count(dir): 869 sys.path.insert(0, dir) 870 base = os.path.splitext(name)[0] 871 872 # Thoroughly check the filterspec against the base module and admit 873 # the (base, filterspec) combination only when it makes sense. 874 filterspec = None 875 for filterspec in configuration.filters: 876 # Optimistically set the flag to True. 877 filtered = True 878 module = __import__(base) 879 parts = filterspec.split('.') 880 obj = module 881 for part in parts: 882 try: 883 parent, obj = obj, getattr(obj, part) 884 except AttributeError: 885 # The filterspec has failed. 886 filtered = False 887 break 888 889 # If filtered, we have a good filterspec. Add it. 890 if filtered: 891 # print("adding filter spec %s to module %s" % (filterspec, module)) 892 configuration.suite.addTests( 893 unittest2.defaultTestLoader.loadTestsFromName( 894 filterspec, module)) 895 continue 896 897 # Forgo this module if the (base, filterspec) combo is invalid 898 if configuration.filters and not filtered: 899 return 900 901 if not filterspec or not filtered: 902 # Add the entire file's worth of tests since we're not filtered. 903 # Also the fail-over case when the filterspec branch 904 # (base, filterspec) combo doesn't make sense. 905 configuration.suite.addTests( 906 unittest2.defaultTestLoader.loadTestsFromName(base)) 907 908 909# TODO: This should be replaced with a call to find_test_files_in_dir_tree. 910def visit(prefix, dir, names): 911 """Visitor function for os.path.walk(path, visit, arg).""" 912 913 dir_components = set(dir.split(os.sep)) 914 excluded_components = set(['.svn', '.git']) 915 if dir_components.intersection(excluded_components): 916 return 917 918 # Gather all the Python test file names that follow the Test*.py pattern. 919 python_test_files = [ 920 name 921 for name in names 922 if name.endswith('.py') and name.startswith(prefix)] 923 924 # Visit all the python test files. 925 for name in python_test_files: 926 try: 927 # Ensure we error out if we have multiple tests with the same 928 # base name. 929 # Future improvement: find all the places where we work with base 930 # names and convert to full paths. We have directory structure 931 # to disambiguate these, so we shouldn't need this constraint. 932 if name in configuration.all_tests: 933 raise Exception("Found multiple tests with the name %s" % name) 934 configuration.all_tests.add(name) 935 936 # Run the relevant tests in the python file. 937 visit_file(dir, name) 938 except Exception as ex: 939 # Convert this exception to a test event error for the file. 940 test_filename = os.path.abspath(os.path.join(dir, name)) 941 if configuration.results_formatter_object is not None: 942 # Grab the backtrace for the exception. 943 import traceback 944 backtrace = traceback.format_exc() 945 946 # Generate the test event. 947 configuration.results_formatter_object.handle_event( 948 EventBuilder.event_for_job_test_add_error( 949 test_filename, ex, backtrace)) 950 raise 951 952 953def disabledynamics(): 954 import lldb 955 ci = lldb.DBG.GetCommandInterpreter() 956 res = lldb.SBCommandReturnObject() 957 ci.HandleCommand( 958 "setting set target.prefer-dynamic-value no-dynamic-values", 959 res, 960 False) 961 if not res.Succeeded(): 962 raise Exception('disabling dynamic type support failed') 963 964 965def lldbLoggings(): 966 import lldb 967 """Check and do lldb loggings if necessary.""" 968 969 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is 970 # defined. Use ${LLDB_LOG} to specify the log file. 971 ci = lldb.DBG.GetCommandInterpreter() 972 res = lldb.SBCommandReturnObject() 973 if ("LLDB_LOG" in os.environ): 974 open(os.environ["LLDB_LOG"], 'w').close() 975 if ("LLDB_LOG_OPTION" in os.environ): 976 lldb_log_option = os.environ["LLDB_LOG_OPTION"] 977 else: 978 lldb_log_option = "event process expr state api" 979 ci.HandleCommand( 980 "log enable -n -f " + 981 os.environ["LLDB_LOG"] + 982 " lldb " + 983 lldb_log_option, 984 res) 985 if not res.Succeeded(): 986 raise Exception('log enable failed (check LLDB_LOG env variable)') 987 988 if ("LLDB_LINUX_LOG" in os.environ): 989 open(os.environ["LLDB_LINUX_LOG"], 'w').close() 990 if ("LLDB_LINUX_LOG_OPTION" in os.environ): 991 lldb_log_option = os.environ["LLDB_LINUX_LOG_OPTION"] 992 else: 993 lldb_log_option = "event process expr state api" 994 ci.HandleCommand( 995 "log enable -n -f " + 996 os.environ["LLDB_LINUX_LOG"] + 997 " linux " + 998 lldb_log_option, 999 res) 1000 if not res.Succeeded(): 1001 raise Exception( 1002 'log enable failed (check LLDB_LINUX_LOG env variable)') 1003 1004 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined. 1005 # Use ${GDB_REMOTE_LOG} to specify the log file. 1006 if ("GDB_REMOTE_LOG" in os.environ): 1007 if ("GDB_REMOTE_LOG_OPTION" in os.environ): 1008 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"] 1009 else: 1010 gdb_remote_log_option = "packets process" 1011 ci.HandleCommand( 1012 "log enable -n -f " + os.environ["GDB_REMOTE_LOG"] + " gdb-remote " 1013 + gdb_remote_log_option, 1014 res) 1015 if not res.Succeeded(): 1016 raise Exception( 1017 'log enable failed (check GDB_REMOTE_LOG env variable)') 1018 1019 1020def getMyCommandLine(): 1021 return ' '.join(sys.argv) 1022 1023# ======================================== # 1024# # 1025# Execution of the test driver starts here # 1026# # 1027# ======================================== # 1028 1029 1030def checkDsymForUUIDIsNotOn(): 1031 cmd = ["defaults", "read", "com.apple.DebugSymbols"] 1032 pipe = subprocess.Popen( 1033 cmd, 1034 stdout=subprocess.PIPE, 1035 stderr=subprocess.STDOUT) 1036 cmd_output = pipe.stdout.read() 1037 if cmd_output and "DBGFileMappedPaths = " in cmd_output: 1038 print("%s =>" % ' '.join(cmd)) 1039 print(cmd_output) 1040 print( 1041 "Disable automatic lookup and caching of dSYMs before running the test suite!") 1042 print("Exiting...") 1043 sys.exit(0) 1044 1045 1046def exitTestSuite(exitCode=None): 1047 import lldb 1048 lldb.SBDebugger.Terminate() 1049 if exitCode: 1050 sys.exit(exitCode) 1051 1052 1053def isMultiprocessTestRunner(): 1054 # We're not multiprocess when we're either explicitly 1055 # the inferior (as specified by the multiprocess test 1056 # runner) OR we've been told to skip using the multiprocess 1057 # test runner 1058 return not ( 1059 configuration.is_inferior_test_runner or configuration.no_multiprocess_test_runner) 1060 1061 1062def getVersionForSDK(sdk): 1063 sdk = str.lower(sdk) 1064 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk) 1065 basename = os.path.basename(full_path) 1066 basename = os.path.splitext(basename)[0] 1067 basename = str.lower(basename) 1068 ver = basename.replace(sdk, '') 1069 return ver 1070 1071 1072def getPathForSDK(sdk): 1073 sdk = str.lower(sdk) 1074 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk) 1075 if os.path.exists(full_path): 1076 return full_path 1077 return None 1078 1079 1080def setDefaultTripleForPlatform(): 1081 if configuration.lldb_platform_name == 'ios-simulator': 1082 triple_str = 'x86_64-apple-ios%s' % ( 1083 getVersionForSDK('iphonesimulator')) 1084 os.environ['TRIPLE'] = triple_str 1085 return {'TRIPLE': triple_str} 1086 return {} 1087 1088 1089def checkCompiler(): 1090 # Add some intervention here to sanity check that the compiler requested is sane. 1091 # If found not to be an executable program, we abort. 1092 c = configuration.compiler 1093 if which(c): 1094 return 1095 1096 if not sys.platform.startswith("darwin"): 1097 raise Exception(c + " is not a valid compiler") 1098 1099 pipe = subprocess.Popen( 1100 ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 1101 cmd_output = pipe.stdout.read() 1102 if not cmd_output or "not found" in cmd_output: 1103 raise Exception(c + " is not a valid compiler") 1104 1105 configuration.compiler = cmd_output.split('\n')[0] 1106 print("'xcrun -find %s' returning %s" % (c, configuration.compiler)) 1107 1108def canRunLibcxxTests(): 1109 from lldbsuite.test import lldbplatformutil 1110 1111 platform = lldbplatformutil.getPlatform() 1112 1113 if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin(): 1114 return True, "libc++ always present" 1115 1116 if platform == "linux": 1117 if not os.path.isdir("/usr/include/c++/v1"): 1118 return False, "Unable to find libc++ installation" 1119 return True, "Headers found, let's hope they work" 1120 1121 return False, "Don't know how to build with libc++ on %s" % platform 1122 1123def checkLibcxxSupport(): 1124 result, reason = canRunLibcxxTests() 1125 if result: 1126 return # libc++ supported 1127 if "libc++" in configuration.categoriesList: 1128 return # libc++ category explicitly requested, let it run. 1129 print("Libc++ tests will not be run because: " + reason) 1130 configuration.skipCategories.append("libc++") 1131 1132def canRunLibstdcxxTests(): 1133 from lldbsuite.test import lldbplatformutil 1134 1135 platform = lldbplatformutil.getPlatform() 1136 if platform == "linux": 1137 return True, "libstdcxx always present" 1138 return False, "Don't know how to build with libstdcxx on %s" % platform 1139 1140def checkLibstdcxxSupport(): 1141 result, reason = canRunLibstdcxxTests() 1142 if result: 1143 return # libstdcxx supported 1144 if "libstdcxx" in configuration.categoriesList: 1145 return # libstdcxx category explicitly requested, let it run. 1146 print("libstdcxx tests will not be run because: " + reason) 1147 configuration.skipCategories.append("libstdcxx") 1148 1149def checkDebugInfoSupport(): 1150 import lldb 1151 1152 platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2] 1153 compiler = configuration.compiler 1154 skipped = [] 1155 for cat in test_categories.debug_info_categories: 1156 if cat in configuration.categoriesList: 1157 continue # Category explicitly requested, let it run. 1158 if test_categories.is_supported_on_platform(cat, platform, compiler): 1159 continue 1160 configuration.skipCategories.append(cat) 1161 skipped.append(cat) 1162 if skipped: 1163 print("Skipping following debug info categories:", skipped) 1164 1165def run_suite(): 1166 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults 1167 # does not exist before proceeding to running the test suite. 1168 if sys.platform.startswith("darwin"): 1169 checkDsymForUUIDIsNotOn() 1170 1171 # 1172 # Start the actions by first parsing the options while setting up the test 1173 # directories, followed by setting up the search paths for lldb utilities; 1174 # then, we walk the directory trees and collect the tests into our test suite. 1175 # 1176 parseOptionsAndInitTestdirs() 1177 1178 # Setup test results (test results formatter and output handling). 1179 setupTestResults() 1180 1181 # If we are running as the multiprocess test runner, kick off the 1182 # multiprocess test runner here. 1183 if isMultiprocessTestRunner(): 1184 from . import dosep 1185 dosep.main( 1186 configuration.num_threads, 1187 configuration.test_runner_name, 1188 configuration.results_formatter_object) 1189 raise Exception("should never get here") 1190 elif configuration.is_inferior_test_runner: 1191 # Shut off Ctrl-C processing in inferiors. The parallel 1192 # test runner handles this more holistically. 1193 signal.signal(signal.SIGINT, signal.SIG_IGN) 1194 1195 setupSysPath() 1196 1197 # 1198 # If '-l' is specified, do not skip the long running tests. 1199 if not configuration.skip_long_running_test: 1200 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO" 1201 1202 # For the time being, let's bracket the test runner within the 1203 # lldb.SBDebugger.Initialize()/Terminate() pair. 1204 import lldb 1205 1206 # Create a singleton SBDebugger in the lldb namespace. 1207 lldb.DBG = lldb.SBDebugger.Create() 1208 1209 if configuration.lldb_platform_name: 1210 print("Setting up remote platform '%s'" % 1211 (configuration.lldb_platform_name)) 1212 lldb.remote_platform = lldb.SBPlatform( 1213 configuration.lldb_platform_name) 1214 if not lldb.remote_platform.IsValid(): 1215 print( 1216 "error: unable to create the LLDB platform named '%s'." % 1217 (configuration.lldb_platform_name)) 1218 exitTestSuite(1) 1219 if configuration.lldb_platform_url: 1220 # We must connect to a remote platform if a LLDB platform URL was 1221 # specified 1222 print( 1223 "Connecting to remote platform '%s' at '%s'..." % 1224 (configuration.lldb_platform_name, configuration.lldb_platform_url)) 1225 platform_connect_options = lldb.SBPlatformConnectOptions( 1226 configuration.lldb_platform_url) 1227 err = lldb.remote_platform.ConnectRemote(platform_connect_options) 1228 if err.Success(): 1229 print("Connected.") 1230 else: 1231 print("error: failed to connect to remote platform using URL '%s': %s" % ( 1232 configuration.lldb_platform_url, err)) 1233 exitTestSuite(1) 1234 else: 1235 configuration.lldb_platform_url = None 1236 1237 platform_changes = setDefaultTripleForPlatform() 1238 first = True 1239 for key in platform_changes: 1240 if first: 1241 print("Environment variables setup for platform support:") 1242 first = False 1243 print("%s = %s" % (key, platform_changes[key])) 1244 1245 if configuration.lldb_platform_working_dir: 1246 print("Setting remote platform working directory to '%s'..." % 1247 (configuration.lldb_platform_working_dir)) 1248 error = lldb.remote_platform.MakeDirectory( 1249 configuration.lldb_platform_working_dir, 448) # 448 = 0o700 1250 if error.Fail(): 1251 raise Exception("making remote directory '%s': %s" % ( 1252 configuration.lldb_platform_working_dir, error)) 1253 1254 if not lldb.remote_platform.SetWorkingDirectory( 1255 configuration.lldb_platform_working_dir): 1256 raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir) 1257 lldb.DBG.SetSelectedPlatform(lldb.remote_platform) 1258 else: 1259 lldb.remote_platform = None 1260 configuration.lldb_platform_working_dir = None 1261 configuration.lldb_platform_url = None 1262 1263 # Set up the working directory. 1264 # Note that it's not dotest's job to clean this directory. 1265 import lldbsuite.test.lldbutil as lldbutil 1266 build_dir = configuration.test_build_dir 1267 lldbutil.mkdir_p(build_dir) 1268 1269 target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2] 1270 1271 checkLibcxxSupport() 1272 checkLibstdcxxSupport() 1273 checkDebugInfoSupport() 1274 1275 # Don't do debugserver tests on anything except OS X. 1276 configuration.dont_do_debugserver_test = "linux" in target_platform or "freebsd" in target_platform or "windows" in target_platform 1277 1278 # Don't do lldb-server (llgs) tests on anything except Linux. 1279 configuration.dont_do_llgs_test = not ("linux" in target_platform) 1280 1281 # Collect tests from the specified testing directories. If a test 1282 # subdirectory filter is explicitly specified, limit the search to that 1283 # subdirectory. 1284 exclusive_test_subdir = configuration.get_absolute_path_to_exclusive_test_subdir() 1285 if exclusive_test_subdir: 1286 dirs_to_search = [exclusive_test_subdir] 1287 else: 1288 dirs_to_search = configuration.testdirs 1289 for testdir in dirs_to_search: 1290 for (dirpath, dirnames, filenames) in os.walk(testdir): 1291 visit('Test', dirpath, filenames) 1292 1293 # 1294 # Now that we have loaded all the test cases, run the whole test suite. 1295 # 1296 1297 # Turn on lldb loggings if necessary. 1298 lldbLoggings() 1299 1300 # Disable default dynamic types for testing purposes 1301 disabledynamics() 1302 1303 # Install the control-c handler. 1304 unittest2.signals.installHandler() 1305 1306 # If sdir_name is not specified through the '-s sdir_name' option, get a 1307 # timestamp string and export it as LLDB_SESSION_DIR environment var. This will 1308 # be used when/if we want to dump the session info of individual test cases 1309 # later on. 1310 # 1311 # See also TestBase.dumpSessionInfo() in lldbtest.py. 1312 import datetime 1313 # The windows platforms don't like ':' in the pathname. 1314 timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S") 1315 if not configuration.sdir_name: 1316 configuration.sdir_name = timestamp_started 1317 os.environ["LLDB_SESSION_DIRNAME"] = os.path.join( 1318 os.getcwd(), configuration.sdir_name) 1319 1320 sys.stderr.write( 1321 "\nSession logs for test failures/errors/unexpected successes" 1322 " will go into directory '%s'\n" % 1323 configuration.sdir_name) 1324 sys.stderr.write("Command invoked: %s\n" % getMyCommandLine()) 1325 1326 if not os.path.isdir(configuration.sdir_name): 1327 try: 1328 os.mkdir(configuration.sdir_name) 1329 except OSError as exception: 1330 if exception.errno != errno.EEXIST: 1331 raise 1332 1333 # 1334 # Invoke the default TextTestRunner to run the test suite 1335 # 1336 checkCompiler() 1337 1338 if not configuration.parsable: 1339 print("compiler=%s" % configuration.compiler) 1340 1341 # Iterating over all possible architecture and compiler combinations. 1342 os.environ["ARCH"] = configuration.arch 1343 os.environ["CC"] = configuration.compiler 1344 configString = "arch=%s compiler=%s" % (configuration.arch, 1345 configuration.compiler) 1346 1347 # Translate ' ' to '-' for pathname component. 1348 if six.PY2: 1349 import string 1350 tbl = string.maketrans(' ', '-') 1351 else: 1352 tbl = str.maketrans(' ', '-') 1353 configPostfix = configString.translate(tbl) 1354 1355 # Output the configuration. 1356 if not configuration.parsable: 1357 sys.stderr.write("\nConfiguration: " + configString + "\n") 1358 1359 # First, write out the number of collected test cases. 1360 if not configuration.parsable: 1361 sys.stderr.write(configuration.separator + "\n") 1362 sys.stderr.write( 1363 "Collected %d test%s\n\n" % 1364 (configuration.suite.countTestCases(), 1365 configuration.suite.countTestCases() != 1 and "s" or "")) 1366 1367 if configuration.parsable: 1368 v = 0 1369 else: 1370 v = configuration.verbose 1371 1372 # Invoke the test runner. 1373 if configuration.count == 1: 1374 result = unittest2.TextTestRunner( 1375 stream=sys.stderr, 1376 verbosity=v, 1377 resultclass=test_result.LLDBTestResult).run( 1378 configuration.suite) 1379 else: 1380 # We are invoking the same test suite more than once. In this case, 1381 # mark __ignore_singleton__ flag as True so the signleton pattern is 1382 # not enforced. 1383 test_result.LLDBTestResult.__ignore_singleton__ = True 1384 for i in range(configuration.count): 1385 1386 result = unittest2.TextTestRunner( 1387 stream=sys.stderr, 1388 verbosity=v, 1389 resultclass=test_result.LLDBTestResult).run( 1390 configuration.suite) 1391 1392 configuration.failed = not result.wasSuccessful() 1393 1394 if configuration.sdir_has_content and not configuration.parsable: 1395 sys.stderr.write( 1396 "Session logs for test failures/errors/unexpected successes" 1397 " can be found in directory '%s'\n" % 1398 configuration.sdir_name) 1399 1400 if configuration.useCategories and len( 1401 configuration.failuresPerCategory) > 0: 1402 sys.stderr.write("Failures per category:\n") 1403 for category in configuration.failuresPerCategory: 1404 sys.stderr.write( 1405 "%s - %d\n" % 1406 (category, configuration.failuresPerCategory[category])) 1407 1408 # Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined. 1409 # This should not be necessary now. 1410 if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ): 1411 print("Terminating Test suite...") 1412 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())]) 1413 1414 # Exiting. 1415 exitTestSuite(configuration.failed) 1416 1417if __name__ == "__main__": 1418 print( 1419 __file__ + 1420 " is for use as a module only. It should not be run as a standalone script.") 1421 sys.exit(-1) 1422