Merge branch '3191_2_help_cli_feature' of https://github.com/twitherspoon/compose into 3191_2_help_cli_feature

This commit is contained in:
Tony Witherspoon 2016-04-07 12:46:27 -04:00
commit f5b80640fe
35 changed files with 539 additions and 226 deletions

4
tests/fixtures/default-env-file/.env vendored Normal file
View file

@ -0,0 +1,4 @@
IMAGE=alpine:latest
COMMAND=true
PORT1=5643
PORT2=9999

View file

@ -0,0 +1,6 @@
web:
image: ${IMAGE}
command: ${COMMAND}
ports:
- $PORT1
- $PORT2

View file

@ -13,4 +13,5 @@ def build_config(contents, **kwargs):
def build_config_details(contents, working_dir='working_dir', filename='filename.yml'):
return ConfigDetails(
working_dir,
[ConfigFile(filename, contents)])
[ConfigFile(filename, contents)],
)

View file

@ -6,6 +6,7 @@ import shutil
import tempfile
from os import path
import pytest
from docker.errors import APIError
from six import StringIO
from six import text_type
@ -768,17 +769,17 @@ class ServiceTest(DockerClientTestCase):
container = service.create_container(number=next_number, quiet=True)
container.start()
self.assertTrue(container.is_running)
self.assertEqual(len(service.containers()), 1)
container.inspect()
assert container.is_running
assert len(service.containers()) == 1
service.scale(1)
self.assertEqual(len(service.containers()), 1)
assert len(service.containers()) == 1
container.inspect()
self.assertTrue(container.is_running)
assert container.is_running
captured_output = mock_log.info.call_args[0]
self.assertIn('Desired container number already achieved', captured_output)
assert 'Desired container number already achieved' in captured_output
@mock.patch('compose.service.log')
def test_scale_with_custom_container_name_outputs_warning(self, mock_log):
@ -985,6 +986,7 @@ class ServiceTest(DockerClientTestCase):
one_off_container = service.create_container(one_off=True)
self.assertNotEqual(one_off_container.name, 'my-web-container')
@pytest.mark.skipif(True, reason="Broken on 1.11.0rc1")
def test_log_drive_invalid(self):
service = self.create_service('web', logging={'driver': 'xxx'})
expected_error_msg = "logger: no log driver named 'xxx' is registered"

View file

@ -12,6 +12,7 @@ from compose.cli.docker_client import docker_client
from compose.config.config import resolve_environment
from compose.config.config import V1
from compose.config.config import V2_0
from compose.config.environment import Environment
from compose.const import API_VERSIONS
from compose.const import LABEL_PROJECT
from compose.progress_stream import stream_output
@ -60,7 +61,7 @@ class DockerClientTestCase(unittest.TestCase):
else:
version = API_VERSIONS[V2_0]
cls.client = docker_client(version)
cls.client = docker_client(Environment(), version)
def tearDown(self):
for c in self.client.containers(
@ -89,7 +90,9 @@ class DockerClientTestCase(unittest.TestCase):
if 'command' not in kwargs:
kwargs['command'] = ["top"]
kwargs['environment'] = resolve_environment(kwargs)
kwargs['environment'] = resolve_environment(
kwargs, Environment.from_env_file(None)
)
labels = dict(kwargs.setdefault('labels', {}))
labels['com.docker.compose.test-name'] = self.id()

View file

@ -6,6 +6,7 @@ import os
import pytest
from compose.cli.command import get_config_path_from_options
from compose.config.environment import Environment
from compose.const import IS_WINDOWS_PLATFORM
from tests import mock
@ -15,24 +16,33 @@ class TestGetConfigPathFromOptions(object):
def test_path_from_options(self):
paths = ['one.yml', 'two.yml']
opts = {'--file': paths}
assert get_config_path_from_options(opts) == paths
environment = Environment.from_env_file('.')
assert get_config_path_from_options('.', opts, environment) == paths
def test_single_path_from_env(self):
with mock.patch.dict(os.environ):
os.environ['COMPOSE_FILE'] = 'one.yml'
assert get_config_path_from_options({}) == ['one.yml']
environment = Environment.from_env_file('.')
assert get_config_path_from_options('.', {}, environment) == ['one.yml']
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='posix separator')
def test_multiple_path_from_env(self):
with mock.patch.dict(os.environ):
os.environ['COMPOSE_FILE'] = 'one.yml:two.yml'
assert get_config_path_from_options({}) == ['one.yml', 'two.yml']
environment = Environment.from_env_file('.')
assert get_config_path_from_options(
'.', {}, environment
) == ['one.yml', 'two.yml']
@pytest.mark.skipif(not IS_WINDOWS_PLATFORM, reason='windows separator')
def test_multiple_path_from_env_windows(self):
with mock.patch.dict(os.environ):
os.environ['COMPOSE_FILE'] = 'one.yml;two.yml'
assert get_config_path_from_options({}) == ['one.yml', 'two.yml']
environment = Environment.from_env_file('.')
assert get_config_path_from_options(
'.', {}, environment
) == ['one.yml', 'two.yml']
def test_no_path(self):
assert not get_config_path_from_options({})
environment = Environment.from_env_file('.')
assert not get_config_path_from_options('.', {}, environment)

