adapt for py-trunk/1.3.1 changes wrt --exitfirst -> --maxfailures
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
- fix --looponfailing - it would not actually run against the fully changed
|
- fix --looponfailing - it would not actually run against the fully changed
|
||||||
source tree when initial conftest files load application state.
|
source tree when initial conftest files load application state.
|
||||||
|
|
||||||
|
- adapt for py-1.3.1's new --maxfailure option
|
||||||
|
|
||||||
1.2
|
1.2
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -22,7 +22,7 @@ setup(
|
|||||||
packages = ['xdist'],
|
packages = ['xdist'],
|
||||||
entry_points = {'pytest11': ['xdist = xdist.plugin'],},
|
entry_points = {'pytest11': ['xdist = xdist.plugin'],},
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
install_requires = ['execnet>=1.0.6', 'py>=1.3.0'],
|
install_requires = ['execnet>=1.0.6', 'py>=1.3.1'],
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 4 - Beta',
|
'Development Status :: 4 - Beta',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ class TestDSession:
|
|||||||
def test_pass():
|
def test_pass():
|
||||||
pass
|
pass
|
||||||
""")
|
""")
|
||||||
modcol.config.option.exitfirst = True
|
modcol.config.option.maxfail = 1
|
||||||
session = DSession(modcol.config)
|
session = DSession(modcol.config)
|
||||||
node = MockNode()
|
node = MockNode()
|
||||||
session.addnode(node)
|
session.addnode(node)
|
||||||
@@ -271,12 +271,44 @@ class TestDSession:
|
|||||||
# run tests ourselves and produce reports
|
# run tests ourselves and produce reports
|
||||||
ev1 = run(items[0], node, "fail")
|
ev1 = run(items[0], node, "fail")
|
||||||
ev2 = run(items[1], node, None)
|
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=ev1) # a failing one
|
||||||
session.queueevent("pytest_runtest_logreport", report=ev2)
|
session.queueevent("pytest_runtest_logreport", report=ev2)
|
||||||
# now call the loop
|
# now call the loop
|
||||||
loopstate = session._initloopstate(items)
|
loopstate = session._initloopstate(items)
|
||||||
from xdist.dsession import ExitFirstInterrupt
|
try:
|
||||||
py.test.raises(ExitFirstInterrupt, "session.loop_once(loopstate)")
|
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.testsfailed
|
||||||
#assert loopstate.shuttingdown
|
#assert loopstate.shuttingdown
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class LoopState(object):
|
|||||||
# waiting for a host to become ready.
|
# waiting for a host to become ready.
|
||||||
self.dowork = True
|
self.dowork = True
|
||||||
self.shuttingdown = False
|
self.shuttingdown = False
|
||||||
self.testsfailed = False
|
self.testsfailed = 0
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<LoopState exitstatus=%r shuttingdown=%r len(colitems)=%d>" % (
|
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
|
if report.when != "teardown": # otherwise we already managed it
|
||||||
self.dsession.removeitem(report.item, report.node)
|
self.dsession.removeitem(report.item, report.node)
|
||||||
if report.failed:
|
if report.failed:
|
||||||
self.testsfailed = True
|
self.testsfailed += 1
|
||||||
|
|
||||||
def pytest_collectreport(self, report):
|
def pytest_collectreport(self, report):
|
||||||
if report.passed:
|
if report.passed:
|
||||||
@@ -58,9 +58,6 @@ class LoopState(object):
|
|||||||
if pending:
|
if pending:
|
||||||
self.dowork = False # avoid busywait, nodes still have work
|
self.dowork = False # avoid busywait, nodes still have work
|
||||||
|
|
||||||
class ExitFirstInterrupt(KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class DSession(session.Session):
|
class DSession(session.Session):
|
||||||
"""
|
"""
|
||||||
Session drives the collection and running of tests
|
Session drives the collection and running of tests
|
||||||
@@ -131,11 +128,14 @@ class DSession(session.Session):
|
|||||||
call(**kwargs)
|
call(**kwargs)
|
||||||
|
|
||||||
# termination conditions
|
# termination conditions
|
||||||
|
maxfail = self.config.getvalue("maxfail")
|
||||||
if (not self.node2pending or
|
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())):
|
(not self.item2nodes and not colitems and not self.queue.qsize())):
|
||||||
if self.config.option.exitfirst:
|
if maxfail and loopstate.testsfailed >= maxfail:
|
||||||
raise ExitFirstInterrupt()
|
raise self.Interrupted("stopping after %d failures" % (
|
||||||
|
loopstate.testsfailed))
|
||||||
self.triggershutdown()
|
self.triggershutdown()
|
||||||
loopstate.shuttingdown = True
|
loopstate.shuttingdown = True
|
||||||
if not self.node2pending:
|
if not self.node2pending:
|
||||||
@@ -181,11 +181,8 @@ class DSession(session.Session):
|
|||||||
break
|
break
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
excinfo = py.code.ExceptionInfo()
|
excinfo = py.code.ExceptionInfo()
|
||||||
if excinfo.errisinstance(ExitFirstInterrupt):
|
self.config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
|
||||||
exitstatus = session.EXIT_TESTSFAILED
|
exitstatus = session.EXIT_INTERRUPTED
|
||||||
else:
|
|
||||||
self.config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
|
|
||||||
exitstatus = session.EXIT_INTERRUPTED
|
|
||||||
except:
|
except:
|
||||||
self.config.pluginmanager.notify_exception()
|
self.config.pluginmanager.notify_exception()
|
||||||
exitstatus = session.EXIT_INTERNALERROR
|
exitstatus = session.EXIT_INTERNALERROR
|
||||||
|
|||||||
Reference in New Issue
Block a user