log_printer_test.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. from __future__ import absolute_import
  2. from __future__ import unicode_literals
  3. import pytest
  4. import six
  5. from six.moves.queue import Queue
  6. from compose.cli.log_printer import build_log_generator
  7. from compose.cli.log_printer import build_log_presenters
  8. from compose.cli.log_printer import build_no_log_generator
  9. from compose.cli.log_printer import consume_queue
  10. from compose.cli.log_printer import QueueItem
  11. from compose.cli.log_printer import wait_on_exit
  12. from compose.container import Container
  13. from tests import mock
  14. def build_mock_container(reader):
  15. return mock.Mock(
  16. spec=Container,
  17. name='myapp_web_1',
  18. name_without_project='web_1',
  19. has_api_logs=True,
  20. log_stream=None,
  21. logs=reader,
  22. wait=mock.Mock(return_value=0),
  23. )
  24. @pytest.fixture
  25. def output_stream():
  26. output = six.StringIO()
  27. output.flush = mock.Mock()
  28. return output
  29. @pytest.fixture
  30. def mock_container():
  31. return mock.Mock(spec=Container, name_without_project='web_1')
  32. class TestLogPresenter(object):
  33. def test_monochrome(self, mock_container):
  34. presenters = build_log_presenters(['foo', 'bar'], True)
  35. presenter = presenters.next()
  36. actual = presenter.present(mock_container, "this line")
  37. assert actual == "web_1 | this line"
  38. def test_polychrome(self, mock_container):
  39. presenters = build_log_presenters(['foo', 'bar'], False)
  40. presenter = presenters.next()
  41. actual = presenter.present(mock_container, "this line")
  42. assert '\033[' in actual
  43. def test_wait_on_exit():
  44. exit_status = 3
  45. mock_container = mock.Mock(
  46. spec=Container,
  47. name='cname',
  48. wait=mock.Mock(return_value=exit_status))
  49. expected = '{} exited with code {}\n'.format(mock_container.name, exit_status)
  50. assert expected == wait_on_exit(mock_container)
  51. def test_build_no_log_generator(mock_container):
  52. mock_container.has_api_logs = False
  53. mock_container.log_driver = 'none'
  54. output, = build_no_log_generator(mock_container, None)
  55. assert "WARNING: no logs are available with the 'none' log driver\n" in output
  56. assert "exited with code" not in output
  57. class TestBuildLogGenerator(object):
  58. def test_no_log_stream(self, mock_container):
  59. mock_container.log_stream = None
  60. mock_container.logs.return_value = iter([b"hello\nworld"])
  61. log_args = {'follow': True}
  62. generator = build_log_generator(mock_container, log_args)
  63. assert generator.next() == "hello\n"
  64. assert generator.next() == "world"
  65. mock_container.logs.assert_called_once_with(
  66. stdout=True,
  67. stderr=True,
  68. stream=True,
  69. **log_args)
  70. def test_with_log_stream(self, mock_container):
  71. mock_container.log_stream = iter([b"hello\nworld"])
  72. log_args = {'follow': True}
  73. generator = build_log_generator(mock_container, log_args)
  74. assert generator.next() == "hello\n"
  75. assert generator.next() == "world"
  76. def test_unicode(self, output_stream):
  77. glyph = u'\u2022\n'
  78. mock_container.log_stream = iter([glyph.encode('utf-8')])
  79. generator = build_log_generator(mock_container, {})
  80. assert generator.next() == glyph
  81. class TestConsumeQueue(object):
  82. def test_item_is_an_exception(self):
  83. class Problem(Exception):
  84. pass
  85. queue = Queue()
  86. error = Problem('oops')
  87. for item in QueueItem.new('a'), QueueItem.new('b'), QueueItem.exception(error):
  88. queue.put(item)
  89. generator = consume_queue(queue, False)
  90. assert generator.next() == 'a'
  91. assert generator.next() == 'b'
  92. with pytest.raises(Problem):
  93. generator.next()
  94. def test_item_is_stop_without_cascade_stop(self):
  95. queue = Queue()
  96. for item in QueueItem.stop(), QueueItem.new('a'), QueueItem.new('b'):
  97. queue.put(item)
  98. generator = consume_queue(queue, False)
  99. assert generator.next() == 'a'
  100. assert generator.next() == 'b'
  101. def test_item_is_stop_with_cascade_stop(self):
  102. queue = Queue()
  103. for item in QueueItem.stop(), QueueItem.new('a'), QueueItem.new('b'):
  104. queue.put(item)
  105. assert list(consume_queue(queue, True)) == []
  106. def test_item_is_none_when_timeout_is_hit(self):
  107. queue = Queue()
  108. generator = consume_queue(queue, False)
  109. assert generator.next() is None