blob: b7a71df71294935ba9083641f2f2e70574390c50 [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 Chen91960d32010-09-08 20:56:16 +000048# Delay startup in order for the debugger to attach.
49delay = False
50
Johnny Chen9707bb62010-06-25 21:14:08 +000051# Default verbosity is 0.
52verbose = 0
53
54# By default, search from the current working directory.
55testdirs = [ os.getcwd() ]
56
Johnny Chen877c7e42010-08-07 00:16:07 +000057# Separator string.
58separator = '-' * 70
59
Johnny Chen840d8e32010-08-17 23:00:13 +000060# Decorated sys.stderr for our consumption.
61err = _WritelnDecorator(sys.stderr)
Johnny Chen877c7e42010-08-07 00:16:07 +000062
Johnny Chen9707bb62010-06-25 21:14:08 +000063
64def usage():
65 print """
66Usage: dotest.py [option] [args]
67where options:
68-h : print this help message and exit (also --help)
Johnny Chen91960d32010-09-08 20:56:16 +000069-d : delay startup for 10 seconds (in order for the debugger to attach)
Johnny Chend0c24b22010-08-23 17:10:44 +000070-t : trace lldb command execution and result
Johnny Chen9707bb62010-06-25 21:14:08 +000071-v : do verbose mode of unittest framework
72
73and:
74args : specify a list of directory names to search for python Test*.py scripts
75 if empty, search from the curret working directory, instead
Johnny Chen58f93922010-06-29 23:10:39 +000076
77Running of this script also sets up the LLDB_TEST environment variable so that
78individual test cases can locate their supporting files correctly.
Johnny Chenfde69bc2010-09-14 22:01:40 +000079
80Environment variables related to loggings:
81
82o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
83 with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
84
85o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
86 'process.gdb-remote' subsystem with a default option of 'packets' if
87 GDB_REMOTE_LOG_OPTION is not defined.
Johnny Chen9707bb62010-06-25 21:14:08 +000088"""
89
90
91def setupSysPath():
92 """Add LLDB.framework/Resources/Python to the search paths for modules."""
93
94 # Get the directory containing the current script.
Johnny Chena1affab2010-07-03 03:41:59 +000095 scriptPath = sys.path[0]
96 if not scriptPath.endswith('test'):
Johnny Chen9707bb62010-06-25 21:14:08 +000097 print "This script expects to reside in lldb's test directory."
98 sys.exit(-1)
99
Johnny Chena1affab2010-07-03 03:41:59 +0000100 os.environ["LLDB_TEST"] = scriptPath
Johnny Chen9de4ede2010-08-31 17:42:54 +0000101 pluginPath = os.path.join(scriptPath, 'plugins')
Johnny Chen58f93922010-06-29 23:10:39 +0000102
Johnny Chena1affab2010-07-03 03:41:59 +0000103 base = os.path.abspath(os.path.join(scriptPath, os.pardir))
Johnny Chen9707bb62010-06-25 21:14:08 +0000104 dbgPath = os.path.join(base, 'build', 'Debug', 'LLDB.framework',
105 'Resources', 'Python')
106 relPath = os.path.join(base, 'build', 'Release', 'LLDB.framework',
107 'Resources', 'Python')
Johnny Chenc202c462010-09-15 18:11:19 +0000108 baiPath = os.path.join(base, 'build', 'BuildAndIntegration',
109 'LLDB.framework', 'Resources', 'Python')
Johnny Chen9707bb62010-06-25 21:14:08 +0000110
111 lldbPath = None
112 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
113 lldbPath = dbgPath
114 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
115 lldbPath = relPath
Johnny Chenc202c462010-09-15 18:11:19 +0000116 elif os.path.isfile(os.path.join(baiPath, 'lldb.py')):
117 lldbPath = baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000118
119 if not lldbPath:
Johnny Chenc202c462010-09-15 18:11:19 +0000120 print 'This script requires lldb.py to be in either ' + dbgPath + ',',
121 print relPath + ', or ' + baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000122 sys.exit(-1)
123
124 sys.path.append(lldbPath)
Johnny Chena1affab2010-07-03 03:41:59 +0000125 sys.path.append(scriptPath)
Johnny Chen9de4ede2010-08-31 17:42:54 +0000126 sys.path.append(pluginPath)
Johnny Chen9707bb62010-06-25 21:14:08 +0000127
128
129def initTestdirs():
130 """Initialize the list of directories containing our unittest scripts.
131
132 '-h/--help as the first option prints out usage info and exit the program.
133 """
134
Johnny Chen91960d32010-09-08 20:56:16 +0000135 global delay
Johnny Chen9707bb62010-06-25 21:14:08 +0000136 global verbose
137 global testdirs
138
139 if len(sys.argv) == 1:
140 pass
141 elif sys.argv[1].find('-h') != -1:
142 # Print usage info and exit.
143 usage()
144 sys.exit(0)
145 else:
Johnny Chend0c24b22010-08-23 17:10:44 +0000146 # Process possible trace and/or verbose flag.
Johnny Chen9707bb62010-06-25 21:14:08 +0000147 index = 1
Johnny Chenfde69bc2010-09-14 22:01:40 +0000148 for i in range(1, len(sys.argv)):
149 if not sys.argv[index].startswith('-'):
150 # End of option processing.
151 break
152
Johnny Chen91960d32010-09-08 20:56:16 +0000153 if sys.argv[index].startswith('-d'):
154 delay = True
155 index += 1
Johnny Chenfde69bc2010-09-14 22:01:40 +0000156 elif sys.argv[index].startswith('-t'):
Johnny Chend0c24b22010-08-23 17:10:44 +0000157 os.environ["LLDB_COMMAND_TRACE"] = "YES"
158 index += 1
Johnny Chenfde69bc2010-09-14 22:01:40 +0000159 elif sys.argv[index].startswith('-v'):
Johnny Chend0c24b22010-08-23 17:10:44 +0000160 verbose = 2
161 index += 1
Johnny Chen9707bb62010-06-25 21:14:08 +0000162
163 # Gather all the dirs passed on the command line.
164 if len(sys.argv) > index:
165 testdirs = map(os.path.abspath, sys.argv[index:])
166
Johnny Chen9707bb62010-06-25 21:14:08 +0000167
168def visit(prefix, dir, names):
169 """Visitor function for os.path.walk(path, visit, arg)."""
170
171 global suite
172
173 for name in names:
174 if os.path.isdir(os.path.join(dir, name)):
175 continue
176
177 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
178 # We found a pattern match for our test case. Add it to the suite.
Johnny Chena85d7ee2010-06-26 00:19:32 +0000179 if not sys.path.count(dir):
180 sys.path.append(dir)
Johnny Chen9707bb62010-06-25 21:14:08 +0000181 base = os.path.splitext(name)[0]
Johnny Chen75e28f92010-08-05 23:42:46 +0000182 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
Johnny Chen9707bb62010-06-25 21:14:08 +0000183
184
185#
186# Start the actions by first setting up the module search path for lldb,
187# followed by initializing the test directories, and then walking the directory
188# trees, while collecting the tests into our test suite.
189#
190setupSysPath()
191initTestdirs()
Johnny Chen91960d32010-09-08 20:56:16 +0000192
193#
194# If '-d' is specified, do a delay of 10 seconds for the debugger to attach.
195#
196if delay:
197 def alarm_handler(*args):
198 raise Exception("timeout")
199
200 signal.signal(signal.SIGALRM, alarm_handler)
201 signal.alarm(10)
202 sys.stdout.write("pid=" + str(os.getpid()) + '\n')
203 sys.stdout.write("Enter RET to proceed (or timeout after 10 seconds):")
204 sys.stdout.flush()
205 try:
206 text = sys.stdin.readline()
207 except:
208 text = ""
209 signal.alarm(0)
210 sys.stdout.write("proceeding...\n")
211 pass
212
Johnny Chen9707bb62010-06-25 21:14:08 +0000213for testdir in testdirs:
214 os.path.walk(testdir, visit, 'Test')
215
216# Now that we have loaded all the test cases, run the whole test suite.
Johnny Chen840d8e32010-08-17 23:00:13 +0000217err.writeln(separator)
218err.writeln("Collected %d test%s" % (suite.countTestCases(),
Johnny Chen877c7e42010-08-07 00:16:07 +0000219 suite.countTestCases() != 1 and "s" or ""))
Johnny Chen840d8e32010-08-17 23:00:13 +0000220err.writeln()
Johnny Chen1bfbd412010-06-29 19:44:16 +0000221
222# For the time being, let's bracket the test runner within the
223# lldb.SBDebugger.Initialize()/Terminate() pair.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000224import lldb, atexit
Johnny Chen1bfbd412010-06-29 19:44:16 +0000225lldb.SBDebugger.Initialize()
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000226atexit.register(lambda: lldb.SBDebugger.Terminate())
Johnny Chen1bfbd412010-06-29 19:44:16 +0000227
Johnny Chen909e5a62010-07-01 22:52:57 +0000228# Create a singleton SBDebugger in the lldb namespace.
229lldb.DBG = lldb.SBDebugger.Create()
230
231# Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
Johnny Chen1a437262010-08-16 22:37:45 +0000232# defined. Use ${LLDB_LOG} to specify the log file.
Johnny Chen909e5a62010-07-01 22:52:57 +0000233ci = lldb.DBG.GetCommandInterpreter()
234res = lldb.SBCommandReturnObject()
235if ("LLDB_LOG" in os.environ):
Johnny Chen4e6c8882010-08-17 21:36:09 +0000236 if ("LLDB_LOG_OPTION" in os.environ):
237 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
238 else:
239 lldb_log_option = "event process"
Johnny Chen909e5a62010-07-01 22:52:57 +0000240 ci.HandleCommand(
Johnny Chen4e6c8882010-08-17 21:36:09 +0000241 "log enable -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
242 res)
Johnny Chen797674b2010-07-02 20:35:23 +0000243 if not res.Succeeded():
Johnny Chen4e6c8882010-08-17 21:36:09 +0000244 raise Exception('log enable failed (check LLDB_LOG env variable.')
Johnny Chenfde69bc2010-09-14 22:01:40 +0000245# Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
Johnny Chen1a437262010-08-16 22:37:45 +0000246# Use ${GDB_REMOTE_LOG} to specify the log file.
247if ("GDB_REMOTE_LOG" in os.environ):
Johnny Chen4e6c8882010-08-17 21:36:09 +0000248 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
249 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
250 else:
251 gdb_remote_log_option = "packets"
Johnny Chen1a437262010-08-16 22:37:45 +0000252 ci.HandleCommand(
Johnny Chen4e6c8882010-08-17 21:36:09 +0000253 "log enable -f " + os.environ["GDB_REMOTE_LOG"] + " process.gdb-remote "
254 + gdb_remote_log_option,
255 res)
Johnny Chen1a437262010-08-16 22:37:45 +0000256 if not res.Succeeded():
Johnny Chen4e6c8882010-08-17 21:36:09 +0000257 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
Johnny Chen909e5a62010-07-01 22:52:57 +0000258
Johnny Chen7987ac92010-08-09 20:40:52 +0000259# Install the control-c handler.
260unittest2.signals.installHandler()
261
262# Invoke the default TextTestRunner to run the test suite.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000263result = unittest2.TextTestRunner(verbosity=verbose).run(suite)
Johnny Chen1bfbd412010-06-29 19:44:16 +0000264
Johnny Chen83f6e512010-08-13 22:58:44 +0000265if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
266 import subprocess
267 print "Terminating Test suite..."
268 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
269
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000270# Exiting.
271sys.exit(not result.wasSuccessful)