Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
faa03ad601 | ||
|
|
43c0591c55 | ||
|
|
7bf3c7f029 | ||
|
|
e0f61e4fa2 | ||
|
|
f7be994848 | ||
|
|
7b19de5450 | ||
|
|
0c4f5eced2 | ||
|
|
e593841a70 | ||
|
|
43b693258f |
2
.hgtags
2
.hgtags
@@ -1,2 +1,4 @@
|
||||
42c6503ee48fae9c4c96d406afb12bfc86f15803 1.0
|
||||
eca7ce17eabf296983c36812c8b8be901e7055a3 1.1
|
||||
56d8e5280be224a0ad3220a9deed55334710bd23 1.2
|
||||
e6c4ce20db4bf65086ff55807a3c306cad7ca393 1.3
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
1.3
|
||||
-------------------------
|
||||
|
||||
- fix --looponfailing - it would not actually run against the fully changed
|
||||
source tree when initial conftest files load application state.
|
||||
|
||||
- adapt for py-1.3.1's new --maxfailure option
|
||||
|
||||
1.2
|
||||
-------------------------
|
||||
|
||||
|
||||
4
setup.py
4
setup.py
@@ -22,9 +22,9 @@ setup(
|
||||
packages = ['xdist'],
|
||||
entry_points = {'pytest11': ['xdist = xdist.plugin'],},
|
||||
zip_safe=False,
|
||||
install_requires = ['execnet>=1.0.6', 'py>=1.3.0'],
|
||||
install_requires = ['execnet>=1.0.6', 'py>=1.3.1'],
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: GNU General Public License (GPL)',
|
||||
'Operating System :: POSIX',
|
||||
|
||||
@@ -259,7 +259,7 @@ class TestDSession:
|
||||
def test_pass():
|
||||
pass
|
||||
""")
|
||||
modcol.config.option.exitfirst = True
|
||||
modcol.config.option.maxfail = 1
|
||||
session = DSession(modcol.config)
|
||||
node = MockNode()
|
||||
session.addnode(node)
|
||||
@@ -271,12 +271,44 @@ class TestDSession:
|
||||
# run tests ourselves and produce reports
|
||||
ev1 = run(items[0], node, "fail")
|
||||
ev2 = run(items[1], node, None)
|
||||
session.queueevent("pytest_runtest_logreport", report=ev1)
|
||||
session.queueevent("pytest_runtest_logreport", report=ev2)
|
||||
# now call the loop
|
||||
loopstate = session._initloopstate(items)
|
||||
py.test.raises(session.Interrupted, "session.loop_once(loopstate)")
|
||||
assert loopstate.testsfailed
|
||||
#assert loopstate.shuttingdown
|
||||
|
||||
def test_maxfail(self, testdir):
|
||||
modcol = testdir.getmodulecol("""
|
||||
def test_fail1():
|
||||
assert 0
|
||||
def test_fail2():
|
||||
assert 0
|
||||
def test_pass():
|
||||
pass
|
||||
""")
|
||||
modcol.config.option.maxfail = 2
|
||||
session = DSession(modcol.config)
|
||||
node = MockNode()
|
||||
session.addnode(node)
|
||||
items = modcol.config.hook.pytest_make_collect_report(collector=modcol).result
|
||||
|
||||
# trigger testing - this sends tests to the node
|
||||
session.triggertesting(items)
|
||||
|
||||
# run tests ourselves and produce reports
|
||||
ev1 = run(items[0], node, "fail")
|
||||
ev2 = run(items[1], node, "fail")
|
||||
session.queueevent("pytest_runtest_logreport", report=ev1) # a failing one
|
||||
session.queueevent("pytest_runtest_logreport", report=ev2)
|
||||
# now call the loop
|
||||
loopstate = session._initloopstate(items)
|
||||
from xdist.dsession import ExitFirstInterrupt
|
||||
py.test.raises(ExitFirstInterrupt, "session.loop_once(loopstate)")
|
||||
try:
|
||||
session.loop_once(loopstate)
|
||||
except session.Interrupted:
|
||||
py.test.fail("raised Interrupted but shouildn't")
|
||||
py.test.raises(session.Interrupted, "session.loop_once(loopstate)")
|
||||
assert loopstate.testsfailed
|
||||
#assert loopstate.shuttingdown
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ class TestLooponFailing:
|
||||
""")
|
||||
session = LooponfailingSession(modcol.config)
|
||||
loopstate = LoopState()
|
||||
session.remotecontrol.setup()
|
||||
session.loop_once(loopstate)
|
||||
assert len(loopstate.colitems) == 1
|
||||
|
||||
@@ -83,7 +82,6 @@ class TestLooponFailing:
|
||||
""")
|
||||
session = LooponfailingSession(modcol.config)
|
||||
loopstate = LoopState()
|
||||
session.remotecontrol.setup()
|
||||
loopstate.colitems = []
|
||||
session.loop_once(loopstate)
|
||||
assert len(loopstate.colitems) == 1
|
||||
@@ -110,7 +108,6 @@ class TestLooponFailing:
|
||||
""")
|
||||
session = LooponfailingSession(modcol.config)
|
||||
loopstate = LoopState()
|
||||
session.remotecontrol.setup()
|
||||
loopstate.colitems = []
|
||||
session.loop_once(loopstate)
|
||||
assert len(loopstate.colitems) == 2
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#
|
||||
__version__ = "1.2"
|
||||
__version__ = "1.3"
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class LoopState(object):
|
||||
# waiting for a host to become ready.
|
||||
self.dowork = True
|
||||
self.shuttingdown = False
|
||||
self.testsfailed = False
|
||||
self.testsfailed = 0
|
||||
|
||||
def __repr__(self):
|
||||
return "<LoopState exitstatus=%r shuttingdown=%r len(colitems)=%d>" % (
|
||||
@@ -31,7 +31,7 @@ class LoopState(object):
|
||||
if report.when != "teardown": # otherwise we already managed it
|
||||
self.dsession.removeitem(report.item, report.node)
|
||||
if report.failed:
|
||||
self.testsfailed = True
|
||||
self.testsfailed += 1
|
||||
|
||||
def pytest_collectreport(self, report):
|
||||
if report.passed:
|
||||
@@ -58,9 +58,6 @@ class LoopState(object):
|
||||
if pending:
|
||||
self.dowork = False # avoid busywait, nodes still have work
|
||||
|
||||
class ExitFirstInterrupt(KeyboardInterrupt):
|
||||
pass
|
||||
|
||||
class DSession(session.Session):
|
||||
"""
|
||||
Session drives the collection and running of tests
|
||||
@@ -131,11 +128,14 @@ class DSession(session.Session):
|
||||
call(**kwargs)
|
||||
|
||||
# termination conditions
|
||||
maxfail = self.config.getvalue("maxfail")
|
||||
if (not self.node2pending or
|
||||
(loopstate.testsfailed and self.config.option.exitfirst) or
|
||||
(loopstate.testsfailed and maxfail and
|
||||
loopstate.testsfailed >= maxfail) or
|
||||
(not self.item2nodes and not colitems and not self.queue.qsize())):
|
||||
if self.config.option.exitfirst:
|
||||
raise ExitFirstInterrupt()
|
||||
if maxfail and loopstate.testsfailed >= maxfail:
|
||||
raise self.Interrupted("stopping after %d failures" % (
|
||||
loopstate.testsfailed))
|
||||
self.triggershutdown()
|
||||
loopstate.shuttingdown = True
|
||||
if not self.node2pending:
|
||||
@@ -181,11 +181,8 @@ class DSession(session.Session):
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
excinfo = py.code.ExceptionInfo()
|
||||
if excinfo.errisinstance(ExitFirstInterrupt):
|
||||
exitstatus = session.EXIT_TESTSFAILED
|
||||
else:
|
||||
self.config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
|
||||
exitstatus = session.EXIT_INTERRUPTED
|
||||
self.config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
|
||||
exitstatus = session.EXIT_INTERRUPTED
|
||||
except:
|
||||
self.config.pluginmanager.notify_exception()
|
||||
exitstatus = session.EXIT_INTERNALERROR
|
||||
|
||||
@@ -120,11 +120,11 @@ Specifying test exec environments in a conftest.py
|
||||
Instead of specifying command line options, you can
|
||||
put options values in a ``conftest.py`` file like this::
|
||||
|
||||
pytest_option_tx = ['ssh=myhost//python=python2.5', 'popen//python=python2.5']
|
||||
pytest_option_dist = True
|
||||
option_tx = ['ssh=myhost//python=python2.5', 'popen//python=python2.5']
|
||||
option_dist = True
|
||||
|
||||
Any commandline ``--tx`` specifictions will add to the list of available execution
|
||||
environments.
|
||||
Any commandline ``--tx`` specifictions will add to the list of
|
||||
available execution environments.
|
||||
|
||||
Specifying "rsync" dirs in a conftest.py
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
@@ -24,7 +24,6 @@ class LooponfailingSession(Session):
|
||||
def main(self, initialitems):
|
||||
try:
|
||||
self.loopstate = loopstate = LoopState([])
|
||||
self.remotecontrol.setup()
|
||||
while 1:
|
||||
self.loop_once(loopstate)
|
||||
if not loopstate.colitems and loopstate.wasfailing:
|
||||
@@ -34,10 +33,10 @@ class LooponfailingSession(Session):
|
||||
print
|
||||
|
||||
def loop_once(self, loopstate):
|
||||
self.remotecontrol.setup()
|
||||
colitems = loopstate.colitems
|
||||
loopstate.wasfailing = colitems and len(colitems)
|
||||
loopstate.colitems = self.remotecontrol.runsession(colitems or ())
|
||||
self.remotecontrol.setup()
|
||||
|
||||
class LoopState:
|
||||
def __init__(self, colitems=None):
|
||||
|
||||
Reference in New Issue
Block a user