View file

@ -17,12 +17,12 @@ class DockerClientTestCase(unittest.TestCase):
def test_docker_client_no_home(self):
with mock.patch.dict(os.environ):
del os.environ['HOME']
docker_client()
docker_client(os.environ)
def test_docker_client_with_custom_timeout(self):
timeout = 300
with mock.patch('compose.cli.docker_client.HTTP_TIMEOUT', 300):
client = docker_client()
client = docker_client(os.environ)
self.assertEqual(client.timeout, int(timeout))
@ -103,3 +103,9 @@ class TLSConfigTestCase(unittest.TestCase):
options = {'--tlskey': self.key}
with pytest.raises(docker.errors.TLSParameterError):
tls_config_from_options(options)
def test_assert_hostname_explicit_skip(self):
options = {'--tlscacert': self.ca_cert, '--skip-hostname-check': True}
result = tls_config_from_options(options)
assert isinstance(result, docker.tls.TLSConfig)
assert result.assert_hostname is False

View file

@ -3,6 +3,8 @@ from __future__ import absolute_import
from __future__ import unicode_literals
import os
import shutil
import tempfile
import docker
import py
@ -43,11 +45,11 @@ class CLITestCase(unittest.TestCase):
project_name = get_project_name(None, project_name=name)
self.assertEquals('explicitprojectname', project_name)
@mock.patch.dict(os.environ)
def test_project_name_from_environment_new_var(self):
name = 'namefromenv'
with mock.patch.dict(os.environ):
os.environ['COMPOSE_PROJECT_NAME'] = name
project_name = get_project_name(None)
os.environ['COMPOSE_PROJECT_NAME'] = name
project_name = get_project_name(None)
self.assertEquals(project_name, name)
def test_project_name_with_empty_environment_var(self):
@ -57,6 +59,22 @@ class CLITestCase(unittest.TestCase):
project_name = get_project_name(base_dir)
self.assertEquals('simplecomposefile', project_name)
@mock.patch.dict(os.environ)
def test_project_name_with_environment_file(self):
base_dir = tempfile.mkdtemp()
try:
name = 'namefromenvfile'
with open(os.path.join(base_dir, '.env'), 'w') as f:
f.write('COMPOSE_PROJECT_NAME={}'.format(name))
project_name = get_project_name(base_dir)
assert project_name == name
# Environment has priority over .env file
os.environ['COMPOSE_PROJECT_NAME'] = 'namefromenv'
assert get_project_name(base_dir) == os.environ['COMPOSE_PROJECT_NAME']
finally:
shutil.rmtree(base_dir)
def test_get_project(self):
base_dir = 'tests/fixtures/longer-filename-composefile'
project = get_project(base_dir)

View file

