mirror of https://github.com/docker/compose.git
Add v2 configuration tests
Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
df6877a277
commit
ecef5d37a7
|
@ -290,7 +290,7 @@ def validate_against_fields_schema(config, filename, version):
|
||||||
_validate_against_schema(
|
_validate_against_schema(
|
||||||
config,
|
config,
|
||||||
schema_filename,
|
schema_filename,
|
||||||
format_checker=["ports", "environment", "bool-value-in-mapping"],
|
format_checker=["ports", "expose", "bool-value-in-mapping"],
|
||||||
filename=filename)
|
filename=filename)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -868,6 +868,7 @@ def get_container_data_volumes(container, volumes_option):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mount = container_mounts.get(volume.internal)
|
mount = container_mounts.get(volume.internal)
|
||||||
|
|
||||||
# New volume, doesn't exist in the old container
|
# New volume, doesn't exist in the old container
|
||||||
if not mount:
|
if not mount:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
from .testcases import DockerClientTestCase
|
from .testcases import DockerClientTestCase
|
||||||
from compose.cli.docker_client import docker_client
|
from compose.cli.docker_client import docker_client
|
||||||
from compose.config import config
|
from compose.config import config
|
||||||
|
@ -508,3 +510,81 @@ class ProjectTest(DockerClientTestCase):
|
||||||
project.up()
|
project.up()
|
||||||
service = project.get_service('web')
|
service = project.get_service('web')
|
||||||
self.assertEqual(len(service.containers()), 1)
|
self.assertEqual(len(service.containers()), 1)
|
||||||
|
|
||||||
|
def test_project_up_volumes(self):
|
||||||
|
vol_name = 'composetests_{0:x}'.format(random.getrandbits(32))
|
||||||
|
config_data = config.Config(
|
||||||
|
2, [{
|
||||||
|
'name': 'web',
|
||||||
|
'image': 'busybox:latest',
|
||||||
|
'command': 'top'
|
||||||
|
}], {vol_name: {'driver': 'local'}}
|
||||||
|
)
|
||||||
|
|
||||||
|
project = Project.from_config(
|
||||||
|
name='composetest',
|
||||||
|
config_data=config_data, client=self.client
|
||||||
|
)
|
||||||
|
project.up()
|
||||||
|
self.assertEqual(len(project.containers()), 1)
|
||||||
|
|
||||||
|
volume_data = self.client.inspect_volume(vol_name)
|
||||||
|
self.assertEqual(volume_data['Name'], vol_name)
|
||||||
|
self.assertEqual(volume_data['Driver'], 'local')
|
||||||
|
|
||||||
|
def test_initialize_volumes(self):
|
||||||
|
vol_name = 'composetests_{0:x}'.format(random.getrandbits(32))
|
||||||
|
config_data = config.Config(
|
||||||
|
2, [{
|
||||||
|
'name': 'web',
|
||||||
|
'image': 'busybox:latest',
|
||||||
|
'command': 'top'
|
||||||
|
}], {vol_name: {}}
|
||||||
|
)
|
||||||
|
|
||||||
|
project = Project.from_config(
|
||||||
|
name='composetest',
|
||||||
|
config_data=config_data, client=self.client
|
||||||
|
)
|
||||||
|
project.initialize_volumes()
|
||||||
|
|
||||||
|
volume_data = self.client.inspect_volume(vol_name)
|
||||||
|
self.assertEqual(volume_data['Name'], vol_name)
|
||||||
|
self.assertEqual(volume_data['Driver'], 'local')
|
||||||
|
|
||||||
|
def test_project_up_implicit_volume_driver(self):
|
||||||
|
vol_name = 'composetests_{0:x}'.format(random.getrandbits(32))
|
||||||
|
config_data = config.Config(
|
||||||
|
2, [{
|
||||||
|
'name': 'web',
|
||||||
|
'image': 'busybox:latest',
|
||||||
|
'command': 'top'
|
||||||
|
}], {vol_name: {}}
|
||||||
|
)
|
||||||
|
|
||||||
|
project = Project.from_config(
|
||||||
|
name='composetest',
|
||||||
|
config_data=config_data, client=self.client
|
||||||
|
)
|
||||||
|
project.up()
|
||||||
|
|
||||||
|
volume_data = self.client.inspect_volume(vol_name)
|
||||||
|
self.assertEqual(volume_data['Name'], vol_name)
|
||||||
|
self.assertEqual(volume_data['Driver'], 'local')
|
||||||
|
|
||||||
|
def test_project_up_invalid_volume_driver(self):
|
||||||
|
vol_name = 'composetests_{0:x}'.format(random.getrandbits(32))
|
||||||
|
config_data = config.Config(
|
||||||
|
2, [{
|
||||||
|
'name': 'web',
|
||||||
|
'image': 'busybox:latest',
|
||||||
|
'command': 'top'
|
||||||
|
}], {vol_name: {'driver': 'foobar'}}
|
||||||
|
)
|
||||||
|
|
||||||
|
project = Project.from_config(
|
||||||
|
name='composetest',
|
||||||
|
config_data=config_data, client=self.client
|
||||||
|
)
|
||||||
|
with self.assertRaises(config.ConfigurationError):
|
||||||
|
project.initialize_volumes()
|
||||||
|
|
|
@ -26,7 +26,7 @@ def make_service_dict(name, service_dict, working_dir, filename=None):
|
||||||
working_dir=working_dir,
|
working_dir=working_dir,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
name=name,
|
name=name,
|
||||||
config=service_dict))
|
config=service_dict), version=1)
|
||||||
return config.process_service(resolver.run())
|
return config.process_service(resolver.run())
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,6 +68,85 @@ class ConfigTest(unittest.TestCase):
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_load_v2(self):
|
||||||
|
config_data = config.load(
|
||||||
|
build_config_details({
|
||||||
|
'version': 2,
|
||||||
|
'services': {
|
||||||
|
'foo': {'image': 'busybox'},
|
||||||
|
'bar': {'image': 'busybox', 'environment': ['FOO=1']},
|
||||||
|
},
|
||||||
|
'volumes': {
|
||||||
|
'hello': {
|
||||||
|
'driver': 'default',
|
||||||
|
'driver_opts': {'beep': 'boop'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 'working_dir', 'filename.yml')
|
||||||
|
)
|
||||||
|
service_dicts = config_data.services
|
||||||
|
volume_dict = config_data.volumes
|
||||||
|
self.assertEqual(
|
||||||
|
service_sort(service_dicts),
|
||||||
|
service_sort([
|
||||||
|
{
|
||||||
|
'name': 'bar',
|
||||||
|
'image': 'busybox',
|
||||||
|
'environment': {'FOO': '1'},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'foo',
|
||||||
|
'image': 'busybox',
|
||||||
|
}
|
||||||
|
])
|
||||||
|
)
|
||||||
|
self.assertEqual(volume_dict, {
|
||||||
|
'hello': {
|
||||||
|
'driver': 'default',
|
||||||
|
'driver_opts': {'beep': 'boop'}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
def test_load_service_with_name_version(self):
|
||||||
|
config_data = config.load(
|
||||||
|
build_config_details({
|
||||||
|
'version': {
|
||||||
|
'image': 'busybox'
|
||||||
|
}
|
||||||
|
}, 'working_dir', 'filename.yml')
|
||||||
|
)
|
||||||
|
service_dicts = config_data.services
|
||||||
|
self.assertEqual(
|
||||||
|
service_sort(service_dicts),
|
||||||
|
service_sort([
|
||||||
|
{
|
||||||
|
'name': 'version',
|
||||||
|
'image': 'busybox',
|
||||||
|
}
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_load_invalid_version(self):
|
||||||
|
with self.assertRaises(ConfigurationError):
|
||||||
|
config.load(
|
||||||
|
build_config_details({
|
||||||
|
'version': 18,
|
||||||
|
'services': {
|
||||||
|
'foo': {'image': 'busybox'}
|
||||||
|
}
|
||||||
|
}, 'working_dir', 'filename.yml')
|
||||||
|
)
|
||||||
|
|
||||||
|
with self.assertRaises(ConfigurationError):
|
||||||
|
config.load(
|
||||||
|
build_config_details({
|
||||||
|
'version': 'two point oh',
|
||||||
|
'services': {
|
||||||
|
'foo': {'image': 'busybox'}
|
||||||
|
}
|
||||||
|
}, 'working_dir', 'filename.yml')
|
||||||
|
)
|
||||||
|
|
||||||
def test_load_throws_error_when_not_dict(self):
|
def test_load_throws_error_when_not_dict(self):
|
||||||
with self.assertRaises(ConfigurationError):
|
with self.assertRaises(ConfigurationError):
|
||||||
config.load(
|
config.load(
|
||||||
|
@ -78,6 +157,16 @@ class ConfigTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_load_throws_error_when_not_dict_v2(self):
|
||||||
|
with self.assertRaises(ConfigurationError):
|
||||||
|
config.load(
|
||||||
|
build_config_details(
|
||||||
|
{'version': 2, 'services': {'web': 'busybox:latest'}},
|
||||||
|
'working_dir',
|
||||||
|
'filename.yml'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def test_load_config_invalid_service_names(self):
|
def test_load_config_invalid_service_names(self):
|
||||||
for invalid_name in ['?not?allowed', ' ', '', '!', '/', '\xe2']:
|
for invalid_name in ['?not?allowed', ' ', '', '!', '/', '\xe2']:
|
||||||
with pytest.raises(ConfigurationError) as exc:
|
with pytest.raises(ConfigurationError) as exc:
|
||||||
|
@ -87,6 +176,17 @@ class ConfigTest(unittest.TestCase):
|
||||||
'filename.yml'))
|
'filename.yml'))
|
||||||
assert 'Invalid service name \'%s\'' % invalid_name in exc.exconly()
|
assert 'Invalid service name \'%s\'' % invalid_name in exc.exconly()
|
||||||
|
|
||||||
|
def test_config_invalid_service_names_v2(self):
|
||||||
|
for invalid_name in ['?not?allowed', ' ', '', '!', '/', '\xe2']:
|
||||||
|
with pytest.raises(ConfigurationError) as exc:
|
||||||
|
config.load(
|
||||||
|
build_config_details({
|
||||||
|
'version': 2,
|
||||||
|
'services': {invalid_name: {'image': 'busybox'}}
|
||||||
|
}, 'working_dir', 'filename.yml')
|
||||||
|
)
|
||||||
|
assert 'Invalid service name \'%s\'' % invalid_name in exc.exconly()
|
||||||
|
|
||||||
def test_load_with_invalid_field_name(self):
|
def test_load_with_invalid_field_name(self):
|
||||||
config_details = build_config_details(
|
config_details = build_config_details(
|
||||||
{'web': {'image': 'busybox', 'name': 'bogus'}},
|
{'web': {'image': 'busybox', 'name': 'bogus'}},
|
||||||
|
@ -120,6 +220,22 @@ class ConfigTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_config_integer_service_name_raise_validation_error_v2(self):
|
||||||
|
expected_error_msg = ("In file 'filename.yml' service name: 1 needs to "
|
||||||
|
"be a string, eg '1'")
|
||||||
|
|
||||||
|
with self.assertRaisesRegexp(ConfigurationError, expected_error_msg):
|
||||||
|
config.load(
|
||||||
|
build_config_details(
|
||||||
|
{
|
||||||
|
'version': 2,
|
||||||
|
'services': {1: {'image': 'busybox'}}
|
||||||
|
},
|
||||||
|
'working_dir',
|
||||||
|
'filename.yml'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@pytest.mark.xfail(IS_WINDOWS_PLATFORM, reason='paths use slash')
|
@pytest.mark.xfail(IS_WINDOWS_PLATFORM, reason='paths use slash')
|
||||||
def test_load_with_multiple_files(self):
|
def test_load_with_multiple_files(self):
|
||||||
base_file = config.ConfigFile(
|
base_file = config.ConfigFile(
|
||||||
|
@ -248,12 +364,55 @@ class ConfigTest(unittest.TestCase):
|
||||||
'volumes': ['/tmp'],
|
'volumes': ['/tmp'],
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
services = config.load(config_details)
|
services = config.load(config_details).services
|
||||||
|
|
||||||
assert services[0]['name'] == 'volume'
|
assert services[0]['name'] == 'volume'
|
||||||
assert services[1]['name'] == 'db'
|
assert services[1]['name'] == 'db'
|
||||||
assert services[2]['name'] == 'web'
|
assert services[2]['name'] == 'web'
|
||||||
|
|
||||||
|
def test_load_with_multiple_files_v2(self):
|
||||||
|
base_file = config.ConfigFile(
|
||||||
|
'base.yaml',
|
||||||
|
{
|
||||||
|
'version': 2,
|
||||||
|
'services': {
|
||||||
|
'web': {
|
||||||
|
'image': 'example/web',
|
||||||
|
'links': ['db'],
|
||||||
|
},
|
||||||
|
'db': {
|
||||||
|
'image': 'example/db',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
override_file = config.ConfigFile(
|
||||||
|
'override.yaml',
|
||||||
|
{
|
||||||
|
'version': 2,
|
||||||
|
'services': {
|
||||||
|
'web': {
|
||||||
|
'build': '/',
|
||||||
|
'volumes': ['/home/user/project:/code'],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
details = config.ConfigDetails('.', [base_file, override_file])
|
||||||
|
|
||||||
|
service_dicts = config.load(details).services
|
||||||
|
expected = [
|
||||||
|
{
|
||||||
|
'name': 'web',
|
||||||
|
'build': os.path.abspath('/'),
|
||||||
|
'links': ['db'],
|
||||||
|
'volumes': [VolumeSpec.parse('/home/user/project:/code')],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'db',
|
||||||
|
'image': 'example/db',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
self.assertEqual(service_sort(service_dicts), service_sort(expected))
|
||||||
|
|
||||||
def test_config_valid_service_names(self):
|
def test_config_valid_service_names(self):
|
||||||
for valid_name in ['_', '-', '.__.', '_what-up.', 'what_.up----', 'whatup']:
|
for valid_name in ['_', '-', '.__.', '_what-up.', 'what_.up----', 'whatup']:
|
||||||
services = config.load(
|
services = config.load(
|
||||||
|
@ -742,7 +901,7 @@ class VolumeConfigTest(unittest.TestCase):
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
).services[0]
|
).services[0]
|
||||||
self.assertEqual(d['volumes'], ['/host/path:/container/path'])
|
self.assertEqual(d['volumes'], [VolumeSpec.parse('/host/path:/container/path')])
|
||||||
|
|
||||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='posix paths')
|
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='posix paths')
|
||||||
@mock.patch.dict(os.environ)
|
@mock.patch.dict(os.environ)
|
||||||
|
@ -1130,9 +1289,10 @@ class EnvTest(unittest.TestCase):
|
||||||
{'foo': {'build': '.', 'volumes': ['$HOSTENV:$CONTAINERENV']}},
|
{'foo': {'build': '.', 'volumes': ['$HOSTENV:$CONTAINERENV']}},
|
||||||
"tests/fixtures/env",
|
"tests/fixtures/env",
|
||||||
)
|
)
|
||||||
|
|
||||||
).services[0]
|
).services[0]
|
||||||
self.assertEqual(set(service_dict['volumes']), set(['/tmp:/host/tmp']))
|
self.assertEqual(
|
||||||
|
set(service_dict['volumes']),
|
||||||
|
set([VolumeSpec.parse('/tmp:/host/tmp')]))
|
||||||
|
|
||||||
service_dict = config.load(
|
service_dict = config.load(
|
||||||
build_config_details(
|
build_config_details(
|
||||||
|
@ -1140,7 +1300,9 @@ class EnvTest(unittest.TestCase):
|
||||||
"tests/fixtures/env",
|
"tests/fixtures/env",
|
||||||
)
|
)
|
||||||
).services[0]
|
).services[0]
|
||||||
self.assertEqual(set(service_dict['volumes']), set(['/opt/tmp:/opt/host/tmp']))
|
self.assertEqual(
|
||||||
|
set(service_dict['volumes']),
|
||||||
|
set([VolumeSpec.parse('/opt/tmp:/opt/host/tmp')]))
|
||||||
|
|
||||||
|
|
||||||
def load_from_filename(filename):
|
def load_from_filename(filename):
|
||||||
|
@ -1595,7 +1757,7 @@ class BuildPathTest(unittest.TestCase):
|
||||||
for valid_url in valid_urls:
|
for valid_url in valid_urls:
|
||||||
service_dict = config.load(build_config_details({
|
service_dict = config.load(build_config_details({
|
||||||
'validurl': {'build': valid_url},
|
'validurl': {'build': valid_url},
|
||||||
}, '.', None))
|
}, '.', None)).services
|
||||||
assert service_dict[0]['build'] == valid_url
|
assert service_dict[0]['build'] == valid_url
|
||||||
|
|
||||||
def test_invalid_url_in_build_path(self):
|
def test_invalid_url_in_build_path(self):
|
||||||
|
|
|
@ -35,29 +35,6 @@ class ProjectTest(unittest.TestCase):
|
||||||
self.assertEqual(project.get_service('db').name, 'db')
|
self.assertEqual(project.get_service('db').name, 'db')
|
||||||
self.assertEqual(project.get_service('db').options['image'], 'busybox:latest')
|
self.assertEqual(project.get_service('db').options['image'], 'busybox:latest')
|
||||||
|
|
||||||
def test_from_dict_sorts_in_dependency_order(self):
|
|
||||||
project = Project.from_config('composetest', Config(None, [
|
|
||||||
{
|
|
||||||
'name': 'web',
|
|
||||||
'image': 'busybox:latest',
|
|
||||||
'links': ['db'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'db',
|
|
||||||
'image': 'busybox:latest',
|
|
||||||
'volumes_from': ['volume']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'volume',
|
|
||||||
'image': 'busybox:latest',
|
|
||||||
'volumes': ['/tmp'],
|
|
||||||
}
|
|
||||||
], None), None)
|
|
||||||
|
|
||||||
self.assertEqual(project.services[0].name, 'volume')
|
|
||||||
self.assertEqual(project.services[1].name, 'db')
|
|
||||||
self.assertEqual(project.services[2].name, 'web')
|
|
||||||
|
|
||||||
def test_from_config(self):
|
def test_from_config(self):
|
||||||
dicts = Config(None, [
|
dicts = Config(None, [
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue