Mini Shell
from logging import getLogger, ERROR, Filter
from textwrap import dedent
from unittest import TestCase
from warnings import catch_warnings
from testfixtures.shouldraise import ShouldAssert
from testfixtures.mock import Mock
from testfixtures import Replacer, LogCapture, compare, Replace
root = getLogger()
one = getLogger('one')
two = getLogger('two')
child = getLogger('one.child')
class DummyFilter(Filter):
def filter(self, _):
return True
class TestLogCapture(TestCase):
def test_simple(self):
root.info('before')
l = LogCapture()
root.info('during')
l.uninstall()
root.info('after')
assert str(l) == "root INFO\n during"
def test_simple_strict(self):
log_capture = LogCapture(ensure_checks_above=ERROR)
root.error('during')
log_capture.uninstall()
with ShouldAssert("Not asserted ERROR log(s): [('root', 'ERROR', 'during')]"):
log_capture.ensure_checked()
def test_simple_strict_re_defaulted(self):
with Replace('testfixtures.LogCapture.default_ensure_checks_above', ERROR):
LogCapture.default_ensure_checks_above = ERROR
log_capture = LogCapture()
root.error('during')
log_capture.uninstall()
with ShouldAssert("Not asserted ERROR log(s): [('root', 'ERROR', 'during')]"):
log_capture.ensure_checked()
def test_simple_strict_asserted_by_check(self):
log_capture = LogCapture(ensure_checks_above=ERROR)
root.error('during')
log_capture.uninstall()
log_capture.check(("root", "ERROR", "during"))
log_capture.ensure_checked()
def test_simple_strict_asserted_by_check_present_ordered(self):
log_capture = LogCapture(ensure_checks_above=ERROR)
root.error('during')
log_capture.uninstall()
log_capture.check_present(("root", "ERROR", "during"))
log_capture.ensure_checked()
def test_simple_strict_asserted_by_check_present_unordered(self):
log_capture = LogCapture(ensure_checks_above=ERROR)
root.error('during')
log_capture.uninstall()
log_capture.check_present(("root", "ERROR", "during"), order_matters=False)
log_capture.ensure_checked()
def test_simple_strict_not_asserted_by_check_present(self):
log_capture = LogCapture(ensure_checks_above=ERROR)
root.error('before')
root.error('during')
log_capture.uninstall()
log_capture.check_present(("root", "ERROR", "during"))
with ShouldAssert("Not asserted ERROR log(s): [('root', 'ERROR', 'before')]"):
log_capture.ensure_checked()
def test_simple_strict_asserted_by_containment(self):
log_capture = LogCapture(ensure_checks_above=ERROR)
root.error('during')
log_capture.uninstall()
assert ("root", "ERROR", "during") in log_capture
assert ("root", "INFO", "during") not in log_capture
log_capture.ensure_checked()
def test_simple_strict_asserted_by_mark_all_checked(self):
log_capture = LogCapture(ensure_checks_above=ERROR)
root.error('during')
log_capture.uninstall()
log_capture.mark_all_checked()
log_capture.ensure_checked()
def test_simple_strict_ctx(self):
with ShouldAssert("Not asserted ERROR log(s): [('root', 'ERROR', 'during')]"):
with LogCapture(ensure_checks_above=ERROR):
root.error('during')
def test_simple_strict_asserted_ctx(self):
with LogCapture(ensure_checks_above=ERROR) as log_capture:
root.error('during')
log_capture.check(("root", "ERROR", "during"))
def test_specific_logger(self):
l = LogCapture('one')
root.info('1')
one.info('2')
two.info('3')
child.info('4')
l.uninstall()
assert str(l) == (
"one INFO\n 2\n"
"one.child INFO\n 4"
)
def test_multiple_loggers(self):
l = LogCapture(('one.child','two'))
root.info('1')
one.info('2')
two.info('3')
child.info('4')
l.uninstall()
assert str(l) == (
"two INFO\n 3\n"
"one.child INFO\n 4"
)
def test_simple_manual_install(self):
l = LogCapture(install=False)
root.info('before')
l.install()
root.info('during')
l.uninstall()
root.info('after')
assert str(l) == "root INFO\n during"
def test_uninstall(self):
# Lets start off with a couple of loggers:
root = getLogger()
child = getLogger('child')
# Add a dummy filter so we can verify it is swapped out
# during the capture, and swapped back in after `uninstall`.
root.addFilter(DummyFilter())
# Lets also record the handlers for these loggers before
# we start the test:
before_root = root.handlers[:]
before_child = child.handlers[:]
# Lets also record the levels for the loggers:
old_root_level=root.level
old_child_level=child.level
# Also record the filters:
old_root_filters = root.filters[:]
old_child_filters = child.filters[:]
# Now the test:
try:
root.setLevel(49)
child.setLevel(69)
l1 = LogCapture()
l2 = LogCapture('child')
root = getLogger()
root.info('1')
child = getLogger('child')
assert root.level == 1
assert child.level == 1
assert root.filters == []
assert child.filters == []
child.info('2')
assert str(l1) == (
"root INFO\n 1\n"
"child INFO\n 2"
)
assert str(l2) == (
"child INFO\n 2"
)
# Add a dummy filter to the child,
# which should be removed by `uninstall`.
child.addFilter(DummyFilter())
l2.uninstall()
l1.uninstall()
assert root.level == 49
assert child.level == 69
finally:
root.setLevel(old_root_level)
child.setLevel(old_child_level)
# Now we check the handlers are as they were before
# the test:
assert root.handlers == before_root
assert child.handlers == before_child
# Also check the filters were restored:
assert root.filters == old_root_filters
assert child.filters == old_child_filters
def test_uninstall_all(self):
before_handlers_root = root.handlers[:]
before_handlers_child = child.handlers[:]
l1 = LogCapture()
l2 = LogCapture('one.child')
# We can see that the LogCaptures have changed the
# handlers, removing existing ones and installing
# their own:
assert len(root.handlers) == 1
assert root.handlers != before_handlers_root
assert len(child.handlers) == 1
assert child.handlers != before_handlers_child
# Now we show the function in action:
LogCapture.uninstall_all()
# ...and we can see the handlers are back as
# they were beefore:
assert before_handlers_root == root.handlers
assert before_handlers_child == child.handlers
def test_two_logcaptures_on_same_logger(self):
# If you create more than one LogCapture on a single
# logger, the 2nd one installed will stop the first
# one working!
l1 = LogCapture()
root.info('1st message')
assert str(l1) == "root INFO\n 1st message"
l2 = LogCapture()
root.info('2nd message')
# So, l1 missed this message:
assert str(l1) == "root INFO\n 1st message"
# ...because l2 kicked it out and recorded the message:
assert str(l2) == "root INFO\n 2nd message"
LogCapture.uninstall_all()
def test_uninstall_more_than_once(self):
# There's no problem with uninstalling a LogCapture
# more than once:
old_level = root.level
try:
root.setLevel(49)
l = LogCapture()
assert root.level == 1
l.uninstall()
assert root.level == 49
root.setLevel(69)
l.uninstall()
assert root.level == 69
finally:
root.setLevel(old_level)
# And even when loggers have been uninstalled, there's
# no problem having uninstall_all as a backstop:
l.uninstall_all()
def test_with_statement(self):
root.info('before')
with LogCapture() as l:
root.info('during')
root.info('after')
assert str(l) == "root INFO\n during"
class LogCaptureTests(TestCase):
def test_remove_existing_handlers(self):
logger = getLogger()
# get original handlers
original_handlers = logger.handlers
# put in a stub which will blow up if used
try:
logger.handlers = start = [object()]
with LogCapture() as l:
logger.info('during')
l.check(('root', 'INFO', 'during'))
compare(logger.handlers, start)
finally:
# only executed if the test fails
logger.handlers = original_handlers
def test_atexit(self):
# http://bugs.python.org/issue25532
from testfixtures.mock import call
m = Mock()
with Replacer() as r:
# make sure the marker is false, other tests will
# probably have set it
r.replace('testfixtures.LogCapture.atexit_setup', False)
r.replace('atexit.register', m.register)
l = LogCapture()
expected = [call.register(l.atexit)]
compare(expected, m.mock_calls)
with catch_warnings(record=True) as w:
l.atexit()
self.assertTrue(len(w), 1)
compare(str(w[0].message), (
"LogCapture instances not uninstalled by shutdown, "
"loggers captured:\n"
"(None,)"
))
l.uninstall()
compare(set(), LogCapture.instances)
# check re-running has no ill effects
l.atexit()
def test_numeric_log_level(self):
with LogCapture() as log:
getLogger().log(42, 'running in the family')
log.check(('root', 'Level 42', 'running in the family'))
def test_enable_disabled_logger(self):
logger = getLogger('disabled')
logger.disabled = True
with LogCapture('disabled') as log:
logger.info('a log message')
log.check(('disabled', 'INFO', 'a log message'))
compare(logger.disabled, True)
def test_no_propogate(self):
logger = getLogger('child')
# paranoid check
compare(logger.propagate, True)
with LogCapture() as global_log:
with LogCapture('child', propagate=False) as child_log:
logger.info('a log message')
child_log.check(('child', 'INFO', 'a log message'))
global_log.check()
compare(logger.propagate, True)
class TestCheckPresent(object):
def test_order_matters_ok(self):
with LogCapture() as log:
root.info('one')
root.error('junk')
root.warning('two')
root.error('junk')
root.error('three')
log.check_present(
('root', 'INFO', 'one'),
('root', 'WARNING', 'two'),
('root', 'ERROR', 'three'),
)
def test_order_matters_not_okay(self):
with LogCapture() as log:
root.error('junk')
with ShouldAssert(dedent("""\
ignored:
[('root', 'ERROR', 'junk')]
same:
[]
expected:
[('root', 'INFO', 'one')]
actual:
[]""")):
log.check_present(
('root', 'INFO', 'one'),
)
def test_order_matters_not_okay_recursive(self):
with LogCapture(recursive_check=True) as log:
root.error('junk')
with ShouldAssert(dedent("""\
same:
[]
expected:
[('root', 'INFO', 'one')]
actual:
[('root', 'ERROR', 'junk')]
While comparing [0]: sequence not as expected:
same:
('root',)
expected:
('INFO', 'one')
actual:
('ERROR', 'junk')
While comparing [0][1]: 'INFO' (expected) != 'ERROR' (actual)""")):
log.check_present(
('root', 'INFO', 'one'),
)
def test_order_matters_but_wrong(self):
with LogCapture() as log:
root.info('one')
root.error('j1')
root.error('three')
root.warning('two')
root.error('j2')
with ShouldAssert(dedent("""\
ignored:
[('root', 'ERROR', 'j1'), ('root', 'ERROR', 'three'), ('root', 'ERROR', 'j2')]
same:
[('root', 'INFO', 'one'), ('root', 'WARNING', 'two')]
expected:
[('root', 'ERROR', 'three')]
actual:
[]""")):
log.check_present(
('root', 'INFO', 'one'),
('root', 'WARNING', 'two'),
('root', 'ERROR', 'three'),
)
def test_order_doesnt_matter_ok(self):
with LogCapture() as log:
root.info('one')
root.error('junk')
root.warning('two')
root.error('junk')
root.error('three')
log.check_present(
('root', 'ERROR', 'three'),
('root', 'INFO', 'one'),
('root', 'WARNING', 'two'),
order_matters=False
)
def test_order_doesnt_matter_not_okay(self):
with LogCapture() as log:
root.error('junk')
with ShouldAssert(dedent("""\
ignored:
[('root', 'ERROR', 'junk')]
in expected but not actual:
[('root', 'INFO', 'one')]""")):
log.check_present(
('root', 'INFO', 'one'),
order_matters=False
)
def test_single_item_ok(self):
with LogCapture() as log:
root.info('one')
root.error('junk')
root.warning('two')
root.error('junk')
root.error('three')
log.check_present(
('root', 'WARNING', 'two'),
)
def test_single_item_not_ok(self):
with LogCapture(attributes=['getMessage']) as log:
root.info('one')
root.error('junk')
root.error('three')
with ShouldAssert(dedent("""\
ignored:
['one', 'junk', 'three']
same:
[]
expected:
['two']
actual:
[]""")):
log.check_present('two')
def test_multiple_identical_expected_order_matters(self):
with LogCapture() as log:
root.info('one')
root.info('one')
root.error('junk')
root.warning('two')
root.error('junk')
root.warning('two')
log.check_present(
('root', 'INFO', 'one'),
('root', 'INFO', 'one'),
('root', 'WARNING', 'two'),
('root', 'WARNING', 'two'),
)
def test_multiple_identical_expected_order_doesnt_matter_ok(self):
with LogCapture() as log:
root.info('one')
root.warning('two')
root.error('junk')
root.warning('two')
root.error('junk')
root.info('one')
log.check_present(
('root', 'INFO', 'one'),
('root', 'INFO', 'one'),
('root', 'WARNING', 'two'),
('root', 'WARNING', 'two'),
order_matters=False
)
def test_multiple_identical_expected_order_doesnt_matter_not_ok(self):
with LogCapture() as log:
root.error('junk')
root.info('one')
root.warning('two')
root.error('junk')
root.info('one')
with ShouldAssert(dedent("""\
ignored:
[('root', 'ERROR', 'junk'), ('root', 'ERROR', 'junk')]
same:
[('root', 'INFO', 'one'), ('root', 'INFO', 'one'), ('root', 'WARNING', 'two')]
in expected but not actual:
[('root', 'WARNING', 'two')]""")):
log.check_present(
('root', 'INFO', 'one'),
('root', 'INFO', 'one'),
('root', 'WARNING', 'two'),
('root', 'WARNING', 'two'),
order_matters=False
)
def test_entries_are_dictionaries(self):
def extract(record):
return {'level': record.levelname, 'message': record.getMessage()}
with LogCapture(attributes=extract) as log:
root.info('one')
root.error('junk')
root.warning('two')
root.error('junk')
root.info('one')
log.check_present(
{'level': 'INFO', 'message': 'one'},
{'level': 'INFO', 'message': 'one'},
{'level': 'WARNING', 'message': 'two'},
order_matters=False
)
def test_almost_same_order_matters(self):
with LogCapture() as log:
root.info('one')
root.error('junk')
root.warning('two')
root.error('junk')
with ShouldAssert(dedent("""\
ignored:
[('root', 'ERROR', 'junk'), ('root', 'ERROR', 'junk')]
same:
[('root', 'INFO', 'one'), ('root', 'WARNING', 'two')]
expected:
[('root', 'ERROR', 'three')]
actual:
[]""")):
log.check_present(
('root', 'INFO', 'one'),
('root', 'WARNING', 'two'),
('root', 'ERROR', 'three'),
)
def test_almost_same_order_doesnt_matter(self):
with LogCapture() as log:
root.info('one')
root.error('junk')
root.error('three')
root.error('junk')
with ShouldAssert(dedent("""\
ignored:
[('root', 'ERROR', 'junk'), ('root', 'ERROR', 'junk')]
same:
[('root', 'ERROR', 'three'), ('root', 'INFO', 'one')]
in expected but not actual:
[('root', 'WARNING', 'two')]""")):
log.check_present(
('root', 'ERROR', 'three'),
('root', 'INFO', 'one'),
('root', 'WARNING', 'two'),
order_matters=False
)
Zerion Mini Shell 1.0