blob: 6b6343c81441e68d1bee9cb1ae2604c86da9a9ca [file] [log] [blame]
Johnny Chene8d9dc62011-10-31 19:04:07 +00001"""
2Run the test suite using a separate process for each test file.
Vince Harronede59652015-01-08 02:11:26 +00003
Siva Chandra2d7832e2015-05-08 23:08:53 +00004Each test will run with a time limit of 10 minutes by default.
Vince Harronede59652015-01-08 02:11:26 +00005
Siva Chandra2d7832e2015-05-08 23:08:53 +00006Override the default time limit of 10 minutes by setting
Vince Harronede59652015-01-08 02:11:26 +00007the environment variable LLDB_TEST_TIMEOUT.
8
9E.g., export LLDB_TEST_TIMEOUT=10m
10
11Override the time limit for individual tests by setting
12the environment variable LLDB_[TEST NAME]_TIMEOUT.
13
14E.g., export LLDB_TESTCONCURRENTEVENTS_TIMEOUT=2m
15
16Set to "0" to run without time limit.
17
18E.g., export LLDB_TEST_TIMEOUT=0
19or export LLDB_TESTCONCURRENTEVENTS_TIMEOUT=0
Vince Harrondcc2b9f2015-05-27 04:40:36 +000020
Chaoren Linb6325d02015-08-12 18:02:54 +000021To collect core files for timed out tests,
22do the following before running dosep.py
Vince Harrondcc2b9f2015-05-27 04:40:36 +000023
24OSX
25ulimit -c unlimited
26sudo sysctl -w kern.corefile=core.%P
27
28Linux:
29ulimit -c unlimited
30echo core.%p | sudo tee /proc/sys/kernel/core_pattern
Johnny Chene8d9dc62011-10-31 19:04:07 +000031"""
32
Zachary Turnerff890da2015-10-19 23:45:41 +000033from __future__ import print_function
Zachary Turnerc1b7cd72015-11-05 19:22:28 +000034from __future__ import absolute_import
Zachary Turner814236d2015-10-21 17:48:52 +000035
Todd Fiala2d3754d2015-09-29 22:19:06 +000036# system packages and modules
Todd Fiala68615ce2015-09-15 21:38:04 +000037import asyncore
Todd Fiala83c32e32015-09-22 21:19:40 +000038import distutils.version
Vince Harrondcc2b9f2015-05-27 04:40:36 +000039import fnmatch
Todd Fiala8cbeed32015-09-08 22:22:33 +000040import multiprocessing
41import multiprocessing.pool
42import os
Todd Fiala3f0a3602014-07-08 06:42:37 +000043import platform
Vince Harron06381732015-05-12 23:10:36 +000044import re
Todd Fiala8cbeed32015-09-08 22:22:33 +000045import signal
Todd Fiala3f0a3602014-07-08 06:42:37 +000046import sys
Todd Fiala8cbeed32015-09-08 22:22:33 +000047import threading
Todd Fiala2d3754d2015-09-29 22:19:06 +000048
Zachary Turner814236d2015-10-21 17:48:52 +000049from six.moves import queue
50
Todd Fiala2d3754d2015-09-29 22:19:06 +000051# Our packages and modules
Zachary Turnerc1b7cd72015-11-05 19:22:28 +000052import lldbsuite.support.seven as seven
53
54from . import dotest_channels
55from . import dotest_args
Zachary Turner905a9882015-12-07 21:23:41 +000056from . import result_formatter
Zachary Turnerc1b7cd72015-11-05 19:22:28 +000057
58# Todo: Convert this folder layout to be relative-import friendly and don't hack up
59# sys.path like this
60sys.path.append(os.path.join(os.path.dirname(__file__), "test_runner", "lib"))
Todd Fiala2d3754d2015-09-29 22:19:06 +000061import lldb_utils
62import process_control
Vince Harron17f429f2014-12-13 00:08:19 +000063
Vince Harron17f429f2014-12-13 00:08:19 +000064# Status codes for running command with timeout.
65eTimedOut, ePassed, eFailed = 124, 0, 1
66
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +000067output_lock = None
68test_counter = None
69total_tests = None
Chaoren Linffc63b02015-08-12 18:02:49 +000070test_name_len = None
Pavel Labath05ab2372015-07-06 15:57:52 +000071dotest_options = None
Zachary Turner38e64172015-08-10 17:46:11 +000072output_on_success = False
Todd Fiala68615ce2015-09-15 21:38:04 +000073RESULTS_FORMATTER = None
74RUNNER_PROCESS_ASYNC_MAP = None
75RESULTS_LISTENER_CHANNEL = None
Chaoren Linb6325d02015-08-12 18:02:54 +000076
Todd Fiala33896a92015-09-18 21:01:13 +000077"""Contains an optional function pointer that can return the worker index
78 for the given thread/process calling it. Returns a 0-based index."""
79GET_WORKER_INDEX = None
80
Todd Fiala1cc97b42015-09-21 05:42:26 +000081
Todd Fiala33896a92015-09-18 21:01:13 +000082def setup_global_variables(
83 lock, counter, total, name_len, options, worker_index_map):
Chaoren Linffc63b02015-08-12 18:02:49 +000084 global output_lock, test_counter, total_tests, test_name_len
85 global dotest_options
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +000086 output_lock = lock
87 test_counter = counter
88 total_tests = total
Chaoren Linffc63b02015-08-12 18:02:49 +000089 test_name_len = name_len
Pavel Labath05ab2372015-07-06 15:57:52 +000090 dotest_options = options
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +000091
Todd Fiala33896a92015-09-18 21:01:13 +000092 if worker_index_map is not None:
93 # We'll use the output lock for this to avoid sharing another lock.
94 # This won't be used much.
95 index_lock = lock
96
97 def get_worker_index_use_pid():
98 """Returns a 0-based, process-unique index for the worker."""
99 pid = os.getpid()
100 with index_lock:
101 if pid not in worker_index_map:
102 worker_index_map[pid] = len(worker_index_map)
103 return worker_index_map[pid]
104
105 global GET_WORKER_INDEX
106 GET_WORKER_INDEX = get_worker_index_use_pid
107
Chaoren Linb6325d02015-08-12 18:02:54 +0000108
Zachary Turner38e64172015-08-10 17:46:11 +0000109def report_test_failure(name, command, output):
110 global output_lock
111 with output_lock:
Greg Clayton1827fc22015-09-19 00:39:09 +0000112 if not (RESULTS_FORMATTER and RESULTS_FORMATTER.is_using_terminal()):
Zachary Turnerff890da2015-10-19 23:45:41 +0000113 print(file=sys.stderr)
114 print(output, file=sys.stderr)
115 print("[%s FAILED]" % name, file=sys.stderr)
116 print("Command invoked: %s" % ' '.join(command), file=sys.stderr)
Chaoren Linffc63b02015-08-12 18:02:49 +0000117 update_progress(name)
Zachary Turner38e64172015-08-10 17:46:11 +0000118
Chaoren Linb6325d02015-08-12 18:02:54 +0000119
Zachary Turner38e64172015-08-10 17:46:11 +0000120def report_test_pass(name, output):
121 global output_lock, output_on_success
122 with output_lock:
Greg Clayton1827fc22015-09-19 00:39:09 +0000123 if not (RESULTS_FORMATTER and RESULTS_FORMATTER.is_using_terminal()):
124 if output_on_success:
Zachary Turnerff890da2015-10-19 23:45:41 +0000125 print(file=sys.stderr)
126 print(output, file=sys.stderr)
127 print("[%s PASSED]" % name, file=sys.stderr)
Chaoren Linffc63b02015-08-12 18:02:49 +0000128 update_progress(name)
Zachary Turner38e64172015-08-10 17:46:11 +0000129
Chaoren Linb6325d02015-08-12 18:02:54 +0000130
Chaoren Linffc63b02015-08-12 18:02:49 +0000131def update_progress(test_name=""):
132 global output_lock, test_counter, total_tests, test_name_len
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +0000133 with output_lock:
Chaoren Linffc63b02015-08-12 18:02:49 +0000134 counter_len = len(str(total_tests))
Greg Clayton1827fc22015-09-19 00:39:09 +0000135 if not (RESULTS_FORMATTER and RESULTS_FORMATTER.is_using_terminal()):
136 sys.stderr.write(
137 "\r%*d out of %d test suites processed - %-*s" %
138 (counter_len, test_counter.value, total_tests,
139 test_name_len.value, test_name))
Chaoren Linffc63b02015-08-12 18:02:49 +0000140 if len(test_name) > test_name_len.value:
141 test_name_len.value = len(test_name)
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +0000142 test_counter.value += 1
Zachary Turner38e64172015-08-10 17:46:11 +0000143 sys.stdout.flush()
144 sys.stderr.flush()
Chaoren Lin5e3ab2b2015-06-01 17:49:25 +0000145
Chaoren Linb6325d02015-08-12 18:02:54 +0000146
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000147def parse_test_results(output):
148 passes = 0
149 failures = 0
Zachary Turner4cceca72015-08-14 16:45:32 +0000150 unexpected_successes = 0
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000151 for result in output:
Chaoren Linb6325d02015-08-12 18:02:54 +0000152 pass_count = re.search("^RESULT:.*([0-9]+) passes",
153 result, re.MULTILINE)
154 fail_count = re.search("^RESULT:.*([0-9]+) failures",
155 result, re.MULTILINE)
156 error_count = re.search("^RESULT:.*([0-9]+) errors",
157 result, re.MULTILINE)
Zachary Turner4cceca72015-08-14 16:45:32 +0000158 unexpected_success_count = re.search("^RESULT:.*([0-9]+) unexpected successes",
159 result, re.MULTILINE)
Chaoren Linb6325d02015-08-12 18:02:54 +0000160 if pass_count is not None:
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000161 passes = passes + int(pass_count.group(1))
Chaoren Linb6325d02015-08-12 18:02:54 +0000162 if fail_count is not None:
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000163 failures = failures + int(fail_count.group(1))
Zachary Turner4cceca72015-08-14 16:45:32 +0000164 if unexpected_success_count is not None:
165 unexpected_successes = unexpected_successes + int(unexpected_success_count.group(1))
Chaoren Linb6325d02015-08-12 18:02:54 +0000166 if error_count is not None:
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000167 failures = failures + int(error_count.group(1))
Zachary Turner4cceca72015-08-14 16:45:32 +0000168 return passes, failures, unexpected_successes
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000169
Chaoren Linb6325d02015-08-12 18:02:54 +0000170
Todd Fiala2d3754d2015-09-29 22:19:06 +0000171class DoTestProcessDriver(process_control.ProcessDriver):
172 """Drives the dotest.py inferior process and handles bookkeeping."""
173 def __init__(self, output_file, output_file_lock, pid_events, file_name,
174 soft_terminate_timeout):
175 super(DoTestProcessDriver, self).__init__(
176 soft_terminate_timeout=soft_terminate_timeout)
177 self.output_file = output_file
178 self.output_lock = lldb_utils.OptionalWith(output_file_lock)
179 self.pid_events = pid_events
180 self.results = None
181 self.file_name = file_name
182
183 def write(self, content):
184 with self.output_lock:
185 self.output_file.write(content)
186
187 def on_process_started(self):
188 if self.pid_events:
189 self.pid_events.put_nowait(('created', self.process.pid))
190
191 def on_process_exited(self, command, output, was_timeout, exit_status):
192 if self.pid_events:
193 # No point in culling out those with no exit_status (i.e.
194 # those we failed to kill). That would just cause
195 # downstream code to try to kill it later on a Ctrl-C. At
196 # this point, a best-effort-to-kill already took place. So
197 # call it destroyed here.
198 self.pid_events.put_nowait(('destroyed', self.process.pid))
199
200 # Override the exit status if it was a timeout.
201 if was_timeout:
202 exit_status = eTimedOut
203
204 # If we didn't end up with any output, call it empty for
205 # stdout/stderr.
206 if output is None:
207 output = ('', '')
208
209 # Now parse the output.
210 passes, failures, unexpected_successes = parse_test_results(output)
211 if exit_status == 0:
212 # stdout does not have any useful information from 'dotest.py',
213 # only stderr does.
214 report_test_pass(self.file_name, output[1])
215 else:
216 report_test_failure(self.file_name, command, output[1])
217
218 # Save off the results for the caller.
219 self.results = (
220 self.file_name,
221 exit_status,
222 passes,
223 failures,
224 unexpected_successes)
225
226
227def get_soft_terminate_timeout():
228 # Defaults to 10 seconds, but can set
229 # LLDB_TEST_SOFT_TERMINATE_TIMEOUT to a floating point
230 # number in seconds. This value indicates how long
231 # the test runner will wait for the dotest inferior to
232 # handle a timeout via a soft terminate before it will
233 # assume that failed and do a hard terminate.
234
235 # TODO plumb through command-line option
236 return float(os.environ.get('LLDB_TEST_SOFT_TERMINATE_TIMEOUT', 10.0))
237
238
239def want_core_on_soft_terminate():
240 # TODO plumb through command-line option
241 if platform.system() == 'Linux':
242 return True
243 else:
244 return False
Todd Fialada817b62015-09-22 18:05:11 +0000245
246
Todd Fiala8cbeed32015-09-08 22:22:33 +0000247def call_with_timeout(command, timeout, name, inferior_pid_events):
Todd Fiala2d3754d2015-09-29 22:19:06 +0000248 # Add our worker index (if we have one) to all test events
249 # from this inferior.
Todd Fiala33896a92015-09-18 21:01:13 +0000250 if GET_WORKER_INDEX is not None:
Todd Fialae83f1402015-09-18 22:45:31 +0000251 try:
252 worker_index = GET_WORKER_INDEX()
253 command.extend([
Todd Fiala2d3754d2015-09-29 22:19:06 +0000254 "--event-add-entries",
255 "worker_index={}:int".format(worker_index)])
256 except: # pylint: disable=bare-except
257 # Ctrl-C does bad things to multiprocessing.Manager.dict()
258 # lookup. Just swallow it.
Todd Fialae83f1402015-09-18 22:45:31 +0000259 pass
260
Todd Fiala2d3754d2015-09-29 22:19:06 +0000261 # Create the inferior dotest.py ProcessDriver.
262 soft_terminate_timeout = get_soft_terminate_timeout()
263 want_core = want_core_on_soft_terminate()
Todd Fiala68615ce2015-09-15 21:38:04 +0000264
Todd Fiala2d3754d2015-09-29 22:19:06 +0000265 process_driver = DoTestProcessDriver(
266 sys.stdout,
267 output_lock,
268 inferior_pid_events,
269 name,
270 soft_terminate_timeout)
Todd Fiala68615ce2015-09-15 21:38:04 +0000271
Todd Fiala2d3754d2015-09-29 22:19:06 +0000272 # Run it with a timeout.
273 process_driver.run_command_with_timeout(command, timeout, want_core)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000274
Todd Fiala2d3754d2015-09-29 22:19:06 +0000275 # Return the results.
276 if not process_driver.results:
277 # This is truly exceptional. Even a failing or timed out
278 # binary should have called the results-generation code.
279 raise Exception("no test results were generated whatsoever")
280 return process_driver.results
Johnny Chene8d9dc62011-10-31 19:04:07 +0000281
Chaoren Linb6325d02015-08-12 18:02:54 +0000282
Zachary Turner7d564542015-11-02 19:19:49 +0000283def process_dir(root, files, dotest_argv, inferior_pid_events):
Steve Puccibefe2b12014-03-07 00:01:11 +0000284 """Examine a directory for tests, and invoke any found within it."""
Chaoren Line80372a2015-08-12 18:02:53 +0000285 results = []
Steve Puccibefe2b12014-03-07 00:01:11 +0000286 for name in files:
Zachary Turner7d564542015-11-02 19:19:49 +0000287 import __main__ as main
288 script_file = main.__file__
Zachary Turnerf6896b02015-01-05 19:37:03 +0000289 command = ([sys.executable, script_file] +
Vince Harron41657cc2015-05-21 18:15:09 +0000290 dotest_argv +
Todd Fialafed95662015-09-03 18:58:44 +0000291 ["--inferior", "-p", name, root])
Vince Harron17f429f2014-12-13 00:08:19 +0000292
293 timeout_name = os.path.basename(os.path.splitext(name)[0]).upper()
294
Chaoren Linb6325d02015-08-12 18:02:54 +0000295 timeout = (os.getenv("LLDB_%s_TIMEOUT" % timeout_name) or
296 getDefaultTimeout(dotest_options.lldb_platform_name))
Vince Harron17f429f2014-12-13 00:08:19 +0000297
Todd Fiala8cbeed32015-09-08 22:22:33 +0000298 results.append(call_with_timeout(
299 command, timeout, name, inferior_pid_events))
Vince Harron17f429f2014-12-13 00:08:19 +0000300
Zachary Turner4cceca72015-08-14 16:45:32 +0000301 # result = (name, status, passes, failures, unexpected_successes)
302 timed_out = [name for name, status, _, _, _ in results
Chaoren Line80372a2015-08-12 18:02:53 +0000303 if status == eTimedOut]
Zachary Turner4cceca72015-08-14 16:45:32 +0000304 passed = [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 failed = [name for name, status, _, _, _ in results
Chaoren Line80372a2015-08-12 18:02:53 +0000307 if status != ePassed]
Zachary Turner4cceca72015-08-14 16:45:32 +0000308 unexpected_passes = [name for name, _, _, _, unexpected_successes in results
309 if unexpected_successes > 0]
Todd Fialafed95662015-09-03 18:58:44 +0000310
Chaoren Line80372a2015-08-12 18:02:53 +0000311 pass_count = sum([result[2] for result in results])
312 fail_count = sum([result[3] for result in results])
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +0000313
Zachary Turner4cceca72015-08-14 16:45:32 +0000314 return (timed_out, passed, failed, unexpected_passes, pass_count, fail_count)
Steve Puccibefe2b12014-03-07 00:01:11 +0000315
316in_q = None
317out_q = None
318
Chaoren Linb6325d02015-08-12 18:02:54 +0000319
Todd Fiala8cbeed32015-09-08 22:22:33 +0000320def process_dir_worker_multiprocessing(
321 a_output_lock, a_test_counter, a_total_tests, a_test_name_len,
Todd Fiala33896a92015-09-18 21:01:13 +0000322 a_dotest_options, job_queue, result_queue, inferior_pid_events,
323 worker_index_map):
Todd Fiala8cbeed32015-09-08 22:22:33 +0000324 """Worker thread main loop when in multiprocessing mode.
Steve Puccibefe2b12014-03-07 00:01:11 +0000325 Takes one directory specification at a time and works on it."""
Todd Fiala8cbeed32015-09-08 22:22:33 +0000326
327 # Shut off interrupt handling in the child process.
328 signal.signal(signal.SIGINT, signal.SIG_IGN)
Ying Chend93aa102015-09-23 21:53:18 +0000329 if hasattr(signal, 'SIGHUP'):
330 signal.signal(signal.SIGHUP, signal.SIG_IGN)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000331
332 # Setup the global state for the worker process.
333 setup_global_variables(
334 a_output_lock, a_test_counter, a_total_tests, a_test_name_len,
Todd Fiala33896a92015-09-18 21:01:13 +0000335 a_dotest_options, worker_index_map)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000336
337 # Keep grabbing entries from the queue until done.
338 while not job_queue.empty():
339 try:
340 job = job_queue.get(block=False)
Pavel Labath48c6b522015-11-02 20:54:25 +0000341 result = process_dir(job[0], job[1], job[2],
Todd Fiala8cbeed32015-09-08 22:22:33 +0000342 inferior_pid_events)
343 result_queue.put(result)
Zachary Turner814236d2015-10-21 17:48:52 +0000344 except queue.Empty:
Todd Fiala8cbeed32015-09-08 22:22:33 +0000345 # Fine, we're done.
346 pass
Steve Puccibefe2b12014-03-07 00:01:11 +0000347
Chaoren Linb6325d02015-08-12 18:02:54 +0000348
Todd Fiala8cbeed32015-09-08 22:22:33 +0000349def process_dir_worker_multiprocessing_pool(args):
350 return process_dir(*args)
351
352
Todd Fiala68615ce2015-09-15 21:38:04 +0000353def process_dir_worker_threading(job_queue, result_queue, inferior_pid_events):
Todd Fiala8cbeed32015-09-08 22:22:33 +0000354 """Worker thread main loop when in threading mode.
355
356 This one supports the hand-rolled pooling support.
357
358 Takes one directory specification at a time and works on it."""
359
360 # Keep grabbing entries from the queue until done.
361 while not job_queue.empty():
362 try:
363 job = job_queue.get(block=False)
Pavel Labath48c6b522015-11-02 20:54:25 +0000364 result = process_dir(job[0], job[1], job[2],
Todd Fiala8cbeed32015-09-08 22:22:33 +0000365 inferior_pid_events)
366 result_queue.put(result)
Zachary Turner814236d2015-10-21 17:48:52 +0000367 except queue.Empty:
Todd Fiala8cbeed32015-09-08 22:22:33 +0000368 # Fine, we're done.
369 pass
370
371
372def process_dir_worker_threading_pool(args):
373 return process_dir(*args)
374
375
376def process_dir_mapper_inprocess(args):
377 """Map adapter for running the subprocess-based, non-threaded test runner.
378
379 @param args the process work item tuple
380 @return the test result tuple
381 """
382 return process_dir(*args)
383
384
385def collect_active_pids_from_pid_events(event_queue):
386 """
387 Returns the set of what should be active inferior pids based on
388 the event stream.
389
390 @param event_queue a multiprocessing.Queue containing events of the
391 form:
392 ('created', pid)
393 ('destroyed', pid)
394
395 @return set of inferior dotest.py pids activated but never completed.
396 """
397 active_pid_set = set()
398 while not event_queue.empty():
399 pid_event = event_queue.get_nowait()
400 if pid_event[0] == 'created':
401 active_pid_set.add(pid_event[1])
402 elif pid_event[0] == 'destroyed':
403 active_pid_set.remove(pid_event[1])
404 return active_pid_set
405
406
407def kill_all_worker_processes(workers, inferior_pid_events):
408 """
409 Kills all specified worker processes and their process tree.
410
411 @param workers a list of multiprocess.Process worker objects.
412 @param inferior_pid_events a multiprocess.Queue that contains
413 all inferior create and destroy events. Used to construct
414 the list of child pids still outstanding that need to be killed.
415 """
416 for worker in workers:
417 worker.terminate()
418 worker.join()
419
420 # Add all the child test pids created.
421 active_pid_set = collect_active_pids_from_pid_events(
422 inferior_pid_events)
423 for inferior_pid in active_pid_set:
Zachary Turnerff890da2015-10-19 23:45:41 +0000424 print("killing inferior pid {}".format(inferior_pid))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000425 os.kill(inferior_pid, signal.SIGKILL)
426
427
428def kill_all_worker_threads(workers, inferior_pid_events):
429 """
430 Kills all specified worker threads and their process tree.
431
432 @param workers a list of multiprocess.Process worker objects.
433 @param inferior_pid_events a multiprocess.Queue that contains
434 all inferior create and destroy events. Used to construct
435 the list of child pids still outstanding that need to be killed.
436 """
437
438 # Add all the child test pids created.
439 active_pid_set = collect_active_pids_from_pid_events(
440 inferior_pid_events)
441 for inferior_pid in active_pid_set:
Zachary Turnerff890da2015-10-19 23:45:41 +0000442 print("killing inferior pid {}".format(inferior_pid))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000443 os.kill(inferior_pid, signal.SIGKILL)
444
445 # We don't have a way to nuke the threads. However, since we killed
446 # all the inferiors, and we drained the job queue, this will be
447 # good enough. Wait cleanly for each worker thread to wrap up.
448 for worker in workers:
449 worker.join()
450
451
452def find_test_files_in_dir_tree(dir_root, found_func):
453 """Calls found_func for all the test files in the given dir hierarchy.
454
455 @param dir_root the path to the directory to start scanning
456 for test files. All files in this directory and all its children
457 directory trees will be searched.
458
459 @param found_func a callable object that will be passed
460 the parent directory (relative to dir_root) and the list of
461 test files from within that directory.
462 """
463 for root, _, files in os.walk(dir_root, topdown=False):
464 def is_test_filename(test_dir, base_filename):
465 """Returns True if the given filename matches the test name format.
466
467 @param test_dir the directory to check. Should be absolute or
468 relative to current working directory.
469
470 @param base_filename the base name of the filename to check for a
471 dherence to the python test case filename format.
472
473 @return True if name matches the python test case filename format.
474 """
475 # Not interested in symbolically linked files.
476 if os.path.islink(os.path.join(test_dir, base_filename)):
477 return False
478 # Only interested in test files with the "Test*.py" naming pattern.
479 return (base_filename.startswith("Test") and
480 base_filename.endswith(".py"))
481
482 tests = [filename for filename in files
483 if is_test_filename(root, filename)]
484 if tests:
485 found_func(root, tests)
486
487
488def initialize_global_vars_common(num_threads, test_work_items):
489 global total_tests, test_counter, test_name_len
Greg Clayton1827fc22015-09-19 00:39:09 +0000490
Todd Fiala8cbeed32015-09-08 22:22:33 +0000491 total_tests = sum([len(item[1]) for item in test_work_items])
492 test_counter = multiprocessing.Value('i', 0)
493 test_name_len = multiprocessing.Value('i', 0)
Greg Clayton1827fc22015-09-19 00:39:09 +0000494 if not (RESULTS_FORMATTER and RESULTS_FORMATTER.is_using_terminal()):
Zachary Turnerff890da2015-10-19 23:45:41 +0000495 print("Testing: %d test suites, %d thread%s" % (
496 total_tests, num_threads, (num_threads > 1) * "s"), file=sys.stderr)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000497 update_progress()
498
499
500def initialize_global_vars_multiprocessing(num_threads, test_work_items):
501 # Initialize the global state we'll use to communicate with the
502 # rest of the flat module.
503 global output_lock
504 output_lock = multiprocessing.RLock()
Todd Fiala33896a92015-09-18 21:01:13 +0000505
Todd Fiala8cbeed32015-09-08 22:22:33 +0000506 initialize_global_vars_common(num_threads, test_work_items)
507
508
509def initialize_global_vars_threading(num_threads, test_work_items):
Todd Fiala33896a92015-09-18 21:01:13 +0000510 """Initializes global variables used in threading mode.
511 @param num_threads specifies the number of workers used.
512 @param test_work_items specifies all the work items
513 that will be processed.
514 """
Todd Fiala8cbeed32015-09-08 22:22:33 +0000515 # Initialize the global state we'll use to communicate with the
516 # rest of the flat module.
517 global output_lock
518 output_lock = threading.RLock()
Todd Fiala33896a92015-09-18 21:01:13 +0000519
520 index_lock = threading.RLock()
521 index_map = {}
522
523 def get_worker_index_threading():
524 """Returns a 0-based, thread-unique index for the worker thread."""
525 thread_id = threading.current_thread().ident
526 with index_lock:
527 if thread_id not in index_map:
528 index_map[thread_id] = len(index_map)
529 return index_map[thread_id]
530
531
532 global GET_WORKER_INDEX
533 GET_WORKER_INDEX = get_worker_index_threading
534
Todd Fiala8cbeed32015-09-08 22:22:33 +0000535 initialize_global_vars_common(num_threads, test_work_items)
536
537
Todd Fiala68615ce2015-09-15 21:38:04 +0000538def ctrl_c_loop(main_op_func, done_func, ctrl_c_handler):
539 """Provides a main loop that is Ctrl-C protected.
540
541 The main loop calls the main_op_func() repeatedly until done_func()
542 returns true. The ctrl_c_handler() method is called with a single
543 int parameter that contains the number of times the ctrl_c has been
544 hit (starting with 1). The ctrl_c_handler() should mutate whatever
545 it needs to have the done_func() return True as soon as it is desired
546 to exit the loop.
547 """
548 done = False
549 ctrl_c_count = 0
550
551 while not done:
552 try:
553 # See if we're done. Start with done check since it is
554 # the first thing executed after a Ctrl-C handler in the
555 # following loop.
556 done = done_func()
557 if not done:
558 # Run the main op once.
559 main_op_func()
560
561 except KeyboardInterrupt:
562 ctrl_c_count += 1
563 ctrl_c_handler(ctrl_c_count)
564
565
566def pump_workers_and_asyncore_map(workers, asyncore_map):
567 """Prunes out completed workers and maintains the asyncore loop.
568
569 The asyncore loop contains the optional socket listener
570 and handlers. When all workers are complete, this method
571 takes care of stopping the listener. It also runs the
572 asyncore loop for the given async map for 10 iterations.
573
574 @param workers the list of worker Thread/Process instances.
575
576 @param asyncore_map the asyncore threading-aware map that
577 indicates which channels are in use and still alive.
578 """
579
580 # Check on all the workers, removing them from the workers
581 # list as they complete.
582 dead_workers = []
583 for worker in workers:
584 # This non-blocking join call is what allows us
585 # to still receive keyboard interrupts.
586 worker.join(0.01)
587 if not worker.is_alive():
588 dead_workers.append(worker)
589 # Clear out the completed workers
590 for dead_worker in dead_workers:
591 workers.remove(dead_worker)
592
593 # If there are no more workers and there is a listener,
594 # close the listener.
595 global RESULTS_LISTENER_CHANNEL
596 if len(workers) == 0 and RESULTS_LISTENER_CHANNEL is not None:
597 RESULTS_LISTENER_CHANNEL.close()
598 RESULTS_LISTENER_CHANNEL = None
599
600 # Pump the asyncore map if it isn't empty.
601 if len(asyncore_map) > 0:
602 asyncore.loop(0.1, False, asyncore_map, 10)
603
604
605def handle_ctrl_c(ctrl_c_count, job_queue, workers, inferior_pid_events,
606 stop_all_inferiors_func):
607 """Performs the appropriate ctrl-c action for non-pool parallel test runners
608
609 @param ctrl_c_count starting with 1, indicates the number of times ctrl-c
610 has been intercepted. The value is 1 on the first intercept, 2 on the
611 second, etc.
612
613 @param job_queue a Queue object that contains the work still outstanding
614 (i.e. hasn't been assigned to a worker yet).
615
616 @param workers list of Thread or Process workers.
617
618 @param inferior_pid_events specifies a Queue of inferior process
619 construction and destruction events. Used to build the list of inferior
620 processes that should be killed if we get that far.
621
622 @param stop_all_inferiors_func a callable object that takes the
623 workers and inferior_pid_events parameters (in that order) if a hard
624 stop is to be used on the workers.
625 """
626
627 # Print out which Ctrl-C we're handling.
628 key_name = [
629 "first",
630 "second",
631 "third",
632 "many"]
633
634 if ctrl_c_count < len(key_name):
635 name_index = ctrl_c_count - 1
636 else:
637 name_index = len(key_name) - 1
638 message = "\nHandling {} KeyboardInterrupt".format(key_name[name_index])
639 with output_lock:
Zachary Turnerff890da2015-10-19 23:45:41 +0000640 print(message)
Todd Fiala68615ce2015-09-15 21:38:04 +0000641
642 if ctrl_c_count == 1:
643 # Remove all outstanding items from the work queue so we stop
644 # doing any more new work.
645 while not job_queue.empty():
646 try:
647 # Just drain it to stop more work from being started.
648 job_queue.get_nowait()
Zachary Turner814236d2015-10-21 17:48:52 +0000649 except queue.Empty:
Todd Fiala68615ce2015-09-15 21:38:04 +0000650 pass
651 with output_lock:
Zachary Turnerff890da2015-10-19 23:45:41 +0000652 print("Stopped more work from being started.")
Todd Fiala68615ce2015-09-15 21:38:04 +0000653 elif ctrl_c_count == 2:
654 # Try to stop all inferiors, even the ones currently doing work.
655 stop_all_inferiors_func(workers, inferior_pid_events)
656 else:
657 with output_lock:
Zachary Turnerff890da2015-10-19 23:45:41 +0000658 print("All teardown activities kicked off, should finish soon.")
Todd Fiala68615ce2015-09-15 21:38:04 +0000659
660
661def workers_and_async_done(workers, async_map):
662 """Returns True if the workers list and asyncore channels are all done.
663
664 @param workers list of workers (threads/processes). These must adhere
665 to the threading Thread or multiprocessing.Process interface.
666
667 @param async_map the threading-aware asyncore channel map to check
668 for live channels.
669
670 @return False if the workers list exists and has any entries in it, or
671 if the async_map exists and has any entries left in it; otherwise, True.
672 """
673 if workers is not None and len(workers) > 0:
674 # We're not done if we still have workers left.
675 return False
676 if async_map is not None and len(async_map) > 0:
677 return False
678 # We're done.
679 return True
680
681
Todd Fiala8cbeed32015-09-08 22:22:33 +0000682def multiprocessing_test_runner(num_threads, test_work_items):
683 """Provides hand-wrapped pooling test runner adapter with Ctrl-C support.
684
685 This concurrent test runner is based on the multiprocessing
686 library, and rolls its own worker pooling strategy so it
687 can handle Ctrl-C properly.
688
689 This test runner is known to have an issue running on
690 Windows platforms.
691
692 @param num_threads the number of worker processes to use.
693
694 @param test_work_items the iterable of test work item tuples
695 to run.
696 """
697
698 # Initialize our global state.
699 initialize_global_vars_multiprocessing(num_threads, test_work_items)
700
701 # Create jobs.
702 job_queue = multiprocessing.Queue(len(test_work_items))
703 for test_work_item in test_work_items:
704 job_queue.put(test_work_item)
705
706 result_queue = multiprocessing.Queue(len(test_work_items))
707
708 # Create queues for started child pids. Terminating
709 # the multiprocess processes does not terminate the
710 # child processes they spawn. We can remove this tracking
711 # if/when we move to having the multiprocess process directly
712 # perform the test logic. The Queue size needs to be able to
713 # hold 2 * (num inferior dotest.py processes started) entries.
714 inferior_pid_events = multiprocessing.Queue(4096)
715
Todd Fiala33896a92015-09-18 21:01:13 +0000716 # Worker dictionary allows each worker to figure out its worker index.
717 manager = multiprocessing.Manager()
718 worker_index_map = manager.dict()
719
Todd Fiala8cbeed32015-09-08 22:22:33 +0000720 # Create workers. We don't use multiprocessing.Pool due to
721 # challenges with handling ^C keyboard interrupts.
722 workers = []
723 for _ in range(num_threads):
724 worker = multiprocessing.Process(
725 target=process_dir_worker_multiprocessing,
726 args=(output_lock,
727 test_counter,
728 total_tests,
729 test_name_len,
730 dotest_options,
731 job_queue,
732 result_queue,
Todd Fiala33896a92015-09-18 21:01:13 +0000733 inferior_pid_events,
734 worker_index_map))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000735 worker.start()
736 workers.append(worker)
737
Todd Fiala68615ce2015-09-15 21:38:04 +0000738 # Main loop: wait for all workers to finish and wait for
739 # the socket handlers to wrap up.
740 ctrl_c_loop(
741 # Main operation of loop
742 lambda: pump_workers_and_asyncore_map(
743 workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000744
Todd Fiala68615ce2015-09-15 21:38:04 +0000745 # Return True when we're done with the main loop.
746 lambda: workers_and_async_done(workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000747
Todd Fiala68615ce2015-09-15 21:38:04 +0000748 # Indicate what we do when we receive one or more Ctrl-Cs.
749 lambda ctrl_c_count: handle_ctrl_c(
750 ctrl_c_count, job_queue, workers, inferior_pid_events,
751 kill_all_worker_processes))
752
753 # Reap the test results.
Todd Fiala8cbeed32015-09-08 22:22:33 +0000754 test_results = []
755 while not result_queue.empty():
756 test_results.append(result_queue.get(block=False))
757 return test_results
758
759
Todd Fiala68615ce2015-09-15 21:38:04 +0000760def map_async_run_loop(future, channel_map, listener_channel):
761 """Blocks until the Pool.map_async completes and the channel completes.
762
763 @param future an AsyncResult instance from a Pool.map_async() call.
764
765 @param channel_map the asyncore dispatch channel map that should be pumped.
766 Optional: may be None.
767
768 @param listener_channel the channel representing a listener that should be
769 closed once the map_async results are available.
770
771 @return the results from the async_result instance.
772 """
773 map_results = None
774
775 done = False
776 while not done:
777 # Check if we need to reap the map results.
778 if map_results is None:
779 if future.ready():
780 # Get the results.
781 map_results = future.get()
782
783 # Close the runner process listener channel if we have
784 # one: no more connections will be incoming.
785 if listener_channel is not None:
786 listener_channel.close()
787
788 # Pump the asyncore loop if we have a listener socket.
789 if channel_map is not None:
790 asyncore.loop(0.01, False, channel_map, 10)
791
792 # Figure out if we're done running.
793 done = map_results is not None
794 if channel_map is not None:
795 # We have a runner process async map. Check if it
796 # is complete.
797 if len(channel_map) > 0:
798 # We still have an asyncore channel running. Not done yet.
799 done = False
800
801 return map_results
802
803
Todd Fiala8cbeed32015-09-08 22:22:33 +0000804def multiprocessing_test_runner_pool(num_threads, test_work_items):
805 # Initialize our global state.
806 initialize_global_vars_multiprocessing(num_threads, test_work_items)
807
Todd Fiala33896a92015-09-18 21:01:13 +0000808 manager = multiprocessing.Manager()
809 worker_index_map = manager.dict()
810
Todd Fiala8cbeed32015-09-08 22:22:33 +0000811 pool = multiprocessing.Pool(
812 num_threads,
813 initializer=setup_global_variables,
814 initargs=(output_lock, test_counter, total_tests, test_name_len,
Todd Fiala33896a92015-09-18 21:01:13 +0000815 dotest_options, worker_index_map))
Todd Fiala68615ce2015-09-15 21:38:04 +0000816
817 # Start the map operation (async mode).
818 map_future = pool.map_async(
819 process_dir_worker_multiprocessing_pool, test_work_items)
820 return map_async_run_loop(
821 map_future, RUNNER_PROCESS_ASYNC_MAP, RESULTS_LISTENER_CHANNEL)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000822
823
824def threading_test_runner(num_threads, test_work_items):
825 """Provides hand-wrapped pooling threading-based test runner adapter
826 with Ctrl-C support.
827
828 This concurrent test runner is based on the threading
829 library, and rolls its own worker pooling strategy so it
830 can handle Ctrl-C properly.
831
832 @param num_threads the number of worker processes to use.
833
834 @param test_work_items the iterable of test work item tuples
835 to run.
836 """
837
838 # Initialize our global state.
839 initialize_global_vars_threading(num_threads, test_work_items)
840
841 # Create jobs.
Zachary Turner814236d2015-10-21 17:48:52 +0000842 job_queue = queue.Queue()
Todd Fiala8cbeed32015-09-08 22:22:33 +0000843 for test_work_item in test_work_items:
844 job_queue.put(test_work_item)
845
Zachary Turner814236d2015-10-21 17:48:52 +0000846 result_queue = queue.Queue()
Todd Fiala8cbeed32015-09-08 22:22:33 +0000847
848 # Create queues for started child pids. Terminating
849 # the threading threads does not terminate the
850 # child processes they spawn.
Zachary Turner814236d2015-10-21 17:48:52 +0000851 inferior_pid_events = queue.Queue()
Todd Fiala8cbeed32015-09-08 22:22:33 +0000852
853 # Create workers. We don't use multiprocessing.pool.ThreadedPool
854 # due to challenges with handling ^C keyboard interrupts.
855 workers = []
856 for _ in range(num_threads):
857 worker = threading.Thread(
858 target=process_dir_worker_threading,
Todd Fiala68615ce2015-09-15 21:38:04 +0000859 args=(job_queue,
Todd Fiala8cbeed32015-09-08 22:22:33 +0000860 result_queue,
861 inferior_pid_events))
862 worker.start()
863 workers.append(worker)
864
Todd Fiala68615ce2015-09-15 21:38:04 +0000865 # Main loop: wait for all workers to finish and wait for
866 # the socket handlers to wrap up.
867 ctrl_c_loop(
868 # Main operation of loop
869 lambda: pump_workers_and_asyncore_map(
870 workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000871
Todd Fiala68615ce2015-09-15 21:38:04 +0000872 # Return True when we're done with the main loop.
873 lambda: workers_and_async_done(workers, RUNNER_PROCESS_ASYNC_MAP),
Todd Fiala8cbeed32015-09-08 22:22:33 +0000874
Todd Fiala68615ce2015-09-15 21:38:04 +0000875 # Indicate what we do when we receive one or more Ctrl-Cs.
876 lambda ctrl_c_count: handle_ctrl_c(
877 ctrl_c_count, job_queue, workers, inferior_pid_events,
878 kill_all_worker_threads))
Todd Fiala8cbeed32015-09-08 22:22:33 +0000879
Todd Fiala68615ce2015-09-15 21:38:04 +0000880 # Reap the test results.
Todd Fiala8cbeed32015-09-08 22:22:33 +0000881 test_results = []
882 while not result_queue.empty():
883 test_results.append(result_queue.get(block=False))
884 return test_results
885
886
887def threading_test_runner_pool(num_threads, test_work_items):
888 # Initialize our global state.
889 initialize_global_vars_threading(num_threads, test_work_items)
890
Todd Fiala68615ce2015-09-15 21:38:04 +0000891 pool = multiprocessing.pool.ThreadPool(num_threads)
892 map_future = pool.map_async(
893 process_dir_worker_threading_pool, test_work_items)
894
895 return map_async_run_loop(
896 map_future, RUNNER_PROCESS_ASYNC_MAP, RESULTS_LISTENER_CHANNEL)
897
898
899def asyncore_run_loop(channel_map):
900 try:
901 asyncore.loop(None, False, channel_map)
902 except:
903 # Swallow it, we're seeing:
904 # error: (9, 'Bad file descriptor')
905 # when the listener channel is closed. Shouldn't be the case.
906 pass
Todd Fiala8cbeed32015-09-08 22:22:33 +0000907
908
909def inprocess_exec_test_runner(test_work_items):
910 # Initialize our global state.
911 initialize_global_vars_multiprocessing(1, test_work_items)
Todd Fiala8cbeed32015-09-08 22:22:33 +0000912
Todd Fiala33896a92015-09-18 21:01:13 +0000913 # We're always worker index 0
914 global GET_WORKER_INDEX
915 GET_WORKER_INDEX = lambda: 0
916
Todd Fiala68615ce2015-09-15 21:38:04 +0000917 # Run the listener and related channel maps in a separate thread.
918 # global RUNNER_PROCESS_ASYNC_MAP
919 global RESULTS_LISTENER_CHANNEL
920 if RESULTS_LISTENER_CHANNEL is not None:
921 socket_thread = threading.Thread(
922 target=lambda: asyncore_run_loop(RUNNER_PROCESS_ASYNC_MAP))
923 socket_thread.start()
924
925 # Do the work.
Zachary Turner1c4059a2015-10-22 20:39:59 +0000926 test_results = list(map(process_dir_mapper_inprocess, test_work_items))
Todd Fiala68615ce2015-09-15 21:38:04 +0000927
928 # If we have a listener channel, shut it down here.
929 if RESULTS_LISTENER_CHANNEL is not None:
930 # Close down the channel.
931 RESULTS_LISTENER_CHANNEL.close()
932 RESULTS_LISTENER_CHANNEL = None
933
934 # Wait for the listener and handlers to complete.
935 socket_thread.join()
936
937 return test_results
Todd Fiala8cbeed32015-09-08 22:22:33 +0000938
939def walk_and_invoke(test_directory, test_subdir, dotest_argv,
Todd Fiala871b2e52015-09-22 22:47:34 +0000940 num_workers, test_runner_func):
Steve Puccibefe2b12014-03-07 00:01:11 +0000941 """Look for matched files and invoke test driver on each one.
942 In single-threaded mode, each test driver is invoked directly.
943 In multi-threaded mode, submit each test driver to a worker
Vince Harrone06a7a82015-05-12 23:12:19 +0000944 queue, and then wait for all to complete.
945
946 test_directory - lldb/test/ directory
Chaoren Linb6325d02015-08-12 18:02:54 +0000947 test_subdir - lldb/test/ or a subfolder with the tests we're interested in
948 running
Vince Harrone06a7a82015-05-12 23:12:19 +0000949 """
Todd Fiala68615ce2015-09-15 21:38:04 +0000950 # The async_map is important to keep all thread-related asyncore
951 # channels distinct when we call asyncore.loop() later on.
952 global RESULTS_LISTENER_CHANNEL, RUNNER_PROCESS_ASYNC_MAP
953 RUNNER_PROCESS_ASYNC_MAP = {}
954
955 # If we're outputting side-channel test results, create the socket
956 # listener channel and tell the inferior to send results to the
957 # port on which we'll be listening.
958 if RESULTS_FORMATTER is not None:
Todd Fialae83f1402015-09-18 22:45:31 +0000959 forwarding_func = RESULTS_FORMATTER.handle_event
Todd Fiala68615ce2015-09-15 21:38:04 +0000960 RESULTS_LISTENER_CHANNEL = (
961 dotest_channels.UnpicklingForwardingListenerChannel(
Todd Fiala871b2e52015-09-22 22:47:34 +0000962 RUNNER_PROCESS_ASYNC_MAP, "localhost", 0,
963 2 * num_workers, forwarding_func))
Todd Fiala68615ce2015-09-15 21:38:04 +0000964 dotest_argv.append("--results-port")
965 dotest_argv.append(str(RESULTS_LISTENER_CHANNEL.address[1]))
Todd Fiala3f0a3602014-07-08 06:42:37 +0000966
967 # Collect the test files that we'll run.
968 test_work_items = []
Todd Fiala8cbeed32015-09-08 22:22:33 +0000969 find_test_files_in_dir_tree(
970 test_subdir, lambda testdir, test_files: test_work_items.append([
Zachary Turner7d564542015-11-02 19:19:49 +0000971 test_subdir, test_files, dotest_argv, None]))
Todd Fiala3f0a3602014-07-08 06:42:37 +0000972
Todd Fiala8cbeed32015-09-08 22:22:33 +0000973 # Convert test work items into test results using whatever
974 # was provided as the test run function.
975 test_results = test_runner_func(test_work_items)
Chaoren Linffc63b02015-08-12 18:02:49 +0000976
Todd Fiala8cbeed32015-09-08 22:22:33 +0000977 # Summarize the results and return to caller.
Chaoren Line80372a2015-08-12 18:02:53 +0000978 timed_out = sum([result[0] for result in test_results], [])
979 passed = sum([result[1] for result in test_results], [])
980 failed = sum([result[2] for result in test_results], [])
Zachary Turner4cceca72015-08-14 16:45:32 +0000981 unexpected_successes = sum([result[3] for result in test_results], [])
982 pass_count = sum([result[4] for result in test_results])
983 fail_count = sum([result[5] for result in test_results])
Todd Fiala3f0a3602014-07-08 06:42:37 +0000984
Todd Fiala8cbeed32015-09-08 22:22:33 +0000985 return (timed_out, passed, failed, unexpected_successes, pass_count,
986 fail_count)
Johnny Chene8d9dc62011-10-31 19:04:07 +0000987
Chaoren Linb6325d02015-08-12 18:02:54 +0000988
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000989def getExpectedTimeouts(platform_name):
Vince Harron06381732015-05-12 23:10:36 +0000990 # returns a set of test filenames that might timeout
991 # are we running against a remote target?
Chaoren Linfebef1b2015-08-19 17:22:12 +0000992 host = sys.platform
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000993 if platform_name is None:
Vince Harron06381732015-05-12 23:10:36 +0000994 target = sys.platform
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000995 else:
Todd Fiala68615ce2015-09-15 21:38:04 +0000996 m = re.search(r'remote-(\w+)', platform_name)
Vince Harronf8b9a1d2015-05-18 19:40:54 +0000997 target = m.group(1)
Vince Harron06381732015-05-12 23:10:36 +0000998
999 expected_timeout = set()
1000
1001 if target.startswith("linux"):
1002 expected_timeout |= {
Vince Harron06381732015-05-12 23:10:36 +00001003 "TestConnectRemote.py",
1004 "TestCreateAfterAttach.py",
Tamas Berghammer0d0ec9f2015-05-19 10:49:40 +00001005 "TestEvents.py",
Vince Harron06381732015-05-12 23:10:36 +00001006 "TestExitDuringStep.py",
Chaoren Linb6325d02015-08-12 18:02:54 +00001007
1008 # Times out in ~10% of the times on the build bot
1009 "TestHelloWorld.py",
Oleksiy Vyalov18f4c9f2015-06-10 01:34:25 +00001010 "TestMultithreaded.py",
Chaoren Linb6325d02015-08-12 18:02:54 +00001011 "TestRegisters.py", # ~12/600 dosep runs (build 3120-3122)
Vince Harron06381732015-05-12 23:10:36 +00001012 "TestThreadStepOut.py",
1013 }
1014 elif target.startswith("android"):
1015 expected_timeout |= {
1016 "TestExitDuringStep.py",
1017 "TestHelloWorld.py",
1018 }
Chaoren Linfebef1b2015-08-19 17:22:12 +00001019 if host.startswith("win32"):
1020 expected_timeout |= {
1021 "TestEvents.py",
1022 "TestThreadStates.py",
1023 }
Ed Maste4dd8fba2015-05-14 16:25:52 +00001024 elif target.startswith("freebsd"):
1025 expected_timeout |= {
1026 "TestBreakpointConditions.py",
Ed Maste08948132015-05-28 18:45:30 +00001027 "TestChangeProcessGroup.py",
Ed Mastebfd05632015-05-27 19:11:29 +00001028 "TestValueObjectRecursion.py",
Ed Maste4dd8fba2015-05-14 16:25:52 +00001029 "TestWatchpointConditionAPI.py",
1030 }
Vince Harron0f173ac2015-05-18 19:36:33 +00001031 elif target.startswith("darwin"):
1032 expected_timeout |= {
Chaoren Linb6325d02015-08-12 18:02:54 +00001033 # times out on MBP Retina, Mid 2012
1034 "TestThreadSpecificBreakpoint.py",
Chaoren Lind9043712015-08-19 17:13:02 +00001035 "TestExitDuringStep.py",
Chaoren Lin99f25be2015-08-20 01:26:57 +00001036 "TestIntegerTypesExpr.py",
Vince Harron0f173ac2015-05-18 19:36:33 +00001037 }
Vince Harron06381732015-05-12 23:10:36 +00001038 return expected_timeout
1039
Chaoren Linb6325d02015-08-12 18:02:54 +00001040
Pavel Labathfad30cf2015-06-29 14:16:51 +00001041def getDefaultTimeout(platform_name):
1042 if os.getenv("LLDB_TEST_TIMEOUT"):
1043 return os.getenv("LLDB_TEST_TIMEOUT")
1044
1045 if platform_name is None:
1046 platform_name = sys.platform
1047
1048 if platform_name.startswith("remote-"):
1049 return "10m"
Todd Fiala88722f72015-11-11 05:10:07 +00001050 elif platform_name == 'darwin':
1051 # We are consistently needing more time on a few tests.
1052 return "6m"
Pavel Labathfad30cf2015-06-29 14:16:51 +00001053 else:
1054 return "4m"
1055
Chaoren Linb6325d02015-08-12 18:02:54 +00001056
Vince Harron0b9dbb52015-05-21 18:18:52 +00001057def touch(fname, times=None):
Greg Clayton8c3f9c92015-08-11 21:01:32 +00001058 if os.path.exists(fname):
Vince Harron0b9dbb52015-05-21 18:18:52 +00001059 os.utime(fname, times)
1060
Chaoren Linb6325d02015-08-12 18:02:54 +00001061
Vince Harrondcc2b9f2015-05-27 04:40:36 +00001062def find(pattern, path):
1063 result = []
1064 for root, dirs, files in os.walk(path):
1065 for name in files:
1066 if fnmatch.fnmatch(name, pattern):
1067 result.append(os.path.join(root, name))
1068 return result
1069
Chaoren Linb6325d02015-08-12 18:02:54 +00001070
Todd Fiala8cbeed32015-09-08 22:22:33 +00001071def get_test_runner_strategies(num_threads):
1072 """Returns the test runner strategies by name in a dictionary.
1073
1074 @param num_threads specifies the number of threads/processes
1075 that will be used for concurrent test runners.
1076
1077 @return dictionary with key as test runner strategy name and
1078 value set to a callable object that takes the test work item
1079 and returns a test result tuple.
1080 """
1081 return {
1082 # multiprocessing supports ctrl-c and does not use
1083 # multiprocessing.Pool.
1084 "multiprocessing":
1085 (lambda work_items: multiprocessing_test_runner(
1086 num_threads, work_items)),
1087
1088 # multiprocessing-pool uses multiprocessing.Pool but
1089 # does not support Ctrl-C.
1090 "multiprocessing-pool":
1091 (lambda work_items: multiprocessing_test_runner_pool(
1092 num_threads, work_items)),
1093
1094 # threading uses a hand-rolled worker pool much
1095 # like multiprocessing, but instead uses in-process
1096 # worker threads. This one supports Ctrl-C.
1097 "threading":
1098 (lambda work_items: threading_test_runner(num_threads, work_items)),
1099
1100 # threading-pool uses threading for the workers (in-process)
1101 # and uses the multiprocessing.pool thread-enabled pool.
Todd Fiala68615ce2015-09-15 21:38:04 +00001102 # This does not properly support Ctrl-C.
Todd Fiala8cbeed32015-09-08 22:22:33 +00001103 "threading-pool":
1104 (lambda work_items: threading_test_runner_pool(
1105 num_threads, work_items)),
1106
1107 # serial uses the subprocess-based, single process
1108 # test runner. This provides process isolation but
Todd Fiala68615ce2015-09-15 21:38:04 +00001109 # no concurrent test execution.
Todd Fiala8cbeed32015-09-08 22:22:33 +00001110 "serial":
1111 inprocess_exec_test_runner
1112 }
1113
1114
Todd Fialaea736242015-09-23 15:21:28 +00001115def _remove_option(
1116 args, long_option_name, short_option_name, takes_arg):
Todd Fiala68615ce2015-09-15 21:38:04 +00001117 """Removes option and related option arguments from args array.
Todd Fialaea736242015-09-23 15:21:28 +00001118
1119 This method removes all short/long options that match the given
1120 arguments.
1121
Todd Fiala68615ce2015-09-15 21:38:04 +00001122 @param args the array of command line arguments (in/out)
Todd Fialaea736242015-09-23 15:21:28 +00001123
1124 @param long_option_name the full command line representation of the
1125 long-form option that will be removed (including '--').
1126
1127 @param short_option_name the short version of the command line option
1128 that will be removed (including '-').
1129
1130 @param takes_arg True if the option takes an argument.
1131
Todd Fiala68615ce2015-09-15 21:38:04 +00001132 """
Todd Fialaea736242015-09-23 15:21:28 +00001133 if long_option_name is not None:
1134 regex_string = "^" + long_option_name + "="
1135 long_regex = re.compile(regex_string)
1136 if short_option_name is not None:
1137 # Short options we only match the -X and assume
1138 # any arg is one command line argument jammed together.
1139 # i.e. -O--abc=1 is a single argument in the args list.
1140 # We don't handle -O --abc=1, as argparse doesn't handle
1141 # it, either.
1142 regex_string = "^" + short_option_name
1143 short_regex = re.compile(regex_string)
1144
1145 def remove_long_internal():
1146 """Removes one matching long option from args.
1147 @returns True if one was found and removed; False otherwise.
1148 """
1149 try:
1150 index = args.index(long_option_name)
1151 # Handle the exact match case.
1152 if takes_arg:
1153 removal_count = 2
1154 else:
1155 removal_count = 1
1156 del args[index:index+removal_count]
1157 return True
1158 except ValueError:
1159 # Thanks to argparse not handling options with known arguments
1160 # like other options parsing libraries (see
1161 # https://bugs.python.org/issue9334), we need to support the
1162 # --results-formatter-options={second-level-arguments} (note
1163 # the equal sign to fool the first-level arguments parser into
1164 # not treating the second-level arguments as first-level
1165 # options). We're certainly at risk of getting this wrong
1166 # since now we're forced into the business of trying to figure
1167 # out what is an argument (although I think this
1168 # implementation will suffice).
1169 for index in range(len(args)):
1170 match = long_regex.search(args[index])
1171 if match:
1172 del args[index]
1173 return True
1174 return False
1175
1176 def remove_short_internal():
1177 """Removes one matching short option from args.
1178 @returns True if one was found and removed; False otherwise.
1179 """
Todd Fiala68615ce2015-09-15 21:38:04 +00001180 for index in range(len(args)):
Todd Fialaea736242015-09-23 15:21:28 +00001181 match = short_regex.search(args[index])
Todd Fiala68615ce2015-09-15 21:38:04 +00001182 if match:
Todd Fiala68615ce2015-09-15 21:38:04 +00001183 del args[index]
Todd Fialaea736242015-09-23 15:21:28 +00001184 return True
1185 return False
Todd Fiala68615ce2015-09-15 21:38:04 +00001186
Todd Fialaea736242015-09-23 15:21:28 +00001187 removal_count = 0
1188 while long_option_name is not None and remove_long_internal():
1189 removal_count += 1
1190 while short_option_name is not None and remove_short_internal():
1191 removal_count += 1
1192 if removal_count == 0:
1193 raise Exception(
1194 "failed to find at least one of '{}', '{}' in options".format(
1195 long_option_name, short_option_name))
Todd Fiala68615ce2015-09-15 21:38:04 +00001196
1197
1198def adjust_inferior_options(dotest_argv):
1199 """Adjusts the commandline args array for inferiors.
1200
1201 This method adjusts the inferior dotest commandline options based
1202 on the parallel test runner's options. Some of the inferior options
1203 will need to change to properly handle aggregation functionality.
1204 """
1205 global dotest_options
1206
1207 # If we don't have a session directory, create one.
1208 if not dotest_options.s:
1209 # no session log directory, we need to add this to prevent
1210 # every dotest invocation from creating its own directory
1211 import datetime
1212 # The windows platforms don't like ':' in the pathname.
Zachary Turneraf383ff2015-10-27 22:33:47 +00001213 timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
Todd Fiala68615ce2015-09-15 21:38:04 +00001214 dotest_argv.append('-s')
1215 dotest_argv.append(timestamp_started)
1216 dotest_options.s = timestamp_started
1217
1218 # Adjust inferior results formatter options - if the parallel
1219 # test runner is collecting into the user-specified test results,
1220 # we'll have inferiors spawn with the --results-port option and
1221 # strip the original test runner options.
1222 if dotest_options.results_file is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001223 _remove_option(dotest_argv, "--results-file", None, True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001224 if dotest_options.results_port is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001225 _remove_option(dotest_argv, "--results-port", None, True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001226 if dotest_options.results_formatter is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001227 _remove_option(dotest_argv, "--results-formatter", None, True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001228 if dotest_options.results_formatter_options is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001229 _remove_option(dotest_argv, "--results-formatter-option", "-O",
1230 True)
Todd Fiala68615ce2015-09-15 21:38:04 +00001231
Todd Fialacee6a6a2015-11-09 18:51:04 +00001232 # Remove the --curses shortcut if specified.
1233 if dotest_options.curses:
1234 _remove_option(dotest_argv, "--curses", None, False)
1235
Todd Fiala33896a92015-09-18 21:01:13 +00001236 # Remove test runner name if present.
1237 if dotest_options.test_runner_name is not None:
Todd Fialaea736242015-09-23 15:21:28 +00001238 _remove_option(dotest_argv, "--test-runner-name", None, True)
Todd Fiala33896a92015-09-18 21:01:13 +00001239
1240
Todd Fiala83c32e32015-09-22 21:19:40 +00001241def is_darwin_version_lower_than(target_version):
1242 """Checks that os is Darwin and version is lower than target_version.
1243
1244 @param target_version the StrictVersion indicating the version
1245 we're checking against.
1246
1247 @return True if the OS is Darwin (OS X) and the version number of
1248 the OS is less than target_version; False in all other cases.
1249 """
1250 if platform.system() != 'Darwin':
1251 # Can't be Darwin lower than a certain version.
1252 return False
1253
1254 system_version = distutils.version.StrictVersion(platform.mac_ver()[0])
Zachary Turnerbac6e4f2015-11-03 21:37:27 +00001255 return seven.cmp_(system_version, target_version) < 0
Todd Fiala83c32e32015-09-22 21:19:40 +00001256
1257
1258def default_test_runner_name(num_threads):
1259 """Returns the default test runner name for the configuration.
1260
1261 @param num_threads the number of threads/workers this test runner is
1262 supposed to use.
1263
1264 @return the test runner name that should be used by default when
1265 no test runner was explicitly called out on the command line.
1266 """
1267 if num_threads == 1:
1268 # Use the serial runner.
1269 test_runner_name = "serial"
1270 elif os.name == "nt":
Adrian McCarthy040b31d2015-10-12 14:46:57 +00001271 # On Windows, Python uses CRT with a low limit on the number of open
1272 # files. If you have a lot of cores, the threading-pool runner will
Zachary Turnerf0c3f682015-11-06 18:14:31 +00001273 # often fail because it exceeds that limit. It's not clear what the
1274 # right balance is, so until we can investigate it more deeply,
1275 # just use the one that works
1276 test_runner_name = "multiprocessing-pool"
Todd Fiala83c32e32015-09-22 21:19:40 +00001277 elif is_darwin_version_lower_than(
1278 distutils.version.StrictVersion("10.10.0")):
1279 # OS X versions before 10.10 appear to have an issue using
1280 # the threading test runner. Fall back to multiprocessing.
1281 # Supports Ctrl-C.
1282 test_runner_name = "multiprocessing"
1283 else:
1284 # For everyone else, use the ctrl-c-enabled threading support.
1285 # Should use fewer system resources than the multprocessing
1286 # variant.
1287 test_runner_name = "threading"
1288 return test_runner_name
1289
1290
Todd Fiala8cbeed32015-09-08 22:22:33 +00001291def main(print_details_on_success, num_threads, test_subdir,
Todd Fiala68615ce2015-09-15 21:38:04 +00001292 test_runner_name, results_formatter):
Todd Fialafed95662015-09-03 18:58:44 +00001293 """Run dotest.py in inferior mode in parallel.
1294
1295 @param print_details_on_success the parsed value of the output-on-success
1296 command line argument. When True, details of a successful dotest inferior
1297 are printed even when everything succeeds. The normal behavior is to
1298 not print any details when all the inferior tests pass.
1299
1300 @param num_threads the parsed value of the num-threads command line
1301 argument.
1302
1303 @param test_subdir optionally specifies a subdir to limit testing
1304 within. May be None if the entire test tree is to be used. This subdir
1305 is assumed to be relative to the lldb/test root of the test hierarchy.
Todd Fiala8cbeed32015-09-08 22:22:33 +00001306
1307 @param test_runner_name if specified, contains the test runner
1308 name which selects the strategy used to run the isolated and
1309 optionally concurrent test runner. Specify None to allow the
1310 system to choose the most appropriate test runner given desired
1311 thread count and OS type.
1312
Todd Fiala68615ce2015-09-15 21:38:04 +00001313 @param results_formatter if specified, provides the TestResultsFormatter
1314 instance that will format and output test result data from the
1315 side-channel test results. When specified, inferior dotest calls
1316 will send test results side-channel data over a socket to the parallel
1317 test runner, which will forward them on to results_formatter.
Todd Fialafed95662015-09-03 18:58:44 +00001318 """
1319
Todd Fiala1cc97b42015-09-21 05:42:26 +00001320 # Do not shut down on sighup.
Ying Chend93aa102015-09-23 21:53:18 +00001321 if hasattr(signal, 'SIGHUP'):
1322 signal.signal(signal.SIGHUP, signal.SIG_IGN)
Todd Fiala1cc97b42015-09-21 05:42:26 +00001323
Todd Fialafed95662015-09-03 18:58:44 +00001324 dotest_argv = sys.argv[1:]
1325
Greg Claytonb0d148e2015-09-21 17:25:01 +00001326 global output_on_success, RESULTS_FORMATTER
Todd Fialafed95662015-09-03 18:58:44 +00001327 output_on_success = print_details_on_success
Todd Fiala68615ce2015-09-15 21:38:04 +00001328 RESULTS_FORMATTER = results_formatter
Todd Fialafed95662015-09-03 18:58:44 +00001329
Vince Harrond5fa1022015-05-10 15:24:12 +00001330 # We can't use sys.path[0] to determine the script directory
1331 # because it doesn't work under a debugger
Vince Harron8994fed2015-05-22 19:49:23 +00001332 parser = dotest_args.create_parser()
Pavel Labath05ab2372015-07-06 15:57:52 +00001333 global dotest_options
Vince Harron8994fed2015-05-22 19:49:23 +00001334 dotest_options = dotest_args.parse_args(parser, dotest_argv)
1335
Todd Fiala68615ce2015-09-15 21:38:04 +00001336 adjust_inferior_options(dotest_argv)
Vince Harron0b9dbb52015-05-21 18:18:52 +00001337
1338 session_dir = os.path.join(os.getcwd(), dotest_options.s)
Ed Mastecec2a5b2014-11-21 02:41:25 +00001339
Vince Harrone06a7a82015-05-12 23:12:19 +00001340 # The root directory was specified on the command line
Todd Fiala68615ce2015-09-15 21:38:04 +00001341 test_directory = os.path.dirname(os.path.realpath(__file__))
Todd Fialafed95662015-09-03 18:58:44 +00001342 if test_subdir and len(test_subdir) > 0:
1343 test_subdir = os.path.join(test_directory, test_subdir)
Vince Harrone06a7a82015-05-12 23:12:19 +00001344 else:
Todd Fialafed95662015-09-03 18:58:44 +00001345 test_subdir = test_directory
Vince Harrone06a7a82015-05-12 23:12:19 +00001346
Vince Harrondcc2b9f2015-05-27 04:40:36 +00001347 # clean core files in test tree from previous runs (Linux)
1348 cores = find('core.*', test_subdir)
1349 for core in cores:
1350 os.unlink(core)
1351
Daniel Maleab42556f2013-04-19 18:32:53 +00001352 system_info = " ".join(platform.uname())
Todd Fiala8cbeed32015-09-08 22:22:33 +00001353
1354 # Figure out which testrunner strategy we'll use.
1355 runner_strategies_by_name = get_test_runner_strategies(num_threads)
1356
1357 # If the user didn't specify a test runner strategy, determine
1358 # the default now based on number of threads and OS type.
1359 if not test_runner_name:
Todd Fiala83c32e32015-09-22 21:19:40 +00001360 test_runner_name = default_test_runner_name(num_threads)
Todd Fiala8cbeed32015-09-08 22:22:33 +00001361
1362 if test_runner_name not in runner_strategies_by_name:
Todd Fiala83c32e32015-09-22 21:19:40 +00001363 raise Exception(
1364 "specified testrunner name '{}' unknown. Valid choices: {}".format(
1365 test_runner_name,
Zachary Turner606e1e32015-10-23 17:53:51 +00001366 list(runner_strategies_by_name.keys())))
Todd Fiala8cbeed32015-09-08 22:22:33 +00001367 test_runner_func = runner_strategies_by_name[test_runner_name]
1368
1369 summary_results = walk_and_invoke(
Todd Fiala871b2e52015-09-22 22:47:34 +00001370 test_directory, test_subdir, dotest_argv,
1371 num_threads, test_runner_func)
Todd Fiala8cbeed32015-09-08 22:22:33 +00001372
1373 (timed_out, passed, failed, unexpected_successes, pass_count,
1374 fail_count) = summary_results
Zachary Turnerc7a7c8a2015-05-28 19:56:26 +00001375
Todd Fialade9a44e2015-09-22 00:15:50 +00001376 # The results formatter - if present - is done now. Tell it to
1377 # terminate.
1378 if results_formatter is not None:
1379 results_formatter.send_terminate_as_needed()
1380
Vince Harron17f429f2014-12-13 00:08:19 +00001381 timed_out = set(timed_out)
Chaoren Line80372a2015-08-12 18:02:53 +00001382 num_test_files = len(passed) + len(failed)
1383 num_test_cases = pass_count + fail_count
Daniel Maleab42556f2013-04-19 18:32:53 +00001384
Vince Harrondcc2b9f2015-05-27 04:40:36 +00001385 # move core files into session dir
1386 cores = find('core.*', test_subdir)
1387 for core in cores:
1388 dst = core.replace(test_directory, "")[1:]
1389 dst = dst.replace(os.path.sep, "-")
1390 os.rename(core, os.path.join(session_dir, dst))
1391
Vince Harron06381732015-05-12 23:10:36 +00001392 # remove expected timeouts from failures
Vince Harronf8b9a1d2015-05-18 19:40:54 +00001393 expected_timeout = getExpectedTimeouts(dotest_options.lldb_platform_name)
Vince Harron06381732015-05-12 23:10:36 +00001394 for xtime in expected_timeout:
1395 if xtime in timed_out:
1396 timed_out.remove(xtime)
1397 failed.remove(xtime)
Vince Harron0b9dbb52015-05-21 18:18:52 +00001398 result = "ExpectedTimeout"
1399 elif xtime in passed:
1400 result = "UnexpectedCompletion"
1401 else:
1402 result = None # failed
1403
1404 if result:
1405 test_name = os.path.splitext(xtime)[0]
1406 touch(os.path.join(session_dir, "{}-{}".format(result, test_name)))
Vince Harron06381732015-05-12 23:10:36 +00001407
Todd Fiala46a4e342015-12-02 18:48:38 +00001408 # Only run the old summary logic if we don't have a results formatter
1409 # that already prints the summary.
1410 if results_formatter is None or not results_formatter.replaces_summary():
1411 print_legacy_summary = True
1412 else:
1413 print_legacy_summary = False
Zachary Turner4cceca72015-08-14 16:45:32 +00001414
Todd Fiala46a4e342015-12-02 18:48:38 +00001415 if not print_legacy_summary:
1416 # Remove this timeout handling once
1417 # https://llvm.org/bugs/show_bug.cgi?id=25703
1418 # is addressed.
1419 #
1420 # Use non-event-based structures to count timeouts.
1421 timeout_count = len(timed_out)
1422 if timeout_count > 0:
1423 failed.sort()
1424 print("Timed out test files: {}".format(len(timed_out)))
1425 for f in failed:
1426 if f in timed_out:
1427 print("TIMEOUT: %s (%s)" % (f, system_info))
Zachary Turner4cceca72015-08-14 16:45:32 +00001428
Todd Fiala46a4e342015-12-02 18:48:38 +00001429 # Figure out exit code by count of test result types.
1430 issue_count = (
1431 results_formatter.counts_by_test_result_status(
Zachary Turner905a9882015-12-07 21:23:41 +00001432 result_formatter.EventBuilder.STATUS_ERROR) +
Todd Fiala46a4e342015-12-02 18:48:38 +00001433 results_formatter.counts_by_test_result_status(
Zachary Turner905a9882015-12-07 21:23:41 +00001434 result_formatter.EventBuilder.STATUS_FAILURE) +
Todd Fiala46a4e342015-12-02 18:48:38 +00001435 timeout_count)
1436 # Return with appropriate result code
1437 if issue_count > 0:
1438 sys.exit(1)
1439 else:
1440 sys.exit(0)
1441 else:
1442 # Print the legacy test results summary.
1443 print()
1444 sys.stdout.write("Ran %d test suites" % num_test_files)
1445 if num_test_files > 0:
1446 sys.stdout.write(" (%d failed) (%f%%)" % (
1447 len(failed), 100.0 * len(failed) / num_test_files))
1448 print()
1449 sys.stdout.write("Ran %d test cases" % num_test_cases)
1450 if num_test_cases > 0:
1451 sys.stdout.write(" (%d failed) (%f%%)" % (
1452 fail_count, 100.0 * fail_count / num_test_cases))
1453 print()
1454 exit_code = 0
1455
1456 if len(failed) > 0:
1457 failed.sort()
1458 print("Failing Tests (%d)" % len(failed))
1459 for f in failed:
1460 print("%s: LLDB (suite) :: %s (%s)" % (
1461 "TIMEOUT" if f in timed_out else "FAIL", f, system_info
1462 ))
1463 exit_code = 1
1464
1465 if len(unexpected_successes) > 0:
1466 unexpected_successes.sort()
1467 print("\nUnexpected Successes (%d)" % len(unexpected_successes))
1468 for u in unexpected_successes:
1469 print("UNEXPECTED SUCCESS: LLDB (suite) :: %s (%s)" % (u, system_info))
Zachary Turner4cceca72015-08-14 16:45:32 +00001470
1471 sys.exit(exit_code)
Johnny Chene8d9dc62011-10-31 19:04:07 +00001472
1473if __name__ == '__main__':
Todd Fialafed95662015-09-03 18:58:44 +00001474 sys.stderr.write(
1475 "error: dosep.py no longer supports being called directly. "
1476 "Please call dotest.py directly. The dosep.py-specific arguments "
1477 "have been added under the Parallel processing arguments.\n")
1478 sys.exit(128)