cli_test.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. # encoding: utf-8
  2. from __future__ import absolute_import
  3. from __future__ import unicode_literals
  4. import os
  5. import shutil
  6. import tempfile
  7. from io import StringIO
  8. import docker
  9. import py
  10. import pytest
  11. from .. import mock
  12. from .. import unittest
  13. from ..helpers import build_config
  14. from compose.cli.command import get_project
  15. from compose.cli.command import get_project_name
  16. from compose.cli.docopt_command import NoSuchCommand
  17. from compose.cli.errors import UserError
  18. from compose.cli.main import TopLevelCommand
  19. from compose.const import IS_WINDOWS_PLATFORM
  20. from compose.project import Project
  21. class CLITestCase(unittest.TestCase):
  22. def test_default_project_name(self):
  23. test_dir = py._path.local.LocalPath('tests/fixtures/simple-composefile')
  24. with test_dir.as_cwd():
  25. project_name = get_project_name('.')
  26. self.assertEqual('simplecomposefile', project_name)
  27. def test_project_name_with_explicit_base_dir(self):
  28. base_dir = 'tests/fixtures/simple-composefile'
  29. project_name = get_project_name(base_dir)
  30. self.assertEqual('simplecomposefile', project_name)
  31. def test_project_name_with_explicit_uppercase_base_dir(self):
  32. base_dir = 'tests/fixtures/UpperCaseDir'
  33. project_name = get_project_name(base_dir)
  34. self.assertEqual('uppercasedir', project_name)
  35. def test_project_name_with_explicit_project_name(self):
  36. name = 'explicit-project-name'
  37. project_name = get_project_name(None, project_name=name)
  38. self.assertEqual('explicitprojectname', project_name)
  39. @mock.patch.dict(os.environ)
  40. def test_project_name_from_environment_new_var(self):
  41. name = 'namefromenv'
  42. os.environ['COMPOSE_PROJECT_NAME'] = name
  43. project_name = get_project_name(None)
  44. self.assertEqual(project_name, name)
  45. def test_project_name_with_empty_environment_var(self):
  46. base_dir = 'tests/fixtures/simple-composefile'
  47. with mock.patch.dict(os.environ):
  48. os.environ['COMPOSE_PROJECT_NAME'] = ''
  49. project_name = get_project_name(base_dir)
  50. self.assertEqual('simplecomposefile', project_name)
  51. @mock.patch.dict(os.environ)
  52. def test_project_name_with_environment_file(self):
  53. base_dir = tempfile.mkdtemp()
  54. try:
  55. name = 'namefromenvfile'
  56. with open(os.path.join(base_dir, '.env'), 'w') as f:
  57. f.write('COMPOSE_PROJECT_NAME={}'.format(name))
  58. project_name = get_project_name(base_dir)
  59. assert project_name == name
  60. # Environment has priority over .env file
  61. os.environ['COMPOSE_PROJECT_NAME'] = 'namefromenv'
  62. assert get_project_name(base_dir) == os.environ['COMPOSE_PROJECT_NAME']
  63. finally:
  64. shutil.rmtree(base_dir)
  65. def test_get_project(self):
  66. base_dir = 'tests/fixtures/longer-filename-composefile'
  67. project = get_project(base_dir)
  68. self.assertEqual(project.name, 'longerfilenamecomposefile')
  69. self.assertTrue(project.client)
  70. self.assertTrue(project.services)
  71. def test_command_help(self):
  72. with mock.patch('sys.stdout', new=StringIO()) as fake_stdout:
  73. TopLevelCommand.help({'COMMAND': 'up'})
  74. assert "Usage: up" in fake_stdout.getvalue()
  75. def test_command_help_nonexistent(self):
  76. with pytest.raises(NoSuchCommand):
  77. TopLevelCommand.help({'COMMAND': 'nonexistent'})
  78. @pytest.mark.xfail(IS_WINDOWS_PLATFORM, reason="requires dockerpty")
  79. @mock.patch('compose.cli.main.RunOperation', autospec=True)
  80. @mock.patch('compose.cli.main.PseudoTerminal', autospec=True)
  81. def test_run_interactive_passes_logs_false(self, mock_pseudo_terminal, mock_run_operation):
  82. mock_client = mock.create_autospec(docker.APIClient)
  83. project = Project.from_config(
  84. name='composetest',
  85. client=mock_client,
  86. config_data=build_config({
  87. 'service': {'image': 'busybox'}
  88. }),
  89. )
  90. command = TopLevelCommand(project)
  91. with pytest.raises(SystemExit):
  92. command.run({
  93. 'SERVICE': 'service',
  94. 'COMMAND': None,
  95. '-e': [],
  96. '--user': None,
  97. '--no-deps': None,
  98. '-d': False,
  99. '-T': None,
  100. '--entrypoint': None,
  101. '--service-ports': None,
  102. '--publish': [],
  103. '--volume': [],
  104. '--rm': None,
  105. '--name': None,
  106. '--workdir': None,
  107. })
  108. _, _, call_kwargs = mock_run_operation.mock_calls[0]
  109. assert call_kwargs['logs'] is False
  110. def test_run_service_with_restart_always(self):
  111. mock_client = mock.create_autospec(docker.APIClient)
  112. project = Project.from_config(
  113. name='composetest',
  114. client=mock_client,
  115. config_data=build_config({
  116. 'service': {
  117. 'image': 'busybox',
  118. 'restart': 'always',
  119. }
  120. }),
  121. )
  122. command = TopLevelCommand(project)
  123. command.run({
  124. 'SERVICE': 'service',
  125. 'COMMAND': None,
  126. '-e': [],
  127. '--user': None,
  128. '--no-deps': None,
  129. '-d': True,
  130. '-T': None,
  131. '--entrypoint': None,
  132. '--service-ports': None,
  133. '--publish': [],
  134. '--volume': [],
  135. '--rm': None,
  136. '--name': None,
  137. '--workdir': None,
  138. })
  139. self.assertEqual(
  140. mock_client.create_host_config.call_args[1]['restart_policy']['Name'],
  141. 'always'
  142. )
  143. command = TopLevelCommand(project)
  144. command.run({
  145. 'SERVICE': 'service',
  146. 'COMMAND': None,
  147. '-e': [],
  148. '--user': None,
  149. '--no-deps': None,
  150. '-d': True,
  151. '-T': None,
  152. '--entrypoint': None,
  153. '--service-ports': None,
  154. '--publish': [],
  155. '--volume': [],
  156. '--rm': True,
  157. '--name': None,
  158. '--workdir': None,
  159. })
  160. self.assertFalse(
  161. mock_client.create_host_config.call_args[1].get('restart_policy')
  162. )
  163. def test_command_manual_and_service_ports_together(self):
  164. project = Project.from_config(
  165. name='composetest',
  166. client=None,
  167. config_data=build_config({
  168. 'service': {'image': 'busybox'},
  169. }),
  170. )
  171. command = TopLevelCommand(project)
  172. with self.assertRaises(UserError):
  173. command.run({
  174. 'SERVICE': 'service',
  175. 'COMMAND': None,
  176. '-e': [],
  177. '--user': None,
  178. '--no-deps': None,
  179. '-d': True,
  180. '-T': None,
  181. '--entrypoint': None,
  182. '--service-ports': True,
  183. '--publish': ['80:80'],
  184. '--rm': None,
  185. '--name': None,
  186. })