From c80f185543884081518424f8c73c7c7c3bb55d00 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 6 Jun 2019 16:49:31 -0300 Subject: [PATCH] Do not show internal error when running out of workers Also show the reason of the session being interrupted in the warnings summary Fix #435 --- changelog/435.bugfix.rst | 1 + changelog/435.feature.rst | 2 ++ testing/acceptance_test.py | 41 ++++++++++++++++++++++++++++++-------- xdist/dsession.py | 21 ++++++++++++++----- 4 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 changelog/435.bugfix.rst create mode 100644 changelog/435.feature.rst diff --git a/changelog/435.bugfix.rst b/changelog/435.bugfix.rst new file mode 100644 index 00000000..5e25be3e --- /dev/null +++ b/changelog/435.bugfix.rst @@ -0,0 +1 @@ +No longer show an internal error when we run out of workers due to crashes. diff --git a/changelog/435.feature.rst b/changelog/435.feature.rst new file mode 100644 index 00000000..dc32c06a --- /dev/null +++ b/changelog/435.feature.rst @@ -0,0 +1,2 @@ +When the test session is interrupted due to running out of workers, the reason is shown in the test summary +for easier viewing. diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 9a8e42b8..475620fd 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -922,14 +922,35 @@ def test_d(): pass res = testdir.runpytest(f, "-n4", "--max-worker-restart=1") res.stdout.fnmatch_lines( [ - "*Replacing crashed worker*", - "*Maximum crashed workers reached: 1*", - "*Worker*crashed while running*", - "*Worker*crashed while running*", + "replacing crashed worker*", + "maximum crashed workers reached: 1*", + "worker*crashed while running*", + "worker*crashed while running*", "*2 failed*2 passed*", ] ) + def test_max_worker_restart_tests_queued(self, testdir): + f = testdir.makepyfile( + """ + import os, pytest + @pytest.mark.parametrize('i', range(10)) + def test(i): os._exit(1) + """ + ) + res = testdir.runpytest(f, "-n2", "--max-worker-restart=3") + res.stdout.fnmatch_lines( + [ + "replacing crashed worker*", + "maximum crashed workers reached: 3*", + "worker*crashed while running*", + "worker*crashed while running*", + "* xdist: maximum crashed workers reached: 3 *", + "* 4 failed in *", + ] + ) + assert "INTERNALERROR" not in res.stdout.str() + def test_max_worker_restart_die(self, testdir): f = testdir.makepyfile( """ @@ -939,7 +960,10 @@ def test_max_worker_restart_die(self, testdir): ) res = testdir.runpytest(f, "-n4", "--max-worker-restart=0") res.stdout.fnmatch_lines( - ["*Unexpectedly no active workers*", "*INTERNALERROR*"] + [ + "* xdist: worker gw* crashed and worker restarting disabled *", + "* no tests ran in *", + ] ) def test_disable_restart(self, testdir): @@ -954,9 +978,10 @@ def test_c(): pass res = testdir.runpytest(f, "-n4", "--max-worker-restart=0") res.stdout.fnmatch_lines( [ - "*Worker restarting disabled*", - "*Worker*crashed while running*", - "*1 failed*2 passed*", + "worker gw* crashed and worker restarting disabled", + "*worker*crashed while running*", + "* xdist: worker gw* crashed and worker restarting disabled *", + "* 1 failed, 2 passed in *", ] ) diff --git a/xdist/dsession.py b/xdist/dsession.py index 8bb559c0..ea96b9fe 100644 --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -49,6 +49,9 @@ def __init__(self, config): self._max_worker_restart = self.config.option.maxworkerrestart if self._max_worker_restart is not None: self._max_worker_restart = int(self._max_worker_restart) + + # summary message to print at the end of the session + self._summary_report = None try: self.terminal = config.pluginmanager.getplugin("terminalreporter") except KeyError: @@ -198,15 +201,23 @@ def worker_errordown(self, node, error): ) if maximum_reached: if self._max_worker_restart == 0: - msg = "Worker restarting disabled" + msg = "worker {} crashed and worker restarting disabled".format( + node.gateway.id + ) else: - msg = "Maximum crashed workers reached: %d" % self._max_worker_restart - self.report_line(msg) + msg = "maximum crashed workers reached: %d" % self._max_worker_restart + self._summary_report = msg + self.report_line("\n" + msg) + self.triggershutdown() else: - self.report_line("Replacing crashed worker %s" % node.gateway.id) + self.report_line("\nreplacing crashed worker %s" % node.gateway.id) self._clone_node(node) self._active_nodes.remove(node) + def pytest_terminal_summary(self, terminalreporter): + if self.config.option.verbose >= 0 and self._summary_report: + terminalreporter.write_sep("=", "xdist: {}".format(self._summary_report)) + def worker_collectionfinish(self, node, ids): """worker has finished test collection. @@ -316,7 +327,7 @@ def handle_crashitem(self, nodeid, worker): # XXX count no of failures and retry N times runner = self.config.pluginmanager.getplugin("runner") fspath = nodeid.split("::")[0] - msg = "Worker %r crashed while running %r" % (worker.gateway.id, nodeid) + msg = "worker %r crashed while running %r" % (worker.gateway.id, nodeid) rep = runner.TestReport( nodeid, (fspath, None, fspath), (), "failed", msg, "???" )