diff --git a/CHANGELOG b/CHANGELOG index 85302a2..62717c7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,10 @@ +1.14.0.dev +---------- + +- new hook: ``pytest_xdist_node_collection_finished(node, ids)``, called when + a worker has finished collection. Thanks Omer Katz for the request and + Bruno Oliveira for the PR. + 1.13.2.dev ---------- diff --git a/testing/test_newhooks.py b/testing/test_newhooks.py new file mode 100644 index 0000000..a6737ea --- /dev/null +++ b/testing/test_newhooks.py @@ -0,0 +1,50 @@ +import pytest + + +class TestHooks: + + @pytest.fixture(autouse=True) + def create_test_file(self, testdir): + testdir.makepyfile(""" + import os + def test_a(): pass + def test_b(): pass + def test_c(): pass + """) + + def test_runtest_logreport(self, testdir): + """Test that log reports from pytest_runtest_logreport when running + with xdist contain a "node" attribute. (#8) + """ + testdir.makeconftest(""" + def pytest_runtest_logreport(report): + if hasattr(report, 'node'): + slaveid = report.node.slaveinput['slaveid'] + if report.when == "call": + print("HOOK: %s %s" % (report.nodeid, slaveid)) + """) + res = testdir.runpytest('-n1', '-s') + res.stdout.fnmatch_lines([ + '*HOOK: test_runtest_logreport.py::test_a gw0*', + '*HOOK: test_runtest_logreport.py::test_b gw0*', + '*HOOK: test_runtest_logreport.py::test_c gw0*', + '*3 passed*', + ]) + + def test_node_collection_finished(self, testdir): + """Test pytest_xdist_node_collection_finished hook (#8). + """ + testdir.makeconftest(""" + def pytest_xdist_node_collection_finished(node, ids): + slaveid = node.slaveinput['slaveid'] + stripped_ids = [x.split('::')[1] for x in ids] + print("HOOK: %s %s" % (slaveid, ', '.join(stripped_ids))) + """) + res = testdir.runpytest('-n2', '-s') + res.stdout.fnmatch_lines_random([ + '*HOOK: gw0 test_a, test_b, test_c', + '*HOOK: gw1 test_a, test_b, test_c', + ]) + res.stdout.fnmatch_lines([ + '*3 passed*', + ]) diff --git a/xdist/dsession.py b/xdist/dsession.py index 451a308..fa66f1d 100644 --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -629,6 +629,8 @@ class DSession: """ if self.shuttingdown: return + self.config.hook.pytest_xdist_node_collection_finished(node=node, + ids=ids) # tell session which items were effectively collected otherwise # the master node will finish the session with EXIT_NOTESTSCOLLECTED self._session.testscollected = len(ids) diff --git a/xdist/newhooks.py b/xdist/newhooks.py index 0207935..d31aed8 100644 --- a/xdist/newhooks.py +++ b/xdist/newhooks.py @@ -1,3 +1,17 @@ +""" +xdist hooks. + +Additionally, pytest-xdist will also decorate a few other hooks +with the worker instance that executed the hook originally: + +``pytest_runtest_logreport``: ``rep`` parameter has a ``node`` attribute. + +You can use this hooks just as you would use normal pytest hooks, but some care +must be taken in plugins in case ``xdist`` is not installed. Please see: + + http://pytest.org/latest/writing_plugins.html#optionally-using-hooks-from-3rd-party-plugins +""" + def pytest_xdist_setupnodes(config, specs): """ called before any remote node is set up. """ @@ -25,3 +39,8 @@ def pytest_testnodeready(node): def pytest_testnodedown(node, error): """ Test Node is down. """ + + +def pytest_xdist_node_collection_finished(node, ids): + """called by the master node when a node finishes collecting. + """