diff --git a/CHANGELOG b/CHANGELOG index 14f888746..3b36188d5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,11 @@ Changes between 1.0.0b8 and 1.0.0b9 ===================================== -* simplified py.test.mark API +* dist-testing: properly handle test items that get locally + collected but cannot be collected on the remote side - often + due to platform/dependency reasons + +* simplified py.test.mark API - see keyword plugin documentation * make assert-reinterpretation work better with comparisons not returning bools (reported with numpy from thanks maciej fijalkowski) diff --git a/py/test/collect.py b/py/test/collect.py index c7bbdb556..eb941a712 100644 --- a/py/test/collect.py +++ b/py/test/collect.py @@ -4,7 +4,6 @@ Collectors and test Items form a tree that is usually built iteratively. """ import py -from py.__.test.outcome import Skipped def configproperty(name): def fget(self): @@ -31,6 +30,10 @@ class Node(object): self.config = getattr(parent, 'config', None) self.fspath = getattr(parent, 'fspath', None) + def _checkcollectable(self): + if not hasattr(self, 'fspath'): + self.parent._memocollect() # to reraise exception + # # note to myself: Pickling is uh. # @@ -44,6 +47,7 @@ class Node(object): except Exception: # seems our parent can't collect us # so let's be somewhat operable + # _checkcollectable() is to tell outsiders about the fact self.name = name self.parent = parent self.config = parent.config diff --git a/py/test/dist/testing/test_dsession.py b/py/test/dist/testing/test_dsession.py index ec33526cc..5c2b1afd2 100644 --- a/py/test/dist/testing/test_dsession.py +++ b/py/test/dist/testing/test_dsession.py @@ -367,13 +367,21 @@ class TestDSession: assert node.gateway.spec.popen #XXX eq.geteventargs("pytest_sessionfinish") - @py.test.mark.xfail - def test_collected_function_causes_remote_skip_at_module_level(self, testdir): - p = testdir.makepyfile(""" - import py - py.test.importorskip("xyz") - def test_func(): - pass - """) - # we need to be able to collect test_func locally but not in the subprocess - XXX +def test_collected_function_causes_remote_skip(testdir): + sub = testdir.mkpydir("testing") + sub.join("test_module.py").write(py.code.Source(""" + import py + path = py.path.local(%r) + if path.check(): + path.remove() + else: + py.test.skip("remote skip") + def test_func(): + pass + def test_func2(): + pass + """ % str(sub.ensure("somefile")))) + result = testdir.runpytest('-v', '--dist=each', '--tx=popen') + result.stdout.fnmatch_lines([ + "*2 skipped*" + ]) diff --git a/py/test/dist/txnode.py b/py/test/dist/txnode.py index d7633e80e..513772947 100644 --- a/py/test/dist/txnode.py +++ b/py/test/dist/txnode.py @@ -124,12 +124,37 @@ class SlaveNode(object): break if isinstance(task, list): for item in task: - item.config.hook.pytest_runtest_protocol(item=item) + self.run_single(item=item) else: - task.config.hook.pytest_runtest_protocol(item=task) + self.run_single(item=task) except KeyboardInterrupt: raise except: er = py.code.ExceptionInfo().getrepr(funcargs=True, showlocals=True) self.sendevent("pytest_internalerror", excrepr=er) raise + + def run_single(self, item): + call = CallInfo(item._checkcollectable, 'setup') + if call.excinfo: + # likely it is not collectable here because of + # platform/import-dependency induced skips + # XXX somewhat ugly shortcuts - also makes a collection + # failure into an ItemTestReport - this might confuse + # pytest_runtest_logreport hooks + runner = item.config.pluginmanager.getplugin("pytest_runner") + rep = runner.pytest_runtest_makereport(item=item, call=call) + self.pytest_runtest_logreport(rep) + return + item.config.hook.pytest_runtest_protocol(item=item) + +class CallInfo: + excinfo = None + def __init__(self, func, when): + self.when = when + try: + self.result = func() + except KeyboardInterrupt: + raise + except: + self.excinfo = py.code.ExceptionInfo() diff --git a/py/test/plugin/pytest_pytester.py b/py/test/plugin/pytest_pytester.py index 0a0ba4c00..f022df147 100644 --- a/py/test/plugin/pytest_pytester.py +++ b/py/test/plugin/pytest_pytester.py @@ -129,7 +129,12 @@ class TmpTestdir: def mkdir(self, name): return self.tmpdir.mkdir(name) - + + def mkpydir(self, name): + p = self.mkdir(name) + p.ensure("__init__.py") + return p + def genitems(self, colitems): return list(self.session.genitems(colitems))