Show a header for each testing phase during live logging
As suggested during review
This commit is contained in:
parent
29a7b5e064
commit
0df42b4426
|
@ -304,6 +304,8 @@ class LoggingPlugin(object):
|
|||
"""Implements the internals of pytest_runtest_xxx() hook."""
|
||||
with catching_logs(LogCaptureHandler(),
|
||||
formatter=self.formatter, level=self.log_level) as log_handler:
|
||||
if self.log_cli_handler:
|
||||
self.log_cli_handler.reset(item, when)
|
||||
if not hasattr(item, 'catch_log_handlers'):
|
||||
item.catch_log_handlers = {}
|
||||
item.catch_log_handlers[when] = log_handler
|
||||
|
@ -322,8 +324,6 @@ class LoggingPlugin(object):
|
|||
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
def pytest_runtest_setup(self, item):
|
||||
if self.log_cli_handler is not None:
|
||||
self.log_cli_handler.reset()
|
||||
with self._runtest_for(item, 'setup'):
|
||||
yield
|
||||
|
||||
|
@ -387,18 +387,28 @@ class _LiveLoggingStreamHandler(logging.StreamHandler):
|
|||
self.capture_manager = capture_manager
|
||||
self._first_record_emitted = False
|
||||
|
||||
def reset(self):
|
||||
self._section_name_shown = False
|
||||
self._when = None
|
||||
self._run_tests = set()
|
||||
|
||||
def reset(self, item, when):
|
||||
self._when = when
|
||||
self._section_name_shown = False
|
||||
if item.name not in self._run_tests:
|
||||
self._first_record_emitted = False
|
||||
self._run_tests.add(item.name)
|
||||
|
||||
def emit(self, record):
|
||||
if self.capture_manager is not None:
|
||||
self.capture_manager.suspend_global_capture()
|
||||
try:
|
||||
if not self._first_record_emitted:
|
||||
if not self._first_record_emitted or self._when == 'teardown':
|
||||
self.stream.write('\n')
|
||||
# we might consider adding a header at this point using self.stream.section('live log', sep='-')
|
||||
# or something similar when we improve live logging output
|
||||
self._first_record_emitted = True
|
||||
if not self._section_name_shown:
|
||||
header = 'live log' if self._when == 'call' else 'live log ' + self._when
|
||||
self.stream.section(header, sep='-', bold=True)
|
||||
self._section_name_shown = True
|
||||
logging.StreamHandler.emit(self, record)
|
||||
finally:
|
||||
if self.capture_manager is not None:
|
||||
|
|
|
@ -196,17 +196,16 @@ def test_log_cli_default_level(testdir):
|
|||
assert result.ret == 0
|
||||
|
||||
|
||||
def test_log_cli_default_level_multiple_tests(testdir):
|
||||
def test_log_cli_default_level_multiple_tests(testdir, request):
|
||||
"""Ensure we reset the first newline added by the live logger between tests"""
|
||||
# Default log file level
|
||||
filename = request.node.name + '.py'
|
||||
testdir.makepyfile('''
|
||||
import pytest
|
||||
import logging
|
||||
|
||||
def test_log_1(request):
|
||||
def test_log_1():
|
||||
logging.warning("log message from test_log_1")
|
||||
|
||||
def test_log_2(request):
|
||||
def test_log_2():
|
||||
logging.warning("log message from test_log_2")
|
||||
''')
|
||||
testdir.makeini('''
|
||||
|
@ -216,16 +215,63 @@ def test_log_cli_default_level_multiple_tests(testdir):
|
|||
|
||||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines([
|
||||
'test_log_cli_default_level_multiple_tests.py::test_log_1 ',
|
||||
'{}::test_log_1 '.format(filename),
|
||||
'*WARNING*log message from test_log_1*',
|
||||
'PASSED *50%*',
|
||||
'test_log_cli_default_level_multiple_tests.py::test_log_2 ',
|
||||
'{}::test_log_2 '.format(filename),
|
||||
'*WARNING*log message from test_log_2*',
|
||||
'PASSED *100%*',
|
||||
'=* 2 passed in *=',
|
||||
])
|
||||
|
||||
|
||||
def test_log_cli_default_level_sections(testdir, request):
|
||||
"""Check that with live logging enable we are printing the correct headers during setup/call/teardown."""
|
||||
filename = request.node.name + '.py'
|
||||
testdir.makepyfile('''
|
||||
import pytest
|
||||
import logging
|
||||
|
||||
@pytest.fixture
|
||||
def fix(request):
|
||||
logging.warning("log message from setup of {}".format(request.node.name))
|
||||
yield
|
||||
logging.warning("log message from teardown of {}".format(request.node.name))
|
||||
|
||||
def test_log_1(fix):
|
||||
logging.warning("log message from test_log_1")
|
||||
|
||||
def test_log_2(fix):
|
||||
logging.warning("log message from test_log_2")
|
||||
''')
|
||||
testdir.makeini('''
|
||||
[pytest]
|
||||
log_cli=true
|
||||
''')
|
||||
|
||||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines([
|
||||
'{}::test_log_1 '.format(filename),
|
||||
'*-- live log setup --*',
|
||||
'*WARNING*log message from setup of test_log_1*',
|
||||
'*-- live log --*',
|
||||
'*WARNING*log message from test_log_1*',
|
||||
'PASSED *50%*',
|
||||
'*-- live log teardown --*',
|
||||
'*WARNING*log message from teardown of test_log_1*',
|
||||
|
||||
'{}::test_log_2 '.format(filename),
|
||||
'*-- live log setup --*',
|
||||
'*WARNING*log message from setup of test_log_2*',
|
||||
'*-- live log --*',
|
||||
'*WARNING*log message from test_log_2*',
|
||||
'PASSED *100%*',
|
||||
'*-- live log teardown --*',
|
||||
'*WARNING*log message from teardown of test_log_2*',
|
||||
'=* 2 passed in *=',
|
||||
])
|
||||
|
||||
|
||||
def test_log_cli_level(testdir):
|
||||
# Default log file level
|
||||
testdir.makepyfile('''
|
||||
|
@ -473,11 +519,19 @@ def test_live_logging_suspends_capture(has_capture_manager, request):
|
|||
assert CaptureManager.suspend_capture_item
|
||||
assert CaptureManager.resume_global_capture
|
||||
|
||||
capture_manager = MockCaptureManager() if has_capture_manager else None
|
||||
out_file = six.StringIO()
|
||||
class DummyTerminal(six.StringIO):
|
||||
|
||||
def section(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
out_file = DummyTerminal()
|
||||
capture_manager = MockCaptureManager() if has_capture_manager else None
|
||||
handler = _LiveLoggingStreamHandler(out_file, capture_manager)
|
||||
|
||||
class DummyItem:
|
||||
name = 'test_foo'
|
||||
handler.reset(DummyItem(), 'call')
|
||||
|
||||
logger = logging.getLogger(__name__ + '.test_live_logging_suspends_capture')
|
||||
logger.addHandler(handler)
|
||||
request.addfinalizer(partial(logger.removeHandler, handler))
|
||||
|
|
Loading…
Reference in New Issue