mirror of https://github.com/docker/compose.git
Rewriting tests to be UCP/Swarm compatible
- Event may contain more information in some cases. Don't assume order or format - Don't assume ports are always exposed on 0.0.0.0 by default - Absence of HostConfig in a create payload sometimes causes an error at the engine level - In Swarm, volume names are prefixed by "<node_name>/" - When testing against Swarm, the default network driver is overlay - Ensure custom test networks are always attachable - Handle Swarm network names - Some params moved to host config in recent (1.21+) version - Conditional test skips for Swarm environments Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
e9b6cc23fc
commit
7a4c328c41
|
@ -56,7 +56,9 @@ HOST_CONFIG_KEYS = [
|
|||
'cpu_count',
|
||||
'cpu_percent',
|
||||
'cpu_quota',
|
||||
'cpu_shares',
|
||||
'cpus',
|
||||
'cpuset',
|
||||
'devices',
|
||||
'dns',
|
||||
'dns_search',
|
||||
|
@ -83,6 +85,7 @@ HOST_CONFIG_KEYS = [
|
|||
'sysctls',
|
||||
'userns_mode',
|
||||
'volumes_from',
|
||||
'volume_driver',
|
||||
]
|
||||
|
||||
CONDITION_STARTED = 'service_started'
|
||||
|
@ -848,6 +851,9 @@ class Service(object):
|
|||
cpu_count=options.get('cpu_count'),
|
||||
cpu_percent=options.get('cpu_percent'),
|
||||
nano_cpus=nano_cpus,
|
||||
volume_driver=options.get('volume_driver'),
|
||||
cpuset_cpus=options.get('cpuset'),
|
||||
cpu_shares=options.get('cpu_shares'),
|
||||
)
|
||||
|
||||
def get_secret_volumes(self):
|
||||
|
|
|
@ -20,6 +20,8 @@ from docker import errors
|
|||
|
||||
from .. import mock
|
||||
from ..helpers import create_host_file
|
||||
from ..helpers import is_cluster
|
||||
from ..helpers import no_cluster
|
||||
from compose.cli.command import get_project
|
||||
from compose.config.errors import DuplicateOverrideFileFound
|
||||
from compose.container import Container
|
||||
|
@ -28,6 +30,7 @@ from compose.utils import nanoseconds_from_time_seconds
|
|||
from tests.integration.testcases import DockerClientTestCase
|
||||
from tests.integration.testcases import get_links
|
||||
from tests.integration.testcases import pull_busybox
|
||||
from tests.integration.testcases import SWARM_SKIP_RM_VOLUMES
|
||||
from tests.integration.testcases import v2_1_only
|
||||
from tests.integration.testcases import v2_only
|
||||
from tests.integration.testcases import v3_only
|
||||
|
@ -68,7 +71,8 @@ def wait_on_condition(condition, delay=0.1, timeout=40):
|
|||
|
||||
def kill_service(service):
|
||||
for container in service.containers():
|
||||
container.kill()
|
||||
if container.is_running:
|
||||
container.kill()
|
||||
|
||||
|
||||
class ContainerCountCondition(object):
|
||||
|
@ -78,7 +82,7 @@ class ContainerCountCondition(object):
|
|||
self.expected = expected
|
||||
|
||||
def __call__(self):
|
||||
return len(self.project.containers()) == self.expected
|
||||
return len([c for c in self.project.containers() if c.is_running]) == self.expected
|
||||
|
||||
def __str__(self):
|
||||
return "waiting for counter count == %s" % self.expected
|
||||
|
@ -116,11 +120,14 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
for container in self.project.containers(stopped=True, one_off=OneOffFilter.only):
|
||||
container.remove(force=True)
|
||||
|
||||
networks = self.client.networks()
|
||||
for n in networks:
|
||||
if n['Name'].startswith('{}_'.format(self.project.name)):
|
||||
if n['Name'].split('/')[-1].startswith('{}_'.format(self.project.name)):
|
||||
self.client.remove_network(n['Name'])
|
||||
volumes = self.client.volumes().get('Volumes') or []
|
||||
for v in volumes:
|
||||
if v['Name'].split('/')[-1].startswith('{}_'.format(self.project.name)):
|
||||
self.client.remove_volume(v['Name'])
|
||||
if hasattr(self, '_project'):
|
||||
del self._project
|
||||
|
||||
|
@ -175,7 +182,10 @@ class CLITestCase(DockerClientTestCase):
|
|||
def test_host_not_reachable_volumes_from_container(self):
|
||||
self.base_dir = 'tests/fixtures/volumes-from-container'
|
||||
|
||||
container = self.client.create_container('busybox', 'true', name='composetest_data_container')
|
||||
container = self.client.create_container(
|
||||
'busybox', 'true', name='composetest_data_container',
|
||||
host_config={}
|
||||
)
|
||||
self.addCleanup(self.client.remove_container, container)
|
||||
|
||||
result = self.dispatch(['-H=tcp://doesnotexist:8000', 'ps'], returncode=1)
|
||||
|
@ -545,42 +555,48 @@ class CLITestCase(DockerClientTestCase):
|
|||
self.dispatch(['create'])
|
||||
service = self.project.get_service('simple')
|
||||
another = self.project.get_service('another')
|
||||
self.assertEqual(len(service.containers()), 0)
|
||||
self.assertEqual(len(another.containers()), 0)
|
||||
self.assertEqual(len(service.containers(stopped=True)), 1)
|
||||
self.assertEqual(len(another.containers(stopped=True)), 1)
|
||||
service_containers = service.containers(stopped=True)
|
||||
another_containers = another.containers(stopped=True)
|
||||
assert len(service_containers) == 1
|
||||
assert len(another_containers) == 1
|
||||
assert not service_containers[0].is_running
|
||||
assert not another_containers[0].is_running
|
||||
|
||||
def test_create_with_force_recreate(self):
|
||||
self.dispatch(['create'], None)
|
||||
service = self.project.get_service('simple')
|
||||
self.assertEqual(len(service.containers()), 0)
|
||||
self.assertEqual(len(service.containers(stopped=True)), 1)
|
||||
service_containers = service.containers(stopped=True)
|
||||
assert len(service_containers) == 1
|
||||
assert not service_containers[0].is_running
|
||||
|
||||
old_ids = [c.id for c in service.containers(stopped=True)]
|
||||
|
||||
self.dispatch(['create', '--force-recreate'], None)
|
||||
self.assertEqual(len(service.containers()), 0)
|
||||
self.assertEqual(len(service.containers(stopped=True)), 1)
|
||||
service_containers = service.containers(stopped=True)
|
||||
assert len(service_containers) == 1
|
||||
assert not service_containers[0].is_running
|
||||
|
||||
new_ids = [c.id for c in service.containers(stopped=True)]
|
||||
new_ids = [c.id for c in service_containers]
|
||||
|
||||
self.assertNotEqual(old_ids, new_ids)
|
||||
assert old_ids != new_ids
|
||||
|
||||
def test_create_with_no_recreate(self):
|
||||
self.dispatch(['create'], None)
|
||||
service = self.project.get_service('simple')
|
||||
self.assertEqual(len(service.containers()), 0)
|
||||
self.assertEqual(len(service.containers(stopped=True)), 1)
|
||||
service_containers = service.containers(stopped=True)
|
||||
assert len(service_containers) == 1
|
||||
assert not service_containers[0].is_running
|
||||
|
||||
old_ids = [c.id for c in service.containers(stopped=True)]
|
||||
|
||||
self.dispatch(['create', '--no-recreate'], None)
|
||||
self.assertEqual(len(service.containers()), 0)
|
||||
self.assertEqual(len(service.containers(stopped=True)), 1)
|
||||
service_containers = service.containers(stopped=True)
|
||||
assert len(service_containers) == 1
|
||||
assert not service_containers[0].is_running
|
||||
|
||||
new_ids = [c.id for c in service.containers(stopped=True)]
|
||||
new_ids = [c.id for c in service_containers]
|
||||
|
||||
self.assertEqual(old_ids, new_ids)
|
||||
assert old_ids == new_ids
|
||||
|
||||
def test_run_one_off_with_volume(self):
|
||||
self.base_dir = 'tests/fixtures/simple-composefile-volume-ready'
|
||||
|
@ -687,7 +703,7 @@ class CLITestCase(DockerClientTestCase):
|
|||
network_name = self.project.networks.networks['default'].full_name
|
||||
networks = self.client.networks(names=[network_name])
|
||||
self.assertEqual(len(networks), 1)
|
||||
self.assertEqual(networks[0]['Driver'], 'bridge')
|
||||
assert networks[0]['Driver'] == 'bridge' if not is_cluster(self.client) else 'overlay'
|
||||
assert 'com.docker.network.bridge.enable_icc' not in networks[0]['Options']
|
||||
|
||||
network = self.client.inspect_network(networks[0]['Id'])
|
||||
|
@ -733,11 +749,11 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
networks = [
|
||||
n for n in self.client.networks()
|
||||
if n['Name'].startswith('{}_'.format(self.project.name))
|
||||
if n['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
|
||||
]
|
||||
|
||||
# Two networks were created: back and front
|
||||
assert sorted(n['Name'] for n in networks) == [back_name, front_name]
|
||||
assert sorted(n['Name'].split('/')[-1] for n in networks) == [back_name, front_name]
|
||||
web_container = self.project.get_service('web').containers()[0]
|
||||
|
||||
back_aliases = web_container.get(
|
||||
|
@ -761,11 +777,11 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
networks = [
|
||||
n for n in self.client.networks()
|
||||
if n['Name'].startswith('{}_'.format(self.project.name))
|
||||
if n['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
|
||||
]
|
||||
|
||||
# One network was created: internal
|
||||
assert sorted(n['Name'] for n in networks) == [internal_net]
|
||||
assert sorted(n['Name'].split('/')[-1] for n in networks) == [internal_net]
|
||||
|
||||
assert networks[0]['Internal'] is True
|
||||
|
||||
|
@ -780,11 +796,11 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
networks = [
|
||||
n for n in self.client.networks()
|
||||
if n['Name'].startswith('{}_'.format(self.project.name))
|
||||
if n['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
|
||||
]
|
||||
|
||||
# One networks was created: front
|
||||
assert sorted(n['Name'] for n in networks) == [static_net]
|
||||
assert sorted(n['Name'].split('/')[-1] for n in networks) == [static_net]
|
||||
web_container = self.project.get_service('web').containers()[0]
|
||||
|
||||
ipam_config = web_container.get(
|
||||
|
@ -803,11 +819,11 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
networks = [
|
||||
n for n in self.client.networks()
|
||||
if n['Name'].startswith('{}_'.format(self.project.name))
|
||||
if n['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
|
||||
]
|
||||
|
||||
# Two networks were created: back and front
|
||||
assert sorted(n['Name'] for n in networks) == [back_name, front_name]
|
||||
assert sorted(n['Name'].split('/')[-1] for n in networks) == [back_name, front_name]
|
||||
|
||||
back_network = [n for n in networks if n['Name'] == back_name][0]
|
||||
front_network = [n for n in networks if n['Name'] == front_name][0]
|
||||
|
@ -847,8 +863,12 @@ class CLITestCase(DockerClientTestCase):
|
|||
assert 'Service "web" uses an undefined network "foo"' in result.stderr
|
||||
|
||||
@v2_only()
|
||||
@no_cluster('container networks not supported in Swarm')
|
||||
def test_up_with_network_mode(self):
|
||||
c = self.client.create_container('busybox', 'top', name='composetest_network_mode_container')
|
||||
c = self.client.create_container(
|
||||
'busybox', 'top', name='composetest_network_mode_container',
|
||||
host_config={}
|
||||
)
|
||||
self.addCleanup(self.client.remove_container, c, force=True)
|
||||
self.client.start(c)
|
||||
container_mode_source = 'container:{}'.format(c['Id'])
|
||||
|
@ -862,7 +882,7 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
networks = [
|
||||
n for n in self.client.networks()
|
||||
if n['Name'].startswith('{}_'.format(self.project.name))
|
||||
if n['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
|
||||
]
|
||||
assert not networks
|
||||
|
||||
|
@ -899,7 +919,7 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
network_names = ['{}_{}'.format(self.project.name, n) for n in ['foo', 'bar']]
|
||||
for name in network_names:
|
||||
self.client.create_network(name)
|
||||
self.client.create_network(name, attachable=True)
|
||||
|
||||
self.dispatch(['-f', filename, 'up', '-d'])
|
||||
container = self.project.containers()[0]
|
||||
|
@ -917,12 +937,12 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
networks = [
|
||||
n['Name'] for n in self.client.networks()
|
||||
if n['Name'].startswith('{}_'.format(self.project.name))
|
||||
if n['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
|
||||
]
|
||||
assert not networks
|
||||
|
||||
network_name = 'composetest_external_network'
|
||||
self.client.create_network(network_name)
|
||||
self.client.create_network(network_name, attachable=True)
|
||||
|
||||
self.dispatch(['-f', filename, 'up', '-d'])
|
||||
container = self.project.containers()[0]
|
||||
|
@ -941,10 +961,10 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
networks = [
|
||||
n for n in self.client.networks()
|
||||
if n['Name'].startswith('{}_'.format(self.project.name))
|
||||
if n['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
|
||||
]
|
||||
|
||||
assert [n['Name'] for n in networks] == [network_with_label]
|
||||
assert [n['Name'].split('/')[-1] for n in networks] == [network_with_label]
|
||||
assert 'label_key' in networks[0]['Labels']
|
||||
assert networks[0]['Labels']['label_key'] == 'label_val'
|
||||
|
||||
|
@ -961,10 +981,10 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
volumes = [
|
||||
v for v in self.client.volumes().get('Volumes', [])
|
||||
if v['Name'].startswith('{}_'.format(self.project.name))
|
||||
if v['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
|
||||
]
|
||||
|
||||
assert [v['Name'] for v in volumes] == [volume_with_label]
|
||||
assert set([v['Name'].split('/')[-1] for v in volumes]) == set([volume_with_label])
|
||||
assert 'label_key' in volumes[0]['Labels']
|
||||
assert volumes[0]['Labels']['label_key'] == 'label_val'
|
||||
|
||||
|
@ -975,7 +995,7 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
network_names = [
|
||||
n['Name'] for n in self.client.networks()
|
||||
if n['Name'].startswith('{}_'.format(self.project.name))
|
||||
if n['Name'].split('/')[-1].startswith('{}_'.format(self.project.name))
|
||||
]
|
||||
assert network_names == []
|
||||
|
||||
|
@ -1010,6 +1030,7 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
assert "Unsupported config option for services.bar: 'net'" in result.stderr
|
||||
|
||||
@no_cluster("Legacy networking not supported on Swarm")
|
||||
def test_up_with_net_v1(self):
|
||||
self.base_dir = 'tests/fixtures/net-container'
|
||||
self.dispatch(['up', '-d'], None)
|
||||
|
@ -1261,6 +1282,7 @@ class CLITestCase(DockerClientTestCase):
|
|||
[u'/bin/true'],
|
||||
)
|
||||
|
||||
@py.test.mark.skipif(SWARM_SKIP_RM_VOLUMES, reason='Swarm DELETE /containers/<id> bug')
|
||||
def test_run_rm(self):
|
||||
self.base_dir = 'tests/fixtures/volume'
|
||||
proc = start_process(self.base_dir, ['run', '--rm', 'test'])
|
||||
|
@ -1274,7 +1296,7 @@ class CLITestCase(DockerClientTestCase):
|
|||
mounts = containers[0].get('Mounts')
|
||||
for mount in mounts:
|
||||
if mount['Destination'] == '/container-path':
|
||||
anonymousName = mount['Name']
|
||||
anonymous_name = mount['Name']
|
||||
break
|
||||
os.kill(proc.pid, signal.SIGINT)
|
||||
wait_on_process(proc, 1)
|
||||
|
@ -1287,9 +1309,11 @@ class CLITestCase(DockerClientTestCase):
|
|||
if volume.internal == '/container-named-path':
|
||||
name = volume.external
|
||||
break
|
||||
volumeNames = [v['Name'] for v in volumes]
|
||||
assert name in volumeNames
|
||||
assert anonymousName not in volumeNames
|
||||
volume_names = [v['Name'].split('/')[-1] for v in volumes]
|
||||
assert name in volume_names
|
||||
if not is_cluster(self.client):
|
||||
# The `-v` flag for `docker rm` in Swarm seems to be broken
|
||||
assert anonymous_name not in volume_names
|
||||
|
||||
def test_run_service_with_dockerfile_entrypoint(self):
|
||||
self.base_dir = 'tests/fixtures/entrypoint-dockerfile'
|
||||
|
@ -1411,11 +1435,10 @@ class CLITestCase(DockerClientTestCase):
|
|||
container.stop()
|
||||
|
||||
# check the ports
|
||||
self.assertNotEqual(port_random, None)
|
||||
self.assertIn("0.0.0.0", port_random)
|
||||
self.assertEqual(port_assigned, "0.0.0.0:49152")
|
||||
self.assertEqual(port_range[0], "0.0.0.0:49153")
|
||||
self.assertEqual(port_range[1], "0.0.0.0:49154")
|
||||
assert port_random is not None
|
||||
assert port_assigned.endswith(':49152')
|
||||
assert port_range[0].endswith(':49153')
|
||||
assert port_range[1].endswith(':49154')
|
||||
|
||||
def test_run_service_with_explicitly_mapped_ports(self):
|
||||
# create one off container
|
||||
|
@ -1431,8 +1454,8 @@ class CLITestCase(DockerClientTestCase):
|
|||
container.stop()
|
||||
|
||||
# check the ports
|
||||
self.assertEqual(port_short, "0.0.0.0:30000")
|
||||
self.assertEqual(port_full, "0.0.0.0:30001")
|
||||
assert port_short.endswith(':30000')
|
||||
assert port_full.endswith(':30001')
|
||||
|
||||
def test_run_service_with_explicitly_mapped_ip_ports(self):
|
||||
# create one off container
|
||||
|
@ -1953,9 +1976,9 @@ class CLITestCase(DockerClientTestCase):
|
|||
result = self.dispatch(['port', 'simple', str(number)])
|
||||
return result.stdout.rstrip()
|
||||
|
||||
self.assertEqual(get_port(3000), container.get_local_port(3000))
|
||||
self.assertEqual(get_port(3001), "0.0.0.0:49152")
|
||||
self.assertEqual(get_port(3002), "0.0.0.0:49153")
|
||||
assert get_port(3000) == container.get_local_port(3000)
|
||||
assert ':49152' in get_port(3001)
|
||||
assert ':49153' in get_port(3002)
|
||||
|
||||
def test_expanded_port(self):
|
||||
self.base_dir = 'tests/fixtures/ports-composefile'
|
||||
|
@ -1966,9 +1989,9 @@ class CLITestCase(DockerClientTestCase):
|
|||
result = self.dispatch(['port', 'simple', str(number)])
|
||||
return result.stdout.rstrip()
|
||||
|
||||
self.assertEqual(get_port(3000), container.get_local_port(3000))
|
||||
self.assertEqual(get_port(3001), "0.0.0.0:49152")
|
||||
self.assertEqual(get_port(3002), "0.0.0.0:49153")
|
||||
assert get_port(3000) == container.get_local_port(3000)
|
||||
assert ':49152' in get_port(3001)
|
||||
assert ':49153' in get_port(3002)
|
||||
|
||||
def test_port_with_scale(self):
|
||||
self.base_dir = 'tests/fixtures/ports-composefile-scale'
|
||||
|
@ -2021,12 +2044,14 @@ class CLITestCase(DockerClientTestCase):
|
|||
assert len(lines) == 2
|
||||
|
||||
container, = self.project.containers()
|
||||
expected_template = (
|
||||
' container {} {} (image=busybox:latest, '
|
||||
'name=simplecomposefile_simple_1)')
|
||||
expected_template = ' container {} {}'
|
||||
expected_meta_info = ['image=busybox:latest', 'name=simplecomposefile_simple_1']
|
||||
|
||||
assert expected_template.format('create', container.id) in lines[0]
|
||||
assert expected_template.format('start', container.id) in lines[1]
|
||||
for line in lines:
|
||||
for info in expected_meta_info:
|
||||
assert info in line
|
||||
|
||||
assert has_timestamp(lines[0])
|
||||
|
||||
|
@ -2069,7 +2094,6 @@ class CLITestCase(DockerClientTestCase):
|
|||
'docker-compose.yml',
|
||||
'docker-compose.override.yml',
|
||||
'extra.yml',
|
||||
|
||||
]
|
||||
self._project = get_project(self.base_dir, config_paths)
|
||||
self.dispatch(
|
||||
|
@ -2086,7 +2110,6 @@ class CLITestCase(DockerClientTestCase):
|
|||
|
||||
web, other, db = containers
|
||||
self.assertEqual(web.human_readable_command, 'top')
|
||||
self.assertTrue({'db', 'other'} <= set(get_links(web)))
|
||||
self.assertEqual(db.human_readable_command, 'top')
|
||||
self.assertEqual(other.human_readable_command, 'top')
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
web:
|
||||
version: '2.2'
|
||||
services:
|
||||
web:
|
||||
command: "top"
|
||||
|
||||
db:
|
||||
db:
|
||||
command: "top"
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
web:
|
||||
version: '2.2'
|
||||
services:
|
||||
web:
|
||||
image: busybox:latest
|
||||
command: "sleep 200"
|
||||
links:
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
db:
|
||||
db:
|
||||
image: busybox:latest
|
||||
command: "sleep 200"
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
|
||||
web:
|
||||
links:
|
||||
version: '2.2'
|
||||
services:
|
||||
web:
|
||||
depends_on:
|
||||
- db
|
||||
- other
|
||||
|
||||
other:
|
||||
other:
|
||||
image: busybox:latest
|
||||
command: "top"
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import functools
|
||||
import os
|
||||
|
||||
from docker.errors import APIError
|
||||
from pytest import skip
|
||||
|
||||
from compose.config.config import ConfigDetails
|
||||
from compose.config.config import ConfigFile
|
||||
from compose.config.config import load
|
||||
|
@ -44,3 +48,34 @@ def create_host_file(client, filename):
|
|||
"Container exited with code {}:\n{}".format(exitcode, output))
|
||||
finally:
|
||||
client.remove_container(container, force=True)
|
||||
|
||||
|
||||
def is_cluster(client):
|
||||
nodes = None
|
||||
|
||||
def get_nodes_number():
|
||||
try:
|
||||
return len(client.nodes())
|
||||
except APIError:
|
||||
# If the Engine is not part of a Swarm, the SDK will raise
|
||||
# an APIError
|
||||
return 0
|
||||
|
||||
if nodes is None:
|
||||
# Only make the API call if the value hasn't been cached yet
|
||||
nodes = get_nodes_number()
|
||||
|
||||
return nodes > 1
|
||||
|
||||
|
||||
def no_cluster(reason):
|
||||
def decorator(f):
|
||||
@functools.wraps(f)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
if is_cluster(self.client):
|
||||
skip("Test will not be run in cluster mode: %s" % reason)
|
||||
return
|
||||
return f(self, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
|
|
@ -6,12 +6,16 @@ import random
|
|||
|
||||
import py
|
||||
import pytest
|
||||
from docker.errors import APIError
|
||||
from docker.errors import NotFound
|
||||
|
||||
from .. import mock
|
||||
from ..helpers import build_config as load_config
|
||||
from ..helpers import create_host_file
|
||||
from ..helpers import is_cluster
|
||||
from ..helpers import no_cluster
|
||||
from .testcases import DockerClientTestCase
|
||||
from .testcases import SWARM_SKIP_CONTAINERS_ALL
|
||||
from compose.config import config
|
||||
from compose.config import ConfigurationError
|
||||
from compose.config import types
|
||||
|
@ -57,6 +61,20 @@ class ProjectTest(DockerClientTestCase):
|
|||
containers = project.containers()
|
||||
self.assertEqual(len(containers), 2)
|
||||
|
||||
@pytest.mark.skipif(SWARM_SKIP_CONTAINERS_ALL, reason='Swarm /containers/json bug')
|
||||
def test_containers_stopped(self):
|
||||
web = self.create_service('web')
|
||||
db = self.create_service('db')
|
||||
project = Project('composetest', [web, db], self.client)
|
||||
|
||||
project.up()
|
||||
assert len(project.containers()) == 2
|
||||
assert len(project.containers(stopped=True)) == 2
|
||||
|
||||
project.stop()
|
||||
assert len(project.containers()) == 0
|
||||
assert len(project.containers(stopped=True)) == 2
|
||||
|
||||
def test_containers_with_service_names(self):
|
||||
web = self.create_service('web')
|
||||
db = self.create_service('db')
|
||||
|
@ -110,6 +128,7 @@ class ProjectTest(DockerClientTestCase):
|
|||
volumes=['/var/data'],
|
||||
name='composetest_data_container',
|
||||
labels={LABEL_PROJECT: 'composetest'},
|
||||
host_config={},
|
||||
)
|
||||
project = Project.from_config(
|
||||
name='composetest',
|
||||
|
@ -125,6 +144,7 @@ class ProjectTest(DockerClientTestCase):
|
|||
self.assertEqual(db._get_volumes_from(), [data_container.id + ':rw'])
|
||||
|
||||
@v2_only()
|
||||
@no_cluster('container networks not supported in Swarm')
|
||||
def test_network_mode_from_service(self):
|
||||
project = Project.from_config(
|
||||
name='composetest',
|
||||
|
@ -152,6 +172,7 @@ class ProjectTest(DockerClientTestCase):
|
|||
self.assertEqual(web.network_mode.mode, 'container:' + net.containers()[0].id)
|
||||
|
||||
@v2_only()
|
||||
@no_cluster('container networks not supported in Swarm')
|
||||
def test_network_mode_from_container(self):
|
||||
def get_project():
|
||||
return Project.from_config(
|
||||
|
@ -179,6 +200,7 @@ class ProjectTest(DockerClientTestCase):
|
|||
name='composetest_net_container',
|
||||
command='top',
|
||||
labels={LABEL_PROJECT: 'composetest'},
|
||||
host_config={},
|
||||
)
|
||||
net_container.start()
|
||||
|
||||
|
@ -188,6 +210,7 @@ class ProjectTest(DockerClientTestCase):
|
|||
web = project.get_service('web')
|
||||
self.assertEqual(web.network_mode.mode, 'container:' + net_container.id)
|
||||
|
||||
@no_cluster('container networks not supported in Swarm')
|
||||
def test_net_from_service_v1(self):
|
||||
project = Project.from_config(
|
||||
name='composetest',
|
||||
|
@ -211,6 +234,7 @@ class ProjectTest(DockerClientTestCase):
|
|||
net = project.get_service('net')
|
||||
self.assertEqual(web.network_mode.mode, 'container:' + net.containers()[0].id)
|
||||
|
||||
@no_cluster('container networks not supported in Swarm')
|
||||
def test_net_from_container_v1(self):
|
||||
def get_project():
|
||||
return Project.from_config(
|
||||
|
@ -235,6 +259,7 @@ class ProjectTest(DockerClientTestCase):
|
|||
name='composetest_net_container',
|
||||
command='top',
|
||||
labels={LABEL_PROJECT: 'composetest'},
|
||||
host_config={},
|
||||
)
|
||||
net_container.start()
|
||||
|
||||
|
@ -260,12 +285,12 @@ class ProjectTest(DockerClientTestCase):
|
|||
|
||||
project.start(service_names=['web'])
|
||||
self.assertEqual(
|
||||
set(c.name for c in project.containers()),
|
||||
set(c.name for c in project.containers() if c.is_running),
|
||||
set([web_container_1.name, web_container_2.name]))
|
||||
|
||||
project.start()
|
||||
self.assertEqual(
|
||||
set(c.name for c in project.containers()),
|
||||
set(c.name for c in project.containers() if c.is_running),
|
||||
set([web_container_1.name, web_container_2.name, db_container.name]))
|
||||
|
||||
project.pause(service_names=['web'])
|
||||
|
@ -285,10 +310,12 @@ class ProjectTest(DockerClientTestCase):
|
|||
self.assertEqual(len([c.name for c in project.containers() if c.is_paused]), 0)
|
||||
|
||||
project.stop(service_names=['web'], timeout=1)
|
||||
self.assertEqual(set(c.name for c in project.containers()), set([db_container.name]))
|
||||
self.assertEqual(
|
||||
set(c.name for c in project.containers() if c.is_running), set([db_container.name])
|
||||
)
|
||||
|
||||
project.kill(service_names=['db'])
|
||||
self.assertEqual(len(project.containers()), 0)
|
||||
self.assertEqual(len([c for c in project.containers() if c.is_running]), 0)
|
||||
self.assertEqual(len(project.containers(stopped=True)), 3)
|
||||
|
||||
project.remove_stopped(service_names=['web'])
|
||||
|
@ -303,11 +330,13 @@ class ProjectTest(DockerClientTestCase):
|
|||
project = Project('composetest', [web, db], self.client)
|
||||
|
||||
project.create(['db'])
|
||||
self.assertEqual(len(project.containers()), 0)
|
||||
self.assertEqual(len(project.containers(stopped=True)), 1)
|
||||
self.assertEqual(len(db.containers()), 0)
|
||||
self.assertEqual(len(db.containers(stopped=True)), 1)
|
||||
self.assertEqual(len(web.containers(stopped=True)), 0)
|
||||
containers = project.containers(stopped=True)
|
||||
assert len(containers) == 1
|
||||
assert not containers[0].is_running
|
||||
db_containers = db.containers(stopped=True)
|
||||
assert len(db_containers) == 1
|
||||
assert not db_containers[0].is_running
|
||||
assert len(web.containers(stopped=True)) == 0
|
||||
|
||||
def test_create_twice(self):
|
||||
web = self.create_service('web')
|
||||
|
@ -316,12 +345,14 @@ class ProjectTest(DockerClientTestCase):
|
|||
|
||||
project.create(['db', 'web'])
|
||||
project.create(['db', 'web'])
|
||||
self.assertEqual(len(project.containers()), 0)
|
||||
self.assertEqual(len(project.containers(stopped=True)), 2)
|
||||
self.assertEqual(len(db.containers()), 0)
|
||||
self.assertEqual(len(db.containers(stopped=True)), 1)
|
||||
self.assertEqual(len(web.containers()), 0)
|
||||
self.assertEqual(len(web.containers(stopped=True)), 1)
|
||||
containers = project.containers(stopped=True)
|
||||
assert len(containers) == 2
|
||||
db_containers = db.containers(stopped=True)
|
||||
assert len(db_containers) == 1
|
||||
assert not db_containers[0].is_running
|
||||
web_containers = web.containers(stopped=True)
|
||||
assert len(web_containers) == 1
|
||||
assert not web_containers[0].is_running
|
||||
|
||||
def test_create_with_links(self):
|
||||
db = self.create_service('db')
|
||||
|
@ -329,12 +360,11 @@ class ProjectTest(DockerClientTestCase):
|
|||
project = Project('composetest', [db, web], self.client)
|
||||
|
||||
project.create(['web'])
|
||||
self.assertEqual(len(project.containers()), 0)
|
||||
self.assertEqual(len(project.containers(stopped=True)), 2)
|
||||
self.assertEqual(len(db.containers()), 0)
|
||||
self.assertEqual(len(db.containers(stopped=True)), 1)
|
||||
self.assertEqual(len(web.containers()), 0)
|
||||
self.assertEqual(len(web.containers(stopped=True)), 1)
|
||||
# self.assertEqual(len(project.containers()), 0)
|
||||
assert len(project.containers(stopped=True)) == 2
|
||||
assert not [c for c in project.containers(stopped=True) if c.is_running]
|
||||
assert len(db.containers(stopped=True)) == 1
|
||||
assert len(web.containers(stopped=True)) == 1
|
||||
|
||||
def test_create_strategy_always(self):
|
||||
db = self.create_service('db')
|
||||
|
@ -343,11 +373,11 @@ class ProjectTest(DockerClientTestCase):
|
|||
old_id = project.containers(stopped=True)[0].id
|
||||
|
||||
project.create(['db'], strategy=ConvergenceStrategy.always)
|
||||
self.assertEqual(len(project.containers()), 0)
|
||||
self.assertEqual(len(project.containers(stopped=True)), 1)
|
||||
assert len(project.containers(stopped=True)) == 1
|
||||
|
||||
db_container = project.containers(stopped=True)[0]
|
||||
self.assertNotEqual(db_container.id, old_id)
|
||||
assert not db_container.is_running
|
||||
assert db_container.id != old_id
|
||||
|
||||
def test_create_strategy_never(self):
|
||||
db = self.create_service('db')
|
||||
|
@ -356,11 +386,11 @@ class ProjectTest(DockerClientTestCase):
|
|||
old_id = project.containers(stopped=True)[0].id
|
||||
|
||||
project.create(['db'], strategy=ConvergenceStrategy.never)
|
||||
self.assertEqual(len(project.containers()), 0)
|
||||
self.assertEqual(len(project.containers(stopped=True)), 1)
|
||||
assert len(project.containers(stopped=True)) == 1
|
||||
|
||||
db_container = project.containers(stopped=True)[0]
|
||||
self.assertEqual(db_container.id, old_id)
|
||||
assert not db_container.is_running
|
||||
assert db_container.id == old_id
|
||||
|
||||
def test_project_up(self):
|
||||
web = self.create_service('web')
|
||||
|
@ -550,8 +580,8 @@ class ProjectTest(DockerClientTestCase):
|
|||
self.assertEqual(len(project.containers(stopped=True)), 2)
|
||||
self.assertEqual(len(project.get_service('web').containers()), 0)
|
||||
self.assertEqual(len(project.get_service('db').containers()), 1)
|
||||
self.assertEqual(len(project.get_service('data').containers()), 0)
|
||||
self.assertEqual(len(project.get_service('data').containers(stopped=True)), 1)
|
||||
assert not project.get_service('data').containers(stopped=True)[0].is_running
|
||||
self.assertEqual(len(project.get_service('console').containers()), 0)
|
||||
|
||||
def test_project_up_recreate_with_tmpfs_volume(self):
|
||||
|
@ -737,10 +767,10 @@ class ProjectTest(DockerClientTestCase):
|
|||
"com.docker.compose.network.test": "9-29-045"
|
||||
}
|
||||
|
||||
@v2_only()
|
||||
@v2_1_only()
|
||||
def test_up_with_network_static_addresses(self):
|
||||
config_data = build_config(
|
||||
version=V2_0,
|
||||
version=V2_1,
|
||||
services=[{
|
||||
'name': 'web',
|
||||
'image': 'busybox:latest',
|
||||
|
@ -766,7 +796,8 @@ class ProjectTest(DockerClientTestCase):
|
|||
{"subnet": "fe80::/64",
|
||||
"gateway": "fe80::1001:1"}
|
||||
]
|
||||
}
|
||||
},
|
||||
'enable_ipv6': True,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -777,13 +808,8 @@ class ProjectTest(DockerClientTestCase):
|
|||
)
|
||||
project.up(detached=True)
|
||||
|
||||
network = self.client.networks(names=['static_test'])[0]
|
||||
service_container = project.get_service('web').containers()[0]
|
||||
|
||||
assert network['Options'] == {
|
||||
"com.docker.network.enable_ipv6": "true"
|
||||
}
|
||||
|
||||
IPAMConfig = (service_container.inspect().get('NetworkSettings', {}).
|
||||
get('Networks', {}).get('composetest_static_test', {}).
|
||||
get('IPAMConfig', {}))
|
||||
|
@ -825,7 +851,7 @@ class ProjectTest(DockerClientTestCase):
|
|||
config_data=config_data,
|
||||
)
|
||||
project.up(detached=True)
|
||||
network = self.client.networks(names=['static_test'])[0]
|
||||
network = [n for n in self.client.networks() if 'static_test' in n['Name']][0]
|
||||
service_container = project.get_service('web').containers()[0]
|
||||
|
||||
assert network['EnableIPv6'] is True
|
||||
|
@ -1026,8 +1052,8 @@ class ProjectTest(DockerClientTestCase):
|
|||
project.up()
|
||||
self.assertEqual(len(project.containers()), 1)
|
||||
|
||||
volume_data = self.client.inspect_volume(full_vol_name)
|
||||
self.assertEqual(volume_data['Name'], full_vol_name)
|
||||
volume_data = self.get_volume_data(full_vol_name)
|
||||
assert volume_data['Name'].split('/')[-1] == full_vol_name
|
||||
self.assertEqual(volume_data['Driver'], 'local')
|
||||
|
||||
@v2_1_only()
|
||||
|
@ -1062,10 +1088,12 @@ class ProjectTest(DockerClientTestCase):
|
|||
|
||||
volumes = [
|
||||
v for v in self.client.volumes().get('Volumes', [])
|
||||
if v['Name'].startswith('composetest_')
|
||||
if v['Name'].split('/')[-1].startswith('composetest_')
|
||||
]
|
||||
|
||||
assert [v['Name'] for v in volumes] == ['composetest_{}'.format(volume_name)]
|
||||
assert set([v['Name'].split('/')[-1] for v in volumes]) == set(
|
||||
['composetest_{}'.format(volume_name)]
|
||||
)
|
||||
|
||||
assert 'label_key' in volumes[0]['Labels']
|
||||
assert volumes[0]['Labels']['label_key'] == 'label_val'
|
||||
|
@ -1205,8 +1233,8 @@ class ProjectTest(DockerClientTestCase):
|
|||
)
|
||||
project.volumes.initialize()
|
||||
|
||||
volume_data = self.client.inspect_volume(full_vol_name)
|
||||
assert volume_data['Name'] == full_vol_name
|
||||
volume_data = self.get_volume_data(full_vol_name)
|
||||
assert volume_data['Name'].split('/')[-1] == full_vol_name
|
||||
assert volume_data['Driver'] == 'local'
|
||||
|
||||
@v2_only()
|
||||
|
@ -1229,8 +1257,8 @@ class ProjectTest(DockerClientTestCase):
|
|||
)
|
||||
project.up()
|
||||
|
||||
volume_data = self.client.inspect_volume(full_vol_name)
|
||||
self.assertEqual(volume_data['Name'], full_vol_name)
|
||||
volume_data = self.get_volume_data(full_vol_name)
|
||||
assert volume_data['Name'].split('/')[-1] == full_vol_name
|
||||
self.assertEqual(volume_data['Driver'], 'local')
|
||||
|
||||
@v3_only()
|
||||
|
@ -1287,10 +1315,11 @@ class ProjectTest(DockerClientTestCase):
|
|||
name='composetest',
|
||||
config_data=config_data, client=self.client
|
||||
)
|
||||
with self.assertRaises(config.ConfigurationError):
|
||||
with self.assertRaises(APIError if is_cluster(self.client) else config.ConfigurationError):
|
||||
project.volumes.initialize()
|
||||
|
||||
@v2_only()
|
||||
@no_cluster('inspect volume by name defect on Swarm Classic')
|
||||
def test_initialize_volumes_updated_driver(self):
|
||||
vol_name = '{0:x}'.format(random.getrandbits(32))
|
||||
full_vol_name = 'composetest_{0}'.format(vol_name)
|
||||
|
@ -1310,8 +1339,8 @@ class ProjectTest(DockerClientTestCase):
|
|||
)
|
||||
project.volumes.initialize()
|
||||
|
||||
volume_data = self.client.inspect_volume(full_vol_name)
|
||||
self.assertEqual(volume_data['Name'], full_vol_name)
|
||||
volume_data = self.get_volume_data(full_vol_name)
|
||||
assert volume_data['Name'].split('/')[-1] == full_vol_name
|
||||
self.assertEqual(volume_data['Driver'], 'local')
|
||||
|
||||
config_data = config_data._replace(
|
||||
|
@ -1348,8 +1377,8 @@ class ProjectTest(DockerClientTestCase):
|
|||
)
|
||||
project.volumes.initialize()
|
||||
|
||||
volume_data = self.client.inspect_volume(full_vol_name)
|
||||
self.assertEqual(volume_data['Name'], full_vol_name)
|
||||
volume_data = self.get_volume_data(full_vol_name)
|
||||
assert volume_data['Name'].split('/')[-1] == full_vol_name
|
||||
self.assertEqual(volume_data['Driver'], 'local')
|
||||
|
||||
config_data = config_data._replace(
|
||||
|
@ -1361,11 +1390,12 @@ class ProjectTest(DockerClientTestCase):
|
|||
client=self.client
|
||||
)
|
||||
project.volumes.initialize()
|
||||
volume_data = self.client.inspect_volume(full_vol_name)
|
||||
self.assertEqual(volume_data['Name'], full_vol_name)
|
||||
volume_data = self.get_volume_data(full_vol_name)
|
||||
assert volume_data['Name'].split('/')[-1] == full_vol_name
|
||||
self.assertEqual(volume_data['Driver'], 'local')
|
||||
|
||||
@v2_only()
|
||||
@no_cluster('inspect volume by name defect on Swarm Classic')
|
||||
def test_initialize_volumes_external_volumes(self):
|
||||
# Use composetest_ prefix so it gets garbage-collected in tearDown()
|
||||
vol_name = 'composetest_{0:x}'.format(random.getrandbits(32))
|
||||
|
|
|
@ -13,9 +13,13 @@ from six import StringIO
|
|||
from six import text_type
|
||||
|
||||
from .. import mock
|
||||
from ..helpers import is_cluster
|
||||
from ..helpers import no_cluster
|
||||
from .testcases import DockerClientTestCase
|
||||
from .testcases import get_links
|
||||
from .testcases import pull_busybox
|
||||
from .testcases import SWARM_SKIP_CONTAINERS_ALL
|
||||
from .testcases import SWARM_SKIP_CPU_SHARES
|
||||
from compose import __version__
|
||||
from compose.config.types import VolumeFromSpec
|
||||
from compose.config.types import VolumeSpec
|
||||
|
@ -100,6 +104,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
service.start_container(container)
|
||||
self.assertEqual('foodriver', container.get('HostConfig.VolumeDriver'))
|
||||
|
||||
@pytest.mark.skipif(SWARM_SKIP_CPU_SHARES, reason='Swarm --cpu-shares bug')
|
||||
def test_create_container_with_cpu_shares(self):
|
||||
service = self.create_service('db', cpu_shares=73)
|
||||
container = service.create_container()
|
||||
|
@ -151,6 +156,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
service.start_container(container)
|
||||
assert container.get('HostConfig.Init') is True
|
||||
|
||||
@pytest.mark.xfail(True, reason='Option has been removed in Engine 17.06.0')
|
||||
def test_create_container_with_init_path(self):
|
||||
self.require_api_version('1.25')
|
||||
docker_init_path = find_executable('docker-init')
|
||||
|
@ -249,6 +255,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
'busybox', 'true',
|
||||
volumes={container_path: {}},
|
||||
labels={'com.docker.compose.test_image': 'true'},
|
||||
host_config={}
|
||||
)
|
||||
image = self.client.commit(tmp_container)['Id']
|
||||
|
||||
|
@ -278,6 +285,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
image='busybox:latest',
|
||||
command=["top"],
|
||||
labels={LABEL_PROJECT: 'composetest'},
|
||||
host_config={},
|
||||
)
|
||||
host_service = self.create_service(
|
||||
'host',
|
||||
|
@ -321,9 +329,15 @@ class ServiceTest(DockerClientTestCase):
|
|||
self.assertIn('FOO=2', new_container.get('Config.Env'))
|
||||
self.assertEqual(new_container.name, 'composetest_db_1')
|
||||
self.assertEqual(new_container.get_mount('/etc')['Source'], volume_path)
|
||||
self.assertIn(
|
||||
'affinity:container==%s' % old_container.id,
|
||||
new_container.get('Config.Env'))
|
||||
if not is_cluster(self.client):
|
||||
assert (
|
||||
'affinity:container==%s' % old_container.id in
|
||||
new_container.get('Config.Env')
|
||||
)
|
||||
else:
|
||||
# In Swarm, the env marker is consumed and the container should be deployed
|
||||
# on the same node.
|
||||
assert old_container.get('Node.Name') == new_container.get('Node.Name')
|
||||
|
||||
self.assertEqual(len(self.client.containers(all=True)), num_containers_before)
|
||||
self.assertNotEqual(old_container.id, new_container.id)
|
||||
|
@ -350,8 +364,13 @@ class ServiceTest(DockerClientTestCase):
|
|||
ConvergencePlan('recreate', [orig_container]))
|
||||
|
||||
assert new_container.get_mount('/etc')['Source'] == volume_path
|
||||
assert ('affinity:container==%s' % orig_container.id in
|
||||
new_container.get('Config.Env'))
|
||||
if not is_cluster(self.client):
|
||||
assert ('affinity:container==%s' % orig_container.id in
|
||||
new_container.get('Config.Env'))
|
||||
else:
|
||||
# In Swarm, the env marker is consumed and the container should be deployed
|
||||
# on the same node.
|
||||
assert orig_container.get('Node.Name') == new_container.get('Node.Name')
|
||||
|
||||
orig_container = new_container
|
||||
|
||||
|
@ -464,18 +483,21 @@ class ServiceTest(DockerClientTestCase):
|
|||
)
|
||||
|
||||
containers = service.execute_convergence_plan(ConvergencePlan('create', []), start=False)
|
||||
self.assertEqual(len(service.containers()), 0)
|
||||
self.assertEqual(len(service.containers(stopped=True)), 1)
|
||||
service_containers = service.containers(stopped=True)
|
||||
assert len(service_containers) == 1
|
||||
assert not service_containers[0].is_running
|
||||
|
||||
containers = service.execute_convergence_plan(
|
||||
ConvergencePlan('recreate', containers),
|
||||
start=False)
|
||||
self.assertEqual(len(service.containers()), 0)
|
||||
self.assertEqual(len(service.containers(stopped=True)), 1)
|
||||
service_containers = service.containers(stopped=True)
|
||||
assert len(service_containers) == 1
|
||||
assert not service_containers[0].is_running
|
||||
|
||||
service.execute_convergence_plan(ConvergencePlan('start', containers), start=False)
|
||||
self.assertEqual(len(service.containers()), 0)
|
||||
self.assertEqual(len(service.containers(stopped=True)), 1)
|
||||
service_containers = service.containers(stopped=True)
|
||||
assert len(service_containers) == 1
|
||||
assert not service_containers[0].is_running
|
||||
|
||||
def test_start_container_passes_through_options(self):
|
||||
db = self.create_service('db')
|
||||
|
@ -487,6 +509,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
create_and_start_container(db)
|
||||
self.assertEqual(db.containers()[0].environment['FOO'], 'BAR')
|
||||
|
||||
@no_cluster('No legacy links support in Swarm')
|
||||
def test_start_container_creates_links(self):
|
||||
db = self.create_service('db')
|
||||
web = self.create_service('web', links=[(db, None)])
|
||||
|
@ -503,6 +526,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
'db'])
|
||||
)
|
||||
|
||||
@no_cluster('No legacy links support in Swarm')
|
||||
def test_start_container_creates_links_with_names(self):
|
||||
db = self.create_service('db')
|
||||
web = self.create_service('web', links=[(db, 'custom_link_name')])
|
||||
|
@ -519,6 +543,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
'custom_link_name'])
|
||||
)
|
||||
|
||||
@no_cluster('No legacy links support in Swarm')
|
||||
def test_start_container_with_external_links(self):
|
||||
db = self.create_service('db')
|
||||
web = self.create_service('web', external_links=['composetest_db_1',
|
||||
|
@ -537,6 +562,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
'db_3']),
|
||||
)
|
||||
|
||||
@no_cluster('No legacy links support in Swarm')
|
||||
def test_start_normal_container_does_not_create_links_to_its_own_service(self):
|
||||
db = self.create_service('db')
|
||||
|
||||
|
@ -546,6 +572,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
c = create_and_start_container(db)
|
||||
self.assertEqual(set(get_links(c)), set([]))
|
||||
|
||||
@no_cluster('No legacy links support in Swarm')
|
||||
def test_start_one_off_container_creates_links_to_its_own_service(self):
|
||||
db = self.create_service('db')
|
||||
|
||||
|
@ -572,7 +599,7 @@ class ServiceTest(DockerClientTestCase):
|
|||
container = create_and_start_container(service)
|
||||
container.wait()
|
||||
self.assertIn(b'success', container.logs())
|
||||
self.assertEqual(len(self.client.images(name='composetest_test')), 1)
|
||||
assert len(self.client.images(name='composetest_test')) >= 1
|
||||
|
||||
def test_start_container_uses_tagged_image_if_it_exists(self):
|
||||
self.check_build('tests/fixtures/simple-dockerfile', tag='composetest_test')
|
||||
|
@ -719,20 +746,27 @@ class ServiceTest(DockerClientTestCase):
|
|||
'0.0.0.0:9001:9000/udp',
|
||||
])
|
||||
container = create_and_start_container(service).inspect()
|
||||
self.assertEqual(container['NetworkSettings']['Ports'], {
|
||||
'8000/tcp': [
|
||||
{
|
||||
'HostIp': '127.0.0.1',
|
||||
'HostPort': '8001',
|
||||
},
|
||||
],
|
||||
'9000/udp': [
|
||||
{
|
||||
'HostIp': '0.0.0.0',
|
||||
'HostPort': '9001',
|
||||
},
|
||||
],
|
||||
})
|
||||
assert container['NetworkSettings']['Ports']['8000/tcp'] == [{
|
||||
'HostIp': '127.0.0.1',
|
||||
'HostPort': '8001',
|
||||
}]
|
||||
assert container['NetworkSettings']['Ports']['9000/udp'][0]['HostPort'] == '9001'
|
||||
if not is_cluster(self.client):
|
||||
assert container['NetworkSettings']['Ports']['9000/udp'][0]['HostIp'] == '0.0.0.0'
|
||||
# self.assertEqual(container['NetworkSettings']['Ports'], {
|
||||
# '8000/tcp': [
|
||||
# {
|
||||
# 'HostIp': '127.0.0.1',
|
||||
# 'HostPort': '8001',
|
||||
# },
|
||||
# ],
|
||||
# '9000/udp': [
|
||||
# {
|
||||
# 'HostIp': '0.0.0.0',
|
||||
# 'HostPort': '9001',
|
||||
# },
|
||||
# ],
|
||||
# })
|
||||
|
||||
def test_create_with_image_id(self):
|
||||
# Get image id for the current busybox:latest
|
||||
|
@ -760,6 +794,10 @@ class ServiceTest(DockerClientTestCase):
|
|||
service.scale(0)
|
||||
self.assertEqual(len(service.containers()), 0)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
SWARM_SKIP_CONTAINERS_ALL,
|
||||
reason='Swarm /containers/json bug'
|
||||
)
|
||||
def test_scale_with_stopped_containers(self):
|
||||
"""
|
||||
Given there are some stopped containers and scale is called with a
|
||||
|
|
|
@ -251,7 +251,7 @@ class ServiceStateTest(DockerClientTestCase):
|
|||
container = web.create_container()
|
||||
|
||||
# update the image
|
||||
c = self.client.create_container(image, ['touch', '/hello.txt'])
|
||||
c = self.client.create_container(image, ['touch', '/hello.txt'], host_config={})
|
||||
self.client.commit(c, repository=repo, tag=tag)
|
||||
self.client.remove_container(c)
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ from docker.utils import version_lt
|
|||
from pytest import skip
|
||||
|
||||
from .. import unittest
|
||||
from ..helpers import is_cluster
|
||||
from compose.cli.docker_client import docker_client
|
||||
from compose.config.config import resolve_environment
|
||||
from compose.config.environment import Environment
|
||||
|
@ -21,6 +22,10 @@ from compose.const import LABEL_PROJECT
|
|||
from compose.progress_stream import stream_output
|
||||
from compose.service import Service
|
||||
|
||||
SWARM_SKIP_CONTAINERS_ALL = os.environ.get('SWARM_SKIP_CONTAINERS_ALL', '0') != '0'
|
||||
SWARM_SKIP_CPU_SHARES = os.environ.get('SWARM_SKIP_CPU_SHARES', '0') != '0'
|
||||
SWARM_SKIP_RM_VOLUMES = os.environ.get('SWARM_SKIP_RM_VOLUMES', '0') != '0'
|
||||
|
||||
|
||||
def pull_busybox(client):
|
||||
client.pull('busybox:latest', stream=False)
|
||||
|
@ -97,7 +102,7 @@ class DockerClientTestCase(unittest.TestCase):
|
|||
|
||||
for i in self.client.images(
|
||||
filters={'label': 'com.docker.compose.test_image'}):
|
||||
self.client.remove_image(i)
|
||||
self.client.remove_image(i, force=True)
|
||||
|
||||
volumes = self.client.volumes().get('Volumes') or []
|
||||
for v in volumes:
|
||||
|
@ -133,3 +138,11 @@ class DockerClientTestCase(unittest.TestCase):
|
|||
api_version = self.client.version()['ApiVersion']
|
||||
if version_lt(api_version, minimum):
|
||||
skip("API version is too low ({} < {})".format(api_version, minimum))
|
||||
|
||||
def get_volume_data(self, volume_name):
|
||||
if not is_cluster(self.client):
|
||||
return self.client.inspect_volume(volume_name)
|
||||
|
||||
volumes = self.client.volumes(filters={'name': volume_name})['Volumes']
|
||||
assert len(volumes) > 0
|
||||
return self.client.inspect_volume(volumes[0]['Name'])
|
||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
|||
|
||||
from docker.errors import DockerException
|
||||
|
||||
from ..helpers import no_cluster
|
||||
from .testcases import DockerClientTestCase
|
||||
from compose.const import LABEL_PROJECT
|
||||
from compose.const import LABEL_VOLUME
|
||||
|
@ -35,26 +36,28 @@ class VolumeTest(DockerClientTestCase):
|
|||
def test_create_volume(self):
|
||||
vol = self.create_volume('volume01')
|
||||
vol.create()
|
||||
info = self.client.inspect_volume(vol.full_name)
|
||||
assert info['Name'] == vol.full_name
|
||||
info = self.get_volume_data(vol.full_name)
|
||||
assert info['Name'].split('/')[-1] == vol.full_name
|
||||
|
||||
def test_recreate_existing_volume(self):
|
||||
vol = self.create_volume('volume01')
|
||||
|
||||
vol.create()
|
||||
info = self.client.inspect_volume(vol.full_name)
|
||||
assert info['Name'] == vol.full_name
|
||||
info = self.get_volume_data(vol.full_name)
|
||||
assert info['Name'].split('/')[-1] == vol.full_name
|
||||
|
||||
vol.create()
|
||||
info = self.client.inspect_volume(vol.full_name)
|
||||
assert info['Name'] == vol.full_name
|
||||
info = self.get_volume_data(vol.full_name)
|
||||
assert info['Name'].split('/')[-1] == vol.full_name
|
||||
|
||||
@no_cluster('inspect volume by name defect on Swarm Classic')
|
||||
def test_inspect_volume(self):
|
||||
vol = self.create_volume('volume01')
|
||||
vol.create()
|
||||
info = vol.inspect()
|
||||
assert info['Name'] == vol.full_name
|
||||
|
||||
@no_cluster('remove volume by name defect on Swarm Classic')
|
||||
def test_remove_volume(self):
|
||||
vol = Volume(self.client, 'composetest', 'volume01')
|
||||
vol.create()
|
||||
|
@ -62,6 +65,7 @@ class VolumeTest(DockerClientTestCase):
|
|||
volumes = self.client.volumes()['Volumes']
|
||||
assert len([v for v in volumes if v['Name'] == vol.full_name]) == 0
|
||||
|
||||
@no_cluster('inspect volume by name defect on Swarm Classic')
|
||||
def test_external_volume(self):
|
||||
vol = self.create_volume('composetest_volume_ext', external=True)
|
||||
assert vol.external is True
|
||||
|
@ -70,6 +74,7 @@ class VolumeTest(DockerClientTestCase):
|
|||
info = vol.inspect()
|
||||
assert info['Name'] == vol.name
|
||||
|
||||
@no_cluster('inspect volume by name defect on Swarm Classic')
|
||||
def test_external_aliased_volume(self):
|
||||
alias_name = 'composetest_alias01'
|
||||
vol = self.create_volume('volume01', external=alias_name)
|
||||
|
@ -79,24 +84,28 @@ class VolumeTest(DockerClientTestCase):
|
|||
info = vol.inspect()
|
||||
assert info['Name'] == alias_name
|
||||
|
||||
@no_cluster('inspect volume by name defect on Swarm Classic')
|
||||
def test_exists(self):
|
||||
vol = self.create_volume('volume01')
|
||||
assert vol.exists() is False
|
||||
vol.create()
|
||||
assert vol.exists() is True
|
||||
|
||||
@no_cluster('inspect volume by name defect on Swarm Classic')
|
||||
def test_exists_external(self):
|
||||
vol = self.create_volume('volume01', external=True)
|
||||
assert vol.exists() is False
|
||||
vol.create()
|
||||
assert vol.exists() is True
|
||||
|
||||
@no_cluster('inspect volume by name defect on Swarm Classic')
|
||||
def test_exists_external_aliased(self):
|
||||
vol = self.create_volume('volume01', external='composetest_alias01')
|
||||
assert vol.exists() is False
|
||||
vol.create()
|
||||
assert vol.exists() is True
|
||||
|
||||
@no_cluster('inspect volume by name defect on Swarm Classic')
|
||||
def test_volume_default_labels(self):
|
||||
vol = self.create_volume('volume01')
|
||||
vol.create()
|
||||
|
|
Loading…
Reference in New Issue