Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
feaf840fab | ||
|
|
f112ad6cfb | ||
|
|
71771fbdc6 | ||
|
|
c0b2df1a77 | ||
|
|
9aa1df89ee | ||
|
|
67e0cd463c | ||
|
|
fb31aa882d | ||
|
|
51b0ba55e9 | ||
|
|
d0ccb5743d | ||
|
|
fa7da18d9b | ||
|
|
cf36bf8bf2 | ||
|
|
55e3d27820 | ||
|
|
a17bc05c5a | ||
|
|
e5e23fd278 | ||
|
|
e48dcda834 |
@@ -19,3 +19,4 @@ dist/
|
|||||||
pytest_xdist.egg-info
|
pytest_xdist.egg-info
|
||||||
issue/
|
issue/
|
||||||
3rdparty/
|
3rdparty/
|
||||||
|
.tox
|
||||||
|
|||||||
2
.hgtags
2
.hgtags
@@ -2,3 +2,5 @@
|
|||||||
eca7ce17eabf296983c36812c8b8be901e7055a3 1.1
|
eca7ce17eabf296983c36812c8b8be901e7055a3 1.1
|
||||||
56d8e5280be224a0ad3220a9deed55334710bd23 1.2
|
56d8e5280be224a0ad3220a9deed55334710bd23 1.2
|
||||||
e6c4ce20db4bf65086ff55807a3c306cad7ca393 1.3
|
e6c4ce20db4bf65086ff55807a3c306cad7ca393 1.3
|
||||||
|
e6c4ce20db4bf65086ff55807a3c306cad7ca393 1.3
|
||||||
|
eaf8b1cb7c312883598677231be5bbeea3b5c127 1.3
|
||||||
|
|||||||
13
CHANGELOG
13
CHANGELOG
@@ -1,3 +1,16 @@
|
|||||||
|
1.4
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
- perform distributed testing related reporting in the plugin
|
||||||
|
rather than having dist-related code in the generic py.test
|
||||||
|
distribution
|
||||||
|
|
||||||
|
- depend on execnet-1.0.7 which adds "env1:NAME=value" keys to
|
||||||
|
gateway specification strings.
|
||||||
|
|
||||||
|
- show detailed gateway setup and platform information only when
|
||||||
|
"-v" or "--verbose" is specified.
|
||||||
|
|
||||||
1.3
|
1.3
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
|||||||
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.1'],
|
install_requires = ['execnet>=1.0.7', 'py>1.3.1'],
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 5 - Production/Stable',
|
'Development Status :: 5 - Production/Stable',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import py
|
import py
|
||||||
|
import sys
|
||||||
|
|
||||||
class TestDistribution:
|
class TestDistribution:
|
||||||
def test_manytests_to_one_popen(self, testdir):
|
def test_manytests_to_one_popen(self, testdir):
|
||||||
@@ -14,7 +15,7 @@ class TestDistribution:
|
|||||||
py.test.skip("hello")
|
py.test.skip("hello")
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
result = testdir.runpytest(p1, '-d', '--tx=popen', '--tx=popen')
|
result = testdir.runpytest(p1, "-v", '-d', '--tx=popen', '--tx=popen')
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*0*popen*Python*",
|
"*0*popen*Python*",
|
||||||
"*1*popen*Python*",
|
"*1*popen*Python*",
|
||||||
@@ -38,7 +39,7 @@ class TestDistribution:
|
|||||||
testdir.makeconftest("""
|
testdir.makeconftest("""
|
||||||
option_tx = 'popen popen popen'.split()
|
option_tx = 'popen popen popen'.split()
|
||||||
""")
|
""")
|
||||||
result = testdir.runpytest(p1, '-d')
|
result = testdir.runpytest(p1, '-d', "-v")
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*0*popen*Python*",
|
"*0*popen*Python*",
|
||||||
"*1*popen*Python*",
|
"*1*popen*Python*",
|
||||||
@@ -47,6 +48,7 @@ class TestDistribution:
|
|||||||
])
|
])
|
||||||
assert result.ret == 1
|
assert result.ret == 1
|
||||||
|
|
||||||
|
@py.test.mark.xfail("sys.platform.startswith('java')")
|
||||||
def test_dist_tests_with_crash(self, testdir):
|
def test_dist_tests_with_crash(self, testdir):
|
||||||
if not hasattr(py.std.os, 'kill'):
|
if not hasattr(py.std.os, 'kill'):
|
||||||
py.test.skip("no os.kill")
|
py.test.skip("no os.kill")
|
||||||
@@ -68,7 +70,7 @@ class TestDistribution:
|
|||||||
os.kill(os.getpid(), 15)
|
os.kill(os.getpid(), 15)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
result = testdir.runpytest(p1, '-d', '--tx=3*popen')
|
result = testdir.runpytest(p1, "-v", '-d', '--tx=3*popen')
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*popen*Python*",
|
"*popen*Python*",
|
||||||
"*popen*Python*",
|
"*popen*Python*",
|
||||||
@@ -85,7 +87,7 @@ class TestDistribution:
|
|||||||
subdir.ensure("__init__.py")
|
subdir.ensure("__init__.py")
|
||||||
p = subdir.join("test_one.py")
|
p = subdir.join("test_one.py")
|
||||||
p.write("def test_5(): assert not __file__.startswith(%r)" % str(p))
|
p.write("def test_5(): assert not __file__.startswith(%r)" % str(p))
|
||||||
result = testdir.runpytest("-d", "--rsyncdir=%(subdir)s" % locals(),
|
result = testdir.runpytest("-v", "-d", "--rsyncdir=%(subdir)s" % locals(),
|
||||||
"--tx=popen//chdir=%(dest)s" % locals(), p)
|
"--tx=popen//chdir=%(dest)s" % locals(), p)
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
@@ -110,7 +112,7 @@ class TestDistribution:
|
|||||||
print("%s...%s" % sys.version_info[:2])
|
print("%s...%s" % sys.version_info[:2])
|
||||||
assert 0
|
assert 0
|
||||||
""")
|
""")
|
||||||
args = ["--dist=each"]
|
args = ["--dist=each", "-v"]
|
||||||
args += ["--tx", "popen//python=%s" % interpreters[0]]
|
args += ["--tx", "popen//python=%s" % interpreters[0]]
|
||||||
args += ["--tx", "popen//python=%s" % interpreters[1]]
|
args += ["--tx", "popen//python=%s" % interpreters[1]]
|
||||||
result = testdir.runpytest(*args)
|
result = testdir.runpytest(*args)
|
||||||
@@ -145,7 +147,7 @@ class TestDistribution:
|
|||||||
'calculated result is %s' % calc_result)
|
'calculated result is %s' % calc_result)
|
||||||
""")
|
""")
|
||||||
p1 = testdir.makepyfile("def test_func(): pass")
|
p1 = testdir.makepyfile("def test_func(): pass")
|
||||||
result = testdir.runpytest(p1, '-d', '--tx=popen')
|
result = testdir.runpytest("-v", p1, '-d', '--tx=popen')
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*popen*Python*",
|
"*popen*Python*",
|
||||||
"*calculated result is 49*",
|
"*calculated result is 49*",
|
||||||
@@ -172,3 +174,57 @@ class TestDistribution:
|
|||||||
assert result.ret
|
assert result.ret
|
||||||
assert 'SIGINT' in s
|
assert 'SIGINT' in s
|
||||||
assert 's2call' in s
|
assert 's2call' in s
|
||||||
|
|
||||||
|
def test_keyboard_interrupt_dist(self, testdir):
|
||||||
|
# xxx could be refined to check for return code
|
||||||
|
p = testdir.makepyfile("""
|
||||||
|
def test_sleep():
|
||||||
|
import time
|
||||||
|
time.sleep(10)
|
||||||
|
""")
|
||||||
|
child = testdir.spawn_pytest("-n1")
|
||||||
|
child.expect(".*test session starts.*")
|
||||||
|
child.kill(2) # keyboard interrupt
|
||||||
|
child.expect(".*KeyboardInterrupt.*")
|
||||||
|
#child.expect(".*seconds.*")
|
||||||
|
child.close()
|
||||||
|
#assert ret == 2
|
||||||
|
|
||||||
|
class TestTerminalReporting:
|
||||||
|
def test_pass_skip_fail(self, testdir):
|
||||||
|
p = testdir.makepyfile("""
|
||||||
|
import py
|
||||||
|
def test_ok():
|
||||||
|
pass
|
||||||
|
def test_skip():
|
||||||
|
py.test.skip("xx")
|
||||||
|
def test_func():
|
||||||
|
assert 0
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest("-n1", "-v")
|
||||||
|
expected = [
|
||||||
|
"*PASS*test_pass_skip_fail.py:2: *test_ok*",
|
||||||
|
"*SKIP*test_pass_skip_fail.py:4: *test_skip*",
|
||||||
|
"*FAIL*test_pass_skip_fail.py:6: *test_func*",
|
||||||
|
]
|
||||||
|
for line in expected:
|
||||||
|
result.stdout.fnmatch_lines([line])
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
" def test_func():",
|
||||||
|
"> assert 0",
|
||||||
|
"E assert 0",
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_fail_platinfo(self, testdir):
|
||||||
|
p = testdir.makepyfile("""
|
||||||
|
def test_func():
|
||||||
|
assert 0
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest("-n1", "-v")
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
"*FAIL*test_fail_platinfo.py:1: *test_func*",
|
||||||
|
"*popen*Python*",
|
||||||
|
" def test_func():",
|
||||||
|
"> assert 0",
|
||||||
|
"E assert 0",
|
||||||
|
])
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import py
|
|||||||
import execnet
|
import execnet
|
||||||
|
|
||||||
pytest_plugins = "pytester"
|
pytest_plugins = "pytester"
|
||||||
option_report = 'skipped'
|
|
||||||
|
|
||||||
#rsyncdirs = ['.', '../xdist', py.path.local(execnet.__file__).dirpath()]
|
#rsyncdirs = ['.', '../xdist', py.path.local(execnet.__file__).dirpath()]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import py
|
import py
|
||||||
|
|
||||||
def test_dist_conftest_options(testdir):
|
@py.test.mark.xfail("sys.version_info[:2] == (2,7)")
|
||||||
|
def test_dist_conftest_options(testdir, recwarn):
|
||||||
p1 = testdir.tmpdir.ensure("dir", 'p1.py')
|
p1 = testdir.tmpdir.ensure("dir", 'p1.py')
|
||||||
p1.dirpath("__init__.py").write("")
|
p1.dirpath("__init__.py").write("")
|
||||||
p1.dirpath("conftest.py").write(py.code.Source("""
|
p1.dirpath("conftest.py").write(py.code.Source("""
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ class TestLooponFailing:
|
|||||||
x = 0
|
x = 0
|
||||||
assert x == 1
|
assert x == 1
|
||||||
""")
|
""")
|
||||||
child = testdir.spawn_pytest("-f %s" % p)
|
child = testdir.spawn_pytest("-f %s --traceconfig" % p)
|
||||||
child.expect("def test_one")
|
child.expect("def test_one")
|
||||||
child.expect("x == 1")
|
child.expect("x == 1")
|
||||||
child.expect("1 failed")
|
child.expect("1 failed")
|
||||||
@@ -146,3 +146,16 @@ class TestLooponFailing:
|
|||||||
child.expect(".*1 passed.*")
|
child.expect(".*1 passed.*")
|
||||||
child.kill(15)
|
child.kill(15)
|
||||||
|
|
||||||
|
def test_looponfail_xfail_passes(self, testdir):
|
||||||
|
p = testdir.makepyfile("""
|
||||||
|
import py
|
||||||
|
@py.test.mark.xfail
|
||||||
|
def test_one():
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
child = testdir.spawn_pytest("-f %s" % p)
|
||||||
|
child.expect("1 xpass")
|
||||||
|
child.expect("### LOOPONFAILING ####")
|
||||||
|
child.expect("waiting for changes")
|
||||||
|
child.kill(15)
|
||||||
|
|
||||||
|
|||||||
@@ -42,13 +42,13 @@ class MySetup:
|
|||||||
eq = EventQueue(self.config.pluginmanager, self.queue)
|
eq = EventQueue(self.config.pluginmanager, self.queue)
|
||||||
return eq.geteventargs(eventname, timeout=timeout)
|
return eq.geteventargs(eventname, timeout=timeout)
|
||||||
|
|
||||||
def makenode(self, config=None):
|
def makenode(self, config=None, xspec="popen"):
|
||||||
if config is None:
|
if config is None:
|
||||||
testdir = self.request.getfuncargvalue("testdir")
|
testdir = self.request.getfuncargvalue("testdir")
|
||||||
config = testdir.reparseconfig([])
|
config = testdir.reparseconfig([])
|
||||||
self.config = config
|
self.config = config
|
||||||
self.queue = Queue()
|
self.queue = Queue()
|
||||||
self.xspec = execnet.XSpec("popen")
|
self.xspec = execnet.XSpec(xspec)
|
||||||
self.gateway = execnet.makegateway(self.xspec)
|
self.gateway = execnet.makegateway(self.xspec)
|
||||||
self.id += 1
|
self.id += 1
|
||||||
self.gateway.id = str(self.id)
|
self.gateway.id = str(self.id)
|
||||||
@@ -147,3 +147,26 @@ class TestMasterSlaveConnection:
|
|||||||
for outcome in "passed failed skipped".split():
|
for outcome in "passed failed skipped".split():
|
||||||
rep = mysetup.geteventargs("pytest_runtest_logreport")['report']
|
rep = mysetup.geteventargs("pytest_runtest_logreport")['report']
|
||||||
assert getattr(rep, outcome)
|
assert getattr(rep, outcome)
|
||||||
|
|
||||||
|
def test_send_one_with_env(self, testdir, mysetup, monkeypatch):
|
||||||
|
if execnet.XSpec("popen").env is None:
|
||||||
|
py.test.skip("requires execnet 1.0.7 or above")
|
||||||
|
monkeypatch.delenv('ENV1', raising=False)
|
||||||
|
monkeypatch.delenv('ENV2', raising=False)
|
||||||
|
monkeypatch.setenv('ENV3', 'var3')
|
||||||
|
|
||||||
|
item = testdir.getitem("""
|
||||||
|
def test_func():
|
||||||
|
import os
|
||||||
|
# ENV1, ENV2 set by xspec; ENV3 inherited from parent process
|
||||||
|
assert os.getenv('ENV2') == 'var2'
|
||||||
|
assert os.getenv('ENV1') == 'var1'
|
||||||
|
assert os.getenv('ENV3') == 'var3'
|
||||||
|
""")
|
||||||
|
node = mysetup.makenode(item.config,
|
||||||
|
xspec="popen//env:ENV1=var1//env:ENV2=var2")
|
||||||
|
node.send(item)
|
||||||
|
kwargs = mysetup.geteventargs("pytest_runtest_logreport")
|
||||||
|
rep = kwargs['report']
|
||||||
|
assert rep.passed
|
||||||
|
|
||||||
|
|||||||
35
tox.ini
Normal file
35
tox.ini
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
[tox]
|
||||||
|
distshare={homedir}/.tox/distshare
|
||||||
|
envlist=py26,py31,py27,py25,py24
|
||||||
|
[tox:hudson]
|
||||||
|
distshare={toxworkdir}/distshare
|
||||||
|
sdistsrc={distshare}/pytest-xdist-*
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
changedir=testing
|
||||||
|
deps=
|
||||||
|
{distshare}/py-*
|
||||||
|
commands=
|
||||||
|
py.test -rsfxX --tools-on-path \
|
||||||
|
--junitxml={envlogdir}/junit-{envname}.xml []
|
||||||
|
[testenv:py27]
|
||||||
|
basepython=python2.7
|
||||||
|
[testenv:py26]
|
||||||
|
basepython=python2.6
|
||||||
|
deps=
|
||||||
|
{distshare}/py-*
|
||||||
|
pexpect
|
||||||
|
#[testenv:py26-py132]
|
||||||
|
#basepython=python2.6
|
||||||
|
#deps= py==1.3.2
|
||||||
|
# execnet==1.0.6
|
||||||
|
[testenv:py25]
|
||||||
|
basepython=python2.5
|
||||||
|
[testenv:py24]
|
||||||
|
basepython=python2.4
|
||||||
|
[testenv:py31]
|
||||||
|
basepython=python3.1
|
||||||
|
#[testenv:pypy]
|
||||||
|
#basepython=pypy-c
|
||||||
|
[testenv:jython]
|
||||||
|
basepython=jython
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
#
|
#
|
||||||
__version__ = "1.3"
|
__version__ = "1.4"
|
||||||
|
|
||||||
|
|||||||
@@ -100,9 +100,12 @@ class DSession(session.Session):
|
|||||||
return exitstatus
|
return exitstatus
|
||||||
|
|
||||||
def collect_all_items(self, colitems):
|
def collect_all_items(self, colitems):
|
||||||
self.report_line("[master] starting full item collection ...")
|
verbose = self.config.getvalue("verbose")
|
||||||
|
if verbose:
|
||||||
|
self.report_line("[master] starting full item collection ...")
|
||||||
allitems = list(self.collect(colitems))
|
allitems = list(self.collect(colitems))
|
||||||
self.report_line("[master] collected %d items" %(len(allitems)))
|
if verbose:
|
||||||
|
self.report_line("[master] collected %d items" %(len(allitems)))
|
||||||
return allitems
|
return allitems
|
||||||
|
|
||||||
def loop_once(self, loopstate):
|
def loop_once(self, loopstate):
|
||||||
@@ -286,6 +289,9 @@ class DSession(session.Session):
|
|||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
""" setup any neccessary resources ahead of the test run. """
|
""" setup any neccessary resources ahead of the test run. """
|
||||||
|
if not self.config.getvalue("verbose"):
|
||||||
|
self.report_line("instantiating gateways (use -v for details): %s" %
|
||||||
|
",".join(self.config.option.tx))
|
||||||
self.nodemanager = NodeManager(self.config)
|
self.nodemanager = NodeManager(self.config)
|
||||||
self.nodemanager.setup_nodes(putevent=self.queue.put)
|
self.nodemanager.setup_nodes(putevent=self.queue.put)
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,4 @@ def pytest_testnodedown(node, error):
|
|||||||
def pytest_rescheduleitems(items):
|
def pytest_rescheduleitems(items):
|
||||||
""" reschedule Items from a node that went down. """
|
""" reschedule Items from a node that went down. """
|
||||||
|
|
||||||
def pytest_looponfailinfo(failreports, rootdirs):
|
|
||||||
""" info for repeating failing tests. """
|
|
||||||
|
|
||||||
|
|||||||
@@ -197,11 +197,23 @@ def pytest_configure(config):
|
|||||||
raise config.Error("--pdb incompatible with --looponfail.")
|
raise config.Error("--pdb incompatible with --looponfail.")
|
||||||
from xdist.remote import LooponfailingSession
|
from xdist.remote import LooponfailingSession
|
||||||
config.setsessionclass(LooponfailingSession)
|
config.setsessionclass(LooponfailingSession)
|
||||||
|
config._isdistsession = True
|
||||||
elif val("dist") != "no":
|
elif val("dist") != "no":
|
||||||
if usepdb:
|
if usepdb:
|
||||||
raise config.Error("--pdb incompatible with distributing tests.")
|
raise config.Error("--pdb incompatible with distributing tests.")
|
||||||
from xdist.dsession import DSession
|
from xdist.dsession import DSession
|
||||||
config.setsessionclass(DSession)
|
config.setsessionclass(DSession)
|
||||||
|
config._isdistsession = True
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_sessionstart(session):
|
||||||
|
config = session.config
|
||||||
|
if hasattr(config, '_isdistsession'):
|
||||||
|
if not config.pluginmanager.hasplugin("terminal") or \
|
||||||
|
not config.pluginmanager.hasplugin("terminalreporter"):
|
||||||
|
return
|
||||||
|
trdist = TerminalDistReporter(config)
|
||||||
|
config.pluginmanager.register(trdist, "terminaldistreporter")
|
||||||
|
|
||||||
def pytest_runtest_protocol(item):
|
def pytest_runtest_protocol(item):
|
||||||
if item.config.getvalue("boxed"):
|
if item.config.getvalue("boxed"):
|
||||||
@@ -244,3 +256,59 @@ def report_process_crash(item, result):
|
|||||||
from py._plugin.pytest_runner import ItemTestReport
|
from py._plugin.pytest_runner import ItemTestReport
|
||||||
return ItemTestReport(item, excinfo=info, when="???")
|
return ItemTestReport(item, excinfo=info, when="???")
|
||||||
|
|
||||||
|
class TerminalDistReporter:
|
||||||
|
def __init__(self, config):
|
||||||
|
self.gateway2info = {}
|
||||||
|
self.config = config
|
||||||
|
self.tplugin = config.pluginmanager.getplugin("terminal")
|
||||||
|
self.tr = config.pluginmanager.getplugin("terminalreporter")
|
||||||
|
|
||||||
|
def write_line(self, msg):
|
||||||
|
self.tr.write_line(msg)
|
||||||
|
|
||||||
|
def pytest_itemstart(self, __multicall__):
|
||||||
|
try:
|
||||||
|
__multicall__.methods.remove(self.tr.pytest_itemstart)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def pytest_runtest_logreport(self, report):
|
||||||
|
if hasattr(report, 'node'):
|
||||||
|
report.headerlines.append(self.gateway2info.get(
|
||||||
|
report.node.gateway,
|
||||||
|
"node %r (platinfo not found? strange)"))
|
||||||
|
|
||||||
|
def pytest_gwmanage_newgateway(self, gateway, platinfo):
|
||||||
|
#self.write_line("%s instantiated gateway from spec %r" %(gateway.id, gateway.spec._spec))
|
||||||
|
d = {}
|
||||||
|
d['version'] = self.tplugin.repr_pythonversion(platinfo.version_info)
|
||||||
|
d['id'] = gateway.id
|
||||||
|
d['spec'] = gateway.spec._spec
|
||||||
|
d['platform'] = platinfo.platform
|
||||||
|
if self.config.option.verbose:
|
||||||
|
d['extra'] = "- " + platinfo.executable
|
||||||
|
else:
|
||||||
|
d['extra'] = ""
|
||||||
|
d['cwd'] = platinfo.cwd
|
||||||
|
infoline = ("[%(id)s] %(spec)s -- platform %(platform)s, "
|
||||||
|
"Python %(version)s "
|
||||||
|
"cwd: %(cwd)s"
|
||||||
|
"%(extra)s" % d)
|
||||||
|
if self.config.getvalue("verbose"):
|
||||||
|
self.write_line(infoline)
|
||||||
|
self.gateway2info[gateway] = infoline
|
||||||
|
|
||||||
|
def pytest_testnodeready(self, node):
|
||||||
|
if self.config.getvalue("verbose"):
|
||||||
|
self.write_line(
|
||||||
|
"[%s] txnode ready to receive tests" %(node.gateway.id,))
|
||||||
|
|
||||||
|
def pytest_testnodedown(self, node, error):
|
||||||
|
if not error:
|
||||||
|
return
|
||||||
|
self.write_line("[%s] node down, error: %s" %(node.gateway.id, error))
|
||||||
|
|
||||||
|
def pytest_rescheduleitems(self, items):
|
||||||
|
if self.config.option.debug:
|
||||||
|
self.write_sep("!", "RESCHEDULING %s " %(items,))
|
||||||
|
|
||||||
|
|||||||
@@ -169,8 +169,21 @@ def slave_runsession(channel, config, fullwidth, hasmarkup):
|
|||||||
|
|
||||||
DEBUG("SLAVE: starting session.main()")
|
DEBUG("SLAVE: starting session.main()")
|
||||||
session.main(colitems)
|
session.main(colitems)
|
||||||
session.config.hook.pytest_looponfailinfo(
|
repr_pytest_looponfailinfo(
|
||||||
failreports=list(failreports),
|
failreports=list(failreports),
|
||||||
rootdirs=[config.topdir])
|
rootdirs=[config.topdir])
|
||||||
rootcol = session.config._rootcol
|
rootcol = session.config._rootcol
|
||||||
channel.send([rootcol.totrail(rep.getnode()) for rep in failreports])
|
channel.send([rootcol.totrail(rep.getnode()) for rep in failreports])
|
||||||
|
|
||||||
|
|
||||||
|
def repr_pytest_looponfailinfo(failreports, rootdirs):
|
||||||
|
tr = py.io.TerminalWriter()
|
||||||
|
if failreports:
|
||||||
|
tr.sep("#", "LOOPONFAILING", red=True)
|
||||||
|
for report in failreports:
|
||||||
|
loc = report._getcrashline()
|
||||||
|
if loc:
|
||||||
|
tr.line(loc, red=True)
|
||||||
|
tr.sep("#", "waiting for changes")
|
||||||
|
for rootdir in rootdirs:
|
||||||
|
tr.line("### Watching: %s" %(rootdir,), bold=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user