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.channels:
305        lldbtest_config.channels = args.channels
306
307    if args.log_success:
308        lldbtest_config.log_success = args.log_success
309
310    if args.out_of_tree_debugserver:
311        lldbtest_config.out_of_tree_debugserver = args.out_of_tree_debugserver
312
313    # Set SDKROOT if we are using an Apple SDK
314    if platform_system == 'Darwin' and args.apple_sdk:
315        os.environ['SDKROOT'] = seven.get_command_output(
316            'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' %
317            (args.apple_sdk))
318
319    if args.arch:
320        configuration.arch = args.arch
321        if configuration.arch.startswith(
322                'arm') and platform_system == 'Darwin' and not args.apple_sdk:
323            os.environ['SDKROOT'] = seven.get_command_output(
324                'xcrun --sdk iphoneos.internal --show-sdk-path 2> /dev/null')
325            if not os.path.exists(os.environ['SDKROOT']):
326                os.environ['SDKROOT'] = seven.get_command_output(
327                    'xcrun --sdk iphoneos --show-sdk-path 2> /dev/null')
328    else:
329        configuration.arch = platform_machine
330
331    if args.categoriesList:
332        configuration.categoriesList = set(
333            test_categories.validate(
334                args.categoriesList, False))
335        configuration.useCategories = True
336    else:
337        configuration.categoriesList = []
338
339    if args.skipCategories:
340        configuration.skipCategories = test_categories.validate(
341            args.skipCategories, False)
342
343    if args.E:
344        cflags_extras = args.E
345        os.environ['CFLAGS_EXTRAS'] = cflags_extras
346
347    if args.d:
348        sys.stdout.write(
349            "Suspending the process %d to wait for debugger to attach...\n" %
350            os.getpid())
351        sys.stdout.flush()
352        os.kill(os.getpid(), signal.SIGSTOP)
353
354    if args.f:
355        if any([x.startswith('-') for x in args.f]):
356            usage(parser)
357        configuration.filters.extend(args.f)
358        # Shut off multiprocessing mode when additional filters are specified.
359        # The rational is that the user is probably going after a very specific
360        # test and doesn't need a bunch of parallel test runners all looking for
361        # it in a frenzy.  Also, '-v' now spits out all test run output even
362        # on success, so the standard recipe for redoing a failing test (with -v
363        # and a -f to filter to the specific test) now causes all test scanning
364        # (in parallel) to print results for do-nothing runs in a very distracting
365        # manner.  If we really need filtered parallel runs in the future, consider
366        # adding a --no-output-on-success that prevents -v from setting
367        # output-on-success.
368        configuration.no_multiprocess_test_runner = True
369
370    if args.l:
371        configuration.skip_long_running_test = False
372
373    if args.framework:
374        configuration.lldbFrameworkPath = args.framework
375
376    if args.executable:
377        # lldb executable is passed explicitly
378        lldbtest_config.lldbExec = os.path.realpath(args.executable)
379        if not is_exe(lldbtest_config.lldbExec):
380            lldbtest_config.lldbExec = which(args.executable)
381        if not is_exe(lldbtest_config.lldbExec):
382            logging.error(
383                    '%s is not a valid executable to test; aborting...',
384                    args.executable)
385            sys.exit(-1)
386
387    if args.server:
388        os.environ['LLDB_DEBUGSERVER_PATH'] = args.server
389
390    if args.excluded:
391        for excl_file in args.excluded:
392            parseExclusion(excl_file)
393
394    if args.p:
395        if args.p.startswith('-'):
396            usage(parser)
397        configuration.regexp = args.p
398
399    if args.q:
400        configuration.parsable = True
401
402    if args.s:
403        if args.s.startswith('-'):
404            usage(parser)
405        configuration.sdir_name = args.s
406    configuration.session_file_format = args.session_file_format
407
408    if args.t:
409        os.environ['LLDB_COMMAND_TRACE'] = 'YES'
410
411    if args.v:
412        configuration.verbose = 2
413
414    # argparse makes sure we have a number
415    if args.sharp:
416        configuration.count = args.sharp
417
418    if sys.platform.startswith('win32'):
419        os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str(
420            args.disable_crash_dialog)
421        os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True)
422
423    if do_help:
424        usage(parser)
425
426    if args.no_multiprocess:
427        configuration.no_multiprocess_test_runner = True
428
429    if args.inferior:
430        configuration.is_inferior_test_runner = True
431
432    if args.num_threads:
433        configuration.num_threads = args.num_threads
434
435    if args.test_subdir:
436        configuration.multiprocess_test_subdir = args.test_subdir
437
438    if args.test_runner_name:
439        configuration.test_runner_name = args.test_runner_name
440
441    # Capture test results-related args.
442    if args.curses and not args.inferior:
443        # Act as if the following args were set.
444        args.results_formatter = "lldbsuite.test_event.formatter.curses.Curses"
445        args.results_file = "stdout"
446
447    if args.results_file:
448        configuration.results_filename = args.results_file
449
450    if args.results_port:
451        configuration.results_port = args.results_port
452
453    if args.results_file and args.results_port:
454        sys.stderr.write(
455            "only one of --results-file and --results-port should "
456            "be specified\n")
457        usage(args)
458
459    if args.results_formatter:
460        configuration.results_formatter_name = args.results_formatter
461    if args.results_formatter_options:
462        configuration.results_formatter_options = args.results_formatter_options
463
464    # Default to using the BasicResultsFormatter if no formatter is specified
465    # and we're not a test inferior.
466    if not args.inferior and configuration.results_formatter_name is None:
467        configuration.results_formatter_name = (
468            "lldbsuite.test_event.formatter.results_formatter.ResultsFormatter")
469
470    # rerun-related arguments
471    configuration.rerun_all_issues = args.rerun_all_issues
472    configuration.rerun_max_file_threshold = args.rerun_max_file_threshold
473
474    if args.lldb_platform_name:
475        configuration.lldb_platform_name = args.lldb_platform_name
476    if args.lldb_platform_url:
477        configuration.lldb_platform_url = args.lldb_platform_url
478    if args.lldb_platform_working_dir:
479        configuration.lldb_platform_working_dir = args.lldb_platform_working_dir
480    if args.test_build_dir:
481        configuration.test_build_dir = args.test_build_dir
482
483    if args.event_add_entries and len(args.event_add_entries) > 0:
484        entries = {}
485        # Parse out key=val pairs, separated by comma
486        for keyval in args.event_add_entries.split(","):
487            key_val_entry = keyval.split("=")
488            if len(key_val_entry) == 2:
489                (key, val) = key_val_entry
490                val_parts = val.split(':')
491                if len(val_parts) > 1:
492                    (val, val_type) = val_parts
493                    if val_type == 'int':
494                        val = int(val)
495                entries[key] = val
496        # Tell the event builder to create all events with these
497        # key/val pairs in them.
498        if len(entries) > 0:
499            EventBuilder.add_entries_to_all_events(entries)
500
501    # Gather all the dirs passed on the command line.
502    if len(args.args) > 0:
503        configuration.testdirs = list(
504            map(lambda x: os.path.realpath(os.path.abspath(x)), args.args))
505        # Shut off multiprocessing mode when test directories are specified.
506        configuration.no_multiprocess_test_runner = True
507
508    lldbtest_config.codesign_identity = args.codesign_identity
509
510    #print("testdirs:", testdirs)
511
512
513def getXcodeOutputPaths(lldbRootDirectory):
514    result = []
515
516    # These are for xcode build directories.
517    xcode3_build_dir = ['build']
518    xcode4_build_dir = ['build', 'lldb', 'Build', 'Products']
519
520    configurations = [
521        ['Debug'],
522        ['DebugClang'],
523        ['Release'],
524        ['BuildAndIntegration']]
525    xcode_build_dirs = [xcode3_build_dir, xcode4_build_dir]
526    for configuration in configurations:
527        for xcode_build_dir in xcode_build_dirs:
528            outputPath = os.path.join(
529                lldbRootDirectory, *(xcode_build_dir + configuration))
530            result.append(outputPath)
531
532    return result
533
534
535def createSocketToLocalPort(port):
536    def socket_closer(s):
537        """Close down an opened socket properly."""
538        s.shutdown(socket.SHUT_RDWR)
539        s.close()
540
541    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
542    sock.connect(("localhost", port))
543    return (sock, lambda: socket_closer(sock))
544
545
546def setupTestResults():
547    """Sets up test results-related objects based on arg settings."""
548    # Setup the results formatter configuration.
549    formatter_config = formatter.FormatterConfig()
550    formatter_config.filename = configuration.results_filename
551    formatter_config.formatter_name = configuration.results_formatter_name
552    formatter_config.formatter_options = (
553        configuration.results_formatter_options)
554    formatter_config.port = configuration.results_port
555
556    # Create the results formatter.
557    formatter_spec = formatter.create_results_formatter(
558        formatter_config)
559    if formatter_spec is not None and formatter_spec.formatter is not None:
560        configuration.results_formatter_object = formatter_spec.formatter
561
562        # Send an initialize message to the formatter.
563        initialize_event = EventBuilder.bare_event("initialize")
564        if isMultiprocessTestRunner():
565            if (configuration.test_runner_name is not None and
566                    configuration.test_runner_name == "serial"):
567                # Only one worker queue here.
568                worker_count = 1
569            else:
570                # Workers will be the number of threads specified.
571                worker_count = configuration.num_threads
572        else:
573            worker_count = 1
574        initialize_event["worker_count"] = worker_count
575
576        formatter_spec.formatter.handle_event(initialize_event)
577
578        # Make sure we clean up the formatter on shutdown.
579        if formatter_spec.cleanup_func is not None:
580            atexit.register(formatter_spec.cleanup_func)
581
582
583def getOutputPaths(lldbRootDirectory):
584    """
585    Returns typical build output paths for the lldb executable
586
587    lldbDirectory - path to the root of the lldb svn/git repo
588    """
589    result = []
590
591    if sys.platform == 'darwin':
592        result.extend(getXcodeOutputPaths(lldbRootDirectory))
593
594    # cmake builds?  look for build or build/host folder next to llvm directory
595    # lldb is located in llvm/tools/lldb so we need to go up three levels
596    llvmParentDir = os.path.abspath(
597        os.path.join(
598            lldbRootDirectory,
599            os.pardir,
600            os.pardir,
601            os.pardir))
602    result.append(os.path.join(llvmParentDir, 'build', 'bin'))
603    result.append(os.path.join(llvmParentDir, 'build', 'host', 'bin'))
604
605    # some cmake developers keep their build directory beside their lldb
606    # directory
607    lldbParentDir = os.path.abspath(os.path.join(lldbRootDirectory, os.pardir))
608    result.append(os.path.join(lldbParentDir, 'build', 'bin'))
609    result.append(os.path.join(lldbParentDir, 'build', 'host', 'bin'))
610
611    return result
612
613
614def setupSysPath():
615    """
616    Add LLDB.framework/Resources/Python to the search paths for modules.
617    As a side effect, we also discover the 'lldb' executable and export it here.
618    """
619
620    # Get the directory containing the current script.
621    if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ:
622        scriptPath = os.environ["DOTEST_SCRIPT_DIR"]
623    else:
624        scriptPath = os.path.dirname(os.path.realpath(__file__))
625    if not scriptPath.endswith('test'):
626        print("This script expects to reside in lldb's test directory.")
627        sys.exit(-1)
628
629    os.environ["LLDB_TEST"] = scriptPath
630
631    # Set up the root build directory.
632    builddir = configuration.test_build_dir
633    if not configuration.test_build_dir:
634        raise Exception("test_build_dir is not set")
635    os.environ["LLDB_BUILD"] = os.path.abspath(configuration.test_build_dir)
636
637    # Set up the LLDB_SRC environment variable, so that the tests can locate
638    # the LLDB source code.
639    os.environ["LLDB_SRC"] = lldbsuite.lldb_root
640
641    pluginPath = os.path.join(scriptPath, 'plugins')
642    toolsLLDBMIPath = os.path.join(scriptPath, 'tools', 'lldb-mi')
643    toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server')
644
645    # Insert script dir, plugin dir, lldb-mi dir and lldb-server dir to the
646    # sys.path.
647    sys.path.insert(0, pluginPath)
648    # Adding test/tools/lldb-mi to the path makes it easy
649    sys.path.insert(0, toolsLLDBMIPath)
650    # to "import lldbmi_testcase" from the MI tests
651    # Adding test/tools/lldb-server to the path makes it easy
652    sys.path.insert(0, toolsLLDBServerPath)
653    # to "import lldbgdbserverutils" from the lldb-server tests
654
655    # This is the root of the lldb git/svn checkout
656    # When this changes over to a package instead of a standalone script, this
657    # will be `lldbsuite.lldb_root`
658    lldbRootDirectory = lldbsuite.lldb_root
659
660    # Some of the tests can invoke the 'lldb' command directly.
661    # We'll try to locate the appropriate executable right here.
662
663    # The lldb executable can be set from the command line
664    # if it's not set, we try to find it now
665    # first, we try the environment
666    if not lldbtest_config.lldbExec:
667        # First, you can define an environment variable LLDB_EXEC specifying the
668        # full pathname of the lldb executable.
669        if "LLDB_EXEC" in os.environ:
670            lldbtest_config.lldbExec = os.environ["LLDB_EXEC"]
671
672    if not lldbtest_config.lldbExec:
673        outputPaths = getOutputPaths(lldbRootDirectory)
674        for outputPath in outputPaths:
675            candidatePath = os.path.join(outputPath, 'lldb')
676            if is_exe(candidatePath):
677                lldbtest_config.lldbExec = candidatePath
678                break
679
680    if not lldbtest_config.lldbExec:
681        # Last, check the path
682        lldbtest_config.lldbExec = which('lldb')
683
684    if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec):
685        print(
686            "'{}' is not a path to a valid executable".format(
687                lldbtest_config.lldbExec))
688        lldbtest_config.lldbExec = None
689
690    if not lldbtest_config.lldbExec:
691        print("The 'lldb' executable cannot be located.  Some of the tests may not be run as a result.")
692        sys.exit(-1)
693
694    # confusingly, this is the "bin" directory
695    lldbLibDir = os.path.dirname(lldbtest_config.lldbExec)
696    os.environ["LLDB_LIB_DIR"] = lldbLibDir
697    lldbImpLibDir = os.path.join(
698        lldbLibDir,
699        '..',
700        'lib') if sys.platform.startswith('win32') else lldbLibDir
701    os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir
702    print("LLDB library dir:", os.environ["LLDB_LIB_DIR"])
703    print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"])
704    os.system('%s -v' % lldbtest_config.lldbExec)
705
706    # Assume lldb-mi is in same place as lldb
707    # If not found, disable the lldb-mi tests
708    # TODO: Append .exe on Windows
709    #   - this will be in a separate commit in case the mi tests fail horribly
710    lldbDir = os.path.dirname(lldbtest_config.lldbExec)
711    lldbMiExec = os.path.join(lldbDir, "lldb-mi")
712    if is_exe(lldbMiExec):
713        os.environ["LLDBMI_EXEC"] = lldbMiExec
714    else:
715        if not configuration.shouldSkipBecauseOfCategories(["lldb-mi"]):
716            print(
717                "The 'lldb-mi' executable cannot be located.  The lldb-mi tests can not be run as a result.")
718            configuration.skipCategories.append("lldb-mi")
719
720    lldbPythonDir = None  # The directory that contains 'lldb/__init__.py'
721    if not configuration.lldbFrameworkPath and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")):
722        configuration.lldbFrameworkPath = os.path.join(lldbLibDir, "LLDB.framework")
723    if configuration.lldbFrameworkPath:
724        lldbtest_config.lldbFrameworkPath = configuration.lldbFrameworkPath
725        candidatePath = os.path.join(
726            configuration.lldbFrameworkPath, 'Resources', 'Python')
727        if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')):
728            lldbPythonDir = candidatePath
729        if not lldbPythonDir:
730            print(
731                'Resources/Python/lldb/__init__.py was not found in ' +
732                configuration.lldbFrameworkPath)
733            sys.exit(-1)
734    else:
735        # If our lldb supports the -P option, use it to find the python path:
736        init_in_python_dir = os.path.join('lldb', '__init__.py')
737
738        lldb_dash_p_result = subprocess.check_output(
739            [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True)
740
741        if lldb_dash_p_result and not lldb_dash_p_result.startswith(
742                ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"):
743            lines = lldb_dash_p_result.splitlines()
744
745            # Workaround for readline vs libedit issue on FreeBSD.  If stdout
746            # is not a terminal Python executes
747            #     rl_variable_bind ("enable-meta-key", "off");
748            # This produces a warning with FreeBSD's libedit because the
749            # enable-meta-key variable is unknown.  Not an issue on Apple
750            # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__
751            # around the call.  See http://bugs.python.org/issue19884 for more
752            # information.  For now we just discard the warning output.
753            if len(lines) >= 1 and lines[0].startswith(
754                    "bind: Invalid command"):
755                lines.pop(0)
756
757            # Taking the last line because lldb outputs
758            # 'Cannot read termcap database;\nusing dumb terminal settings.\n'
759            # before the path
760            if len(lines) >= 1 and os.path.isfile(
761                    os.path.join(lines[-1], init_in_python_dir)):
762                lldbPythonDir = lines[-1]
763                if "freebsd" in sys.platform or "linux" in sys.platform:
764                    os.environ['LLDB_LIB_DIR'] = os.path.join(
765                        lldbPythonDir, '..', '..')
766
767        if not lldbPythonDir:
768            if platform.system() == "Darwin":
769                python_resource_dir = ['LLDB.framework', 'Resources', 'Python']
770                outputPaths = getXcodeOutputPaths(lldbRootDirectory)
771                for outputPath in outputPaths:
772                    candidatePath = os.path.join(
773                        outputPath, *python_resource_dir)
774                    if os.path.isfile(
775                        os.path.join(
776                            candidatePath,
777                            init_in_python_dir)):
778                        lldbPythonDir = candidatePath
779                        break
780
781                if not lldbPythonDir:
782                    print("lldb.py is not found, some tests may fail.")
783            else:
784                print(
785                    "Unable to load lldb extension module.  Possible reasons for this include:")
786                print("  1) LLDB was built with LLDB_DISABLE_PYTHON=1")
787                print(
788                    "  2) PYTHONPATH and PYTHONHOME are not set correctly.  PYTHONHOME should refer to")
789                print(
790                    "     the version of Python that LLDB built and linked against, and PYTHONPATH")
791                print(
792                    "     should contain the Lib directory for the same python distro, as well as the")
793                print("     location of LLDB\'s site-packages folder.")
794                print(
795                    "  3) A different version of Python than that which was built against is exported in")
796                print("     the system\'s PATH environment variable, causing conflicts.")
797                print(
798                    "  4) The executable '%s' could not be found.  Please check " %
799                    lldbtest_config.lldbExec)
800                print("     that it exists and is executable.")
801
802    if lldbPythonDir:
803        lldbPythonDir = os.path.normpath(lldbPythonDir)
804        # Some of the code that uses this path assumes it hasn't resolved the Versions... link.
805        # If the path we've constructed looks like that, then we'll strip out
806        # the Versions/A part.
807        (before, frameWithVersion, after) = lldbPythonDir.rpartition(
808            "LLDB.framework/Versions/A")
809        if frameWithVersion != "":
810            lldbPythonDir = before + "LLDB.framework" + after
811
812        lldbPythonDir = os.path.abspath(lldbPythonDir)
813
814        # If tests need to find LLDB_FRAMEWORK, now they can do it
815        os.environ["LLDB_FRAMEWORK"] = os.path.dirname(
816            os.path.dirname(lldbPythonDir))
817
818        # This is to locate the lldb.py module.  Insert it right after
819        # sys.path[0].
820        sys.path[1:1] = [lldbPythonDir]
821
822
823def visit_file(dir, name):
824    # Try to match the regexp pattern, if specified.
825    if configuration.regexp:
826        if not re.search(configuration.regexp, name):
827            # We didn't match the regex, we're done.
828            return
829
830    if configuration.skip_tests:
831        for file_regexp in configuration.skip_tests:
832            if re.search(file_regexp, name):
833                return
834
835    # We found a match for our test.  Add it to the suite.
836
837    # Update the sys.path first.
838    if not sys.path.count(dir):
839        sys.path.insert(0, dir)
840    base = os.path.splitext(name)[0]
841
842    # Thoroughly check the filterspec against the base module and admit
843    # the (base, filterspec) combination only when it makes sense.
844    filterspec = None
845    for filterspec in configuration.filters:
846        # Optimistically set the flag to True.
847        filtered = True
848        module = __import__(base)
849        parts = filterspec.split('.')
850        obj = module
851        for part in parts:
852            try:
853                parent, obj = obj, getattr(obj, part)
854            except AttributeError:
855                # The filterspec has failed.
856                filtered = False
857                break
858
859        # If filtered, we have a good filterspec.  Add it.
860        if filtered:
861            # print("adding filter spec %s to module %s" % (filterspec, module))
862            configuration.suite.addTests(
863                unittest2.defaultTestLoader.loadTestsFromName(
864                    filterspec, module))
865            continue
866
867    # Forgo this module if the (base, filterspec) combo is invalid
868    if configuration.filters and not filtered:
869        return
870
871    if not filterspec or not filtered:
872        # Add the entire file's worth of tests since we're not filtered.
873        # Also the fail-over case when the filterspec branch
874        # (base, filterspec) combo doesn't make sense.
875        configuration.suite.addTests(
876            unittest2.defaultTestLoader.loadTestsFromName(base))
877
878
879def visit(prefix, dir, names):
880    """Visitor function for os.path.walk(path, visit, arg)."""
881
882    dir_components = set(dir.split(os.sep))
883    excluded_components = set(['.svn', '.git'])
884    if dir_components.intersection(excluded_components):
885        return
886
887    # Gather all the Python test file names that follow the Test*.py pattern.
888    python_test_files = [
889        name
890        for name in names
891        if name.endswith('.py') and name.startswith(prefix)]
892
893    # Visit all the python test files.
894    for name in python_test_files:
895        try:
896            # Ensure we error out if we have multiple tests with the same
897            # base name.
898            # Future improvement: find all the places where we work with base
899            # names and convert to full paths.  We have directory structure
900            # to disambiguate these, so we shouldn't need this constraint.
901            if name in configuration.all_tests:
902                raise Exception("Found multiple tests with the name %s" % name)
903            configuration.all_tests.add(name)
904
905            # Run the relevant tests in the python file.
906            visit_file(dir, name)
907        except Exception as ex:
908            # Convert this exception to a test event error for the file.
909            test_filename = os.path.abspath(os.path.join(dir, name))
910            if configuration.results_formatter_object is not None:
911                # Grab the backtrace for the exception.
912                import traceback
913                backtrace = traceback.format_exc()
914
915                # Generate the test event.
916                configuration.results_formatter_object.handle_event(
917                    EventBuilder.event_for_job_test_add_error(
918                        test_filename, ex, backtrace))
919            raise
920
921
922def disabledynamics():
923    import lldb
924    ci = lldb.DBG.GetCommandInterpreter()
925    res = lldb.SBCommandReturnObject()
926    ci.HandleCommand(
927        "setting set target.prefer-dynamic-value no-dynamic-values",
928        res,
929        False)
930    if not res.Succeeded():
931        raise Exception('disabling dynamic type support failed')
932
933
934def lldbLoggings():
935    import lldb
936    """Check and do lldb loggings if necessary."""
937
938    # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
939    # defined.  Use ${LLDB_LOG} to specify the log file.
940    ci = lldb.DBG.GetCommandInterpreter()
941    res = lldb.SBCommandReturnObject()
942    if ("LLDB_LOG" in os.environ):
943        open(os.environ["LLDB_LOG"], 'w').close()
944        if ("LLDB_LOG_OPTION" in os.environ):
945            lldb_log_option = os.environ["LLDB_LOG_OPTION"]
946        else:
947            lldb_log_option = "event process expr state api"
948        ci.HandleCommand(
949            "log enable -n -f " +
950            os.environ["LLDB_LOG"] +
951            " lldb " +
952            lldb_log_option,
953            res)
954        if not res.Succeeded():
955            raise Exception('log enable failed (check LLDB_LOG env variable)')
956
957    if ("LLDB_LINUX_LOG" in os.environ):
958        open(os.environ["LLDB_LINUX_LOG"], 'w').close()
959        if ("LLDB_LINUX_LOG_OPTION" in os.environ):
960            lldb_log_option = os.environ["LLDB_LINUX_LOG_OPTION"]
961        else:
962            lldb_log_option = "event process expr state api"
963        ci.HandleCommand(
964            "log enable -n -f " +
965            os.environ["LLDB_LINUX_LOG"] +
966            " linux " +
967            lldb_log_option,
968            res)
969        if not res.Succeeded():
970            raise Exception(
971                'log enable failed (check LLDB_LINUX_LOG env variable)')
972
973    # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
974    # Use ${GDB_REMOTE_LOG} to specify the log file.
975    if ("GDB_REMOTE_LOG" in os.environ):
976        if ("GDB_REMOTE_LOG_OPTION" in os.environ):
977            gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
978        else:
979            gdb_remote_log_option = "packets process"
980        ci.HandleCommand(
981            "log enable -n -f " + os.environ["GDB_REMOTE_LOG"] + " gdb-remote "
982            + gdb_remote_log_option,
983            res)
984        if not res.Succeeded():
985            raise Exception(
986                'log enable failed (check GDB_REMOTE_LOG env variable)')
987
988
989def getMyCommandLine():
990    return ' '.join(sys.argv)
991
992# ======================================== #
993#                                          #
994# Execution of the test driver starts here #
995#                                          #
996# ======================================== #
997
998
999def checkDsymForUUIDIsNotOn():
1000    cmd = ["defaults", "read", "com.apple.DebugSymbols"]
1001    pipe = subprocess.Popen(
1002        cmd,
1003        stdout=subprocess.PIPE,
1004        stderr=subprocess.STDOUT)
1005    cmd_output = pipe.stdout.read()
1006    if cmd_output and "DBGFileMappedPaths = " in cmd_output:
1007        print("%s =>" % ' '.join(cmd))
1008        print(cmd_output)
1009        print(
1010            "Disable automatic lookup and caching of dSYMs before running the test suite!")
1011        print("Exiting...")
1012        sys.exit(0)
1013
1014
1015def exitTestSuite(exitCode=None):
1016    import lldb
1017    lldb.SBDebugger.Terminate()
1018    if exitCode:
1019        sys.exit(exitCode)
1020
1021
1022def isMultiprocessTestRunner():
1023    # We're not multiprocess when we're either explicitly
1024    # the inferior (as specified by the multiprocess test
1025    # runner) OR we've been told to skip using the multiprocess
1026    # test runner
1027    return not (
1028        configuration.is_inferior_test_runner or configuration.no_multiprocess_test_runner)
1029
1030
1031def getVersionForSDK(sdk):
1032    sdk = str.lower(sdk)
1033    full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk)
1034    basename = os.path.basename(full_path)
1035    basename = os.path.splitext(basename)[0]
1036    basename = str.lower(basename)
1037    ver = basename.replace(sdk, '')
1038    return ver
1039
1040
1041def getPathForSDK(sdk):
1042    sdk = str.lower(sdk)
1043    full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk)
1044    if os.path.exists(full_path):
1045        return full_path
1046    return None
1047
1048
1049def setDefaultTripleForPlatform():
1050    if configuration.lldb_platform_name == 'ios-simulator':
1051        triple_str = 'x86_64-apple-ios%s' % (
1052            getVersionForSDK('iphonesimulator'))
1053        os.environ['TRIPLE'] = triple_str
1054        return {'TRIPLE': triple_str}
1055    return {}
1056
1057
1058def checkCompiler():
1059    # Add some intervention here to sanity check that the compiler requested is sane.
1060    # If found not to be an executable program, we abort.
1061    c = configuration.compiler
1062    if which(c):
1063        return
1064
1065    if not sys.platform.startswith("darwin"):
1066        raise Exception(c + " is not a valid compiler")
1067
1068    pipe = subprocess.Popen(
1069        ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
1070    cmd_output = pipe.stdout.read()
1071    if not cmd_output or "not found" in cmd_output:
1072        raise Exception(c + " is not a valid compiler")
1073
1074    configuration.compiler = cmd_output.split('\n')[0]
1075    print("'xcrun -find %s' returning %s" % (c, configuration.compiler))
1076
1077def canRunLibcxxTests():
1078    from lldbsuite.test import lldbplatformutil
1079
1080    platform = lldbplatformutil.getPlatform()
1081
1082    if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin():
1083        return True, "libc++ always present"
1084
1085    if platform == "linux":
1086        if not os.path.isdir("/usr/include/c++/v1"):
1087            return False, "Unable to find libc++ installation"
1088        return True, "Headers found, let's hope they work"
1089
1090    return False, "Don't know how to build with libc++ on %s" % platform
1091
1092def checkLibcxxSupport():
1093    result, reason = canRunLibcxxTests()
1094    if result:
1095        return # libc++ supported
1096    if "libc++" in configuration.categoriesList:
1097        return # libc++ category explicitly requested, let it run.
1098    print("Libc++ tests will not be run because: " + reason)
1099    configuration.skipCategories.append("libc++")
1100
1101def run_suite():
1102    # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults
1103    # does not exist before proceeding to running the test suite.
1104    if sys.platform.startswith("darwin"):
1105        checkDsymForUUIDIsNotOn()
1106
1107    #
1108    # Start the actions by first parsing the options while setting up the test
1109    # directories, followed by setting up the search paths for lldb utilities;
1110    # then, we walk the directory trees and collect the tests into our test suite.
1111    #
1112    parseOptionsAndInitTestdirs()
1113
1114    # Setup test results (test results formatter and output handling).
1115    setupTestResults()
1116
1117    # If we are running as the multiprocess test runner, kick off the
1118    # multiprocess test runner here.
1119    if isMultiprocessTestRunner():
1120        from . import dosep
1121        dosep.main(
1122            configuration.num_threads,
1123            configuration.multiprocess_test_subdir,
1124            configuration.test_runner_name,
1125            configuration.results_formatter_object)
1126        raise Exception("should never get here")
1127    elif configuration.is_inferior_test_runner:
1128        # Shut off Ctrl-C processing in inferiors.  The parallel
1129        # test runner handles this more holistically.
1130        signal.signal(signal.SIGINT, signal.SIG_IGN)
1131
1132    setupSysPath()
1133
1134    #
1135    # If '-l' is specified, do not skip the long running tests.
1136    if not configuration.skip_long_running_test:
1137        os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
1138
1139    # For the time being, let's bracket the test runner within the
1140    # lldb.SBDebugger.Initialize()/Terminate() pair.
1141    import lldb
1142
1143    # Create a singleton SBDebugger in the lldb namespace.
1144    lldb.DBG = lldb.SBDebugger.Create()
1145
1146    if configuration.lldb_platform_name:
1147        print("Setting up remote platform '%s'" %
1148              (configuration.lldb_platform_name))
1149        lldb.remote_platform = lldb.SBPlatform(
1150            configuration.lldb_platform_name)
1151        if not lldb.remote_platform.IsValid():
1152            print(
1153                "error: unable to create the LLDB platform named '%s'." %
1154                (configuration.lldb_platform_name))
1155            exitTestSuite(1)
1156        if configuration.lldb_platform_url:
1157            # We must connect to a remote platform if a LLDB platform URL was
1158            # specified
1159            print(
1160                "Connecting to remote platform '%s' at '%s'..." %
1161                (configuration.lldb_platform_name, configuration.lldb_platform_url))
1162            platform_connect_options = lldb.SBPlatformConnectOptions(
1163                configuration.lldb_platform_url)
1164            err = lldb.remote_platform.ConnectRemote(platform_connect_options)
1165            if err.Success():
1166                print("Connected.")
1167            else:
1168                print("error: failed to connect to remote platform using URL '%s': %s" % (
1169                    configuration.lldb_platform_url, err))
1170                exitTestSuite(1)
1171        else:
1172            configuration.lldb_platform_url = None
1173
1174    platform_changes = setDefaultTripleForPlatform()
1175    first = True
1176    for key in platform_changes:
1177        if first:
1178            print("Environment variables setup for platform support:")
1179            first = False
1180        print("%s = %s" % (key, platform_changes[key]))
1181
1182    if configuration.lldb_platform_working_dir:
1183        print("Setting remote platform working directory to '%s'..." %
1184              (configuration.lldb_platform_working_dir))
1185        error = lldb.remote_platform.MakeDirectory(
1186            configuration.lldb_platform_working_dir, 448)  # 448 = 0o700
1187        if error.Fail():
1188            raise Exception("making remote directory '%s': %s" % (
1189                remote_test_dir, error))
1190
1191        if not lldb.remote_platform.SetWorkingDirectory(
1192                configuration.lldb_platform_working_dir):
1193            raise Exception("failed to set working directory '%s'" % remote_test_dir)
1194        lldb.DBG.SetSelectedPlatform(lldb.remote_platform)
1195    else:
1196        lldb.remote_platform = None
1197        configuration.lldb_platform_working_dir = None
1198        configuration.lldb_platform_url = None
1199
1200    # Set up the working directory.
1201    # Note that it's not dotest's job to clean this directory.
1202    import lldbsuite.test.lldbutil as lldbutil
1203    build_dir = configuration.test_build_dir
1204    lldbutil.mkdir_p(build_dir)
1205
1206    target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2]
1207
1208    checkLibcxxSupport()
1209
1210    # Don't do debugserver tests on everything except OS X.
1211    configuration.dont_do_debugserver_test = "linux" in target_platform or "freebsd" in target_platform or "windows" in target_platform
1212
1213    # Don't do lldb-server (llgs) tests on anything except Linux.
1214    configuration.dont_do_llgs_test = not ("linux" in target_platform)
1215
1216    #
1217    # Walk through the testdirs while collecting tests.
1218    #
1219    for testdir in configuration.testdirs:
1220        for (dirpath, dirnames, filenames) in os.walk(testdir):
1221            visit('Test', dirpath, filenames)
1222
1223    #
1224    # Now that we have loaded all the test cases, run the whole test suite.
1225    #
1226
1227    # Turn on lldb loggings if necessary.
1228    lldbLoggings()
1229
1230    # Disable default dynamic types for testing purposes
1231    disabledynamics()
1232
1233    # Install the control-c handler.
1234    unittest2.signals.installHandler()
1235
1236    # If sdir_name is not specified through the '-s sdir_name' option, get a
1237    # timestamp string and export it as LLDB_SESSION_DIR environment var.  This will
1238    # be used when/if we want to dump the session info of individual test cases
1239    # later on.
1240    #
1241    # See also TestBase.dumpSessionInfo() in lldbtest.py.
1242    import datetime
1243    # The windows platforms don't like ':' in the pathname.
1244    timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
1245    if not configuration.sdir_name:
1246        configuration.sdir_name = timestamp_started
1247    os.environ["LLDB_SESSION_DIRNAME"] = os.path.join(
1248        os.getcwd(), configuration.sdir_name)
1249
1250    sys.stderr.write(
1251        "\nSession logs for test failures/errors/unexpected successes"
1252        " will go into directory '%s'\n" %
1253        configuration.sdir_name)
1254    sys.stderr.write("Command invoked: %s\n" % getMyCommandLine())
1255
1256    if not os.path.isdir(configuration.sdir_name):
1257        try:
1258            os.mkdir(configuration.sdir_name)
1259        except OSError as exception:
1260            if exception.errno != errno.EEXIST:
1261                raise
1262
1263    #
1264    # Invoke the default TextTestRunner to run the test suite
1265    #
1266    checkCompiler()
1267
1268    if not configuration.parsable:
1269        print("compiler=%s" % configuration.compiler)
1270
1271    # Iterating over all possible architecture and compiler combinations.
1272    os.environ["ARCH"] = configuration.arch
1273    os.environ["CC"] = configuration.compiler
1274    configString = "arch=%s compiler=%s" % (configuration.arch,
1275                                            configuration.compiler)
1276
1277    # Translate ' ' to '-' for pathname component.
1278    if six.PY2:
1279        import string
1280        tbl = string.maketrans(' ', '-')
1281    else:
1282        tbl = str.maketrans(' ', '-')
1283    configPostfix = configString.translate(tbl)
1284
1285    # Output the configuration.
1286    if not configuration.parsable:
1287        sys.stderr.write("\nConfiguration: " + configString + "\n")
1288
1289    # First, write out the number of collected test cases.
1290    if not configuration.parsable:
1291        sys.stderr.write(configuration.separator + "\n")
1292        sys.stderr.write(
1293            "Collected %d test%s\n\n" %
1294            (configuration.suite.countTestCases(),
1295             configuration.suite.countTestCases() != 1 and "s" or ""))
1296
1297    if configuration.parsable:
1298        v = 0
1299    else:
1300        v = configuration.verbose
1301
1302    # Invoke the test runner.
1303    if configuration.count == 1:
1304        result = unittest2.TextTestRunner(
1305            stream=sys.stderr,
1306            verbosity=v,
1307            resultclass=test_result.LLDBTestResult).run(
1308            configuration.suite)
1309    else:
1310        # We are invoking the same test suite more than once.  In this case,
1311        # mark __ignore_singleton__ flag as True so the signleton pattern is
1312        # not enforced.
1313        test_result.LLDBTestResult.__ignore_singleton__ = True
1314        for i in range(configuration.count):
1315
1316            result = unittest2.TextTestRunner(
1317                stream=sys.stderr,
1318                verbosity=v,
1319                resultclass=test_result.LLDBTestResult).run(
1320                configuration.suite)
1321
1322    configuration.failed = not result.wasSuccessful()
1323
1324    if configuration.sdir_has_content and not configuration.parsable:
1325        sys.stderr.write(
1326            "Session logs for test failures/errors/unexpected successes"
1327            " can be found in directory '%s'\n" %
1328            configuration.sdir_name)
1329
1330    if configuration.useCategories and len(
1331            configuration.failuresPerCategory) > 0:
1332        sys.stderr.write("Failures per category:\n")
1333        for category in configuration.failuresPerCategory:
1334            sys.stderr.write(
1335                "%s - %d\n" %
1336                (category, configuration.failuresPerCategory[category]))
1337
1338    # Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
1339    # This should not be necessary now.
1340    if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
1341        print("Terminating Test suite...")
1342        subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
1343
1344    # Exiting.
1345    exitTestSuite(configuration.failed)
1346
1347if __name__ == "__main__":
1348    print(
1349        __file__ +
1350        " is for use as a module only.  It should not be run as a standalone script.")
1351    sys.exit(-1)
1352