mirror of https://github.com/docker/compose.git
Some more test adjustments for Swarm support
Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
8f0ef26a73
commit
6a4adb64f9
|
@ -7,3 +7,5 @@ coverage-html
|
||||||
docs/_site
|
docs/_site
|
||||||
venv
|
venv
|
||||||
.tox
|
.tox
|
||||||
|
**/__pycache__
|
||||||
|
*.pyc
|
||||||
|
|
|
@ -20,8 +20,6 @@ from docker import errors
|
||||||
|
|
||||||
from .. import mock
|
from .. import mock
|
||||||
from ..helpers import create_host_file
|
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.cli.command import get_project
|
||||||
from compose.config.errors import DuplicateOverrideFileFound
|
from compose.config.errors import DuplicateOverrideFileFound
|
||||||
from compose.container import Container
|
from compose.container import Container
|
||||||
|
@ -29,6 +27,8 @@ from compose.project import OneOffFilter
|
||||||
from compose.utils import nanoseconds_from_time_seconds
|
from compose.utils import nanoseconds_from_time_seconds
|
||||||
from tests.integration.testcases import DockerClientTestCase
|
from tests.integration.testcases import DockerClientTestCase
|
||||||
from tests.integration.testcases import get_links
|
from tests.integration.testcases import get_links
|
||||||
|
from tests.integration.testcases import is_cluster
|
||||||
|
from tests.integration.testcases import no_cluster
|
||||||
from tests.integration.testcases import pull_busybox
|
from tests.integration.testcases import pull_busybox
|
||||||
from tests.integration.testcases import SWARM_SKIP_RM_VOLUMES
|
from tests.integration.testcases import SWARM_SKIP_RM_VOLUMES
|
||||||
from tests.integration.testcases import v2_1_only
|
from tests.integration.testcases import v2_1_only
|
||||||
|
@ -116,7 +116,7 @@ class CLITestCase(DockerClientTestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
if self.base_dir:
|
if self.base_dir:
|
||||||
self.project.kill()
|
self.project.kill()
|
||||||
self.project.remove_stopped()
|
self.project.down(None, True)
|
||||||
|
|
||||||
for container in self.project.containers(stopped=True, one_off=OneOffFilter.only):
|
for container in self.project.containers(stopped=True, one_off=OneOffFilter.only):
|
||||||
container.remove(force=True)
|
container.remove(force=True)
|
||||||
|
@ -1214,6 +1214,7 @@ class CLITestCase(DockerClientTestCase):
|
||||||
self.assertEqual(proc.returncode, 1)
|
self.assertEqual(proc.returncode, 1)
|
||||||
|
|
||||||
@v2_only()
|
@v2_only()
|
||||||
|
@no_cluster('Container PID mode does not work across clusters')
|
||||||
def test_up_with_pid_mode(self):
|
def test_up_with_pid_mode(self):
|
||||||
c = self.client.create_container(
|
c = self.client.create_container(
|
||||||
'busybox', 'top', name='composetest_pid_mode_container',
|
'busybox', 'top', name='composetest_pid_mode_container',
|
||||||
|
@ -1244,8 +1245,8 @@ class CLITestCase(DockerClientTestCase):
|
||||||
self.assertEqual(len(self.project.containers()), 1)
|
self.assertEqual(len(self.project.containers()), 1)
|
||||||
|
|
||||||
stdout, stderr = self.dispatch(['exec', '-T', 'console', 'ls', '-1d', '/'])
|
stdout, stderr = self.dispatch(['exec', '-T', 'console', 'ls', '-1d', '/'])
|
||||||
self.assertEqual(stdout, "/\n")
|
|
||||||
self.assertEqual(stderr, "")
|
self.assertEqual(stderr, "")
|
||||||
|
self.assertEqual(stdout, "/\n")
|
||||||
|
|
||||||
def test_exec_custom_user(self):
|
def test_exec_custom_user(self):
|
||||||
self.base_dir = 'tests/fixtures/links-composefile'
|
self.base_dir = 'tests/fixtures/links-composefile'
|
||||||
|
@ -1826,7 +1827,13 @@ class CLITestCase(DockerClientTestCase):
|
||||||
|
|
||||||
result = self.dispatch(['logs', '-f'])
|
result = self.dispatch(['logs', '-f'])
|
||||||
|
|
||||||
|
if not is_cluster(self.client):
|
||||||
assert result.stdout.count('\n') == 5
|
assert result.stdout.count('\n') == 5
|
||||||
|
else:
|
||||||
|
# Sometimes logs are picked up from old containers that haven't yet
|
||||||
|
# been removed (removal in Swarm is async)
|
||||||
|
assert result.stdout.count('\n') >= 5
|
||||||
|
|
||||||
assert 'simple' in result.stdout
|
assert 'simple' in result.stdout
|
||||||
assert 'another' in result.stdout
|
assert 'another' in result.stdout
|
||||||
assert 'exited with code 0' in result.stdout
|
assert 'exited with code 0' in result.stdout
|
||||||
|
@ -1882,7 +1889,10 @@ class CLITestCase(DockerClientTestCase):
|
||||||
self.dispatch(['up'])
|
self.dispatch(['up'])
|
||||||
|
|
||||||
result = self.dispatch(['logs', '--tail', '2'])
|
result = self.dispatch(['logs', '--tail', '2'])
|
||||||
assert result.stdout.count('\n') == 3
|
assert 'c\n' in result.stdout
|
||||||
|
assert 'd\n' in result.stdout
|
||||||
|
assert 'a\n' not in result.stdout
|
||||||
|
assert 'b\n' not in result.stdout
|
||||||
|
|
||||||
def test_kill(self):
|
def test_kill(self):
|
||||||
self.dispatch(['up', '-d'], None)
|
self.dispatch(['up', '-d'], None)
|
||||||
|
@ -2045,8 +2055,8 @@ class CLITestCase(DockerClientTestCase):
|
||||||
return result.stdout.rstrip()
|
return result.stdout.rstrip()
|
||||||
|
|
||||||
assert get_port(3000) == container.get_local_port(3000)
|
assert get_port(3000) == container.get_local_port(3000)
|
||||||
assert ':49152' in get_port(3001)
|
assert ':53222' in get_port(3001)
|
||||||
assert ':49153' in get_port(3002)
|
assert ':53223' in get_port(3002)
|
||||||
|
|
||||||
def test_port_with_scale(self):
|
def test_port_with_scale(self):
|
||||||
self.base_dir = 'tests/fixtures/ports-composefile-scale'
|
self.base_dir = 'tests/fixtures/ports-composefile-scale'
|
||||||
|
|
|
@ -6,10 +6,10 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- target: 3000
|
- target: 3000
|
||||||
- target: 3001
|
- target: 3001
|
||||||
published: 49152
|
published: 53222
|
||||||
- target: 3002
|
- target: 3002
|
||||||
published: 49153
|
published: 53223
|
||||||
protocol: tcp
|
protocol: tcp
|
||||||
- target: 3003
|
- target: 3003
|
||||||
published: 49154
|
published: 53224
|
||||||
protocol: udp
|
protocol: udp
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import functools
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from docker.errors import APIError
|
|
||||||
from pytest import skip
|
|
||||||
|
|
||||||
from compose.config.config import ConfigDetails
|
from compose.config.config import ConfigDetails
|
||||||
from compose.config.config import ConfigFile
|
from compose.config.config import ConfigFile
|
||||||
from compose.config.config import load
|
from compose.config.config import load
|
||||||
|
@ -48,34 +44,3 @@ def create_host_file(client, filename):
|
||||||
"Container exited with code {}:\n{}".format(exitcode, output))
|
"Container exited with code {}:\n{}".format(exitcode, output))
|
||||||
finally:
|
finally:
|
||||||
client.remove_container(container, force=True)
|
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
|
|
||||||
|
|
|
@ -12,8 +12,6 @@ from docker.errors import NotFound
|
||||||
from .. import mock
|
from .. import mock
|
||||||
from ..helpers import build_config as load_config
|
from ..helpers import build_config as load_config
|
||||||
from ..helpers import create_host_file
|
from ..helpers import create_host_file
|
||||||
from ..helpers import is_cluster
|
|
||||||
from ..helpers import no_cluster
|
|
||||||
from .testcases import DockerClientTestCase
|
from .testcases import DockerClientTestCase
|
||||||
from .testcases import SWARM_SKIP_CONTAINERS_ALL
|
from .testcases import SWARM_SKIP_CONTAINERS_ALL
|
||||||
from compose.config import config
|
from compose.config import config
|
||||||
|
@ -33,6 +31,8 @@ from compose.errors import NoHealthCheckConfigured
|
||||||
from compose.project import Project
|
from compose.project import Project
|
||||||
from compose.project import ProjectError
|
from compose.project import ProjectError
|
||||||
from compose.service import ConvergenceStrategy
|
from compose.service import ConvergenceStrategy
|
||||||
|
from tests.integration.testcases import is_cluster
|
||||||
|
from tests.integration.testcases import no_cluster
|
||||||
from tests.integration.testcases import v2_1_only
|
from tests.integration.testcases import v2_1_only
|
||||||
from tests.integration.testcases import v2_2_only
|
from tests.integration.testcases import v2_2_only
|
||||||
from tests.integration.testcases import v2_only
|
from tests.integration.testcases import v2_only
|
||||||
|
|
|
@ -13,8 +13,6 @@ from six import StringIO
|
||||||
from six import text_type
|
from six import text_type
|
||||||
|
|
||||||
from .. import mock
|
from .. import mock
|
||||||
from ..helpers import is_cluster
|
|
||||||
from ..helpers import no_cluster
|
|
||||||
from .testcases import DockerClientTestCase
|
from .testcases import DockerClientTestCase
|
||||||
from .testcases import get_links
|
from .testcases import get_links
|
||||||
from .testcases import pull_busybox
|
from .testcases import pull_busybox
|
||||||
|
@ -38,6 +36,8 @@ from compose.service import ConvergenceStrategy
|
||||||
from compose.service import NetworkMode
|
from compose.service import NetworkMode
|
||||||
from compose.service import PidMode
|
from compose.service import PidMode
|
||||||
from compose.service import Service
|
from compose.service import Service
|
||||||
|
from tests.integration.testcases import is_cluster
|
||||||
|
from tests.integration.testcases import no_cluster
|
||||||
from tests.integration.testcases import v2_1_only
|
from tests.integration.testcases import v2_1_only
|
||||||
from tests.integration.testcases import v2_2_only
|
from tests.integration.testcases import v2_2_only
|
||||||
from tests.integration.testcases import v2_only
|
from tests.integration.testcases import v2_only
|
||||||
|
@ -635,7 +635,10 @@ class ServiceTest(DockerClientTestCase):
|
||||||
with open(os.path.join(base_dir, 'Dockerfile'), 'w') as f:
|
with open(os.path.join(base_dir, 'Dockerfile'), 'w') as f:
|
||||||
f.write("FROM busybox\n")
|
f.write("FROM busybox\n")
|
||||||
|
|
||||||
self.create_service('web', build={'context': base_dir}).build()
|
service = self.create_service('web', build={'context': base_dir})
|
||||||
|
service.build()
|
||||||
|
self.addCleanup(self.client.remove_image, service.image_name)
|
||||||
|
|
||||||
assert self.client.inspect_image('composetest_web')
|
assert self.client.inspect_image('composetest_web')
|
||||||
|
|
||||||
def test_build_non_ascii_filename(self):
|
def test_build_non_ascii_filename(self):
|
||||||
|
@ -648,7 +651,9 @@ class ServiceTest(DockerClientTestCase):
|
||||||
with open(os.path.join(base_dir.encode('utf8'), b'foo\xE2bar'), 'w') as f:
|
with open(os.path.join(base_dir.encode('utf8'), b'foo\xE2bar'), 'w') as f:
|
||||||
f.write("hello world\n")
|
f.write("hello world\n")
|
||||||
|
|
||||||
self.create_service('web', build={'context': text_type(base_dir)}).build()
|
service = self.create_service('web', build={'context': text_type(base_dir)})
|
||||||
|
service.build()
|
||||||
|
self.addCleanup(self.client.remove_image, service.image_name)
|
||||||
assert self.client.inspect_image('composetest_web')
|
assert self.client.inspect_image('composetest_web')
|
||||||
|
|
||||||
def test_build_with_image_name(self):
|
def test_build_with_image_name(self):
|
||||||
|
@ -683,6 +688,7 @@ class ServiceTest(DockerClientTestCase):
|
||||||
build={'context': text_type(base_dir),
|
build={'context': text_type(base_dir),
|
||||||
'args': {"build_version": "1"}})
|
'args': {"build_version": "1"}})
|
||||||
service.build()
|
service.build()
|
||||||
|
self.addCleanup(self.client.remove_image, service.image_name)
|
||||||
assert service.image()
|
assert service.image()
|
||||||
assert "build_version=1" in service.image()['ContainerConfig']['Cmd']
|
assert "build_version=1" in service.image()['ContainerConfig']['Cmd']
|
||||||
|
|
||||||
|
@ -699,6 +705,8 @@ class ServiceTest(DockerClientTestCase):
|
||||||
build={'context': text_type(base_dir),
|
build={'context': text_type(base_dir),
|
||||||
'args': {"build_version": "1"}})
|
'args': {"build_version": "1"}})
|
||||||
service.build(build_args_override={'build_version': '2'})
|
service.build(build_args_override={'build_version': '2'})
|
||||||
|
self.addCleanup(self.client.remove_image, service.image_name)
|
||||||
|
|
||||||
assert service.image()
|
assert service.image()
|
||||||
assert "build_version=2" in service.image()['ContainerConfig']['Cmd']
|
assert "build_version=2" in service.image()['ContainerConfig']['Cmd']
|
||||||
|
|
||||||
|
@ -714,9 +722,12 @@ class ServiceTest(DockerClientTestCase):
|
||||||
'labels': {'com.docker.compose.test': 'true'}
|
'labels': {'com.docker.compose.test': 'true'}
|
||||||
})
|
})
|
||||||
service.build()
|
service.build()
|
||||||
|
self.addCleanup(self.client.remove_image, service.image_name)
|
||||||
|
|
||||||
assert service.image()
|
assert service.image()
|
||||||
assert service.image()['Config']['Labels']['com.docker.compose.test'] == 'true'
|
assert service.image()['Config']['Labels']['com.docker.compose.test'] == 'true'
|
||||||
|
|
||||||
|
@no_cluster('Container networks not on Swarm')
|
||||||
def test_build_with_network(self):
|
def test_build_with_network(self):
|
||||||
base_dir = tempfile.mkdtemp()
|
base_dir = tempfile.mkdtemp()
|
||||||
self.addCleanup(shutil.rmtree, base_dir)
|
self.addCleanup(shutil.rmtree, base_dir)
|
||||||
|
@ -739,6 +750,8 @@ class ServiceTest(DockerClientTestCase):
|
||||||
})
|
})
|
||||||
|
|
||||||
service.build()
|
service.build()
|
||||||
|
self.addCleanup(self.client.remove_image, service.image_name)
|
||||||
|
|
||||||
assert service.image()
|
assert service.image()
|
||||||
|
|
||||||
def test_start_container_stays_unprivileged(self):
|
def test_start_container_stays_unprivileged(self):
|
||||||
|
@ -1130,6 +1143,8 @@ class ServiceTest(DockerClientTestCase):
|
||||||
build={'context': base_dir,
|
build={'context': base_dir,
|
||||||
'cache_from': ['build1']})
|
'cache_from': ['build1']})
|
||||||
service.build()
|
service.build()
|
||||||
|
self.addCleanup(self.client.remove_image, service.image_name)
|
||||||
|
|
||||||
assert service.image()
|
assert service.image()
|
||||||
|
|
||||||
@mock.patch.dict(os.environ)
|
@mock.patch.dict(os.environ)
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import functools
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from docker.errors import APIError
|
||||||
from docker.utils import version_lt
|
from docker.utils import version_lt
|
||||||
|
|
||||||
from .. import unittest
|
from .. import unittest
|
||||||
from ..helpers import is_cluster
|
|
||||||
from compose.cli.docker_client import docker_client
|
from compose.cli.docker_client import docker_client
|
||||||
from compose.config.config import resolve_environment
|
from compose.config.config import resolve_environment
|
||||||
from compose.config.environment import Environment
|
from compose.config.environment import Environment
|
||||||
|
@ -25,6 +26,7 @@ from compose.service import Service
|
||||||
SWARM_SKIP_CONTAINERS_ALL = os.environ.get('SWARM_SKIP_CONTAINERS_ALL', '0') != '0'
|
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_CPU_SHARES = os.environ.get('SWARM_SKIP_CPU_SHARES', '0') != '0'
|
||||||
SWARM_SKIP_RM_VOLUMES = os.environ.get('SWARM_SKIP_RM_VOLUMES', '0') != '0'
|
SWARM_SKIP_RM_VOLUMES = os.environ.get('SWARM_SKIP_RM_VOLUMES', '0') != '0'
|
||||||
|
SWARM_ASSUME_MULTINODE = os.environ.get('SWARM_ASSUME_MULTINODE', '0') != '0'
|
||||||
|
|
||||||
|
|
||||||
def pull_busybox(client):
|
def pull_busybox(client):
|
||||||
|
@ -141,3 +143,35 @@ class DockerClientTestCase(unittest.TestCase):
|
||||||
volumes = self.client.volumes(filters={'name': volume_name})['Volumes']
|
volumes = self.client.volumes(filters={'name': volume_name})['Volumes']
|
||||||
assert len(volumes) > 0
|
assert len(volumes) > 0
|
||||||
return self.client.inspect_volume(volumes[0]['Name'])
|
return self.client.inspect_volume(volumes[0]['Name'])
|
||||||
|
|
||||||
|
|
||||||
|
def is_cluster(client):
|
||||||
|
if SWARM_ASSUME_MULTINODE:
|
||||||
|
return True
|
||||||
|
|
||||||
|
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 not hasattr(is_cluster, 'nodes') or is_cluster.nodes is None:
|
||||||
|
# Only make the API call if the value hasn't been cached yet
|
||||||
|
is_cluster.nodes = get_nodes_number()
|
||||||
|
|
||||||
|
return is_cluster.nodes > 1
|
||||||
|
|
||||||
|
|
||||||
|
def no_cluster(reason):
|
||||||
|
def decorator(f):
|
||||||
|
@functools.wraps(f)
|
||||||
|
def wrapper(self, *args, **kwargs):
|
||||||
|
if is_cluster(self.client):
|
||||||
|
pytest.skip("Test will not be run in cluster mode: %s" % reason)
|
||||||
|
return
|
||||||
|
return f(self, *args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
|
@ -3,8 +3,8 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from docker.errors import DockerException
|
from docker.errors import DockerException
|
||||||
|
|
||||||
from ..helpers import no_cluster
|
|
||||||
from .testcases import DockerClientTestCase
|
from .testcases import DockerClientTestCase
|
||||||
|
from .testcases import no_cluster
|
||||||
from compose.const import LABEL_PROJECT
|
from compose.const import LABEL_PROJECT
|
||||||
from compose.const import LABEL_VOLUME
|
from compose.const import LABEL_VOLUME
|
||||||
from compose.volume import Volume
|
from compose.volume import Volume
|
||||||
|
|
Loading…
Reference in New Issue