Add tests for reactive log printing.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
Daniel Nephin 2016-03-02 17:04:52 -05:00
commit 44c1747127
6 changed files with 218 additions and 133 deletions

View file

@ -5,9 +5,11 @@ import pytest
import six
from six.moves.queue import Queue
from compose.cli.log_printer import build_log_generator
from compose.cli.log_printer import build_log_presenters
from compose.cli.log_printer import build_no_log_generator
from compose.cli.log_printer import consume_queue
from compose.cli.log_printer import LogPrinter
from compose.cli.log_printer import STOP
from compose.cli.log_printer import QueueItem
from compose.cli.log_printer import wait_on_exit
from compose.container import Container
from tests import mock
@ -34,72 +36,73 @@ def output_stream():
@pytest.fixture
def mock_container():
def reader(*args, **kwargs):
yield b"hello\nworld"
return build_mock_container(reader)
return mock.Mock(spec=Container, name_without_project='web_1')
@pytest.mark.skipif(True, reason="wip")
class TestLogPrinter(object):
class TestLogPresenter(object):
def test_single_container(self, output_stream, mock_container):
LogPrinter([mock_container], output=output_stream, log_args={'follow': True}).run()
def test_monochrome(self, mock_container):
presenters = build_log_presenters(['foo', 'bar'], True)
presenter = presenters.next()
actual = presenter.present(mock_container, "this line")
assert actual == "web_1 | this line"
output = output_stream.getvalue()
assert 'hello' in output
assert 'world' in output
# Call count is 2 lines + "container exited line"
assert output_stream.flush.call_count == 3
def test_polychrome(self, mock_container):
presenters = build_log_presenters(['foo', 'bar'], False)
presenter = presenters.next()
actual = presenter.present(mock_container, "this line")
assert '\033[' in actual
def test_single_container_without_stream(self, output_stream, mock_container):
LogPrinter([mock_container], output=output_stream).run()
output = output_stream.getvalue()
assert 'hello' in output
assert 'world' in output
# Call count is 2 lines
assert output_stream.flush.call_count == 2
def test_wait_on_exit():
exit_status = 3
mock_container = mock.Mock(
spec=Container,
name='cname',
wait=mock.Mock(return_value=exit_status))
def test_monochrome(self, output_stream, mock_container):
LogPrinter([mock_container], output=output_stream, monochrome=True).run()
assert '\033[' not in output_stream.getvalue()
expected = '{} exited with code {}\n'.format(mock_container.name, exit_status)
assert expected == wait_on_exit(mock_container)
def test_polychrome(self, output_stream, mock_container):
LogPrinter([mock_container], output=output_stream).run()
assert '\033[' in output_stream.getvalue()
def test_build_no_log_generator(mock_container):
mock_container.has_api_logs = False
mock_container.log_driver = 'none'
output, = build_no_log_generator(mock_container, None)
assert "WARNING: no logs are available with the 'none' log driver\n" in output
assert "exited with code" not in output
class TestBuildLogGenerator(object):
def test_no_log_stream(self, mock_container):
mock_container.log_stream = None
mock_container.logs.return_value = iter([b"hello\nworld"])
log_args = {'follow': True}
generator = build_log_generator(mock_container, log_args)
assert generator.next() == "hello\n"
assert generator.next() == "world"
mock_container.logs.assert_called_once_with(
stdout=True,
stderr=True,
stream=True,
**log_args)
def test_with_log_stream(self, mock_container):
mock_container.log_stream = iter([b"hello\nworld"])
log_args = {'follow': True}
generator = build_log_generator(mock_container, log_args)
assert generator.next() == "hello\n"
assert generator.next() == "world"
def test_unicode(self, output_stream):
glyph = u'\u2022'
glyph = u'\u2022\n'
mock_container.log_stream = iter([glyph.encode('utf-8')])
def reader(*args, **kwargs):
yield glyph.encode('utf-8') + b'\n'
container = build_mock_container(reader)
LogPrinter([container], output=output_stream).run()
output = output_stream.getvalue()
if six.PY2:
output = output.decode('utf-8')
assert glyph in output
def test_wait_on_exit(self):
exit_status = 3
mock_container = mock.Mock(
spec=Container,
name='cname',
wait=mock.Mock(return_value=exit_status))
expected = '{} exited with code {}\n'.format(mock_container.name, exit_status)
assert expected == wait_on_exit(mock_container)
def test_generator_with_no_logs(self, mock_container, output_stream):
mock_container.has_api_logs = False
mock_container.log_driver = 'none'
LogPrinter([mock_container], output=output_stream).run()
output = output_stream.getvalue()
assert "WARNING: no logs are available with the 'none' log driver\n" in output
assert "exited with code" not in output
generator = build_log_generator(mock_container, {})
assert generator.next() == glyph
class TestConsumeQueue(object):
@ -111,7 +114,7 @@ class TestConsumeQueue(object):
queue = Queue()
error = Problem('oops')
for item in ('a', None), ('b', None), (None, error):
for item in QueueItem.new('a'), QueueItem.new('b'), QueueItem.exception(error):
queue.put(item)
generator = consume_queue(queue, False)
@ -122,7 +125,7 @@ class TestConsumeQueue(object):
def test_item_is_stop_without_cascade_stop(self):
queue = Queue()
for item in (STOP, None), ('a', None), ('b', None):
for item in QueueItem.stop(), QueueItem.new('a'), QueueItem.new('b'):
queue.put(item)
generator = consume_queue(queue, False)
@ -131,7 +134,12 @@ class TestConsumeQueue(object):
def test_item_is_stop_with_cascade_stop(self):
queue = Queue()
for item in (STOP, None), ('a', None), ('b', None):
for item in QueueItem.stop(), QueueItem.new('a'), QueueItem.new('b'):
queue.put(item)
assert list(consume_queue(queue, True)) == []
def test_item_is_none_when_timeout_is_hit(self):
queue = Queue()
generator = consume_queue(queue, False)
assert generator.next() is None