blob: f661ed9504fd41652092f4afba30b8fc1a0ef754 [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 Chen9707bb62010-06-25 21:14:08 +000078# Default verbosity is 0.
79verbose = 0
80
81# By default, search from the current working directory.
82testdirs = [ os.getcwd() ]
83
Johnny Chen877c7e42010-08-07 00:16:07 +000084# Separator string.
85separator = '-' * 70
86
Johnny Chen9707bb62010-06-25 21:14:08 +000087
88def usage():
89 print """
90Usage: dotest.py [option] [args]
91where options:
92-h : print this help message and exit (also --help)
Johnny Chen9fdb0a92010-09-18 00:16:47 +000093-c : read a config file specified after this option
Johnny Chenb40056b2010-09-21 00:09:27 +000094 (see also lldb-trunk/example/test/usage-config)
Johnny Chen91960d32010-09-08 20:56:16 +000095-d : delay startup for 10 seconds (in order for the debugger to attach)
Johnny Chen46be75d2010-10-11 16:19:48 +000096-f : specify a filter, which consists of the test class name, a dot, followed by
97 the test method, to admit tests into the test suite
Johnny Chenb62436b2010-10-06 20:40:56 +000098 e.g., -f 'ClassTypesTestCase.test_with_dwarf_and_python_api'
99-g : if specified, only the modules with the corect filter will be run
100 it has no effect if no '-f' option is present
101 '-f filterspec -g' can be used with '-p filename-regexp' to select only
102 the testfile.testclass.testmethod to run
Johnny Chenaf149a02010-09-16 17:11:30 +0000103-i : ignore (don't bailout) if 'lldb.py' module cannot be located in the build
104 tree relative to this script; use PYTHONPATH to locate the module
Johnny Chen41998192010-10-01 22:59:49 +0000105-l : don't skip long running test
Johnny Chen7c52ff12010-09-27 23:29:54 +0000106-p : specify a regexp filename pattern for inclusion in the test suite
Johnny Chen548aefd2010-10-11 22:25:46 +0000107-r : specify a dir to relocate the tests and their intermediate files to;
108 the directory must not exist before running this test driver;
109 no cleanup of intermediate test files is performed in this case
Johnny Chend0c24b22010-08-23 17:10:44 +0000110-t : trace lldb command execution and result
Johnny Chen9707bb62010-06-25 21:14:08 +0000111-v : do verbose mode of unittest framework
Johnny Chene47649c2010-10-07 02:04:14 +0000112-w : insert some wait time (currently 0.5 sec) between consecutive test cases
Johnny Chen9707bb62010-06-25 21:14:08 +0000113
114and:
115args : specify a list of directory names to search for python Test*.py scripts
116 if empty, search from the curret working directory, instead
Johnny Chen58f93922010-06-29 23:10:39 +0000117
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000118This is an example of using the -f -g options to pinpoint to a specfic test
119method to be run:
120
121$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command -g
122----------------------------------------------------------------------
123Collected 1 test
124
125test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
126Test 'frame variable this' when stopped on a class constructor. ... ok
127
128----------------------------------------------------------------------
129Ran 1 test in 1.396s
130
131OK
132$
133
Johnny Chen58f93922010-06-29 23:10:39 +0000134Running of this script also sets up the LLDB_TEST environment variable so that
Johnny Chenaf149a02010-09-16 17:11:30 +0000135individual test cases can locate their supporting files correctly. The script
136tries to set up Python's search paths for modules by looking at the build tree
137relative to this script. See also the '-i' option.
Johnny Chenfde69bc2010-09-14 22:01:40 +0000138
139Environment variables related to loggings:
140
141o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
142 with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
143
144o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
145 'process.gdb-remote' subsystem with a default option of 'packets' if
146 GDB_REMOTE_LOG_OPTION is not defined.
Johnny Chen9707bb62010-06-25 21:14:08 +0000147"""
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000148 sys.exit(0)
Johnny Chen9707bb62010-06-25 21:14:08 +0000149
150
Johnny Chenaf149a02010-09-16 17:11:30 +0000151def parseOptionsAndInitTestdirs():
152 """Initialize the list of directories containing our unittest scripts.
153
154 '-h/--help as the first option prints out usage info and exit the program.
155 """
156
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000157 global configFile
Johnny Chenaf149a02010-09-16 17:11:30 +0000158 global delay
Johnny Chenb62436b2010-10-06 20:40:56 +0000159 global filterspec
160 global fs4all
Johnny Chen7c52ff12010-09-27 23:29:54 +0000161 global ignore
Johnny Chen41998192010-10-01 22:59:49 +0000162 global skipLongRunningTest
Johnny Chen7c52ff12010-09-27 23:29:54 +0000163 global regexp
Johnny Chen548aefd2010-10-11 22:25:46 +0000164 global rdir
Johnny Chenaf149a02010-09-16 17:11:30 +0000165 global verbose
166 global testdirs
167
168 if len(sys.argv) == 1:
169 return
170
171 # Process possible trace and/or verbose flag, among other things.
172 index = 1
Johnny Chence2212c2010-10-07 15:41:55 +0000173 while index < len(sys.argv):
Johnny Chenaf149a02010-09-16 17:11:30 +0000174 if not sys.argv[index].startswith('-'):
175 # End of option processing.
176 break
177
178 if sys.argv[index].find('-h') != -1:
179 usage()
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000180 elif sys.argv[index].startswith('-c'):
181 # Increment by 1 to fetch the config file name option argument.
182 index += 1
183 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
184 usage()
185 configFile = sys.argv[index]
186 if not os.path.isfile(configFile):
187 print "Config file:", configFile, "does not exist!"
188 usage()
189 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000190 elif sys.argv[index].startswith('-d'):
191 delay = True
192 index += 1
Johnny Chenb62436b2010-10-06 20:40:56 +0000193 elif sys.argv[index].startswith('-f'):
194 # Increment by 1 to fetch the filter spec.
195 index += 1
196 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
197 usage()
198 filterspec = sys.argv[index]
199 index += 1
200 elif sys.argv[index].startswith('-g'):
201 fs4all = True
202 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000203 elif sys.argv[index].startswith('-i'):
204 ignore = True
205 index += 1
Johnny Chen41998192010-10-01 22:59:49 +0000206 elif sys.argv[index].startswith('-l'):
207 skipLongRunningTest = False
208 index += 1
Johnny Chen7c52ff12010-09-27 23:29:54 +0000209 elif sys.argv[index].startswith('-p'):
210 # Increment by 1 to fetch the reg exp pattern argument.
211 index += 1
212 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
213 usage()
214 regexp = sys.argv[index]
215 index += 1
Johnny Chen548aefd2010-10-11 22:25:46 +0000216 elif sys.argv[index].startswith('-r'):
217 # Increment by 1 to fetch the relocated directory argument.
218 index += 1
219 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
220 usage()
221 rdir = os.path.abspath(sys.argv[index])
222 if os.path.exists(rdir):
223 print "Relocated directory:", rdir, "must not exist!"
224 usage()
225 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000226 elif sys.argv[index].startswith('-t'):
227 os.environ["LLDB_COMMAND_TRACE"] = "YES"
228 index += 1
229 elif sys.argv[index].startswith('-v'):
230 verbose = 2
231 index += 1
Johnny Chene47649c2010-10-07 02:04:14 +0000232 elif sys.argv[index].startswith('-w'):
233 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] = 'YES'
234 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000235 else:
236 print "Unknown option: ", sys.argv[index]
237 usage()
Johnny Chenaf149a02010-09-16 17:11:30 +0000238
239 # Gather all the dirs passed on the command line.
240 if len(sys.argv) > index:
241 testdirs = map(os.path.abspath, sys.argv[index:])
242
Johnny Chen548aefd2010-10-11 22:25:46 +0000243 # If '-r dir' is specified, the tests should be run under the relocated
244 # directory. Let's copy the testdirs over.
245 if rdir:
246 from shutil import copytree, ignore_patterns
247
248 tmpdirs = []
249 for srcdir in testdirs:
250 dstdir = os.path.join(rdir, os.path.basename(srcdir))
251 # Don't copy the *.pyc and .svn stuffs.
252 copytree(srcdir, dstdir, ignore=ignore_patterns('*.pyc', '.svn'))
253 tmpdirs.append(dstdir)
254
255 # This will be our modified testdirs.
256 testdirs = tmpdirs
257
258 # With '-r dir' specified, there's no cleanup of intermediate test files.
259 os.environ["LLDB_DO_CLEANUP"] = 'NO'
260
261 # If testdirs is ['test'], the make directory has already been copied
262 # recursively and is contained within the rdir/test dir. For anything
263 # else, we would need to copy over the make directory and its contents,
264 # so that, os.listdir(rdir) looks like, for example:
265 #
266 # array_types conditional_break make
267 #
268 # where the make directory contains the Makefile.rules file.
269 if len(testdirs) != 1 or os.path.basename(testdirs[0]) != 'test':
270 # Don't copy the .svn stuffs.
271 copytree('make', os.path.join(rdir, 'make'),
272 ignore=ignore_patterns('.svn'))
273
274 #print "testdirs:", testdirs
275
Johnny Chenb40056b2010-09-21 00:09:27 +0000276 # Source the configFile if specified.
277 # The side effect, if any, will be felt from this point on. An example
278 # config file may be these simple two lines:
279 #
280 # sys.stderr = open("/tmp/lldbtest-stderr", "w")
281 # sys.stdout = open("/tmp/lldbtest-stdout", "w")
282 #
283 # which will reassign the two file objects to sys.stderr and sys.stdout,
284 # respectively.
285 #
286 # See also lldb-trunk/example/test/usage-config.
287 global config
288 if configFile:
289 # Pass config (a dictionary) as the locals namespace for side-effect.
290 execfile(configFile, globals(), config)
291 #print "config:", config
292 #print "sys.stderr:", sys.stderr
293 #print "sys.stdout:", sys.stdout
294
Johnny Chenaf149a02010-09-16 17:11:30 +0000295
Johnny Chen9707bb62010-06-25 21:14:08 +0000296def setupSysPath():
297 """Add LLDB.framework/Resources/Python to the search paths for modules."""
298
Johnny Chen548aefd2010-10-11 22:25:46 +0000299 global rdir
300 global testdirs
301
Johnny Chen9707bb62010-06-25 21:14:08 +0000302 # Get the directory containing the current script.
Johnny Chena1affab2010-07-03 03:41:59 +0000303 scriptPath = sys.path[0]
304 if not scriptPath.endswith('test'):
Johnny Chen9707bb62010-06-25 21:14:08 +0000305 print "This script expects to reside in lldb's test directory."
306 sys.exit(-1)
307
Johnny Chen548aefd2010-10-11 22:25:46 +0000308 if rdir:
309 # Set up the LLDB_TEST environment variable appropriately, so that the
310 # individual tests can be located relatively.
311 #
312 # See also lldbtest.TestBase.setUpClass(cls).
313 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
314 os.environ["LLDB_TEST"] = os.path.join(rdir, 'test')
315 else:
316 os.environ["LLDB_TEST"] = rdir
317 else:
318 os.environ["LLDB_TEST"] = scriptPath
Johnny Chen9de4ede2010-08-31 17:42:54 +0000319 pluginPath = os.path.join(scriptPath, 'plugins')
Johnny Chen58f93922010-06-29 23:10:39 +0000320
Johnny Chenaf149a02010-09-16 17:11:30 +0000321 # Append script dir and plugin dir to the sys.path.
322 sys.path.append(scriptPath)
323 sys.path.append(pluginPath)
324
325 global ignore
326
327 # The '-i' option is used to skip looking for lldb.py in the build tree.
328 if ignore:
329 return
330
Johnny Chena1affab2010-07-03 03:41:59 +0000331 base = os.path.abspath(os.path.join(scriptPath, os.pardir))
Johnny Chen9707bb62010-06-25 21:14:08 +0000332 dbgPath = os.path.join(base, 'build', 'Debug', 'LLDB.framework',
333 'Resources', 'Python')
334 relPath = os.path.join(base, 'build', 'Release', 'LLDB.framework',
335 'Resources', 'Python')
Johnny Chenc202c462010-09-15 18:11:19 +0000336 baiPath = os.path.join(base, 'build', 'BuildAndIntegration',
337 'LLDB.framework', 'Resources', 'Python')
Johnny Chen9707bb62010-06-25 21:14:08 +0000338
339 lldbPath = None
340 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
341 lldbPath = dbgPath
342 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
343 lldbPath = relPath
Johnny Chenc202c462010-09-15 18:11:19 +0000344 elif os.path.isfile(os.path.join(baiPath, 'lldb.py')):
345 lldbPath = baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000346
347 if not lldbPath:
Johnny Chenc202c462010-09-15 18:11:19 +0000348 print 'This script requires lldb.py to be in either ' + dbgPath + ',',
349 print relPath + ', or ' + baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000350 sys.exit(-1)
351
Johnny Chenaf149a02010-09-16 17:11:30 +0000352 # This is to locate the lldb.py module. Insert it right after sys.path[0].
353 sys.path[1:1] = [lldbPath]
Johnny Chen9707bb62010-06-25 21:14:08 +0000354
Johnny Chen9707bb62010-06-25 21:14:08 +0000355
Johnny Chencd0279d2010-09-20 18:07:50 +0000356def doDelay(delta):
357 """Delaying startup for delta-seconds to facilitate debugger attachment."""
358 def alarm_handler(*args):
359 raise Exception("timeout")
360
361 signal.signal(signal.SIGALRM, alarm_handler)
362 signal.alarm(delta)
363 sys.stdout.write("pid=%d\n" % os.getpid())
364 sys.stdout.write("Enter RET to proceed (or timeout after %d seconds):" %
365 delta)
366 sys.stdout.flush()
367 try:
368 text = sys.stdin.readline()
369 except:
370 text = ""
371 signal.alarm(0)
372 sys.stdout.write("proceeding...\n")
373 pass
374
375
Johnny Chen9707bb62010-06-25 21:14:08 +0000376def visit(prefix, dir, names):
377 """Visitor function for os.path.walk(path, visit, arg)."""
378
379 global suite
Johnny Chen7c52ff12010-09-27 23:29:54 +0000380 global regexp
Johnny Chenb62436b2010-10-06 20:40:56 +0000381 global filterspec
382 global fs4all
Johnny Chen9707bb62010-06-25 21:14:08 +0000383
384 for name in names:
385 if os.path.isdir(os.path.join(dir, name)):
386 continue
387
388 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
Johnny Chen7c52ff12010-09-27 23:29:54 +0000389 # Try to match the regexp pattern, if specified.
390 if regexp:
391 import re
392 if re.search(regexp, name):
393 #print "Filename: '%s' matches pattern: '%s'" % (name, regexp)
394 pass
395 else:
396 #print "Filename: '%s' does not match pattern: '%s'" % (name, regexp)
397 continue
398
Johnny Chen953864a2010-10-12 21:35:54 +0000399 # We found a match for our test. Add it to the suite.
Johnny Chen79723352010-10-12 15:53:22 +0000400
401 # Update the sys.path first.
Johnny Chena85d7ee2010-06-26 00:19:32 +0000402 if not sys.path.count(dir):
Johnny Chen548aefd2010-10-11 22:25:46 +0000403 sys.path.insert(0, dir)
Johnny Chen9707bb62010-06-25 21:14:08 +0000404 base = os.path.splitext(name)[0]
Johnny Chenb62436b2010-10-06 20:40:56 +0000405
406 # Thoroughly check the filterspec against the base module and admit
407 # the (base, filterspec) combination only when it makes sense.
408 if filterspec:
409 # Optimistically set the flag to True.
410 filtered = True
411 module = __import__(base)
412 parts = filterspec.split('.')
413 obj = module
414 for part in parts:
415 try:
416 parent, obj = obj, getattr(obj, part)
417 except AttributeError:
418 # The filterspec has failed.
419 filtered = False
420 break
421 # Forgo this module if the (base, filterspec) combo is invalid
422 # and the '-g' option is present.
423 if fs4all and not filtered:
424 continue
425
Johnny Chen953864a2010-10-12 21:35:54 +0000426 # Add either the filtered test case or the entire test class.
Johnny Chenb62436b2010-10-06 20:40:56 +0000427 if filterspec and filtered:
428 suite.addTests(
429 unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
430 else:
431 # A simple case of just the module name. Also the failover case
432 # from the filterspec branch when the (base, filterspec) combo
433 # doesn't make sense.
434 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
Johnny Chen9707bb62010-06-25 21:14:08 +0000435
436
Johnny Chencd0279d2010-09-20 18:07:50 +0000437def lldbLoggings():
438 """Check and do lldb loggings if necessary."""
439
440 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
441 # defined. Use ${LLDB_LOG} to specify the log file.
442 ci = lldb.DBG.GetCommandInterpreter()
443 res = lldb.SBCommandReturnObject()
444 if ("LLDB_LOG" in os.environ):
445 if ("LLDB_LOG_OPTION" in os.environ):
446 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
447 else:
448 lldb_log_option = "event process"
449 ci.HandleCommand(
450 "log enable -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
451 res)
452 if not res.Succeeded():
453 raise Exception('log enable failed (check LLDB_LOG env variable.')
454 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
455 # Use ${GDB_REMOTE_LOG} to specify the log file.
456 if ("GDB_REMOTE_LOG" in os.environ):
457 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
458 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
459 else:
460 gdb_remote_log_option = "packets"
461 ci.HandleCommand(
462 "log enable -f " + os.environ["GDB_REMOTE_LOG"] + " process.gdb-remote "
463 + gdb_remote_log_option,
464 res)
465 if not res.Succeeded():
466 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
467
468
469############################################
470# #
471# Execution of the test driver starts here #
472# #
473############################################
474
Johnny Chen9707bb62010-06-25 21:14:08 +0000475#
Johnny Chenaf149a02010-09-16 17:11:30 +0000476# Start the actions by first parsing the options while setting up the test
477# directories, followed by setting up the search paths for lldb utilities;
478# then, we walk the directory trees and collect the tests into our test suite.
Johnny Chen9707bb62010-06-25 21:14:08 +0000479#
Johnny Chenaf149a02010-09-16 17:11:30 +0000480parseOptionsAndInitTestdirs()
Johnny Chen9707bb62010-06-25 21:14:08 +0000481setupSysPath()
Johnny Chen91960d32010-09-08 20:56:16 +0000482
483#
484# If '-d' is specified, do a delay of 10 seconds for the debugger to attach.
485#
486if delay:
Johnny Chencd0279d2010-09-20 18:07:50 +0000487 doDelay(10)
Johnny Chen91960d32010-09-08 20:56:16 +0000488
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000489#
Johnny Chen41998192010-10-01 22:59:49 +0000490# If '-l' is specified, do not skip the long running tests.
491if not skipLongRunningTest:
492 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
493
494#
Johnny Chen79723352010-10-12 15:53:22 +0000495# Walk through the testdirs while collecting tests.
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000496#
Johnny Chen9707bb62010-06-25 21:14:08 +0000497for testdir in testdirs:
498 os.path.walk(testdir, visit, 'Test')
499
Johnny Chenb40056b2010-09-21 00:09:27 +0000500#
Johnny Chen9707bb62010-06-25 21:14:08 +0000501# Now that we have loaded all the test cases, run the whole test suite.
Johnny Chenb40056b2010-09-21 00:09:27 +0000502#
Johnny Chencd0279d2010-09-20 18:07:50 +0000503
Johnny Chen1bfbd412010-06-29 19:44:16 +0000504# For the time being, let's bracket the test runner within the
505# lldb.SBDebugger.Initialize()/Terminate() pair.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000506import lldb, atexit
Johnny Chen6b6f5ba2010-10-14 16:36:49 +0000507# Update: the act of importing lldb now executes lldb.SBDebugger.Initialize(),
508# there's no need to call it a second time.
509#lldb.SBDebugger.Initialize()
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000510atexit.register(lambda: lldb.SBDebugger.Terminate())
Johnny Chen1bfbd412010-06-29 19:44:16 +0000511
Johnny Chen909e5a62010-07-01 22:52:57 +0000512# Create a singleton SBDebugger in the lldb namespace.
513lldb.DBG = lldb.SBDebugger.Create()
514
Johnny Chencd0279d2010-09-20 18:07:50 +0000515# Turn on lldb loggings if necessary.
516lldbLoggings()
Johnny Chen909e5a62010-07-01 22:52:57 +0000517
Johnny Chen7987ac92010-08-09 20:40:52 +0000518# Install the control-c handler.
519unittest2.signals.installHandler()
520
Johnny Chence681462010-10-19 00:25:01 +0000521# Now get a timestamp string and export it as LLDB_TIMESTAMP environment var.
522# This will be useful when/if we want to dump the session info of individual
523# test cases later on.
524#
525# See also TestBase.dumpSessionInfo() in lldbtest.py.
526import datetime
527raw_timestamp = str(datetime.datetime.today())
528os.environ["LLDB_TIMESTAMP"] = raw_timestamp.replace(' ', '-')
529
Johnny Chenb40056b2010-09-21 00:09:27 +0000530#
531# Invoke the default TextTestRunner to run the test suite, possibly iterating
532# over different configurations.
533#
534
Johnny Chenb40056b2010-09-21 00:09:27 +0000535iterArchs = False
Johnny Chenf032d902010-09-21 00:16:09 +0000536iterCompilers = False
Johnny Chenb40056b2010-09-21 00:09:27 +0000537
538from types import *
539if "archs" in config:
540 archs = config["archs"]
541 if type(archs) is ListType and len(archs) >= 1:
542 iterArchs = True
543if "compilers" in config:
544 compilers = config["compilers"]
545 if type(compilers) is ListType and len(compilers) >= 1:
546 iterCompilers = True
547
Johnny Chen953864a2010-10-12 21:35:54 +0000548# Make a shallow copy of sys.path, we need to manipulate the search paths later.
549# This is only necessary if we are relocated and with different configurations.
550if rdir and (iterArchs or iterCompilers):
551 old_sys_path = sys.path[:]
552 old_stderr = sys.stderr
553 old_stdout = sys.stdout
554 new_stderr = None
555 new_stdout = None
556
Johnny Chenb40056b2010-09-21 00:09:27 +0000557for ia in range(len(archs) if iterArchs else 1):
558 archConfig = ""
559 if iterArchs:
Johnny Chen18a921f2010-09-30 17:11:58 +0000560 os.environ["ARCH"] = archs[ia]
Johnny Chenb40056b2010-09-21 00:09:27 +0000561 archConfig = "arch=%s" % archs[ia]
562 for ic in range(len(compilers) if iterCompilers else 1):
563 if iterCompilers:
Johnny Chen18a921f2010-09-30 17:11:58 +0000564 os.environ["CC"] = compilers[ic]
Johnny Chenb40056b2010-09-21 00:09:27 +0000565 configString = "%s compiler=%s" % (archConfig, compilers[ic])
566 else:
567 configString = archConfig
568
Johnny Chenb40056b2010-09-21 00:09:27 +0000569 if iterArchs or iterCompilers:
Johnny Chen953864a2010-10-12 21:35:54 +0000570 # If we specified a relocated directory to run the test suite, do
571 # the extra housekeeping to copy the testdirs to a configStringified
572 # directory and to update sys.path before invoking the test runner.
573 # The purpose is to separate the configuration-specific directories
574 # from each other.
575 if rdir:
576 from string import maketrans
577 from shutil import copytree, ignore_patterns
578
579 # Translate ' ' to '-' for dir name.
580 tbl = maketrans(' ', '-')
581 configPostfix = configString.translate(tbl)
582 newrdir = "%s.%s" % (rdir, configPostfix)
583
584 # Copy the tree to a new directory with postfix name configPostfix.
585 copytree(rdir, newrdir, ignore=ignore_patterns('*.pyc', '*.o', '*.d'))
586
587 # Check whether we need to split stderr/stdout into configuration
588 # specific files.
589 if old_stderr.name != '<stderr>' and config.get('split_stderr'):
590 if new_stderr:
591 new_stderr.close()
592 new_stderr = open("%s.%s" % (old_stderr.name, configPostfix), "w")
593 sys.stderr = new_stderr
Johnny Chen4b6630e2010-10-12 21:50:36 +0000594 if old_stdout.name != '<stdout>' and config.get('split_stdout'):
Johnny Chen953864a2010-10-12 21:35:54 +0000595 if new_stdout:
596 new_stdout.close()
597 new_stdout = open("%s.%s" % (old_stdout.name, configPostfix), "w")
598 sys.stdout = new_stdout
599
600 # Update the LLDB_TEST environment variable to reflect new top
601 # level test directory.
602 #
603 # See also lldbtest.TestBase.setUpClass(cls).
604 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
605 os.environ["LLDB_TEST"] = os.path.join(newrdir, 'test')
606 else:
607 os.environ["LLDB_TEST"] = newrdir
608
609 # And update the Python search paths for modules.
610 sys.path = [x.replace(rdir, newrdir, 1) for x in old_sys_path]
611
612 # Output the configuration.
Johnny Chenb40056b2010-09-21 00:09:27 +0000613 sys.stderr.write("\nConfiguration: " + configString + "\n")
Johnny Chen953864a2010-10-12 21:35:54 +0000614
615 #print "sys.stderr name is", sys.stderr.name
616 #print "sys.stdout name is", sys.stdout.name
617
618 # First, write out the number of collected test cases.
619 sys.stderr.write(separator + "\n")
620 sys.stderr.write("Collected %d test%s\n\n"
621 % (suite.countTestCases(),
622 suite.countTestCases() != 1 and "s" or ""))
623
624 # Invoke the test runner.
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000625 class LLDBTestResult(unittest2.TextTestResult):
626 """
627 Enforce a singleton pattern to allow inspection of test progress.
628 """
629 __singleton__ = None
630
631 def __init__(self, *args):
632 if LLDBTestResult.__singleton__:
633 raise "LLDBTestResult instantiated more than once"
634 super(LLDBTestResult, self).__init__(*args)
635 LLDBTestResult.__singleton__ = self
636 # Now put this singleton into the lldb module namespace.
637 lldb.test_result = self
638
Johnny Chence681462010-10-19 00:25:01 +0000639 def addError(self, test, err):
640 super(LLDBTestResult, self).addError(test, err)
641 method = getattr(test, "markError", None)
642 if method:
643 method()
644
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000645 def addFailure(self, test, err):
646 super(LLDBTestResult, self).addFailure(test, err)
647 method = getattr(test, "markFailure", None)
648 if method:
649 method()
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000650
651 result = unittest2.TextTestRunner(stream=sys.stderr, verbosity=verbose,
652 resultclass=LLDBTestResult).run(suite)
Johnny Chenb40056b2010-09-21 00:09:27 +0000653
Johnny Chen1bfbd412010-06-29 19:44:16 +0000654
Johnny Chencd0279d2010-09-20 18:07:50 +0000655# Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
656# This should not be necessary now.
Johnny Chen83f6e512010-08-13 22:58:44 +0000657if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
658 import subprocess
659 print "Terminating Test suite..."
660 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
661
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000662# Exiting.
663sys.exit(not result.wasSuccessful)