Add v2 configuration tests

Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
Joffrey F 2015-12-01 17:28:42 -08:00
parent df6877a277
commit ecef5d37a7
5 changed files with 251 additions and 31 deletions

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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):

View File

@ -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, [
{ {