summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2021-04-04 22:56:00 +0200
committerStefan Behnel <stefan_ml@behnel.de>2021-04-14 14:15:10 +0200
commit7c0585e3c560e7ed13e99e95423cdeff4ebcb26d (patch)
tree672d979b760342238a93f2dbdf3f8d02998847aa
parent315c20ef3dd6006df6e61693650d183720798002 (diff)
downloadcython-7c0585e3c560e7ed13e99e95423cdeff4ebcb26d.tar.gz
Summarize test failures when running in shards.
-rwxr-xr-xruntests.py39
1 files changed, 30 insertions, 9 deletions
diff --git a/runtests.py b/runtests.py
index 9e1c05509..f1ea8e87d 100755
--- a/runtests.py
+++ b/runtests.py
@@ -2137,14 +2137,16 @@ def main():
import multiprocessing
pool = multiprocessing.Pool(options.shard_count)
tasks = [(options, cmd_args, shard_num) for shard_num in range(options.shard_count)]
- errors = []
+ error_shards = []
+ failure_outputs = []
# NOTE: create process pool before time stamper thread to avoid forking issues.
total_time = time.time()
stats = Stats()
with time_stamper_thread():
- for shard_num, shard_stats, return_code in pool.imap_unordered(runtests_callback, tasks):
+ for shard_num, shard_stats, return_code, failure_output in pool.imap_unordered(runtests_callback, tasks):
if return_code != 0:
- errors.append(shard_num)
+ error_shards.append(shard_num)
+ failure_outputs.append(failure_output)
sys.stderr.write("FAILED (%s/%s)\n" % (shard_num, options.shard_count))
sys.stderr.write("ALL DONE (%s/%s)\n" % (shard_num, options.shard_count))
stats.update(shard_stats)
@@ -2152,14 +2154,16 @@ def main():
pool.join()
total_time = time.time() - total_time
sys.stderr.write("Sharded tests run in %d seconds (%.1f minutes)\n" % (round(total_time), total_time / 60.))
- if errors:
- sys.stderr.write("Errors for shards %s\n" % ", ".join([str(e) for e in errors]))
+ if error_shards:
+ sys.stderr.write("Errors found in shards %s\n" % ", ".join([str(e) for e in error_shards]))
+ for failure_output in zip(error_shards, failure_outputs):
+ sys.stderr.write("\nErrors from shard %s:\n%s" % failure_output)
return_code = 1
else:
return_code = 0
else:
with time_stamper_thread():
- _, stats, return_code = runtests(options, cmd_args, coverage)
+ _, stats, return_code, _ = runtests(options, cmd_args, coverage)
if coverage:
if options.shard_count > 1 and options.shard_num == -1:
@@ -2504,10 +2508,27 @@ def runtests(options, cmd_args, coverage=None):
import refnanny
sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog]))
- if options.exit_ok:
- return options.shard_num, stats, 0
+ result_code = 0 if options.exit_ok else not result.wasSuccessful()
+
+ if xml_output_dir:
+ failure_output = ""
else:
- return options.shard_num, stats, not result.wasSuccessful()
+ failure_output = "".join(collect_failure_output(result))
+
+ return options.shard_num, stats, result_code, failure_output
+
+
+def collect_failure_output(result):
+ """Extract test error/failure output from a TextTestResult."""
+ failure_output = []
+ for flavour, errors in (("ERROR", result.errors), ("FAIL", result.failures)):
+ for test, err in errors:
+ failure_output.append("%s\n%s: %s\n%s\n%s\n" % (
+ result.separator1,
+ flavour, result.getDescription(test),
+ result.separator2,
+ err))
+ return failure_output
if __name__ == '__main__':