|
|
@@ -26,7 +26,7 @@ def make_service_dict(name, service_dict, working_dir, filename=None):
|
|
|
working_dir=working_dir,
|
|
|
filename=filename,
|
|
|
name=name,
|
|
|
- config=service_dict))
|
|
|
+ config=service_dict), version=1)
|
|
|
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):
|
|
|
with self.assertRaises(ConfigurationError):
|
|
|
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):
|
|
|
for invalid_name in ['?not?allowed', ' ', '', '!', '/', '\xe2']:
|
|
|
with pytest.raises(ConfigurationError) as exc:
|
|
|
@@ -87,6 +176,17 @@ class ConfigTest(unittest.TestCase):
|
|
|
'filename.yml'))
|
|
|
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):
|
|
|
config_details = build_config_details(
|
|
|
{'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')
|
|
|
def test_load_with_multiple_files(self):
|
|
|
base_file = config.ConfigFile(
|
|
|
@@ -248,12 +364,55 @@ class ConfigTest(unittest.TestCase):
|
|
|
'volumes': ['/tmp'],
|
|
|
}
|
|
|
})
|
|
|
- services = config.load(config_details)
|
|
|
+ services = config.load(config_details).services
|
|
|
|
|
|
assert services[0]['name'] == 'volume'
|
|
|
assert services[1]['name'] == 'db'
|
|
|
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):
|
|
|
for valid_name in ['_', '-', '.__.', '_what-up.', 'what_.up----', 'whatup']:
|
|
|
services = config.load(
|
|
|
@@ -742,7 +901,7 @@ class VolumeConfigTest(unittest.TestCase):
|
|
|
None,
|
|
|
)
|
|
|
).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')
|
|
|
@mock.patch.dict(os.environ)
|
|
|
@@ -1130,9 +1289,10 @@ class EnvTest(unittest.TestCase):
|
|
|
{'foo': {'build': '.', 'volumes': ['$HOSTENV:$CONTAINERENV']}},
|
|
|
"tests/fixtures/env",
|
|
|
)
|
|
|
-
|
|
|
).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(
|
|
|
build_config_details(
|
|
|
@@ -1140,7 +1300,9 @@ class EnvTest(unittest.TestCase):
|
|
|
"tests/fixtures/env",
|
|
|
)
|
|
|
).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):
|
|
|
@@ -1595,7 +1757,7 @@ class BuildPathTest(unittest.TestCase):
|
|
|
for valid_url in valid_urls:
|
|
|
service_dict = config.load(build_config_details({
|
|
|
'validurl': {'build': valid_url},
|
|
|
- }, '.', None))
|
|
|
+ }, '.', None)).services
|
|
|
assert service_dict[0]['build'] == valid_url
|
|
|
|
|
|
def test_invalid_url_in_build_path(self):
|