Add captured log msgs to junit xml file
For each test this adds the captured log msgs to a system-* tag in the junit xml output file. The destination of the system-* tag is specified by junit_logging ini option.
This commit is contained in:
parent
f2fb841b29
commit
c0ef4a4d35
|
@ -130,10 +130,47 @@ class _NodeReporter(object):
|
||||||
self.append(node)
|
self.append(node)
|
||||||
|
|
||||||
def write_captured_output(self, report):
|
def write_captured_output(self, report):
|
||||||
for capname in ('out', 'err'):
|
content_out = report.capstdout
|
||||||
content = getattr(report, 'capstd' + capname)
|
content_log = report.caplog
|
||||||
|
content_err = report.capstderr
|
||||||
|
|
||||||
|
if content_log or content_out:
|
||||||
|
if content_log and self.xml.logging == 'system-out':
|
||||||
|
if content_out:
|
||||||
|
# syncing stdout and the log-output is not done yet. It's
|
||||||
|
# probably not worth the effort. Therefore, first the captured
|
||||||
|
# stdout is shown and then the captured logs.
|
||||||
|
content = '\n'.join([
|
||||||
|
' Captured Stdout '.center(80, '-'),
|
||||||
|
content_out,
|
||||||
|
'',
|
||||||
|
' Captured Log '.center(80, '-'),
|
||||||
|
content_log])
|
||||||
|
else:
|
||||||
|
content = content_log
|
||||||
|
else:
|
||||||
|
content = content_out
|
||||||
|
|
||||||
if content:
|
if content:
|
||||||
tag = getattr(Junit, 'system-' + capname)
|
tag = getattr(Junit, 'system-out')
|
||||||
|
self.append(tag(bin_xml_escape(content)))
|
||||||
|
|
||||||
|
if content_log or content_err:
|
||||||
|
if content_log and self.xml.logging == 'system-err':
|
||||||
|
if content_err:
|
||||||
|
content = '\n'.join([
|
||||||
|
' Captured Stderr '.center(80, '-'),
|
||||||
|
content_err,
|
||||||
|
'',
|
||||||
|
' Captured Log '.center(80, '-'),
|
||||||
|
content_log])
|
||||||
|
else:
|
||||||
|
content = content_log
|
||||||
|
else:
|
||||||
|
content = content_err
|
||||||
|
|
||||||
|
if content:
|
||||||
|
tag = getattr(Junit, 'system-err')
|
||||||
self.append(tag(bin_xml_escape(content)))
|
self.append(tag(bin_xml_escape(content)))
|
||||||
|
|
||||||
def append_pass(self, report):
|
def append_pass(self, report):
|
||||||
|
@ -254,13 +291,18 @@ def pytest_addoption(parser):
|
||||||
default=None,
|
default=None,
|
||||||
help="prepend prefix to classnames in junit-xml output")
|
help="prepend prefix to classnames in junit-xml output")
|
||||||
parser.addini("junit_suite_name", "Test suite name for JUnit report", default="pytest")
|
parser.addini("junit_suite_name", "Test suite name for JUnit report", default="pytest")
|
||||||
|
parser.addini("junit_logging", "Write captured log messages to JUnit report: "
|
||||||
|
"one of no|system-out|system-err",
|
||||||
|
default="no") # choices=['no', 'stdout', 'stderr'])
|
||||||
|
|
||||||
|
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
xmlpath = config.option.xmlpath
|
xmlpath = config.option.xmlpath
|
||||||
# prevent opening xmllog on slave nodes (xdist)
|
# prevent opening xmllog on slave nodes (xdist)
|
||||||
if xmlpath and not hasattr(config, 'slaveinput'):
|
if xmlpath and not hasattr(config, 'slaveinput'):
|
||||||
config._xml = LogXML(xmlpath, config.option.junitprefix, config.getini("junit_suite_name"))
|
config._xml = LogXML(xmlpath, config.option.junitprefix,
|
||||||
|
config.getini("junit_suite_name"),
|
||||||
|
config.getini("junit_logging"))
|
||||||
config.pluginmanager.register(config._xml)
|
config.pluginmanager.register(config._xml)
|
||||||
|
|
||||||
|
|
||||||
|
@ -287,11 +329,12 @@ def mangle_test_address(address):
|
||||||
|
|
||||||
|
|
||||||
class LogXML(object):
|
class LogXML(object):
|
||||||
def __init__(self, logfile, prefix, suite_name="pytest"):
|
def __init__(self, logfile, prefix, suite_name="pytest", logging="no"):
|
||||||
logfile = os.path.expanduser(os.path.expandvars(logfile))
|
logfile = os.path.expanduser(os.path.expandvars(logfile))
|
||||||
self.logfile = os.path.normpath(os.path.abspath(logfile))
|
self.logfile = os.path.normpath(os.path.abspath(logfile))
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
self.suite_name = suite_name
|
self.suite_name = suite_name
|
||||||
|
self.logging = logging
|
||||||
self.stats = dict.fromkeys([
|
self.stats = dict.fromkeys([
|
||||||
'error',
|
'error',
|
||||||
'passed',
|
'passed',
|
||||||
|
|
|
@ -256,6 +256,14 @@ class BaseReport(object):
|
||||||
exc = tw.stringio.getvalue()
|
exc = tw.stringio.getvalue()
|
||||||
return exc.strip()
|
return exc.strip()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def caplog(self):
|
||||||
|
"""Return captured log lines, if log capturing is enabled
|
||||||
|
|
||||||
|
.. versionadded:: 3.4
|
||||||
|
"""
|
||||||
|
return '\n'.join(content for (prefix, content) in self.get_sections('Captured log'))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def capstdout(self):
|
def capstdout(self):
|
||||||
"""Return captured text from stdout, if capturing is enabled
|
"""Return captured text from stdout, if capturing is enabled
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Captured log messages are added to the ``<system-out>`` tag in the generated junit xml file if the ``junit_logging`` ini option is set to ``system-out``. If the value of this ini option is ``system-err`, the logs are written to ``<system-err>``. The default value for ``junit_logging`` is ``no``, meaning captured logs are not written to the output file.
|
|
@ -328,23 +328,28 @@ class TestPython(object):
|
||||||
fnode.assert_attr(message="internal error")
|
fnode.assert_attr(message="internal error")
|
||||||
assert "Division" in fnode.toxml()
|
assert "Division" in fnode.toxml()
|
||||||
|
|
||||||
def test_failure_function(self, testdir):
|
@pytest.mark.parametrize('junit_logging', ['no', 'system-out', 'system-err'])
|
||||||
|
def test_failure_function(self, testdir, junit_logging):
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile("""
|
||||||
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def test_fail():
|
def test_fail():
|
||||||
print ("hello-stdout")
|
print ("hello-stdout")
|
||||||
sys.stderr.write("hello-stderr\\n")
|
sys.stderr.write("hello-stderr\\n")
|
||||||
|
logging.info('info msg')
|
||||||
|
logging.warning('warning msg')
|
||||||
raise ValueError(42)
|
raise ValueError(42)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
result, dom = runandparse(testdir)
|
result, dom = runandparse(testdir, '-o', 'junit_logging=%s' % junit_logging)
|
||||||
assert result.ret
|
assert result.ret
|
||||||
node = dom.find_first_by_tag("testsuite")
|
node = dom.find_first_by_tag("testsuite")
|
||||||
node.assert_attr(failures=1, tests=1)
|
node.assert_attr(failures=1, tests=1)
|
||||||
tnode = node.find_first_by_tag("testcase")
|
tnode = node.find_first_by_tag("testcase")
|
||||||
tnode.assert_attr(
|
tnode.assert_attr(
|
||||||
file="test_failure_function.py",
|
file="test_failure_function.py",
|
||||||
line="1",
|
line="3",
|
||||||
classname="test_failure_function",
|
classname="test_failure_function",
|
||||||
name="test_fail")
|
name="test_fail")
|
||||||
fnode = tnode.find_first_by_tag("failure")
|
fnode = tnode.find_first_by_tag("failure")
|
||||||
|
@ -353,9 +358,21 @@ class TestPython(object):
|
||||||
systemout = fnode.next_siebling
|
systemout = fnode.next_siebling
|
||||||
assert systemout.tag == "system-out"
|
assert systemout.tag == "system-out"
|
||||||
assert "hello-stdout" in systemout.toxml()
|
assert "hello-stdout" in systemout.toxml()
|
||||||
|
assert "info msg" not in systemout.toxml()
|
||||||
systemerr = systemout.next_siebling
|
systemerr = systemout.next_siebling
|
||||||
assert systemerr.tag == "system-err"
|
assert systemerr.tag == "system-err"
|
||||||
assert "hello-stderr" in systemerr.toxml()
|
assert "hello-stderr" in systemerr.toxml()
|
||||||
|
assert "info msg" not in systemerr.toxml()
|
||||||
|
|
||||||
|
if junit_logging == 'system-out':
|
||||||
|
assert "warning msg" in systemout.toxml()
|
||||||
|
assert "warning msg" not in systemerr.toxml()
|
||||||
|
elif junit_logging == 'system-err':
|
||||||
|
assert "warning msg" not in systemout.toxml()
|
||||||
|
assert "warning msg" in systemerr.toxml()
|
||||||
|
elif junit_logging == 'no':
|
||||||
|
assert "warning msg" not in systemout.toxml()
|
||||||
|
assert "warning msg" not in systemerr.toxml()
|
||||||
|
|
||||||
def test_failure_verbose_message(self, testdir):
|
def test_failure_verbose_message(self, testdir):
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile("""
|
||||||
|
|
Loading…
Reference in New Issue