blob: 13948edfcfca9ad268e60324fd659748a4fb91a3 [file] [log] [blame]
Zachary Turnerc432c8f2015-10-28 17:43:26 +00001"""
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
Zachary Turnerc1b7cd72015-11-05 19:22:28 +000021from __future__ import absolute_import
Zachary Turnerc432c8f2015-10-28 17:43:26 +000022from __future__ import print_function
Zachary Turnerc1b7cd72015-11-05 19:22:28 +000023
24# System modules
Zachary Turner19474e12015-11-03 19:20:39 +000025import sys
Zachary Turnerc432c8f2015-10-28 17:43:26 +000026import atexit
Zachary Turnerc432c8f2015-10-28 17:43:26 +000027import importlib
28import os
Zachary Turnerc432c8f2015-10-28 17:43:26 +000029import errno
30import platform
31import progress
32import signal
33import socket
34import subprocess
35import sys
Zachary Turnerc432c8f2015-10-28 17:43:26 +000036import inspect
Zachary Turnerc432c8f2015-10-28 17:43:26 +000037
Zachary Turnerc1b7cd72015-11-05 19:22:28 +000038# Third-party modules
Zachary Turnerc432c8f2015-10-28 17:43:26 +000039import six
Zachary Turnerc1b7cd72015-11-05 19:22:28 +000040import unittest2
41
42# LLDB Modules
43import lldbsuite
44from . import dotest_args
45from . import lldbtest_config
46from . import test_categories
47from . import test_results
48from .test_results import EventBuilder
49from ..support import seven
Zachary Turnerc432c8f2015-10-28 17:43:26 +000050
51def is_exe(fpath):
52 """Returns true if fpath is an executable."""
53 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
54
55def which(program):
56 """Returns the full path to a program; None otherwise."""
57 fpath, fname = os.path.split(program)
58 if fpath:
59 if is_exe(program):
60 return program
61 else:
62 for path in os.environ["PATH"].split(os.pathsep):
63 exe_file = os.path.join(path, program)
64 if is_exe(exe_file):
65 return exe_file
66 return None
67
68class _WritelnDecorator(object):
69 """Used to decorate file-like objects with a handy 'writeln' method"""
70 def __init__(self,stream):
71 self.stream = stream
72
73 def __getattr__(self, attr):
74 if attr in ('stream', '__getstate__'):
75 raise AttributeError(attr)
76 return getattr(self.stream,attr)
77
78 def writeln(self, arg=None):
79 if arg:
80 self.write(arg)
81 self.write('\n') # text-mode streams translate to \r\n if needed
82
83#
84# Global variables:
85#
86
87# The test suite.
88suite = unittest2.TestSuite()
89
90# By default, benchmarks tests are not run.
91just_do_benchmarks_test = False
92
93dont_do_dsym_test = False
94dont_do_dwarf_test = False
95dont_do_dwo_test = False
96
97# The blacklist is optional (-b blacklistFile) and allows a central place to skip
98# testclass's and/or testclass.testmethod's.
99blacklist = None
100
101# The dictionary as a result of sourcing blacklistFile.
102blacklistConfig = {}
103
104# The list of categories we said we care about
105categoriesList = None
106# set to true if we are going to use categories for cherry-picking test cases
107useCategories = False
108# Categories we want to skip
109skipCategories = []
110# use this to track per-category failures
111failuresPerCategory = {}
112
113# The path to LLDB.framework is optional.
114lldbFrameworkPath = None
115
116# The config file is optional.
117configFile = None
118
119# Test suite repeat count. Can be overwritten with '-# count'.
120count = 1
121
122# The dictionary as a result of sourcing configFile.
123config = {}
124# The pre_flight and post_flight functions come from reading a config file.
125pre_flight = None
126post_flight = None
127# So do the lldbtest_remote_sandbox and lldbtest_remote_shell_template variables.
128lldbtest_remote_sandbox = None
129lldbtest_remote_shell_template = None
130
131# The 'archs' and 'compilers' can be specified via either command line or configFile,
132# with the command line overriding the configFile. The corresponding options can be
133# specified more than once. For example, "-A x86_64 -A i386" => archs=['x86_64', 'i386']
134# and "-C gcc -C clang" => compilers=['gcc', 'clang'].
135archs = None # Must be initialized after option parsing
136compilers = None # Must be initialized after option parsing
137
138# The arch might dictate some specific CFLAGS to be passed to the toolchain to build
139# the inferior programs. The global variable cflags_extras provides a hook to do
140# just that.
141cflags_extras = ''
142
143# Dump the Python sys.path variable. Use '-D' to dump sys.path.
144dumpSysPath = False
145
146# Full path of the benchmark executable, as specified by the '-e' option.
147bmExecutable = None
148# The breakpoint specification of bmExecutable, as specified by the '-x' option.
149bmBreakpointSpec = None
150# The benchmark iteration count, as specified by the '-y' option.
151bmIterationCount = -1
152
153# By default, don't exclude any directories. Use '-X' to add one excluded directory.
154excluded = set(['.svn', '.git'])
155
156# By default, failfast is False. Use '-F' to overwrite it.
157failfast = False
158
159# The filters (testclass.testmethod) used to admit tests into our test suite.
160filters = []
161
162# The runhooks is a list of lldb commands specifically for the debugger.
163# Use '-k' to specify a runhook.
164runHooks = []
165
166# If '-g' is specified, the filterspec is not exclusive. If a test module does
167# not contain testclass.testmethod which matches the filterspec, the whole test
168# module is still admitted into our test suite. fs4all flag defaults to True.
169fs4all = True
170
171# Ignore the build search path relative to this script to locate the lldb.py module.
172ignore = False
173
174# By default, we do not skip build and cleanup. Use '-S' option to override.
175skip_build_and_cleanup = False
176
177# By default, we skip long running test case. Use '-l' option to override.
178skip_long_running_test = True
179
180# By default, we print the build dir, lldb version, and svn info. Use '-n' option to
181# turn it off.
182noHeaders = False
183
184# Parsable mode silences headers, and any other output this script might generate, and instead
185# prints machine-readable output similar to what clang tests produce.
186parsable = False
187
188# The regular expression pattern to match against eligible filenames as our test cases.
189regexp = None
190
191# By default, tests are executed in place and cleanups are performed afterwards.
192# Use '-r dir' option to relocate the tests and their intermediate files to a
193# different directory and to forgo any cleanups. The directory specified must
194# not exist yet.
195rdir = None
196
197# By default, recorded session info for errored/failed test are dumped into its
198# own file under a session directory named after the timestamp of the test suite
199# run. Use '-s session-dir-name' to specify a specific dir name.
200sdir_name = None
201
202# Set this flag if there is any session info dumped during the test run.
203sdir_has_content = False
204
205# svn_info stores the output from 'svn info lldb.base.dir'.
206svn_info = ''
207
208# svn_silent means do not try to obtain svn status
209svn_silent = True
210
211# Default verbosity is 0.
212verbose = 1
213
214# Set to True only if verbose is 0 and LLDB trace mode is off.
215progress_bar = False
216
217# By default, search from the script directory.
218# We can't use sys.path[0] to determine the script directory
219# because it doesn't work under a debugger
220testdirs = [ os.path.dirname(os.path.realpath(__file__)) ]
221
222# Separator string.
223separator = '-' * 70
224
225failed = False
226
227# LLDB Remote platform setting
228lldb_platform_name = None
229lldb_platform_url = None
230lldb_platform_working_dir = None
231
232# Parallel execution settings
233is_inferior_test_runner = False
234multiprocess_test_subdir = None
235num_threads = None
236output_on_success = False
237no_multiprocess_test_runner = False
238test_runner_name = None
239
240# Test results handling globals
241results_filename = None
242results_port = None
243results_file_object = None
244results_formatter_name = None
245results_formatter_object = None
246results_formatter_options = None
247
248# The names of all tests. Used to assert we don't have two tests with the same base name.
249all_tests = set()
250
251def usage(parser):
252 parser.print_help()
253 if verbose > 0:
254 print("""
255Examples:
256
257This is an example of using the -f option to pinpoint to a specific test class
258and test method to be run:
259
260$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command
261----------------------------------------------------------------------
262Collected 1 test
263
264test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
265Test 'frame variable this' when stopped on a class constructor. ... ok
266
267----------------------------------------------------------------------
268Ran 1 test in 1.396s
269
270OK
271
272And this is an example of using the -p option to run a single file (the filename
273matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
274
275$ ./dotest.py -v -p ObjC
276----------------------------------------------------------------------
277Collected 4 tests
278
279test_break_with_dsym (TestObjCMethods.FoundationTestCase)
280Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
281test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
282Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
283test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
284Lookup objective-c data types and evaluate expressions. ... ok
285test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
286Lookup objective-c data types and evaluate expressions. ... ok
287
288----------------------------------------------------------------------
289Ran 4 tests in 16.661s
290
291OK
292
293Running of this script also sets up the LLDB_TEST environment variable so that
294individual test cases can locate their supporting files correctly. The script
295tries to set up Python's search paths for modules by looking at the build tree
296relative to this script. See also the '-i' option in the following example.
297
298Finally, this is an example of using the lldb.py module distributed/installed by
299Xcode4 to run against the tests under the 'forward' directory, and with the '-w'
300option to add some delay between two tests. It uses ARCH=x86_64 to specify that
301as the architecture and CC=clang to specify the compiler used for the test run:
302
303$ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward
304
305Session logs for test failures/errors will go into directory '2010-11-11-13_56_16'
306----------------------------------------------------------------------
307Collected 2 tests
308
309test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
310Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
311test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
312Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
313
314----------------------------------------------------------------------
315Ran 2 tests in 5.659s
316
317OK
318
319The 'Session ...' verbiage is recently introduced (see also the '-s' option) to
320notify the directory containing the session logs for test failures or errors.
321In case there is any test failure/error, a similar message is appended at the
322end of the stderr output for your convenience.
323
324ENABLING LOGS FROM TESTS
325
326Option 1:
327
328Writing logs into different files per test case::
329
330This option is particularly useful when multiple dotest instances are created
331by dosep.py
332
333$ ./dotest.py --channel "lldb all"
334
335$ ./dotest.py --channel "lldb all" --channel "gdb-remote packets"
336
337These log files are written to:
338
339<session-dir>/<test-id>-host.log (logs from lldb host process)
340<session-dir>/<test-id>-server.log (logs from debugserver/lldb-server)
341<session-dir>/<test-id>-<test-result>.log (console logs)
342
343By default, logs from successful runs are deleted. Use the --log-success flag
344to create reference logs for debugging.
345
346$ ./dotest.py --log-success
347
348Option 2: (DEPRECATED)
349
350The following options can only enable logs from the host lldb process.
351Only categories from the "lldb" or "gdb-remote" channels can be enabled
352They also do not automatically enable logs in locally running debug servers.
353Also, logs from all test case are written into each log file
354
355o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
356 with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
357
358o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
359 'process.gdb-remote' subsystem with a default option of 'packets' if
360 GDB_REMOTE_LOG_OPTION is not defined.
361
362""")
363 sys.exit(0)
364
365
366def setCrashInfoHook_Mac(text):
367 import crashinfo
368 crashinfo.setCrashReporterDescription(text)
369
370# implement this in some suitable way for your platform, and then bind it
371# to setCrashInfoHook
372def setCrashInfoHook_NonMac(text):
373 pass
374
375setCrashInfoHook = None
376
377def deleteCrashInfoDylib(dylib_path):
378 try:
379 # Need to modify this to handle multiple tests running at the same time. If we move this
380 # to the test's real dir, all should be we run sequentially within a test directory.
381 # os.remove(dylib_path)
382 None
383 finally:
384 pass
385
386def setupCrashInfoHook():
387 global setCrashInfoHook
388 setCrashInfoHook = setCrashInfoHook_NonMac # safe default
389 if platform.system() == "Darwin":
Chaoren Lin18da38e2015-11-05 22:00:47 +0000390 from . import lock
Zachary Turnerc432c8f2015-10-28 17:43:26 +0000391 test_dir = os.environ['LLDB_TEST']
392 if not test_dir or not os.path.exists(test_dir):
393 return
394 dylib_lock = os.path.join(test_dir,"crashinfo.lock")
395 dylib_src = os.path.join(test_dir,"crashinfo.c")
396 dylib_dst = os.path.join(test_dir,"crashinfo.so")
397 try:
398 compile_lock = lock.Lock(dylib_lock)
399 compile_lock.acquire()
400 if not os.path.isfile(dylib_dst) or os.path.getmtime(dylib_dst) < os.path.getmtime(dylib_src):
401 # we need to compile
402 cmd = "SDKROOT= xcrun clang %s -o %s -framework Python -Xlinker -dylib -iframework /System/Library/Frameworks/ -Xlinker -F /System/Library/Frameworks/" % (dylib_src,dylib_dst)
403 if subprocess.call(cmd,shell=True) != 0 or not os.path.isfile(dylib_dst):
404 raise Exception('command failed: "{}"'.format(cmd))
405 finally:
406 compile_lock.release()
407 del compile_lock
408
409 setCrashInfoHook = setCrashInfoHook_Mac
410
411 else:
412 pass
413
414def shouldSkipBecauseOfCategories(test_categories):
415 global useCategories, categoriesList, skipCategories
416
417 if useCategories:
418 if len(test_categories) == 0 or len(categoriesList & set(test_categories)) == 0:
419 return True
420
421 for category in skipCategories:
422 if category in test_categories:
423 return True
424
425 return False
426
427def parseOptionsAndInitTestdirs():
428 """Initialize the list of directories containing our unittest scripts.
429
430 '-h/--help as the first option prints out usage info and exit the program.
431 """
432
433 global just_do_benchmarks_test
434 global dont_do_dsym_test
435 global dont_do_dwarf_test
436 global dont_do_dwo_test
437 global blacklist
438 global blacklistConfig
439 global categoriesList
440 global validCategories
441 global useCategories
442 global skipCategories
443 global lldbFrameworkPath
444 global configFile
445 global archs
446 global compilers
447 global count
448 global dumpSysPath
449 global bmExecutable
450 global bmBreakpointSpec
451 global bmIterationCount
452 global failfast
453 global filters
454 global fs4all
455 global ignore
456 global progress_bar
457 global runHooks
458 global skip_build_and_cleanup
459 global skip_long_running_test
460 global noHeaders
461 global parsable
462 global regexp
463 global rdir
464 global sdir_name
465 global svn_silent
466 global verbose
467 global testdirs
468 global lldb_platform_name
469 global lldb_platform_url
470 global lldb_platform_working_dir
471 global setCrashInfoHook
472 global is_inferior_test_runner
473 global multiprocess_test_subdir
474 global num_threads
475 global output_on_success
476 global no_multiprocess_test_runner
477 global test_runner_name
478 global results_filename
479 global results_formatter_name
480 global results_formatter_options
481 global results_port
482
483 do_help = False
484
485 platform_system = platform.system()
486 platform_machine = platform.machine()
487
488 parser = dotest_args.create_parser()
489 args = dotest_args.parse_args(parser, sys.argv[1:])
490
491 if args.unset_env_varnames:
492 for env_var in args.unset_env_varnames:
493 if env_var in os.environ:
494 # From Python Doc: When unsetenv() is supported, deletion of items in os.environ
495 # is automatically translated into a corresponding call to unsetenv().
496 del os.environ[env_var]
497 #os.unsetenv(env_var)
498
499 if args.set_env_vars:
500 for env_var in args.set_env_vars:
501 parts = env_var.split('=', 1)
502 if len(parts) == 1:
503 os.environ[parts[0]] = ""
504 else:
505 os.environ[parts[0]] = parts[1]
506
507 # only print the args if being verbose (and parsable is off)
508 if args.v and not args.q:
509 print(sys.argv)
510
511 if args.h:
512 do_help = True
513
514 if args.compilers:
515 compilers = args.compilers
516 else:
517 # Use a compiler appropriate appropriate for the Apple SDK if one was specified
518 if platform_system == 'Darwin' and args.apple_sdk:
Zachary Turnerbb03a462015-11-03 18:55:22 +0000519 compilers = [seven.get_command_output('xcrun -sdk "%s" -find clang 2> /dev/null' % (args.apple_sdk))]
Zachary Turnerc432c8f2015-10-28 17:43:26 +0000520 else:
521 # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first
522 candidateCompilers = ['clang-3.5', 'clang', 'gcc']
523 for candidate in candidateCompilers:
524 if which(candidate):
525 compilers = [candidate]
526 break
527
528 if args.channels:
529 lldbtest_config.channels = args.channels
530
531 if args.log_success:
532 lldbtest_config.log_success = args.log_success
533
534 # Set SDKROOT if we are using an Apple SDK
535 if platform_system == 'Darwin' and args.apple_sdk:
Zachary Turnerbb03a462015-11-03 18:55:22 +0000536 os.environ['SDKROOT'] = seven.get_command_output('xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % (args.apple_sdk))
Zachary Turnerc432c8f2015-10-28 17:43:26 +0000537
538 if args.archs:
539 archs = args.archs
540 for arch in archs:
541 if arch.startswith('arm') and platform_system == 'Darwin' and not args.apple_sdk:
Zachary Turnerbb03a462015-11-03 18:55:22 +0000542 os.environ['SDKROOT'] = seven.get_command_output('xcrun --sdk iphoneos.internal --show-sdk-path 2> /dev/null')
Zachary Turnerc432c8f2015-10-28 17:43:26 +0000543 if not os.path.exists(os.environ['SDKROOT']):
Zachary Turnerbb03a462015-11-03 18:55:22 +0000544 os.environ['SDKROOT'] = seven.get_command_output('xcrun --sdk iphoneos --show-sdk-path 2> /dev/null')
Zachary Turnerc432c8f2015-10-28 17:43:26 +0000545 else:
546 archs = [platform_machine]
547
548 if args.categoriesList:
549 categoriesList = set(test_categories.validate(args.categoriesList, False))
550 useCategories = True
551 else:
552 categoriesList = []
553
554 if args.skipCategories:
555 skipCategories = test_categories.validate(args.skipCategories, False)
556
557 if args.D:
558 dumpSysPath = True
559
560 if args.E:
561 cflags_extras = args.E
562 os.environ['CFLAGS_EXTRAS'] = cflags_extras
563
564 # argparse makes sure we have correct options
565 if args.N == 'dwarf':
566 dont_do_dwarf_test = True
567 elif args.N == 'dwo':
568 dont_do_dwo_test = True
569 elif args.N == 'dsym':
570 dont_do_dsym_test = True
571
572 if args.a or args.plus_a:
573 print("Options '-a' and '+a' have been deprecated. Please use the test category\n"
574 "functionality (-G pyapi, --skip-category pyapi) instead.")
575 sys.exit(1)
576
577 if args.m or args.plus_m:
578 print("Options '-m' and '+m' have been deprecated. Please use the test category\n"
579 "functionality (-G lldb-mi, --skip-category lldb-mi) instead.")
580 sys.exit(1)
581
582 if args.plus_b:
583 just_do_benchmarks_test = True
584
585 if args.b:
586 if args.b.startswith('-'):
587 usage(parser)
588 blacklistFile = args.b
589 if not os.path.isfile(blacklistFile):
590 print('Blacklist file:', blacklistFile, 'does not exist!')
591 usage(parser)
592 # Now read the blacklist contents and assign it to blacklist.
593 execfile(blacklistFile, globals(), blacklistConfig)
594 blacklist = blacklistConfig.get('blacklist')
595
596 if args.c:
597 if args.c.startswith('-'):
598 usage(parser)
599 configFile = args.c
600 if not os.path.isfile(configFile):
601 print('Config file:', configFile, 'does not exist!')
602 usage(parser)
603
604 if args.d:
605 sys.stdout.write("Suspending the process %d to wait for debugger to attach...\n" % os.getpid())
606 sys.stdout.flush()
607 os.kill(os.getpid(), signal.SIGSTOP)
608
609 if args.e:
610 if args.e.startswith('-'):
611 usage(parser)
612 bmExecutable = args.e
613 if not is_exe(bmExecutable):
614 usage(parser)
615
616 if args.F:
617 failfast = True
618
619 if args.f:
620 if any([x.startswith('-') for x in args.f]):
621 usage(parser)
622 filters.extend(args.f)
623 # Shut off multiprocessing mode when additional filters are specified.
624 # The rational is that the user is probably going after a very specific
625 # test and doesn't need a bunch of parallel test runners all looking for
626 # it in a frenzy. Also, '-v' now spits out all test run output even
627 # on success, so the standard recipe for redoing a failing test (with -v
628 # and a -f to filter to the specific test) now causes all test scanning
629 # (in parallel) to print results for do-nothing runs in a very distracting
630 # manner. If we really need filtered parallel runs in the future, consider
631 # adding a --no-output-on-success that prevents -v from setting
632 # output-on-success.
633 no_multiprocess_test_runner = True
634
635 if args.g:
636 fs4all = False
637
638 if args.i:
639 ignore = True
640
641 if args.k:
642 runHooks.extend(args.k)
643
644 if args.l:
645 skip_long_running_test = False
646
647 if args.framework:
648 lldbFrameworkPath = args.framework
649
650 if args.executable:
651 lldbtest_config.lldbExec = args.executable
652
653 if args.libcxx:
654 os.environ["LIBCXX_PATH"] = args.libcxx
655
656 if args.n:
657 noHeaders = True
658
659 if args.p:
660 if args.p.startswith('-'):
661 usage(parser)
662 regexp = args.p
663
664 if args.q:
665 noHeaders = True
666 parsable = True
667
668 if args.P and not args.v:
669 progress_bar = True
670 verbose = 0
671
672 if args.R:
673 if args.R.startswith('-'):
674 usage(parser)
675 rdir = os.path.abspath(args.R)
676 if os.path.exists(rdir):
677 import shutil
678 print('Removing tree:', rdir)
679 shutil.rmtree(rdir)
680
681 if args.r:
682 if args.r.startswith('-'):
683 usage(parser)
684 rdir = os.path.abspath(args.r)
685 if os.path.exists(rdir):
686 print('Relocated directory:', rdir, 'must not exist!')
687 usage(parser)
688
689 if args.S:
690 skip_build_and_cleanup = True
691
692 if args.s:
693 if args.s.startswith('-'):
694 usage(parser)
695 sdir_name = args.s
696
697 if args.t:
698 os.environ['LLDB_COMMAND_TRACE'] = 'YES'
699
700 if args.T:
701 svn_silent = False
702
703 if args.v:
704 verbose = 2
705
706 if args.w:
707 os.environ['LLDB_WAIT_BETWEEN_TEST_CASES'] = 'YES'
708
709 if args.X:
710 if args.X.startswith('-'):
711 usage(parser)
712 excluded.add(args.X)
713
714 if args.x:
715 if args.x.startswith('-'):
716 usage(parser)
717 bmBreakpointSpec = args.x
718
719 # argparse makes sure we have a number
720 if args.y:
721 bmIterationCount = args.y
722
723 # argparse makes sure we have a number
724 if args.sharp:
725 count = args.sharp
726
727 if sys.platform.startswith('win32'):
728 os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str(args.disable_crash_dialog)
729 os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(args.hide_inferior_console)
730
731 if do_help == True:
732 usage(parser)
733
734 if args.no_multiprocess:
735 no_multiprocess_test_runner = True
736
737 if args.inferior:
738 is_inferior_test_runner = True
739
740 # Turn on output_on_sucess if either explicitly added or -v specified.
741 if args.output_on_success or args.v:
742 output_on_success = True
743
744 if args.num_threads:
745 num_threads = args.num_threads
746
747 if args.test_subdir:
748 multiprocess_test_subdir = args.test_subdir
749
750 if args.test_runner_name:
751 test_runner_name = args.test_runner_name
752
753 # Capture test results-related args.
754 if args.results_file:
755 results_filename = args.results_file
756
757 if args.results_port:
758 results_port = args.results_port
759
760 if args.results_file and args.results_port:
761 sys.stderr.write(
762 "only one of --results-file and --results-port should "
763 "be specified\n")
764 usage(args)
765
766 if args.results_formatter:
767 results_formatter_name = args.results_formatter
768 if args.results_formatter_options:
769 results_formatter_options = args.results_formatter_options
770
771 if args.lldb_platform_name:
772 lldb_platform_name = args.lldb_platform_name
773 if args.lldb_platform_url:
774 lldb_platform_url = args.lldb_platform_url
775 if args.lldb_platform_working_dir:
776 lldb_platform_working_dir = args.lldb_platform_working_dir
777
778 if args.event_add_entries and len(args.event_add_entries) > 0:
779 entries = {}
780 # Parse out key=val pairs, separated by comma
781 for keyval in args.event_add_entries.split(","):
782 key_val_entry = keyval.split("=")
783 if len(key_val_entry) == 2:
784 (key, val) = key_val_entry
785 val_parts = val.split(':')
786 if len(val_parts) > 1:
787 (val, val_type) = val_parts
788 if val_type == 'int':
789 val = int(val)
790 entries[key] = val
791 # Tell the event builder to create all events with these
792 # key/val pairs in them.
793 if len(entries) > 0:
794 test_results.EventBuilder.add_entries_to_all_events(entries)
795
796 # Gather all the dirs passed on the command line.
797 if len(args.args) > 0:
798 testdirs = list(map(os.path.abspath, args.args))
799 # Shut off multiprocessing mode when test directories are specified.
800 no_multiprocess_test_runner = True
801
802 # If '-r dir' is specified, the tests should be run under the relocated
803 # directory. Let's copy the testdirs over.
804 if rdir:
805 from shutil import copytree, ignore_patterns
806
807 tmpdirs = []
808 orig_testdirs = testdirs[:]
809 for srcdir in testdirs:
810 # For example, /Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/hello_watchpoint
811 # shall be split into ['/Volumes/data/lldb/svn/ToT/', 'functionalities/watchpoint/hello_watchpoint'].
812 # Utilize the relative path to the 'test' directory to make our destination dir path.
813 if ("test" + os.sep) in srcdir:
814 to_split_on = "test" + os.sep
815 else:
816 to_split_on = "test"
817 dstdir = os.path.join(rdir, srcdir.split(to_split_on)[1])
818 dstdir = dstdir.rstrip(os.sep)
819 # Don't copy the *.pyc and .svn stuffs.
820 copytree(srcdir, dstdir, ignore=ignore_patterns('*.pyc', '.svn'))
821 tmpdirs.append(dstdir)
822
823 # This will be our modified testdirs.
824 testdirs = tmpdirs
825
826 # With '-r dir' specified, there's no cleanup of intermediate test files.
827 os.environ["LLDB_DO_CLEANUP"] = 'NO'
828
829 # If the original testdirs is ['test'], the make directory has already been copied
830 # recursively and is contained within the rdir/test dir. For anything
831 # else, we would need to copy over the make directory and its contents,
832 # so that, os.listdir(rdir) looks like, for example:
833 #
834 # array_types conditional_break make
835 #
836 # where the make directory contains the Makefile.rules file.
837 if len(testdirs) != 1 or os.path.basename(orig_testdirs[0]) != 'test':
838 scriptdir = os.path.dirname(__file__)
839 # Don't copy the .svn stuffs.
840 copytree(os.path.join(scriptdir, 'make'), os.path.join(rdir, 'make'),
841 ignore=ignore_patterns('.svn'))
842
843 #print("testdirs:", testdirs)
844
845 # Source the configFile if specified.
846 # The side effect, if any, will be felt from this point on. An example
847 # config file may be these simple two lines:
848 #
849 # sys.stderr = open("/tmp/lldbtest-stderr", "w")
850 # sys.stdout = open("/tmp/lldbtest-stdout", "w")
851 #
852 # which will reassign the two file objects to sys.stderr and sys.stdout,
853 # respectively.
854 #
855 # See also lldb-trunk/examples/test/usage-config.
856 global config, pre_flight, post_flight, lldbtest_remote_sandbox, lldbtest_remote_shell_template
857 if configFile:
858 # Pass config (a dictionary) as the locals namespace for side-effect.
859 execfile(configFile, globals(), config)
860 #print("config:", config)
861 if "pre_flight" in config:
862 pre_flight = config["pre_flight"]
863 if not six.callable(pre_flight):
864 print("fatal error: pre_flight is not callable, exiting.")
865 sys.exit(1)
866 if "post_flight" in config:
867 post_flight = config["post_flight"]
868 if not six.callable(post_flight):
869 print("fatal error: post_flight is not callable, exiting.")
870 sys.exit(1)
871 if "lldbtest_remote_sandbox" in config:
872 lldbtest_remote_sandbox = config["lldbtest_remote_sandbox"]
873 if "lldbtest_remote_shell_template" in config:
874 lldbtest_remote_shell_template = config["lldbtest_remote_shell_template"]
875 #print("sys.stderr:", sys.stderr)
876 #print("sys.stdout:", sys.stdout)
877
878def getXcodeOutputPaths(lldbRootDirectory):
879 result = []
880
881 # These are for xcode build directories.
882 xcode3_build_dir = ['build']
883 xcode4_build_dir = ['build', 'lldb', 'Build', 'Products']
884
885 configurations = [['Debug'], ['DebugClang'], ['Release'], ['BuildAndIntegration']]
886 xcode_build_dirs = [xcode3_build_dir, xcode4_build_dir]
887 for configuration in configurations:
888 for xcode_build_dir in xcode_build_dirs:
889 outputPath = os.path.join(lldbRootDirectory, *(xcode_build_dir+configuration) )
890 result.append(outputPath)
891
892 return result
893
894
895def createSocketToLocalPort(port):
896 def socket_closer(s):
897 """Close down an opened socket properly."""
898 s.shutdown(socket.SHUT_RDWR)
899 s.close()
900
901 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
902 sock.connect(("localhost", port))
903 return (sock, lambda: socket_closer(sock))
904
905
906def setupTestResults():
907 """Sets up test results-related objects based on arg settings."""
908 global results_filename
909 global results_file_object
910 global results_formatter_name
911 global results_formatter_object
912 global results_formatter_options
913 global results_port
914
915 default_formatter_name = None
916 cleanup_func = None
917
918 if results_filename:
919 # Open the results file for writing.
920 if results_filename == 'stdout':
921 results_file_object = sys.stdout
922 cleanup_func = None
923 elif results_filename == 'stderr':
924 results_file_object = sys.stderr
925 cleanup_func = None
926 else:
927 results_file_object = open(results_filename, "w")
928 cleanup_func = results_file_object.close
Todd Fialad8078ff2015-11-04 17:10:40 +0000929 default_formatter_name = "lldbsuite.test.test_results.XunitFormatter"
Zachary Turnerc432c8f2015-10-28 17:43:26 +0000930 elif results_port:
931 # Connect to the specified localhost port.
932 results_file_object, cleanup_func = createSocketToLocalPort(
933 results_port)
Todd Fialad8078ff2015-11-04 17:10:40 +0000934 default_formatter_name = "lldbsuite.test.test_results.RawPickledFormatter"
Zachary Turnerc432c8f2015-10-28 17:43:26 +0000935
936 if results_file_object:
937 # We care about the formatter. Choose user-specified or, if
938 # none specified, use the default for the output type.
939 if results_formatter_name:
940 formatter_name = results_formatter_name
941 else:
942 formatter_name = default_formatter_name
943
944 # Create an instance of the class. First figure out the package/module.
945 components = formatter_name.split(".")
946 module = importlib.import_module(".".join(components[:-1]))
947
948 # Create the class name we need to load.
949 clazz = getattr(module, components[-1])
950
951 # Handle formatter options for the results formatter class.
952 formatter_arg_parser = clazz.arg_parser()
953 if results_formatter_options and len(results_formatter_options) > 0:
954 command_line_options = results_formatter_options
955 else:
956 command_line_options = []
957
958 formatter_options = formatter_arg_parser.parse_args(
959 command_line_options)
960
961 # Create the TestResultsFormatter given the processed options.
962 results_formatter_object = clazz(results_file_object, formatter_options)
963
964 # Start the results formatter session - we'll only have one
965 # during a given dotest process invocation.
966 initialize_event = EventBuilder.bare_event("initialize")
967 if isMultiprocessTestRunner():
968 if test_runner_name is not None and test_runner_name == "serial":
969 # Only one worker queue here.
970 worker_count = 1
971 else:
972 # Workers will be the number of threads specified.
973 worker_count = num_threads
974 else:
975 worker_count = 1
976 initialize_event["worker_count"] = worker_count
977
978 results_formatter_object.handle_event(initialize_event)
979
980 def shutdown_formatter():
981 # Tell the formatter to write out anything it may have
982 # been saving until the very end (e.g. xUnit results
983 # can't complete its output until this point).
984 results_formatter_object.send_terminate_as_needed()
985
986 # And now close out the output file-like object.
987 if cleanup_func is not None:
988 cleanup_func()
989
990 atexit.register(shutdown_formatter)
991
992
993def getOutputPaths(lldbRootDirectory):
994 """
995 Returns typical build output paths for the lldb executable
996
997 lldbDirectory - path to the root of the lldb svn/git repo
998 """
999 result = []
1000
1001 if sys.platform == 'darwin':
1002 result.extend(getXcodeOutputPaths(lldbRootDirectory))
1003
1004 # cmake builds? look for build or build/host folder next to llvm directory
1005 # lldb is located in llvm/tools/lldb so we need to go up three levels
1006 llvmParentDir = os.path.abspath(os.path.join(lldbRootDirectory, os.pardir, os.pardir, os.pardir))
1007 result.append(os.path.join(llvmParentDir, 'build', 'bin'))
1008 result.append(os.path.join(llvmParentDir, 'build', 'host', 'bin'))
1009
1010 # some cmake developers keep their build directory beside their lldb directory
1011 lldbParentDir = os.path.abspath(os.path.join(lldbRootDirectory, os.pardir))
1012 result.append(os.path.join(lldbParentDir, 'build', 'bin'))
1013 result.append(os.path.join(lldbParentDir, 'build', 'host', 'bin'))
1014
1015 return result
1016
1017def setupSysPath():
1018 """
1019 Add LLDB.framework/Resources/Python to the search paths for modules.
1020 As a side effect, we also discover the 'lldb' executable and export it here.
1021 """
1022
1023 global rdir
1024 global testdirs
1025 global dumpSysPath
1026 global noHeaders
1027 global svn_info
1028 global svn_silent
1029 global lldbFrameworkPath
1030
1031 # Get the directory containing the current script.
1032 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ:
1033 scriptPath = os.environ["DOTEST_SCRIPT_DIR"]
1034 else:
1035 scriptPath = os.path.dirname(os.path.realpath(__file__))
1036 if not scriptPath.endswith('test'):
1037 print("This script expects to reside in lldb's test directory.")
1038 sys.exit(-1)
1039
1040 if rdir:
1041 # Set up the LLDB_TEST environment variable appropriately, so that the
1042 # individual tests can be located relatively.
1043 #
1044 # See also lldbtest.TestBase.setUpClass(cls).
1045 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
1046 os.environ["LLDB_TEST"] = os.path.join(rdir, 'test')
1047 else:
1048 os.environ["LLDB_TEST"] = rdir
1049 else:
1050 os.environ["LLDB_TEST"] = scriptPath
1051
1052 # Set up the LLDB_SRC environment variable, so that the tests can locate
1053 # the LLDB source code.
1054 os.environ["LLDB_SRC"] = lldbsuite.lldb_root
1055
1056 pluginPath = os.path.join(scriptPath, 'plugins')
1057 toolsLLDBMIPath = os.path.join(scriptPath, 'tools', 'lldb-mi')
1058 toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server')
1059
1060 # Insert script dir, plugin dir, lldb-mi dir and lldb-server dir to the sys.path.
Zachary Turnerc432c8f2015-10-28 17:43:26 +00001061 sys.path.insert(0, pluginPath)
1062 sys.path.insert(0, toolsLLDBMIPath) # Adding test/tools/lldb-mi to the path makes it easy
1063 # to "import lldbmi_testcase" from the MI tests
1064 sys.path.insert(0, toolsLLDBServerPath) # Adding test/tools/lldb-server to the path makes it easy
1065 # to "import lldbgdbserverutils" from the lldb-server tests
1066
1067 # This is the root of the lldb git/svn checkout
1068 # When this changes over to a package instead of a standalone script, this
1069 # will be `lldbsuite.lldb_root`
1070 lldbRootDirectory = lldbsuite.lldb_root
1071
1072 # Some of the tests can invoke the 'lldb' command directly.
1073 # We'll try to locate the appropriate executable right here.
1074
1075 # The lldb executable can be set from the command line
1076 # if it's not set, we try to find it now
1077 # first, we try the environment
1078 if not lldbtest_config.lldbExec:
1079 # First, you can define an environment variable LLDB_EXEC specifying the
1080 # full pathname of the lldb executable.
1081 if "LLDB_EXEC" in os.environ:
1082 lldbtest_config.lldbExec = os.environ["LLDB_EXEC"]
1083
1084 if not lldbtest_config.lldbExec:
1085 outputPaths = getOutputPaths(lldbRootDirectory)
1086 for outputPath in outputPaths:
1087 candidatePath = os.path.join(outputPath, 'lldb')
1088 if is_exe(candidatePath):
1089 lldbtest_config.lldbExec = candidatePath
1090 break
1091
1092 if not lldbtest_config.lldbExec:
1093 # Last, check the path
1094 lldbtest_config.lldbExec = which('lldb')
1095
1096 if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec):
1097 print("'{}' is not a path to a valid executable".format(lldbtest_config.lldbExec))
1098 lldbtest_config.lldbExec = None
1099
1100 if not lldbtest_config.lldbExec:
1101 print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.")
1102 sys.exit(-1)
1103
1104 lldbLibDir = os.path.dirname(lldbtest_config.lldbExec) # confusingly, this is the "bin" directory
1105 os.environ["LLDB_LIB_DIR"] = lldbLibDir
1106 lldbImpLibDir = os.path.join(lldbLibDir, '..', 'lib') if sys.platform.startswith('win32') else lldbLibDir
1107 os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir
1108 if not noHeaders:
1109 print("LLDB library dir:", os.environ["LLDB_LIB_DIR"])
1110 print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"])
1111 os.system('%s -v' % lldbtest_config.lldbExec)
1112
1113 # Assume lldb-mi is in same place as lldb
1114 # If not found, disable the lldb-mi tests
1115 lldbMiExec = None
1116 if lldbtest_config.lldbExec and is_exe(lldbtest_config.lldbExec + "-mi"):
1117 lldbMiExec = lldbtest_config.lldbExec + "-mi"
1118 if not lldbMiExec:
1119 if not shouldSkipBecauseOfCategories(["lldb-mi"]):
1120 print("The 'lldb-mi' executable cannot be located. The lldb-mi tests can not be run as a result.")
1121 skipCategories.append("lldb-mi")
1122 else:
1123 os.environ["LLDBMI_EXEC"] = lldbMiExec
1124
1125 # Skip printing svn/git information when running in parsable (lit-test compatibility) mode
1126 if not svn_silent and not parsable:
1127 if os.path.isdir(os.path.join(lldbRootDirectory, '.svn')) and which("svn") is not None:
1128 pipe = subprocess.Popen([which("svn"), "info", lldbRootDirectory], stdout = subprocess.PIPE)
1129 svn_info = pipe.stdout.read()
1130 elif os.path.isdir(os.path.join(lldbRootDirectory, '.git')) and which("git") is not None:
1131 pipe = subprocess.Popen([which("git"), "svn", "info", lldbRootDirectory], stdout = subprocess.PIPE)
1132 svn_info = pipe.stdout.read()
1133 if not noHeaders:
1134 print(svn_info)
1135
1136 global ignore
1137
1138 lldbPythonDir = None # The directory that contains 'lldb/__init__.py'
1139 if lldbFrameworkPath:
1140 candidatePath = os.path.join(lldbFrameworkPath, 'Resources', 'Python')
1141 if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')):
1142 lldbPythonDir = candidatePath
1143 if not lldbPythonDir:
1144 print('Resources/Python/lldb/__init__.py was not found in ' + lldbFrameworkPath)
1145 sys.exit(-1)
1146 else:
1147 # The '-i' option is used to skip looking for lldb.py in the build tree.
1148 if ignore:
1149 return
1150
1151 # If our lldb supports the -P option, use it to find the python path:
1152 init_in_python_dir = os.path.join('lldb', '__init__.py')
1153
Zachary Turnerbbc5b462015-11-04 01:03:47 +00001154 lldb_dash_p_result = subprocess.check_output([lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True)
Zachary Turnerc432c8f2015-10-28 17:43:26 +00001155
1156 if lldb_dash_p_result and not lldb_dash_p_result.startswith(("<", "lldb: invalid option:")) \
1157 and not lldb_dash_p_result.startswith("Traceback"):
1158 lines = lldb_dash_p_result.splitlines()
1159
1160 # Workaround for readline vs libedit issue on FreeBSD. If stdout
1161 # is not a terminal Python executes
1162 # rl_variable_bind ("enable-meta-key", "off");
1163 # This produces a warning with FreeBSD's libedit because the
1164 # enable-meta-key variable is unknown. Not an issue on Apple
1165 # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__
1166 # around the call. See http://bugs.python.org/issue19884 for more
1167 # information. For now we just discard the warning output.
1168 if len(lines) >= 1 and lines[0].startswith("bind: Invalid command"):
1169 lines.pop(0)
1170
1171 # Taking the last line because lldb outputs
1172 # 'Cannot read termcap database;\nusing dumb terminal settings.\n'
1173 # before the path
1174 if len(lines) >= 1 and os.path.isfile(os.path.join(lines[-1], init_in_python_dir)):
1175 lldbPythonDir = lines[-1]
1176 if "freebsd" in sys.platform or "linux" in sys.platform:
1177 os.environ['LLDB_LIB_DIR'] = os.path.join(lldbPythonDir, '..', '..')
1178
1179 if not lldbPythonDir:
1180 if platform.system() == "Darwin":
1181 python_resource_dir = ['LLDB.framework', 'Resources', 'Python']
1182 outputPaths = getXcodeOutputPaths()
1183 for outputPath in outputPaths:
1184 candidatePath = os.path.join(outputPath, python_resource_dir)
1185 if os.path.isfile(os.path.join(candidatePath, init_in_python_dir)):
1186 lldbPythonDir = candidatePath
1187 break
1188
1189 if not lldbPythonDir:
1190 print('This script requires lldb.py to be in either ' + dbgPath + ',', end=' ')
1191 print(relPath + ', or ' + baiPath + '. Some tests might fail.')
1192 else:
1193 print("Unable to load lldb extension module. Possible reasons for this include:")
1194 print(" 1) LLDB was built with LLDB_DISABLE_PYTHON=1")
1195 print(" 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to")
1196 print(" the version of Python that LLDB built and linked against, and PYTHONPATH")
1197 print(" should contain the Lib directory for the same python distro, as well as the")
1198 print(" location of LLDB\'s site-packages folder.")
1199 print(" 3) A different version of Python than that which was built against is exported in")
1200 print(" the system\'s PATH environment variable, causing conflicts.")
1201 print(" 4) The executable '%s' could not be found. Please check " % lldbExecutable)
1202 print(" that it exists and is executable.")
1203
1204 if lldbPythonDir:
1205 lldbPythonDir = os.path.normpath(lldbPythonDir)
1206 # Some of the code that uses this path assumes it hasn't resolved the Versions... link.
1207 # If the path we've constructed looks like that, then we'll strip out the Versions/A part.
1208 (before, frameWithVersion, after) = lldbPythonDir.rpartition("LLDB.framework/Versions/A")
1209 if frameWithVersion != "" :
1210 lldbPythonDir = before + "LLDB.framework" + after
1211
1212 lldbPythonDir = os.path.abspath(lldbPythonDir)
1213
1214 # If tests need to find LLDB_FRAMEWORK, now they can do it
1215 os.environ["LLDB_FRAMEWORK"] = os.path.dirname(os.path.dirname(lldbPythonDir))
1216
1217 # This is to locate the lldb.py module. Insert it right after sys.path[0].
1218 sys.path[1:1] = [lldbPythonDir]
1219 if dumpSysPath:
1220 print("sys.path:", sys.path)
1221
1222def visit(prefix, dir, names):
1223 """Visitor function for os.path.walk(path, visit, arg)."""
1224
1225 global suite
1226 global regexp
1227 global filters
1228 global fs4all
1229 global excluded
1230 global all_tests
1231
1232 if set(dir.split(os.sep)).intersection(excluded):
1233 #print("Detected an excluded dir component: %s" % dir)
1234 return
1235
1236 for name in names:
Zachary Turnerc432c8f2015-10-28 17:43:26 +00001237 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
1238
1239 if name in all_tests:
1240 raise Exception("Found multiple tests with the name %s" % name)
1241 all_tests.add(name)
1242
1243 # Try to match the regexp pattern, if specified.
1244 if regexp:
1245 import re
1246 if re.search(regexp, name):
1247 #print("Filename: '%s' matches pattern: '%s'" % (name, regexp))
1248 pass
1249 else:
1250 #print("Filename: '%s' does not match pattern: '%s'" % (name, regexp))
1251 continue
1252
1253 # We found a match for our test. Add it to the suite.
1254
1255 # Update the sys.path first.
1256 if not sys.path.count(dir):
1257 sys.path.insert(0, dir)
1258 base = os.path.splitext(name)[0]
1259
1260 # Thoroughly check the filterspec against the base module and admit
1261 # the (base, filterspec) combination only when it makes sense.
1262 filterspec = None
1263 for filterspec in filters:
1264 # Optimistically set the flag to True.
1265 filtered = True
1266 module = __import__(base)
1267 parts = filterspec.split('.')
1268 obj = module
1269 for part in parts:
1270 try:
1271 parent, obj = obj, getattr(obj, part)
1272 except AttributeError:
1273 # The filterspec has failed.
1274 filtered = False
1275 break
1276
1277 # If filtered, we have a good filterspec. Add it.
1278 if filtered:
1279 #print("adding filter spec %s to module %s" % (filterspec, module))
1280 suite.addTests(
1281 unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
1282 continue
1283
1284 # Forgo this module if the (base, filterspec) combo is invalid
1285 # and no '-g' option is specified
1286 if filters and fs4all and not filtered:
1287 continue
1288
1289 # Add either the filtered test case(s) (which is done before) or the entire test class.
1290 if not filterspec or not filtered:
1291 # A simple case of just the module name. Also the failover case
1292 # from the filterspec branch when the (base, filterspec) combo
1293 # doesn't make sense.
1294 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
1295
1296
1297def disabledynamics():
1298 import lldb
1299 ci = lldb.DBG.GetCommandInterpreter()
1300 res = lldb.SBCommandReturnObject()
1301 ci.HandleCommand("setting set target.prefer-dynamic-value no-dynamic-values", res, False)
1302 if not res.Succeeded():
1303 raise Exception('disabling dynamic type support failed')
1304
1305def lldbLoggings():
1306 import lldb
1307 """Check and do lldb loggings if necessary."""
1308
1309 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
1310 # defined. Use ${LLDB_LOG} to specify the log file.
1311 ci = lldb.DBG.GetCommandInterpreter()
1312 res = lldb.SBCommandReturnObject()
1313 if ("LLDB_LOG" in os.environ):
1314 open(os.environ["LLDB_LOG"], 'w').close()
1315 if ("LLDB_LOG_OPTION" in os.environ):
1316 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
1317 else:
1318 lldb_log_option = "event process expr state api"
1319 ci.HandleCommand(
1320 "log enable -n -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
1321 res)
1322 if not res.Succeeded():
1323 raise Exception('log enable failed (check LLDB_LOG env variable)')
1324
1325 if ("LLDB_LINUX_LOG" in os.environ):
1326 open(os.environ["LLDB_LINUX_LOG"], 'w').close()
1327 if ("LLDB_LINUX_LOG_OPTION" in os.environ):
1328 lldb_log_option = os.environ["LLDB_LINUX_LOG_OPTION"]
1329 else:
1330 lldb_log_option = "event process expr state api"
1331 ci.HandleCommand(
1332 "log enable -n -f " + os.environ["LLDB_LINUX_LOG"] + " linux " + lldb_log_option,
1333 res)
1334 if not res.Succeeded():
1335 raise Exception('log enable failed (check LLDB_LINUX_LOG env variable)')
1336
1337 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
1338 # Use ${GDB_REMOTE_LOG} to specify the log file.
1339 if ("GDB_REMOTE_LOG" in os.environ):
1340 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
1341 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
1342 else:
1343 gdb_remote_log_option = "packets process"
1344 ci.HandleCommand(
1345 "log enable -n -f " + os.environ["GDB_REMOTE_LOG"] + " gdb-remote "
1346 + gdb_remote_log_option,
1347 res)
1348 if not res.Succeeded():
1349 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable)')
1350
1351def getMyCommandLine():
1352 return ' '.join(sys.argv)
1353
1354# ======================================== #
1355# #
1356# Execution of the test driver starts here #
1357# #
1358# ======================================== #
1359
1360def checkDsymForUUIDIsNotOn():
1361 cmd = ["defaults", "read", "com.apple.DebugSymbols"]
1362 pipe = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
1363 cmd_output = pipe.stdout.read()
1364 if cmd_output and "DBGFileMappedPaths = " in cmd_output:
1365 print("%s =>" % ' '.join(cmd))
1366 print(cmd_output)
1367 print("Disable automatic lookup and caching of dSYMs before running the test suite!")
1368 print("Exiting...")
1369 sys.exit(0)
1370
1371def exitTestSuite(exitCode = None):
1372 import lldb
1373 lldb.SBDebugger.Terminate()
1374 if exitCode:
1375 sys.exit(exitCode)
1376
1377
1378def isMultiprocessTestRunner():
1379 # We're not multiprocess when we're either explicitly
1380 # the inferior (as specified by the multiprocess test
1381 # runner) OR we've been told to skip using the multiprocess
1382 # test runner
1383 return not (is_inferior_test_runner or no_multiprocess_test_runner)
1384
Enrico Granata5f92a132015-11-05 00:46:25 +00001385def getVersionForSDK(sdk):
1386 sdk = str.lower(sdk)
1387 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk)
1388 basename = os.path.basename(full_path)
1389 basename = os.path.splitext(basename)[0]
1390 basename = str.lower(basename)
1391 ver = basename.replace(sdk, '')
1392 return ver
1393
1394def getPathForSDK(sdk):
1395 sdk = str.lower(sdk)
1396 full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk)
1397 if os.path.exists(full_path): return full_path
1398 return None
1399
1400def setDefaultTripleForPlatform():
1401 if lldb_platform_name == 'ios-simulator':
1402 triple_str = 'x86_64-apple-ios%s' % (getVersionForSDK('iphonesimulator'))
1403 os.environ['TRIPLE'] = triple_str
1404 return {'TRIPLE':triple_str}
1405 return {}
1406
Zachary Turnerc432c8f2015-10-28 17:43:26 +00001407def run_suite():
1408 global just_do_benchmarks_test
1409 global dont_do_dsym_test
1410 global dont_do_dwarf_test
1411 global dont_do_dwo_test
1412 global blacklist
1413 global blacklistConfig
1414 global categoriesList
1415 global validCategories
1416 global useCategories
1417 global skipCategories
1418 global lldbFrameworkPath
1419 global configFile
1420 global archs
1421 global compilers
1422 global count
1423 global dumpSysPath
1424 global bmExecutable
1425 global bmBreakpointSpec
1426 global bmIterationCount
1427 global failed
1428 global failfast
1429 global filters
1430 global fs4all
1431 global ignore
1432 global progress_bar
1433 global runHooks
1434 global skip_build_and_cleanup
1435 global skip_long_running_test
1436 global noHeaders
1437 global parsable
1438 global regexp
1439 global rdir
1440 global sdir_name
1441 global svn_silent
1442 global verbose
1443 global testdirs
1444 global lldb_platform_name
1445 global lldb_platform_url
1446 global lldb_platform_working_dir
1447 global setCrashInfoHook
1448 global is_inferior_test_runner
1449 global multiprocess_test_subdir
1450 global num_threads
1451 global output_on_success
1452 global no_multiprocess_test_runner
1453 global test_runner_name
1454 global results_filename
1455 global results_formatter_name
1456 global results_formatter_options
1457 global results_port
1458
1459 # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults
1460 # does not exist before proceeding to running the test suite.
1461 if sys.platform.startswith("darwin"):
1462 checkDsymForUUIDIsNotOn()
1463
1464 #
1465 # Start the actions by first parsing the options while setting up the test
1466 # directories, followed by setting up the search paths for lldb utilities;
1467 # then, we walk the directory trees and collect the tests into our test suite.
1468 #
1469 parseOptionsAndInitTestdirs()
1470
1471 # Setup test results (test results formatter and output handling).
1472 setupTestResults()
1473
1474 # If we are running as the multiprocess test runner, kick off the
1475 # multiprocess test runner here.
1476 if isMultiprocessTestRunner():
Zachary Turnerc1b7cd72015-11-05 19:22:28 +00001477 from . import dosep
Zachary Turnerc432c8f2015-10-28 17:43:26 +00001478 dosep.main(output_on_success, num_threads, multiprocess_test_subdir,
1479 test_runner_name, results_formatter_object)
1480 raise Exception("should never get here")
1481 elif is_inferior_test_runner:
1482 # Shut off Ctrl-C processing in inferiors. The parallel
1483 # test runner handles this more holistically.
1484 signal.signal(signal.SIGINT, signal.SIG_IGN)
1485
1486 setupSysPath()
1487 setupCrashInfoHook()
1488
1489 #
1490 # If '-l' is specified, do not skip the long running tests.
1491 if not skip_long_running_test:
1492 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
1493
1494 # For the time being, let's bracket the test runner within the
1495 # lldb.SBDebugger.Initialize()/Terminate() pair.
1496 import lldb
1497
1498 # Create a singleton SBDebugger in the lldb namespace.
1499 lldb.DBG = lldb.SBDebugger.Create()
1500
1501 if lldb_platform_name:
1502 print("Setting up remote platform '%s'" % (lldb_platform_name))
1503 lldb.remote_platform = lldb.SBPlatform(lldb_platform_name)
Enrico Granata5f92a132015-11-05 00:46:25 +00001504 lldb.remote_platform_name = lldb_platform_name
Zachary Turnerc432c8f2015-10-28 17:43:26 +00001505 if not lldb.remote_platform.IsValid():
1506 print("error: unable to create the LLDB platform named '%s'." % (lldb_platform_name))
1507 exitTestSuite(1)
1508 if lldb_platform_url:
1509 # We must connect to a remote platform if a LLDB platform URL was specified
1510 print("Connecting to remote platform '%s' at '%s'..." % (lldb_platform_name, lldb_platform_url))
1511 lldb.platform_url = lldb_platform_url
1512 platform_connect_options = lldb.SBPlatformConnectOptions(lldb_platform_url)
1513 err = lldb.remote_platform.ConnectRemote(platform_connect_options)
1514 if err.Success():
1515 print("Connected.")
1516 else:
1517 print("error: failed to connect to remote platform using URL '%s': %s" % (lldb_platform_url, err))
1518 exitTestSuite(1)
1519 else:
1520 lldb.platform_url = None
1521
Enrico Granata5f92a132015-11-05 00:46:25 +00001522 platform_changes = setDefaultTripleForPlatform()
1523 first = True
1524 for key in platform_changes:
1525 if first:
1526 print("Environment variables setup for platform support:")
1527 first = False
1528 print("%s = %s" % (key,platform_changes[key]))
1529
1530 if lldb_platform_working_dir:
1531 print("Setting remote platform working directory to '%s'..." % (lldb_platform_working_dir))
1532 lldb.remote_platform.SetWorkingDirectory(lldb_platform_working_dir)
Zachary Turnerc432c8f2015-10-28 17:43:26 +00001533 lldb.remote_platform_working_dir = lldb_platform_working_dir
1534 lldb.DBG.SetSelectedPlatform(lldb.remote_platform)
1535 else:
1536 lldb.remote_platform = None
1537 lldb.remote_platform_working_dir = None
1538 lldb.platform_url = None
1539
1540 target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2]
1541
1542 # By default, both dsym, dwarf and dwo tests are performed.
1543 # Use @dsym_test, @dwarf_test or @dwo_test decorators, defined in lldbtest.py, to mark a test as
1544 # a dsym, dwarf or dwo test. Use '-N dsym', '-N dwarf' or '-N dwo' to exclude dsym, dwarf or
1545 # dwo tests from running.
1546 dont_do_dsym_test = dont_do_dsym_test or any(platform in target_platform for platform in ["linux", "freebsd", "windows"])
1547 dont_do_dwo_test = dont_do_dwo_test or any(platform in target_platform for platform in ["darwin", "macosx", "ios"])
1548
1549 # Don't do debugserver tests on everything except OS X.
1550 dont_do_debugserver_test = "linux" in target_platform or "freebsd" in target_platform or "windows" in target_platform
1551
1552 # Don't do lldb-server (llgs) tests on anything except Linux.
1553 dont_do_llgs_test = not ("linux" in target_platform)
1554
1555 #
1556 # Walk through the testdirs while collecting tests.
1557 #
1558 for testdir in testdirs:
Zachary Turnere6ba0532015-11-05 01:33:54 +00001559 for (dirpath, dirnames, filenames) in os.walk(testdir):
1560 visit('Test', dirpath, filenames)
Zachary Turnerc432c8f2015-10-28 17:43:26 +00001561
1562 #
1563 # Now that we have loaded all the test cases, run the whole test suite.
1564 #
1565
1566 # Put the blacklist in the lldb namespace, to be used by lldb.TestBase.
1567 lldb.blacklist = blacklist
1568
1569 # The pre_flight and post_flight come from reading a config file.
1570 lldb.pre_flight = pre_flight
1571 lldb.post_flight = post_flight
1572 def getsource_if_available(obj):
1573 """
1574 Return the text of the source code for an object if available. Otherwise,
1575 a print representation is returned.
1576 """
1577 import inspect
1578 try:
1579 return inspect.getsource(obj)
1580 except:
1581 return repr(obj)
1582
1583 if not noHeaders:
1584 print("lldb.pre_flight:", getsource_if_available(lldb.pre_flight))
1585 print("lldb.post_flight:", getsource_if_available(lldb.post_flight))
1586
1587 # If either pre_flight or post_flight is defined, set lldb.test_remote to True.
1588 if lldb.pre_flight or lldb.post_flight:
1589 lldb.test_remote = True
1590 else:
1591 lldb.test_remote = False
1592
1593 # So do the lldbtest_remote_sandbox and lldbtest_remote_shell_template variables.
1594 lldb.lldbtest_remote_sandbox = lldbtest_remote_sandbox
1595 lldb.lldbtest_remote_sandboxed_executable = None
1596 lldb.lldbtest_remote_shell_template = lldbtest_remote_shell_template
1597
1598 # Put all these test decorators in the lldb namespace.
1599 lldb.just_do_benchmarks_test = just_do_benchmarks_test
1600 lldb.dont_do_dsym_test = dont_do_dsym_test
1601 lldb.dont_do_dwarf_test = dont_do_dwarf_test
1602 lldb.dont_do_dwo_test = dont_do_dwo_test
1603 lldb.dont_do_debugserver_test = dont_do_debugserver_test
1604 lldb.dont_do_llgs_test = dont_do_llgs_test
1605
1606 # Do we need to skip build and cleanup?
1607 lldb.skip_build_and_cleanup = skip_build_and_cleanup
1608
1609 # Put bmExecutable, bmBreakpointSpec, and bmIterationCount into the lldb namespace, too.
1610 lldb.bmExecutable = bmExecutable
1611 lldb.bmBreakpointSpec = bmBreakpointSpec
1612 lldb.bmIterationCount = bmIterationCount
1613
1614 # And don't forget the runHooks!
1615 lldb.runHooks = runHooks
1616
1617 # Turn on lldb loggings if necessary.
1618 lldbLoggings()
1619
1620 # Disable default dynamic types for testing purposes
1621 disabledynamics()
1622
1623 # Install the control-c handler.
1624 unittest2.signals.installHandler()
1625
1626 # If sdir_name is not specified through the '-s sdir_name' option, get a
1627 # timestamp string and export it as LLDB_SESSION_DIR environment var. This will
1628 # be used when/if we want to dump the session info of individual test cases
1629 # later on.
1630 #
1631 # See also TestBase.dumpSessionInfo() in lldbtest.py.
1632 import datetime
1633 # The windows platforms don't like ':' in the pathname.
1634 timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
1635 if not sdir_name:
1636 sdir_name = timestamp_started
1637 os.environ["LLDB_SESSION_DIRNAME"] = os.path.join(os.getcwd(), sdir_name)
1638
1639 if not noHeaders:
1640 sys.stderr.write("\nSession logs for test failures/errors/unexpected successes"
1641 " will go into directory '%s'\n" % sdir_name)
1642 sys.stderr.write("Command invoked: %s\n" % getMyCommandLine())
1643
1644 if not os.path.isdir(sdir_name):
1645 try:
1646 os.mkdir(sdir_name)
1647 except OSError as exception:
1648 if exception.errno != errno.EEXIST:
1649 raise
1650 where_to_save_session = os.getcwd()
1651 fname = os.path.join(sdir_name, "TestStarted-%d" % os.getpid())
1652 with open(fname, "w") as f:
1653 print("Test started at: %s\n" % timestamp_started, file=f)
1654 print(svn_info, file=f)
1655 print("Command invoked: %s\n" % getMyCommandLine(), file=f)
1656
1657 #
1658 # Invoke the default TextTestRunner to run the test suite, possibly iterating
1659 # over different configurations.
1660 #
1661
1662 iterArchs = False
1663 iterCompilers = False
1664
1665 if not archs and "archs" in config:
1666 archs = config["archs"]
1667
1668 if isinstance(archs, list) and len(archs) >= 1:
1669 iterArchs = True
1670
1671 if not compilers and "compilers" in config:
1672 compilers = config["compilers"]
1673
1674 #
1675 # Add some intervention here to sanity check that the compilers requested are sane.
1676 # If found not to be an executable program, the invalid one is dropped from the list.
1677 for i in range(len(compilers)):
1678 c = compilers[i]
1679 if which(c):
1680 continue
1681 else:
1682 if sys.platform.startswith("darwin"):
1683 pipe = subprocess.Popen(['xcrun', '-find', c], stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
1684 cmd_output = pipe.stdout.read()
1685 if cmd_output:
1686 if "not found" in cmd_output:
1687 print("dropping %s from the compilers used" % c)
1688 compilers.remove(i)
1689 else:
1690 compilers[i] = cmd_output.split('\n')[0]
1691 print("'xcrun -find %s' returning %s" % (c, compilers[i]))
1692
1693 if not parsable:
1694 print("compilers=%s" % str(compilers))
1695
1696 if not compilers or len(compilers) == 0:
1697 print("No eligible compiler found, exiting.")
1698 exitTestSuite(1)
1699
1700 if isinstance(compilers, list) and len(compilers) >= 1:
1701 iterCompilers = True
1702
1703 # Make a shallow copy of sys.path, we need to manipulate the search paths later.
1704 # This is only necessary if we are relocated and with different configurations.
1705 if rdir:
1706 old_sys_path = sys.path[:]
1707 # If we iterate on archs or compilers, there is a chance we want to split stderr/stdout.
1708 if iterArchs or iterCompilers:
1709 old_stderr = sys.stderr
1710 old_stdout = sys.stdout
1711 new_stderr = None
1712 new_stdout = None
1713
1714 # Iterating over all possible architecture and compiler combinations.
1715 for ia in range(len(archs) if iterArchs else 1):
1716 archConfig = ""
1717 if iterArchs:
1718 os.environ["ARCH"] = archs[ia]
1719 archConfig = "arch=%s" % archs[ia]
1720 for ic in range(len(compilers) if iterCompilers else 1):
1721 if iterCompilers:
1722 os.environ["CC"] = compilers[ic]
1723 configString = "%s compiler=%s" % (archConfig, compilers[ic])
1724 else:
1725 configString = archConfig
1726
1727 if iterArchs or iterCompilers:
1728 # Translate ' ' to '-' for pathname component.
1729 from string import maketrans
1730 tbl = maketrans(' ', '-')
1731 configPostfix = configString.translate(tbl)
1732
1733 # Check whether we need to split stderr/stdout into configuration
1734 # specific files.
1735 if old_stderr.name != '<stderr>' and config.get('split_stderr'):
1736 if new_stderr:
1737 new_stderr.close()
1738 new_stderr = open("%s.%s" % (old_stderr.name, configPostfix), "w")
1739 sys.stderr = new_stderr
1740 if old_stdout.name != '<stdout>' and config.get('split_stdout'):
1741 if new_stdout:
1742 new_stdout.close()
1743 new_stdout = open("%s.%s" % (old_stdout.name, configPostfix), "w")
1744 sys.stdout = new_stdout
1745
1746 # If we specified a relocated directory to run the test suite, do
1747 # the extra housekeeping to copy the testdirs to a configStringified
1748 # directory and to update sys.path before invoking the test runner.
1749 # The purpose is to separate the configuration-specific directories
1750 # from each other.
1751 if rdir:
1752 from shutil import copytree, rmtree, ignore_patterns
1753
1754 newrdir = "%s.%s" % (rdir, configPostfix)
1755
1756 # Copy the tree to a new directory with postfix name configPostfix.
1757 if os.path.exists(newrdir):
1758 rmtree(newrdir)
1759 copytree(rdir, newrdir, ignore=ignore_patterns('*.pyc', '*.o', '*.d'))
1760
1761 # Update the LLDB_TEST environment variable to reflect new top
1762 # level test directory.
1763 #
1764 # See also lldbtest.TestBase.setUpClass(cls).
1765 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
1766 os.environ["LLDB_TEST"] = os.path.join(newrdir, 'test')
1767 else:
1768 os.environ["LLDB_TEST"] = newrdir
1769
1770 # And update the Python search paths for modules.
1771 sys.path = [x.replace(rdir, newrdir, 1) for x in old_sys_path]
1772
1773 # Output the configuration.
1774 if not parsable:
1775 sys.stderr.write("\nConfiguration: " + configString + "\n")
1776
1777 #print("sys.stderr name is", sys.stderr.name)
1778 #print("sys.stdout name is", sys.stdout.name)
1779
1780 # First, write out the number of collected test cases.
1781 if not parsable:
1782 sys.stderr.write(separator + "\n")
1783 sys.stderr.write("Collected %d test%s\n\n"
1784 % (suite.countTestCases(),
1785 suite.countTestCases() != 1 and "s" or ""))
1786
1787 class LLDBTestResult(unittest2.TextTestResult):
1788 """
1789 Enforce a singleton pattern to allow introspection of test progress.
1790
1791 Overwrite addError(), addFailure(), and addExpectedFailure() methods
1792 to enable each test instance to track its failure/error status. It
1793 is used in the LLDB test framework to emit detailed trace messages
1794 to a log file for easier human inspection of test failures/errors.
1795 """
1796 __singleton__ = None
1797 __ignore_singleton__ = False
1798
1799 @staticmethod
1800 def getTerminalSize():
1801 import os
1802 env = os.environ
1803 def ioctl_GWINSZ(fd):
1804 try:
1805 import fcntl, termios, struct, os
1806 cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,
1807 '1234'))
1808 except:
1809 return
1810 return cr
1811 cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
1812 if not cr:
1813 try:
1814 fd = os.open(os.ctermid(), os.O_RDONLY)
1815 cr = ioctl_GWINSZ(fd)
1816 os.close(fd)
1817 except:
1818 pass
1819 if not cr:
1820 cr = (env.get('LINES', 25), env.get('COLUMNS', 80))
1821 return int(cr[1]), int(cr[0])
1822
1823 def __init__(self, *args):
1824 if not LLDBTestResult.__ignore_singleton__ and LLDBTestResult.__singleton__:
1825 raise Exception("LLDBTestResult instantiated more than once")
1826 super(LLDBTestResult, self).__init__(*args)
1827 LLDBTestResult.__singleton__ = self
1828 # Now put this singleton into the lldb module namespace.
1829 lldb.test_result = self
1830 # Computes the format string for displaying the counter.
1831 global suite
1832 counterWidth = len(str(suite.countTestCases()))
1833 self.fmt = "%" + str(counterWidth) + "d: "
1834 self.indentation = ' ' * (counterWidth + 2)
1835 # This counts from 1 .. suite.countTestCases().
1836 self.counter = 0
1837 (width, height) = LLDBTestResult.getTerminalSize()
1838 self.progressbar = None
1839 global progress_bar
1840 if width > 10 and not parsable and progress_bar:
1841 try:
1842 self.progressbar = progress.ProgressWithEvents(stdout=self.stream,start=0,end=suite.countTestCases(),width=width-10)
1843 except:
1844 self.progressbar = None
1845 self.results_formatter = results_formatter_object
1846
1847 def _config_string(self, test):
1848 compiler = getattr(test, "getCompiler", None)
1849 arch = getattr(test, "getArchitecture", None)
1850 return "%s-%s" % (compiler() if compiler else "", arch() if arch else "")
1851
1852 def _exc_info_to_string(self, err, test):
1853 """Overrides superclass TestResult's method in order to append
1854 our test config info string to the exception info string."""
1855 if hasattr(test, "getArchitecture") and hasattr(test, "getCompiler"):
1856 return '%sConfig=%s-%s' % (super(LLDBTestResult, self)._exc_info_to_string(err, test),
1857 test.getArchitecture(),
1858 test.getCompiler())
1859 else:
1860 return super(LLDBTestResult, self)._exc_info_to_string(err, test)
1861
1862 def getDescription(self, test):
1863 doc_first_line = test.shortDescription()
1864 if self.descriptions and doc_first_line:
1865 return '\n'.join((str(test), self.indentation + doc_first_line))
1866 else:
1867 return str(test)
1868
1869 def getCategoriesForTest(self,test):
1870 if hasattr(test,"_testMethodName"):
1871 test_method = getattr(test,"_testMethodName")
1872 test_method = getattr(test,test_method)
1873 else:
1874 test_method = None
1875 if test_method != None and hasattr(test_method,"getCategories"):
1876 test_categories = test_method.getCategories(test)
1877 elif hasattr(test,"getCategories"):
1878 test_categories = test.getCategories()
1879 elif inspect.ismethod(test) and test.__self__ != None and hasattr(test.__self__,"getCategories"):
1880 test_categories = test.__self__.getCategories()
1881 else:
1882 test_categories = []
1883 if test_categories == None:
1884 test_categories = []
1885 return test_categories
1886
1887 def hardMarkAsSkipped(self,test):
1888 getattr(test, test._testMethodName).__func__.__unittest_skip__ = True
1889 getattr(test, test._testMethodName).__func__.__unittest_skip_why__ = "test case does not fall in any category of interest for this run"
1890 test.__class__.__unittest_skip__ = True
1891 test.__class__.__unittest_skip_why__ = "test case does not fall in any category of interest for this run"
1892
1893 def startTest(self, test):
1894 if shouldSkipBecauseOfCategories(self.getCategoriesForTest(test)):
1895 self.hardMarkAsSkipped(test)
1896 global setCrashInfoHook
1897 setCrashInfoHook("%s at %s" % (str(test),inspect.getfile(test.__class__)))
1898 self.counter += 1
1899 #if self.counter == 4:
1900 # import crashinfo
1901 # crashinfo.testCrashReporterDescription(None)
1902 test.test_number = self.counter
1903 if self.showAll:
1904 self.stream.write(self.fmt % self.counter)
1905 super(LLDBTestResult, self).startTest(test)
1906 if self.results_formatter:
1907 self.results_formatter.handle_event(
1908 EventBuilder.event_for_start(test))
1909
1910 def addSuccess(self, test):
1911 global parsable
1912 super(LLDBTestResult, self).addSuccess(test)
1913 if parsable:
1914 self.stream.write("PASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
1915 if self.results_formatter:
1916 self.results_formatter.handle_event(
1917 EventBuilder.event_for_success(test))
1918
1919 def addError(self, test, err):
1920 global sdir_has_content
1921 global parsable
1922 sdir_has_content = True
1923 super(LLDBTestResult, self).addError(test, err)
1924 method = getattr(test, "markError", None)
1925 if method:
1926 method()
1927 if parsable:
1928 self.stream.write("FAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
1929 if self.results_formatter:
1930 self.results_formatter.handle_event(
1931 EventBuilder.event_for_error(test, err))
1932
1933 def addCleanupError(self, test, err):
1934 global sdir_has_content
1935 global parsable
1936 sdir_has_content = True
1937 super(LLDBTestResult, self).addCleanupError(test, err)
1938 method = getattr(test, "markCleanupError", None)
1939 if method:
1940 method()
1941 if parsable:
1942 self.stream.write("CLEANUP ERROR: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
1943 if self.results_formatter:
1944 self.results_formatter.handle_event(
1945 EventBuilder.event_for_cleanup_error(
1946 test, err))
1947
1948 def addFailure(self, test, err):
1949 global sdir_has_content
1950 global failuresPerCategory
1951 global parsable
1952 sdir_has_content = True
1953 super(LLDBTestResult, self).addFailure(test, err)
1954 method = getattr(test, "markFailure", None)
1955 if method:
1956 method()
1957 if parsable:
1958 self.stream.write("FAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
1959 if useCategories:
1960 test_categories = self.getCategoriesForTest(test)
1961 for category in test_categories:
1962 if category in failuresPerCategory:
1963 failuresPerCategory[category] = failuresPerCategory[category] + 1
1964 else:
1965 failuresPerCategory[category] = 1
1966 if self.results_formatter:
1967 self.results_formatter.handle_event(
1968 EventBuilder.event_for_failure(test, err))
1969
1970
1971 def addExpectedFailure(self, test, err, bugnumber):
1972 global sdir_has_content
1973 global parsable
1974 sdir_has_content = True
1975 super(LLDBTestResult, self).addExpectedFailure(test, err, bugnumber)
1976 method = getattr(test, "markExpectedFailure", None)
1977 if method:
1978 method(err, bugnumber)
1979 if parsable:
1980 self.stream.write("XFAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
1981 if self.results_formatter:
1982 self.results_formatter.handle_event(
1983 EventBuilder.event_for_expected_failure(
1984 test, err, bugnumber))
1985
1986 def addSkip(self, test, reason):
1987 global sdir_has_content
1988 global parsable
1989 sdir_has_content = True
1990 super(LLDBTestResult, self).addSkip(test, reason)
1991 method = getattr(test, "markSkippedTest", None)
1992 if method:
1993 method()
1994 if parsable:
1995 self.stream.write("UNSUPPORTED: LLDB (%s) :: %s (%s) \n" % (self._config_string(test), str(test), reason))
1996 if self.results_formatter:
1997 self.results_formatter.handle_event(
1998 EventBuilder.event_for_skip(test, reason))
1999
2000 def addUnexpectedSuccess(self, test, bugnumber):
2001 global sdir_has_content
2002 global parsable
2003 sdir_has_content = True
2004 super(LLDBTestResult, self).addUnexpectedSuccess(test, bugnumber)
2005 method = getattr(test, "markUnexpectedSuccess", None)
2006 if method:
2007 method(bugnumber)
2008 if parsable:
2009 self.stream.write("XPASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
2010 if self.results_formatter:
2011 self.results_formatter.handle_event(
2012 EventBuilder.event_for_unexpected_success(
2013 test, bugnumber))
2014
2015
2016 if parsable:
2017 v = 0
2018 elif progress_bar:
2019 v = 1
2020 else:
2021 v = verbose
2022
2023 # Invoke the test runner.
2024 if count == 1:
2025 result = unittest2.TextTestRunner(stream=sys.stderr,
2026 verbosity=v,
2027 failfast=failfast,
2028 resultclass=LLDBTestResult).run(suite)
2029 else:
2030 # We are invoking the same test suite more than once. In this case,
2031 # mark __ignore_singleton__ flag as True so the signleton pattern is
2032 # not enforced.
2033 LLDBTestResult.__ignore_singleton__ = True
2034 for i in range(count):
2035
2036 result = unittest2.TextTestRunner(stream=sys.stderr,
2037 verbosity=v,
2038 failfast=failfast,
2039 resultclass=LLDBTestResult).run(suite)
2040
2041 failed = failed or not result.wasSuccessful()
2042
2043 if sdir_has_content and not parsable:
2044 sys.stderr.write("Session logs for test failures/errors/unexpected successes"
2045 " can be found in directory '%s'\n" % sdir_name)
2046
2047 if useCategories and len(failuresPerCategory) > 0:
2048 sys.stderr.write("Failures per category:\n")
2049 for category in failuresPerCategory:
2050 sys.stderr.write("%s - %d\n" % (category,failuresPerCategory[category]))
2051
2052 os.chdir(where_to_save_session)
2053 fname = os.path.join(sdir_name, "TestFinished-%d" % os.getpid())
2054 with open(fname, "w") as f:
2055 print("Test finished at: %s\n" % datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S"), file=f)
2056
2057 # Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
2058 # This should not be necessary now.
2059 if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
2060 print("Terminating Test suite...")
2061 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
2062
2063 # Exiting.
2064 exitTestSuite(failed)
2065
2066if __name__ == "__main__":
Zachary Turner7d564542015-11-02 19:19:49 +00002067 print(__file__ + " is for use as a module only. It should not be run as a standalone script.")
2068 sys.exit(-1)