fix distributed testing reporting details
This commit is contained in:
@@ -51,8 +51,7 @@ class TestDistribution:
|
|||||||
)
|
)
|
||||||
result = testdir.runpytest(p1, "-v", '-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*",
|
"*1*Python*",
|
||||||
"*1*popen*Python*",
|
|
||||||
"*2 failed, 1 passed, 1 skipped*",
|
"*2 failed, 1 passed, 1 skipped*",
|
||||||
])
|
])
|
||||||
assert result.ret == 1
|
assert result.ret == 1
|
||||||
@@ -89,9 +88,7 @@ class TestDistribution:
|
|||||||
""")
|
""")
|
||||||
result = testdir.runpytest(p1, '-d', "-v")
|
result = testdir.runpytest(p1, '-d', "-v")
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*0*popen*Python*",
|
"*2*Python*",
|
||||||
"*1*popen*Python*",
|
|
||||||
"*2*popen*Python*",
|
|
||||||
"*2 failed, 1 passed, 1 skipped*",
|
"*2 failed, 1 passed, 1 skipped*",
|
||||||
])
|
])
|
||||||
assert result.ret == 1
|
assert result.ret == 1
|
||||||
@@ -120,8 +117,8 @@ class TestDistribution:
|
|||||||
)
|
)
|
||||||
result = testdir.runpytest(p1, "-v", '-d', '-n1')
|
result = testdir.runpytest(p1, "-v", '-d', '-n1')
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*popen*Python*",
|
"*Python*",
|
||||||
"*test_ok*PASS*",
|
"*PASS**test_ok*",
|
||||||
"*node*down*",
|
"*node*down*",
|
||||||
"*3 failed, 1 passed, 1 skipped*"
|
"*3 failed, 1 passed, 1 skipped*"
|
||||||
])
|
])
|
||||||
@@ -139,7 +136,7 @@ class TestDistribution:
|
|||||||
"--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([
|
||||||
"*0* *popen*platform*",
|
"*0* *cwd*",
|
||||||
#"RSyncStart: [G1]",
|
#"RSyncStart: [G1]",
|
||||||
#"RSyncFinished: [G1]",
|
#"RSyncFinished: [G1]",
|
||||||
"*1 passed*"
|
"*1 passed*"
|
||||||
@@ -196,7 +193,7 @@ class TestDistribution:
|
|||||||
p1 = testdir.makepyfile("def test_func(): pass")
|
p1 = testdir.makepyfile("def test_func(): pass")
|
||||||
result = testdir.runpytest("-v", p1, '-d', '--tx=popen')
|
result = testdir.runpytest("-v", p1, '-d', '--tx=popen')
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*popen*Python*",
|
"*0*Python*",
|
||||||
"*calculated result is 49*",
|
"*calculated result is 49*",
|
||||||
"*1 passed*"
|
"*1 passed*"
|
||||||
])
|
])
|
||||||
@@ -251,15 +248,13 @@ class TestTerminalReporting:
|
|||||||
assert 0
|
assert 0
|
||||||
""")
|
""")
|
||||||
result = testdir.runpytest("-n1", "-v")
|
result = testdir.runpytest("-n1", "-v")
|
||||||
expected = [
|
result.stdout.fnmatch_lines_random([
|
||||||
"*PASS*test_pass_skip_fail.py:2: *test_ok*",
|
"*PASS*test_pass_skip_fail.py:2: *test_ok*",
|
||||||
"*SKIP*test_pass_skip_fail.py:4: *test_skip*",
|
"*SKIP*test_pass_skip_fail.py:4: *test_skip*",
|
||||||
"*FAIL*test_pass_skip_fail.py:6: *test_func*",
|
"*FAIL*test_pass_skip_fail.py:6: *test_func*",
|
||||||
]
|
])
|
||||||
for line in expected:
|
|
||||||
result.stdout.fnmatch_lines([line])
|
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
" def test_func():",
|
"*def test_func():",
|
||||||
"> assert 0",
|
"> assert 0",
|
||||||
"E assert 0",
|
"E assert 0",
|
||||||
])
|
])
|
||||||
@@ -272,8 +267,8 @@ class TestTerminalReporting:
|
|||||||
result = testdir.runpytest("-n1", "-v")
|
result = testdir.runpytest("-n1", "-v")
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*FAIL*test_fail_platinfo.py:1: *test_func*",
|
"*FAIL*test_fail_platinfo.py:1: *test_func*",
|
||||||
"*popen*Python*",
|
"*0*Python*",
|
||||||
" def test_func():",
|
"*def test_func():",
|
||||||
"> assert 0",
|
"> assert 0",
|
||||||
"E assert 0",
|
"E assert 0",
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -156,7 +156,11 @@ class DSession:
|
|||||||
exitstatus=exitstatus,)
|
exitstatus=exitstatus,)
|
||||||
return exitstatus
|
return exitstatus
|
||||||
|
|
||||||
def slave_slaveready(self, node):
|
def slave_slaveready(self, node, slaveinfo):
|
||||||
|
node.slaveinfo = slaveinfo
|
||||||
|
node.slaveinfo['id'] = node.gateway.id
|
||||||
|
node.slaveinfo['spec'] = node.gateway.spec
|
||||||
|
self.config.hook.pytest_testnodeready(node=node)
|
||||||
self.sched.addnode(node)
|
self.sched.addnode(node)
|
||||||
if self.shuttingdown:
|
if self.shuttingdown:
|
||||||
node.shutdown()
|
node.shutdown()
|
||||||
@@ -173,7 +177,7 @@ class DSession:
|
|||||||
self.session_finished = True
|
self.session_finished = True
|
||||||
|
|
||||||
def slave_errordown(self, node, error):
|
def slave_errordown(self, node, error):
|
||||||
self.report_line("node %r down on error: %s" %(node.gateway.id, error,))
|
self.config.hook.pytest_testnodedown(node=node, error=error)
|
||||||
crashitem = self.sched.remove_node(node)
|
crashitem = self.sched.remove_node(node)
|
||||||
if crashitem:
|
if crashitem:
|
||||||
self.handle_crashitem(crashitem, node)
|
self.handle_crashitem(crashitem, node)
|
||||||
@@ -197,11 +201,13 @@ class DSession:
|
|||||||
def slave_testreport(self, node, rep):
|
def slave_testreport(self, node, rep):
|
||||||
self.sched.remove_item(node, rep.nodeid)
|
self.sched.remove_item(node, rep.nodeid)
|
||||||
#self.report_line("testreport %s: %s" %(rep.id, rep.status))
|
#self.report_line("testreport %s: %s" %(rep.id, rep.status))
|
||||||
|
enrich_report_with_platform_data(rep, node)
|
||||||
self.config.hook.pytest_runtest_logreport(report=rep)
|
self.config.hook.pytest_runtest_logreport(report=rep)
|
||||||
self._handlefailures(rep)
|
self._handlefailures(rep)
|
||||||
|
|
||||||
def slave_collectreport(self, node, rep):
|
def slave_collectreport(self, node, rep):
|
||||||
#self.report_line("collectreport %s: %s" %(rep.id, rep.status))
|
#self.report_line("collectreport %s: %s" %(rep.id, rep.status))
|
||||||
|
#rep.node = node
|
||||||
self._handlefailures(rep)
|
self._handlefailures(rep)
|
||||||
|
|
||||||
def _handlefailures(self, rep):
|
def _handlefailures(self, rep):
|
||||||
@@ -263,6 +269,7 @@ class DSession:
|
|||||||
msg = "Slave %r crashed while running %r" %(slave.gateway.id, nodeid)
|
msg = "Slave %r crashed while running %r" %(slave.gateway.id, nodeid)
|
||||||
rep = runner.TestReport(nodeid, (), fspath, (fspath, None, fspath), (),
|
rep = runner.TestReport(nodeid, (), fspath, (fspath, None, fspath), (),
|
||||||
"failed", msg, "???")
|
"failed", msg, "???")
|
||||||
|
enrich_report_with_platform_data(rep, slave)
|
||||||
self.config.hook.pytest_runtest_logreport(report=rep)
|
self.config.hook.pytest_runtest_logreport(report=rep)
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
@@ -279,52 +286,39 @@ class DSession:
|
|||||||
|
|
||||||
class TerminalDistReporter:
|
class TerminalDistReporter:
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.gateway2info = {}
|
|
||||||
self.config = config
|
self.config = config
|
||||||
self.tplugin = config.pluginmanager.getplugin("terminal")
|
|
||||||
self.tr = config.pluginmanager.getplugin("terminalreporter")
|
self.tr = config.pluginmanager.getplugin("terminalreporter")
|
||||||
|
|
||||||
def write_line(self, msg):
|
def write_line(self, msg):
|
||||||
self.tr.write_line(msg)
|
self.tr.write_line(msg)
|
||||||
|
|
||||||
def pytest_itemstart(self, __multicall__):
|
def pytest_gwmanage_newgateway(self, gateway):
|
||||||
try:
|
rinfo = gateway._rinfo()
|
||||||
__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"):
|
if self.config.getvalue("verbose"):
|
||||||
self.write_line(infoline)
|
version = "%s.%s.%s" %rinfo.version_info[:3]
|
||||||
self.gateway2info[gateway] = infoline
|
self.write_line("[%s] %s Python %s cwd: %s" % (
|
||||||
|
gateway.id, rinfo.platform, version, rinfo.cwd))
|
||||||
|
|
||||||
def pytest_testnodeready(self, node):
|
def pytest_testnodeready(self, node):
|
||||||
if self.config.getvalue("verbose"):
|
if self.config.getvalue("debug"):
|
||||||
self.write_line(
|
d = node.slaveinfo
|
||||||
"[%s] txnode ready to receive tests" %(node.gateway.id,))
|
infoline = "[%s] -- Python %s" %(
|
||||||
|
d['id'],
|
||||||
|
d['version'].replace('\n', ' -- '),)
|
||||||
|
self.write_line(infoline)
|
||||||
|
|
||||||
def pytest_testnodedown(self, node, error):
|
def pytest_testnodedown(self, node, error):
|
||||||
if not error:
|
if not error:
|
||||||
return
|
return
|
||||||
self.write_line("[%s] node down, error: %s" %(node.gateway.id, error))
|
self.write_line("[%s] node down: %s" %(node.gateway.id, error))
|
||||||
|
|
||||||
|
def enrich_report_with_platform_data(rep, node):
|
||||||
|
rep.node = node
|
||||||
|
if hasattr(rep, 'node') and rep.longrepr:
|
||||||
|
d = node.slaveinfo
|
||||||
|
ver = "%s.%s.%s" % d['version_info'][:3]
|
||||||
|
infoline = "[%s] %s -- Python %s %s" % (
|
||||||
|
d['id'], d['sysplatform'], ver, d['executable'])
|
||||||
|
# XXX more structured longrepr?
|
||||||
|
rep.longrepr = infoline + "\n\n" + str(rep.longrepr)
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ class GatewayManager:
|
|||||||
assert not list(self.group)
|
assert not list(self.group)
|
||||||
for spec in self.specs:
|
for spec in self.specs:
|
||||||
gw = self.group.makegateway(spec)
|
gw = self.group.makegateway(spec)
|
||||||
self.hook.pytest_gwmanage_newgateway(
|
self.hook.pytest_gwmanage_newgateway(gateway=gw)
|
||||||
gateway=gw, platinfo=gw._rinfo())
|
|
||||||
|
|
||||||
def rsync(self, source, notify=None, verbose=False, ignores=None):
|
def rsync(self, source, notify=None, verbose=False, ignores=None):
|
||||||
""" perform rsync to all remote hosts.
|
""" perform rsync to all remote hosts.
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class SlaveController(object):
|
|||||||
if eventname in ("collectionstart"):
|
if eventname in ("collectionstart"):
|
||||||
self.log("ignoring %s(%s)" %(eventname, kwargs))
|
self.log("ignoring %s(%s)" %(eventname, kwargs))
|
||||||
elif eventname == "slaveready":
|
elif eventname == "slaveready":
|
||||||
self.notify_inproc(eventname, node=self)
|
self.notify_inproc(eventname, node=self, **kwargs)
|
||||||
elif eventname == "slavefinished":
|
elif eventname == "slavefinished":
|
||||||
self._down = True
|
self._down = True
|
||||||
self.slaveoutput = kwargs['slaveoutput']
|
self.slaveoutput = kwargs['slaveoutput']
|
||||||
@@ -166,7 +166,8 @@ class SlaveInteractor:
|
|||||||
def pytest_sessionstart(self, session):
|
def pytest_sessionstart(self, session):
|
||||||
self.session = session
|
self.session = session
|
||||||
self.collection = session.collection
|
self.collection = session.collection
|
||||||
self.sendevent("slaveready")
|
slaveinfo = getinfodict()
|
||||||
|
self.sendevent("slaveready", slaveinfo=slaveinfo)
|
||||||
|
|
||||||
def pytest_sessionfinish(self, __multicall__, exitstatus):
|
def pytest_sessionfinish(self, __multicall__, exitstatus):
|
||||||
self.config.slaveoutput['exitstatus'] = exitstatus
|
self.config.slaveoutput['exitstatus'] = exitstatus
|
||||||
@@ -225,3 +226,13 @@ def unserialize_report(reportdict):
|
|||||||
else:
|
else:
|
||||||
return runner.TestReport(**d)
|
return runner.TestReport(**d)
|
||||||
|
|
||||||
|
def getinfodict():
|
||||||
|
import os, sys, platform
|
||||||
|
return dict(
|
||||||
|
version = sys.version,
|
||||||
|
version_info = tuple(sys.version_info),
|
||||||
|
sysplatform = sys.platform,
|
||||||
|
platform = platform.platform(),
|
||||||
|
executable = sys.executable,
|
||||||
|
cwd = os.getcwd(),
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user