diff --git a/python/helpers/pycharm/_jb_runner_tools.py b/python/helpers/pycharm/_jb_runner_tools.py index 689eedc9aefd..f905d35146a7 100644 --- a/python/helpers/pycharm/_jb_runner_tools.py +++ b/python/helpers/pycharm/_jb_runner_tools.py @@ -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() diff --git a/python/helpers/pycharm/teamcity/messages.py b/python/helpers/pycharm/teamcity/messages.py index cbbf8d150e25..c62cec411232 100644 --- a/python/helpers/pycharm/teamcity/messages.py +++ b/python/helpers/pycharm/teamcity/messages.py @@ -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) diff --git a/python/helpers/pycharm/teamcity/pytest_plugin.py b/python/helpers/pycharm/teamcity/pytest_plugin.py index 549bf5037d31..3a886d8cb555 100644 --- a/python/helpers/pycharm/teamcity/pytest_plugin.py +++ b/python/helpers/pycharm/teamcity/pytest_plugin.py @@ -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)) diff --git a/python/helpers/pycharm/teamcity/unittestpy.py b/python/helpers/pycharm/teamcity/unittestpy.py index 476fa7917228..96cfffaa03b8 100644 --- a/python/helpers/pycharm/teamcity/unittestpy.py +++ b/python/helpers/pycharm/teamcity/unittestpy.py @@ -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: