blob: c85e2067d5d0f1d5ee607d71670c83b8e9bc6f7c [file] [log] [blame]
Johnny Chen9707bb62010-06-25 21:14:08 +00001#!/usr/bin/env python
2
3"""
4A simple testing framework for lldb using python's unit testing framework.
5
6Tests for lldb are written as python scripts which take advantage of the script
7bridging provided by LLDB.framework to interact with lldb core.
8
9A specific naming pattern is followed by the .py script to be recognized as
10a module which implements a test scenario, namely, Test*.py.
11
12To specify the directories where "Test*.py" python test scripts are located,
13you need to pass in a list of directory names. By default, the current
14working directory is searched if nothing is specified on the command line.
Johnny Chen872aee12010-09-16 15:44:23 +000015
16Type:
17
18./dotest.py -h
19
20for available options.
Johnny Chen9707bb62010-06-25 21:14:08 +000021"""
22
Johnny Chen91960d32010-09-08 20:56:16 +000023import os, signal, sys, time
Johnny Chen75e28f92010-08-05 23:42:46 +000024import unittest2
Johnny Chen9707bb62010-06-25 21:14:08 +000025
Johnny Chen877c7e42010-08-07 00:16:07 +000026class _WritelnDecorator(object):
27 """Used to decorate file-like objects with a handy 'writeln' method"""
28 def __init__(self,stream):
29 self.stream = stream
30
31 def __getattr__(self, attr):
32 if attr in ('stream', '__getstate__'):
33 raise AttributeError(attr)
34 return getattr(self.stream,attr)
35
36 def writeln(self, arg=None):
37 if arg:
38 self.write(arg)
39 self.write('\n') # text-mode streams translate to \r\n if needed
40
Johnny Chen9707bb62010-06-25 21:14:08 +000041#
42# Global variables:
43#
44
45# The test suite.
Johnny Chen75e28f92010-08-05 23:42:46 +000046suite = unittest2.TestSuite()
Johnny Chen9707bb62010-06-25 21:14:08 +000047
Johnny Chen9fdb0a92010-09-18 00:16:47 +000048# The config file is optional.
49configFile = None
50
Johnny Chend2acdb32010-11-16 22:42:58 +000051# Test suite repeat count. Can be overwritten with '-# count'.
52count = 1
53
Johnny Chenb40056b2010-09-21 00:09:27 +000054# The dictionary as a result of sourcing configFile.
55config = {}
56
Johnny Chen91960d32010-09-08 20:56:16 +000057# Delay startup in order for the debugger to attach.
58delay = False
59
Johnny Chena224cd12010-11-08 01:21:03 +000060# The filter (testclass.testmethod) used to admit tests into our test suite.
Johnny Chenb62436b2010-10-06 20:40:56 +000061filterspec = None
62
Johnny Chena224cd12010-11-08 01:21:03 +000063# If '-g' is specified, the filterspec is not exclusive. If a test module does
64# not contain testclass.testmethod which matches the filterspec, the whole test
65# module is still admitted into our test suite. fs4all flag defaults to True.
66fs4all = True
Johnny Chenb62436b2010-10-06 20:40:56 +000067
Johnny Chenaf149a02010-09-16 17:11:30 +000068# Ignore the build search path relative to this script to locate the lldb.py module.
69ignore = False
70
Johnny Chen548aefd2010-10-11 22:25:46 +000071# By default, we skip long running test case. Use '-l' option to override.
Johnny Chen41998192010-10-01 22:59:49 +000072skipLongRunningTest = True
73
Johnny Chen7c52ff12010-09-27 23:29:54 +000074# The regular expression pattern to match against eligible filenames as our test cases.
75regexp = None
76
Johnny Chen548aefd2010-10-11 22:25:46 +000077# By default, tests are executed in place and cleanups are performed afterwards.
78# Use '-r dir' option to relocate the tests and their intermediate files to a
79# different directory and to forgo any cleanups. The directory specified must
80# not exist yet.
81rdir = None
82
Johnny Chen125fc2b2010-10-21 16:55:35 +000083# By default, recorded session info for errored/failed test are dumped into its
84# own file under a session directory named after the timestamp of the test suite
85# run. Use '-s session-dir-name' to specify a specific dir name.
86sdir_name = None
87
Johnny Chen63c2cba2010-10-29 22:20:36 +000088# Set this flag if there is any session info dumped during the test run.
89sdir_has_content = False
90
Johnny Chen9707bb62010-06-25 21:14:08 +000091# Default verbosity is 0.
92verbose = 0
93
94# By default, search from the current working directory.
95testdirs = [ os.getcwd() ]
96
Johnny Chen877c7e42010-08-07 00:16:07 +000097# Separator string.
98separator = '-' * 70
99
Johnny Chen9707bb62010-06-25 21:14:08 +0000100
101def usage():
102 print """
103Usage: dotest.py [option] [args]
104where options:
105-h : print this help message and exit (also --help)
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000106-c : read a config file specified after this option
Johnny Chenb40056b2010-09-21 00:09:27 +0000107 (see also lldb-trunk/example/test/usage-config)
Johnny Chen91960d32010-09-08 20:56:16 +0000108-d : delay startup for 10 seconds (in order for the debugger to attach)
Johnny Chen46be75d2010-10-11 16:19:48 +0000109-f : specify a filter, which consists of the test class name, a dot, followed by
Johnny Chen1a6e92a2010-11-08 20:17:04 +0000110 the test method, to only admit such test into the test suite
Johnny Chenb62436b2010-10-06 20:40:56 +0000111 e.g., -f 'ClassTypesTestCase.test_with_dwarf_and_python_api'
Johnny Chena224cd12010-11-08 01:21:03 +0000112-g : if specified, the filterspec by -f is not exclusive, i.e., if a test module
113 does not match the filterspec (testclass.testmethod), the whole module is
114 still admitted to the test suite
Johnny Chenaf149a02010-09-16 17:11:30 +0000115-i : ignore (don't bailout) if 'lldb.py' module cannot be located in the build
116 tree relative to this script; use PYTHONPATH to locate the module
Johnny Chen41998192010-10-01 22:59:49 +0000117-l : don't skip long running test
Johnny Chen7c52ff12010-09-27 23:29:54 +0000118-p : specify a regexp filename pattern for inclusion in the test suite
Johnny Chen548aefd2010-10-11 22:25:46 +0000119-r : specify a dir to relocate the tests and their intermediate files to;
120 the directory must not exist before running this test driver;
121 no cleanup of intermediate test files is performed in this case
Johnny Chen125fc2b2010-10-21 16:55:35 +0000122-s : specify the name of the dir created to store the session files of tests
123 with errored or failed status; if not specified, the test driver uses the
124 timestamp as the session dir name
Johnny Chend0c24b22010-08-23 17:10:44 +0000125-t : trace lldb command execution and result
Johnny Chen9707bb62010-06-25 21:14:08 +0000126-v : do verbose mode of unittest framework
Johnny Chene47649c2010-10-07 02:04:14 +0000127-w : insert some wait time (currently 0.5 sec) between consecutive test cases
Johnny Chend2acdb32010-11-16 22:42:58 +0000128-# : Repeat the test suite for a specified number of times
Johnny Chen9707bb62010-06-25 21:14:08 +0000129
130and:
Johnny Chen9656ab22010-10-22 19:00:18 +0000131args : specify a list of directory names to search for test modules named after
132 Test*.py (test discovery)
Johnny Chen9707bb62010-06-25 21:14:08 +0000133 if empty, search from the curret working directory, instead
Johnny Chen58f93922010-06-29 23:10:39 +0000134
Johnny Chen9656ab22010-10-22 19:00:18 +0000135Examples:
136
Johnny Chena224cd12010-11-08 01:21:03 +0000137This is an example of using the -f option to pinpoint to a specfic test class
138and test method to be run:
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000139
Johnny Chena224cd12010-11-08 01:21:03 +0000140$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000141----------------------------------------------------------------------
142Collected 1 test
143
144test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
145Test 'frame variable this' when stopped on a class constructor. ... ok
146
147----------------------------------------------------------------------
148Ran 1 test in 1.396s
149
150OK
Johnny Chen9656ab22010-10-22 19:00:18 +0000151
152And this is an example of using the -p option to run a single file (the filename
153matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
154
155$ ./dotest.py -v -p ObjC
156----------------------------------------------------------------------
157Collected 4 tests
158
159test_break_with_dsym (TestObjCMethods.FoundationTestCase)
160Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'. ... ok
161test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
162Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'. ... ok
163test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
164Lookup objective-c data types and evaluate expressions. ... ok
165test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
166Lookup objective-c data types and evaluate expressions. ... ok
167
168----------------------------------------------------------------------
169Ran 4 tests in 16.661s
170
171OK
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000172
Johnny Chen58f93922010-06-29 23:10:39 +0000173Running of this script also sets up the LLDB_TEST environment variable so that
Johnny Chenaf149a02010-09-16 17:11:30 +0000174individual test cases can locate their supporting files correctly. The script
175tries to set up Python's search paths for modules by looking at the build tree
Johnny Chena85859f2010-11-11 22:14:56 +0000176relative to this script. See also the '-i' option in the following example.
177
178Finally, this is an example of using the lldb.py module distributed/installed by
179Xcode4 to run against the tests under the 'forward' directory, and with the '-w'
180option to add some delay between two tests. It uses ARCH=x86_64 to specify that
181as the architecture and CC=clang to specify the compiler used for the test run:
182
183$ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward
184
185Session logs for test failures/errors will go into directory '2010-11-11-13_56_16'
186----------------------------------------------------------------------
187Collected 2 tests
188
189test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
190Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
191test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
192Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
193
194----------------------------------------------------------------------
195Ran 2 tests in 5.659s
196
197OK
198
199The 'Session ...' verbiage is recently introduced (see also the '-s' option) to
200notify the directory containing the session logs for test failures or errors.
201In case there is any test failure/error, a similar message is appended at the
202end of the stderr output for your convenience.
Johnny Chenfde69bc2010-09-14 22:01:40 +0000203
204Environment variables related to loggings:
205
206o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
207 with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
208
209o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
210 'process.gdb-remote' subsystem with a default option of 'packets' if
211 GDB_REMOTE_LOG_OPTION is not defined.
Johnny Chen9707bb62010-06-25 21:14:08 +0000212"""
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000213 sys.exit(0)
Johnny Chen9707bb62010-06-25 21:14:08 +0000214
215
Johnny Chenaf149a02010-09-16 17:11:30 +0000216def parseOptionsAndInitTestdirs():
217 """Initialize the list of directories containing our unittest scripts.
218
219 '-h/--help as the first option prints out usage info and exit the program.
220 """
221
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000222 global configFile
Johnny Chend2acdb32010-11-16 22:42:58 +0000223 global count
Johnny Chenaf149a02010-09-16 17:11:30 +0000224 global delay
Johnny Chenb62436b2010-10-06 20:40:56 +0000225 global filterspec
226 global fs4all
Johnny Chen7c52ff12010-09-27 23:29:54 +0000227 global ignore
Johnny Chen41998192010-10-01 22:59:49 +0000228 global skipLongRunningTest
Johnny Chen7c52ff12010-09-27 23:29:54 +0000229 global regexp
Johnny Chen548aefd2010-10-11 22:25:46 +0000230 global rdir
Johnny Chen125fc2b2010-10-21 16:55:35 +0000231 global sdir_name
Johnny Chenaf149a02010-09-16 17:11:30 +0000232 global verbose
233 global testdirs
234
235 if len(sys.argv) == 1:
236 return
237
238 # Process possible trace and/or verbose flag, among other things.
239 index = 1
Johnny Chence2212c2010-10-07 15:41:55 +0000240 while index < len(sys.argv):
Johnny Chenaf149a02010-09-16 17:11:30 +0000241 if not sys.argv[index].startswith('-'):
242 # End of option processing.
243 break
244
245 if sys.argv[index].find('-h') != -1:
246 usage()
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000247 elif sys.argv[index].startswith('-c'):
248 # Increment by 1 to fetch the config file name option argument.
249 index += 1
250 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
251 usage()
252 configFile = sys.argv[index]
253 if not os.path.isfile(configFile):
254 print "Config file:", configFile, "does not exist!"
255 usage()
256 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000257 elif sys.argv[index].startswith('-d'):
258 delay = True
259 index += 1
Johnny Chenb62436b2010-10-06 20:40:56 +0000260 elif sys.argv[index].startswith('-f'):
261 # Increment by 1 to fetch the filter spec.
262 index += 1
263 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
264 usage()
265 filterspec = sys.argv[index]
266 index += 1
267 elif sys.argv[index].startswith('-g'):
Johnny Chena224cd12010-11-08 01:21:03 +0000268 fs4all = False
Johnny Chenb62436b2010-10-06 20:40:56 +0000269 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000270 elif sys.argv[index].startswith('-i'):
271 ignore = True
272 index += 1
Johnny Chen41998192010-10-01 22:59:49 +0000273 elif sys.argv[index].startswith('-l'):
274 skipLongRunningTest = False
275 index += 1
Johnny Chen7c52ff12010-09-27 23:29:54 +0000276 elif sys.argv[index].startswith('-p'):
277 # Increment by 1 to fetch the reg exp pattern argument.
278 index += 1
279 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
280 usage()
281 regexp = sys.argv[index]
282 index += 1
Johnny Chen548aefd2010-10-11 22:25:46 +0000283 elif sys.argv[index].startswith('-r'):
284 # Increment by 1 to fetch the relocated directory argument.
285 index += 1
286 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
287 usage()
288 rdir = os.path.abspath(sys.argv[index])
289 if os.path.exists(rdir):
290 print "Relocated directory:", rdir, "must not exist!"
291 usage()
292 index += 1
Johnny Chen125fc2b2010-10-21 16:55:35 +0000293 elif sys.argv[index].startswith('-s'):
294 # Increment by 1 to fetch the session dir name.
295 index += 1
296 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
297 usage()
298 sdir_name = sys.argv[index]
299 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000300 elif sys.argv[index].startswith('-t'):
301 os.environ["LLDB_COMMAND_TRACE"] = "YES"
302 index += 1
303 elif sys.argv[index].startswith('-v'):
304 verbose = 2
305 index += 1
Johnny Chene47649c2010-10-07 02:04:14 +0000306 elif sys.argv[index].startswith('-w'):
307 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] = 'YES'
308 index += 1
Johnny Chend2acdb32010-11-16 22:42:58 +0000309 elif sys.argv[index].startswith('-#'):
310 # Increment by 1 to fetch the repeat count argument.
311 index += 1
312 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
313 usage()
314 count = int(sys.argv[index])
315 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000316 else:
317 print "Unknown option: ", sys.argv[index]
318 usage()
Johnny Chenaf149a02010-09-16 17:11:30 +0000319
320 # Gather all the dirs passed on the command line.
321 if len(sys.argv) > index:
322 testdirs = map(os.path.abspath, sys.argv[index:])
323
Johnny Chen548aefd2010-10-11 22:25:46 +0000324 # If '-r dir' is specified, the tests should be run under the relocated
325 # directory. Let's copy the testdirs over.
326 if rdir:
327 from shutil import copytree, ignore_patterns
328
329 tmpdirs = []
330 for srcdir in testdirs:
331 dstdir = os.path.join(rdir, os.path.basename(srcdir))
332 # Don't copy the *.pyc and .svn stuffs.
333 copytree(srcdir, dstdir, ignore=ignore_patterns('*.pyc', '.svn'))
334 tmpdirs.append(dstdir)
335
336 # This will be our modified testdirs.
337 testdirs = tmpdirs
338
339 # With '-r dir' specified, there's no cleanup of intermediate test files.
340 os.environ["LLDB_DO_CLEANUP"] = 'NO'
341
342 # If testdirs is ['test'], the make directory has already been copied
343 # recursively and is contained within the rdir/test dir. For anything
344 # else, we would need to copy over the make directory and its contents,
345 # so that, os.listdir(rdir) looks like, for example:
346 #
347 # array_types conditional_break make
348 #
349 # where the make directory contains the Makefile.rules file.
350 if len(testdirs) != 1 or os.path.basename(testdirs[0]) != 'test':
351 # Don't copy the .svn stuffs.
352 copytree('make', os.path.join(rdir, 'make'),
353 ignore=ignore_patterns('.svn'))
354
355 #print "testdirs:", testdirs
356
Johnny Chenb40056b2010-09-21 00:09:27 +0000357 # Source the configFile if specified.
358 # The side effect, if any, will be felt from this point on. An example
359 # config file may be these simple two lines:
360 #
361 # sys.stderr = open("/tmp/lldbtest-stderr", "w")
362 # sys.stdout = open("/tmp/lldbtest-stdout", "w")
363 #
364 # which will reassign the two file objects to sys.stderr and sys.stdout,
365 # respectively.
366 #
367 # See also lldb-trunk/example/test/usage-config.
368 global config
369 if configFile:
370 # Pass config (a dictionary) as the locals namespace for side-effect.
371 execfile(configFile, globals(), config)
372 #print "config:", config
373 #print "sys.stderr:", sys.stderr
374 #print "sys.stdout:", sys.stdout
375
Johnny Chenaf149a02010-09-16 17:11:30 +0000376
Johnny Chen9707bb62010-06-25 21:14:08 +0000377def setupSysPath():
378 """Add LLDB.framework/Resources/Python to the search paths for modules."""
379
Johnny Chen548aefd2010-10-11 22:25:46 +0000380 global rdir
381 global testdirs
382
Johnny Chen9707bb62010-06-25 21:14:08 +0000383 # Get the directory containing the current script.
Johnny Chena1affab2010-07-03 03:41:59 +0000384 scriptPath = sys.path[0]
385 if not scriptPath.endswith('test'):
Johnny Chen9707bb62010-06-25 21:14:08 +0000386 print "This script expects to reside in lldb's test directory."
387 sys.exit(-1)
388
Johnny Chen548aefd2010-10-11 22:25:46 +0000389 if rdir:
390 # Set up the LLDB_TEST environment variable appropriately, so that the
391 # individual tests can be located relatively.
392 #
393 # See also lldbtest.TestBase.setUpClass(cls).
394 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
395 os.environ["LLDB_TEST"] = os.path.join(rdir, 'test')
396 else:
397 os.environ["LLDB_TEST"] = rdir
398 else:
399 os.environ["LLDB_TEST"] = scriptPath
Johnny Chen9de4ede2010-08-31 17:42:54 +0000400 pluginPath = os.path.join(scriptPath, 'plugins')
Johnny Chen58f93922010-06-29 23:10:39 +0000401
Johnny Chenaf149a02010-09-16 17:11:30 +0000402 # Append script dir and plugin dir to the sys.path.
403 sys.path.append(scriptPath)
404 sys.path.append(pluginPath)
405
406 global ignore
407
408 # The '-i' option is used to skip looking for lldb.py in the build tree.
409 if ignore:
410 return
411
Johnny Chena1affab2010-07-03 03:41:59 +0000412 base = os.path.abspath(os.path.join(scriptPath, os.pardir))
Johnny Chen9707bb62010-06-25 21:14:08 +0000413 dbgPath = os.path.join(base, 'build', 'Debug', 'LLDB.framework',
414 'Resources', 'Python')
415 relPath = os.path.join(base, 'build', 'Release', 'LLDB.framework',
416 'Resources', 'Python')
Johnny Chenc202c462010-09-15 18:11:19 +0000417 baiPath = os.path.join(base, 'build', 'BuildAndIntegration',
418 'LLDB.framework', 'Resources', 'Python')
Johnny Chen9707bb62010-06-25 21:14:08 +0000419
420 lldbPath = None
421 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
422 lldbPath = dbgPath
423 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
424 lldbPath = relPath
Johnny Chenc202c462010-09-15 18:11:19 +0000425 elif os.path.isfile(os.path.join(baiPath, 'lldb.py')):
426 lldbPath = baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000427
428 if not lldbPath:
Johnny Chenc202c462010-09-15 18:11:19 +0000429 print 'This script requires lldb.py to be in either ' + dbgPath + ',',
430 print relPath + ', or ' + baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000431 sys.exit(-1)
432
Johnny Chenaf149a02010-09-16 17:11:30 +0000433 # This is to locate the lldb.py module. Insert it right after sys.path[0].
434 sys.path[1:1] = [lldbPath]
Johnny Chen9707bb62010-06-25 21:14:08 +0000435
Johnny Chen9707bb62010-06-25 21:14:08 +0000436
Johnny Chencd0279d2010-09-20 18:07:50 +0000437def doDelay(delta):
438 """Delaying startup for delta-seconds to facilitate debugger attachment."""
439 def alarm_handler(*args):
440 raise Exception("timeout")
441
442 signal.signal(signal.SIGALRM, alarm_handler)
443 signal.alarm(delta)
444 sys.stdout.write("pid=%d\n" % os.getpid())
445 sys.stdout.write("Enter RET to proceed (or timeout after %d seconds):" %
446 delta)
447 sys.stdout.flush()
448 try:
449 text = sys.stdin.readline()
450 except:
451 text = ""
452 signal.alarm(0)
453 sys.stdout.write("proceeding...\n")
454 pass
455
456
Johnny Chen9707bb62010-06-25 21:14:08 +0000457def visit(prefix, dir, names):
458 """Visitor function for os.path.walk(path, visit, arg)."""
459
460 global suite
Johnny Chen7c52ff12010-09-27 23:29:54 +0000461 global regexp
Johnny Chenb62436b2010-10-06 20:40:56 +0000462 global filterspec
463 global fs4all
Johnny Chen9707bb62010-06-25 21:14:08 +0000464
465 for name in names:
466 if os.path.isdir(os.path.join(dir, name)):
467 continue
468
469 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
Johnny Chen7c52ff12010-09-27 23:29:54 +0000470 # Try to match the regexp pattern, if specified.
471 if regexp:
472 import re
473 if re.search(regexp, name):
474 #print "Filename: '%s' matches pattern: '%s'" % (name, regexp)
475 pass
476 else:
477 #print "Filename: '%s' does not match pattern: '%s'" % (name, regexp)
478 continue
479
Johnny Chen953864a2010-10-12 21:35:54 +0000480 # We found a match for our test. Add it to the suite.
Johnny Chen79723352010-10-12 15:53:22 +0000481
482 # Update the sys.path first.
Johnny Chena85d7ee2010-06-26 00:19:32 +0000483 if not sys.path.count(dir):
Johnny Chen548aefd2010-10-11 22:25:46 +0000484 sys.path.insert(0, dir)
Johnny Chen9707bb62010-06-25 21:14:08 +0000485 base = os.path.splitext(name)[0]
Johnny Chenb62436b2010-10-06 20:40:56 +0000486
487 # Thoroughly check the filterspec against the base module and admit
488 # the (base, filterspec) combination only when it makes sense.
489 if filterspec:
490 # Optimistically set the flag to True.
491 filtered = True
492 module = __import__(base)
493 parts = filterspec.split('.')
494 obj = module
495 for part in parts:
496 try:
497 parent, obj = obj, getattr(obj, part)
498 except AttributeError:
499 # The filterspec has failed.
500 filtered = False
501 break
502 # Forgo this module if the (base, filterspec) combo is invalid
Johnny Chena224cd12010-11-08 01:21:03 +0000503 # and no '-g' option is specified
Johnny Chenb62436b2010-10-06 20:40:56 +0000504 if fs4all and not filtered:
505 continue
506
Johnny Chen953864a2010-10-12 21:35:54 +0000507 # Add either the filtered test case or the entire test class.
Johnny Chenb62436b2010-10-06 20:40:56 +0000508 if filterspec and filtered:
509 suite.addTests(
510 unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
511 else:
512 # A simple case of just the module name. Also the failover case
513 # from the filterspec branch when the (base, filterspec) combo
514 # doesn't make sense.
515 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
Johnny Chen9707bb62010-06-25 21:14:08 +0000516
517
Johnny Chencd0279d2010-09-20 18:07:50 +0000518def lldbLoggings():
519 """Check and do lldb loggings if necessary."""
520
521 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
522 # defined. Use ${LLDB_LOG} to specify the log file.
523 ci = lldb.DBG.GetCommandInterpreter()
524 res = lldb.SBCommandReturnObject()
525 if ("LLDB_LOG" in os.environ):
526 if ("LLDB_LOG_OPTION" in os.environ):
527 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
528 else:
529 lldb_log_option = "event process"
530 ci.HandleCommand(
531 "log enable -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
532 res)
533 if not res.Succeeded():
534 raise Exception('log enable failed (check LLDB_LOG env variable.')
535 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
536 # Use ${GDB_REMOTE_LOG} to specify the log file.
537 if ("GDB_REMOTE_LOG" in os.environ):
538 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
539 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
540 else:
541 gdb_remote_log_option = "packets"
542 ci.HandleCommand(
543 "log enable -f " + os.environ["GDB_REMOTE_LOG"] + " process.gdb-remote "
544 + gdb_remote_log_option,
545 res)
546 if not res.Succeeded():
547 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
548
549
Johnny Chend96b5682010-11-05 17:30:53 +0000550# ======================================== #
Johnny Chencd0279d2010-09-20 18:07:50 +0000551# #
552# Execution of the test driver starts here #
553# #
Johnny Chend96b5682010-11-05 17:30:53 +0000554# ======================================== #
Johnny Chencd0279d2010-09-20 18:07:50 +0000555
Johnny Chen9707bb62010-06-25 21:14:08 +0000556#
Johnny Chenaf149a02010-09-16 17:11:30 +0000557# Start the actions by first parsing the options while setting up the test
558# directories, followed by setting up the search paths for lldb utilities;
559# then, we walk the directory trees and collect the tests into our test suite.
Johnny Chen9707bb62010-06-25 21:14:08 +0000560#
Johnny Chenaf149a02010-09-16 17:11:30 +0000561parseOptionsAndInitTestdirs()
Johnny Chen9707bb62010-06-25 21:14:08 +0000562setupSysPath()
Johnny Chen91960d32010-09-08 20:56:16 +0000563
564#
565# If '-d' is specified, do a delay of 10 seconds for the debugger to attach.
566#
567if delay:
Johnny Chencd0279d2010-09-20 18:07:50 +0000568 doDelay(10)
Johnny Chen91960d32010-09-08 20:56:16 +0000569
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000570#
Johnny Chen41998192010-10-01 22:59:49 +0000571# If '-l' is specified, do not skip the long running tests.
572if not skipLongRunningTest:
573 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
574
575#
Johnny Chen79723352010-10-12 15:53:22 +0000576# Walk through the testdirs while collecting tests.
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000577#
Johnny Chen9707bb62010-06-25 21:14:08 +0000578for testdir in testdirs:
579 os.path.walk(testdir, visit, 'Test')
580
Johnny Chenb40056b2010-09-21 00:09:27 +0000581#
Johnny Chen9707bb62010-06-25 21:14:08 +0000582# Now that we have loaded all the test cases, run the whole test suite.
Johnny Chenb40056b2010-09-21 00:09:27 +0000583#
Johnny Chencd0279d2010-09-20 18:07:50 +0000584
Johnny Chen1bfbd412010-06-29 19:44:16 +0000585# For the time being, let's bracket the test runner within the
586# lldb.SBDebugger.Initialize()/Terminate() pair.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000587import lldb, atexit
Johnny Chen6b6f5ba2010-10-14 16:36:49 +0000588# Update: the act of importing lldb now executes lldb.SBDebugger.Initialize(),
589# there's no need to call it a second time.
590#lldb.SBDebugger.Initialize()
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000591atexit.register(lambda: lldb.SBDebugger.Terminate())
Johnny Chen1bfbd412010-06-29 19:44:16 +0000592
Johnny Chen909e5a62010-07-01 22:52:57 +0000593# Create a singleton SBDebugger in the lldb namespace.
594lldb.DBG = lldb.SBDebugger.Create()
595
Johnny Chencd0279d2010-09-20 18:07:50 +0000596# Turn on lldb loggings if necessary.
597lldbLoggings()
Johnny Chen909e5a62010-07-01 22:52:57 +0000598
Johnny Chen7987ac92010-08-09 20:40:52 +0000599# Install the control-c handler.
600unittest2.signals.installHandler()
601
Johnny Chen125fc2b2010-10-21 16:55:35 +0000602# If sdir_name is not specified through the '-s sdir_name' option, get a
603# timestamp string and export it as LLDB_SESSION_DIR environment var. This will
604# be used when/if we want to dump the session info of individual test cases
605# later on.
Johnny Chence681462010-10-19 00:25:01 +0000606#
607# See also TestBase.dumpSessionInfo() in lldbtest.py.
Johnny Chen125fc2b2010-10-21 16:55:35 +0000608if not sdir_name:
609 import datetime
Johnny Chen41fae812010-10-29 22:26:38 +0000610 # The windows platforms don't like ':' in the pathname.
Johnny Chen76bd0102010-10-28 16:32:13 +0000611 timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
Johnny Chen125fc2b2010-10-21 16:55:35 +0000612 sdir_name = timestamp
613os.environ["LLDB_SESSION_DIRNAME"] = sdir_name
Johnny Chen47c47c42010-11-09 23:42:00 +0000614sys.stderr.write("\nSession logs for test failures/errors will go into directory '%s'\n" % sdir_name)
Johnny Chence681462010-10-19 00:25:01 +0000615
Johnny Chenb40056b2010-09-21 00:09:27 +0000616#
617# Invoke the default TextTestRunner to run the test suite, possibly iterating
618# over different configurations.
619#
620
Johnny Chenb40056b2010-09-21 00:09:27 +0000621iterArchs = False
Johnny Chenf032d902010-09-21 00:16:09 +0000622iterCompilers = False
Johnny Chenb40056b2010-09-21 00:09:27 +0000623
624from types import *
625if "archs" in config:
626 archs = config["archs"]
627 if type(archs) is ListType and len(archs) >= 1:
628 iterArchs = True
629if "compilers" in config:
630 compilers = config["compilers"]
631 if type(compilers) is ListType and len(compilers) >= 1:
632 iterCompilers = True
633
Johnny Chen953864a2010-10-12 21:35:54 +0000634# Make a shallow copy of sys.path, we need to manipulate the search paths later.
635# This is only necessary if we are relocated and with different configurations.
636if rdir and (iterArchs or iterCompilers):
637 old_sys_path = sys.path[:]
638 old_stderr = sys.stderr
639 old_stdout = sys.stdout
640 new_stderr = None
641 new_stdout = None
642
Johnny Chend96b5682010-11-05 17:30:53 +0000643# Iterating over all possible architecture and compiler combinations.
Johnny Chenb40056b2010-09-21 00:09:27 +0000644for ia in range(len(archs) if iterArchs else 1):
645 archConfig = ""
646 if iterArchs:
Johnny Chen18a921f2010-09-30 17:11:58 +0000647 os.environ["ARCH"] = archs[ia]
Johnny Chenb40056b2010-09-21 00:09:27 +0000648 archConfig = "arch=%s" % archs[ia]
649 for ic in range(len(compilers) if iterCompilers else 1):
650 if iterCompilers:
Johnny Chen18a921f2010-09-30 17:11:58 +0000651 os.environ["CC"] = compilers[ic]
Johnny Chenb40056b2010-09-21 00:09:27 +0000652 configString = "%s compiler=%s" % (archConfig, compilers[ic])
653 else:
654 configString = archConfig
655
Johnny Chenb40056b2010-09-21 00:09:27 +0000656 if iterArchs or iterCompilers:
Johnny Chen953864a2010-10-12 21:35:54 +0000657 # If we specified a relocated directory to run the test suite, do
658 # the extra housekeeping to copy the testdirs to a configStringified
659 # directory and to update sys.path before invoking the test runner.
660 # The purpose is to separate the configuration-specific directories
661 # from each other.
662 if rdir:
663 from string import maketrans
664 from shutil import copytree, ignore_patterns
665
666 # Translate ' ' to '-' for dir name.
667 tbl = maketrans(' ', '-')
668 configPostfix = configString.translate(tbl)
669 newrdir = "%s.%s" % (rdir, configPostfix)
670
671 # Copy the tree to a new directory with postfix name configPostfix.
672 copytree(rdir, newrdir, ignore=ignore_patterns('*.pyc', '*.o', '*.d'))
673
674 # Check whether we need to split stderr/stdout into configuration
675 # specific files.
676 if old_stderr.name != '<stderr>' and config.get('split_stderr'):
677 if new_stderr:
678 new_stderr.close()
679 new_stderr = open("%s.%s" % (old_stderr.name, configPostfix), "w")
680 sys.stderr = new_stderr
Johnny Chen4b6630e2010-10-12 21:50:36 +0000681 if old_stdout.name != '<stdout>' and config.get('split_stdout'):
Johnny Chen953864a2010-10-12 21:35:54 +0000682 if new_stdout:
683 new_stdout.close()
684 new_stdout = open("%s.%s" % (old_stdout.name, configPostfix), "w")
685 sys.stdout = new_stdout
686
687 # Update the LLDB_TEST environment variable to reflect new top
688 # level test directory.
689 #
690 # See also lldbtest.TestBase.setUpClass(cls).
691 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
692 os.environ["LLDB_TEST"] = os.path.join(newrdir, 'test')
693 else:
694 os.environ["LLDB_TEST"] = newrdir
695
696 # And update the Python search paths for modules.
697 sys.path = [x.replace(rdir, newrdir, 1) for x in old_sys_path]
698
699 # Output the configuration.
Johnny Chenb40056b2010-09-21 00:09:27 +0000700 sys.stderr.write("\nConfiguration: " + configString + "\n")
Johnny Chen953864a2010-10-12 21:35:54 +0000701
702 #print "sys.stderr name is", sys.stderr.name
703 #print "sys.stdout name is", sys.stdout.name
704
705 # First, write out the number of collected test cases.
706 sys.stderr.write(separator + "\n")
707 sys.stderr.write("Collected %d test%s\n\n"
708 % (suite.countTestCases(),
709 suite.countTestCases() != 1 and "s" or ""))
710
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000711 class LLDBTestResult(unittest2.TextTestResult):
712 """
Johnny Chen26be4532010-11-09 23:56:14 +0000713 Enforce a singleton pattern to allow introspection of test progress.
714
715 Overwrite addError(), addFailure(), and addExpectedFailure() methods
716 to enable each test instance to track its failure/error status. It
717 is used in the LLDB test framework to emit detailed trace messages
718 to a log file for easier human inspection of test failres/errors.
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000719 """
720 __singleton__ = None
Johnny Chen360dd372010-11-29 17:50:10 +0000721 __ignore_singleton__ = False
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000722
723 def __init__(self, *args):
Johnny Chen360dd372010-11-29 17:50:10 +0000724 if not LLDBTestResult.__ignore_singleton__ and LLDBTestResult.__singleton__:
Johnny Chend2acdb32010-11-16 22:42:58 +0000725 raise Exception("LLDBTestResult instantiated more than once")
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000726 super(LLDBTestResult, self).__init__(*args)
727 LLDBTestResult.__singleton__ = self
728 # Now put this singleton into the lldb module namespace.
729 lldb.test_result = self
730
Johnny Chence681462010-10-19 00:25:01 +0000731 def addError(self, test, err):
Johnny Chen63c2cba2010-10-29 22:20:36 +0000732 global sdir_has_content
733 sdir_has_content = True
Johnny Chence681462010-10-19 00:25:01 +0000734 super(LLDBTestResult, self).addError(test, err)
735 method = getattr(test, "markError", None)
736 if method:
737 method()
738
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000739 def addFailure(self, test, err):
Johnny Chen63c2cba2010-10-29 22:20:36 +0000740 global sdir_has_content
741 sdir_has_content = True
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000742 super(LLDBTestResult, self).addFailure(test, err)
743 method = getattr(test, "markFailure", None)
744 if method:
745 method()
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000746
Johnny Chendd2bb2c2010-11-03 18:17:03 +0000747 def addExpectedFailure(self, test, err):
748 global sdir_has_content
749 sdir_has_content = True
750 super(LLDBTestResult, self).addExpectedFailure(test, err)
751 method = getattr(test, "markExpectedFailure", None)
752 if method:
753 method()
754
Johnny Chen26be4532010-11-09 23:56:14 +0000755 # Invoke the test runner.
Johnny Chend2acdb32010-11-16 22:42:58 +0000756 if count == 1:
757 result = unittest2.TextTestRunner(stream=sys.stderr, verbosity=verbose,
758 resultclass=LLDBTestResult).run(suite)
759 else:
Johnny Chend6e7ca22010-11-29 17:52:43 +0000760 # We are invoking the same test suite more than once. In this case,
761 # mark __ignore_singleton__ flag as True so the signleton pattern is
762 # not enforced.
Johnny Chen360dd372010-11-29 17:50:10 +0000763 LLDBTestResult.__ignore_singleton__ = True
Johnny Chend2acdb32010-11-16 22:42:58 +0000764 for i in range(count):
Johnny Chen360dd372010-11-29 17:50:10 +0000765 result = unittest2.TextTestRunner(stream=sys.stderr, verbosity=verbose,
766 resultclass=LLDBTestResult).run(suite)
Johnny Chenb40056b2010-09-21 00:09:27 +0000767
Johnny Chen1bfbd412010-06-29 19:44:16 +0000768
Johnny Chen63c2cba2010-10-29 22:20:36 +0000769if sdir_has_content:
Johnny Chen47c47c42010-11-09 23:42:00 +0000770 sys.stderr.write("Session logs for test failures/errors can be found in directory '%s'\n" % sdir_name)
Johnny Chen63c2cba2010-10-29 22:20:36 +0000771
Johnny Chencd0279d2010-09-20 18:07:50 +0000772# Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
773# This should not be necessary now.
Johnny Chen83f6e512010-08-13 22:58:44 +0000774if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
775 import subprocess
776 print "Terminating Test suite..."
777 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
778
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000779# Exiting.
780sys.exit(not result.wasSuccessful)