blob: 716adbc3c288b5d50ede923b323b07826b4d8c10 [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
Vince Harrondcc2b9f2015-05-27 04:40:36 +000022
Chaoren Linb6325d02015-08-12 18:02:54 +000023To collect core files for timed out tests,
24do the following before running dosep.py
Vince Harrondcc2b9f2015-05-27 04:40:36 +000025
26OSX
27ulimit -c unlimited
28sudo sysctl -w kern.corefile=core.%P
29
30Linux:
31ulimit -c unlimited
32echo core.%p | sudo tee /proc/sys/kernel/core_pattern
Johnny Chene8d9dc62011-10-31 19:04:07 +000033"""
34
Zachary Turnerff890da2015-10-19 23:45:41 +000035from __future__ import print_function
36
Zachary Turner0a0490b2015-10-27 20:12:05 +000037import use_lldb_suite
Zachary Turner814236d2015-10-21 17:48:52 +000038
Todd Fiala2d3754d2015-09-29 22:19:06 +000039# system packages and modules
Todd Fiala68615ce2015-09-15 21:38:04 +000040import asyncore
Todd Fiala83c32e32015-09-22 21:19:40 +000041import distutils.version
Vince Harrondcc2b9f2015-05-27 04:40:36 +000042import fnmatch
Todd Fiala8cbeed32015-09-08 22:22:33 +000043import multiprocessing
44import multiprocessing.pool
45import os
Todd Fiala3f0a3602014-07-08 06:42:37 +000046import platform
Vince Harron06381732015-05-12 23:10:36 +000047import re
Todd Fiala8cbeed32015-09-08 22:22:33 +000048import signal
Todd Fiala3f0a3602014-07-08 06:42:37 +000049import sys
Todd Fiala8cbeed32015-09-08 22:22:33 +000050import threading
Todd Fiala2d3754d2015-09-29 22:19:06 +000051
Zachary Turner814236d2015-10-21 17:48:52 +000052from six.moves import queue
53
Todd Fiala2d3754d2015-09-29 22:19:06 +000054# Add our local test_runner/lib dir to the python path.
55sys.path.append(os.path.join(os.path.dirname(__file__), "test_runner", "lib"))
56
57# Our packages and modules
Todd Fiala68615ce2015-09-15 21:38:04 +000058import dotest_channels
Todd Fiala8cbeed32015-09-08 22:22:33 +000059import dotest_args
Todd Fiala2d3754d2015-09-29 22:19:06 +000060import lldb_utils
61import process_control
Vince Harron17f429f2014-12-13 00:08:19 +000062
Vince Harron17f429f2014-12-13 00:08:19 +000063# Status codes for running command with timeout.
64eTimedOut, ePassed, eFailed = 124, 0, 1
65
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +000066output_lock = None
67test_counter = None
68total_tests = None
Chaoren Linffc63b02015-08-12 18:02:49 +000069test_name_len = None
Pavel Labath05ab2372015-07-06 15:57:52 +000070dotest_options = None
Zachary Turner38e64172015-08-10 17:46:11 +000071output_on_success = False
Todd Fiala68615ce2015-09-15 21:38:04 +000072RESULTS_FORMATTER = None
73RUNNER_PROCESS_ASYNC_MAP = None
74RESULTS_LISTENER_CHANNEL = None
Chaoren Linb6325d02015-08-12 18:02:54 +000075
Todd Fiala33896a92015-09-18 21:01:13 +000076"""Contains an optional function pointer that can return the worker index
77 for the given thread/process calling it. Returns a 0-based index."""
78GET_WORKER_INDEX = None
79
Todd Fiala1cc97b42015-09-21 05:42:26 +000080
Todd Fiala33896a92015-09-18 21:01:13 +000081def setup_global_variables(
82 lock, counter, total, name_len, options, worker_index_map):
Chaoren Linffc63b02015-08-12 18:02:49 +000083 global output_lock, test_counter, total_tests, test_name_len
84 global dotest_options
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +000085 output_lock = lock
86 test_counter = counter
87 total_tests = total
Chaoren Linffc63b02015-08-12 18:02:49 +000088 test_name_len = name_len
Pavel Labath05ab2372015-07-06 15:57:52 +000089 dotest_options = options
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +000090
Todd Fiala33896a92015-09-18 21:01:13 +000091 if worker_index_map is not None:
92 # We'll use the output lock for this to avoid sharing another lock.
93 # This won't be used much.
94 index_lock = lock
95
96 def get_worker_index_use_pid():
97 """Returns a 0-based, process-unique index for the worker."""
98 pid = os.getpid()
99 with index_lock:
100 if pid not in worker_index_map:
101 worker_index_map[pid] = len(worker_index_map)
102 return worker_index_map[pid]
103
104 global GET_WORKER_INDEX
105 GET_WORKER_INDEX = get_worker_index_use_pid
106
Chaoren Linb6325d02015-08-12 18:02:54 +0000107
Zachary Turner38e64172015-08-10 17:46:11 +0000108def report_test_failure(name, command, output):
109 global output_lock
110 with output_lock:
Greg Clayton1827fc22015-09-19 00:39:09 +0000111 if not (RESULTS_FORMATTER and RESULTS_FORMATTER.is_using_terminal()):
Zachary Turnerff890da2015-10-19 23:45:41 +0000112 print(file=sys.stderr)
113 print(output, file=sys.stderr)
114 print("[%s FAILED]" % name, file=sys.stderr)
115 print("Command invoked: %s" % ' '.join(command), file=sys.stderr)
Chaoren Linffc63b02015-08-12 18:02:49 +0000116 update_progress(name)
Zachary Turner38e64172015-08-10 17:46:11 +0000117
Chaoren Linb6325d02015-08-12 18:02:54 +0000118
Zachary Turner38e64172015-08-10 17:46:11 +0000119def report_test_pass(name, output):
120 global output_lock, output_on_success
121 with output_lock:
Greg Clayton1827fc22015-09-19 00:39:09 +0000122 if not (RESULTS_FORMATTER and RESULTS_FORMATTER.is_using_terminal()):
123 if output_on_success:
Zachary Turnerff890da2015-10-19 23:45:41 +0000124 print(file=sys.stderr)
125 print(output, file=sys.stderr)
126 print("[%s PASSED]" % name, file=sys.stderr)
Chaoren Linffc63b02015-08-12 18:02:49 +0000127 update_progress(name)
Zachary Turner38e64172015-08-10 17:46:11 +0000128
Chaoren Linb6325d02015-08-12 18:02:54 +0000129
Chaoren Linffc63b02015-08-12 18:02:49 +0000130def update_progress(test_name=""):
131 global output_lock, test_counter, total_tests, test_name_len
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +0000132 with output_lock:
Chaoren Linffc63b02015-08-12 18:02:49 +0000133 counter_len = len(str(total_tests))
Greg Clayton1827fc22015-09-19 00:39:09 +0000134 if not (RESULTS_FORMATTER and RESULTS_FORMATTER.is_using_terminal()):
135 sys.stderr.write(
136 "\r%*d out of %d test suites processed - %-*s" %
137 (counter_len, test_counter.value, total_tests,
138 test_name_len.value, test_name))
Chaoren Linffc63b02015-08-12 18:02:49 +0000139 if len(test_name) > test_name_len.value:
140 test_name_len.value = len(test_name)
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +0000141 test_counter.value += 1
Zachary Turner38e64172015-08-10 17:46:11 +0000142 sys.stdout.flush()
143 sys.stderr.flush()
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +0000144
Chaoren Linb6325d02015-08-12 18:02:54 +0000145
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000146def parse_test_results(output):
147 passes = 0
148 failures = 0
Zachary Turner4cceca72015-08-14 16:45:32 +0000149 unexpected_successes = 0
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000150 for result in output:
Chaoren Linb6325d02015-08-12 18:02:54 +0000151 pass_count = re.search("^RESULT:.*([0-9]+) passes",
152 result, re.MULTILINE)
153 fail_count = re.search("^RESULT:.*([0-9]+) failures",
154 result, re.MULTILINE)
155 error_count = re.search("^RESULT:.*([0-9]+) errors",
156 result, re.MULTILINE)
Zachary Turner4cceca72015-08-14 16:45:32 +0000157 unexpected_success_count = re.search("^RESULT:.*([0-9]+) unexpected successes",
158 result, re.MULTILINE)
Chaoren Linb6325d02015-08-12 18:02:54 +0000159 if pass_count is not None:
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000160 passes = passes + int(pass_count.group(1))
Chaoren Linb6325d02015-08-12 18:02:54 +0000161 if fail_count is not None:
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000162 failures = failures + int(fail_count.group(1))
Zachary Turner4cceca72015-08-14 16:45:32 +0000163 if unexpected_success_count is not None:
164 unexpected_successes = unexpected_successes + int(unexpected_success_count.group(1))
Chaoren Linb6325d02015-08-12 18:02:54 +0000165 if error_count is not None:
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000166 failures = failures + int(error_count.group(1))
Zachary Turner4cceca72015-08-14 16:45:32 +0000167 return passes, failures, unexpected_successes
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000168
Chaoren Linb6325d02015-08-12 18:02:54 +0000169
Todd Fiala2d3754d2015-09-29 22:19:06 +0000170class DoTestProcessDriver(process_control.ProcessDriver):
171 """Drives the dotest.py inferior process and handles bookkeeping."""
172 def __init__(self, output_file, output_file_lock, pid_events, file_name,
173 soft_terminate_timeout):
174 super(DoTestProcessDriver, self).__init__(
175 soft_terminate_timeout=soft_terminate_timeout)
176 self.output_file = output_file
177 self.output_lock = lldb_utils.OptionalWith(output_file_lock)
178 self.pid_events = pid_events
179 self.results = None
180 self.file_name = file_name
181
182 def write(self, content):
183 with self.output_lock:
184 self.output_file.write(content)
185
186 def on_process_started(self):
187 if self.pid_events:
188 self.pid_events.put_nowait(('created', self.process.pid))
189
190 def on_process_exited(self, command, output, was_timeout, exit_status):
191 if self.pid_events:
192 # No point in culling out those with no exit_status (i.e.
193 # those we failed to kill). That would just cause
194 # downstream code to try to kill it later on a Ctrl-C. At
195 # this point, a best-effort-to-kill already took place. So
196 # call it destroyed here.
197 self.pid_events.put_nowait(('destroyed', self.process.pid))
198
199 # Override the exit status if it was a timeout.
200 if was_timeout:
201 exit_status = eTimedOut
202
203 # If we didn't end up with any output, call it empty for
204 # stdout/stderr.
205 if output is None:
206 output = ('', '')
207
208 # Now parse the output.
209 passes, failures, unexpected_successes = parse_test_results(output)
210 if exit_status == 0:
211 # stdout does not have any useful information from 'dotest.py',
212 # only stderr does.
213 report_test_pass(self.file_name, output[1])
214 else:
215 report_test_failure(self.file_name, command, output[1])
216
217 # Save off the results for the caller.
218 self.results = (
219 self.file_name,
220 exit_status,
221 passes,
222 failures,
223 unexpected_successes)
224
225
226def get_soft_terminate_timeout():
227 # Defaults to 10 seconds, but can set
228 # LLDB_TEST_SOFT_TERMINATE_TIMEOUT to a floating point
229 # number in seconds. This value indicates how long
230 # the test runner will wait for the dotest inferior to
231 # handle a timeout via a soft terminate before it will
232 # assume that failed and do a hard terminate.
233
234 # TODO plumb through command-line option
235 return float(os.environ.get('LLDB_TEST_SOFT_TERMINATE_TIMEOUT', 10.0))
236
237
238def want_core_on_soft_terminate():
239 # TODO plumb through command-line option
240 if platform.system() == 'Linux':
241 return True
242 else:
243 return False
Todd Fialada817b62015-09-22 18:05:11 +0000244
245
Todd Fiala8cbeed32015-09-08 22:22:33 +0000246def call_with_timeout(command, timeout, name, inferior_pid_events):
Todd Fiala2d3754d2015-09-29 22:19:06 +0000247 # Add our worker index (if we have one) to all test events
248 # from this inferior.
Todd Fiala33896a92015-09-18 21:01:13 +0000249 if GET_WORKER_INDEX is not None:
Todd Fialae83f1402015-09-18 22:45:31 +0000250 try:
251 worker_index = GET_WORKER_INDEX()
252 command.extend([
Todd Fiala2d3754d2015-09-29 22:19:06 +0000253 "--event-add-entries",
254 "worker_index={}:int".format(worker_index)])
255 except: # pylint: disable=bare-except
256 # Ctrl-C does bad things to multiprocessing.Manager.dict()
257 # lookup. Just swallow it.
Todd Fialae83f1402015-09-18 22:45:31 +0000258 pass
259
Todd Fiala2d3754d2015-09-29 22:19:06 +0000260 # Create the inferior dotest.py ProcessDriver.
261 soft_terminate_timeout = get_soft_terminate_timeout()
262 want_core = want_core_on_soft_terminate()
Todd Fiala68615ce2015-09-15 21:38:04 +0000263
Todd Fiala2d3754d2015-09-29 22:19:06 +0000264 process_driver = DoTestProcessDriver(
265 sys.stdout,
266 output_lock,
267 inferior_pid_events,
268 name,
269 soft_terminate_timeout)
Todd Fiala68615ce2015-09-15 21:38:04 +0000270
Todd Fiala2d3754d2015-09-29 22:19:06 +0000271 # Run it with a timeout.
272 process_driver.run_command_with_timeout(command, timeout, want_core)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000273
Todd Fiala2d3754d2015-09-29 22:19:06 +0000274 # Return the results.
275 if not process_driver.results:
276 # This is truly exceptional. Even a failing or timed out
277 # binary should have called the results-generation code.
278 raise Exception("no test results were generated whatsoever")
279 return process_driver.results
Johnny Chene8d9dc62011-10-31 19:04:07 +0000280
Chaoren Linb6325d02015-08-12 18:02:54 +0000281
Todd Fiala8cbeed32015-09-08 22:22:33 +0000282def process_dir(root, files, test_root, dotest_argv, inferior_pid_events):
Steve Puccibefe2b12014-03-07 00:01:11 +0000283 """Examine a directory for tests, and invoke any found within it."""
Chaoren Line80372a2015-08-12 18:02:53 +0000284 results = []
Steve Puccibefe2b12014-03-07 00:01:11 +0000285 for name in files:
Zachary Turnerf6896b02015-01-05 19:37:03 +0000286 script_file = os.path.join(test_root, "dotest.py")
Zachary Turnerf6896b02015-01-05 19:37:03 +0000287 command = ([sys.executable, script_file] +
Vince Harron41657cc2015-05-21 18:15:09 +0000288 dotest_argv +
Todd Fialafed95662015-09-03 18:58:44 +0000289 ["--inferior", "-p", name, root])
Vince Harron17f429f2014-12-13 00:08:19 +0000290
291 timeout_name = os.path.basename(os.path.splitext(name)[0]).upper()
292
Chaoren Linb6325d02015-08-12 18:02:54 +0000293 timeout = (os.getenv("LLDB_%s_TIMEOUT" % timeout_name) or
294 getDefaultTimeout(dotest_options.lldb_platform_name))
Vince Harron17f429f2014-12-13 00:08:19 +0000295
Todd Fiala8cbeed32015-09-08 22:22:33 +0000296 results.append(call_with_timeout(
297 command, timeout, name, inferior_pid_events))
Vince Harron17f429f2014-12-13 00:08:19 +0000298
Zachary Turner4cceca72015-08-14 16:45:32 +0000299 # result = (name, status, passes, failures, unexpected_successes)
300 timed_out = [name for name, status, _, _, _ in results
Chaoren Line80372a2015-08-12 18:02:53 +0000301 if status == eTimedOut]
Zachary Turner4cceca72015-08-14 16:45:32 +0000302 passed = [name for name, status, _, _, _ in results
Chaoren Line80372a2015-08-12 18:02:53 +0000303 if status == ePassed]
Zachary Turner4cceca72015-08-14 16:45:32 +0000304 failed = [name for name, status, _, _, _ in results
Chaoren Line80372a2015-08-12 18:02:53 +0000305 if status != ePassed]
Zachary Turner4cceca72015-08-14 16:45:32 +0000306 unexpected_passes = [name for name, _, _, _, unexpected_successes in results
307 if unexpected_successes > 0]
Todd Fialafed95662015-09-03 18:58:44 +0000308
Chaoren Line80372a2015-08-12 18:02:53 +0000309 pass_count = sum([result[2] for result in results])
310 fail_count = sum([result[3] for result in results])
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000311
Zachary Turner4cceca72015-08-14 16:45:32 +0000312 return (timed_out, passed, failed, unexpected_passes, pass_count, fail_count)
Steve Puccibefe2b12014-03-07 00:01:11 +0000313
314in_q = None
315out_q = None
316
Chaoren Linb6325d02015-08-12 18:02:54 +0000317
Todd Fiala8cbeed32015-09-08 22:22:33 +0000318def process_dir_worker_multiprocessing(
319 a_output_lock, a_test_counter, a_total_tests, a_test_name_len,
Todd Fiala33896a92015-09-18 21:01:13 +0000320 a_dotest_options, job_queue, result_queue, inferior_pid_events,
321 worker_index_map):
Todd Fiala8cbeed32015-09-08 22:22:33 +0000322 """Worker thread main loop when in multiprocessing mode.
Steve Puccibefe2b12014-03-07 00:01:11 +0000323 Takes one directory specification at a time and works on it."""
Todd Fiala8cbeed32015-09-08 22:22:33 +0000324
325 # Shut off interrupt handling in the child process.
326 signal.signal(signal.SIGINT, signal.SIG_IGN)
Ying Chend93aa102015-09-23 21:53:18 +0000327 if hasattr(signal, 'SIGHUP'):
328 signal.signal(signal.SIGHUP, signal.SIG_IGN)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000329
330 # Setup the global state for the worker process.
331 setup_global_variables(
332 a_output_lock, a_test_counter, a_total_tests, a_test_name_len,
Todd Fiala33896a92015-09-18 21:01:13 +0000333 a_dotest_options, worker_index_map)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000334
335 # Keep grabbing entries from the queue until done.
336 while not job_queue.empty():
337 try:
338 job = job_queue.get(block=False)
339 result = process_dir(job[0], job[1], job[2], job[3],
340 inferior_pid_events)
341 result_queue.put(result)
Zachary Turner814236d2015-10-21 17:48:52 +0000342 except queue.Empty:
Todd Fiala8cbeed32015-09-08 22:22:33 +0000343 # Fine, we're done.
344 pass
Steve Puccibefe2b12014-03-07 00:01:11 +0000345
Chaoren Linb6325d02015-08-12 18:02:54 +0000346
Todd Fiala8cbeed32015-09-08 22:22:33 +0000347def process_dir_worker_multiprocessing_pool(args):
348 return process_dir(*args)
349
350
Todd Fiala68615ce2015-09-15 21:38:04 +0000351def process_dir_worker_threading(job_queue, result_queue, inferior_pid_events):
Todd Fiala8cbeed32015-09-08 22:22:33 +0000352 """Worker thread main loop when in threading mode.
353
354 This one supports the hand-rolled pooling support.
355
356 Takes one directory specification at a time and works on it."""
357
358 # Keep grabbing entries from the queue until done.
359 while not job_queue.empty():
360 try:
361 job = job_queue.get(block=False)
362 result = process_dir(job[0], job[1], job[2], job[3],
363 inferior_pid_events)
364 result_queue.put(result)
Zachary Turner814236d2015-10-21 17:48:52 +0000365 except queue.Empty:
Todd Fiala8cbeed32015-09-08 22:22:33 +0000366 # Fine, we're done.
367 pass
368
369
370def process_dir_worker_threading_pool(args):
371 return process_dir(*args)
372
373
374def process_dir_mapper_inprocess(args):
375 """Map adapter for running the subprocess-based, non-threaded test runner.
376
377 @param args the process work item tuple
378 @return the test result tuple
379 """
380 return process_dir(*args)
381
382
383def collect_active_pids_from_pid_events(event_queue):
384 """
385 Returns the set of what should be active inferior pids based on
386 the event stream.
387
388 @param event_queue a multiprocessing.Queue containing events of the
389 form:
390 ('created', pid)
391 ('destroyed', pid)
392
393 @return set of inferior dotest.py pids activated but never completed.
394 """
395 active_pid_set = set()
396 while not event_queue.empty():
397 pid_event = event_queue.get_nowait()
398 if pid_event[0] == 'created':
399 active_pid_set.add(pid_event[1])
400 elif pid_event[0] == 'destroyed':
401 active_pid_set.remove(pid_event[1])
402 return active_pid_set
403
404
405def kill_all_worker_processes(workers, inferior_pid_events):
406 """
407 Kills all specified worker processes and their process tree.
408
409 @param workers a list of multiprocess.Process worker objects.
410 @param inferior_pid_events a multiprocess.Queue that contains
411 all inferior create and destroy events. Used to construct
412 the list of child pids still outstanding that need to be killed.
413 """
414 for worker in workers:
415 worker.terminate()
416 worker.join()
417
418 # Add all the child test pids created.
419 active_pid_set = collect_active_pids_from_pid_events(
420 inferior_pid_events)
421 for inferior_pid in active_pid_set:
Zachary Turnerff890da2015-10-19 23:45:41 +0000422 print("killing inferior pid {}".format(inferior_pid))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000423 os.kill(inferior_pid, signal.SIGKILL)
424
425
426def kill_all_worker_threads(workers, inferior_pid_events):
427 """
428 Kills all specified worker threads and their process tree.
429
430 @param workers a list of multiprocess.Process worker objects.
431 @param inferior_pid_events a multiprocess.Queue that contains
432 all inferior create and destroy events. Used to construct
433 the list of child pids still outstanding that need to be killed.
434 """
435
436 # Add all the child test pids created.
437 active_pid_set = collect_active_pids_from_pid_events(
438 inferior_pid_events)
439 for inferior_pid in active_pid_set:
Zachary Turnerff890da2015-10-19 23:45:41 +0000440 print("killing inferior pid {}".format(inferior_pid))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000441 os.kill(inferior_pid, signal.SIGKILL)
442
443 # We don't have a way to nuke the threads. However, since we killed
444 # all the inferiors, and we drained the job queue, this will be
445 # good enough. Wait cleanly for each worker thread to wrap up.
446 for worker in workers:
447 worker.join()
448
449
450def find_test_files_in_dir_tree(dir_root, found_func):
451 """Calls found_func for all the test files in the given dir hierarchy.
452
453 @param dir_root the path to the directory to start scanning
454 for test files. All files in this directory and all its children
455 directory trees will be searched.
456
457 @param found_func a callable object that will be passed
458 the parent directory (relative to dir_root) and the list of
459 test files from within that directory.
460 """
461 for root, _, files in os.walk(dir_root, topdown=False):
462 def is_test_filename(test_dir, base_filename):
463 """Returns True if the given filename matches the test name format.
464
465 @param test_dir the directory to check. Should be absolute or
466 relative to current working directory.
467
468 @param base_filename the base name of the filename to check for a
469 dherence to the python test case filename format.
470
471 @return True if name matches the python test case filename format.
472 """
473 # Not interested in symbolically linked files.
474 if os.path.islink(os.path.join(test_dir, base_filename)):
475 return False
476 # Only interested in test files with the "Test*.py" naming pattern.
477 return (base_filename.startswith("Test") and
478 base_filename.endswith(".py"))
479
480 tests = [filename for filename in files
481 if is_test_filename(root, filename)]
482 if tests:
483 found_func(root, tests)
484
485
486def initialize_global_vars_common(num_threads, test_work_items):
487 global total_tests, test_counter, test_name_len
Greg Clayton1827fc22015-09-19 00:39:09 +0000488
Todd Fiala8cbeed32015-09-08 22:22:33 +0000489 total_tests = sum([len(item[1]) for item in test_work_items])
490 test_counter = multiprocessing.Value('i', 0)
491 test_name_len = multiprocessing.Value('i', 0)
Greg Clayton1827fc22015-09-19 00:39:09 +0000492 if not (RESULTS_FORMATTER and RESULTS_FORMATTER.is_using_terminal()):
Zachary Turnerff890da2015-10-19 23:45:41 +0000493 print("Testing: %d test suites, %d thread%s" % (
494 total_tests, num_threads, (num_threads > 1) * "s"), file=sys.stderr)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000495 update_progress()
496
497
498def initialize_global_vars_multiprocessing(num_threads, test_work_items):
499 # Initialize the global state we'll use to communicate with the
500 # rest of the flat module.
501 global output_lock
502 output_lock = multiprocessing.RLock()
Todd Fiala33896a92015-09-18 21:01:13 +0000503
Todd Fiala8cbeed32015-09-08 22:22:33 +0000504 initialize_global_vars_common(num_threads, test_work_items)
505
506
507def initialize_global_vars_threading(num_threads, test_work_items):
Todd Fiala33896a92015-09-18 21:01:13 +0000508 """Initializes global variables used in threading mode.
509 @param num_threads specifies the number of workers used.
510 @param test_work_items specifies all the work items
511 that will be processed.
512 """
Todd Fiala8cbeed32015-09-08 22:22:33 +0000513 # Initialize the global state we'll use to communicate with the
514 # rest of the flat module.
515 global output_lock
516 output_lock = threading.RLock()
Todd Fiala33896a92015-09-18 21:01:13 +0000517
518 index_lock = threading.RLock()
519 index_map = {}
520
521 def get_worker_index_threading():
522 """Returns a 0-based, thread-unique index for the worker thread."""
523 thread_id = threading.current_thread().ident
524 with index_lock:
525 if thread_id not in index_map:
526 index_map[thread_id] = len(index_map)
527 return index_map[thread_id]
528
529
530 global GET_WORKER_INDEX
531 GET_WORKER_INDEX = get_worker_index_threading
532
Todd Fiala8cbeed32015-09-08 22:22:33 +0000533 initialize_global_vars_common(num_threads, test_work_items)
534
535
Todd Fiala68615ce2015-09-15 21:38:04 +0000536def ctrl_c_loop(main_op_func, done_func, ctrl_c_handler):
537 """Provides a main loop that is Ctrl-C protected.
538
539 The main loop calls the main_op_func() repeatedly until done_func()
540 returns true. The ctrl_c_handler() method is called with a single
541 int parameter that contains the number of times the ctrl_c has been
542 hit (starting with 1). The ctrl_c_handler() should mutate whatever
543 it needs to have the done_func() return True as soon as it is desired
544 to exit the loop.
545 """
546 done = False
547 ctrl_c_count = 0
548
549 while not done:
550 try:
551 # See if we're done. Start with done check since it is
552 # the first thing executed after a Ctrl-C handler in the
553 # following loop.
554 done = done_func()
555 if not done:
556 # Run the main op once.
557 main_op_func()
558
559 except KeyboardInterrupt:
560 ctrl_c_count += 1
561 ctrl_c_handler(ctrl_c_count)
562
563
564def pump_workers_and_asyncore_map(workers, asyncore_map):
565 """Prunes out completed workers and maintains the asyncore loop.
566
567 The asyncore loop contains the optional socket listener
568 and handlers. When all workers are complete, this method
569 takes care of stopping the listener. It also runs the
570 asyncore loop for the given async map for 10 iterations.
571
572 @param workers the list of worker Thread/Process instances.
573
574 @param asyncore_map the asyncore threading-aware map that
575 indicates which channels are in use and still alive.
576 """
577
578 # Check on all the workers, removing them from the workers
579 # list as they complete.
580 dead_workers = []
581 for worker in workers:
582 # This non-blocking join call is what allows us
583 # to still receive keyboard interrupts.
584 worker.join(0.01)
585 if not worker.is_alive():
586 dead_workers.append(worker)
587 # Clear out the completed workers
588 for dead_worker in dead_workers:
589 workers.remove(dead_worker)
590
591 # If there are no more workers and there is a listener,
592 # close the listener.
593 global RESULTS_LISTENER_CHANNEL
594 if len(workers) == 0 and RESULTS_LISTENER_CHANNEL is not None:
595 RESULTS_LISTENER_CHANNEL.close()
596 RESULTS_LISTENER_CHANNEL = None
597
598 # Pump the asyncore map if it isn't empty.
599 if len(asyncore_map) > 0:
600 asyncore.loop(0.1, False, asyncore_map, 10)
601
602
603def handle_ctrl_c(ctrl_c_count, job_queue, workers, inferior_pid_events,
604 stop_all_inferiors_func):
605 """Performs the appropriate ctrl-c action for non-pool parallel test runners
606
607 @param ctrl_c_count starting with 1, indicates the number of times ctrl-c
608 has been intercepted. The value is 1 on the first intercept, 2 on the
609 second, etc.
610
611 @param job_queue a Queue object that contains the work still outstanding
612 (i.e. hasn't been assigned to a worker yet).
613
614 @param workers list of Thread or Process workers.
615
616 @param inferior_pid_events specifies a Queue of inferior process
617 construction and destruction events. Used to build the list of inferior
618 processes that should be killed if we get that far.
619
620 @param stop_all_inferiors_func a callable object that takes the
621 workers and inferior_pid_events parameters (in that order) if a hard
622 stop is to be used on the workers.
623 """
624
625 # Print out which Ctrl-C we're handling.
626 key_name = [
627 "first",
628 "second",
629 "third",
630 "many"]
631
632 if ctrl_c_count < len(key_name):
633 name_index = ctrl_c_count - 1
634 else:
635 name_index = len(key_name) - 1
636 message = "\nHandling {} KeyboardInterrupt".format(key_name[name_index])
637 with output_lock:
Zachary Turnerff890da2015-10-19 23:45:41 +0000638 print(message)
Todd Fiala68615ce2015-09-15 21:38:04 +0000639
640 if ctrl_c_count == 1:
641 # Remove all outstanding items from the work queue so we stop
642 # doing any more new work.
643 while not job_queue.empty():
644 try:
645 # Just drain it to stop more work from being started.
646 job_queue.get_nowait()
Zachary Turner814236d2015-10-21 17:48:52 +0000647 except queue.Empty:
Todd Fiala68615ce2015-09-15 21:38:04 +0000648 pass
649 with output_lock:
Zachary Turnerff890da2015-10-19 23:45:41 +0000650 print("Stopped more work from being started.")
Todd Fiala68615ce2015-09-15 21:38:04 +0000651 elif ctrl_c_count == 2:
652 # Try to stop all inferiors, even the ones currently doing work.
653 stop_all_inferiors_func(workers, inferior_pid_events)
654 else:
655 with output_lock:
Zachary Turnerff890da2015-10-19 23:45:41 +0000656 print("All teardown activities kicked off, should finish soon.")
Todd Fiala68615ce2015-09-15 21:38:04 +0000657
658
659def workers_and_async_done(workers, async_map):
660 """Returns True if the workers list and asyncore channels are all done.
661
662 @param workers list of workers (threads/processes). These must adhere
663 to the threading Thread or multiprocessing.Process interface.
664
665 @param async_map the threading-aware asyncore channel map to check
666 for live channels.
667
668 @return False if the workers list exists and has any entries in it, or
669 if the async_map exists and has any entries left in it; otherwise, True.
670 """
671 if workers is not None and len(workers) > 0:
672 # We're not done if we still have workers left.
673 return False
674 if async_map is not None and len(async_map) > 0:
675 return False
676 # We're done.
677 return True
678
679
Todd Fiala8cbeed32015-09-08 22:22:33 +0000680def multiprocessing_test_runner(num_threads, test_work_items):
681 """Provides hand-wrapped pooling test runner adapter with Ctrl-C support.
682
683 This concurrent test runner is based on the multiprocessing
684 library, and rolls its own worker pooling strategy so it
685 can handle Ctrl-C properly.
686
687 This test runner is known to have an issue running on
688 Windows platforms.
689
690 @param num_threads the number of worker processes to use.
691
692 @param test_work_items the iterable of test work item tuples
693 to run.
694 """
695
696 # Initialize our global state.
697 initialize_global_vars_multiprocessing(num_threads, test_work_items)
698
699 # Create jobs.
700 job_queue = multiprocessing.Queue(len(test_work_items))
701 for test_work_item in test_work_items:
702 job_queue.put(test_work_item)
703
704 result_queue = multiprocessing.Queue(len(test_work_items))
705
706 # Create queues for started child pids. Terminating
707 # the multiprocess processes does not terminate the
708 # child processes they spawn. We can remove this tracking
709 # if/when we move to having the multiprocess process directly
710 # perform the test logic. The Queue size needs to be able to
711 # hold 2 * (num inferior dotest.py processes started) entries.
712 inferior_pid_events = multiprocessing.Queue(4096)
713
Todd Fiala33896a92015-09-18 21:01:13 +0000714 # Worker dictionary allows each worker to figure out its worker index.
715 manager = multiprocessing.Manager()
716 worker_index_map = manager.dict()
717
Todd Fiala8cbeed32015-09-08 22:22:33 +0000718 # Create workers. We don't use multiprocessing.Pool due to
719 # challenges with handling ^C keyboard interrupts.
720 workers = []
721 for _ in range(num_threads):
722 worker = multiprocessing.Process(
723 target=process_dir_worker_multiprocessing,
724 args=(output_lock,
725 test_counter,
726 total_tests,
727 test_name_len,
728 dotest_options,
729 job_queue,
730 result_queue,
Todd Fiala33896a92015-09-18 21:01:13 +0000731 inferior_pid_events,
732 worker_index_map))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000733 worker.start()
734 workers.append(worker)
735
Todd Fiala68615ce2015-09-15 21:38:04 +0000736 # Main loop: wait for all workers to finish and wait for
737 # the socket handlers to wrap up.
738 ctrl_c_loop(
739 # Main operation of loop
740 lambda: pump_workers_and_asyncore_map(
741 workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000742
Todd Fiala68615ce2015-09-15 21:38:04 +0000743 # Return True when we're done with the main loop.
744 lambda: workers_and_async_done(workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000745
Todd Fiala68615ce2015-09-15 21:38:04 +0000746 # Indicate what we do when we receive one or more Ctrl-Cs.
747 lambda ctrl_c_count: handle_ctrl_c(
748 ctrl_c_count, job_queue, workers, inferior_pid_events,
749 kill_all_worker_processes))
750
751 # Reap the test results.
Todd Fiala8cbeed32015-09-08 22:22:33 +0000752 test_results = []
753 while not result_queue.empty():
754 test_results.append(result_queue.get(block=False))
755 return test_results
756
757
Todd Fiala68615ce2015-09-15 21:38:04 +0000758def map_async_run_loop(future, channel_map, listener_channel):
759 """Blocks until the Pool.map_async completes and the channel completes.
760
761 @param future an AsyncResult instance from a Pool.map_async() call.
762
763 @param channel_map the asyncore dispatch channel map that should be pumped.
764 Optional: may be None.
765
766 @param listener_channel the channel representing a listener that should be
767 closed once the map_async results are available.
768
769 @return the results from the async_result instance.
770 """
771 map_results = None
772
773 done = False
774 while not done:
775 # Check if we need to reap the map results.
776 if map_results is None:
777 if future.ready():
778 # Get the results.
779 map_results = future.get()
780
781 # Close the runner process listener channel if we have
782 # one: no more connections will be incoming.
783 if listener_channel is not None:
784 listener_channel.close()
785
786 # Pump the asyncore loop if we have a listener socket.
787 if channel_map is not None:
788 asyncore.loop(0.01, False, channel_map, 10)
789
790 # Figure out if we're done running.
791 done = map_results is not None
792 if channel_map is not None:
793 # We have a runner process async map. Check if it
794 # is complete.
795 if len(channel_map) > 0:
796 # We still have an asyncore channel running. Not done yet.
797 done = False
798
799 return map_results
800
801
Todd Fiala8cbeed32015-09-08 22:22:33 +0000802def multiprocessing_test_runner_pool(num_threads, test_work_items):
803 # Initialize our global state.
804 initialize_global_vars_multiprocessing(num_threads, test_work_items)
805
Todd Fiala33896a92015-09-18 21:01:13 +0000806 manager = multiprocessing.Manager()
807 worker_index_map = manager.dict()
808
Todd Fiala8cbeed32015-09-08 22:22:33 +0000809 pool = multiprocessing.Pool(
810 num_threads,
811 initializer=setup_global_variables,
812 initargs=(output_lock, test_counter, total_tests, test_name_len,
Todd Fiala33896a92015-09-18 21:01:13 +0000813 dotest_options, worker_index_map))
Todd Fiala68615ce2015-09-15 21:38:04 +0000814
815 # Start the map operation (async mode).
816 map_future = pool.map_async(
817 process_dir_worker_multiprocessing_pool, test_work_items)
818 return map_async_run_loop(
819 map_future, RUNNER_PROCESS_ASYNC_MAP, RESULTS_LISTENER_CHANNEL)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000820
821
822def threading_test_runner(num_threads, test_work_items):
823 """Provides hand-wrapped pooling threading-based test runner adapter
824 with Ctrl-C support.
825
826 This concurrent test runner is based on the threading
827 library, and rolls its own worker pooling strategy so it
828 can handle Ctrl-C properly.
829
830 @param num_threads the number of worker processes to use.
831
832 @param test_work_items the iterable of test work item tuples
833 to run.
834 """
835
836 # Initialize our global state.
837 initialize_global_vars_threading(num_threads, test_work_items)
838
839 # Create jobs.
Zachary Turner814236d2015-10-21 17:48:52 +0000840 job_queue = queue.Queue()
Todd Fiala8cbeed32015-09-08 22:22:33 +0000841 for test_work_item in test_work_items:
842 job_queue.put(test_work_item)
843
Zachary Turner814236d2015-10-21 17:48:52 +0000844 result_queue = queue.Queue()
Todd Fiala8cbeed32015-09-08 22:22:33 +0000845
846 # Create queues for started child pids. Terminating
847 # the threading threads does not terminate the
848 # child processes they spawn.
Zachary Turner814236d2015-10-21 17:48:52 +0000849 inferior_pid_events = queue.Queue()
Todd Fiala8cbeed32015-09-08 22:22:33 +0000850
851 # Create workers. We don't use multiprocessing.pool.ThreadedPool
852 # due to challenges with handling ^C keyboard interrupts.
853 workers = []
854 for _ in range(num_threads):
855 worker = threading.Thread(
856 target=process_dir_worker_threading,
Todd Fiala68615ce2015-09-15 21:38:04 +0000857 args=(job_queue,
Todd Fiala8cbeed32015-09-08 22:22:33 +0000858 result_queue,
859 inferior_pid_events))
860 worker.start()
861 workers.append(worker)
862
Todd Fiala68615ce2015-09-15 21:38:04 +0000863 # Main loop: wait for all workers to finish and wait for
864 # the socket handlers to wrap up.
865 ctrl_c_loop(
866 # Main operation of loop
867 lambda: pump_workers_and_asyncore_map(
868 workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000869
Todd Fiala68615ce2015-09-15 21:38:04 +0000870 # Return True when we're done with the main loop.
871 lambda: workers_and_async_done(workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000872
Todd Fiala68615ce2015-09-15 21:38:04 +0000873 # Indicate what we do when we receive one or more Ctrl-Cs.
874 lambda ctrl_c_count: handle_ctrl_c(
875 ctrl_c_count, job_queue, workers, inferior_pid_events,
876 kill_all_worker_threads))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000877
Todd Fiala68615ce2015-09-15 21:38:04 +0000878 # Reap the test results.
Todd Fiala8cbeed32015-09-08 22:22:33 +0000879 test_results = []
880 while not result_queue.empty():
881 test_results.append(result_queue.get(block=False))
882 return test_results
883
884
885def threading_test_runner_pool(num_threads, test_work_items):
886 # Initialize our global state.
887 initialize_global_vars_threading(num_threads, test_work_items)
888
Todd Fiala68615ce2015-09-15 21:38:04 +0000889 pool = multiprocessing.pool.ThreadPool(num_threads)
890 map_future = pool.map_async(
891 process_dir_worker_threading_pool, test_work_items)
892
893 return map_async_run_loop(
894 map_future, RUNNER_PROCESS_ASYNC_MAP, RESULTS_LISTENER_CHANNEL)
895
896
897def asyncore_run_loop(channel_map):
898 try:
899 asyncore.loop(None, False, channel_map)
900 except:
901 # Swallow it, we're seeing:
902 # error: (9, 'Bad file descriptor')
903 # when the listener channel is closed. Shouldn't be the case.
904 pass
Todd Fiala8cbeed32015-09-08 22:22:33 +0000905
906
907def inprocess_exec_test_runner(test_work_items):
908 # Initialize our global state.
909 initialize_global_vars_multiprocessing(1, test_work_items)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000910
Todd Fiala33896a92015-09-18 21:01:13 +0000911 # We're always worker index 0
912 global GET_WORKER_INDEX
913 GET_WORKER_INDEX = lambda: 0
914
Todd Fiala68615ce2015-09-15 21:38:04 +0000915 # Run the listener and related channel maps in a separate thread.
916 # global RUNNER_PROCESS_ASYNC_MAP
917 global RESULTS_LISTENER_CHANNEL
918 if RESULTS_LISTENER_CHANNEL is not None:
919 socket_thread = threading.Thread(
920 target=lambda: asyncore_run_loop(RUNNER_PROCESS_ASYNC_MAP))
921 socket_thread.start()
922
923 # Do the work.
Zachary Turner1c4059a2015-10-22 20:39:59 +0000924 test_results = list(map(process_dir_mapper_inprocess, test_work_items))
Todd Fiala68615ce2015-09-15 21:38:04 +0000925
926 # If we have a listener channel, shut it down here.
927 if RESULTS_LISTENER_CHANNEL is not None:
928 # Close down the channel.
929 RESULTS_LISTENER_CHANNEL.close()
930 RESULTS_LISTENER_CHANNEL = None
931
932 # Wait for the listener and handlers to complete.
933 socket_thread.join()
934
935 return test_results
Todd Fiala8cbeed32015-09-08 22:22:33 +0000936
937def walk_and_invoke(test_directory, test_subdir, dotest_argv,
Todd Fiala871b2e52015-09-22 22:47:34 +0000938 num_workers, test_runner_func):
Steve Puccibefe2b12014-03-07 00:01:11 +0000939 """Look for matched files and invoke test driver on each one.
940 In single-threaded mode, each test driver is invoked directly.
941 In multi-threaded mode, submit each test driver to a worker
Vince Harrone06a7a82015-05-12 23:12:19 +0000942 queue, and then wait for all to complete.
943
944 test_directory - lldb/test/ directory
Chaoren Linb6325d02015-08-12 18:02:54 +0000945 test_subdir - lldb/test/ or a subfolder with the tests we're interested in
946 running
Vince Harrone06a7a82015-05-12 23:12:19 +0000947 """
Todd Fiala68615ce2015-09-15 21:38:04 +0000948 # The async_map is important to keep all thread-related asyncore
949 # channels distinct when we call asyncore.loop() later on.
950 global RESULTS_LISTENER_CHANNEL, RUNNER_PROCESS_ASYNC_MAP
951 RUNNER_PROCESS_ASYNC_MAP = {}
952
953 # If we're outputting side-channel test results, create the socket
954 # listener channel and tell the inferior to send results to the
955 # port on which we'll be listening.
956 if RESULTS_FORMATTER is not None:
Todd Fialae83f1402015-09-18 22:45:31 +0000957 forwarding_func = RESULTS_FORMATTER.handle_event
Todd Fiala68615ce2015-09-15 21:38:04 +0000958 RESULTS_LISTENER_CHANNEL = (
959 dotest_channels.UnpicklingForwardingListenerChannel(
Todd Fiala871b2e52015-09-22 22:47:34 +0000960 RUNNER_PROCESS_ASYNC_MAP, "localhost", 0,
961 2 * num_workers, forwarding_func))
Todd Fiala68615ce2015-09-15 21:38:04 +0000962 dotest_argv.append("--results-port")
963 dotest_argv.append(str(RESULTS_LISTENER_CHANNEL.address[1]))
Todd Fiala3f0a3602014-07-08 06:42:37 +0000964
965 # Collect the test files that we'll run.
966 test_work_items = []
Todd Fiala8cbeed32015-09-08 22:22:33 +0000967 find_test_files_in_dir_tree(
968 test_subdir, lambda testdir, test_files: test_work_items.append([
969 test_subdir, test_files, test_directory, dotest_argv, None]))
Todd Fiala3f0a3602014-07-08 06:42:37 +0000970
Todd Fiala8cbeed32015-09-08 22:22:33 +0000971 # Convert test work items into test results using whatever
972 # was provided as the test run function.
973 test_results = test_runner_func(test_work_items)
Chaoren Linffc63b02015-08-12 18:02:49 +0000974
Todd Fiala8cbeed32015-09-08 22:22:33 +0000975 # Summarize the results and return to caller.
Chaoren Line80372a2015-08-12 18:02:53 +0000976 timed_out = sum([result[0] for result in test_results], [])
977 passed = sum([result[1] for result in test_results], [])
978 failed = sum([result[2] for result in test_results], [])
Zachary Turner4cceca72015-08-14 16:45:32 +0000979 unexpected_successes = sum([result[3] for result in test_results], [])
980 pass_count = sum([result[4] for result in test_results])
981 fail_count = sum([result[5] for result in test_results])
Todd Fiala3f0a3602014-07-08 06:42:37 +0000982
Todd Fiala8cbeed32015-09-08 22:22:33 +0000983 return (timed_out, passed, failed, unexpected_successes, pass_count,
984 fail_count)
Johnny Chene8d9dc62011-10-31 19:04:07 +0000985
Chaoren Linb6325d02015-08-12 18:02:54 +0000986
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000987def getExpectedTimeouts(platform_name):
Vince Harron06381732015-05-12 23:10:36 +0000988 # returns a set of test filenames that might timeout
989 # are we running against a remote target?
Chaoren Linfebef1b2015-08-19 17:22:12 +0000990 host = sys.platform
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000991 if platform_name is None:
Vince Harron06381732015-05-12 23:10:36 +0000992 target = sys.platform
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000993 else:
Todd Fiala68615ce2015-09-15 21:38:04 +0000994 m = re.search(r'remote-(\w+)', platform_name)
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000995 target = m.group(1)
Vince Harron06381732015-05-12 23:10:36 +0000996
997 expected_timeout = set()
998
999 if target.startswith("linux"):
1000 expected_timeout |= {
Vince Harron06381732015-05-12 23:10:36 +00001001 "TestConnectRemote.py",
1002 "TestCreateAfterAttach.py",
Tamas Berghammer0d0ec9f2015-05-19 10:49:40 +00001003 "TestEvents.py",
Vince Harron06381732015-05-12 23:10:36 +00001004 "TestExitDuringStep.py",
Chaoren Linb6325d02015-08-12 18:02:54 +00001005
1006 # Times out in ~10% of the times on the build bot
1007 "TestHelloWorld.py",
Oleksiy Vyalov18f4c9f2015-06-10 01:34:25 +00001008 "TestMultithreaded.py",
Chaoren Linb6325d02015-08-12 18:02:54 +00001009 "TestRegisters.py", # ~12/600 dosep runs (build 3120-3122)
Vince Harron06381732015-05-12 23:10:36 +00001010 "TestThreadStepOut.py",
1011 }
1012 elif target.startswith("android"):
1013 expected_timeout |= {
1014 "TestExitDuringStep.py",
1015 "TestHelloWorld.py",
1016 }
Chaoren Linfebef1b2015-08-19 17:22:12 +00001017 if host.startswith("win32"):
1018 expected_timeout |= {
1019 "TestEvents.py",
1020 "TestThreadStates.py",
1021 }
Ed Maste4dd8fba2015-05-14 16:25:52 +00001022 elif target.startswith("freebsd"):
1023 expected_timeout |= {
1024 "TestBreakpointConditions.py",
Ed Maste08948132015-05-28 18:45:30 +00001025 "TestChangeProcessGroup.py",
Ed Mastebfd05632015-05-27 19:11:29 +00001026 "TestValueObjectRecursion.py",
Ed Maste4dd8fba2015-05-14 16:25:52 +00001027 "TestWatchpointConditionAPI.py",
1028 }
Vince Harron0f173ac2015-05-18 19:36:33 +00001029 elif target.startswith("darwin"):
1030 expected_timeout |= {
Chaoren Linb6325d02015-08-12 18:02:54 +00001031 # times out on MBP Retina, Mid 2012
1032 "TestThreadSpecificBreakpoint.py",
Chaoren Lind9043712015-08-19 17:13:02 +00001033 "TestExitDuringStep.py",
Chaoren Lin99f25be2015-08-20 01:26:57 +00001034 "TestIntegerTypesExpr.py",
Vince Harron0f173ac2015-05-18 19:36:33 +00001035 }
Vince Harron06381732015-05-12 23:10:36 +00001036 return expected_timeout
1037
Chaoren Linb6325d02015-08-12 18:02:54 +00001038
Pavel Labathfad30cf2015-06-29 14:16:51 +00001039def getDefaultTimeout(platform_name):
1040 if os.getenv("LLDB_TEST_TIMEOUT"):
1041 return os.getenv("LLDB_TEST_TIMEOUT")
1042
1043 if platform_name is None:
1044 platform_name = sys.platform
1045
1046 if platform_name.startswith("remote-"):
1047 return "10m"
1048 else:
1049 return "4m"
1050
Chaoren Linb6325d02015-08-12 18:02:54 +00001051
Vince Harron0b9dbb52015-05-21 18:18:52 +00001052def touch(fname, times=None):
Greg Clayton8c3f9c92015-08-11 21:01:32 +00001053 if os.path.exists(fname):
Vince Harron0b9dbb52015-05-21 18:18:52 +00001054 os.utime(fname, times)
1055
Chaoren Linb6325d02015-08-12 18:02:54 +00001056
Vince Harrondcc2b9f2015-05-27 04:40:36 +00001057def find(pattern, path):
1058 result = []
1059 for root, dirs, files in os.walk(path):
1060 for name in files:
1061 if fnmatch.fnmatch(name, pattern):
1062 result.append(os.path.join(root, name))
1063 return result
1064
Chaoren Linb6325d02015-08-12 18:02:54 +00001065
Todd Fiala8cbeed32015-09-08 22:22:33 +00001066def get_test_runner_strategies(num_threads):
1067 """Returns the test runner strategies by name in a dictionary.
1068
1069 @param num_threads specifies the number of threads/processes
1070 that will be used for concurrent test runners.
1071
1072 @return dictionary with key as test runner strategy name and
1073 value set to a callable object that takes the test work item
1074 and returns a test result tuple.
1075 """
1076 return {
1077 # multiprocessing supports ctrl-c and does not use
1078 # multiprocessing.Pool.
1079 "multiprocessing":
1080 (lambda work_items: multiprocessing_test_runner(
1081 num_threads, work_items)),
1082
1083 # multiprocessing-pool uses multiprocessing.Pool but
1084 # does not support Ctrl-C.
1085 "multiprocessing-pool":
1086 (lambda work_items: multiprocessing_test_runner_pool(
1087 num_threads, work_items)),
1088
1089 # threading uses a hand-rolled worker pool much
1090 # like multiprocessing, but instead uses in-process
1091 # worker threads. This one supports Ctrl-C.
1092 "threading":
1093 (lambda work_items: threading_test_runner(num_threads, work_items)),
1094
1095 # threading-pool uses threading for the workers (in-process)
1096 # and uses the multiprocessing.pool thread-enabled pool.
Todd Fiala68615ce2015-09-15 21:38:04 +00001097 # This does not properly support Ctrl-C.
Todd Fiala8cbeed32015-09-08 22:22:33 +00001098 "threading-pool":
1099 (lambda work_items: threading_test_runner_pool(
1100 num_threads, work_items)),
1101
1102 # serial uses the subprocess-based, single process
1103 # test runner. This provides process isolation but
Todd Fiala68615ce2015-09-15 21:38:04 +00001104 # no concurrent test execution.
Todd Fiala8cbeed32015-09-08 22:22:33 +00001105 "serial":
1106 inprocess_exec_test_runner
1107 }
1108
1109
Todd Fialaea736242015-09-23 15:21:28 +00001110def _remove_option(
1111 args, long_option_name, short_option_name, takes_arg):
Todd Fiala68615ce2015-09-15 21:38:04 +00001112 """Removes option and related option arguments from args array.
Todd Fialaea736242015-09-23 15:21:28 +00001113
1114 This method removes all short/long options that match the given
1115 arguments.
1116
Todd Fiala68615ce2015-09-15 21:38:04 +00001117 @param args the array of command line arguments (in/out)
Todd Fialaea736242015-09-23 15:21:28 +00001118
1119 @param long_option_name the full command line representation of the
1120 long-form option that will be removed (including '--').
1121
1122 @param short_option_name the short version of the command line option
1123 that will be removed (including '-').
1124
1125 @param takes_arg True if the option takes an argument.
1126
Todd Fiala68615ce2015-09-15 21:38:04 +00001127 """
Todd Fialaea736242015-09-23 15:21:28 +00001128 if long_option_name is not None:
1129 regex_string = "^" + long_option_name + "="
1130 long_regex = re.compile(regex_string)
1131 if short_option_name is not None:
1132 # Short options we only match the -X and assume
1133 # any arg is one command line argument jammed together.
1134 # i.e. -O--abc=1 is a single argument in the args list.
1135 # We don't handle -O --abc=1, as argparse doesn't handle
1136 # it, either.
1137 regex_string = "^" + short_option_name
1138 short_regex = re.compile(regex_string)
1139
1140 def remove_long_internal():
1141 """Removes one matching long option from args.
1142 @returns True if one was found and removed; False otherwise.
1143 """
1144 try:
1145 index = args.index(long_option_name)
1146 # Handle the exact match case.
1147 if takes_arg:
1148 removal_count = 2
1149 else:
1150 removal_count = 1
1151 del args[index:index+removal_count]
1152 return True
1153 except ValueError:
1154 # Thanks to argparse not handling options with known arguments
1155 # like other options parsing libraries (see
1156 # https://bugs.python.org/issue9334), we need to support the
1157 # --results-formatter-options={second-level-arguments} (note
1158 # the equal sign to fool the first-level arguments parser into
1159 # not treating the second-level arguments as first-level
1160 # options). We're certainly at risk of getting this wrong
1161 # since now we're forced into the business of trying to figure
1162 # out what is an argument (although I think this
1163 # implementation will suffice).
1164 for index in range(len(args)):
1165 match = long_regex.search(args[index])
1166 if match:
1167 del args[index]
1168 return True
1169 return False
1170
1171 def remove_short_internal():
1172 """Removes one matching short option from args.
1173 @returns True if one was found and removed; False otherwise.
1174 """
Todd Fiala68615ce2015-09-15 21:38:04 +00001175 for index in range(len(args)):
Todd Fialaea736242015-09-23 15:21:28 +00001176 match = short_regex.search(args[index])
Todd Fiala68615ce2015-09-15 21:38:04 +00001177 if match:
Todd Fiala68615ce2015-09-15 21:38:04 +00001178 del args[index]
Todd Fialaea736242015-09-23 15:21:28 +00001179 return True
1180 return False
Todd Fiala68615ce2015-09-15 21:38:04 +00001181
Todd Fialaea736242015-09-23 15:21:28 +00001182 removal_count = 0
1183 while long_option_name is not None and remove_long_internal():
1184 removal_count += 1
1185 while short_option_name is not None and remove_short_internal():
1186 removal_count += 1
1187 if removal_count == 0:
1188 raise Exception(
1189 "failed to find at least one of '{}', '{}' in options".format(
1190 long_option_name, short_option_name))
Todd Fiala68615ce2015-09-15 21:38:04 +00001191
1192
1193def adjust_inferior_options(dotest_argv):
1194 """Adjusts the commandline args array for inferiors.
1195
1196 This method adjusts the inferior dotest commandline options based
1197 on the parallel test runner's options. Some of the inferior options
1198 will need to change to properly handle aggregation functionality.
1199 """
1200 global dotest_options
1201
1202 # If we don't have a session directory, create one.
1203 if not dotest_options.s:
1204 # no session log directory, we need to add this to prevent
1205 # every dotest invocation from creating its own directory
1206 import datetime
1207 # The windows platforms don't like ':' in the pathname.
1208 timestamp_started = datetime.datetime.now().strftime("%F-%H_%M_%S")
1209 dotest_argv.append('-s')
1210 dotest_argv.append(timestamp_started)
1211 dotest_options.s = timestamp_started
1212
1213 # Adjust inferior results formatter options - if the parallel
1214 # test runner is collecting into the user-specified test results,
1215 # we'll have inferiors spawn with the --results-port option and
1216 # strip the original test runner options.
1217 if dotest_options.results_file is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001218 _remove_option(dotest_argv, "--results-file", None, True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001219 if dotest_options.results_port is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001220 _remove_option(dotest_argv, "--results-port", None, True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001221 if dotest_options.results_formatter is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001222 _remove_option(dotest_argv, "--results-formatter", None, True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001223 if dotest_options.results_formatter_options is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001224 _remove_option(dotest_argv, "--results-formatter-option", "-O",
1225 True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001226
Todd Fiala33896a92015-09-18 21:01:13 +00001227 # Remove test runner name if present.
1228 if dotest_options.test_runner_name is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001229 _remove_option(dotest_argv, "--test-runner-name", None, True)
Todd Fiala33896a92015-09-18 21:01:13 +00001230
1231
Todd Fiala83c32e32015-09-22 21:19:40 +00001232def is_darwin_version_lower_than(target_version):
1233 """Checks that os is Darwin and version is lower than target_version.
1234
1235 @param target_version the StrictVersion indicating the version
1236 we're checking against.
1237
1238 @return True if the OS is Darwin (OS X) and the version number of
1239 the OS is less than target_version; False in all other cases.
1240 """
1241 if platform.system() != 'Darwin':
1242 # Can't be Darwin lower than a certain version.
1243 return False
1244
1245 system_version = distutils.version.StrictVersion(platform.mac_ver()[0])
Todd Fiala871b2e52015-09-22 22:47:34 +00001246 return cmp(system_version, target_version) < 0
Todd Fiala83c32e32015-09-22 21:19:40 +00001247
1248
1249def default_test_runner_name(num_threads):
1250 """Returns the default test runner name for the configuration.
1251
1252 @param num_threads the number of threads/workers this test runner is
1253 supposed to use.
1254
1255 @return the test runner name that should be used by default when
1256 no test runner was explicitly called out on the command line.
1257 """
1258 if num_threads == 1:
1259 # Use the serial runner.
1260 test_runner_name = "serial"
1261 elif os.name == "nt":
Adrian McCarthy040b31d2015-10-12 14:46:57 +00001262 # On Windows, Python uses CRT with a low limit on the number of open
1263 # files. If you have a lot of cores, the threading-pool runner will
1264 # often fail because it exceeds that limit.
1265 if num_threads > 32:
1266 test_runner_name = "multiprocessing-pool"
1267 else:
1268 test_runner_name = "threading-pool"
Todd Fiala83c32e32015-09-22 21:19:40 +00001269 elif is_darwin_version_lower_than(
1270 distutils.version.StrictVersion("10.10.0")):
1271 # OS X versions before 10.10 appear to have an issue using
1272 # the threading test runner. Fall back to multiprocessing.
1273 # Supports Ctrl-C.
1274 test_runner_name = "multiprocessing"
1275 else:
1276 # For everyone else, use the ctrl-c-enabled threading support.
1277 # Should use fewer system resources than the multprocessing
1278 # variant.
1279 test_runner_name = "threading"
1280 return test_runner_name
1281
1282
Todd Fiala8cbeed32015-09-08 22:22:33 +00001283def main(print_details_on_success, num_threads, test_subdir,
Todd Fiala68615ce2015-09-15 21:38:04 +00001284 test_runner_name, results_formatter):
Todd Fialafed95662015-09-03 18:58:44 +00001285 """Run dotest.py in inferior mode in parallel.
1286
1287 @param print_details_on_success the parsed value of the output-on-success
1288 command line argument. When True, details of a successful dotest inferior
1289 are printed even when everything succeeds. The normal behavior is to
1290 not print any details when all the inferior tests pass.
1291
1292 @param num_threads the parsed value of the num-threads command line
1293 argument.
1294
1295 @param test_subdir optionally specifies a subdir to limit testing
1296 within. May be None if the entire test tree is to be used. This subdir
1297 is assumed to be relative to the lldb/test root of the test hierarchy.
Todd Fiala8cbeed32015-09-08 22:22:33 +00001298
1299 @param test_runner_name if specified, contains the test runner
1300 name which selects the strategy used to run the isolated and
1301 optionally concurrent test runner. Specify None to allow the
1302 system to choose the most appropriate test runner given desired
1303 thread count and OS type.
1304
Todd Fiala68615ce2015-09-15 21:38:04 +00001305 @param results_formatter if specified, provides the TestResultsFormatter
1306 instance that will format and output test result data from the
1307 side-channel test results. When specified, inferior dotest calls
1308 will send test results side-channel data over a socket to the parallel
1309 test runner, which will forward them on to results_formatter.
Todd Fialafed95662015-09-03 18:58:44 +00001310 """
1311
Todd Fiala1cc97b42015-09-21 05:42:26 +00001312 # Do not shut down on sighup.
Ying Chend93aa102015-09-23 21:53:18 +00001313 if hasattr(signal, 'SIGHUP'):
1314 signal.signal(signal.SIGHUP, signal.SIG_IGN)
Todd Fiala1cc97b42015-09-21 05:42:26 +00001315
Todd Fialafed95662015-09-03 18:58:44 +00001316 dotest_argv = sys.argv[1:]
1317
Greg Claytonb0d148e2015-09-21 17:25:01 +00001318 global output_on_success, RESULTS_FORMATTER
Todd Fialafed95662015-09-03 18:58:44 +00001319 output_on_success = print_details_on_success
Todd Fiala68615ce2015-09-15 21:38:04 +00001320 RESULTS_FORMATTER = results_formatter
Todd Fialafed95662015-09-03 18:58:44 +00001321
Vince Harrond5fa1022015-05-10 15:24:12 +00001322 # We can't use sys.path[0] to determine the script directory
1323 # because it doesn't work under a debugger
Vince Harron8994fed2015-05-22 19:49:23 +00001324 parser = dotest_args.create_parser()
Pavel Labath05ab2372015-07-06 15:57:52 +00001325 global dotest_options
Vince Harron8994fed2015-05-22 19:49:23 +00001326 dotest_options = dotest_args.parse_args(parser, dotest_argv)
1327
Todd Fiala68615ce2015-09-15 21:38:04 +00001328 adjust_inferior_options(dotest_argv)
Vince Harron0b9dbb52015-05-21 18:18:52 +00001329
1330 session_dir = os.path.join(os.getcwd(), dotest_options.s)
Ed Mastecec2a5b2014-11-21 02:41:25 +00001331
Vince Harrone06a7a82015-05-12 23:12:19 +00001332 # The root directory was specified on the command line
Todd Fiala68615ce2015-09-15 21:38:04 +00001333 test_directory = os.path.dirname(os.path.realpath(__file__))
Todd Fialafed95662015-09-03 18:58:44 +00001334 if test_subdir and len(test_subdir) > 0:
1335 test_subdir = os.path.join(test_directory, test_subdir)
Vince Harrone06a7a82015-05-12 23:12:19 +00001336 else:
Todd Fialafed95662015-09-03 18:58:44 +00001337 test_subdir = test_directory
Vince Harrone06a7a82015-05-12 23:12:19 +00001338
Vince Harrondcc2b9f2015-05-27 04:40:36 +00001339 # clean core files in test tree from previous runs (Linux)
1340 cores = find('core.*', test_subdir)
1341 for core in cores:
1342 os.unlink(core)
1343
Daniel Maleab42556f2013-04-19 18:32:53 +00001344 system_info = " ".join(platform.uname())
Todd Fiala8cbeed32015-09-08 22:22:33 +00001345
1346 # Figure out which testrunner strategy we'll use.
1347 runner_strategies_by_name = get_test_runner_strategies(num_threads)
1348
1349 # If the user didn't specify a test runner strategy, determine
1350 # the default now based on number of threads and OS type.
1351 if not test_runner_name:
Todd Fiala83c32e32015-09-22 21:19:40 +00001352 test_runner_name = default_test_runner_name(num_threads)
Todd Fiala8cbeed32015-09-08 22:22:33 +00001353
1354 if test_runner_name not in runner_strategies_by_name:
Todd Fiala83c32e32015-09-22 21:19:40 +00001355 raise Exception(
1356 "specified testrunner name '{}' unknown. Valid choices: {}".format(
1357 test_runner_name,
Zachary Turner606e1e32015-10-23 17:53:51 +00001358 list(runner_strategies_by_name.keys())))
Todd Fiala8cbeed32015-09-08 22:22:33 +00001359 test_runner_func = runner_strategies_by_name[test_runner_name]
1360
1361 summary_results = walk_and_invoke(
Todd Fiala871b2e52015-09-22 22:47:34 +00001362 test_directory, test_subdir, dotest_argv,
1363 num_threads, test_runner_func)
Todd Fiala8cbeed32015-09-08 22:22:33 +00001364
1365 (timed_out, passed, failed, unexpected_successes, pass_count,
1366 fail_count) = summary_results
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +00001367
Todd Fialade9a44e2015-09-22 00:15:50 +00001368 # The results formatter - if present - is done now. Tell it to
1369 # terminate.
1370 if results_formatter is not None:
1371 results_formatter.send_terminate_as_needed()
1372
Vince Harron17f429f2014-12-13 00:08:19 +00001373 timed_out = set(timed_out)
Chaoren Line80372a2015-08-12 18:02:53 +00001374 num_test_files = len(passed) + len(failed)
1375 num_test_cases = pass_count + fail_count
Daniel Maleab42556f2013-04-19 18:32:53 +00001376
Vince Harrondcc2b9f2015-05-27 04:40:36 +00001377 # move core files into session dir
1378 cores = find('core.*', test_subdir)
1379 for core in cores:
1380 dst = core.replace(test_directory, "")[1:]
1381 dst = dst.replace(os.path.sep, "-")
1382 os.rename(core, os.path.join(session_dir, dst))
1383
Vince Harron06381732015-05-12 23:10:36 +00001384 # remove expected timeouts from failures
Vince Harronf8b9a1d2015-05-18 19:40:54 +00001385 expected_timeout = getExpectedTimeouts(dotest_options.lldb_platform_name)
Vince Harron06381732015-05-12 23:10:36 +00001386 for xtime in expected_timeout:
1387 if xtime in timed_out:
1388 timed_out.remove(xtime)
1389 failed.remove(xtime)
Vince Harron0b9dbb52015-05-21 18:18:52 +00001390 result = "ExpectedTimeout"
1391 elif xtime in passed:
1392 result = "UnexpectedCompletion"
1393 else:
1394 result = None # failed
1395
1396 if result:
1397 test_name = os.path.splitext(xtime)[0]
1398 touch(os.path.join(session_dir, "{}-{}".format(result, test_name)))
Vince Harron06381732015-05-12 23:10:36 +00001399
Zachary Turnerff890da2015-10-19 23:45:41 +00001400 print()
Chaoren Lin5a59e462015-08-12 18:02:51 +00001401 sys.stdout.write("Ran %d test suites" % num_test_files)
1402 if num_test_files > 0:
1403 sys.stdout.write(" (%d failed) (%f%%)" % (
1404 len(failed), 100.0 * len(failed) / num_test_files))
Zachary Turnerff890da2015-10-19 23:45:41 +00001405 print()
Chaoren Line80372a2015-08-12 18:02:53 +00001406 sys.stdout.write("Ran %d test cases" % num_test_cases)
1407 if num_test_cases > 0:
Chaoren Lin5a59e462015-08-12 18:02:51 +00001408 sys.stdout.write(" (%d failed) (%f%%)" % (
Chaoren Line80372a2015-08-12 18:02:53 +00001409 fail_count, 100.0 * fail_count / num_test_cases))
Zachary Turnerff890da2015-10-19 23:45:41 +00001410 print()
Zachary Turner4cceca72015-08-14 16:45:32 +00001411 exit_code = 0
1412
Daniel Maleacbaef262013-02-15 21:31:37 +00001413 if len(failed) > 0:
Shawn Best13491c42014-10-22 19:29:00 +00001414 failed.sort()
Zachary Turnerff890da2015-10-19 23:45:41 +00001415 print("Failing Tests (%d)" % len(failed))
Daniel Maleacbaef262013-02-15 21:31:37 +00001416 for f in failed:
Zachary Turnerff890da2015-10-19 23:45:41 +00001417 print("%s: LLDB (suite) :: %s (%s)" % (
Vince Harron17f429f2014-12-13 00:08:19 +00001418 "TIMEOUT" if f in timed_out else "FAIL", f, system_info
Zachary Turnerff890da2015-10-19 23:45:41 +00001419 ))
Zachary Turner4cceca72015-08-14 16:45:32 +00001420 exit_code = 1
1421
1422 if len(unexpected_successes) > 0:
1423 unexpected_successes.sort()
Zachary Turnerff890da2015-10-19 23:45:41 +00001424 print("\nUnexpected Successes (%d)" % len(unexpected_successes))
Zachary Turner4cceca72015-08-14 16:45:32 +00001425 for u in unexpected_successes:
Zachary Turnerff890da2015-10-19 23:45:41 +00001426 print("UNEXPECTED SUCCESS: LLDB (suite) :: %s (%s)" % (u, system_info))
Zachary Turner4cceca72015-08-14 16:45:32 +00001427
1428 sys.exit(exit_code)
Johnny Chene8d9dc62011-10-31 19:04:07 +00001429
1430if __name__ == '__main__':
Todd Fialafed95662015-09-03 18:58:44 +00001431 sys.stderr.write(
1432 "error: dosep.py no longer supports being called directly. "
1433 "Please call dotest.py directly. The dosep.py-specific arguments "
1434 "have been added under the Parallel processing arguments.\n")
1435 sys.exit(128)