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