Skip to content

Commit 007bc0b

Browse files
author
Vasileios Karakasis
authored
Merge pull request #1176 from ZQyou/feature/summary-rerun-failures
[feat] Print failure statistics table as well as the run options for failures
2 parents ece0880 + 4f13a7e commit 007bc0b

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

reframe/frontend/cli.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ def main():
231231
misc_options.add_argument(
232232
'--nocolor', action='store_false', dest='colorize', default=True,
233233
help='Disable coloring of output')
234+
misc_options.add_argument(
235+
'--failure-stats', action='store_true',
236+
help='Print failure statistics')
234237
misc_options.add_argument('--performance-report', action='store_true',
235238
help='Print the performance report')
236239
misc_options.add_argument(
@@ -630,6 +633,8 @@ def main():
630633
if runner.stats.failures():
631634
printer.info(runner.stats.failure_report())
632635
success = False
636+
if options.failure_stats:
637+
printer.info(runner.stats.failure_stats())
633638

634639
if options.performance_report:
635640
printer.info(runner.stats.performance_report())

reframe/frontend/statistics.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ def failure_report(self):
9797
report.append(' * Job type: %s (id=%s)' % (job_type, jobid))
9898
report.append(' * Maintainers: %s' % check.maintainers)
9999
report.append(' * Failing phase: %s' % tf.failed_stage)
100+
report.append(" * Rerun with '-n %s -p %s --system %s'" %
101+
(check.name, environ_name, partname))
100102
reason = ' * Reason: '
101103
if tf.exc_info is not None:
102104
from reframe.core.exceptions import format_exception
@@ -115,6 +117,50 @@ def failure_report(self):
115117
report.append(line_width * '-')
116118
return '\n'.join(report)
117119

120+
def failure_stats(self):
121+
failures = {}
122+
current_run = rt.runtime().current_run
123+
for tf in (t for t in self.tasks(current_run) if t.failed):
124+
check = tf.check
125+
partition = check.current_partition
126+
partname = partition.fullname if partition else 'None'
127+
environ_name = (check.current_environ.name
128+
if check.current_environ else 'None')
129+
f = f'[{check.name}, {environ_name}, {partname}]'
130+
if tf.failed_stage not in failures:
131+
failures[tf.failed_stage] = []
132+
133+
failures[tf.failed_stage].append(f)
134+
135+
line_width = 78
136+
stats_start = line_width * '='
137+
stats_title = 'FAILURE STATISTICS'
138+
stats_end = line_width * '-'
139+
stats_body = []
140+
row_format = "{:<11} {:<5} {}"
141+
stats_hline = row_format.format(11*'-', 5*'-', 60*'-')
142+
stats_header = row_format.format('Phase', '#', 'Failing test cases')
143+
num_tests = len(self.tasks(current_run))
144+
num_failures = 0
145+
for l in failures.values():
146+
num_failures += len(l)
147+
148+
stats_body = ['']
149+
stats_body.append('Total number of test cases: %s' % num_tests)
150+
stats_body.append('Total number of failures: %s' % num_failures)
151+
stats_body.append('')
152+
stats_body.append(stats_header)
153+
stats_body.append(stats_hline)
154+
for p, l in failures.items():
155+
stats_body.append(row_format.format(p, len(l), l[0]))
156+
for f in l[1:]:
157+
stats_body.append(row_format.format('', '', str(f)))
158+
159+
if stats_body:
160+
return '\n'.join([stats_start, stats_title, *stats_body,
161+
stats_end])
162+
return ''
163+
118164
def performance_report(self):
119165
line_width = 78
120166
report_start = line_width * '='

unittests/test_cli.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,17 @@ def test_performance_check_failure(self):
228228
self.environs)
229229
assert self._perflog_exists('PerformanceFailureCheck')
230230

231+
def test_failure_stats(self):
232+
self.checkpath = ['unittests/resources/checks/frontend_checks.py']
233+
self.more_options = ['-t', 'SanityFailureCheck', '--failure-stats']
234+
returncode, stdout, stderr = self._run_reframe()
235+
236+
assert r'FAILURE STATISTICS' in stdout
237+
assert r'sanity 1 [SanityFailureCheck' in stdout
238+
assert 'Traceback' not in stdout
239+
assert 'Traceback' not in stderr
240+
assert returncode != 0
241+
231242
def test_performance_report(self):
232243
self.checkpath = ['unittests/resources/checks/frontend_checks.py']
233244
self.more_options = ['-t', 'PerformanceFailureCheck',

0 commit comments

Comments
 (0)