@ -17,6 +17,7 @@ from compose.config.config import resolve_build_args
from compose.config.config import resolve_environment
from compose.config.config import V1
from compose.config.config import V2_0
from compose.config.environment import Environment
from compose.config.errors import ConfigurationError
from compose.config.errors import VERSION_EXPLANATION
from compose.config.types import VolumeSpec
@ -36,7 +37,9 @@ def make_service_dict(name, service_dict, working_dir, filename=None):
filename=filename,
name=name,
config=service_dict),
config.ConfigFile(filename=filename, config={}))
config.ConfigFile(filename=filename, config={}),
environment=Environment.from_env_file(working_dir)
)
return config.process_service(resolver.run())
@ -1581,8 +1584,25 @@ class PortsTest(unittest.TestCase):
class InterpolationTest(unittest.TestCase):
@mock.patch.dict(os.environ)
def test_config_file_with_environment_file(self):
project_dir = 'tests/fixtures/default-env-file'
service_dicts = config.load(
config.find(
project_dir, None, Environment.from_env_file(project_dir)
)
).services
self.assertEqual(service_dicts[0], {
'name': 'web',
'image': 'alpine:latest',
'ports': ['5643', '9999'],
'command': 'true'
})
@mock.patch.dict(os.environ)
def test_config_file_with_environment_variable(self):
project_dir = 'tests/fixtures/environment-interpolation'
os.environ.update(
IMAGE="busybox",
HOST_PORT="80",
@ -1590,7 +1610,9 @@ class InterpolationTest(unittest.TestCase):
)
service_dicts = config.load(
config.find('tests/fixtures/environment-interpolation', None),
config.find(
project_dir, None, Environment.from_env_file(project_dir)
)
).services
self.assertEqual(service_dicts, [
@ -1620,7 +1642,7 @@ class InterpolationTest(unittest.TestCase):
None,
)
with mock.patch('compose.config.interpolation.log') as log:
with mock.patch('compose.config.environment.log') as log:
config.load(config_details)
self.assertEqual(2, log.warn.call_count)
@ -2041,7 +2063,9 @@ class EnvTest(unittest.TestCase):
},
}
self.assertEqual(
resolve_environment(service_dict),
resolve_environment(
service_dict, Environment.from_env_file(None)
),
{'FILE_DEF': 'F1', 'FILE_DEF_EMPTY': '', 'ENV_DEF': 'E3', 'NO_DEF': None},
)
@ -2078,7 +2102,10 @@ class EnvTest(unittest.TestCase):
os.environ['FILE_DEF_EMPTY'] = 'E2'
os.environ['ENV_DEF'] = 'E3'
self.assertEqual(
resolve_environment({'env_file': ['tests/fixtures/env/resolve.env']}),
resolve_environment(
{'env_file': ['tests/fixtures/env/resolve.env']},
Environment.from_env_file(None)
),
{
'FILE_DEF': u'bär',
'FILE_DEF_EMPTY': '',
@ -2101,7 +2128,7 @@ class EnvTest(unittest.TestCase):
}
}
self.assertEqual(
resolve_build_args(build),
resolve_build_args(build, Environment.from_env_file(build['context'])),
{'arg1': 'value1', 'empty_arg': '', 'env_arg': 'value2', 'no_env': None},
)
@ -2133,7 +2160,9 @@ class EnvTest(unittest.TestCase):
def load_from_filename(filename):
return config.load(config.find('.', [filename])).services
return config.load(
config.find('.', [filename], Environment.from_env_file('.'))
).services
class ExtendsTest(unittest.TestCase):
@ -2465,6 +2494,7 @@ class ExtendsTest(unittest.TestCase):
},
]))
@mock.patch.dict(os.environ)
def test_extends_with_environment_and_env_files(self):
tmpdir = py.test.ensuretemp('test_extends_with_environment')
self.addCleanup(tmpdir.remove)
@ -2520,12 +2550,12 @@ class ExtendsTest(unittest.TestCase):
},
},
]
with mock.patch.dict(os.environ):
os.environ['SECRET'] = 'secret'
os.environ['THING'] = 'thing'
os.environ['COMMON_ENV_FILE'] = 'secret'
os.environ['TOP_ENV_FILE'] = 'secret'
config = load_from_filename(str(tmpdir.join('docker-compose.yml')))
os.environ['SECRET'] = 'secret'
os.environ['THING'] = 'thing'
os.environ['COMMON_ENV_FILE'] = 'secret'
os.environ['TOP_ENV_FILE'] = 'secret'
config = load_from_filename(str(tmpdir.join('docker-compose.yml')))
assert config == expected

View file

@ -6,6 +6,7 @@ import os
import mock
import pytest
from compose.config.environment import Environment
from compose.config.interpolation import interpolate_environment_variables
@ -19,7 +20,7 @@ def mock_env():
def test_interpolate_environment_variables_in_services(mock_env):
services = {
'servivea': {
'servicea': {
'image': 'example:${USER}',
'volumes': ['$FOO:/target'],
'logging': {
@ -31,7 +32,7 @@ def test_interpolate_environment_variables_in_services(mock_env):
}
}
expected = {
'servivea': {
'servicea': {
'image': 'example:jenny',
'volumes': ['bar:/target'],
'logging': {
@ -42,7 +43,9 @@ def test_interpolate_environment_variables_in_services(mock_env):
}
}
}
assert interpolate_environment_variables(services, 'service') == expected
assert interpolate_environment_variables(
services, 'service', Environment.from_env_file(None)
) == expected
def test_interpolate_environment_variables_in_volumes(mock_env):
@ -66,4 +69,6 @@ def test_interpolate_environment_variables_in_volumes(mock_env):
},
'other': {},
}
assert interpolate_environment_variables(volumes, 'volume') == expected
assert interpolate_environment_variables(
volumes, 'volume', Environment.from_env_file(None)
) == expected

View file

@ -3,7 +3,7 @@ from __future__ import unicode_literals
import unittest
from compose.config.interpolation import BlankDefaultDict as bddict
from compose.config.environment import Environment as bddict
from compose.config.interpolation import interpolate
from compose.config.interpolation import InvalidInterpolation

View file

@ -270,12 +270,21 @@ class ProjectTest(unittest.TestCase):
'time': 1420092061,
'timeNano': 14200920610000004000,
},
{
'status': 'destroy',
'from': 'example/db',
'id': 'eeeee',
'time': 1420092061,
'timeNano': 14200920610000004000,
},
])
def dt_with_microseconds(dt, us):
return datetime.datetime.fromtimestamp(dt).replace(microsecond=us)
def get_container(cid):
if cid == 'eeeee':
raise NotFound(None, None, "oops")
if cid == 'abcde':
name = 'web'
labels = {LABEL_SERVICE: name}