blob: 5fe9b9bd5759640076045ff8b0bff793ebdfcbe5 [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 Chenb62436b2010-10-06 20:40:56 +000057# The filter (testcase.testmethod) used to admit tests into our test suite.
58filterspec = None
59
60# If '-g' is specified, the filterspec must be consulted for each test module, default to False.
61fs4all = False
62
Johnny Chenaf149a02010-09-16 17:11:30 +000063# Ignore the build search path relative to this script to locate the lldb.py module.
64ignore = False
65
Johnny Chen548aefd2010-10-11 22:25:46 +000066# By default, we skip long running test case. Use '-l' option to override.
Johnny Chen41998192010-10-01 22:59:49 +000067skipLongRunningTest = True
68
Johnny Chen7c52ff12010-09-27 23:29:54 +000069# The regular expression pattern to match against eligible filenames as our test cases.
70regexp = None
71
Johnny Chen548aefd2010-10-11 22:25:46 +000072# By default, tests are executed in place and cleanups are performed afterwards.
73# Use '-r dir' option to relocate the tests and their intermediate files to a
74# different directory and to forgo any cleanups. The directory specified must
75# not exist yet.
76rdir = None
77
Johnny Chen125fc2b2010-10-21 16:55:35 +000078# By default, recorded session info for errored/failed test are dumped into its
79# own file under a session directory named after the timestamp of the test suite
80# run. Use '-s session-dir-name' to specify a specific dir name.
81sdir_name = None
82
Johnny Chen63c2cba2010-10-29 22:20:36 +000083# Set this flag if there is any session info dumped during the test run.
84sdir_has_content = False
85
Johnny Chen9707bb62010-06-25 21:14:08 +000086# Default verbosity is 0.
87verbose = 0
88
89# By default, search from the current working directory.
90testdirs = [ os.getcwd() ]
91
Johnny Chen877c7e42010-08-07 00:16:07 +000092# Separator string.
93separator = '-' * 70
94
Johnny Chen9707bb62010-06-25 21:14:08 +000095
96def usage():
97 print """
98Usage: dotest.py [option] [args]
99where options:
100-h : print this help message and exit (also --help)
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000101-c : read a config file specified after this option
Johnny Chenb40056b2010-09-21 00:09:27 +0000102 (see also lldb-trunk/example/test/usage-config)
Johnny Chen91960d32010-09-08 20:56:16 +0000103-d : delay startup for 10 seconds (in order for the debugger to attach)
Johnny Chen46be75d2010-10-11 16:19:48 +0000104-f : specify a filter, which consists of the test class name, a dot, followed by
105 the test method, to admit tests into the test suite
Johnny Chenb62436b2010-10-06 20:40:56 +0000106 e.g., -f 'ClassTypesTestCase.test_with_dwarf_and_python_api'
107-g : if specified, only the modules with the corect filter will be run
108 it has no effect if no '-f' option is present
109 '-f filterspec -g' can be used with '-p filename-regexp' to select only
110 the testfile.testclass.testmethod to run
Johnny Chenaf149a02010-09-16 17:11:30 +0000111-i : ignore (don't bailout) if 'lldb.py' module cannot be located in the build
112 tree relative to this script; use PYTHONPATH to locate the module
Johnny Chen41998192010-10-01 22:59:49 +0000113-l : don't skip long running test
Johnny Chen7c52ff12010-09-27 23:29:54 +0000114-p : specify a regexp filename pattern for inclusion in the test suite
Johnny Chen548aefd2010-10-11 22:25:46 +0000115-r : specify a dir to relocate the tests and their intermediate files to;
116 the directory must not exist before running this test driver;
117 no cleanup of intermediate test files is performed in this case
Johnny Chen125fc2b2010-10-21 16:55:35 +0000118-s : specify the name of the dir created to store the session files of tests
119 with errored or failed status; if not specified, the test driver uses the
120 timestamp as the session dir name
Johnny Chend0c24b22010-08-23 17:10:44 +0000121-t : trace lldb command execution and result
Johnny Chen9707bb62010-06-25 21:14:08 +0000122-v : do verbose mode of unittest framework
Johnny Chene47649c2010-10-07 02:04:14 +0000123-w : insert some wait time (currently 0.5 sec) between consecutive test cases
Johnny Chen9707bb62010-06-25 21:14:08 +0000124
125and:
Johnny Chen9656ab22010-10-22 19:00:18 +0000126args : specify a list of directory names to search for test modules named after
127 Test*.py (test discovery)
Johnny Chen9707bb62010-06-25 21:14:08 +0000128 if empty, search from the curret working directory, instead
Johnny Chen58f93922010-06-29 23:10:39 +0000129
Johnny Chen9656ab22010-10-22 19:00:18 +0000130Examples:
131
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000132This is an example of using the -f -g options to pinpoint to a specfic test
133method to be run:
134
135$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command -g
136----------------------------------------------------------------------
137Collected 1 test
138
139test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
140Test 'frame variable this' when stopped on a class constructor. ... ok
141
142----------------------------------------------------------------------
143Ran 1 test in 1.396s
144
145OK
Johnny Chen9656ab22010-10-22 19:00:18 +0000146
147And this is an example of using the -p option to run a single file (the filename
148matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
149
150$ ./dotest.py -v -p ObjC
151----------------------------------------------------------------------
152Collected 4 tests
153
154test_break_with_dsym (TestObjCMethods.FoundationTestCase)
155Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'. ... ok
156test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
157Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'. ... ok
158test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
159Lookup objective-c data types and evaluate expressions. ... ok
160test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
161Lookup objective-c data types and evaluate expressions. ... ok
162
163----------------------------------------------------------------------
164Ran 4 tests in 16.661s
165
166OK
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000167
Johnny Chen58f93922010-06-29 23:10:39 +0000168Running of this script also sets up the LLDB_TEST environment variable so that
Johnny Chenaf149a02010-09-16 17:11:30 +0000169individual test cases can locate their supporting files correctly. The script
170tries to set up Python's search paths for modules by looking at the build tree
171relative to this script. See also the '-i' option.
Johnny Chenfde69bc2010-09-14 22:01:40 +0000172
173Environment variables related to loggings:
174
175o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
176 with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
177
178o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
179 'process.gdb-remote' subsystem with a default option of 'packets' if
180 GDB_REMOTE_LOG_OPTION is not defined.
Johnny Chen9707bb62010-06-25 21:14:08 +0000181"""
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000182 sys.exit(0)
Johnny Chen9707bb62010-06-25 21:14:08 +0000183
184
Johnny Chenaf149a02010-09-16 17:11:30 +0000185def parseOptionsAndInitTestdirs():
186 """Initialize the list of directories containing our unittest scripts.
187
188 '-h/--help as the first option prints out usage info and exit the program.
189 """
190
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000191 global configFile
Johnny Chenaf149a02010-09-16 17:11:30 +0000192 global delay
Johnny Chenb62436b2010-10-06 20:40:56 +0000193 global filterspec
194 global fs4all
Johnny Chen7c52ff12010-09-27 23:29:54 +0000195 global ignore
Johnny Chen41998192010-10-01 22:59:49 +0000196 global skipLongRunningTest
Johnny Chen7c52ff12010-09-27 23:29:54 +0000197 global regexp
Johnny Chen548aefd2010-10-11 22:25:46 +0000198 global rdir
Johnny Chen125fc2b2010-10-21 16:55:35 +0000199 global sdir_name
Johnny Chenaf149a02010-09-16 17:11:30 +0000200 global verbose
201 global testdirs
202
203 if len(sys.argv) == 1:
204 return
205
206 # Process possible trace and/or verbose flag, among other things.
207 index = 1
Johnny Chence2212c2010-10-07 15:41:55 +0000208 while index < len(sys.argv):
Johnny Chenaf149a02010-09-16 17:11:30 +0000209 if not sys.argv[index].startswith('-'):
210 # End of option processing.
211 break
212
213 if sys.argv[index].find('-h') != -1:
214 usage()
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000215 elif sys.argv[index].startswith('-c'):
216 # Increment by 1 to fetch the config file name option argument.
217 index += 1
218 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
219 usage()
220 configFile = sys.argv[index]
221 if not os.path.isfile(configFile):
222 print "Config file:", configFile, "does not exist!"
223 usage()
224 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000225 elif sys.argv[index].startswith('-d'):
226 delay = True
227 index += 1
Johnny Chenb62436b2010-10-06 20:40:56 +0000228 elif sys.argv[index].startswith('-f'):
229 # Increment by 1 to fetch the filter spec.
230 index += 1
231 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
232 usage()
233 filterspec = sys.argv[index]
234 index += 1
235 elif sys.argv[index].startswith('-g'):
236 fs4all = True
237 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000238 elif sys.argv[index].startswith('-i'):
239 ignore = True
240 index += 1
Johnny Chen41998192010-10-01 22:59:49 +0000241 elif sys.argv[index].startswith('-l'):
242 skipLongRunningTest = False
243 index += 1
Johnny Chen7c52ff12010-09-27 23:29:54 +0000244 elif sys.argv[index].startswith('-p'):
245 # Increment by 1 to fetch the reg exp pattern argument.
246 index += 1
247 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
248 usage()
249 regexp = sys.argv[index]
250 index += 1
Johnny Chen548aefd2010-10-11 22:25:46 +0000251 elif sys.argv[index].startswith('-r'):
252 # Increment by 1 to fetch the relocated directory argument.
253 index += 1
254 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
255 usage()
256 rdir = os.path.abspath(sys.argv[index])
257 if os.path.exists(rdir):
258 print "Relocated directory:", rdir, "must not exist!"
259 usage()
260 index += 1
Johnny Chen125fc2b2010-10-21 16:55:35 +0000261 elif sys.argv[index].startswith('-s'):
262 # Increment by 1 to fetch the session dir name.
263 index += 1
264 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
265 usage()
266 sdir_name = sys.argv[index]
267 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000268 elif sys.argv[index].startswith('-t'):
269 os.environ["LLDB_COMMAND_TRACE"] = "YES"
270 index += 1
271 elif sys.argv[index].startswith('-v'):
272 verbose = 2
273 index += 1
Johnny Chene47649c2010-10-07 02:04:14 +0000274 elif sys.argv[index].startswith('-w'):
275 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] = 'YES'
276 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000277 else:
278 print "Unknown option: ", sys.argv[index]
279 usage()
Johnny Chenaf149a02010-09-16 17:11:30 +0000280
281 # Gather all the dirs passed on the command line.
282 if len(sys.argv) > index:
283 testdirs = map(os.path.abspath, sys.argv[index:])
284
Johnny Chen548aefd2010-10-11 22:25:46 +0000285 # If '-r dir' is specified, the tests should be run under the relocated
286 # directory. Let's copy the testdirs over.
287 if rdir:
288 from shutil import copytree, ignore_patterns
289
290 tmpdirs = []
291 for srcdir in testdirs:
292 dstdir = os.path.join(rdir, os.path.basename(srcdir))
293 # Don't copy the *.pyc and .svn stuffs.
294 copytree(srcdir, dstdir, ignore=ignore_patterns('*.pyc', '.svn'))
295 tmpdirs.append(dstdir)
296
297 # This will be our modified testdirs.
298 testdirs = tmpdirs
299
300 # With '-r dir' specified, there's no cleanup of intermediate test files.
301 os.environ["LLDB_DO_CLEANUP"] = 'NO'
302
303 # If testdirs is ['test'], the make directory has already been copied
304 # recursively and is contained within the rdir/test dir. For anything
305 # else, we would need to copy over the make directory and its contents,
306 # so that, os.listdir(rdir) looks like, for example:
307 #
308 # array_types conditional_break make
309 #
310 # where the make directory contains the Makefile.rules file.
311 if len(testdirs) != 1 or os.path.basename(testdirs[0]) != 'test':
312 # Don't copy the .svn stuffs.
313 copytree('make', os.path.join(rdir, 'make'),
314 ignore=ignore_patterns('.svn'))
315
316 #print "testdirs:", testdirs
317
Johnny Chenb40056b2010-09-21 00:09:27 +0000318 # Source the configFile if specified.
319 # The side effect, if any, will be felt from this point on. An example
320 # config file may be these simple two lines:
321 #
322 # sys.stderr = open("/tmp/lldbtest-stderr", "w")
323 # sys.stdout = open("/tmp/lldbtest-stdout", "w")
324 #
325 # which will reassign the two file objects to sys.stderr and sys.stdout,
326 # respectively.
327 #
328 # See also lldb-trunk/example/test/usage-config.
329 global config
330 if configFile:
331 # Pass config (a dictionary) as the locals namespace for side-effect.
332 execfile(configFile, globals(), config)
333 #print "config:", config
334 #print "sys.stderr:", sys.stderr
335 #print "sys.stdout:", sys.stdout
336
Johnny Chenaf149a02010-09-16 17:11:30 +0000337
Johnny Chen9707bb62010-06-25 21:14:08 +0000338def setupSysPath():
339 """Add LLDB.framework/Resources/Python to the search paths for modules."""
340
Johnny Chen548aefd2010-10-11 22:25:46 +0000341 global rdir
342 global testdirs
343
Johnny Chen9707bb62010-06-25 21:14:08 +0000344 # Get the directory containing the current script.
Johnny Chena1affab2010-07-03 03:41:59 +0000345 scriptPath = sys.path[0]
346 if not scriptPath.endswith('test'):
Johnny Chen9707bb62010-06-25 21:14:08 +0000347 print "This script expects to reside in lldb's test directory."
348 sys.exit(-1)
349
Johnny Chen548aefd2010-10-11 22:25:46 +0000350 if rdir:
351 # Set up the LLDB_TEST environment variable appropriately, so that the
352 # individual tests can be located relatively.
353 #
354 # See also lldbtest.TestBase.setUpClass(cls).
355 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
356 os.environ["LLDB_TEST"] = os.path.join(rdir, 'test')
357 else:
358 os.environ["LLDB_TEST"] = rdir
359 else:
360 os.environ["LLDB_TEST"] = scriptPath
Johnny Chen9de4ede2010-08-31 17:42:54 +0000361 pluginPath = os.path.join(scriptPath, 'plugins')
Johnny Chen58f93922010-06-29 23:10:39 +0000362
Johnny Chenaf149a02010-09-16 17:11:30 +0000363 # Append script dir and plugin dir to the sys.path.
364 sys.path.append(scriptPath)
365 sys.path.append(pluginPath)
366
367 global ignore
368
369 # The '-i' option is used to skip looking for lldb.py in the build tree.
370 if ignore:
371 return
372
Johnny Chena1affab2010-07-03 03:41:59 +0000373 base = os.path.abspath(os.path.join(scriptPath, os.pardir))
Johnny Chen9707bb62010-06-25 21:14:08 +0000374 dbgPath = os.path.join(base, 'build', 'Debug', 'LLDB.framework',
375 'Resources', 'Python')
376 relPath = os.path.join(base, 'build', 'Release', 'LLDB.framework',
377 'Resources', 'Python')
Johnny Chenc202c462010-09-15 18:11:19 +0000378 baiPath = os.path.join(base, 'build', 'BuildAndIntegration',
379 'LLDB.framework', 'Resources', 'Python')
Johnny Chen9707bb62010-06-25 21:14:08 +0000380
381 lldbPath = None
382 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
383 lldbPath = dbgPath
384 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
385 lldbPath = relPath
Johnny Chenc202c462010-09-15 18:11:19 +0000386 elif os.path.isfile(os.path.join(baiPath, 'lldb.py')):
387 lldbPath = baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000388
389 if not lldbPath:
Johnny Chenc202c462010-09-15 18:11:19 +0000390 print 'This script requires lldb.py to be in either ' + dbgPath + ',',
391 print relPath + ', or ' + baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000392 sys.exit(-1)
393
Johnny Chenaf149a02010-09-16 17:11:30 +0000394 # This is to locate the lldb.py module. Insert it right after sys.path[0].
395 sys.path[1:1] = [lldbPath]
Johnny Chen9707bb62010-06-25 21:14:08 +0000396
Johnny Chen9707bb62010-06-25 21:14:08 +0000397
Johnny Chencd0279d2010-09-20 18:07:50 +0000398def doDelay(delta):
399 """Delaying startup for delta-seconds to facilitate debugger attachment."""
400 def alarm_handler(*args):
401 raise Exception("timeout")
402
403 signal.signal(signal.SIGALRM, alarm_handler)
404 signal.alarm(delta)
405 sys.stdout.write("pid=%d\n" % os.getpid())
406 sys.stdout.write("Enter RET to proceed (or timeout after %d seconds):" %
407 delta)
408 sys.stdout.flush()
409 try:
410 text = sys.stdin.readline()
411 except:
412 text = ""
413 signal.alarm(0)
414 sys.stdout.write("proceeding...\n")
415 pass
416
417
Johnny Chen9707bb62010-06-25 21:14:08 +0000418def visit(prefix, dir, names):
419 """Visitor function for os.path.walk(path, visit, arg)."""
420
421 global suite
Johnny Chen7c52ff12010-09-27 23:29:54 +0000422 global regexp
Johnny Chenb62436b2010-10-06 20:40:56 +0000423 global filterspec
424 global fs4all
Johnny Chen9707bb62010-06-25 21:14:08 +0000425
426 for name in names:
427 if os.path.isdir(os.path.join(dir, name)):
428 continue
429
430 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
Johnny Chen7c52ff12010-09-27 23:29:54 +0000431 # Try to match the regexp pattern, if specified.
432 if regexp:
433 import re
434 if re.search(regexp, name):
435 #print "Filename: '%s' matches pattern: '%s'" % (name, regexp)
436 pass
437 else:
438 #print "Filename: '%s' does not match pattern: '%s'" % (name, regexp)
439 continue
440
Johnny Chen953864a2010-10-12 21:35:54 +0000441 # We found a match for our test. Add it to the suite.
Johnny Chen79723352010-10-12 15:53:22 +0000442
443 # Update the sys.path first.
Johnny Chena85d7ee2010-06-26 00:19:32 +0000444 if not sys.path.count(dir):
Johnny Chen548aefd2010-10-11 22:25:46 +0000445 sys.path.insert(0, dir)
Johnny Chen9707bb62010-06-25 21:14:08 +0000446 base = os.path.splitext(name)[0]
Johnny Chenb62436b2010-10-06 20:40:56 +0000447
448 # Thoroughly check the filterspec against the base module and admit
449 # the (base, filterspec) combination only when it makes sense.
450 if filterspec:
451 # Optimistically set the flag to True.
452 filtered = True
453 module = __import__(base)
454 parts = filterspec.split('.')
455 obj = module
456 for part in parts:
457 try:
458 parent, obj = obj, getattr(obj, part)
459 except AttributeError:
460 # The filterspec has failed.
461 filtered = False
462 break
463 # Forgo this module if the (base, filterspec) combo is invalid
464 # and the '-g' option is present.
465 if fs4all and not filtered:
466 continue
467
Johnny Chen953864a2010-10-12 21:35:54 +0000468 # Add either the filtered test case or the entire test class.
Johnny Chenb62436b2010-10-06 20:40:56 +0000469 if filterspec and filtered:
470 suite.addTests(
471 unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
472 else:
473 # A simple case of just the module name. Also the failover case
474 # from the filterspec branch when the (base, filterspec) combo
475 # doesn't make sense.
476 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
Johnny Chen9707bb62010-06-25 21:14:08 +0000477
478
Johnny Chencd0279d2010-09-20 18:07:50 +0000479def lldbLoggings():
480 """Check and do lldb loggings if necessary."""
481
482 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
483 # defined. Use ${LLDB_LOG} to specify the log file.
484 ci = lldb.DBG.GetCommandInterpreter()
485 res = lldb.SBCommandReturnObject()
486 if ("LLDB_LOG" in os.environ):
487 if ("LLDB_LOG_OPTION" in os.environ):
488 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
489 else:
490 lldb_log_option = "event process"
491 ci.HandleCommand(
492 "log enable -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
493 res)
494 if not res.Succeeded():
495 raise Exception('log enable failed (check LLDB_LOG env variable.')
496 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
497 # Use ${GDB_REMOTE_LOG} to specify the log file.
498 if ("GDB_REMOTE_LOG" in os.environ):
499 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
500 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
501 else:
502 gdb_remote_log_option = "packets"
503 ci.HandleCommand(
504 "log enable -f " + os.environ["GDB_REMOTE_LOG"] + " process.gdb-remote "
505 + gdb_remote_log_option,
506 res)
507 if not res.Succeeded():
508 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
509
510
511############################################
512# #
513# Execution of the test driver starts here #
514# #
515############################################
516
Johnny Chen9707bb62010-06-25 21:14:08 +0000517#
Johnny Chenaf149a02010-09-16 17:11:30 +0000518# Start the actions by first parsing the options while setting up the test
519# directories, followed by setting up the search paths for lldb utilities;
520# then, we walk the directory trees and collect the tests into our test suite.
Johnny Chen9707bb62010-06-25 21:14:08 +0000521#
Johnny Chenaf149a02010-09-16 17:11:30 +0000522parseOptionsAndInitTestdirs()
Johnny Chen9707bb62010-06-25 21:14:08 +0000523setupSysPath()
Johnny Chen91960d32010-09-08 20:56:16 +0000524
525#
526# If '-d' is specified, do a delay of 10 seconds for the debugger to attach.
527#
528if delay:
Johnny Chencd0279d2010-09-20 18:07:50 +0000529 doDelay(10)
Johnny Chen91960d32010-09-08 20:56:16 +0000530
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000531#
Johnny Chen41998192010-10-01 22:59:49 +0000532# If '-l' is specified, do not skip the long running tests.
533if not skipLongRunningTest:
534 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
535
536#
Johnny Chen79723352010-10-12 15:53:22 +0000537# Walk through the testdirs while collecting tests.
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000538#
Johnny Chen9707bb62010-06-25 21:14:08 +0000539for testdir in testdirs:
540 os.path.walk(testdir, visit, 'Test')
541
Johnny Chenb40056b2010-09-21 00:09:27 +0000542#
Johnny Chen9707bb62010-06-25 21:14:08 +0000543# Now that we have loaded all the test cases, run the whole test suite.
Johnny Chenb40056b2010-09-21 00:09:27 +0000544#
Johnny Chencd0279d2010-09-20 18:07:50 +0000545
Johnny Chen1bfbd412010-06-29 19:44:16 +0000546# For the time being, let's bracket the test runner within the
547# lldb.SBDebugger.Initialize()/Terminate() pair.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000548import lldb, atexit
Johnny Chen6b6f5ba2010-10-14 16:36:49 +0000549# Update: the act of importing lldb now executes lldb.SBDebugger.Initialize(),
550# there's no need to call it a second time.
551#lldb.SBDebugger.Initialize()
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000552atexit.register(lambda: lldb.SBDebugger.Terminate())
Johnny Chen1bfbd412010-06-29 19:44:16 +0000553
Johnny Chen909e5a62010-07-01 22:52:57 +0000554# Create a singleton SBDebugger in the lldb namespace.
555lldb.DBG = lldb.SBDebugger.Create()
556
Johnny Chencd0279d2010-09-20 18:07:50 +0000557# Turn on lldb loggings if necessary.
558lldbLoggings()
Johnny Chen909e5a62010-07-01 22:52:57 +0000559
Johnny Chen7987ac92010-08-09 20:40:52 +0000560# Install the control-c handler.
561unittest2.signals.installHandler()
562
Johnny Chen125fc2b2010-10-21 16:55:35 +0000563# If sdir_name is not specified through the '-s sdir_name' option, get a
564# timestamp string and export it as LLDB_SESSION_DIR environment var. This will
565# be used when/if we want to dump the session info of individual test cases
566# later on.
Johnny Chence681462010-10-19 00:25:01 +0000567#
568# See also TestBase.dumpSessionInfo() in lldbtest.py.
Johnny Chen125fc2b2010-10-21 16:55:35 +0000569if not sdir_name:
570 import datetime
Johnny Chen41fae812010-10-29 22:26:38 +0000571 # The windows platforms don't like ':' in the pathname.
Johnny Chen76bd0102010-10-28 16:32:13 +0000572 timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
Johnny Chen125fc2b2010-10-21 16:55:35 +0000573 sdir_name = timestamp
574os.environ["LLDB_SESSION_DIRNAME"] = sdir_name
Johnny Chence681462010-10-19 00:25:01 +0000575
Johnny Chenb40056b2010-09-21 00:09:27 +0000576#
577# Invoke the default TextTestRunner to run the test suite, possibly iterating
578# over different configurations.
579#
580
Johnny Chenb40056b2010-09-21 00:09:27 +0000581iterArchs = False
Johnny Chenf032d902010-09-21 00:16:09 +0000582iterCompilers = False
Johnny Chenb40056b2010-09-21 00:09:27 +0000583
584from types import *
585if "archs" in config:
586 archs = config["archs"]
587 if type(archs) is ListType and len(archs) >= 1:
588 iterArchs = True
589if "compilers" in config:
590 compilers = config["compilers"]
591 if type(compilers) is ListType and len(compilers) >= 1:
592 iterCompilers = True
593
Johnny Chen953864a2010-10-12 21:35:54 +0000594# Make a shallow copy of sys.path, we need to manipulate the search paths later.
595# This is only necessary if we are relocated and with different configurations.
596if rdir and (iterArchs or iterCompilers):
597 old_sys_path = sys.path[:]
598 old_stderr = sys.stderr
599 old_stdout = sys.stdout
600 new_stderr = None
601 new_stdout = None
602
Johnny Chenb40056b2010-09-21 00:09:27 +0000603for ia in range(len(archs) if iterArchs else 1):
604 archConfig = ""
605 if iterArchs:
Johnny Chen18a921f2010-09-30 17:11:58 +0000606 os.environ["ARCH"] = archs[ia]
Johnny Chenb40056b2010-09-21 00:09:27 +0000607 archConfig = "arch=%s" % archs[ia]
608 for ic in range(len(compilers) if iterCompilers else 1):
609 if iterCompilers:
Johnny Chen18a921f2010-09-30 17:11:58 +0000610 os.environ["CC"] = compilers[ic]
Johnny Chenb40056b2010-09-21 00:09:27 +0000611 configString = "%s compiler=%s" % (archConfig, compilers[ic])
612 else:
613 configString = archConfig
614
Johnny Chenb40056b2010-09-21 00:09:27 +0000615 if iterArchs or iterCompilers:
Johnny Chen953864a2010-10-12 21:35:54 +0000616 # If we specified a relocated directory to run the test suite, do
617 # the extra housekeeping to copy the testdirs to a configStringified
618 # directory and to update sys.path before invoking the test runner.
619 # The purpose is to separate the configuration-specific directories
620 # from each other.
621 if rdir:
622 from string import maketrans
623 from shutil import copytree, ignore_patterns
624
625 # Translate ' ' to '-' for dir name.
626 tbl = maketrans(' ', '-')
627 configPostfix = configString.translate(tbl)
628 newrdir = "%s.%s" % (rdir, configPostfix)
629
630 # Copy the tree to a new directory with postfix name configPostfix.
631 copytree(rdir, newrdir, ignore=ignore_patterns('*.pyc', '*.o', '*.d'))
632
633 # Check whether we need to split stderr/stdout into configuration
634 # specific files.
635 if old_stderr.name != '<stderr>' and config.get('split_stderr'):
636 if new_stderr:
637 new_stderr.close()
638 new_stderr = open("%s.%s" % (old_stderr.name, configPostfix), "w")
639 sys.stderr = new_stderr
Johnny Chen4b6630e2010-10-12 21:50:36 +0000640 if old_stdout.name != '<stdout>' and config.get('split_stdout'):
Johnny Chen953864a2010-10-12 21:35:54 +0000641 if new_stdout:
642 new_stdout.close()
643 new_stdout = open("%s.%s" % (old_stdout.name, configPostfix), "w")
644 sys.stdout = new_stdout
645
646 # Update the LLDB_TEST environment variable to reflect new top
647 # level test directory.
648 #
649 # See also lldbtest.TestBase.setUpClass(cls).
650 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
651 os.environ["LLDB_TEST"] = os.path.join(newrdir, 'test')
652 else:
653 os.environ["LLDB_TEST"] = newrdir
654
655 # And update the Python search paths for modules.
656 sys.path = [x.replace(rdir, newrdir, 1) for x in old_sys_path]
657
658 # Output the configuration.
Johnny Chenb40056b2010-09-21 00:09:27 +0000659 sys.stderr.write("\nConfiguration: " + configString + "\n")
Johnny Chen953864a2010-10-12 21:35:54 +0000660
661 #print "sys.stderr name is", sys.stderr.name
662 #print "sys.stdout name is", sys.stdout.name
663
664 # First, write out the number of collected test cases.
665 sys.stderr.write(separator + "\n")
666 sys.stderr.write("Collected %d test%s\n\n"
667 % (suite.countTestCases(),
668 suite.countTestCases() != 1 and "s" or ""))
669
670 # Invoke the test runner.
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000671 class LLDBTestResult(unittest2.TextTestResult):
672 """
673 Enforce a singleton pattern to allow inspection of test progress.
674 """
675 __singleton__ = None
676
677 def __init__(self, *args):
678 if LLDBTestResult.__singleton__:
679 raise "LLDBTestResult instantiated more than once"
680 super(LLDBTestResult, self).__init__(*args)
681 LLDBTestResult.__singleton__ = self
682 # Now put this singleton into the lldb module namespace.
683 lldb.test_result = self
684
Johnny Chence681462010-10-19 00:25:01 +0000685 def addError(self, test, err):
Johnny Chen63c2cba2010-10-29 22:20:36 +0000686 global sdir_has_content
687 sdir_has_content = True
Johnny Chence681462010-10-19 00:25:01 +0000688 super(LLDBTestResult, self).addError(test, err)
689 method = getattr(test, "markError", None)
690 if method:
691 method()
692
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000693 def addFailure(self, test, err):
Johnny Chen63c2cba2010-10-29 22:20:36 +0000694 global sdir_has_content
695 sdir_has_content = True
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000696 super(LLDBTestResult, self).addFailure(test, err)
697 method = getattr(test, "markFailure", None)
698 if method:
699 method()
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000700
Johnny Chendd2bb2c2010-11-03 18:17:03 +0000701 def addExpectedFailure(self, test, err):
702 global sdir_has_content
703 sdir_has_content = True
704 super(LLDBTestResult, self).addExpectedFailure(test, err)
705 method = getattr(test, "markExpectedFailure", None)
706 if method:
707 method()
708
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000709 result = unittest2.TextTestRunner(stream=sys.stderr, verbosity=verbose,
710 resultclass=LLDBTestResult).run(suite)
Johnny Chenb40056b2010-09-21 00:09:27 +0000711
Johnny Chen1bfbd412010-06-29 19:44:16 +0000712
Johnny Chen63c2cba2010-10-29 22:20:36 +0000713if sdir_has_content:
714 sys.stderr.write("\nSession logs for test failures/errors can be found in directory '%s'\n" % sdir_name)
715
Johnny Chencd0279d2010-09-20 18:07:50 +0000716# Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
717# This should not be necessary now.
Johnny Chen83f6e512010-08-13 22:58:44 +0000718if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
719 import subprocess
720 print "Terminating Test suite..."
721 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
722
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000723# Exiting.
724sys.exit(not result.wasSuccessful)