From 6038ec21ca5264466bdd32dd42dd014b5fd934e4 Mon Sep 17 00:00:00 2001 From: Jonathan Hunt Date: Thu, 25 Apr 2013 17:45:42 -0700 Subject: [PATCH 1/5] Added test to catch import failure in distributed mode. --- testing/acceptance_test.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index f38e772..c103173 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -24,6 +24,18 @@ class TestDistribution: "*1 failed*", ]) + def test_n1_import_error(self, testdir): + p1 = testdir.makepyfile(""" + import __import_of_missing_module + def test_import(): + pass + """) + result = testdir.runpytest(p1, "-n1") + assert result.ret == 1 + result.stdout.fnmatch_lines([ + "*1 failed*", + ]) + def test_n1_skip(self, testdir): p1 = testdir.makepyfile(""" def test_skip(): From 46b94c1c81d5d5671bdf37c8aeb92bf39dfb0081 Mon Sep 17 00:00:00 2001 From: Jonathan Hunt Date: Thu, 25 Apr 2013 18:04:24 -0700 Subject: [PATCH 2/5] Report ImportErrors in distributed mode. --- testing/acceptance_test.py | 2 +- xdist/dsession.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index c103173..95f1332 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -33,7 +33,7 @@ class TestDistribution: result = testdir.runpytest(p1, "-n1") assert result.ret == 1 result.stdout.fnmatch_lines([ - "*1 failed*", + "E ImportError: No module named __import_of_missing_module", ]) def test_n1_skip(self, testdir): diff --git a/xdist/dsession.py b/xdist/dsession.py index b7d9b04..0ec92e9 100644 --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -285,8 +285,7 @@ class DSession: self._handlefailures(rep) def slave_collectreport(self, node, rep): - #self.report_line("collectreport %s: %s" %(rep.id, rep.status)) - #rep.node = node + self.config.hook.pytest_collectreport(report=rep) self._handlefailures(rep) def _handlefailures(self, rep): From 10c9c34c75293c290a77b58c5d38f2e9fcb230a9 Mon Sep 17 00:00:00 2001 From: Jonathan Hunt Date: Thu, 25 Apr 2013 18:20:40 -0700 Subject: [PATCH 3/5] Passing tests, avoiding duplicate errors. --- testing/acceptance_test.py | 12 ++++++++++++ xdist/dsession.py | 13 +++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 95f1332..d657b43 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -36,6 +36,18 @@ class TestDistribution: "E ImportError: No module named __import_of_missing_module", ]) + def test_n2_import_error(self, testdir): + """Check that we don't report the same import error multiple times + in distributed mode.""" + p1 = testdir.makepyfile(""" + import __import_of_missing_module + def test_import(): + pass + """) + result1 = testdir.runpytest(p1, "-n2") + result2 = testdir.runpytest(p1, "-n1") + assert len(result1.stdout.lines) == len(result2.stdout.lines) + def test_n1_skip(self, testdir): p1 = testdir.makepyfile(""" def test_skip(): diff --git a/xdist/dsession.py b/xdist/dsession.py index 0ec92e9..88f2725 100644 --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -159,6 +159,7 @@ class DSession: self.countfailures = 0 self.maxfail = config.getvalue("maxfail") self.queue = queue.Queue() + self._failed_collection_paths = {} try: self.terminal = config.pluginmanager.getplugin("terminalreporter") except KeyError: @@ -285,8 +286,16 @@ class DSession: self._handlefailures(rep) def slave_collectreport(self, node, rep): - self.config.hook.pytest_collectreport(report=rep) - self._handlefailures(rep) + if rep.failed: + self._failed_slave_collectreport(node, rep) + + def _failed_slave_collectreport(self, node, rep): + # Check we haven't already seen this report. + str_path = str(rep.fspath) + if str_path not in self._failed_collection_paths: + self._failed_collection_paths[str_path] = True + self.config.hook.pytest_collectreport(report=rep) + self._handlefailures(rep) def _handlefailures(self, rep): if rep.failed: From 6c1587a157a61b0760e41b17b8368076b27943d1 Mon Sep 17 00:00:00 2001 From: Jonathan Hunt Date: Sun, 28 Apr 2013 16:06:41 -0700 Subject: [PATCH 4/5] Added an additional test for import errors in --tx mode. --- testing/acceptance_test.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index d657b43..34596ee 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -60,6 +60,18 @@ class TestDistribution: "*1 skipped*", ]) + def test_manytests_to_one_import_error(self, testdir): + p1 = testdir.makepyfile(""" + import __import_of_missing_module + def test_import(): + pass + """) + result = testdir.runpytest(p1, '--tx=popen', '--tx=popen') + assert result.ret == 1 + result.stdout.fnmatch_lines([ + "E ImportError: No module named __import_of_missing_module", + ]) + def test_manytests_to_one_popen(self, testdir): p1 = testdir.makepyfile(""" import py From 26016aefd1821d766c53ea46e7e273047dceb535 Mon Sep 17 00:00:00 2001 From: Jonathan Hunt Date: Sun, 28 Apr 2013 16:14:52 -0700 Subject: [PATCH 5/5] Use the error longrepr rather than the file path to check for duplicate errors. --- xdist/dsession.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xdist/dsession.py b/xdist/dsession.py index 88f2725..6ffc80c 100644 --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -159,7 +159,7 @@ class DSession: self.countfailures = 0 self.maxfail = config.getvalue("maxfail") self.queue = queue.Queue() - self._failed_collection_paths = {} + self._failed_collection_errors = {} try: self.terminal = config.pluginmanager.getplugin("terminalreporter") except KeyError: @@ -290,10 +290,10 @@ class DSession: self._failed_slave_collectreport(node, rep) def _failed_slave_collectreport(self, node, rep): - # Check we haven't already seen this report. - str_path = str(rep.fspath) - if str_path not in self._failed_collection_paths: - self._failed_collection_paths[str_path] = True + # Check we haven't already seen this report (from + # another slave). + if rep.longrepr not in self._failed_collection_errors: + self._failed_collection_errors[rep.longrepr] = True self.config.hook.pytest_collectreport(report=rep) self._handlefailures(rep)