mirror of https://github.com/docker/compose.git
242 lines
8.5 KiB
Python
242 lines
8.5 KiB
Python
from __future__ import absolute_import
|
|
from __future__ import unicode_literals
|
|
|
|
import logging
|
|
|
|
import docker
|
|
import pytest
|
|
|
|
from compose import container
|
|
from compose.cli.errors import UserError
|
|
from compose.cli.formatter import ConsoleWarningFormatter
|
|
from compose.cli.main import build_one_off_container_options
|
|
from compose.cli.main import call_docker
|
|
from compose.cli.main import convergence_strategy_from_opts
|
|
from compose.cli.main import filter_containers_to_service_names
|
|
from compose.cli.main import get_docker_start_call
|
|
from compose.cli.main import setup_console_handler
|
|
from compose.cli.main import warn_for_swarm_mode
|
|
from compose.service import ConvergenceStrategy
|
|
from tests import mock
|
|
|
|
|
|
def mock_container(service, number):
|
|
return mock.create_autospec(
|
|
container.Container,
|
|
service=service,
|
|
number=number,
|
|
name_without_project='{0}_{1}'.format(service, number))
|
|
|
|
|
|
@pytest.fixture
|
|
def logging_handler():
|
|
stream = mock.Mock()
|
|
stream.isatty.return_value = True
|
|
return logging.StreamHandler(stream=stream)
|
|
|
|
|
|
class TestCLIMainTestCase(object):
|
|
|
|
def test_filter_containers_to_service_names(self):
|
|
containers = [
|
|
mock_container('web', 1),
|
|
mock_container('web', 2),
|
|
mock_container('db', 1),
|
|
mock_container('other', 1),
|
|
mock_container('another', 1),
|
|
]
|
|
service_names = ['web', 'db']
|
|
actual = filter_containers_to_service_names(containers, service_names)
|
|
assert actual == containers[:3]
|
|
|
|
def test_filter_containers_to_service_names_all(self):
|
|
containers = [
|
|
mock_container('web', 1),
|
|
mock_container('db', 1),
|
|
mock_container('other', 1),
|
|
]
|
|
service_names = []
|
|
actual = filter_containers_to_service_names(containers, service_names)
|
|
assert actual == containers
|
|
|
|
def test_warning_in_swarm_mode(self):
|
|
mock_client = mock.create_autospec(docker.APIClient)
|
|
mock_client.info.return_value = {'Swarm': {'LocalNodeState': 'active'}}
|
|
|
|
with mock.patch('compose.cli.main.log') as fake_log:
|
|
warn_for_swarm_mode(mock_client)
|
|
assert fake_log.warning.call_count == 1
|
|
|
|
def test_build_one_off_container_options(self):
|
|
command = 'build myservice'
|
|
detach = False
|
|
options = {
|
|
'-e': ['MYVAR=MYVALUE'],
|
|
'-T': True,
|
|
'--label': ['MYLABEL'],
|
|
'--entrypoint': 'bash',
|
|
'--user': 'MYUSER',
|
|
'--service-ports': [],
|
|
'--publish': '',
|
|
'--name': 'MYNAME',
|
|
'--workdir': '.',
|
|
'--volume': [],
|
|
'stdin_open': False,
|
|
}
|
|
|
|
expected_container_options = {
|
|
'command': command,
|
|
'tty': False,
|
|
'stdin_open': False,
|
|
'detach': detach,
|
|
'entrypoint': 'bash',
|
|
'environment': {'MYVAR': 'MYVALUE'},
|
|
'labels': {'MYLABEL': ''},
|
|
'name': 'MYNAME',
|
|
'ports': [],
|
|
'restart': None,
|
|
'user': 'MYUSER',
|
|
'working_dir': '.',
|
|
}
|
|
|
|
container_options = build_one_off_container_options(options, detach, command)
|
|
assert container_options == expected_container_options
|
|
|
|
def test_get_docker_start_call(self):
|
|
container_id = 'my_container_id'
|
|
|
|
mock_container_options = {'detach': False, 'stdin_open': True}
|
|
expected_docker_start_call = ['start', '--attach', '--interactive', container_id]
|
|
docker_start_call = get_docker_start_call(mock_container_options, container_id)
|
|
assert expected_docker_start_call == docker_start_call
|
|
|
|
mock_container_options = {'detach': False, 'stdin_open': False}
|
|
expected_docker_start_call = ['start', '--attach', container_id]
|
|
docker_start_call = get_docker_start_call(mock_container_options, container_id)
|
|
assert expected_docker_start_call == docker_start_call
|
|
|
|
mock_container_options = {'detach': True, 'stdin_open': True}
|
|
expected_docker_start_call = ['start', '--interactive', container_id]
|
|
docker_start_call = get_docker_start_call(mock_container_options, container_id)
|
|
assert expected_docker_start_call == docker_start_call
|
|
|
|
mock_container_options = {'detach': True, 'stdin_open': False}
|
|
expected_docker_start_call = ['start', container_id]
|
|
docker_start_call = get_docker_start_call(mock_container_options, container_id)
|
|
assert expected_docker_start_call == docker_start_call
|
|
|
|
|
|
class TestSetupConsoleHandlerTestCase(object):
|
|
|
|
def test_with_tty_verbose(self, logging_handler):
|
|
setup_console_handler(logging_handler, True)
|
|
assert type(logging_handler.formatter) == ConsoleWarningFormatter
|
|
assert '%(name)s' in logging_handler.formatter._fmt
|
|
assert '%(funcName)s' in logging_handler.formatter._fmt
|
|
|
|
def test_with_tty_not_verbose(self, logging_handler):
|
|
setup_console_handler(logging_handler, False)
|
|
assert type(logging_handler.formatter) == ConsoleWarningFormatter
|
|
assert '%(name)s' not in logging_handler.formatter._fmt
|
|
assert '%(funcName)s' not in logging_handler.formatter._fmt
|
|
|
|
def test_with_not_a_tty(self, logging_handler):
|
|
logging_handler.stream.isatty.return_value = False
|
|
setup_console_handler(logging_handler, False)
|
|
assert type(logging_handler.formatter) == logging.Formatter
|
|
|
|
|
|
class TestConvergeStrategyFromOptsTestCase(object):
|
|
|
|
def test_invalid_opts(self):
|
|
options = {'--force-recreate': True, '--no-recreate': True}
|
|
with pytest.raises(UserError):
|
|
convergence_strategy_from_opts(options)
|
|
|
|
def test_always(self):
|
|
options = {'--force-recreate': True, '--no-recreate': False}
|
|
assert (
|
|
convergence_strategy_from_opts(options) ==
|
|
ConvergenceStrategy.always
|
|
)
|
|
|
|
def test_never(self):
|
|
options = {'--force-recreate': False, '--no-recreate': True}
|
|
assert (
|
|
convergence_strategy_from_opts(options) ==
|
|
ConvergenceStrategy.never
|
|
)
|
|
|
|
def test_changed(self):
|
|
options = {'--force-recreate': False, '--no-recreate': False}
|
|
assert (
|
|
convergence_strategy_from_opts(options) ==
|
|
ConvergenceStrategy.changed
|
|
)
|
|
|
|
|
|
def mock_find_executable(exe):
|
|
return exe
|
|
|
|
|
|
@mock.patch('compose.cli.main.find_executable', mock_find_executable)
|
|
class TestCallDocker(object):
|
|
def test_simple_no_options(self):
|
|
with mock.patch('subprocess.call') as fake_call:
|
|
call_docker(['ps'], {}, {})
|
|
|
|
assert fake_call.call_args[0][0] == ['docker', 'ps']
|
|
|
|
def test_simple_tls_option(self):
|
|
with mock.patch('subprocess.call') as fake_call:
|
|
call_docker(['ps'], {'--tls': True}, {})
|
|
|
|
assert fake_call.call_args[0][0] == ['docker', '--tls', 'ps']
|
|
|
|
def test_advanced_tls_options(self):
|
|
with mock.patch('subprocess.call') as fake_call:
|
|
call_docker(['ps'], {
|
|
'--tls': True,
|
|
'--tlscacert': './ca.pem',
|
|
'--tlscert': './cert.pem',
|
|
'--tlskey': './key.pem',
|
|
}, {})
|
|
|
|
assert fake_call.call_args[0][0] == [
|
|
'docker', '--tls', '--tlscacert', './ca.pem', '--tlscert',
|
|
'./cert.pem', '--tlskey', './key.pem', 'ps'
|
|
]
|
|
|
|
def test_with_host_option(self):
|
|
with mock.patch('subprocess.call') as fake_call:
|
|
call_docker(['ps'], {'--host': 'tcp://mydocker.net:2333'}, {})
|
|
|
|
assert fake_call.call_args[0][0] == [
|
|
'docker', '--host', 'tcp://mydocker.net:2333', 'ps'
|
|
]
|
|
|
|
def test_with_http_host(self):
|
|
with mock.patch('subprocess.call') as fake_call:
|
|
call_docker(['ps'], {'--host': 'http://mydocker.net:2333'}, {})
|
|
|
|
assert fake_call.call_args[0][0] == [
|
|
'docker', '--host', 'tcp://mydocker.net:2333', 'ps',
|
|
]
|
|
|
|
def test_with_host_option_shorthand_equal(self):
|
|
with mock.patch('subprocess.call') as fake_call:
|
|
call_docker(['ps'], {'--host': '=tcp://mydocker.net:2333'}, {})
|
|
|
|
assert fake_call.call_args[0][0] == [
|
|
'docker', '--host', 'tcp://mydocker.net:2333', 'ps'
|
|
]
|
|
|
|
def test_with_env(self):
|
|
with mock.patch('subprocess.call') as fake_call:
|
|
call_docker(['ps'], {}, {'DOCKER_HOST': 'tcp://mydocker.net:2333'})
|
|
|
|
assert fake_call.call_args[0][0] == [
|
|
'docker', 'ps'
|
|
]
|
|
assert fake_call.call_args[1]['env'] == {'DOCKER_HOST': 'tcp://mydocker.net:2333'}
|