[python, tests] Report interactive interruptions of unittest/pytest tests via testIgnored(stopped=true)

GitOrigin-RevId: 30e049cccb17934daafe25c0d0205a99bf950d70
This commit is contained in:
Christoph Thiede
2025-08-19 15:17:26 +00:00
committed by intellij-monorepo-bot
parent 4c857301db
commit 4221bbc60f
4 changed files with 35 additions and 7 deletions
+18 -7
View File
@@ -128,7 +128,15 @@ class NewTeamcityServiceMessages(_old_service_messages):
is_test = messageName == "testStarted"
if messageName == "testSuiteStarted" or is_test:
self._test_suites[full_name] = (full_name, current, parent, is_test)
self._test_suites[full_name] = (full_name, current, parent, is_test, False)
elif messageName == "testIgnored" and properties.get("stopped") == "true":
ancestors = self._test_to_list(full_name)
# mark ancestors as explicitly stopped
for i in range(len(ancestors), 0, -1):
ancestor = ".".join(ancestors[:i])
# keep old entries intact; only change was_stopped
old_entry = self._test_suites[ancestor]
self._test_suites[ancestor] = old_entry[:4] + (True,) + old_entry[5:]
_old_service_messages.message(self, messageName, **properties)
def _test_to_list(self, test_name):
@@ -257,15 +265,18 @@ class NewTeamcityServiceMessages(_old_service_messages):
def close_suites(self):
# Go in reverse order and close all suites
for (test_suite, node_id, parent_node_id, is_test) in \
for (test_suite, node_id, parent_node_id, is_test, was_stopped) in \
reversed(list(self._test_suites.values())):
# suits are explicitly closed, but if test can't been finished, it is skipped
message = "testIgnored" if is_test else "testSuiteFinished"
_old_service_messages.message(self, message, **{
# suites are explicitly closed, but if test can't been finished, it was either stopped or skipped
message = "testIgnored" if is_test or was_stopped else "testSuiteFinished"
kwargs = {
"name": test_suite,
"nodeId": str(node_id),
"parentNodeId": str(parent_node_id)
})
"parentNodeId": str(parent_node_id),
}
if was_stopped:
kwargs["stopped"] = "true"
_old_service_messages.message(self, message, **kwargs)
self._test_suites = OrderedDict()
@@ -169,6 +169,9 @@ class TeamcityServiceMessages(object):
def testIgnored(self, testName, message='', flowId=None):
self.message('testIgnored', name=testName, message=message, flowId=flowId)
def testStopped(self, testName, message='', flowId=None):
self.message('testIgnored', name=testName, message=message, flowId=flowId, stopped="true")
def testFailed(self, testName, message='', details='', flowId=None, comparison_failure=None):
if not comparison_failure:
self.message('testFailed', name=testName, message=message, details=details, flowId=flowId)
@@ -161,6 +161,16 @@ class EchoTeamCityMessages(object):
return "%s:%s (%s)" % (str(location[0]), str(location[1]), str(location[2]))
return str(location)
def pytest_sessionfinish(self, session, exitstatus):
if exitstatus > pytest.ExitCode.TESTS_FAILED and self.current_test_item:
test_id = self.format_test_id(self.current_test_item.nodeid, self.current_test_item.location)
self.teamcity.testStopped(
test_id,
message=exitstatus.name if hasattr(exitstatus, 'name') else str(exitstatus),
flowId=test_id
)
self.report_test_finished(test_id)
def pytest_collection_finish(self, session):
self.teamcity.testCount(len(session.items))
@@ -276,6 +276,10 @@ class TeamcityTestResult(TextTestResult):
if subtest_failures:
self.report_fail(test, "One or more subtests failed", "")
if sys.exc_info()[0] is not None:
# test was interrupted (e.g., SIGINT)
self.messages.testStopped(test_id, flowId=test_id)
try:
time_diff = datetime.datetime.now() - self.test_started_datetime_map[test_id]
except KeyError: