blob: bb32146dc36ec3ee6e45a7861ef1a240b4d9ac9f [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 Chenb40056b2010-09-21 00:09:27 +000051# The dictionary as a result of sourcing configFile.
52config = {}
53
Johnny Chen91960d32010-09-08 20:56:16 +000054# Delay startup in order for the debugger to attach.
55delay = False
56
Johnny Chena224cd12010-11-08 01:21:03 +000057# The filter (testclass.testmethod) used to admit tests into our test suite.
Johnny Chenb62436b2010-10-06 20:40:56 +000058filterspec = None
59
Johnny Chena224cd12010-11-08 01:21:03 +000060# If '-g' is specified, the filterspec is not exclusive. If a test module does
61# not contain testclass.testmethod which matches the filterspec, the whole test
62# module is still admitted into our test suite. fs4all flag defaults to True.
63fs4all = True
Johnny Chenb62436b2010-10-06 20:40:56 +000064
Johnny Chenaf149a02010-09-16 17:11:30 +000065# Ignore the build search path relative to this script to locate the lldb.py module.
66ignore = False
67
Johnny Chen548aefd2010-10-11 22:25:46 +000068# By default, we skip long running test case. Use '-l' option to override.
Johnny Chen41998192010-10-01 22:59:49 +000069skipLongRunningTest = True
70
Johnny Chen7c52ff12010-09-27 23:29:54 +000071# The regular expression pattern to match against eligible filenames as our test cases.
72regexp = None
73
Johnny Chen548aefd2010-10-11 22:25:46 +000074# By default, tests are executed in place and cleanups are performed afterwards.
75# Use '-r dir' option to relocate the tests and their intermediate files to a
76# different directory and to forgo any cleanups. The directory specified must
77# not exist yet.
78rdir = None
79
Johnny Chen125fc2b2010-10-21 16:55:35 +000080# By default, recorded session info for errored/failed test are dumped into its
81# own file under a session directory named after the timestamp of the test suite
82# run. Use '-s session-dir-name' to specify a specific dir name.
83sdir_name = None
84
Johnny Chen63c2cba2010-10-29 22:20:36 +000085# Set this flag if there is any session info dumped during the test run.
86sdir_has_content = False
87
Johnny Chen9707bb62010-06-25 21:14:08 +000088# Default verbosity is 0.
89verbose = 0
90
91# By default, search from the current working directory.
92testdirs = [ os.getcwd() ]
93
Johnny Chen877c7e42010-08-07 00:16:07 +000094# Separator string.
95separator = '-' * 70
96
Johnny Chen9707bb62010-06-25 21:14:08 +000097
98def usage():
99 print """
100Usage: dotest.py [option] [args]
101where options:
102-h : print this help message and exit (also --help)
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000103-c : read a config file specified after this option
Johnny Chenb40056b2010-09-21 00:09:27 +0000104 (see also lldb-trunk/example/test/usage-config)
Johnny Chen91960d32010-09-08 20:56:16 +0000105-d : delay startup for 10 seconds (in order for the debugger to attach)
Johnny Chen46be75d2010-10-11 16:19:48 +0000106-f : specify a filter, which consists of the test class name, a dot, followed by
Johnny Chen1a6e92a2010-11-08 20:17:04 +0000107 the test method, to only admit such test into the test suite
Johnny Chenb62436b2010-10-06 20:40:56 +0000108 e.g., -f 'ClassTypesTestCase.test_with_dwarf_and_python_api'
Johnny Chena224cd12010-11-08 01:21:03 +0000109-g : if specified, the filterspec by -f is not exclusive, i.e., if a test module
110 does not match the filterspec (testclass.testmethod), the whole module is
111 still admitted to the test suite
Johnny Chenaf149a02010-09-16 17:11:30 +0000112-i : ignore (don't bailout) if 'lldb.py' module cannot be located in the build
113 tree relative to this script; use PYTHONPATH to locate the module
Johnny Chen41998192010-10-01 22:59:49 +0000114-l : don't skip long running test
Johnny Chen7c52ff12010-09-27 23:29:54 +0000115-p : specify a regexp filename pattern for inclusion in the test suite
Johnny Chen548aefd2010-10-11 22:25:46 +0000116-r : specify a dir to relocate the tests and their intermediate files to;
117 the directory must not exist before running this test driver;
118 no cleanup of intermediate test files is performed in this case
Johnny Chen125fc2b2010-10-21 16:55:35 +0000119-s : specify the name of the dir created to store the session files of tests
120 with errored or failed status; if not specified, the test driver uses the
121 timestamp as the session dir name
Johnny Chend0c24b22010-08-23 17:10:44 +0000122-t : trace lldb command execution and result
Johnny Chen9707bb62010-06-25 21:14:08 +0000123-v : do verbose mode of unittest framework
Johnny Chene47649c2010-10-07 02:04:14 +0000124-w : insert some wait time (currently 0.5 sec) between consecutive test cases
Johnny Chen9707bb62010-06-25 21:14:08 +0000125
126and:
Johnny Chen9656ab22010-10-22 19:00:18 +0000127args : specify a list of directory names to search for test modules named after
128 Test*.py (test discovery)
Johnny Chen9707bb62010-06-25 21:14:08 +0000129 if empty, search from the curret working directory, instead
Johnny Chen58f93922010-06-29 23:10:39 +0000130
Johnny Chen9656ab22010-10-22 19:00:18 +0000131Examples:
132
Johnny Chena224cd12010-11-08 01:21:03 +0000133This is an example of using the -f option to pinpoint to a specfic test class
134and test method to be run:
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000135
Johnny Chena224cd12010-11-08 01:21:03 +0000136$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000137----------------------------------------------------------------------
138Collected 1 test
139
140test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
141Test 'frame variable this' when stopped on a class constructor. ... ok
142
143----------------------------------------------------------------------
144Ran 1 test in 1.396s
145
146OK
Johnny Chen9656ab22010-10-22 19:00:18 +0000147
148And this is an example of using the -p option to run a single file (the filename
149matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
150
151$ ./dotest.py -v -p ObjC
152----------------------------------------------------------------------
153Collected 4 tests
154
155test_break_with_dsym (TestObjCMethods.FoundationTestCase)
156Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'. ... ok
157test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
158Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'. ... ok
159test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
160Lookup objective-c data types and evaluate expressions. ... ok
161test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
162Lookup objective-c data types and evaluate expressions. ... ok
163
164----------------------------------------------------------------------
165Ran 4 tests in 16.661s
166
167OK
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000168
Johnny Chen58f93922010-06-29 23:10:39 +0000169Running of this script also sets up the LLDB_TEST environment variable so that
Johnny Chenaf149a02010-09-16 17:11:30 +0000170individual test cases can locate their supporting files correctly. The script
171tries to set up Python's search paths for modules by looking at the build tree
172relative to this script. See also the '-i' option.
Johnny Chenfde69bc2010-09-14 22:01:40 +0000173
174Environment variables related to loggings:
175
176o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
177 with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
178
179o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
180 'process.gdb-remote' subsystem with a default option of 'packets' if
181 GDB_REMOTE_LOG_OPTION is not defined.
Johnny Chen9707bb62010-06-25 21:14:08 +0000182"""
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000183 sys.exit(0)
Johnny Chen9707bb62010-06-25 21:14:08 +0000184
185
Johnny Chenaf149a02010-09-16 17:11:30 +0000186def parseOptionsAndInitTestdirs():
187 """Initialize the list of directories containing our unittest scripts.
188
189 '-h/--help as the first option prints out usage info and exit the program.
190 """
191
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000192 global configFile
Johnny Chenaf149a02010-09-16 17:11:30 +0000193 global delay
Johnny Chenb62436b2010-10-06 20:40:56 +0000194 global filterspec
195 global fs4all
Johnny Chen7c52ff12010-09-27 23:29:54 +0000196 global ignore
Johnny Chen41998192010-10-01 22:59:49 +0000197 global skipLongRunningTest
Johnny Chen7c52ff12010-09-27 23:29:54 +0000198 global regexp
Johnny Chen548aefd2010-10-11 22:25:46 +0000199 global rdir
Johnny Chen125fc2b2010-10-21 16:55:35 +0000200 global sdir_name
Johnny Chenaf149a02010-09-16 17:11:30 +0000201 global verbose
202 global testdirs
203
204 if len(sys.argv) == 1:
205 return
206
207 # Process possible trace and/or verbose flag, among other things.
208 index = 1
Johnny Chence2212c2010-10-07 15:41:55 +0000209 while index < len(sys.argv):
Johnny Chenaf149a02010-09-16 17:11:30 +0000210 if not sys.argv[index].startswith('-'):
211 # End of option processing.
212 break
213
214 if sys.argv[index].find('-h') != -1:
215 usage()
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000216 elif sys.argv[index].startswith('-c'):
217 # Increment by 1 to fetch the config file name option argument.
218 index += 1
219 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
220 usage()
221 configFile = sys.argv[index]
222 if not os.path.isfile(configFile):
223 print "Config file:", configFile, "does not exist!"
224 usage()
225 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000226 elif sys.argv[index].startswith('-d'):
227 delay = True
228 index += 1
Johnny Chenb62436b2010-10-06 20:40:56 +0000229 elif sys.argv[index].startswith('-f'):
230 # Increment by 1 to fetch the filter spec.
231 index += 1
232 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
233 usage()
234 filterspec = sys.argv[index]
235 index += 1
236 elif sys.argv[index].startswith('-g'):
Johnny Chena224cd12010-11-08 01:21:03 +0000237 fs4all = False
Johnny Chenb62436b2010-10-06 20:40:56 +0000238 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000239 elif sys.argv[index].startswith('-i'):
240 ignore = True
241 index += 1
Johnny Chen41998192010-10-01 22:59:49 +0000242 elif sys.argv[index].startswith('-l'):
243 skipLongRunningTest = False
244 index += 1
Johnny Chen7c52ff12010-09-27 23:29:54 +0000245 elif sys.argv[index].startswith('-p'):
246 # Increment by 1 to fetch the reg exp pattern argument.
247 index += 1
248 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
249 usage()
250 regexp = sys.argv[index]
251 index += 1
Johnny Chen548aefd2010-10-11 22:25:46 +0000252 elif sys.argv[index].startswith('-r'):
253 # Increment by 1 to fetch the relocated directory argument.
254 index += 1
255 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
256 usage()
257 rdir = os.path.abspath(sys.argv[index])
258 if os.path.exists(rdir):
259 print "Relocated directory:", rdir, "must not exist!"
260 usage()
261 index += 1
Johnny Chen125fc2b2010-10-21 16:55:35 +0000262 elif sys.argv[index].startswith('-s'):
263 # Increment by 1 to fetch the session dir name.
264 index += 1
265 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
266 usage()
267 sdir_name = sys.argv[index]
268 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000269 elif sys.argv[index].startswith('-t'):
270 os.environ["LLDB_COMMAND_TRACE"] = "YES"
271 index += 1
272 elif sys.argv[index].startswith('-v'):
273 verbose = 2
274 index += 1
Johnny Chene47649c2010-10-07 02:04:14 +0000275 elif sys.argv[index].startswith('-w'):
276 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] = 'YES'
277 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000278 else:
279 print "Unknown option: ", sys.argv[index]
280 usage()
Johnny Chenaf149a02010-09-16 17:11:30 +0000281
282 # Gather all the dirs passed on the command line.
283 if len(sys.argv) > index:
284 testdirs = map(os.path.abspath, sys.argv[index:])
285
Johnny Chen548aefd2010-10-11 22:25:46 +0000286 # If '-r dir' is specified, the tests should be run under the relocated
287 # directory. Let's copy the testdirs over.
288 if rdir:
289 from shutil import copytree, ignore_patterns
290
291 tmpdirs = []
292 for srcdir in testdirs:
293 dstdir = os.path.join(rdir, os.path.basename(srcdir))
294 # Don't copy the *.pyc and .svn stuffs.
295 copytree(srcdir, dstdir, ignore=ignore_patterns('*.pyc', '.svn'))
296 tmpdirs.append(dstdir)
297
298 # This will be our modified testdirs.
299 testdirs = tmpdirs
300
301 # With '-r dir' specified, there's no cleanup of intermediate test files.
302 os.environ["LLDB_DO_CLEANUP"] = 'NO'
303
304 # If testdirs is ['test'], the make directory has already been copied
305 # recursively and is contained within the rdir/test dir. For anything
306 # else, we would need to copy over the make directory and its contents,
307 # so that, os.listdir(rdir) looks like, for example:
308 #
309 # array_types conditional_break make
310 #
311 # where the make directory contains the Makefile.rules file.
312 if len(testdirs) != 1 or os.path.basename(testdirs[0]) != 'test':
313 # Don't copy the .svn stuffs.
314 copytree('make', os.path.join(rdir, 'make'),
315 ignore=ignore_patterns('.svn'))
316
317 #print "testdirs:", testdirs
318
Johnny Chenb40056b2010-09-21 00:09:27 +0000319 # Source the configFile if specified.
320 # The side effect, if any, will be felt from this point on. An example
321 # config file may be these simple two lines:
322 #
323 # sys.stderr = open("/tmp/lldbtest-stderr", "w")
324 # sys.stdout = open("/tmp/lldbtest-stdout", "w")
325 #
326 # which will reassign the two file objects to sys.stderr and sys.stdout,
327 # respectively.
328 #
329 # See also lldb-trunk/example/test/usage-config.
330 global config
331 if configFile:
332 # Pass config (a dictionary) as the locals namespace for side-effect.
333 execfile(configFile, globals(), config)
334 #print "config:", config
335 #print "sys.stderr:", sys.stderr
336 #print "sys.stdout:", sys.stdout
337
Johnny Chenaf149a02010-09-16 17:11:30 +0000338
Johnny Chen9707bb62010-06-25 21:14:08 +0000339def setupSysPath():
340 """Add LLDB.framework/Resources/Python to the search paths for modules."""
341
Johnny Chen548aefd2010-10-11 22:25:46 +0000342 global rdir
343 global testdirs
344
Johnny Chen9707bb62010-06-25 21:14:08 +0000345 # Get the directory containing the current script.
Johnny Chena1affab2010-07-03 03:41:59 +0000346 scriptPath = sys.path[0]
347 if not scriptPath.endswith('test'):
Johnny Chen9707bb62010-06-25 21:14:08 +0000348 print "This script expects to reside in lldb's test directory."
349 sys.exit(-1)
350
Johnny Chen548aefd2010-10-11 22:25:46 +0000351 if rdir:
352 # Set up the LLDB_TEST environment variable appropriately, so that the
353 # individual tests can be located relatively.
354 #
355 # See also lldbtest.TestBase.setUpClass(cls).
356 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
357 os.environ["LLDB_TEST"] = os.path.join(rdir, 'test')
358 else:
359 os.environ["LLDB_TEST"] = rdir
360 else:
361 os.environ["LLDB_TEST"] = scriptPath
Johnny Chen9de4ede2010-08-31 17:42:54 +0000362 pluginPath = os.path.join(scriptPath, 'plugins')
Johnny Chen58f93922010-06-29 23:10:39 +0000363
Johnny Chenaf149a02010-09-16 17:11:30 +0000364 # Append script dir and plugin dir to the sys.path.
365 sys.path.append(scriptPath)
366 sys.path.append(pluginPath)
367
368 global ignore
369
370 # The '-i' option is used to skip looking for lldb.py in the build tree.
371 if ignore:
372 return
373
Johnny Chena1affab2010-07-03 03:41:59 +0000374 base = os.path.abspath(os.path.join(scriptPath, os.pardir))
Johnny Chen9707bb62010-06-25 21:14:08 +0000375 dbgPath = os.path.join(base, 'build', 'Debug', 'LLDB.framework',
376 'Resources', 'Python')
377 relPath = os.path.join(base, 'build', 'Release', 'LLDB.framework',
378 'Resources', 'Python')
Johnny Chenc202c462010-09-15 18:11:19 +0000379 baiPath = os.path.join(base, 'build', 'BuildAndIntegration',
380 'LLDB.framework', 'Resources', 'Python')
Johnny Chen9707bb62010-06-25 21:14:08 +0000381
382 lldbPath = None
383 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
384 lldbPath = dbgPath
385 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
386 lldbPath = relPath
Johnny Chenc202c462010-09-15 18:11:19 +0000387 elif os.path.isfile(os.path.join(baiPath, 'lldb.py')):
388 lldbPath = baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000389
390 if not lldbPath:
Johnny Chenc202c462010-09-15 18:11:19 +0000391 print 'This script requires lldb.py to be in either ' + dbgPath + ',',
392 print relPath + ', or ' + baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000393 sys.exit(-1)
394
Johnny Chenaf149a02010-09-16 17:11:30 +0000395 # This is to locate the lldb.py module. Insert it right after sys.path[0].
396 sys.path[1:1] = [lldbPath]
Johnny Chen9707bb62010-06-25 21:14:08 +0000397
Johnny Chen9707bb62010-06-25 21:14:08 +0000398
Johnny Chencd0279d2010-09-20 18:07:50 +0000399def doDelay(delta):
400 """Delaying startup for delta-seconds to facilitate debugger attachment."""
401 def alarm_handler(*args):
402 raise Exception("timeout")
403
404 signal.signal(signal.SIGALRM, alarm_handler)
405 signal.alarm(delta)
406 sys.stdout.write("pid=%d\n" % os.getpid())
407 sys.stdout.write("Enter RET to proceed (or timeout after %d seconds):" %
408 delta)
409 sys.stdout.flush()
410 try:
411 text = sys.stdin.readline()
412 except:
413 text = ""
414 signal.alarm(0)
415 sys.stdout.write("proceeding...\n")
416 pass
417
418
Johnny Chen9707bb62010-06-25 21:14:08 +0000419def visit(prefix, dir, names):
420 """Visitor function for os.path.walk(path, visit, arg)."""
421
422 global suite
Johnny Chen7c52ff12010-09-27 23:29:54 +0000423 global regexp
Johnny Chenb62436b2010-10-06 20:40:56 +0000424 global filterspec
425 global fs4all
Johnny Chen9707bb62010-06-25 21:14:08 +0000426
427 for name in names:
428 if os.path.isdir(os.path.join(dir, name)):
429 continue
430
431 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
Johnny Chen7c52ff12010-09-27 23:29:54 +0000432 # Try to match the regexp pattern, if specified.
433 if regexp:
434 import re
435 if re.search(regexp, name):
436 #print "Filename: '%s' matches pattern: '%s'" % (name, regexp)
437 pass
438 else:
439 #print "Filename: '%s' does not match pattern: '%s'" % (name, regexp)
440 continue
441
Johnny Chen953864a2010-10-12 21:35:54 +0000442 # We found a match for our test. Add it to the suite.
Johnny Chen79723352010-10-12 15:53:22 +0000443
444 # Update the sys.path first.
Johnny Chena85d7ee2010-06-26 00:19:32 +0000445 if not sys.path.count(dir):
Johnny Chen548aefd2010-10-11 22:25:46 +0000446 sys.path.insert(0, dir)
Johnny Chen9707bb62010-06-25 21:14:08 +0000447 base = os.path.splitext(name)[0]
Johnny Chenb62436b2010-10-06 20:40:56 +0000448
449 # Thoroughly check the filterspec against the base module and admit
450 # the (base, filterspec) combination only when it makes sense.
451 if filterspec:
452 # Optimistically set the flag to True.
453 filtered = True
454 module = __import__(base)
455 parts = filterspec.split('.')
456 obj = module
457 for part in parts:
458 try:
459 parent, obj = obj, getattr(obj, part)
460 except AttributeError:
461 # The filterspec has failed.
462 filtered = False
463 break
464 # Forgo this module if the (base, filterspec) combo is invalid
Johnny Chena224cd12010-11-08 01:21:03 +0000465 # and no '-g' option is specified
Johnny Chenb62436b2010-10-06 20:40:56 +0000466 if fs4all and not filtered:
467 continue
468
Johnny Chen953864a2010-10-12 21:35:54 +0000469 # Add either the filtered test case or the entire test class.
Johnny Chenb62436b2010-10-06 20:40:56 +0000470 if filterspec and filtered:
471 suite.addTests(
472 unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
473 else:
474 # A simple case of just the module name. Also the failover case
475 # from the filterspec branch when the (base, filterspec) combo
476 # doesn't make sense.
477 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
Johnny Chen9707bb62010-06-25 21:14:08 +0000478
479
Johnny Chencd0279d2010-09-20 18:07:50 +0000480def lldbLoggings():
481 """Check and do lldb loggings if necessary."""
482
483 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
484 # defined. Use ${LLDB_LOG} to specify the log file.
485 ci = lldb.DBG.GetCommandInterpreter()
486 res = lldb.SBCommandReturnObject()
487 if ("LLDB_LOG" in os.environ):
488 if ("LLDB_LOG_OPTION" in os.environ):
489 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
490 else:
491 lldb_log_option = "event process"
492 ci.HandleCommand(
493 "log enable -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
494 res)
495 if not res.Succeeded():
496 raise Exception('log enable failed (check LLDB_LOG env variable.')
497 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
498 # Use ${GDB_REMOTE_LOG} to specify the log file.
499 if ("GDB_REMOTE_LOG" in os.environ):
500 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
501 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
502 else:
503 gdb_remote_log_option = "packets"
504 ci.HandleCommand(
505 "log enable -f " + os.environ["GDB_REMOTE_LOG"] + " process.gdb-remote "
506 + gdb_remote_log_option,
507 res)
508 if not res.Succeeded():
509 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
510
511
Johnny Chend96b5682010-11-05 17:30:53 +0000512# ======================================== #
Johnny Chencd0279d2010-09-20 18:07:50 +0000513# #
514# Execution of the test driver starts here #
515# #
Johnny Chend96b5682010-11-05 17:30:53 +0000516# ======================================== #
Johnny Chencd0279d2010-09-20 18:07:50 +0000517
Johnny Chen9707bb62010-06-25 21:14:08 +0000518#
Johnny Chenaf149a02010-09-16 17:11:30 +0000519# Start the actions by first parsing the options while setting up the test
520# directories, followed by setting up the search paths for lldb utilities;
521# then, we walk the directory trees and collect the tests into our test suite.
Johnny Chen9707bb62010-06-25 21:14:08 +0000522#
Johnny Chenaf149a02010-09-16 17:11:30 +0000523parseOptionsAndInitTestdirs()
Johnny Chen9707bb62010-06-25 21:14:08 +0000524setupSysPath()
Johnny Chen91960d32010-09-08 20:56:16 +0000525
526#
527# If '-d' is specified, do a delay of 10 seconds for the debugger to attach.
528#
529if delay:
Johnny Chencd0279d2010-09-20 18:07:50 +0000530 doDelay(10)
Johnny Chen91960d32010-09-08 20:56:16 +0000531
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000532#
Johnny Chen41998192010-10-01 22:59:49 +0000533# If '-l' is specified, do not skip the long running tests.
534if not skipLongRunningTest:
535 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
536
537#
Johnny Chen79723352010-10-12 15:53:22 +0000538# Walk through the testdirs while collecting tests.
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000539#
Johnny Chen9707bb62010-06-25 21:14:08 +0000540for testdir in testdirs:
541 os.path.walk(testdir, visit, 'Test')
542
Johnny Chenb40056b2010-09-21 00:09:27 +0000543#
Johnny Chen9707bb62010-06-25 21:14:08 +0000544# Now that we have loaded all the test cases, run the whole test suite.
Johnny Chenb40056b2010-09-21 00:09:27 +0000545#
Johnny Chencd0279d2010-09-20 18:07:50 +0000546
Johnny Chen1bfbd412010-06-29 19:44:16 +0000547# For the time being, let's bracket the test runner within the
548# lldb.SBDebugger.Initialize()/Terminate() pair.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000549import lldb, atexit
Johnny Chen6b6f5ba2010-10-14 16:36:49 +0000550# Update: the act of importing lldb now executes lldb.SBDebugger.Initialize(),
551# there's no need to call it a second time.
552#lldb.SBDebugger.Initialize()
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000553atexit.register(lambda: lldb.SBDebugger.Terminate())
Johnny Chen1bfbd412010-06-29 19:44:16 +0000554
Johnny Chen909e5a62010-07-01 22:52:57 +0000555# Create a singleton SBDebugger in the lldb namespace.
556lldb.DBG = lldb.SBDebugger.Create()
557
Johnny Chencd0279d2010-09-20 18:07:50 +0000558# Turn on lldb loggings if necessary.
559lldbLoggings()
Johnny Chen909e5a62010-07-01 22:52:57 +0000560
Johnny Chen7987ac92010-08-09 20:40:52 +0000561# Install the control-c handler.
562unittest2.signals.installHandler()
563
Johnny Chen125fc2b2010-10-21 16:55:35 +0000564# If sdir_name is not specified through the '-s sdir_name' option, get a
565# timestamp string and export it as LLDB_SESSION_DIR environment var. This will
566# be used when/if we want to dump the session info of individual test cases
567# later on.
Johnny Chence681462010-10-19 00:25:01 +0000568#
569# See also TestBase.dumpSessionInfo() in lldbtest.py.
Johnny Chen125fc2b2010-10-21 16:55:35 +0000570if not sdir_name:
571 import datetime
Johnny Chen41fae812010-10-29 22:26:38 +0000572 # The windows platforms don't like ':' in the pathname.
Johnny Chen76bd0102010-10-28 16:32:13 +0000573 timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
Johnny Chen125fc2b2010-10-21 16:55:35 +0000574 sdir_name = timestamp
575os.environ["LLDB_SESSION_DIRNAME"] = sdir_name
Johnny Chen47c47c42010-11-09 23:42:00 +0000576sys.stderr.write("\nSession logs for test failures/errors will go into directory '%s'\n" % sdir_name)
Johnny Chence681462010-10-19 00:25:01 +0000577
Johnny Chenb40056b2010-09-21 00:09:27 +0000578#
579# Invoke the default TextTestRunner to run the test suite, possibly iterating
580# over different configurations.
581#
582
Johnny Chenb40056b2010-09-21 00:09:27 +0000583iterArchs = False
Johnny Chenf032d902010-09-21 00:16:09 +0000584iterCompilers = False
Johnny Chenb40056b2010-09-21 00:09:27 +0000585
586from types import *
587if "archs" in config:
588 archs = config["archs"]
589 if type(archs) is ListType and len(archs) >= 1:
590 iterArchs = True
591if "compilers" in config:
592 compilers = config["compilers"]
593 if type(compilers) is ListType and len(compilers) >= 1:
594 iterCompilers = True
595
Johnny Chen953864a2010-10-12 21:35:54 +0000596# Make a shallow copy of sys.path, we need to manipulate the search paths later.
597# This is only necessary if we are relocated and with different configurations.
598if rdir and (iterArchs or iterCompilers):
599 old_sys_path = sys.path[:]
600 old_stderr = sys.stderr
601 old_stdout = sys.stdout
602 new_stderr = None
603 new_stdout = None
604
Johnny Chend96b5682010-11-05 17:30:53 +0000605# Iterating over all possible architecture and compiler combinations.
Johnny Chenb40056b2010-09-21 00:09:27 +0000606for ia in range(len(archs) if iterArchs else 1):
607 archConfig = ""
608 if iterArchs:
Johnny Chen18a921f2010-09-30 17:11:58 +0000609 os.environ["ARCH"] = archs[ia]
Johnny Chenb40056b2010-09-21 00:09:27 +0000610 archConfig = "arch=%s" % archs[ia]
611 for ic in range(len(compilers) if iterCompilers else 1):
612 if iterCompilers:
Johnny Chen18a921f2010-09-30 17:11:58 +0000613 os.environ["CC"] = compilers[ic]
Johnny Chenb40056b2010-09-21 00:09:27 +0000614 configString = "%s compiler=%s" % (archConfig, compilers[ic])
615 else:
616 configString = archConfig
617
Johnny Chenb40056b2010-09-21 00:09:27 +0000618 if iterArchs or iterCompilers:
Johnny Chen953864a2010-10-12 21:35:54 +0000619 # If we specified a relocated directory to run the test suite, do
620 # the extra housekeeping to copy the testdirs to a configStringified
621 # directory and to update sys.path before invoking the test runner.
622 # The purpose is to separate the configuration-specific directories
623 # from each other.
624 if rdir:
625 from string import maketrans
626 from shutil import copytree, ignore_patterns
627
628 # Translate ' ' to '-' for dir name.
629 tbl = maketrans(' ', '-')
630 configPostfix = configString.translate(tbl)
631 newrdir = "%s.%s" % (rdir, configPostfix)
632
633 # Copy the tree to a new directory with postfix name configPostfix.
634 copytree(rdir, newrdir, ignore=ignore_patterns('*.pyc', '*.o', '*.d'))
635
636 # Check whether we need to split stderr/stdout into configuration
637 # specific files.
638 if old_stderr.name != '<stderr>' and config.get('split_stderr'):
639 if new_stderr:
640 new_stderr.close()
641 new_stderr = open("%s.%s" % (old_stderr.name, configPostfix), "w")
642 sys.stderr = new_stderr
Johnny Chen4b6630e2010-10-12 21:50:36 +0000643 if old_stdout.name != '<stdout>' and config.get('split_stdout'):
Johnny Chen953864a2010-10-12 21:35:54 +0000644 if new_stdout:
645 new_stdout.close()
646 new_stdout = open("%s.%s" % (old_stdout.name, configPostfix), "w")
647 sys.stdout = new_stdout
648
649 # Update the LLDB_TEST environment variable to reflect new top
650 # level test directory.
651 #
652 # See also lldbtest.TestBase.setUpClass(cls).
653 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
654 os.environ["LLDB_TEST"] = os.path.join(newrdir, 'test')
655 else:
656 os.environ["LLDB_TEST"] = newrdir
657
658 # And update the Python search paths for modules.
659 sys.path = [x.replace(rdir, newrdir, 1) for x in old_sys_path]
660
661 # Output the configuration.
Johnny Chenb40056b2010-09-21 00:09:27 +0000662 sys.stderr.write("\nConfiguration: " + configString + "\n")
Johnny Chen953864a2010-10-12 21:35:54 +0000663
664 #print "sys.stderr name is", sys.stderr.name
665 #print "sys.stdout name is", sys.stdout.name
666
667 # First, write out the number of collected test cases.
668 sys.stderr.write(separator + "\n")
669 sys.stderr.write("Collected %d test%s\n\n"
670 % (suite.countTestCases(),
671 suite.countTestCases() != 1 and "s" or ""))
672
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000673 class LLDBTestResult(unittest2.TextTestResult):
674 """
Johnny Chen26be4532010-11-09 23:56:14 +0000675 Enforce a singleton pattern to allow introspection of test progress.
676
677 Overwrite addError(), addFailure(), and addExpectedFailure() methods
678 to enable each test instance to track its failure/error status. It
679 is used in the LLDB test framework to emit detailed trace messages
680 to a log file for easier human inspection of test failres/errors.
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000681 """
682 __singleton__ = None
683
684 def __init__(self, *args):
685 if LLDBTestResult.__singleton__:
686 raise "LLDBTestResult instantiated more than once"
687 super(LLDBTestResult, self).__init__(*args)
688 LLDBTestResult.__singleton__ = self
689 # Now put this singleton into the lldb module namespace.
690 lldb.test_result = self
691
Johnny Chence681462010-10-19 00:25:01 +0000692 def addError(self, test, err):
Johnny Chen63c2cba2010-10-29 22:20:36 +0000693 global sdir_has_content
694 sdir_has_content = True
Johnny Chence681462010-10-19 00:25:01 +0000695 super(LLDBTestResult, self).addError(test, err)
696 method = getattr(test, "markError", None)
697 if method:
698 method()
699
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000700 def addFailure(self, test, err):
Johnny Chen63c2cba2010-10-29 22:20:36 +0000701 global sdir_has_content
702 sdir_has_content = True
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000703 super(LLDBTestResult, self).addFailure(test, err)
704 method = getattr(test, "markFailure", None)
705 if method:
706 method()
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000707
Johnny Chendd2bb2c2010-11-03 18:17:03 +0000708 def addExpectedFailure(self, test, err):
709 global sdir_has_content
710 sdir_has_content = True
711 super(LLDBTestResult, self).addExpectedFailure(test, err)
712 method = getattr(test, "markExpectedFailure", None)
713 if method:
714 method()
715
Johnny Chen26be4532010-11-09 23:56:14 +0000716 # Invoke the test runner.
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000717 result = unittest2.TextTestRunner(stream=sys.stderr, verbosity=verbose,
718 resultclass=LLDBTestResult).run(suite)
Johnny Chenb40056b2010-09-21 00:09:27 +0000719
Johnny Chen1bfbd412010-06-29 19:44:16 +0000720
Johnny Chen63c2cba2010-10-29 22:20:36 +0000721if sdir_has_content:
Johnny Chen47c47c42010-11-09 23:42:00 +0000722 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 +0000723
Johnny Chencd0279d2010-09-20 18:07:50 +0000724# Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
725# This should not be necessary now.
Johnny Chen83f6e512010-08-13 22:58:44 +0000726if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
727 import subprocess
728 print "Terminating Test suite..."
729 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
730
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000731# Exiting.
732sys.exit(not result.wasSuccessful)