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