blob: 0806074df5f8e97e2409df651b7ec0ccd674da94 [file] [log] [blame]
Johnny Chene8d9dc62011-10-31 19:04:07 +00001#!/usr/bin/env python
2
3"""
4Run the test suite using a separate process for each test file.
Vince Harronede59652015-01-08 02:11:26 +00005
Siva Chandra2d7832e2015-05-08 23:08:53 +00006Each test will run with a time limit of 10 minutes by default.
Vince Harronede59652015-01-08 02:11:26 +00007
Siva Chandra2d7832e2015-05-08 23:08:53 +00008Override the default time limit of 10 minutes by setting
Vince Harronede59652015-01-08 02:11:26 +00009the environment variable LLDB_TEST_TIMEOUT.
10
11E.g., export LLDB_TEST_TIMEOUT=10m
12
13Override the time limit for individual tests by setting
14the environment variable LLDB_[TEST NAME]_TIMEOUT.
15
16E.g., export LLDB_TESTCONCURRENTEVENTS_TIMEOUT=2m
17
18Set to "0" to run without time limit.
19
20E.g., export LLDB_TEST_TIMEOUT=0
21or export LLDB_TESTCONCURRENTEVENTS_TIMEOUT=0
Johnny Chene8d9dc62011-10-31 19:04:07 +000022"""
23
Greg Clayton2256d0d2014-03-24 23:01:57 +000024import multiprocessing
Todd Fiala3f0a3602014-07-08 06:42:37 +000025import os
26import platform
Vince Harron06381732015-05-12 23:10:36 +000027import re
Vince Harronf8b9a1d2015-05-18 19:40:54 +000028import dotest_args
Vince Harron17f429f2014-12-13 00:08:19 +000029import shlex
30import subprocess
Todd Fiala3f0a3602014-07-08 06:42:37 +000031import sys
Steve Puccibefe2b12014-03-07 00:01:11 +000032
Johnny Chene8d9dc62011-10-31 19:04:07 +000033from optparse import OptionParser
34
Vince Harron17f429f2014-12-13 00:08:19 +000035def get_timeout_command():
Vince Harronede59652015-01-08 02:11:26 +000036 """Search for a suitable timeout command."""
Vince Harron17f429f2014-12-13 00:08:19 +000037 if sys.platform.startswith("win32"):
38 return None
39 try:
40 subprocess.call("timeout")
41 return "timeout"
42 except OSError:
43 pass
44 try:
45 subprocess.call("gtimeout")
46 return "gtimeout"
47 except OSError:
48 pass
49 return None
50
51timeout_command = get_timeout_command()
52
Siva Chandra2d7832e2015-05-08 23:08:53 +000053default_timeout = os.getenv("LLDB_TEST_TIMEOUT") or "10m"
Vince Harron17f429f2014-12-13 00:08:19 +000054
55# Status codes for running command with timeout.
56eTimedOut, ePassed, eFailed = 124, 0, 1
57
58def call_with_timeout(command, timeout):
Vince Harronede59652015-01-08 02:11:26 +000059 """Run command with a timeout if possible."""
Zachary Turnerdc494d52015-02-07 00:14:55 +000060 if os.name != "nt":
61 if timeout_command and timeout != "0":
62 return subprocess.call([timeout_command, timeout] + command,
63 stdin=subprocess.PIPE, close_fds=True)
64 return (ePassed if subprocess.call(command, stdin=subprocess.PIPE, close_fds=True) == 0
65 else eFailed)
66 else:
67 if timeout_command and timeout != "0":
68 return subprocess.call([timeout_command, timeout] + command,
69 stdin=subprocess.PIPE)
70 return (ePassed if subprocess.call(command, stdin=subprocess.PIPE) == 0
71 else eFailed)
Johnny Chene8d9dc62011-10-31 19:04:07 +000072
Vince Harron41657cc2015-05-21 18:15:09 +000073def process_dir(root, files, test_root, dotest_argv):
Steve Puccibefe2b12014-03-07 00:01:11 +000074 """Examine a directory for tests, and invoke any found within it."""
Vince Harron17f429f2014-12-13 00:08:19 +000075 timed_out = []
Daniel Maleacbaef262013-02-15 21:31:37 +000076 failed = []
77 passed = []
Steve Puccibefe2b12014-03-07 00:01:11 +000078 for name in files:
79 path = os.path.join(root, name)
80
81 # We're only interested in the test file with the "Test*.py" naming pattern.
82 if not name.startswith("Test") or not name.endswith(".py"):
83 continue
84
85 # Neither a symbolically linked file.
86 if os.path.islink(path):
87 continue
88
Zachary Turnerf6896b02015-01-05 19:37:03 +000089 script_file = os.path.join(test_root, "dotest.py")
Zachary Turnerf6896b02015-01-05 19:37:03 +000090 command = ([sys.executable, script_file] +
Vince Harron41657cc2015-05-21 18:15:09 +000091 dotest_argv +
Vince Harron17f429f2014-12-13 00:08:19 +000092 ["-p", name, root])
93
94 timeout_name = os.path.basename(os.path.splitext(name)[0]).upper()
95
96 timeout = os.getenv("LLDB_%s_TIMEOUT" % timeout_name) or default_timeout
97
98 exit_status = call_with_timeout(command, timeout)
99
100 if ePassed == exit_status:
Steve Puccibefe2b12014-03-07 00:01:11 +0000101 passed.append(name)
Vince Harron17f429f2014-12-13 00:08:19 +0000102 else:
103 if eTimedOut == exit_status:
104 timed_out.append(name)
105 failed.append(name)
106 return (timed_out, failed, passed)
Steve Puccibefe2b12014-03-07 00:01:11 +0000107
108in_q = None
109out_q = None
110
Todd Fiala3f0a3602014-07-08 06:42:37 +0000111def process_dir_worker(arg_tuple):
Steve Puccibefe2b12014-03-07 00:01:11 +0000112 """Worker thread main loop when in multithreaded mode.
113 Takes one directory specification at a time and works on it."""
Vince Harron41657cc2015-05-21 18:15:09 +0000114 (root, files, test_root, dotest_argv) = arg_tuple
115 return process_dir(root, files, test_root, dotest_argv)
Steve Puccibefe2b12014-03-07 00:01:11 +0000116
Vince Harron41657cc2015-05-21 18:15:09 +0000117def walk_and_invoke(test_directory, test_subdir, dotest_argv, num_threads):
Steve Puccibefe2b12014-03-07 00:01:11 +0000118 """Look for matched files and invoke test driver on each one.
119 In single-threaded mode, each test driver is invoked directly.
120 In multi-threaded mode, submit each test driver to a worker
Vince Harrone06a7a82015-05-12 23:12:19 +0000121 queue, and then wait for all to complete.
122
123 test_directory - lldb/test/ directory
124 test_subdir - lldb/test/ or a subfolder with the tests we're interested in running
125 """
Todd Fiala3f0a3602014-07-08 06:42:37 +0000126
127 # Collect the test files that we'll run.
128 test_work_items = []
Vince Harrone06a7a82015-05-12 23:12:19 +0000129 for root, dirs, files in os.walk(test_subdir, topdown=False):
Vince Harron41657cc2015-05-21 18:15:09 +0000130 test_work_items.append((root, files, test_directory, dotest_argv))
Todd Fiala3f0a3602014-07-08 06:42:37 +0000131
132 # Run the items, either in a pool (for multicore speedup) or
133 # calling each individually.
134 if num_threads > 1:
135 pool = multiprocessing.Pool(num_threads)
136 test_results = pool.map(process_dir_worker, test_work_items)
137 else:
138 test_results = []
139 for work_item in test_work_items:
140 test_results.append(process_dir_worker(work_item))
141
Vince Harron17f429f2014-12-13 00:08:19 +0000142 timed_out = []
Steve Puccibefe2b12014-03-07 00:01:11 +0000143 failed = []
144 passed = []
Todd Fiala3f0a3602014-07-08 06:42:37 +0000145
146 for test_result in test_results:
Vince Harron17f429f2014-12-13 00:08:19 +0000147 (dir_timed_out, dir_failed, dir_passed) = test_result
148 timed_out += dir_timed_out
Todd Fiala3f0a3602014-07-08 06:42:37 +0000149 failed += dir_failed
150 passed += dir_passed
151
Vince Harron17f429f2014-12-13 00:08:19 +0000152 return (timed_out, failed, passed)
Johnny Chene8d9dc62011-10-31 19:04:07 +0000153
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000154def getExpectedTimeouts(platform_name):
Vince Harron06381732015-05-12 23:10:36 +0000155 # returns a set of test filenames that might timeout
156 # are we running against a remote target?
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000157 if platform_name is None:
Vince Harron06381732015-05-12 23:10:36 +0000158 target = sys.platform
159 remote = False
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000160 else:
161 m = re.search('remote-(\w+)', platform_name)
162 target = m.group(1)
163 remote = True
Vince Harron06381732015-05-12 23:10:36 +0000164
165 expected_timeout = set()
166
167 if target.startswith("linux"):
168 expected_timeout |= {
Vince Harronde92b522015-05-13 23:59:03 +0000169 "TestAttachDenied.py",
Vince Harron06381732015-05-12 23:10:36 +0000170 "TestAttachResume.py",
171 "TestConnectRemote.py",
172 "TestCreateAfterAttach.py",
Tamas Berghammer0d0ec9f2015-05-19 10:49:40 +0000173 "TestEvents.py",
Vince Harron06381732015-05-12 23:10:36 +0000174 "TestExitDuringStep.py",
175 "TestThreadStepOut.py",
176 }
177 elif target.startswith("android"):
178 expected_timeout |= {
179 "TestExitDuringStep.py",
180 "TestHelloWorld.py",
181 }
Ed Maste4dd8fba2015-05-14 16:25:52 +0000182 elif target.startswith("freebsd"):
183 expected_timeout |= {
184 "TestBreakpointConditions.py",
185 "TestWatchpointConditionAPI.py",
186 }
Vince Harron0f173ac2015-05-18 19:36:33 +0000187 elif target.startswith("darwin"):
188 expected_timeout |= {
189 "TestThreadSpecificBreakpoint.py", # times out on MBP Retina, Mid 2012
190 }
Vince Harron06381732015-05-12 23:10:36 +0000191 return expected_timeout
192
Vince Harron0b9dbb52015-05-21 18:18:52 +0000193def touch(fname, times=None):
194 with open(fname, 'a'):
195 os.utime(fname, times)
196
Johnny Chene8d9dc62011-10-31 19:04:07 +0000197def main():
Vince Harrond5fa1022015-05-10 15:24:12 +0000198 # We can't use sys.path[0] to determine the script directory
199 # because it doesn't work under a debugger
Vince Harrone06a7a82015-05-12 23:12:19 +0000200 test_directory = os.path.dirname(os.path.realpath(__file__))
Johnny Chene8d9dc62011-10-31 19:04:07 +0000201 parser = OptionParser(usage="""\
202Run lldb test suite using a separate process for each test file.
Vince Harronede59652015-01-08 02:11:26 +0000203
Siva Chandra2d7832e2015-05-08 23:08:53 +0000204 Each test will run with a time limit of 10 minutes by default.
Vince Harronede59652015-01-08 02:11:26 +0000205
Siva Chandra2d7832e2015-05-08 23:08:53 +0000206 Override the default time limit of 10 minutes by setting
Vince Harronede59652015-01-08 02:11:26 +0000207 the environment variable LLDB_TEST_TIMEOUT.
208
209 E.g., export LLDB_TEST_TIMEOUT=10m
210
211 Override the time limit for individual tests by setting
212 the environment variable LLDB_[TEST NAME]_TIMEOUT.
213
214 E.g., export LLDB_TESTCONCURRENTEVENTS_TIMEOUT=2m
215
216 Set to "0" to run without time limit.
217
218 E.g., export LLDB_TEST_TIMEOUT=0
219 or export LLDB_TESTCONCURRENTEVENTS_TIMEOUT=0
Johnny Chene8d9dc62011-10-31 19:04:07 +0000220""")
221 parser.add_option('-o', '--options',
222 type='string', action='store',
223 dest='dotest_options',
224 help="""The options passed to 'dotest.py' if specified.""")
225
Greg Clayton2256d0d2014-03-24 23:01:57 +0000226 parser.add_option('-t', '--threads',
227 type='int',
228 dest='num_threads',
Ed Mastecec2a5b2014-11-21 02:41:25 +0000229 help="""The number of threads to use when running tests separately.""")
Greg Clayton2256d0d2014-03-24 23:01:57 +0000230
Johnny Chene8d9dc62011-10-31 19:04:07 +0000231 opts, args = parser.parse_args()
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000232 dotest_option_string = opts.dotest_options
233
Vince Harron41657cc2015-05-21 18:15:09 +0000234 is_posix = (os.name == "posix")
235 dotest_argv = shlex.split(dotest_option_string, posix=is_posix) if dotest_option_string else []
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000236 dotest_options = dotest_args.getArguments(dotest_argv)
Vince Harron41657cc2015-05-21 18:15:09 +0000237 if not dotest_options.s:
238 # no session log directory, we need to add this to prevent
239 # every dotest invocation from creating its own directory
240 import datetime
241 # The windows platforms don't like ':' in the pathname.
242 timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
243 dotest_argv.append('-s')
244 dotest_argv.append(timestamp_started)
Vince Harron0b9dbb52015-05-21 18:18:52 +0000245 dotest_options.s = timestamp_started
246
247 session_dir = os.path.join(os.getcwd(), dotest_options.s)
Ed Mastecec2a5b2014-11-21 02:41:25 +0000248
Vince Harrone06a7a82015-05-12 23:12:19 +0000249 # The root directory was specified on the command line
250 if len(args) == 0:
251 test_subdir = test_directory
252 else:
253 test_subdir = os.path.join(test_directory, args[0])
254
Ed Mastecec2a5b2014-11-21 02:41:25 +0000255 if opts.num_threads:
256 num_threads = opts.num_threads
257 else:
Greg Clayton2256d0d2014-03-24 23:01:57 +0000258 num_threads_str = os.environ.get("LLDB_TEST_THREADS")
259 if num_threads_str:
260 num_threads = int(num_threads_str)
Greg Clayton2256d0d2014-03-24 23:01:57 +0000261 else:
Ed Mastecec2a5b2014-11-21 02:41:25 +0000262 num_threads = multiprocessing.cpu_count()
263 if num_threads < 1:
264 num_threads = 1
Johnny Chene8d9dc62011-10-31 19:04:07 +0000265
Daniel Maleab42556f2013-04-19 18:32:53 +0000266 system_info = " ".join(platform.uname())
Vince Harron41657cc2015-05-21 18:15:09 +0000267 (timed_out, failed, passed) = walk_and_invoke(test_directory, test_subdir, dotest_argv,
Vince Harron17f429f2014-12-13 00:08:19 +0000268 num_threads)
269 timed_out = set(timed_out)
Daniel Maleacbaef262013-02-15 21:31:37 +0000270 num_tests = len(failed) + len(passed)
Daniel Maleab42556f2013-04-19 18:32:53 +0000271
Vince Harron06381732015-05-12 23:10:36 +0000272 # remove expected timeouts from failures
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000273 expected_timeout = getExpectedTimeouts(dotest_options.lldb_platform_name)
Vince Harron06381732015-05-12 23:10:36 +0000274 for xtime in expected_timeout:
275 if xtime in timed_out:
276 timed_out.remove(xtime)
277 failed.remove(xtime)
Vince Harron0b9dbb52015-05-21 18:18:52 +0000278 result = "ExpectedTimeout"
279 elif xtime in passed:
280 result = "UnexpectedCompletion"
281 else:
282 result = None # failed
283
284 if result:
285 test_name = os.path.splitext(xtime)[0]
286 touch(os.path.join(session_dir, "{}-{}".format(result, test_name)))
Vince Harron06381732015-05-12 23:10:36 +0000287
Daniel Maleacbaef262013-02-15 21:31:37 +0000288 print "Ran %d tests." % num_tests
289 if len(failed) > 0:
Shawn Best13491c42014-10-22 19:29:00 +0000290 failed.sort()
Daniel Maleacbaef262013-02-15 21:31:37 +0000291 print "Failing Tests (%d)" % len(failed)
292 for f in failed:
Vince Harron17f429f2014-12-13 00:08:19 +0000293 print "%s: LLDB (suite) :: %s (%s)" % (
294 "TIMEOUT" if f in timed_out else "FAIL", f, system_info
295 )
Daniel Maleacbaef262013-02-15 21:31:37 +0000296 sys.exit(1)
297 sys.exit(0)
Johnny Chene8d9dc62011-10-31 19:04:07 +0000298
299if __name__ == '__main__':
300 main()