properly handle test items that get locally collected but cannot be collected on the remote side (often due to platform reasons)
--HG-- branch : 1.0.x
This commit is contained in:
parent
dcf194ebb8
commit
ad34e50b71
|
@ -1,7 +1,11 @@
|
||||||
Changes between 1.0.0b8 and 1.0.0b9
|
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
|
* make assert-reinterpretation work better with comparisons not
|
||||||
returning bools (reported with numpy from thanks maciej fijalkowski)
|
returning bools (reported with numpy from thanks maciej fijalkowski)
|
||||||
|
|
|
@ -4,7 +4,6 @@ Collectors and test Items form a tree
|
||||||
that is usually built iteratively.
|
that is usually built iteratively.
|
||||||
"""
|
"""
|
||||||
import py
|
import py
|
||||||
from py.__.test.outcome import Skipped
|
|
||||||
|
|
||||||
def configproperty(name):
|
def configproperty(name):
|
||||||
def fget(self):
|
def fget(self):
|
||||||
|
@ -31,6 +30,10 @@ class Node(object):
|
||||||
self.config = getattr(parent, 'config', None)
|
self.config = getattr(parent, 'config', None)
|
||||||
self.fspath = getattr(parent, 'fspath', 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.
|
# note to myself: Pickling is uh.
|
||||||
#
|
#
|
||||||
|
@ -44,6 +47,7 @@ class Node(object):
|
||||||
except Exception:
|
except Exception:
|
||||||
# seems our parent can't collect us
|
# seems our parent can't collect us
|
||||||
# so let's be somewhat operable
|
# so let's be somewhat operable
|
||||||
|
# _checkcollectable() is to tell outsiders about the fact
|
||||||
self.name = name
|
self.name = name
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.config = parent.config
|
self.config = parent.config
|
||||||
|
|
|
@ -367,13 +367,21 @@ class TestDSession:
|
||||||
assert node.gateway.spec.popen
|
assert node.gateway.spec.popen
|
||||||
#XXX eq.geteventargs("pytest_sessionfinish")
|
#XXX eq.geteventargs("pytest_sessionfinish")
|
||||||
|
|
||||||
@py.test.mark.xfail
|
def test_collected_function_causes_remote_skip(testdir):
|
||||||
def test_collected_function_causes_remote_skip_at_module_level(self, testdir):
|
sub = testdir.mkpydir("testing")
|
||||||
p = testdir.makepyfile("""
|
sub.join("test_module.py").write(py.code.Source("""
|
||||||
import py
|
import py
|
||||||
py.test.importorskip("xyz")
|
path = py.path.local(%r)
|
||||||
|
if path.check():
|
||||||
|
path.remove()
|
||||||
|
else:
|
||||||
|
py.test.skip("remote skip")
|
||||||
def test_func():
|
def test_func():
|
||||||
pass
|
pass
|
||||||
""")
|
def test_func2():
|
||||||
# we need to be able to collect test_func locally but not in the subprocess
|
pass
|
||||||
XXX
|
""" % str(sub.ensure("somefile"))))
|
||||||
|
result = testdir.runpytest('-v', '--dist=each', '--tx=popen')
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
"*2 skipped*"
|
||||||
|
])
|
||||||
|
|
|
@ -124,12 +124,37 @@ class SlaveNode(object):
|
||||||
break
|
break
|
||||||
if isinstance(task, list):
|
if isinstance(task, list):
|
||||||
for item in task:
|
for item in task:
|
||||||
item.config.hook.pytest_runtest_protocol(item=item)
|
self.run_single(item=item)
|
||||||
else:
|
else:
|
||||||
task.config.hook.pytest_runtest_protocol(item=task)
|
self.run_single(item=task)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
er = py.code.ExceptionInfo().getrepr(funcargs=True, showlocals=True)
|
er = py.code.ExceptionInfo().getrepr(funcargs=True, showlocals=True)
|
||||||
self.sendevent("pytest_internalerror", excrepr=er)
|
self.sendevent("pytest_internalerror", excrepr=er)
|
||||||
raise
|
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()
|
||||||
|
|
|
@ -130,6 +130,11 @@ class TmpTestdir:
|
||||||
def mkdir(self, name):
|
def mkdir(self, name):
|
||||||
return self.tmpdir.mkdir(name)
|
return self.tmpdir.mkdir(name)
|
||||||
|
|
||||||
|
def mkpydir(self, name):
|
||||||
|
p = self.mkdir(name)
|
||||||
|
p.ensure("__init__.py")
|
||||||
|
return p
|
||||||
|
|
||||||
def genitems(self, colitems):
|
def genitems(self, colitems):
|
||||||
return list(self.session.genitems(colitems))
|
return list(self.session.genitems(colitems))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue