Commit 7c0585e3 authored by Stefan Behnel's avatar Stefan Behnel

Summarize test failures when running in shards.

parent 315c20ef
...@@ -2137,14 +2137,16 @@ def main(): ...@@ -2137,14 +2137,16 @@ def main():
import multiprocessing import multiprocessing
pool = multiprocessing.Pool(options.shard_count) pool = multiprocessing.Pool(options.shard_count)
tasks = [(options, cmd_args, shard_num) for shard_num in range(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. # NOTE: create process pool before time stamper thread to avoid forking issues.
total_time = time.time() total_time = time.time()
stats = Stats() stats = Stats()
with time_stamper_thread(): 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: 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("FAILED (%s/%s)\n" % (shard_num, options.shard_count))
sys.stderr.write("ALL DONE (%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) stats.update(shard_stats)
...@@ -2152,14 +2154,16 @@ def main(): ...@@ -2152,14 +2154,16 @@ def main():
pool.join() pool.join()
total_time = time.time() - total_time total_time = time.time() - total_time
sys.stderr.write("Sharded tests run in %d seconds (%.1f minutes)\n" % (round(total_time), total_time / 60.)) sys.stderr.write("Sharded tests run in %d seconds (%.1f minutes)\n" % (round(total_time), total_time / 60.))
if errors: if error_shards:
sys.stderr.write("Errors for shards %s\n" % ", ".join([str(e) for e in errors])) 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 return_code = 1
else: else:
return_code = 0 return_code = 0
else: else:
with time_stamper_thread(): with time_stamper_thread():
_, stats, return_code = runtests(options, cmd_args, coverage) _, stats, return_code, _ = runtests(options, cmd_args, coverage)
if coverage: if coverage:
if options.shard_count > 1 and options.shard_num == -1: if options.shard_count > 1 and options.shard_num == -1:
...@@ -2504,10 +2508,27 @@ def runtests(options, cmd_args, coverage=None): ...@@ -2504,10 +2508,27 @@ def runtests(options, cmd_args, coverage=None):
import refnanny import refnanny
sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog])) sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog]))
if options.exit_ok: result_code = 0 if options.exit_ok else not result.wasSuccessful()
return options.shard_num, stats, 0
if xml_output_dir:
failure_output = ""
else: 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__': if __name__ == '__main__':
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment