blob: 4f9a23d61184dfdd1fbdec01c745ac6eff4fcd09 [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
Zachary Turner7d564542015-11-02 19:19:49 +0000282def process_dir(root, files, 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 Turner7d564542015-11-02 19:19:49 +0000286 import __main__ as main
287 script_file = main.__file__
Zachary Turnerf6896b02015-01-05 19:37:03 +0000288 command = ([sys.executable, script_file] +
Vince Harron41657cc2015-05-21 18:15:09 +0000289 dotest_argv +
Todd Fialafed95662015-09-03 18:58:44 +0000290 ["--inferior", "-p", name, root])
Vince Harron17f429f2014-12-13 00:08:19 +0000291
292 timeout_name = os.path.basename(os.path.splitext(name)[0]).upper()
293
Chaoren Linb6325d02015-08-12 18:02:54 +0000294 timeout = (os.getenv("LLDB_%s_TIMEOUT" % timeout_name) or
295 getDefaultTimeout(dotest_options.lldb_platform_name))
Vince Harron17f429f2014-12-13 00:08:19 +0000296
Todd Fiala8cbeed32015-09-08 22:22:33 +0000297 results.append(call_with_timeout(
298 command, timeout, name, inferior_pid_events))
Vince Harron17f429f2014-12-13 00:08:19 +0000299
Zachary Turner4cceca72015-08-14 16:45:32 +0000300 # result = (name, status, passes, failures, unexpected_successes)
301 timed_out = [name for name, status, _, _, _ in results
Chaoren Line80372a2015-08-12 18:02:53 +0000302 if status == eTimedOut]
Zachary Turner4cceca72015-08-14 16:45:32 +0000303 passed = [name for name, status, _, _, _ in results
Chaoren Line80372a2015-08-12 18:02:53 +0000304 if status == ePassed]
Zachary Turner4cceca72015-08-14 16:45:32 +0000305 failed = [name for name, status, _, _, _ in results
Chaoren Line80372a2015-08-12 18:02:53 +0000306 if status != ePassed]
Zachary Turner4cceca72015-08-14 16:45:32 +0000307 unexpected_passes = [name for name, _, _, _, unexpected_successes in results
308 if unexpected_successes > 0]
Todd Fialafed95662015-09-03 18:58:44 +0000309
Chaoren Line80372a2015-08-12 18:02:53 +0000310 pass_count = sum([result[2] for result in results])
311 fail_count = sum([result[3] for result in results])
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000312
Zachary Turner4cceca72015-08-14 16:45:32 +0000313 return (timed_out, passed, failed, unexpected_passes, pass_count, fail_count)
Steve Puccibefe2b12014-03-07 00:01:11 +0000314
315in_q = None
316out_q = None
317
Chaoren Linb6325d02015-08-12 18:02:54 +0000318
Todd Fiala8cbeed32015-09-08 22:22:33 +0000319def process_dir_worker_multiprocessing(
320 a_output_lock, a_test_counter, a_total_tests, a_test_name_len,
Todd Fiala33896a92015-09-18 21:01:13 +0000321 a_dotest_options, job_queue, result_queue, inferior_pid_events,
322 worker_index_map):
Todd Fiala8cbeed32015-09-08 22:22:33 +0000323 """Worker thread main loop when in multiprocessing mode.
Steve Puccibefe2b12014-03-07 00:01:11 +0000324 Takes one directory specification at a time and works on it."""
Todd Fiala8cbeed32015-09-08 22:22:33 +0000325
326 # Shut off interrupt handling in the child process.
327 signal.signal(signal.SIGINT, signal.SIG_IGN)
Ying Chend93aa102015-09-23 21:53:18 +0000328 if hasattr(signal, 'SIGHUP'):
329 signal.signal(signal.SIGHUP, signal.SIG_IGN)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000330
331 # Setup the global state for the worker process.
332 setup_global_variables(
333 a_output_lock, a_test_counter, a_total_tests, a_test_name_len,
Todd Fiala33896a92015-09-18 21:01:13 +0000334 a_dotest_options, worker_index_map)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000335
336 # Keep grabbing entries from the queue until done.
337 while not job_queue.empty():
338 try:
339 job = job_queue.get(block=False)
340 result = process_dir(job[0], job[1], job[2], job[3],
341 inferior_pid_events)
342 result_queue.put(result)
Zachary Turner814236d2015-10-21 17:48:52 +0000343 except queue.Empty:
Todd Fiala8cbeed32015-09-08 22:22:33 +0000344 # Fine, we're done.
345 pass
Steve Puccibefe2b12014-03-07 00:01:11 +0000346
Chaoren Linb6325d02015-08-12 18:02:54 +0000347
Todd Fiala8cbeed32015-09-08 22:22:33 +0000348def process_dir_worker_multiprocessing_pool(args):
349 return process_dir(*args)
350
351
Todd Fiala68615ce2015-09-15 21:38:04 +0000352def process_dir_worker_threading(job_queue, result_queue, inferior_pid_events):
Todd Fiala8cbeed32015-09-08 22:22:33 +0000353 """Worker thread main loop when in threading mode.
354
355 This one supports the hand-rolled pooling support.
356
357 Takes one directory specification at a time and works on it."""
358
359 # Keep grabbing entries from the queue until done.
360 while not job_queue.empty():
361 try:
362 job = job_queue.get(block=False)
363 result = process_dir(job[0], job[1], job[2], job[3],
364 inferior_pid_events)
365 result_queue.put(result)
Zachary Turner814236d2015-10-21 17:48:52 +0000366 except queue.Empty:
Todd Fiala8cbeed32015-09-08 22:22:33 +0000367 # Fine, we're done.
368 pass
369
370
371def process_dir_worker_threading_pool(args):
372 return process_dir(*args)
373
374
375def process_dir_mapper_inprocess(args):
376 """Map adapter for running the subprocess-based, non-threaded test runner.
377
378 @param args the process work item tuple
379 @return the test result tuple
380 """
381 return process_dir(*args)
382
383
384def collect_active_pids_from_pid_events(event_queue):
385 """
386 Returns the set of what should be active inferior pids based on
387 the event stream.
388
389 @param event_queue a multiprocessing.Queue containing events of the
390 form:
391 ('created', pid)
392 ('destroyed', pid)
393
394 @return set of inferior dotest.py pids activated but never completed.
395 """
396 active_pid_set = set()
397 while not event_queue.empty():
398 pid_event = event_queue.get_nowait()
399 if pid_event[0] == 'created':
400 active_pid_set.add(pid_event[1])
401 elif pid_event[0] == 'destroyed':
402 active_pid_set.remove(pid_event[1])
403 return active_pid_set
404
405
406def kill_all_worker_processes(workers, inferior_pid_events):
407 """
408 Kills all specified worker processes and their process tree.
409
410 @param workers a list of multiprocess.Process worker objects.
411 @param inferior_pid_events a multiprocess.Queue that contains
412 all inferior create and destroy events. Used to construct
413 the list of child pids still outstanding that need to be killed.
414 """
415 for worker in workers:
416 worker.terminate()
417 worker.join()
418
419 # Add all the child test pids created.
420 active_pid_set = collect_active_pids_from_pid_events(
421 inferior_pid_events)
422 for inferior_pid in active_pid_set:
Zachary Turnerff890da2015-10-19 23:45:41 +0000423 print("killing inferior pid {}".format(inferior_pid))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000424 os.kill(inferior_pid, signal.SIGKILL)
425
426
427def kill_all_worker_threads(workers, inferior_pid_events):
428 """
429 Kills all specified worker threads and their process tree.
430
431 @param workers a list of multiprocess.Process worker objects.
432 @param inferior_pid_events a multiprocess.Queue that contains
433 all inferior create and destroy events. Used to construct
434 the list of child pids still outstanding that need to be killed.
435 """
436
437 # Add all the child test pids created.
438 active_pid_set = collect_active_pids_from_pid_events(
439 inferior_pid_events)
440 for inferior_pid in active_pid_set:
Zachary Turnerff890da2015-10-19 23:45:41 +0000441 print("killing inferior pid {}".format(inferior_pid))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000442 os.kill(inferior_pid, signal.SIGKILL)
443
444 # We don't have a way to nuke the threads. However, since we killed
445 # all the inferiors, and we drained the job queue, this will be
446 # good enough. Wait cleanly for each worker thread to wrap up.
447 for worker in workers:
448 worker.join()
449
450
451def find_test_files_in_dir_tree(dir_root, found_func):
452 """Calls found_func for all the test files in the given dir hierarchy.
453
454 @param dir_root the path to the directory to start scanning
455 for test files. All files in this directory and all its children
456 directory trees will be searched.
457
458 @param found_func a callable object that will be passed
459 the parent directory (relative to dir_root) and the list of
460 test files from within that directory.
461 """
462 for root, _, files in os.walk(dir_root, topdown=False):
463 def is_test_filename(test_dir, base_filename):
464 """Returns True if the given filename matches the test name format.
465
466 @param test_dir the directory to check. Should be absolute or
467 relative to current working directory.
468
469 @param base_filename the base name of the filename to check for a
470 dherence to the python test case filename format.
471
472 @return True if name matches the python test case filename format.
473 """
474 # Not interested in symbolically linked files.
475 if os.path.islink(os.path.join(test_dir, base_filename)):
476 return False
477 # Only interested in test files with the "Test*.py" naming pattern.
478 return (base_filename.startswith("Test") and
479 base_filename.endswith(".py"))
480
481 tests = [filename for filename in files
482 if is_test_filename(root, filename)]
483 if tests:
484 found_func(root, tests)
485
486
487def initialize_global_vars_common(num_threads, test_work_items):
488 global total_tests, test_counter, test_name_len
Greg Clayton1827fc22015-09-19 00:39:09 +0000489
Todd Fiala8cbeed32015-09-08 22:22:33 +0000490 total_tests = sum([len(item[1]) for item in test_work_items])
491 test_counter = multiprocessing.Value('i', 0)
492 test_name_len = multiprocessing.Value('i', 0)
Greg Clayton1827fc22015-09-19 00:39:09 +0000493 if not (RESULTS_FORMATTER and RESULTS_FORMATTER.is_using_terminal()):
Zachary Turnerff890da2015-10-19 23:45:41 +0000494 print("Testing: %d test suites, %d thread%s" % (
495 total_tests, num_threads, (num_threads > 1) * "s"), file=sys.stderr)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000496 update_progress()
497
498
499def initialize_global_vars_multiprocessing(num_threads, test_work_items):
500 # Initialize the global state we'll use to communicate with the
501 # rest of the flat module.
502 global output_lock
503 output_lock = multiprocessing.RLock()
Todd Fiala33896a92015-09-18 21:01:13 +0000504
Todd Fiala8cbeed32015-09-08 22:22:33 +0000505 initialize_global_vars_common(num_threads, test_work_items)
506
507
508def initialize_global_vars_threading(num_threads, test_work_items):
Todd Fiala33896a92015-09-18 21:01:13 +0000509 """Initializes global variables used in threading mode.
510 @param num_threads specifies the number of workers used.
511 @param test_work_items specifies all the work items
512 that will be processed.
513 """
Todd Fiala8cbeed32015-09-08 22:22:33 +0000514 # Initialize the global state we'll use to communicate with the
515 # rest of the flat module.
516 global output_lock
517 output_lock = threading.RLock()
Todd Fiala33896a92015-09-18 21:01:13 +0000518
519 index_lock = threading.RLock()
520 index_map = {}
521
522 def get_worker_index_threading():
523 """Returns a 0-based, thread-unique index for the worker thread."""
524 thread_id = threading.current_thread().ident
525 with index_lock:
526 if thread_id not in index_map:
527 index_map[thread_id] = len(index_map)
528 return index_map[thread_id]
529
530
531 global GET_WORKER_INDEX
532 GET_WORKER_INDEX = get_worker_index_threading
533
Todd Fiala8cbeed32015-09-08 22:22:33 +0000534 initialize_global_vars_common(num_threads, test_work_items)
535
536
Todd Fiala68615ce2015-09-15 21:38:04 +0000537def ctrl_c_loop(main_op_func, done_func, ctrl_c_handler):
538 """Provides a main loop that is Ctrl-C protected.
539
540 The main loop calls the main_op_func() repeatedly until done_func()
541 returns true. The ctrl_c_handler() method is called with a single
542 int parameter that contains the number of times the ctrl_c has been
543 hit (starting with 1). The ctrl_c_handler() should mutate whatever
544 it needs to have the done_func() return True as soon as it is desired
545 to exit the loop.
546 """
547 done = False
548 ctrl_c_count = 0
549
550 while not done:
551 try:
552 # See if we're done. Start with done check since it is
553 # the first thing executed after a Ctrl-C handler in the
554 # following loop.
555 done = done_func()
556 if not done:
557 # Run the main op once.
558 main_op_func()
559
560 except KeyboardInterrupt:
561 ctrl_c_count += 1
562 ctrl_c_handler(ctrl_c_count)
563
564
565def pump_workers_and_asyncore_map(workers, asyncore_map):
566 """Prunes out completed workers and maintains the asyncore loop.
567
568 The asyncore loop contains the optional socket listener
569 and handlers. When all workers are complete, this method
570 takes care of stopping the listener. It also runs the
571 asyncore loop for the given async map for 10 iterations.
572
573 @param workers the list of worker Thread/Process instances.
574
575 @param asyncore_map the asyncore threading-aware map that
576 indicates which channels are in use and still alive.
577 """
578
579 # Check on all the workers, removing them from the workers
580 # list as they complete.
581 dead_workers = []
582 for worker in workers:
583 # This non-blocking join call is what allows us
584 # to still receive keyboard interrupts.
585 worker.join(0.01)
586 if not worker.is_alive():
587 dead_workers.append(worker)
588 # Clear out the completed workers
589 for dead_worker in dead_workers:
590 workers.remove(dead_worker)
591
592 # If there are no more workers and there is a listener,
593 # close the listener.
594 global RESULTS_LISTENER_CHANNEL
595 if len(workers) == 0 and RESULTS_LISTENER_CHANNEL is not None:
596 RESULTS_LISTENER_CHANNEL.close()
597 RESULTS_LISTENER_CHANNEL = None
598
599 # Pump the asyncore map if it isn't empty.
600 if len(asyncore_map) > 0:
601 asyncore.loop(0.1, False, asyncore_map, 10)
602
603
604def handle_ctrl_c(ctrl_c_count, job_queue, workers, inferior_pid_events,
605 stop_all_inferiors_func):
606 """Performs the appropriate ctrl-c action for non-pool parallel test runners
607
608 @param ctrl_c_count starting with 1, indicates the number of times ctrl-c
609 has been intercepted. The value is 1 on the first intercept, 2 on the
610 second, etc.
611
612 @param job_queue a Queue object that contains the work still outstanding
613 (i.e. hasn't been assigned to a worker yet).
614
615 @param workers list of Thread or Process workers.
616
617 @param inferior_pid_events specifies a Queue of inferior process
618 construction and destruction events. Used to build the list of inferior
619 processes that should be killed if we get that far.
620
621 @param stop_all_inferiors_func a callable object that takes the
622 workers and inferior_pid_events parameters (in that order) if a hard
623 stop is to be used on the workers.
624 """
625
626 # Print out which Ctrl-C we're handling.
627 key_name = [
628 "first",
629 "second",
630 "third",
631 "many"]
632
633 if ctrl_c_count < len(key_name):
634 name_index = ctrl_c_count - 1
635 else:
636 name_index = len(key_name) - 1
637 message = "\nHandling {} KeyboardInterrupt".format(key_name[name_index])
638 with output_lock:
Zachary Turnerff890da2015-10-19 23:45:41 +0000639 print(message)
Todd Fiala68615ce2015-09-15 21:38:04 +0000640
641 if ctrl_c_count == 1:
642 # Remove all outstanding items from the work queue so we stop
643 # doing any more new work.
644 while not job_queue.empty():
645 try:
646 # Just drain it to stop more work from being started.
647 job_queue.get_nowait()
Zachary Turner814236d2015-10-21 17:48:52 +0000648 except queue.Empty:
Todd Fiala68615ce2015-09-15 21:38:04 +0000649 pass
650 with output_lock:
Zachary Turnerff890da2015-10-19 23:45:41 +0000651 print("Stopped more work from being started.")
Todd Fiala68615ce2015-09-15 21:38:04 +0000652 elif ctrl_c_count == 2:
653 # Try to stop all inferiors, even the ones currently doing work.
654 stop_all_inferiors_func(workers, inferior_pid_events)
655 else:
656 with output_lock:
Zachary Turnerff890da2015-10-19 23:45:41 +0000657 print("All teardown activities kicked off, should finish soon.")
Todd Fiala68615ce2015-09-15 21:38:04 +0000658
659
660def workers_and_async_done(workers, async_map):
661 """Returns True if the workers list and asyncore channels are all done.
662
663 @param workers list of workers (threads/processes). These must adhere
664 to the threading Thread or multiprocessing.Process interface.
665
666 @param async_map the threading-aware asyncore channel map to check
667 for live channels.
668
669 @return False if the workers list exists and has any entries in it, or
670 if the async_map exists and has any entries left in it; otherwise, True.
671 """
672 if workers is not None and len(workers) > 0:
673 # We're not done if we still have workers left.
674 return False
675 if async_map is not None and len(async_map) > 0:
676 return False
677 # We're done.
678 return True
679
680
Todd Fiala8cbeed32015-09-08 22:22:33 +0000681def multiprocessing_test_runner(num_threads, test_work_items):
682 """Provides hand-wrapped pooling test runner adapter with Ctrl-C support.
683
684 This concurrent test runner is based on the multiprocessing
685 library, and rolls its own worker pooling strategy so it
686 can handle Ctrl-C properly.
687
688 This test runner is known to have an issue running on
689 Windows platforms.
690
691 @param num_threads the number of worker processes to use.
692
693 @param test_work_items the iterable of test work item tuples
694 to run.
695 """
696
697 # Initialize our global state.
698 initialize_global_vars_multiprocessing(num_threads, test_work_items)
699
700 # Create jobs.
701 job_queue = multiprocessing.Queue(len(test_work_items))
702 for test_work_item in test_work_items:
703 job_queue.put(test_work_item)
704
705 result_queue = multiprocessing.Queue(len(test_work_items))
706
707 # Create queues for started child pids. Terminating
708 # the multiprocess processes does not terminate the
709 # child processes they spawn. We can remove this tracking
710 # if/when we move to having the multiprocess process directly
711 # perform the test logic. The Queue size needs to be able to
712 # hold 2 * (num inferior dotest.py processes started) entries.
713 inferior_pid_events = multiprocessing.Queue(4096)
714
Todd Fiala33896a92015-09-18 21:01:13 +0000715 # Worker dictionary allows each worker to figure out its worker index.
716 manager = multiprocessing.Manager()
717 worker_index_map = manager.dict()
718
Todd Fiala8cbeed32015-09-08 22:22:33 +0000719 # Create workers. We don't use multiprocessing.Pool due to
720 # challenges with handling ^C keyboard interrupts.
721 workers = []
722 for _ in range(num_threads):
723 worker = multiprocessing.Process(
724 target=process_dir_worker_multiprocessing,
725 args=(output_lock,
726 test_counter,
727 total_tests,
728 test_name_len,
729 dotest_options,
730 job_queue,
731 result_queue,
Todd Fiala33896a92015-09-18 21:01:13 +0000732 inferior_pid_events,
733 worker_index_map))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000734 worker.start()
735 workers.append(worker)
736
Todd Fiala68615ce2015-09-15 21:38:04 +0000737 # Main loop: wait for all workers to finish and wait for
738 # the socket handlers to wrap up.
739 ctrl_c_loop(
740 # Main operation of loop
741 lambda: pump_workers_and_asyncore_map(
742 workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000743
Todd Fiala68615ce2015-09-15 21:38:04 +0000744 # Return True when we're done with the main loop.
745 lambda: workers_and_async_done(workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000746
Todd Fiala68615ce2015-09-15 21:38:04 +0000747 # Indicate what we do when we receive one or more Ctrl-Cs.
748 lambda ctrl_c_count: handle_ctrl_c(
749 ctrl_c_count, job_queue, workers, inferior_pid_events,
750 kill_all_worker_processes))
751
752 # Reap the test results.
Todd Fiala8cbeed32015-09-08 22:22:33 +0000753 test_results = []
754 while not result_queue.empty():
755 test_results.append(result_queue.get(block=False))
756 return test_results
757
758
Todd Fiala68615ce2015-09-15 21:38:04 +0000759def map_async_run_loop(future, channel_map, listener_channel):
760 """Blocks until the Pool.map_async completes and the channel completes.
761
762 @param future an AsyncResult instance from a Pool.map_async() call.
763
764 @param channel_map the asyncore dispatch channel map that should be pumped.
765 Optional: may be None.
766
767 @param listener_channel the channel representing a listener that should be
768 closed once the map_async results are available.
769
770 @return the results from the async_result instance.
771 """
772 map_results = None
773
774 done = False
775 while not done:
776 # Check if we need to reap the map results.
777 if map_results is None:
778 if future.ready():
779 # Get the results.
780 map_results = future.get()
781
782 # Close the runner process listener channel if we have
783 # one: no more connections will be incoming.
784 if listener_channel is not None:
785 listener_channel.close()
786
787 # Pump the asyncore loop if we have a listener socket.
788 if channel_map is not None:
789 asyncore.loop(0.01, False, channel_map, 10)
790
791 # Figure out if we're done running.
792 done = map_results is not None
793 if channel_map is not None:
794 # We have a runner process async map. Check if it
795 # is complete.
796 if len(channel_map) > 0:
797 # We still have an asyncore channel running. Not done yet.
798 done = False
799
800 return map_results
801
802
Todd Fiala8cbeed32015-09-08 22:22:33 +0000803def multiprocessing_test_runner_pool(num_threads, test_work_items):
804 # Initialize our global state.
805 initialize_global_vars_multiprocessing(num_threads, test_work_items)
806
Todd Fiala33896a92015-09-18 21:01:13 +0000807 manager = multiprocessing.Manager()
808 worker_index_map = manager.dict()
809
Todd Fiala8cbeed32015-09-08 22:22:33 +0000810 pool = multiprocessing.Pool(
811 num_threads,
812 initializer=setup_global_variables,
813 initargs=(output_lock, test_counter, total_tests, test_name_len,
Todd Fiala33896a92015-09-18 21:01:13 +0000814 dotest_options, worker_index_map))
Todd Fiala68615ce2015-09-15 21:38:04 +0000815
816 # Start the map operation (async mode).
817 map_future = pool.map_async(
818 process_dir_worker_multiprocessing_pool, test_work_items)
819 return map_async_run_loop(
820 map_future, RUNNER_PROCESS_ASYNC_MAP, RESULTS_LISTENER_CHANNEL)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000821
822
823def threading_test_runner(num_threads, test_work_items):
824 """Provides hand-wrapped pooling threading-based test runner adapter
825 with Ctrl-C support.
826
827 This concurrent test runner is based on the threading
828 library, and rolls its own worker pooling strategy so it
829 can handle Ctrl-C properly.
830
831 @param num_threads the number of worker processes to use.
832
833 @param test_work_items the iterable of test work item tuples
834 to run.
835 """
836
837 # Initialize our global state.
838 initialize_global_vars_threading(num_threads, test_work_items)
839
840 # Create jobs.
Zachary Turner814236d2015-10-21 17:48:52 +0000841 job_queue = queue.Queue()
Todd Fiala8cbeed32015-09-08 22:22:33 +0000842 for test_work_item in test_work_items:
843 job_queue.put(test_work_item)
844
Zachary Turner814236d2015-10-21 17:48:52 +0000845 result_queue = queue.Queue()
Todd Fiala8cbeed32015-09-08 22:22:33 +0000846
847 # Create queues for started child pids. Terminating
848 # the threading threads does not terminate the
849 # child processes they spawn.
Zachary Turner814236d2015-10-21 17:48:52 +0000850 inferior_pid_events = queue.Queue()
Todd Fiala8cbeed32015-09-08 22:22:33 +0000851
852 # Create workers. We don't use multiprocessing.pool.ThreadedPool
853 # due to challenges with handling ^C keyboard interrupts.
854 workers = []
855 for _ in range(num_threads):
856 worker = threading.Thread(
857 target=process_dir_worker_threading,
Todd Fiala68615ce2015-09-15 21:38:04 +0000858 args=(job_queue,
Todd Fiala8cbeed32015-09-08 22:22:33 +0000859 result_queue,
860 inferior_pid_events))
861 worker.start()
862 workers.append(worker)
863
Todd Fiala68615ce2015-09-15 21:38:04 +0000864 # Main loop: wait for all workers to finish and wait for
865 # the socket handlers to wrap up.
866 ctrl_c_loop(
867 # Main operation of loop
868 lambda: pump_workers_and_asyncore_map(
869 workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000870
Todd Fiala68615ce2015-09-15 21:38:04 +0000871 # Return True when we're done with the main loop.
872 lambda: workers_and_async_done(workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000873
Todd Fiala68615ce2015-09-15 21:38:04 +0000874 # Indicate what we do when we receive one or more Ctrl-Cs.
875 lambda ctrl_c_count: handle_ctrl_c(
876 ctrl_c_count, job_queue, workers, inferior_pid_events,
877 kill_all_worker_threads))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000878
Todd Fiala68615ce2015-09-15 21:38:04 +0000879 # Reap the test results.
Todd Fiala8cbeed32015-09-08 22:22:33 +0000880 test_results = []
881 while not result_queue.empty():
882 test_results.append(result_queue.get(block=False))
883 return test_results
884
885
886def threading_test_runner_pool(num_threads, test_work_items):
887 # Initialize our global state.
888 initialize_global_vars_threading(num_threads, test_work_items)
889
Todd Fiala68615ce2015-09-15 21:38:04 +0000890 pool = multiprocessing.pool.ThreadPool(num_threads)
891 map_future = pool.map_async(
892 process_dir_worker_threading_pool, test_work_items)
893
894 return map_async_run_loop(
895 map_future, RUNNER_PROCESS_ASYNC_MAP, RESULTS_LISTENER_CHANNEL)
896
897
898def asyncore_run_loop(channel_map):
899 try:
900 asyncore.loop(None, False, channel_map)
901 except:
902 # Swallow it, we're seeing:
903 # error: (9, 'Bad file descriptor')
904 # when the listener channel is closed. Shouldn't be the case.
905 pass
Todd Fiala8cbeed32015-09-08 22:22:33 +0000906
907
908def inprocess_exec_test_runner(test_work_items):
909 # Initialize our global state.
910 initialize_global_vars_multiprocessing(1, test_work_items)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000911
Todd Fiala33896a92015-09-18 21:01:13 +0000912 # We're always worker index 0
913 global GET_WORKER_INDEX
914 GET_WORKER_INDEX = lambda: 0
915
Todd Fiala68615ce2015-09-15 21:38:04 +0000916 # Run the listener and related channel maps in a separate thread.
917 # global RUNNER_PROCESS_ASYNC_MAP
918 global RESULTS_LISTENER_CHANNEL
919 if RESULTS_LISTENER_CHANNEL is not None:
920 socket_thread = threading.Thread(
921 target=lambda: asyncore_run_loop(RUNNER_PROCESS_ASYNC_MAP))
922 socket_thread.start()
923
924 # Do the work.
Zachary Turner1c4059a2015-10-22 20:39:59 +0000925 test_results = list(map(process_dir_mapper_inprocess, test_work_items))
Todd Fiala68615ce2015-09-15 21:38:04 +0000926
927 # If we have a listener channel, shut it down here.
928 if RESULTS_LISTENER_CHANNEL is not None:
929 # Close down the channel.
930 RESULTS_LISTENER_CHANNEL.close()
931 RESULTS_LISTENER_CHANNEL = None
932
933 # Wait for the listener and handlers to complete.
934 socket_thread.join()
935
936 return test_results
Todd Fiala8cbeed32015-09-08 22:22:33 +0000937
938def walk_and_invoke(test_directory, test_subdir, dotest_argv,
Todd Fiala871b2e52015-09-22 22:47:34 +0000939 num_workers, test_runner_func):
Steve Puccibefe2b12014-03-07 00:01:11 +0000940 """Look for matched files and invoke test driver on each one.
941 In single-threaded mode, each test driver is invoked directly.
942 In multi-threaded mode, submit each test driver to a worker
Vince Harrone06a7a82015-05-12 23:12:19 +0000943 queue, and then wait for all to complete.
944
945 test_directory - lldb/test/ directory
Chaoren Linb6325d02015-08-12 18:02:54 +0000946 test_subdir - lldb/test/ or a subfolder with the tests we're interested in
947 running
Vince Harrone06a7a82015-05-12 23:12:19 +0000948 """
Todd Fiala68615ce2015-09-15 21:38:04 +0000949 # The async_map is important to keep all thread-related asyncore
950 # channels distinct when we call asyncore.loop() later on.
951 global RESULTS_LISTENER_CHANNEL, RUNNER_PROCESS_ASYNC_MAP
952 RUNNER_PROCESS_ASYNC_MAP = {}
953
954 # If we're outputting side-channel test results, create the socket
955 # listener channel and tell the inferior to send results to the
956 # port on which we'll be listening.
957 if RESULTS_FORMATTER is not None:
Todd Fialae83f1402015-09-18 22:45:31 +0000958 forwarding_func = RESULTS_FORMATTER.handle_event
Todd Fiala68615ce2015-09-15 21:38:04 +0000959 RESULTS_LISTENER_CHANNEL = (
960 dotest_channels.UnpicklingForwardingListenerChannel(
Todd Fiala871b2e52015-09-22 22:47:34 +0000961 RUNNER_PROCESS_ASYNC_MAP, "localhost", 0,
962 2 * num_workers, forwarding_func))
Todd Fiala68615ce2015-09-15 21:38:04 +0000963 dotest_argv.append("--results-port")
964 dotest_argv.append(str(RESULTS_LISTENER_CHANNEL.address[1]))
Todd Fiala3f0a3602014-07-08 06:42:37 +0000965
966 # Collect the test files that we'll run.
967 test_work_items = []
Todd Fiala8cbeed32015-09-08 22:22:33 +0000968 find_test_files_in_dir_tree(
969 test_subdir, lambda testdir, test_files: test_work_items.append([
Zachary Turner7d564542015-11-02 19:19:49 +0000970 test_subdir, test_files, dotest_argv, None]))
Todd Fiala3f0a3602014-07-08 06:42:37 +0000971
Todd Fiala8cbeed32015-09-08 22:22:33 +0000972 # Convert test work items into test results using whatever
973 # was provided as the test run function.
974 test_results = test_runner_func(test_work_items)
Chaoren Linffc63b02015-08-12 18:02:49 +0000975
Todd Fiala8cbeed32015-09-08 22:22:33 +0000976 # Summarize the results and return to caller.
Chaoren Line80372a2015-08-12 18:02:53 +0000977 timed_out = sum([result[0] for result in test_results], [])
978 passed = sum([result[1] for result in test_results], [])
979 failed = sum([result[2] for result in test_results], [])
Zachary Turner4cceca72015-08-14 16:45:32 +0000980 unexpected_successes = sum([result[3] for result in test_results], [])
981 pass_count = sum([result[4] for result in test_results])
982 fail_count = sum([result[5] for result in test_results])
Todd Fiala3f0a3602014-07-08 06:42:37 +0000983
Todd Fiala8cbeed32015-09-08 22:22:33 +0000984 return (timed_out, passed, failed, unexpected_successes, pass_count,
985 fail_count)
Johnny Chene8d9dc62011-10-31 19:04:07 +0000986
Chaoren Linb6325d02015-08-12 18:02:54 +0000987
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000988def getExpectedTimeouts(platform_name):
Vince Harron06381732015-05-12 23:10:36 +0000989 # returns a set of test filenames that might timeout
990 # are we running against a remote target?
Chaoren Linfebef1b2015-08-19 17:22:12 +0000991 host = sys.platform
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000992 if platform_name is None:
Vince Harron06381732015-05-12 23:10:36 +0000993 target = sys.platform
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000994 else:
Todd Fiala68615ce2015-09-15 21:38:04 +0000995 m = re.search(r'remote-(\w+)', platform_name)
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000996 target = m.group(1)
Vince Harron06381732015-05-12 23:10:36 +0000997
998 expected_timeout = set()
999
1000 if target.startswith("linux"):
1001 expected_timeout |= {
Vince Harron06381732015-05-12 23:10:36 +00001002 "TestConnectRemote.py",
1003 "TestCreateAfterAttach.py",
Tamas Berghammer0d0ec9f2015-05-19 10:49:40 +00001004 "TestEvents.py",
Vince Harron06381732015-05-12 23:10:36 +00001005 "TestExitDuringStep.py",
Chaoren Linb6325d02015-08-12 18:02:54 +00001006
1007 # Times out in ~10% of the times on the build bot
1008 "TestHelloWorld.py",
Oleksiy Vyalov18f4c9f2015-06-10 01:34:25 +00001009 "TestMultithreaded.py",
Chaoren Linb6325d02015-08-12 18:02:54 +00001010 "TestRegisters.py", # ~12/600 dosep runs (build 3120-3122)
Vince Harron06381732015-05-12 23:10:36 +00001011 "TestThreadStepOut.py",
1012 }
1013 elif target.startswith("android"):
1014 expected_timeout |= {
1015 "TestExitDuringStep.py",
1016 "TestHelloWorld.py",
1017 }
Chaoren Linfebef1b2015-08-19 17:22:12 +00001018 if host.startswith("win32"):
1019 expected_timeout |= {
1020 "TestEvents.py",
1021 "TestThreadStates.py",
1022 }
Ed Maste4dd8fba2015-05-14 16:25:52 +00001023 elif target.startswith("freebsd"):
1024 expected_timeout |= {
1025 "TestBreakpointConditions.py",
Ed Maste08948132015-05-28 18:45:30 +00001026 "TestChangeProcessGroup.py",
Ed Mastebfd05632015-05-27 19:11:29 +00001027 "TestValueObjectRecursion.py",
Ed Maste4dd8fba2015-05-14 16:25:52 +00001028 "TestWatchpointConditionAPI.py",
1029 }
Vince Harron0f173ac2015-05-18 19:36:33 +00001030 elif target.startswith("darwin"):
1031 expected_timeout |= {
Chaoren Linb6325d02015-08-12 18:02:54 +00001032 # times out on MBP Retina, Mid 2012
1033 "TestThreadSpecificBreakpoint.py",
Chaoren Lind9043712015-08-19 17:13:02 +00001034 "TestExitDuringStep.py",
Chaoren Lin99f25be2015-08-20 01:26:57 +00001035 "TestIntegerTypesExpr.py",
Vince Harron0f173ac2015-05-18 19:36:33 +00001036 }
Vince Harron06381732015-05-12 23:10:36 +00001037 return expected_timeout
1038
Chaoren Linb6325d02015-08-12 18:02:54 +00001039
Pavel Labathfad30cf2015-06-29 14:16:51 +00001040def getDefaultTimeout(platform_name):
1041 if os.getenv("LLDB_TEST_TIMEOUT"):
1042 return os.getenv("LLDB_TEST_TIMEOUT")
1043
1044 if platform_name is None:
1045 platform_name = sys.platform
1046
1047 if platform_name.startswith("remote-"):
1048 return "10m"
1049 else:
1050 return "4m"
1051
Chaoren Linb6325d02015-08-12 18:02:54 +00001052
Vince Harron0b9dbb52015-05-21 18:18:52 +00001053def touch(fname, times=None):
Greg Clayton8c3f9c92015-08-11 21:01:32 +00001054 if os.path.exists(fname):
Vince Harron0b9dbb52015-05-21 18:18:52 +00001055 os.utime(fname, times)
1056
Chaoren Linb6325d02015-08-12 18:02:54 +00001057
Vince Harrondcc2b9f2015-05-27 04:40:36 +00001058def find(pattern, path):
1059 result = []
1060 for root, dirs, files in os.walk(path):
1061 for name in files:
1062 if fnmatch.fnmatch(name, pattern):
1063 result.append(os.path.join(root, name))
1064 return result
1065
Chaoren Linb6325d02015-08-12 18:02:54 +00001066
Todd Fiala8cbeed32015-09-08 22:22:33 +00001067def get_test_runner_strategies(num_threads):
1068 """Returns the test runner strategies by name in a dictionary.
1069
1070 @param num_threads specifies the number of threads/processes
1071 that will be used for concurrent test runners.
1072
1073 @return dictionary with key as test runner strategy name and
1074 value set to a callable object that takes the test work item
1075 and returns a test result tuple.
1076 """
1077 return {
1078 # multiprocessing supports ctrl-c and does not use
1079 # multiprocessing.Pool.
1080 "multiprocessing":
1081 (lambda work_items: multiprocessing_test_runner(
1082 num_threads, work_items)),
1083
1084 # multiprocessing-pool uses multiprocessing.Pool but
1085 # does not support Ctrl-C.
1086 "multiprocessing-pool":
1087 (lambda work_items: multiprocessing_test_runner_pool(
1088 num_threads, work_items)),
1089
1090 # threading uses a hand-rolled worker pool much
1091 # like multiprocessing, but instead uses in-process
1092 # worker threads. This one supports Ctrl-C.
1093 "threading":
1094 (lambda work_items: threading_test_runner(num_threads, work_items)),
1095
1096 # threading-pool uses threading for the workers (in-process)
1097 # and uses the multiprocessing.pool thread-enabled pool.
Todd Fiala68615ce2015-09-15 21:38:04 +00001098 # This does not properly support Ctrl-C.
Todd Fiala8cbeed32015-09-08 22:22:33 +00001099 "threading-pool":
1100 (lambda work_items: threading_test_runner_pool(
1101 num_threads, work_items)),
1102
1103 # serial uses the subprocess-based, single process
1104 # test runner. This provides process isolation but
Todd Fiala68615ce2015-09-15 21:38:04 +00001105 # no concurrent test execution.
Todd Fiala8cbeed32015-09-08 22:22:33 +00001106 "serial":
1107 inprocess_exec_test_runner
1108 }
1109
1110
Todd Fialaea736242015-09-23 15:21:28 +00001111def _remove_option(
1112 args, long_option_name, short_option_name, takes_arg):
Todd Fiala68615ce2015-09-15 21:38:04 +00001113 """Removes option and related option arguments from args array.
Todd Fialaea736242015-09-23 15:21:28 +00001114
1115 This method removes all short/long options that match the given
1116 arguments.
1117
Todd Fiala68615ce2015-09-15 21:38:04 +00001118 @param args the array of command line arguments (in/out)
Todd Fialaea736242015-09-23 15:21:28 +00001119
1120 @param long_option_name the full command line representation of the
1121 long-form option that will be removed (including '--').
1122
1123 @param short_option_name the short version of the command line option
1124 that will be removed (including '-').
1125
1126 @param takes_arg True if the option takes an argument.
1127
Todd Fiala68615ce2015-09-15 21:38:04 +00001128 """
Todd Fialaea736242015-09-23 15:21:28 +00001129 if long_option_name is not None:
1130 regex_string = "^" + long_option_name + "="
1131 long_regex = re.compile(regex_string)
1132 if short_option_name is not None:
1133 # Short options we only match the -X and assume
1134 # any arg is one command line argument jammed together.
1135 # i.e. -O--abc=1 is a single argument in the args list.
1136 # We don't handle -O --abc=1, as argparse doesn't handle
1137 # it, either.
1138 regex_string = "^" + short_option_name
1139 short_regex = re.compile(regex_string)
1140
1141 def remove_long_internal():
1142 """Removes one matching long option from args.
1143 @returns True if one was found and removed; False otherwise.
1144 """
1145 try:
1146 index = args.index(long_option_name)
1147 # Handle the exact match case.
1148 if takes_arg:
1149 removal_count = 2
1150 else:
1151 removal_count = 1
1152 del args[index:index+removal_count]
1153 return True
1154 except ValueError:
1155 # Thanks to argparse not handling options with known arguments
1156 # like other options parsing libraries (see
1157 # https://bugs.python.org/issue9334), we need to support the
1158 # --results-formatter-options={second-level-arguments} (note
1159 # the equal sign to fool the first-level arguments parser into
1160 # not treating the second-level arguments as first-level
1161 # options). We're certainly at risk of getting this wrong
1162 # since now we're forced into the business of trying to figure
1163 # out what is an argument (although I think this
1164 # implementation will suffice).
1165 for index in range(len(args)):
1166 match = long_regex.search(args[index])
1167 if match:
1168 del args[index]
1169 return True
1170 return False
1171
1172 def remove_short_internal():
1173 """Removes one matching short option from args.
1174 @returns True if one was found and removed; False otherwise.
1175 """
Todd Fiala68615ce2015-09-15 21:38:04 +00001176 for index in range(len(args)):
Todd Fialaea736242015-09-23 15:21:28 +00001177 match = short_regex.search(args[index])
Todd Fiala68615ce2015-09-15 21:38:04 +00001178 if match:
Todd Fiala68615ce2015-09-15 21:38:04 +00001179 del args[index]
Todd Fialaea736242015-09-23 15:21:28 +00001180 return True
1181 return False
Todd Fiala68615ce2015-09-15 21:38:04 +00001182
Todd Fialaea736242015-09-23 15:21:28 +00001183 removal_count = 0
1184 while long_option_name is not None and remove_long_internal():
1185 removal_count += 1
1186 while short_option_name is not None and remove_short_internal():
1187 removal_count += 1
1188 if removal_count == 0:
1189 raise Exception(
1190 "failed to find at least one of '{}', '{}' in options".format(
1191 long_option_name, short_option_name))
Todd Fiala68615ce2015-09-15 21:38:04 +00001192
1193
1194def adjust_inferior_options(dotest_argv):
1195 """Adjusts the commandline args array for inferiors.
1196
1197 This method adjusts the inferior dotest commandline options based
1198 on the parallel test runner's options. Some of the inferior options
1199 will need to change to properly handle aggregation functionality.
1200 """
1201 global dotest_options
1202
1203 # If we don't have a session directory, create one.
1204 if not dotest_options.s:
1205 # no session log directory, we need to add this to prevent
1206 # every dotest invocation from creating its own directory
1207 import datetime
1208 # The windows platforms don't like ':' in the pathname.
Zachary Turneraf383ff2015-10-27 22:33:47 +00001209 timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
Todd Fiala68615ce2015-09-15 21:38:04 +00001210 dotest_argv.append('-s')
1211 dotest_argv.append(timestamp_started)
1212 dotest_options.s = timestamp_started
1213
1214 # Adjust inferior results formatter options - if the parallel
1215 # test runner is collecting into the user-specified test results,
1216 # we'll have inferiors spawn with the --results-port option and
1217 # strip the original test runner options.
1218 if dotest_options.results_file is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001219 _remove_option(dotest_argv, "--results-file", None, True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001220 if dotest_options.results_port is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001221 _remove_option(dotest_argv, "--results-port", None, True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001222 if dotest_options.results_formatter is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001223 _remove_option(dotest_argv, "--results-formatter", None, True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001224 if dotest_options.results_formatter_options is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001225 _remove_option(dotest_argv, "--results-formatter-option", "-O",
1226 True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001227
Todd Fiala33896a92015-09-18 21:01:13 +00001228 # Remove test runner name if present.
1229 if dotest_options.test_runner_name is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001230 _remove_option(dotest_argv, "--test-runner-name", None, True)
Todd Fiala33896a92015-09-18 21:01:13 +00001231
1232
Todd Fiala83c32e32015-09-22 21:19:40 +00001233def is_darwin_version_lower_than(target_version):
1234 """Checks that os is Darwin and version is lower than target_version.
1235
1236 @param target_version the StrictVersion indicating the version
1237 we're checking against.
1238
1239 @return True if the OS is Darwin (OS X) and the version number of
1240 the OS is less than target_version; False in all other cases.
1241 """
1242 if platform.system() != 'Darwin':
1243 # Can't be Darwin lower than a certain version.
1244 return False
1245
1246 system_version = distutils.version.StrictVersion(platform.mac_ver()[0])
Todd Fiala871b2e52015-09-22 22:47:34 +00001247 return cmp(system_version, target_version) < 0
Todd Fiala83c32e32015-09-22 21:19:40 +00001248
1249
1250def default_test_runner_name(num_threads):
1251 """Returns the default test runner name for the configuration.
1252
1253 @param num_threads the number of threads/workers this test runner is
1254 supposed to use.
1255
1256 @return the test runner name that should be used by default when
1257 no test runner was explicitly called out on the command line.
1258 """
1259 if num_threads == 1:
1260 # Use the serial runner.
1261 test_runner_name = "serial"
1262 elif os.name == "nt":
Adrian McCarthy040b31d2015-10-12 14:46:57 +00001263 # On Windows, Python uses CRT with a low limit on the number of open
1264 # files. If you have a lot of cores, the threading-pool runner will
1265 # often fail because it exceeds that limit.
1266 if num_threads > 32:
1267 test_runner_name = "multiprocessing-pool"
1268 else:
1269 test_runner_name = "threading-pool"
Todd Fiala83c32e32015-09-22 21:19:40 +00001270 elif is_darwin_version_lower_than(
1271 distutils.version.StrictVersion("10.10.0")):
1272 # OS X versions before 10.10 appear to have an issue using
1273 # the threading test runner. Fall back to multiprocessing.
1274 # Supports Ctrl-C.
1275 test_runner_name = "multiprocessing"
1276 else:
1277 # For everyone else, use the ctrl-c-enabled threading support.
1278 # Should use fewer system resources than the multprocessing
1279 # variant.
1280 test_runner_name = "threading"
1281 return test_runner_name
1282
1283
Todd Fiala8cbeed32015-09-08 22:22:33 +00001284def main(print_details_on_success, num_threads, test_subdir,
Todd Fiala68615ce2015-09-15 21:38:04 +00001285 test_runner_name, results_formatter):
Todd Fialafed95662015-09-03 18:58:44 +00001286 """Run dotest.py in inferior mode in parallel.
1287
1288 @param print_details_on_success the parsed value of the output-on-success
1289 command line argument. When True, details of a successful dotest inferior
1290 are printed even when everything succeeds. The normal behavior is to
1291 not print any details when all the inferior tests pass.
1292
1293 @param num_threads the parsed value of the num-threads command line
1294 argument.
1295
1296 @param test_subdir optionally specifies a subdir to limit testing
1297 within. May be None if the entire test tree is to be used. This subdir
1298 is assumed to be relative to the lldb/test root of the test hierarchy.
Todd Fiala8cbeed32015-09-08 22:22:33 +00001299
1300 @param test_runner_name if specified, contains the test runner
1301 name which selects the strategy used to run the isolated and
1302 optionally concurrent test runner. Specify None to allow the
1303 system to choose the most appropriate test runner given desired
1304 thread count and OS type.
1305
Todd Fiala68615ce2015-09-15 21:38:04 +00001306 @param results_formatter if specified, provides the TestResultsFormatter
1307 instance that will format and output test result data from the
1308 side-channel test results. When specified, inferior dotest calls
1309 will send test results side-channel data over a socket to the parallel
1310 test runner, which will forward them on to results_formatter.
Todd Fialafed95662015-09-03 18:58:44 +00001311 """
1312
Todd Fiala1cc97b42015-09-21 05:42:26 +00001313 # Do not shut down on sighup.
Ying Chend93aa102015-09-23 21:53:18 +00001314 if hasattr(signal, 'SIGHUP'):
1315 signal.signal(signal.SIGHUP, signal.SIG_IGN)
Todd Fiala1cc97b42015-09-21 05:42:26 +00001316
Todd Fialafed95662015-09-03 18:58:44 +00001317 dotest_argv = sys.argv[1:]
1318
Greg Claytonb0d148e2015-09-21 17:25:01 +00001319 global output_on_success, RESULTS_FORMATTER
Todd Fialafed95662015-09-03 18:58:44 +00001320 output_on_success = print_details_on_success
Todd Fiala68615ce2015-09-15 21:38:04 +00001321 RESULTS_FORMATTER = results_formatter
Todd Fialafed95662015-09-03 18:58:44 +00001322
Vince Harrond5fa1022015-05-10 15:24:12 +00001323 # We can't use sys.path[0] to determine the script directory
1324 # because it doesn't work under a debugger
Vince Harron8994fed2015-05-22 19:49:23 +00001325 parser = dotest_args.create_parser()
Pavel Labath05ab2372015-07-06 15:57:52 +00001326 global dotest_options
Vince Harron8994fed2015-05-22 19:49:23 +00001327 dotest_options = dotest_args.parse_args(parser, dotest_argv)
1328
Todd Fiala68615ce2015-09-15 21:38:04 +00001329 adjust_inferior_options(dotest_argv)
Vince Harron0b9dbb52015-05-21 18:18:52 +00001330
1331 session_dir = os.path.join(os.getcwd(), dotest_options.s)
Ed Mastecec2a5b2014-11-21 02:41:25 +00001332
Vince Harrone06a7a82015-05-12 23:12:19 +00001333 # The root directory was specified on the command line
Todd Fiala68615ce2015-09-15 21:38:04 +00001334 test_directory = os.path.dirname(os.path.realpath(__file__))
Todd Fialafed95662015-09-03 18:58:44 +00001335 if test_subdir and len(test_subdir) > 0:
1336 test_subdir = os.path.join(test_directory, test_subdir)
Vince Harrone06a7a82015-05-12 23:12:19 +00001337 else:
Todd Fialafed95662015-09-03 18:58:44 +00001338 test_subdir = test_directory
Vince Harrone06a7a82015-05-12 23:12:19 +00001339
Vince Harrondcc2b9f2015-05-27 04:40:36 +00001340 # clean core files in test tree from previous runs (Linux)
1341 cores = find('core.*', test_subdir)
1342 for core in cores:
1343 os.unlink(core)
1344
Daniel Maleab42556f2013-04-19 18:32:53 +00001345 system_info = " ".join(platform.uname())
Todd Fiala8cbeed32015-09-08 22:22:33 +00001346
1347 # Figure out which testrunner strategy we'll use.
1348 runner_strategies_by_name = get_test_runner_strategies(num_threads)
1349
1350 # If the user didn't specify a test runner strategy, determine
1351 # the default now based on number of threads and OS type.
1352 if not test_runner_name:
Todd Fiala83c32e32015-09-22 21:19:40 +00001353 test_runner_name = default_test_runner_name(num_threads)
Todd Fiala8cbeed32015-09-08 22:22:33 +00001354
1355 if test_runner_name not in runner_strategies_by_name:
Todd Fiala83c32e32015-09-22 21:19:40 +00001356 raise Exception(
1357 "specified testrunner name '{}' unknown. Valid choices: {}".format(
1358 test_runner_name,
Zachary Turner606e1e32015-10-23 17:53:51 +00001359 list(runner_strategies_by_name.keys())))
Todd Fiala8cbeed32015-09-08 22:22:33 +00001360 test_runner_func = runner_strategies_by_name[test_runner_name]
1361
1362 summary_results = walk_and_invoke(
Todd Fiala871b2e52015-09-22 22:47:34 +00001363 test_directory, test_subdir, dotest_argv,
1364 num_threads, test_runner_func)
Todd Fiala8cbeed32015-09-08 22:22:33 +00001365
1366 (timed_out, passed, failed, unexpected_successes, pass_count,
1367 fail_count) = summary_results
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +00001368
Todd Fialade9a44e2015-09-22 00:15:50 +00001369 # The results formatter - if present - is done now. Tell it to
1370 # terminate.
1371 if results_formatter is not None:
1372 results_formatter.send_terminate_as_needed()
1373
Vince Harron17f429f2014-12-13 00:08:19 +00001374 timed_out = set(timed_out)
Chaoren Line80372a2015-08-12 18:02:53 +00001375 num_test_files = len(passed) + len(failed)
1376 num_test_cases = pass_count + fail_count
Daniel Maleab42556f2013-04-19 18:32:53 +00001377
Vince Harrondcc2b9f2015-05-27 04:40:36 +00001378 # move core files into session dir
1379 cores = find('core.*', test_subdir)
1380 for core in cores:
1381 dst = core.replace(test_directory, "")[1:]
1382 dst = dst.replace(os.path.sep, "-")
1383 os.rename(core, os.path.join(session_dir, dst))
1384
Vince Harron06381732015-05-12 23:10:36 +00001385 # remove expected timeouts from failures
Vince Harronf8b9a1d2015-05-18 19:40:54 +00001386 expected_timeout = getExpectedTimeouts(dotest_options.lldb_platform_name)
Vince Harron06381732015-05-12 23:10:36 +00001387 for xtime in expected_timeout:
1388 if xtime in timed_out:
1389 timed_out.remove(xtime)
1390 failed.remove(xtime)
Vince Harron0b9dbb52015-05-21 18:18:52 +00001391 result = "ExpectedTimeout"
1392 elif xtime in passed:
1393 result = "UnexpectedCompletion"
1394 else:
1395 result = None # failed
1396
1397 if result:
1398 test_name = os.path.splitext(xtime)[0]
1399 touch(os.path.join(session_dir, "{}-{}".format(result, test_name)))
Vince Harron06381732015-05-12 23:10:36 +00001400
Zachary Turnerff890da2015-10-19 23:45:41 +00001401 print()
Chaoren Lin5a59e462015-08-12 18:02:51 +00001402 sys.stdout.write("Ran %d test suites" % num_test_files)
1403 if num_test_files > 0:
1404 sys.stdout.write(" (%d failed) (%f%%)" % (
1405 len(failed), 100.0 * len(failed) / num_test_files))
Zachary Turnerff890da2015-10-19 23:45:41 +00001406 print()
Chaoren Line80372a2015-08-12 18:02:53 +00001407 sys.stdout.write("Ran %d test cases" % num_test_cases)
1408 if num_test_cases > 0:
Chaoren Lin5a59e462015-08-12 18:02:51 +00001409 sys.stdout.write(" (%d failed) (%f%%)" % (
Chaoren Line80372a2015-08-12 18:02:53 +00001410 fail_count, 100.0 * fail_count / num_test_cases))
Zachary Turnerff890da2015-10-19 23:45:41 +00001411 print()
Zachary Turner4cceca72015-08-14 16:45:32 +00001412 exit_code = 0
1413
Daniel Maleacbaef262013-02-15 21:31:37 +00001414 if len(failed) > 0:
Shawn Best13491c42014-10-22 19:29:00 +00001415 failed.sort()
Zachary Turnerff890da2015-10-19 23:45:41 +00001416 print("Failing Tests (%d)" % len(failed))
Daniel Maleacbaef262013-02-15 21:31:37 +00001417 for f in failed:
Zachary Turnerff890da2015-10-19 23:45:41 +00001418 print("%s: LLDB (suite) :: %s (%s)" % (
Vince Harron17f429f2014-12-13 00:08:19 +00001419 "TIMEOUT" if f in timed_out else "FAIL", f, system_info
Zachary Turnerff890da2015-10-19 23:45:41 +00001420 ))
Zachary Turner4cceca72015-08-14 16:45:32 +00001421 exit_code = 1
1422
1423 if len(unexpected_successes) > 0:
1424 unexpected_successes.sort()
Zachary Turnerff890da2015-10-19 23:45:41 +00001425 print("\nUnexpected Successes (%d)" % len(unexpected_successes))
Zachary Turner4cceca72015-08-14 16:45:32 +00001426 for u in unexpected_successes:
Zachary Turnerff890da2015-10-19 23:45:41 +00001427 print("UNEXPECTED SUCCESS: LLDB (suite) :: %s (%s)" % (u, system_info))
Zachary Turner4cceca72015-08-14 16:45:32 +00001428
1429 sys.exit(exit_code)
Johnny Chene8d9dc62011-10-31 19:04:07 +00001430
1431if __name__ == '__main__':
Todd Fialafed95662015-09-03 18:58:44 +00001432 sys.stderr.write(
1433 "error: dosep.py no longer supports being called directly. "
1434 "Please call dotest.py directly. The dosep.py-specific arguments "
1435 "have been added under the Parallel processing arguments.\n")
1436 sys.exit(128)