@@ -11,15 +11,14 @@
1111importunittest
1212fromtest.libregrtest.cmdlineimport_parse_args
1313fromtest.libregrtest.runtestimport (
14-findtests, split_test_packages, runtest, get_abs_module, is_failed,
15-PROGRESS_MIN_TIME,
16-Passed, Failed, EnvChanged, Skipped, ResourceDenied, Interrupted,
17-ChildError, DidNotRun)
14+findtests, split_test_packages, runtest, get_abs_module,
15+PROGRESS_MIN_TIME, State)
1816fromtest.libregrtest.setupimportsetup_tests
1917fromtest.libregrtest.pgoimportsetup_pgo_tests
2018fromtest.libregrtest.utilsimport (removepy, count, format_duration,
2119printlist, get_build_info)
2220fromtestimportsupport
21+fromtest.supportimportTestStats
2322fromtest.supportimportos_helper
2423fromtest.supportimportthreading_helper
2524@@ -78,13 +77,14 @@ def __init__(self):
7877self.good= []
7978self.bad= []
8079self.skipped= []
81-self.resource_denieds= []
80+self.resource_denied= []
8281self.environment_changed= []
8382self.run_no_tests= []
8483self.need_rerun= []
8584self.rerun= []
8685self.first_result=None
8786self.interrupted=False
87+self.stats_dict: dict[str, TestStats] = {}
88888989# used by --slow
9090self.test_times= []
@@ -93,7 +93,7 @@ def __init__(self):
9393self.tracer=None
94949595# used to display the progress bar "[ 3/100]"
96-self.start_time=time.monotonic()
96+self.start_time=time.perf_counter()
9797self.test_count=''
9898self.test_count_width=1
9999@@ -111,36 +111,41 @@ def __init__(self):
111111112112defget_executed(self):
113113return (set(self.good) |set(self.bad) |set(self.skipped)
114-|set(self.resource_denieds) |set(self.environment_changed)
114+|set(self.resource_denied) |set(self.environment_changed)
115115|set(self.run_no_tests))
116116117117defaccumulate_result(self, result, rerun=False):
118-test_name=result.name
119-120-ifnotisinstance(result, (ChildError, Interrupted)) andnotrerun:
121-self.test_times.append((result.duration_sec, test_name))
122-123-ifisinstance(result, Passed):
124-self.good.append(test_name)
125-elifisinstance(result, ResourceDenied):
126-self.skipped.append(test_name)
127-self.resource_denieds.append(test_name)
128-elifisinstance(result, Skipped):
129-self.skipped.append(test_name)
130-elifisinstance(result, EnvChanged):
131-self.environment_changed.append(test_name)
132-elifisinstance(result, Failed):
133-ifnotrerun:
134-self.bad.append(test_name)
135-self.need_rerun.append(result)
136-elifisinstance(result, DidNotRun):
137-self.run_no_tests.append(test_name)
138-elifisinstance(result, Interrupted):
139-self.interrupted=True
140-else:
141-raiseValueError("invalid test result: %r"%result)
118+test_name=result.test_name
119+120+ifresult.has_meaningful_duration() andnotrerun:
121+self.test_times.append((result.duration, test_name))
142122143-ifrerunandnotisinstance(result, (Failed, Interrupted)):
123+matchresult.state:
124+caseState.PASSED:
125+self.good.append(test_name)
126+caseState.ENV_CHANGED:
127+self.environment_changed.append(test_name)
128+caseState.SKIPPED:
129+self.skipped.append(test_name)
130+caseState.RESOURCE_DENIED:
131+self.skipped.append(test_name)
132+self.resource_denied.append(test_name)
133+caseState.INTERRUPTED:
134+self.interrupted=True
135+caseState.DID_NOT_RUN:
136+self.run_no_tests.append(test_name)
137+case _:
138+ifresult.is_failed(self.ns.fail_env_changed):
139+ifnotrerun:
140+self.bad.append(test_name)
141+self.need_rerun.append(result)
142+else:
143+raiseValueError(f"invalid test state: {state!r}")
144+145+ifresult.statsisnotNone:
146+self.stats_dict[result.test_name] =result.stats
147+148+ifrerunandnot(result.is_failed(False) orresult.state==State.INTERRUPTED):
144149self.bad.remove(test_name)
145150146151xml_data=result.xml_data
@@ -162,7 +167,7 @@ def log(self, line=''):
162167line=f"load avg: {load_avg:.2f}{line}"
163168164169# add the timestamp prefix: "0:01:05 "
165-test_time=time.monotonic() -self.start_time
170+test_time=time.perf_counter() -self.start_time
166171167172mins, secs=divmod(int(test_time), 60)
168173hours, mins=divmod(mins, 60)
@@ -337,7 +342,7 @@ def rerun_failed_tests(self):
337342rerun_list=list(self.need_rerun)
338343self.need_rerun.clear()
339344forresultinrerun_list:
340-test_name=result.name
345+test_name=result.test_name
341346self.rerun.append(test_name)
342347343348errors=result.errorsor []
@@ -364,7 +369,7 @@ def rerun_failed_tests(self):
364369365370self.accumulate_result(result, rerun=True)
366371367-ifisinstance(result, Interrupted):
372+ifresult.state==State.INTERRUPTED:
368373break
369374370375ifself.bad:
@@ -461,7 +466,7 @@ def run_tests_sequential(self):
461466462467previous_test=None
463468fortest_index, test_nameinenumerate(self.tests, 1):
464-start_time=time.monotonic()
469+start_time=time.perf_counter()
465470466471text=test_name
467472ifprevious_test:
@@ -480,14 +485,14 @@ def run_tests_sequential(self):
480485result=runtest(self.ns, test_name)
481486self.accumulate_result(result)
482487483-ifisinstance(result, Interrupted):
488+ifresult.state==State.INTERRUPTED:
484489break
485490486491previous_test=str(result)
487-test_time=time.monotonic() -start_time
492+test_time=time.perf_counter() -start_time
488493iftest_time>=PROGRESS_MIN_TIME:
489494previous_test="%s in %s"% (previous_test, format_duration(test_time))
490-elifisinstance(result, Passed):
495+elifresult.state==State.PASSED:
491496# be quiet: say nothing if the test passed shortly
492497previous_test=None
493498@@ -496,7 +501,7 @@ def run_tests_sequential(self):
496501ifmodulenotinsave_modulesandmodule.startswith("test."):
497502support.unload(module)
498503499-ifself.ns.failfastandis_failed(result, self.ns):
504+ifself.ns.failfastandresult.is_failed(self.ns.fail_env_changed):
500505break
501506502507ifprevious_test:
@@ -631,13 +636,48 @@ def finalize(self):
631636coverdir=self.ns.coverdir)
632637633638print()
634-duration=time.monotonic() -self.start_time
635-print("Total duration: %s"%format_duration(duration))
636-print("Tests result: %s"%self.get_tests_result())
639+self.display_summary()
637640638641ifself.ns.runleaks:
639642os.system("leaks %d"%os.getpid())
640643644+defdisplay_summary(self):
645+duration=time.perf_counter() -self.start_time
646+647+# Total duration
648+print("Total duration: %s"%format_duration(duration))
649+650+# Total tests
651+total=TestStats()
652+forstatsinself.stats_dict.values():
653+total.accumulate(stats)
654+stats= [f'run={total.tests_run:,}']
655+iftotal.failures:
656+stats.append(f'failures={total.failures:,}')
657+iftotal.skipped:
658+stats.append(f'skipped={total.skipped:,}')
659+print(f"Total tests: {' '.join(stats)}")
660+661+# Total test files
662+report= [f'success={len(self.good)}']
663+ifself.bad:
664+report.append(f'failed={len(self.bad)}')
665+ifself.environment_changed:
666+report.append(f'env_changed={len(self.environment_changed)}')
667+ifself.skipped:
668+report.append(f'skipped={len(self.skipped)}')
669+ifself.resource_denied:
670+report.append(f'resource_denied={len(self.resource_denied)}')
671+ifself.rerun:
672+report.append(f'rerun={len(self.rerun)}')
673+ifself.run_no_tests:
674+report.append(f'run_no_tests={len(self.run_no_tests)}')
675+print(f"Total test files: {' '.join(report)}")
676+677+# Result
678+result=self.get_tests_result()
679+print(f"Result: {result}")
680+641681defsave_xml_result(self):
642682ifnotself.ns.xmlpathandnotself.testsuite_xml:
643683return