2014-06-18 15:50:57 +02:00
|
|
|
from __future__ import absolute_import
|
2015-08-24 21:25:25 +02:00
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
2015-11-05 21:33:42 +01:00
|
|
|
import pytest
|
2014-08-19 23:36:46 +02:00
|
|
|
import six
|
2016-03-01 23:44:25 +01:00
|
|
|
from six.moves.queue import Queue
|
2014-08-19 23:36:46 +02:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
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
|
2016-03-01 23:44:25 +01:00
|
|
|
from compose.cli.log_printer import consume_queue
|
2016-03-02 23:04:52 +01:00
|
|
|
from compose.cli.log_printer import QueueItem
|
2015-09-09 23:53:36 +02:00
|
|
|
from compose.cli.log_printer import wait_on_exit
|
|
|
|
from compose.container import Container
|
2015-11-05 21:33:42 +01:00
|
|
|
from tests import mock
|
2014-06-18 15:50:57 +02:00
|
|
|
|
|
|
|
|
2015-09-09 23:53:36 +02:00
|
|
|
def build_mock_container(reader):
|
|
|
|
return mock.Mock(
|
|
|
|
spec=Container,
|
|
|
|
name='myapp_web_1',
|
|
|
|
name_without_project='web_1',
|
|
|
|
has_api_logs=True,
|
2015-10-26 11:27:57 +01:00
|
|
|
log_stream=None,
|
2016-01-21 13:16:04 +01:00
|
|
|
logs=reader,
|
2015-09-09 23:53:36 +02:00
|
|
|
wait=mock.Mock(return_value=0),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2015-11-05 21:33:42 +01:00
|
|
|
@pytest.fixture
|
|
|
|
def output_stream():
|
|
|
|
output = six.StringIO()
|
|
|
|
output.flush = mock.Mock()
|
|
|
|
return output
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def mock_container():
|
2016-03-02 23:04:52 +01:00
|
|
|
return mock.Mock(spec=Container, name_without_project='web_1')
|
2015-11-05 21:33:42 +01:00
|
|
|
|
2014-08-07 06:03:29 +02:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
class TestLogPresenter(object):
|
2014-06-18 15:50:57 +02:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
def test_monochrome(self, mock_container):
|
|
|
|
presenters = build_log_presenters(['foo', 'bar'], True)
|
2016-03-07 20:56:14 +01:00
|
|
|
presenter = next(presenters)
|
2016-03-02 23:04:52 +01:00
|
|
|
actual = presenter.present(mock_container, "this line")
|
|
|
|
assert actual == "web_1 | this line"
|
2014-06-18 15:50:57 +02:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
def test_polychrome(self, mock_container):
|
|
|
|
presenters = build_log_presenters(['foo', 'bar'], False)
|
2016-03-07 20:56:14 +01:00
|
|
|
presenter = next(presenters)
|
2016-03-02 23:04:52 +01:00
|
|
|
actual = presenter.present(mock_container, "this line")
|
|
|
|
assert '\033[' in actual
|
2014-08-07 06:03:29 +02:00
|
|
|
|
2016-01-21 13:16:04 +01:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
def test_wait_on_exit():
|
|
|
|
exit_status = 3
|
|
|
|
mock_container = mock.Mock(
|
|
|
|
spec=Container,
|
|
|
|
name='cname',
|
|
|
|
wait=mock.Mock(return_value=exit_status))
|
2016-01-21 13:16:04 +01:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
expected = '{} exited with code {}\n'.format(mock_container.name, exit_status)
|
|
|
|
assert expected == wait_on_exit(mock_container)
|
2014-08-07 06:03:29 +02:00
|
|
|
|
2015-11-05 21:33:42 +01:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
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
|
2014-06-18 15:50:57 +02:00
|
|
|
|
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
class TestBuildLogGenerator(object):
|
2015-08-24 18:43:08 +02:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
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}
|
2014-06-18 15:50:57 +02:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
generator = build_log_generator(mock_container, log_args)
|
2016-03-07 20:56:14 +01:00
|
|
|
assert next(generator) == "hello\n"
|
|
|
|
assert next(generator) == "world"
|
2016-03-02 23:04:52 +01:00
|
|
|
mock_container.logs.assert_called_once_with(
|
|
|
|
stdout=True,
|
|
|
|
stderr=True,
|
|
|
|
stream=True,
|
|
|
|
**log_args)
|
2014-06-18 15:50:57 +02:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
def test_with_log_stream(self, mock_container):
|
|
|
|
mock_container.log_stream = iter([b"hello\nworld"])
|
|
|
|
log_args = {'follow': True}
|
2014-06-18 15:50:57 +02:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
generator = build_log_generator(mock_container, log_args)
|
2016-03-07 20:56:14 +01:00
|
|
|
assert next(generator) == "hello\n"
|
|
|
|
assert next(generator) == "world"
|
2016-03-02 23:04:52 +01:00
|
|
|
|
|
|
|
def test_unicode(self, output_stream):
|
|
|
|
glyph = u'\u2022\n'
|
|
|
|
mock_container.log_stream = iter([glyph.encode('utf-8')])
|
2014-06-18 15:50:57 +02:00
|
|
|
|
2016-03-02 23:04:52 +01:00
|
|
|
generator = build_log_generator(mock_container, {})
|
2016-03-07 20:56:14 +01:00
|
|
|
assert next(generator) == glyph
|
2016-03-01 23:44:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
class TestConsumeQueue(object):
|
|
|
|
|
|
|
|
def test_item_is_an_exception(self):
|
|
|
|
|
|
|
|
class Problem(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
queue = Queue()
|
|
|
|
error = Problem('oops')
|
2016-03-02 23:04:52 +01:00
|
|
|
for item in QueueItem.new('a'), QueueItem.new('b'), QueueItem.exception(error):
|
2016-03-01 23:44:25 +01:00
|
|
|
queue.put(item)
|
|
|
|
|
|
|
|
generator = consume_queue(queue, False)
|
2016-03-07 20:56:14 +01:00
|
|
|
assert next(generator) == 'a'
|
|
|
|
assert next(generator) == 'b'
|
2016-03-01 23:44:25 +01:00
|
|
|
with pytest.raises(Problem):
|
2016-03-07 20:56:14 +01:00
|
|
|
next(generator)
|
2016-03-01 23:44:25 +01:00
|
|
|
|
|
|
|
def test_item_is_stop_without_cascade_stop(self):
|
|
|
|
queue = Queue()
|
2016-03-02 23:04:52 +01:00
|
|
|
for item in QueueItem.stop(), QueueItem.new('a'), QueueItem.new('b'):
|
2016-03-01 23:44:25 +01:00
|
|
|
queue.put(item)
|
|
|
|
|
|
|
|
generator = consume_queue(queue, False)
|
2016-03-07 20:56:14 +01:00
|
|
|
assert next(generator) == 'a'
|
|
|
|
assert next(generator) == 'b'
|
2016-03-01 23:44:25 +01:00
|
|
|
|
|
|
|
def test_item_is_stop_with_cascade_stop(self):
|
|
|
|
queue = Queue()
|
2016-03-02 23:04:52 +01:00
|
|
|
for item in QueueItem.stop(), QueueItem.new('a'), QueueItem.new('b'):
|
2016-03-01 23:44:25 +01:00
|
|
|
queue.put(item)
|
|
|
|
|
|
|
|
assert list(consume_queue(queue, True)) == []
|
2016-03-02 23:04:52 +01:00
|
|
|
|
|
|
|
def test_item_is_none_when_timeout_is_hit(self):
|
|
|
|
queue = Queue()
|
|
|
|
generator = consume_queue(queue, False)
|
2016-03-07 20:56:14 +01:00
|
|
|
assert next(generator) is None
|