summaryrefslogtreecommitdiff
path: root/tests/integration
diff options
context:
space:
mode:
authorFelipe Sateler <fsateler@debian.org>2019-11-22 20:51:27 -0300
committerFelipe Sateler <fsateler@debian.org>2019-11-22 20:51:27 -0300
commit3f9a8392bb8dd13baef20d58914f822202947664 (patch)
tree2b710defcc6f1351e83f4ddba795032a6444a6c8 /tests/integration
parent0e08ec700f3e27bee8da6605cdd93491a14454dd (diff)
parent001f034ab762eab7724e4c2bc955b7f3f3dc8504 (diff)
Merge tag 'upstream/4.1.0'
Upstream version 4.1.0
Diffstat (limited to 'tests/integration')
-rw-r--r--tests/integration/api_build_test.py58
-rw-r--r--tests/integration/api_client_test.py2
-rw-r--r--tests/integration/api_container_test.py272
-rw-r--r--tests/integration/api_exec_test.py181
-rw-r--r--tests/integration/api_healthcheck_test.py10
-rw-r--r--tests/integration/api_image_test.py24
-rw-r--r--tests/integration/api_network_test.py20
-rw-r--r--tests/integration/api_plugin_test.py16
-rw-r--r--tests/integration/api_service_test.py155
-rw-r--r--tests/integration/api_swarm_test.py54
-rw-r--r--tests/integration/base.py80
-rw-r--r--tests/integration/conftest.py10
-rw-r--r--tests/integration/credentials/__init__.py0
-rw-r--r--tests/integration/credentials/store_test.py87
-rw-r--r--tests/integration/credentials/utils_test.py22
-rw-r--r--tests/integration/errors_test.py4
-rw-r--r--tests/integration/models_containers_test.py102
-rw-r--r--tests/integration/models_images_test.py35
-rw-r--r--tests/integration/models_swarm_test.py12
-rw-r--r--tests/integration/regression_test.py12
20 files changed, 854 insertions, 302 deletions
diff --git a/tests/integration/api_build_test.py b/tests/integration/api_build_test.py
index baaf33e..5712812 100644
--- a/tests/integration/api_build_test.py
+++ b/tests/integration/api_build_test.py
@@ -4,15 +4,58 @@ import shutil
import tempfile
from docker import errors
+from docker.utils.proxy import ProxyConfig
import pytest
import six
-from .base import BaseAPIIntegrationTest, BUSYBOX
+from .base import BaseAPIIntegrationTest, TEST_IMG
from ..helpers import random_name, requires_api_version, requires_experimental
class BuildTest(BaseAPIIntegrationTest):
+ def test_build_with_proxy(self):
+ self.client._proxy_configs = ProxyConfig(
+ ftp='a', http='b', https='c', no_proxy='d'
+ )
+
+ script = io.BytesIO('\n'.join([
+ 'FROM busybox',
+ 'RUN env | grep "FTP_PROXY=a"',
+ 'RUN env | grep "ftp_proxy=a"',
+ 'RUN env | grep "HTTP_PROXY=b"',
+ 'RUN env | grep "http_proxy=b"',
+ 'RUN env | grep "HTTPS_PROXY=c"',
+ 'RUN env | grep "https_proxy=c"',
+ 'RUN env | grep "NO_PROXY=d"',
+ 'RUN env | grep "no_proxy=d"',
+ ]).encode('ascii'))
+
+ self.client.build(fileobj=script, decode=True)
+
+ def test_build_with_proxy_and_buildargs(self):
+ self.client._proxy_configs = ProxyConfig(
+ ftp='a', http='b', https='c', no_proxy='d'
+ )
+
+ script = io.BytesIO('\n'.join([
+ 'FROM busybox',
+ 'RUN env | grep "FTP_PROXY=XXX"',
+ 'RUN env | grep "ftp_proxy=xxx"',
+ 'RUN env | grep "HTTP_PROXY=b"',
+ 'RUN env | grep "http_proxy=b"',
+ 'RUN env | grep "HTTPS_PROXY=c"',
+ 'RUN env | grep "https_proxy=c"',
+ 'RUN env | grep "NO_PROXY=d"',
+ 'RUN env | grep "no_proxy=d"',
+ ]).encode('ascii'))
+
+ self.client.build(
+ fileobj=script,
+ decode=True,
+ buildargs={'FTP_PROXY': 'XXX', 'ftp_proxy': 'xxx'}
+ )
+
def test_build_streaming(self):
script = io.BytesIO('\n'.join([
'FROM busybox',
@@ -234,7 +277,7 @@ class BuildTest(BaseAPIIntegrationTest):
# Set up pingable endpoint on custom network
network = self.client.create_network(random_name())['Id']
self.tmp_networks.append(network)
- container = self.client.create_container(BUSYBOX, 'top')
+ container = self.client.create_container(TEST_IMG, 'top')
self.tmp_containers.append(container)
self.client.start(container)
self.client.connect_container_to_network(
@@ -405,8 +448,10 @@ class BuildTest(BaseAPIIntegrationTest):
for _ in stream:
pass
- assert excinfo.value.status_code == 400
- assert 'invalid platform' in excinfo.exconly()
+ # Some API versions incorrectly returns 500 status; assert 4xx or 5xx
+ assert excinfo.value.is_error()
+ assert 'unknown operating system' in excinfo.exconly() \
+ or 'invalid platform' in excinfo.exconly()
def test_build_out_of_context_dockerfile(self):
base_dir = tempfile.mkdtemp()
@@ -540,6 +585,11 @@ class BuildTest(BaseAPIIntegrationTest):
) == sorted(lsdata)
@requires_api_version('1.31')
+ @pytest.mark.xfail(
+ True,
+ reason='Currently fails on 18.09: '
+ 'https://github.com/moby/moby/issues/37920'
+ )
def test_prune_builds(self):
prune_result = self.client.prune_builds()
assert 'SpaceReclaimed' in prune_result
diff --git a/tests/integration/api_client_test.py b/tests/integration/api_client_test.py
index 905e064..9e348f3 100644
--- a/tests/integration/api_client_test.py
+++ b/tests/integration/api_client_test.py
@@ -47,7 +47,7 @@ class ConnectionTimeoutTest(unittest.TestCase):
# This call isn't supposed to complete, and it should fail fast.
try:
res = self.client.inspect_container('id')
- except:
+ except: # noqa: E722
pass
end = time.time()
assert res is None
diff --git a/tests/integration/api_container_test.py b/tests/integration/api_container_test.py
index ff70148..1ba3eaa 100644
--- a/tests/integration/api_container_test.py
+++ b/tests/integration/api_container_test.py
@@ -5,28 +5,27 @@ import tempfile
import threading
from datetime import datetime
-import docker
-from docker.constants import IS_WINDOWS_PLATFORM
-from docker.utils.socket import next_frame_size
-from docker.utils.socket import read_exactly
-
import pytest
-
import requests
import six
-from .base import BUSYBOX, BaseAPIIntegrationTest
+import docker
from .. import helpers
-from ..helpers import (
- requires_api_version, ctrl_with, assert_cat_socket_detached_with_keys
-)
+from ..helpers import assert_cat_socket_detached_with_keys
+from ..helpers import ctrl_with
+from ..helpers import requires_api_version
+from .base import BaseAPIIntegrationTest
+from .base import TEST_IMG
+from docker.constants import IS_WINDOWS_PLATFORM
+from docker.utils.socket import next_frame_header
+from docker.utils.socket import read_exactly
class ListContainersTest(BaseAPIIntegrationTest):
def test_list_containers(self):
res0 = self.client.containers(all=True)
size = len(res0)
- res1 = self.client.create_container(BUSYBOX, 'true')
+ res1 = self.client.create_container(TEST_IMG, 'true')
assert 'Id' in res1
self.client.start(res1['Id'])
self.tmp_containers.append(res1['Id'])
@@ -38,20 +37,20 @@ class ListContainersTest(BaseAPIIntegrationTest):
assert 'Command' in retrieved
assert retrieved['Command'] == six.text_type('true')
assert 'Image' in retrieved
- assert re.search(r'busybox:.*', retrieved['Image'])
+ assert re.search(r'alpine:.*', retrieved['Image'])
assert 'Status' in retrieved
class CreateContainerTest(BaseAPIIntegrationTest):
def test_create(self):
- res = self.client.create_container(BUSYBOX, 'true')
+ res = self.client.create_container(TEST_IMG, 'true')
assert 'Id' in res
self.tmp_containers.append(res['Id'])
def test_create_with_host_pid_mode(self):
ctnr = self.client.create_container(
- BUSYBOX, 'true', host_config=self.client.create_host_config(
+ TEST_IMG, 'true', host_config=self.client.create_host_config(
pid_mode='host', network_mode='none'
)
)
@@ -66,7 +65,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_create_with_links(self):
res0 = self.client.create_container(
- BUSYBOX, 'cat',
+ TEST_IMG, 'cat',
detach=True, stdin_open=True,
environment={'FOO': '1'})
@@ -76,7 +75,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
self.client.start(container1_id)
res1 = self.client.create_container(
- BUSYBOX, 'cat',
+ TEST_IMG, 'cat',
detach=True, stdin_open=True,
environment={'FOO': '1'})
@@ -95,7 +94,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
link_env_prefix2 = link_alias2.upper()
res2 = self.client.create_container(
- BUSYBOX, 'env', host_config=self.client.create_host_config(
+ TEST_IMG, 'env', host_config=self.client.create_host_config(
links={link_path1: link_alias1, link_path2: link_alias2},
network_mode='bridge'
)
@@ -115,7 +114,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_create_with_restart_policy(self):
container = self.client.create_container(
- BUSYBOX, ['sleep', '2'],
+ TEST_IMG, ['sleep', '2'],
host_config=self.client.create_host_config(
restart_policy={"Name": "always", "MaximumRetryCount": 0},
network_mode='none'
@@ -134,21 +133,21 @@ class CreateContainerTest(BaseAPIIntegrationTest):
vol_names = ['foobar_vol0', 'foobar_vol1']
res0 = self.client.create_container(
- BUSYBOX, 'true', name=vol_names[0]
+ TEST_IMG, 'true', name=vol_names[0]
)
container1_id = res0['Id']
self.tmp_containers.append(container1_id)
self.client.start(container1_id)
res1 = self.client.create_container(
- BUSYBOX, 'true', name=vol_names[1]
+ TEST_IMG, 'true', name=vol_names[1]
)
container2_id = res1['Id']
self.tmp_containers.append(container2_id)
self.client.start(container2_id)
res = self.client.create_container(
- BUSYBOX, 'cat', detach=True, stdin_open=True,
+ TEST_IMG, 'cat', detach=True, stdin_open=True,
host_config=self.client.create_host_config(
volumes_from=vol_names, network_mode='none'
)
@@ -162,7 +161,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def create_container_readonly_fs(self):
ctnr = self.client.create_container(
- BUSYBOX, ['mkdir', '/shrine'],
+ TEST_IMG, ['mkdir', '/shrine'],
host_config=self.client.create_host_config(
read_only=True, network_mode='none'
)
@@ -174,7 +173,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
assert res != 0
def create_container_with_name(self):
- res = self.client.create_container(BUSYBOX, 'true', name='foobar')
+ res = self.client.create_container(TEST_IMG, 'true', name='foobar')
assert 'Id' in res
self.tmp_containers.append(res['Id'])
inspect = self.client.inspect_container(res['Id'])
@@ -183,7 +182,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def create_container_privileged(self):
res = self.client.create_container(
- BUSYBOX, 'true', host_config=self.client.create_host_config(
+ TEST_IMG, 'true', host_config=self.client.create_host_config(
privileged=True, network_mode='none'
)
)
@@ -209,7 +208,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_create_with_mac_address(self):
mac_address_expected = "02:42:ac:11:00:0a"
container = self.client.create_container(
- BUSYBOX, ['sleep', '60'], mac_address=mac_address_expected)
+ TEST_IMG, ['sleep', '60'], mac_address=mac_address_expected)
id = container['Id']
@@ -221,7 +220,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_group_id_ints(self):
container = self.client.create_container(
- BUSYBOX, 'id -G',
+ TEST_IMG, 'id -G',
host_config=self.client.create_host_config(group_add=[1000, 1001])
)
self.tmp_containers.append(container)
@@ -237,7 +236,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_group_id_strings(self):
container = self.client.create_container(
- BUSYBOX, 'id -G', host_config=self.client.create_host_config(
+ TEST_IMG, 'id -G', host_config=self.client.create_host_config(
group_add=['1000', '1001']
)
)
@@ -260,7 +259,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
)
container = self.client.create_container(
- BUSYBOX, ['true'],
+ TEST_IMG, ['true'],
host_config=self.client.create_host_config(log_config=log_config)
)
self.tmp_containers.append(container['Id'])
@@ -282,7 +281,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
with pytest.raises(docker.errors.APIError) as excinfo:
# raises an internal server error 500
container = self.client.create_container(
- BUSYBOX, ['true'], host_config=self.client.create_host_config(
+ TEST_IMG, ['true'], host_config=self.client.create_host_config(
log_config=log_config
)
)
@@ -297,7 +296,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
)
container = self.client.create_container(
- BUSYBOX, ['true'],
+ TEST_IMG, ['true'],
host_config=self.client.create_host_config(log_config=log_config)
)
self.tmp_containers.append(container['Id'])
@@ -316,7 +315,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
)
container = self.client.create_container(
- BUSYBOX, ['true'],
+ TEST_IMG, ['true'],
host_config=self.client.create_host_config(log_config=log_config)
)
self.tmp_containers.append(container['Id'])
@@ -330,7 +329,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_create_with_memory_constraints_with_str(self):
ctnr = self.client.create_container(
- BUSYBOX, 'true',
+ TEST_IMG, 'true',
host_config=self.client.create_host_config(
memswap_limit='1G',
mem_limit='700M'
@@ -348,7 +347,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_create_with_memory_constraints_with_int(self):
ctnr = self.client.create_container(
- BUSYBOX, 'true',
+ TEST_IMG, 'true',
host_config=self.client.create_host_config(mem_swappiness=40)
)
assert 'Id' in ctnr
@@ -362,16 +361,15 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_create_with_environment_variable_no_value(self):
container = self.client.create_container(
- BUSYBOX,
+ TEST_IMG,
['echo'],
environment={'Foo': None, 'Other': 'one', 'Blank': ''},
)
self.tmp_containers.append(container['Id'])
config = self.client.inspect_container(container['Id'])
- assert (
- sorted(config['Config']['Env']) ==
- sorted(['Foo', 'Other=one', 'Blank='])
- )
+ assert 'Foo' in config['Config']['Env']
+ assert 'Other=one' in config['Config']['Env']
+ assert 'Blank=' in config['Config']['Env']
@requires_api_version('1.22')
def test_create_with_tmpfs(self):
@@ -380,7 +378,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
}
container = self.client.create_container(
- BUSYBOX,
+ TEST_IMG,
['echo'],
host_config=self.client.create_host_config(
tmpfs=tmpfs))
@@ -392,7 +390,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
@requires_api_version('1.24')
def test_create_with_isolation(self):
container = self.client.create_container(
- BUSYBOX, ['echo'], host_config=self.client.create_host_config(
+ TEST_IMG, ['echo'], host_config=self.client.create_host_config(
isolation='default'
)
)
@@ -406,7 +404,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
auto_remove=True
)
container = self.client.create_container(
- BUSYBOX, ['echo', 'test'], host_config=host_config
+ TEST_IMG, ['echo', 'test'], host_config=host_config
)
self.tmp_containers.append(container['Id'])
config = self.client.inspect_container(container)
@@ -415,7 +413,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
@requires_api_version('1.25')
def test_create_with_stop_timeout(self):
container = self.client.create_container(
- BUSYBOX, ['echo', 'test'], stop_timeout=25
+ TEST_IMG, ['echo', 'test'], stop_timeout=25
)
self.tmp_containers.append(container['Id'])
config = self.client.inspect_container(container)
@@ -428,7 +426,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
storage_opt={'size': '120G'}
)
container = self.client.create_container(
- BUSYBOX, ['echo', 'test'], host_config=host_config
+ TEST_IMG, ['echo', 'test'], host_config=host_config
)
self.tmp_containers.append(container)
config = self.client.inspect_container(container)
@@ -439,7 +437,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
@requires_api_version('1.25')
def test_create_with_init(self):
ctnr = self.client.create_container(
- BUSYBOX, 'true',
+ TEST_IMG, 'true',
host_config=self.client.create_host_config(
init=True
)
@@ -448,25 +446,12 @@ class CreateContainerTest(BaseAPIIntegrationTest):
config = self.client.inspect_container(ctnr)
assert config['HostConfig']['Init'] is True
- @pytest.mark.xfail(True, reason='init-path removed in 17.05.0')
- @requires_api_version('1.25')
- def test_create_with_init_path(self):
- ctnr = self.client.create_container(
- BUSYBOX, 'true',
- host_config=self.client.create_host_config(
- init_path="/usr/libexec/docker-init"
- )
- )
- self.tmp_containers.append(ctnr['Id'])
- config = self.client.inspect_container(ctnr)
- assert config['HostConfig']['InitPath'] == "/usr/libexec/docker-init"
-
@requires_api_version('1.24')
@pytest.mark.xfail(not os.path.exists('/sys/fs/cgroup/cpu.rt_runtime_us'),
reason='CONFIG_RT_GROUP_SCHED isn\'t enabled')
def test_create_with_cpu_rt_options(self):
ctnr = self.client.create_container(
- BUSYBOX, 'true', host_config=self.client.create_host_config(
+ TEST_IMG, 'true', host_config=self.client.create_host_config(
cpu_rt_period=1000, cpu_rt_runtime=500
)
)
@@ -479,7 +464,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_create_with_device_cgroup_rules(self):
rule = 'c 7:128 rwm'
ctnr = self.client.create_container(
- BUSYBOX, 'cat /sys/fs/cgroup/devices/devices.list',
+ TEST_IMG, 'cat /sys/fs/cgroup/devices/devices.list',
host_config=self.client.create_host_config(
device_cgroup_rules=[rule]
)
@@ -490,6 +475,16 @@ class CreateContainerTest(BaseAPIIntegrationTest):
self.client.start(ctnr)
assert rule in self.client.logs(ctnr).decode('utf-8')
+ def test_create_with_uts_mode(self):
+ container = self.client.create_container(
+ TEST_IMG, ['echo'], host_config=self.client.create_host_config(
+ uts_mode='host'
+ )
+ )
+ self.tmp_containers.append(container)
+ config = self.client.inspect_container(container)
+ assert config['HostConfig']['UTSMode'] == 'host'
+
@pytest.mark.xfail(
IS_WINDOWS_PLATFORM, reason='Test not designed for Windows platform'
@@ -506,7 +501,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
self.run_with_volume(
False,
- BUSYBOX,
+ TEST_IMG,
['touch', os.path.join(self.mount_dest, self.filename)],
)
@@ -514,7 +509,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
container = self.run_with_volume(
False,
- BUSYBOX,
+ TEST_IMG,
['ls', self.mount_dest],
)
logs = self.client.logs(container)
@@ -528,12 +523,12 @@ class VolumeBindTest(BaseAPIIntegrationTest):
def test_create_with_binds_ro(self):
self.run_with_volume(
False,
- BUSYBOX,
+ TEST_IMG,
['touch', os.path.join(self.mount_dest, self.filename)],
)
container = self.run_with_volume(
True,
- BUSYBOX,
+ TEST_IMG,
['ls', self.mount_dest],
)
logs = self.client.logs(container)
@@ -552,7 +547,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
)
host_config = self.client.create_host_config(mounts=[mount])
container = self.run_container(
- BUSYBOX, ['ls', self.mount_dest],
+ TEST_IMG, ['ls', self.mount_dest],
host_config=host_config
)
assert container
@@ -571,7 +566,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
)
host_config = self.client.create_host_config(mounts=[mount])
container = self.run_container(
- BUSYBOX, ['ls', self.mount_dest],
+ TEST_IMG, ['ls', self.mount_dest],
host_config=host_config
)
assert container
@@ -590,7 +585,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
)
host_config = self.client.create_host_config(mounts=[mount])
container = self.client.create_container(
- BUSYBOX, ['true'], host_config=host_config,
+ TEST_IMG, ['true'], host_config=host_config,
)
assert container
inspect_data = self.client.inspect_container(container)
@@ -636,7 +631,7 @@ class ArchiveTest(BaseAPIIntegrationTest):
def test_get_file_archive_from_container(self):
data = 'The Maid and the Pocket Watch of Blood'
ctnr = self.client.create_container(
- BUSYBOX, 'sh -c "echo {0} > /vol1/data.txt"'.format(data),
+ TEST_IMG, 'sh -c "echo {0} > /vol1/data.txt"'.format(data),
volumes=['/vol1']
)
self.tmp_containers.append(ctnr)
@@ -655,7 +650,7 @@ class ArchiveTest(BaseAPIIntegrationTest):
def test_get_file_stat_from_container(self):
data = 'The Maid and the Pocket Watch of Blood'
ctnr = self.client.create_container(
- BUSYBOX, 'sh -c "echo -n {0} > /vol1/data.txt"'.format(data),
+ TEST_IMG, 'sh -c "echo -n {0} > /vol1/data.txt"'.format(data),
volumes=['/vol1']
)
self.tmp_containers.append(ctnr)
@@ -673,7 +668,7 @@ class ArchiveTest(BaseAPIIntegrationTest):
test_file.write(data)
test_file.seek(0)
ctnr = self.client.create_container(
- BUSYBOX,
+ TEST_IMG,
'cat {0}'.format(
os.path.join('/vol1/', os.path.basename(test_file.name))
),
@@ -695,7 +690,7 @@ class ArchiveTest(BaseAPIIntegrationTest):
dirs = ['foo', 'bar']
base = helpers.make_tree(dirs, files)
ctnr = self.client.create_container(
- BUSYBOX, 'ls -p /vol1', volumes=['/vol1']
+ TEST_IMG, 'ls -p /vol1', volumes=['/vol1']
)
self.tmp_containers.append(ctnr)
with docker.utils.tar(base) as test_tar:
@@ -716,7 +711,7 @@ class RenameContainerTest(BaseAPIIntegrationTest):
def test_rename_container(self):
version = self.client.version()['Version']
name = 'hong_meiling'
- res = self.client.create_container(BUSYBOX, 'true')
+ res = self.client.create_container(TEST_IMG, 'true')
assert 'Id' in res
self.tmp_containers.append(res['Id'])
self.client.rename(res, name)
@@ -730,7 +725,7 @@ class RenameContainerTest(BaseAPIIntegrationTest):
class StartContainerTest(BaseAPIIntegrationTest):
def test_start_container(self):
- res = self.client.create_container(BUSYBOX, 'true')
+ res = self.client.create_container(TEST_IMG, 'true')
assert 'Id' in res
self.tmp_containers.append(res['Id'])
self.client.start(res['Id'])
@@ -746,7 +741,7 @@ class StartContainerTest(BaseAPIIntegrationTest):
assert inspect['State']['ExitCode'] == 0
def test_start_container_with_dict_instead_of_id(self):
- res = self.client.create_container(BUSYBOX, 'true')
+ res = self.client.create_container(TEST_IMG, 'true')
assert 'Id' in res
self.tmp_containers.append(res['Id'])
self.client.start(res)
@@ -774,7 +769,7 @@ class StartContainerTest(BaseAPIIntegrationTest):
'true && echo "Night of Nights"'
]
for cmd in commands:
- container = self.client.create_container(BUSYBOX, cmd)
+ container = self.client.create_container(TEST_IMG, cmd)
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
@@ -784,7 +779,7 @@ class StartContainerTest(BaseAPIIntegrationTest):
class WaitTest(BaseAPIIntegrationTest):
def test_wait(self):
- res = self.client.create_container(BUSYBOX, ['sleep', '3'])
+ res = self.client.create_container(TEST_IMG, ['sleep', '3'])
id = res['Id']
self.tmp_containers.append(id)
self.client.start(id)
@@ -797,7 +792,7 @@ class WaitTest(BaseAPIIntegrationTest):
assert inspect['State']['ExitCode'] == exitcode
def test_wait_with_dict_instead_of_id(self):
- res = self.client.create_container(BUSYBOX, ['sleep', '3'])
+ res = self.client.create_container(TEST_IMG, ['sleep', '3'])
id = res['Id']
self.tmp_containers.append(id)
self.client.start(res)
@@ -811,13 +806,13 @@ class WaitTest(BaseAPIIntegrationTest):
@requires_api_version('1.30')
def test_wait_with_condition(self):
- ctnr = self.client.create_container(BUSYBOX, 'true')
+ ctnr = self.client.create_container(TEST_IMG, 'true')
self.tmp_containers.append(ctnr)
with pytest.raises(requests.exceptions.ConnectionError):
self.client.wait(ctnr, condition='removed', timeout=1)
ctnr = self.client.create_container(
- BUSYBOX, ['sleep', '3'],
+ TEST_IMG, ['sleep', '3'],
host_config=self.client.create_host_config(auto_remove=True)
)
self.tmp_containers.append(ctnr)
@@ -831,7 +826,7 @@ class LogsTest(BaseAPIIntegrationTest):
def test_logs(self):
snippet = 'Flowering Nights (Sakuya Iyazoi)'
container = self.client.create_container(
- BUSYBOX, 'echo {0}'.format(snippet)
+ TEST_IMG, 'echo {0}'.format(snippet)
)
id = container['Id']
self.tmp_containers.append(id)
@@ -845,7 +840,7 @@ class LogsTest(BaseAPIIntegrationTest):
snippet = '''Line1
Line2'''
container = self.client.create_container(
- BUSYBOX, 'echo "{0}"'.format(snippet)
+ TEST_IMG, 'echo "{0}"'.format(snippet)
)
id = container['Id']
self.tmp_containers.append(id)
@@ -858,7 +853,7 @@ Line2'''
def test_logs_streaming_and_follow(self):
snippet = 'Flowering Nights (Sakuya Iyazoi)'
container = self.client.create_container(
- BUSYBOX, 'echo {0}'.format(snippet)
+ TEST_IMG, 'echo {0}'.format(snippet)
)
id = container['Id']
self.tmp_containers.append(id)
@@ -873,10 +868,12 @@ Line2'''
assert logs == (snippet + '\n').encode(encoding='ascii')
@pytest.mark.timeout(5)
+ @pytest.mark.skipif(os.environ.get('DOCKER_HOST', '').startswith('ssh://'),
+ reason='No cancellable streams over SSH')
def test_logs_streaming_and_follow_and_cancel(self):
snippet = 'Flowering Nights (Sakuya Iyazoi)'
container = self.client.create_container(
- BUSYBOX, 'sh -c "echo \\"{0}\\" && sleep 3"'.format(snippet)
+ TEST_IMG, 'sh -c "echo \\"{0}\\" && sleep 3"'.format(snippet)
)
id = container['Id']
self.tmp_containers.append(id)
@@ -894,7 +891,7 @@ Line2'''
def test_logs_with_dict_instead_of_id(self):
snippet = 'Flowering Nights (Sakuya Iyazoi)'
container = self.client.create_container(
- BUSYBOX, 'echo {0}'.format(snippet)
+ TEST_IMG, 'echo {0}'.format(snippet)
)
id = container['Id']
self.tmp_containers.append(id)
@@ -907,7 +904,7 @@ Line2'''
def test_logs_with_tail_0(self):
snippet = 'Flowering Nights (Sakuya Iyazoi)'
container = self.client.create_container(
- BUSYBOX, 'echo "{0}"'.format(snippet)
+ TEST_IMG, 'echo "{0}"'.format(snippet)
)
id = container['Id']
self.tmp_containers.append(id)
@@ -921,7 +918,7 @@ Line2'''
def test_logs_with_until(self):
snippet = 'Shanghai Teahouse (Hong Meiling)'
container = self.client.create_container(
- BUSYBOX, 'echo "{0}"'.format(snippet)
+ TEST_IMG, 'echo "{0}"'.format(snippet)
)
self.tmp_containers.append(container)
@@ -936,7 +933,7 @@ Line2'''
class DiffTest(BaseAPIIntegrationTest):
def test_diff(self):
- container = self.client.create_container(BUSYBOX, ['touch', '/test'])
+ container = self.client.create_container(TEST_IMG, ['touch', '/test'])
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
@@ -949,7 +946,7 @@ class DiffTest(BaseAPIIntegrationTest):
assert test_diff[0]['Kind'] == 1
def test_diff_with_dict_instead_of_id(self):
- container = self.client.create_container(BUSYBOX, ['touch', '/test'])
+ container = self.client.create_container(TEST_IMG, ['touch', '/test'])
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
@@ -964,7 +961,7 @@ class DiffTest(BaseAPIIntegrationTest):
class StopTest(BaseAPIIntegrationTest):
def test_stop(self):
- container = self.client.create_container(BUSYBOX, ['sleep', '9999'])
+ container = self.client.create_container(TEST_IMG, ['sleep', '9999'])
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
@@ -976,7 +973,7 @@ class StopTest(BaseAPIIntegrationTest):
assert state['Running'] is False
def test_stop_with_dict_instead_of_id(self):
- container = self.client.create_container(BUSYBOX, ['sleep', '9999'])
+ container = self.client.create_container(TEST_IMG, ['sleep', '9999'])
assert 'Id' in container
id = container['Id']
self.client.start(container)
@@ -991,7 +988,7 @@ class StopTest(BaseAPIIntegrationTest):
class KillTest(BaseAPIIntegrationTest):
def test_kill(self):
- container = self.client.create_container(BUSYBOX, ['sleep', '9999'])
+ container = self.client.create_container(TEST_IMG, ['sleep', '9999'])
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
@@ -1005,7 +1002,7 @@ class KillTest(BaseAPIIntegrationTest):
assert state['Running'] is False
def test_kill_with_dict_instead_of_id(self):
- container = self.client.create_container(BUSYBOX, ['sleep', '9999'])
+ container = self.client.create_container(TEST_IMG, ['sleep', '9999'])
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
@@ -1019,7 +1016,7 @@ class KillTest(BaseAPIIntegrationTest):
assert state['Running'] is False
def test_kill_with_signal(self):
- id = self.client.create_container(BUSYBOX, ['sleep', '60'])
+ id = self.client.create_container(TEST_IMG, ['sleep', '60'])
self.tmp_containers.append(id)
self.client.start(id)
self.client.kill(
@@ -1036,7 +1033,7 @@ class KillTest(BaseAPIIntegrationTest):
assert state['Running'] is False, state
def test_kill_with_signal_name(self):
- id = self.client.create_container(BUSYBOX, ['sleep', '60'])
+ id = self.client.create_container(TEST_IMG, ['sleep', '60'])
self.client.start(id)
self.tmp_containers.append(id)
self.client.kill(id, signal='SIGKILL')
@@ -1051,7 +1048,7 @@ class KillTest(BaseAPIIntegrationTest):
assert state['Running'] is False, state
def test_kill_with_signal_integer(self):
- id = self.client.create_container(BUSYBOX, ['sleep', '60'])
+ id = self.client.create_container(TEST_IMG, ['sleep', '60'])
self.client.start(id)
self.tmp_containers.append(id)
self.client.kill(id, signal=9)
@@ -1068,14 +1065,19 @@ class KillTest(BaseAPIIntegrationTest):
class PortTest(BaseAPIIntegrationTest):
def test_port(self):
-
port_bindings = {
'1111': ('127.0.0.1', '4567'),
- '2222': ('127.0.0.1', '4568')
+ '2222': ('127.0.0.1', '4568'),
+ '3333/udp': ('127.0.0.1', '4569'),
}
+ ports = [
+ 1111,
+ 2222,
+ (3333, 'udp'),
+ ]
container = self.client.create_container(
- BUSYBOX, ['sleep', '60'], ports=list(port_bindings.keys()),
+ TEST_IMG, ['sleep', '60'], ports=ports,
host_config=self.client.create_host_config(
port_bindings=port_bindings, network_mode='bridge'
)
@@ -1086,13 +1088,15 @@ class PortTest(BaseAPIIntegrationTest):
# Call the port function on each biding and compare expected vs actual
for port in port_bindings:
+ port, _, protocol = port.partition('/')
actual_bindings = self.client.port(container, port)
port_binding = actual_bindings.pop()
ip, host_port = port_binding['HostIp'], port_binding['HostPort']
- assert ip == port_bindings[port][0]
- assert host_port == port_bindings[port][1]
+ port_binding = port if not protocol else port + "/" + protocol
+ assert ip == port_bindings[port_binding][0]
+ assert host_port == port_bindings[port_binding][1]
self.client.kill(id)
@@ -1100,7 +1104,7 @@ class PortTest(BaseAPIIntegrationTest):
class ContainerTopTest(BaseAPIIntegrationTest):
def test_top(self):
container = self.client.create_container(
- BUSYBOX, ['sleep', '60']
+ TEST_IMG, ['sleep', '60']
)
self.tmp_containers.append(container)
@@ -1120,7 +1124,7 @@ class ContainerTopTest(BaseAPIIntegrationTest):
)
def test_top_with_psargs(self):
container = self.client.create_container(
- BUSYBOX, ['sleep', '60'])
+ TEST_IMG, ['sleep', '60'])
self.tmp_containers.append(container)
@@ -1136,7 +1140,7 @@ class ContainerTopTest(BaseAPIIntegrationTest):
class RestartContainerTest(BaseAPIIntegrationTest):
def test_restart(self):
- container = self.client.create_container(BUSYBOX, ['sleep', '9999'])
+ container = self.client.create_container(TEST_IMG, ['sleep', '9999'])
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
@@ -1155,16 +1159,16 @@ class RestartContainerTest(BaseAPIIntegrationTest):
self.client.kill(id)
def test_restart_with_low_timeout(self):
- container = self.client.create_container(BUSYBOX, ['sleep', '9999'])
+ container = self.client.create_container(TEST_IMG, ['sleep', '9999'])
self.client.start(container)
- self.client.timeout = 1
- self.client.restart(container, timeout=3)
+ self.client.timeout = 3
+ self.client.restart(container, timeout=1)
self.client.timeout = None
- self.client.restart(container, timeout=3)
+ self.client.restart(container, timeout=1)
self.client.kill(container)
def test_restart_with_dict_instead_of_id(self):
- container = self.client.create_container(BUSYBOX, ['sleep', '9999'])
+ container = self.client.create_container(TEST_IMG, ['sleep', '9999'])
assert 'Id' in container
id = container['Id']
self.client.start(container)
@@ -1186,7 +1190,7 @@ class RestartContainerTest(BaseAPIIntegrationTest):
class RemoveContainerTest(BaseAPIIntegrationTest):
def test_remove(self):
- container = self.client.create_container(BUSYBOX, ['true'])
+ container = self.client.create_container(TEST_IMG, ['true'])
id = container['Id']
self.client.start(id)
self.client.wait(id)
@@ -1196,7 +1200,7 @@ class RemoveContainerTest(BaseAPIIntegrationTest):
assert len(res) == 0
def test_remove_with_dict_instead_of_id(self):
- container = self.client.create_container(BUSYBOX, ['true'])
+ container = self.client.create_container(TEST_IMG, ['true'])
id = container['Id']
self.client.start(id)
self.client.wait(id)
@@ -1208,7 +1212,7 @@ class RemoveContainerTest(BaseAPIIntegrationTest):
class AttachContainerTest(BaseAPIIntegrationTest):
def test_run_container_streaming(self):
- container = self.client.create_container(BUSYBOX, '/bin/sh',
+ container = self.client.create_container(TEST_IMG, '/bin/sh',
detach=True, stdin_open=True)
id = container['Id']
self.tmp_containers.append(id)
@@ -1220,7 +1224,7 @@ class AttachContainerTest(BaseAPIIntegrationTest):
line = 'hi there and stuff and things, words!'
# `echo` appends CRLF, `printf` doesn't
command = "printf '{0}'".format(line)
- container = self.client.create_container(BUSYBOX, command,
+ container = self.client.create_container(TEST_IMG, command,
detach=True, tty=False)
self.tmp_containers.append(container)
@@ -1230,31 +1234,37 @@ class AttachContainerTest(BaseAPIIntegrationTest):
self.client.start(container)
- next_size = next_frame_size(pty_stdout)
+ (stream, next_size) = next_frame_header(pty_stdout)
+ assert stream == 1 # correspond to stdout
assert next_size == len(line)
data = read_exactly(pty_stdout, next_size)
assert data.decode('utf-8') == line
def test_attach_no_stream(self):
container = self.client.create_container(
- BUSYBOX, 'echo hello'
+ TEST_IMG, 'echo hello'
)
self.tmp_containers.append(container)
self.client.start(container)
output = self.client.attach(container, stream=False, logs=True)
assert output == 'hello\n'.encode(encoding='ascii')
- @pytest.mark.timeout(5)
+ @pytest.mark.timeout(10)
+ @pytest.mark.skipif(os.environ.get('DOCKER_HOST', '').startswith('ssh://'),
+ reason='No cancellable streams over SSH')
+ @pytest.mark.xfail(condition=os.environ.get('DOCKER_TLS_VERIFY') or
+ os.environ.get('DOCKER_CERT_PATH'),
+ reason='Flaky test on TLS')
def test_attach_stream_and_cancel(self):
container = self.client.create_container(
- BUSYBOX, 'sh -c "echo hello && sleep 60"',
+ TEST_IMG, 'sh -c "sleep 2 && echo hello && sleep 60"',
tty=True
)
self.tmp_containers.append(container)
self.client.start(container)
output = self.client.attach(container, stream=True, logs=True)
- threading.Timer(1, output.close).start()
+ threading.Timer(3, output.close).start()
lines = []
for line in output:
@@ -1265,7 +1275,7 @@ class AttachContainerTest(BaseAPIIntegrationTest):
def test_detach_with_default(self):
container = self.client.create_container(
- BUSYBOX, 'cat',
+ TEST_IMG, 'cat',
detach=True, stdin_open=True, tty=True
)
self.tmp_containers.append(container)
@@ -1284,7 +1294,7 @@ class AttachContainerTest(BaseAPIIntegrationTest):
self.client._general_configs['detachKeys'] = 'ctrl-p'
container = self.client.create_container(
- BUSYBOX, 'cat',
+ TEST_IMG, 'cat',
detach=True, stdin_open=True, tty=True
)
self.tmp_containers.append(container)
@@ -1301,7 +1311,7 @@ class AttachContainerTest(BaseAPIIntegrationTest):
self.client._general_configs['detachKeys'] = 'ctrl-p'
container = self.client.create_container(
- BUSYBOX, 'cat',
+ TEST_IMG, 'cat',
detach=True, stdin_open=True, tty=True
)
self.tmp_containers.append(container)
@@ -1317,7 +1327,7 @@ class AttachContainerTest(BaseAPIIntegrationTest):
class PauseTest(BaseAPIIntegrationTest):
def test_pause_unpause(self):
- container = self.client.create_container(BUSYBOX, ['sleep', '9999'])
+ container = self.client.create_container(TEST_IMG, ['sleep', '9999'])
id = container['Id']
self.tmp_containers.append(id)
self.client.start(container)
@@ -1348,9 +1358,9 @@ class PruneTest(BaseAPIIntegrationTest):
@requires_api_version('1.25')
def test_prune_containers(self):
container1 = self.client.create_container(
- BUSYBOX, ['sh', '-c', 'echo hello > /data.txt']
+ TEST_IMG, ['sh', '-c', 'echo hello > /data.txt']
)
- container2 = self.client.create_container(BUSYBOX, ['sleep', '9999'])
+ container2 = self.client.create_container(TEST_IMG, ['sleep', '9999'])
self.client.start(container1)
self.client.start(container2)
self.client.wait(container1)
@@ -1363,7 +1373,7 @@ class PruneTest(BaseAPIIntegrationTest):
class GetContainerStatsTest(BaseAPIIntegrationTest):
def test_get_container_stats_no_stream(self):
container = self.client.create_container(
- BUSYBOX, ['sleep', '60'],
+ TEST_IMG, ['sleep', '60'],
)
self.tmp_containers.append(container)
self.client.start(container)
@@ -1377,7 +1387,7 @@ class GetContainerStatsTest(BaseAPIIntegrationTest):
def test_get_container_stats_stream(self):
container = self.client.create_container(
- BUSYBOX, ['sleep', '60'],
+ TEST_IMG, ['sleep', '60'],
)
self.tmp_containers.append(container)
self.client.start(container)
@@ -1395,7 +1405,7 @@ class ContainerUpdateTest(BaseAPIIntegrationTest):
old_mem_limit = 400 * 1024 * 1024
new_mem_limit = 300 * 1024 * 1024
container = self.client.create_container(
- BUSYBOX, 'top', host_config=self.client.create_host_config(
+ TEST_IMG, 'top', host_config=self.client.create_host_config(
mem_limit=old_mem_limit
)
)
@@ -1416,7 +1426,7 @@ class ContainerUpdateTest(BaseAPIIntegrationTest):
'Name': 'on-failure'
}
container = self.client.create_container(
- BUSYBOX, ['sleep', '60'],
+ TEST_IMG, ['sleep', '60'],
host_config=self.client.create_host_config(
restart_policy=old_restart_policy
)
@@ -1440,7 +1450,7 @@ class ContainerCPUTest(BaseAPIIntegrationTest):
def test_container_cpu_shares(self):
cpu_shares = 512
container = self.client.create_container(
- BUSYBOX, 'ls', host_config=self.client.create_host_config(
+ TEST_IMG, 'ls', host_config=self.client.create_host_config(
cpu_shares=cpu_shares
)
)
@@ -1452,7 +1462,7 @@ class ContainerCPUTest(BaseAPIIntegrationTest):
def test_container_cpuset(self):
cpuset_cpus = "0,1"
container = self.client.create_container(
- BUSYBOX, 'ls', host_config=self.client.create_host_config(
+ TEST_IMG, 'ls', host_config=self.client.create_host_config(
cpuset_cpus=cpuset_cpus
)
)
@@ -1464,7 +1474,7 @@ class ContainerCPUTest(BaseAPIIntegrationTest):
@requires_api_version('1.25')
def test_create_with_runtime(self):
container = self.client.create_container(
- BUSYBOX, ['echo', 'test'], runtime='runc'
+ TEST_IMG, ['echo', 'test'], runtime='runc'
)
self.tmp_containers.append(container['Id'])
config = self.client.inspect_container(container)
@@ -1475,7 +1485,7 @@ class LinkTest(BaseAPIIntegrationTest):
def test_remove_link(self):
# Create containers
container1 = self.client.create_container(
- BUSYBOX, 'cat', detach=True, stdin_open=True
+ TEST_IMG, 'cat', detach=True, stdin_open=True
)
container1_id = container1['Id']
self.tmp_containers.append(container1_id)
@@ -1487,7 +1497,7 @@ class LinkTest(BaseAPIIntegrationTest):
link_alias = 'mylink'
container2 = self.client.create_container(
- BUSYBOX, 'cat', host_config=self.client.create_host_config(
+ TEST_IMG, 'cat', host_config=self.client.create_host_config(
links={link_path: link_alias}
)
)
diff --git a/tests/integration/api_exec_test.py b/tests/integration/api_exec_test.py
index 1a5a4e5..554e862 100644
--- a/tests/integration/api_exec_test.py
+++ b/tests/integration/api_exec_test.py
@@ -1,15 +1,54 @@
-from docker.utils.socket import next_frame_size
+from ..helpers import assert_cat_socket_detached_with_keys
+from ..helpers import ctrl_with
+from ..helpers import requires_api_version
+from .base import BaseAPIIntegrationTest
+from .base import TEST_IMG
+from docker.utils.proxy import ProxyConfig
+from docker.utils.socket import next_frame_header
from docker.utils.socket import read_exactly
-from .base import BaseAPIIntegrationTest, BUSYBOX
-from ..helpers import (
- requires_api_version, ctrl_with, assert_cat_socket_detached_with_keys
-)
-
class ExecTest(BaseAPIIntegrationTest):
+ def test_execute_command_with_proxy_env(self):
+ # Set a custom proxy config on the client
+ self.client._proxy_configs = ProxyConfig(
+ ftp='a', https='b', http='c', no_proxy='d'
+ )
+
+ container = self.client.create_container(
+ TEST_IMG, 'cat', detach=True, stdin_open=True,
+ )
+ self.client.start(container)
+ self.tmp_containers.append(container)
+
+ cmd = 'sh -c "env | grep -i proxy"'
+
+ # First, just make sure the environment variables from the custom
+ # config are set
+
+ res = self.client.exec_create(container, cmd=cmd)
+ output = self.client.exec_start(res).decode('utf-8').split('\n')
+ expected = [
+ 'ftp_proxy=a', 'https_proxy=b', 'http_proxy=c', 'no_proxy=d',
+ 'FTP_PROXY=a', 'HTTPS_PROXY=b', 'HTTP_PROXY=c', 'NO_PROXY=d'
+ ]
+ for item in expected:
+ assert item in output
+
+ # Overwrite some variables with a custom environment
+ env = {'https_proxy': 'xxx', 'HTTPS_PROXY': 'XXX'}
+
+ res = self.client.exec_create(container, cmd=cmd, environment=env)
+ output = self.client.exec_start(res).decode('utf-8').split('\n')
+ expected = [
+ 'ftp_proxy=a', 'https_proxy=xxx', 'http_proxy=c', 'no_proxy=d',
+ 'FTP_PROXY=a', 'HTTPS_PROXY=XXX', 'HTTP_PROXY=c', 'NO_PROXY=d'
+ ]
+ for item in expected:
+ assert item in output
+
def test_execute_command(self):
- container = self.client.create_container(BUSYBOX, 'cat',
+ container = self.client.create_container(TEST_IMG, 'cat',
detach=True, stdin_open=True)
id = container['Id']
self.client.start(id)
@@ -22,7 +61,7 @@ class ExecTest(BaseAPIIntegrationTest):
assert exec_log == b'hello\n'
def test_exec_command_string(self):
- container = self.client.create_container(BUSYBOX, 'cat',
+ container = self.client.create_container(TEST_IMG, 'cat',
detach=True, stdin_open=True)
id = container['Id']
self.client.start(id)
@@ -35,20 +74,20 @@ class ExecTest(BaseAPIIntegrationTest):
assert exec_log == b'hello world\n'
def test_exec_command_as_user(self):
- container = self.client.create_container(BUSYBOX, 'cat',
+ container = self.client.create_container(TEST_IMG, 'cat',
detach=True, stdin_open=True)
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
- res = self.client.exec_create(id, 'whoami', user='default')
+ res = self.client.exec_create(id, 'whoami', user='postgres')
assert 'Id' in res
exec_log = self.client.exec_start(res)
- assert exec_log == b'default\n'
+ assert exec_log == b'postgres\n'
def test_exec_command_as_root(self):
- container = self.client.create_container(BUSYBOX, 'cat',
+ container = self.client.create_container(TEST_IMG, 'cat',
detach=True, stdin_open=True)
id = container['Id']
self.client.start(id)
@@ -61,7 +100,7 @@ class ExecTest(BaseAPIIntegrationTest):
assert exec_log == b'root\n'
def test_exec_command_streaming(self):
- container = self.client.create_container(BUSYBOX, 'cat',
+ container = self.client.create_container(TEST_IMG, 'cat',
detach=True, stdin_open=True)
id = container['Id']
self.tmp_containers.append(id)
@@ -76,7 +115,7 @@ class ExecTest(BaseAPIIntegrationTest):
assert res == b'hello\nworld\n'
def test_exec_start_socket(self):
- container = self.client.create_container(BUSYBOX, 'cat',
+ container = self.client.create_container(TEST_IMG, 'cat',
detach=True, stdin_open=True)
container_id = container['Id']
self.client.start(container_id)
@@ -91,13 +130,14 @@ class ExecTest(BaseAPIIntegrationTest):
socket = self.client.exec_start(exec_id, socket=True)
self.addCleanup(socket.close)
- next_size = next_frame_size(socket)
+ (stream, next_size) = next_frame_header(socket)
+ assert stream == 1 # stdout (0 = stdin, 1 = stdout, 2 = stderr)
assert next_size == len(line)
data = read_exactly(socket, next_size)
assert data.decode('utf-8') == line
def test_exec_start_detached(self):
- container = self.client.create_container(BUSYBOX, 'cat',
+ container = self.client.create_container(TEST_IMG, 'cat',
detach=True, stdin_open=True)
container_id = container['Id']
self.client.start(container_id)
@@ -112,7 +152,7 @@ class ExecTest(BaseAPIIntegrationTest):
assert response == ""
def test_exec_inspect(self):
- container = self.client.create_container(BUSYBOX, 'cat',
+ container = self.client.create_container(TEST_IMG, 'cat',
detach=True, stdin_open=True)
id = container['Id']
self.client.start(id)
@@ -127,7 +167,7 @@ class ExecTest(BaseAPIIntegrationTest):
@requires_api_version('1.25')
def test_exec_command_with_env(self):
- container = self.client.create_container(BUSYBOX, 'cat',
+ container = self.client.create_container(TEST_IMG, 'cat',
detach=True, stdin_open=True)
id = container['Id']
self.client.start(id)
@@ -142,18 +182,18 @@ class ExecTest(BaseAPIIntegrationTest):
@requires_api_version('1.35')
def test_exec_command_with_workdir(self):
container = self.client.create_container(
- BUSYBOX, 'cat', detach=True, stdin_open=True
+ TEST_IMG, 'cat', detach=True, stdin_open=True
)
self.tmp_containers.append(container)
self.client.start(container)
- res = self.client.exec_create(container, 'pwd', workdir='/var/www')
+ res = self.client.exec_create(container, 'pwd', workdir='/var/opt')
exec_log = self.client.exec_start(res)
- assert exec_log == b'/var/www\n'
+ assert exec_log == b'/var/opt\n'
def test_detach_with_default(self):
container = self.client.create_container(
- BUSYBOX, 'cat', detach=True, stdin_open=True
+ TEST_IMG, 'cat', detach=True, stdin_open=True
)
id = container['Id']
self.client.start(id)
@@ -172,7 +212,7 @@ class ExecTest(BaseAPIIntegrationTest):
def test_detach_with_config_file(self):
self.client._general_configs['detachKeys'] = 'ctrl-p'
container = self.client.create_container(
- BUSYBOX, 'cat', detach=True, stdin_open=True
+ TEST_IMG, 'cat', detach=True, stdin_open=True
)
id = container['Id']
self.client.start(id)
@@ -186,20 +226,87 @@ class ExecTest(BaseAPIIntegrationTest):
assert_cat_socket_detached_with_keys(sock, [ctrl_with('p')])
- def test_detach_with_arg(self):
- self.client._general_configs['detachKeys'] = 'ctrl-p'
- container = self.client.create_container(
- BUSYBOX, 'cat', detach=True, stdin_open=True
- )
- id = container['Id']
- self.client.start(id)
- self.tmp_containers.append(id)
- exec_id = self.client.exec_create(
- id, 'cat',
- stdin=True, tty=True, detach_keys='ctrl-x', stdout=True
+class ExecDemuxTest(BaseAPIIntegrationTest):
+ cmd = 'sh -c "{}"'.format(' ; '.join([
+ # Write something on stdout
+ 'echo hello out',
+ # Busybox's sleep does not handle sub-second times.
+ # This loops takes ~0.3 second to execute on my machine.
+ 'sleep 0.5',
+ # Write something on stderr
+ 'echo hello err >&2'])
+ )
+
+ def setUp(self):
+ super(ExecDemuxTest, self).setUp()
+ self.container = self.client.create_container(
+ TEST_IMG, 'cat', detach=True, stdin_open=True
)
- sock = self.client.exec_start(exec_id, tty=True, socket=True)
- self.addCleanup(sock.close)
+ self.client.start(self.container)
+ self.tmp_containers.append(self.container)
- assert_cat_socket_detached_with_keys(sock, [ctrl_with('x')])
+ def test_exec_command_no_stream_no_demux(self):
+ # tty=False, stream=False, demux=False
+ res = self.client.exec_create(self.container, self.cmd)
+ exec_log = self.client.exec_start(res)
+ assert b'hello out\n' in exec_log
+ assert b'hello err\n' in exec_log
+
+ def test_exec_command_stream_no_demux(self):
+ # tty=False, stream=True, demux=False
+ res = self.client.exec_create(self.container, self.cmd)
+ exec_log = list(self.client.exec_start(res, stream=True))
+ assert len(exec_log) == 2
+ assert b'hello out\n' in exec_log
+ assert b'hello err\n' in exec_log
+
+ def test_exec_command_no_stream_demux(self):
+ # tty=False, stream=False, demux=True
+ res = self.client.exec_create(self.container, self.cmd)
+ exec_log = self.client.exec_start(res, demux=True)
+ assert exec_log == (b'hello out\n', b'hello err\n')
+
+ def test_exec_command_stream_demux(self):
+ # tty=False, stream=True, demux=True
+ res = self.client.exec_create(self.container, self.cmd)
+ exec_log = list(self.client.exec_start(res, demux=True, stream=True))
+ assert len(exec_log) == 2
+ assert (b'hello out\n', None) in exec_log
+ assert (None, b'hello err\n') in exec_log
+
+ def test_exec_command_tty_no_stream_no_demux(self):
+ # tty=True, stream=False, demux=False
+ res = self.client.exec_create(self.container, self.cmd, tty=True)
+ exec_log = self.client.exec_start(res)
+ assert exec_log == b'hello out\r\nhello err\r\n'
+
+ def test_exec_command_tty_stream_no_demux(self):
+ # tty=True, stream=True, demux=False
+ res = self.client.exec_create(self.container, self.cmd, tty=True)
+ exec_log = list(self.client.exec_start(res, stream=True))
+ assert b'hello out\r\n' in exec_log
+ if len(exec_log) == 2:
+ assert b'hello err\r\n' in exec_log
+ else:
+ assert len(exec_log) == 3
+ assert b'hello err' in exec_log
+ assert b'\r\n' in exec_log
+
+ def test_exec_command_tty_no_stream_demux(self):
+ # tty=True, stream=False, demux=True
+ res = self.client.exec_create(self.container, self.cmd, tty=True)
+ exec_log = self.client.exec_start(res, demux=True)
+ assert exec_log == (b'hello out\r\nhello err\r\n', None)
+
+ def test_exec_command_tty_stream_demux(self):
+ # tty=True, stream=True, demux=True
+ res = self.client.exec_create(self.container, self.cmd, tty=True)
+ exec_log = list(self.client.exec_start(res, demux=True, stream=True))
+ assert (b'hello out\r\n', None) in exec_log
+ if len(exec_log) == 2:
+ assert (b'hello err\r\n', None) in exec_log
+ else:
+ assert len(exec_log) == 3
+ assert (b'hello err', None) in exec_log
+ assert (b'\r\n', None) in exec_log
diff --git a/tests/integration/api_healthcheck_test.py b/tests/integration/api_healthcheck_test.py
index 5dbac37..c54583b 100644
--- a/tests/integration/api_healthcheck_test.py
+++ b/tests/integration/api_healthcheck_test.py
@@ -1,4 +1,4 @@
-from .base import BaseAPIIntegrationTest, BUSYBOX
+from .base import BaseAPIIntegrationTest, TEST_IMG
from .. import helpers
SECOND = 1000000000
@@ -16,7 +16,7 @@ class HealthcheckTest(BaseAPIIntegrationTest):
@helpers.requires_api_version('1.24')
def test_healthcheck_shell_command(self):
container = self.client.create_container(
- BUSYBOX, 'top', healthcheck=dict(test='echo "hello world"'))
+ TEST_IMG, 'top', healthcheck=dict(test='echo "hello world"'))
self.tmp_containers.append(container)
res = self.client.inspect_container(container)
@@ -27,7 +27,7 @@ class HealthcheckTest(BaseAPIIntegrationTest):
@helpers.requires_api_version('1.24')
def test_healthcheck_passes(self):
container = self.client.create_container(
- BUSYBOX, 'top', healthcheck=dict(
+ TEST_IMG, 'top', healthcheck=dict(
test="true",
interval=1 * SECOND,
timeout=1 * SECOND,
@@ -40,7 +40,7 @@ class HealthcheckTest(BaseAPIIntegrationTest):
@helpers.requires_api_version('1.24')
def test_healthcheck_fails(self):
container = self.client.create_container(
- BUSYBOX, 'top', healthcheck=dict(
+ TEST_IMG, 'top', healthcheck=dict(
test="false",
interval=1 * SECOND,
timeout=1 * SECOND,
@@ -53,7 +53,7 @@ class HealthcheckTest(BaseAPIIntegrationTest):
@helpers.requires_api_version('1.29')
def test_healthcheck_start_period(self):
container = self.client.create_container(
- BUSYBOX, 'top', healthcheck=dict(
+ TEST_IMG, 'top', healthcheck=dict(
test="echo 'x' >> /counter.txt && "
"test `cat /counter.txt | wc -l` -ge 3",
interval=1 * SECOND,
diff --git a/tests/integration/api_image_test.py b/tests/integration/api_image_test.py
index 050e7f3..2bc96ab 100644
--- a/tests/integration/api_image_test.py
+++ b/tests/integration/api_image_test.py
@@ -15,7 +15,7 @@ from six.moves import socketserver
import docker
from ..helpers import requires_api_version, requires_experimental
-from .base import BaseAPIIntegrationTest, BUSYBOX
+from .base import BaseAPIIntegrationTest, TEST_IMG
class ListImagesTest(BaseAPIIntegrationTest):
@@ -69,13 +69,15 @@ class PullImageTest(BaseAPIIntegrationTest):
with pytest.raises(docker.errors.APIError) as excinfo:
self.client.pull('hello-world', platform='foobar')
- assert excinfo.value.status_code == 500
- assert 'invalid platform' in excinfo.exconly()
+ # Some API versions incorrectly returns 500 status; assert 4xx or 5xx
+ assert excinfo.value.is_error()
+ assert 'unknown operating system' in excinfo.exconly() \
+ or 'invalid platform' in excinfo.exconly()
class CommitTest(BaseAPIIntegrationTest):
def test_commit(self):
- container = self.client.create_container(BUSYBOX, ['touch', '/test'])
+ container = self.client.create_container(TEST_IMG, ['touch', '/test'])
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
@@ -88,13 +90,13 @@ class CommitTest(BaseAPIIntegrationTest):
assert img['Container'].startswith(id)
assert 'ContainerConfig' in img
assert 'Image' in img['ContainerConfig']
- assert BUSYBOX == img['ContainerConfig']['Image']
- busybox_id = self.client.inspect_image(BUSYBOX)['Id']
+ assert TEST_IMG == img['ContainerConfig']['Image']
+ busybox_id = self.client.inspect_image(TEST_IMG)['Id']
assert 'Parent' in img
assert img['Parent'] == busybox_id
def test_commit_with_changes(self):
- cid = self.client.create_container(BUSYBOX, ['touch', '/test'])
+ cid = self.client.create_container(TEST_IMG, ['touch', '/test'])
self.tmp_containers.append(cid)
self.client.start(cid)
img_id = self.client.commit(
@@ -110,7 +112,7 @@ class CommitTest(BaseAPIIntegrationTest):
class RemoveImageTest(BaseAPIIntegrationTest):
def test_remove(self):
- container = self.client.create_container(BUSYBOX, ['touch', '/test'])
+ container = self.client.create_container(TEST_IMG, ['touch', '/test'])
id = container['Id']
self.client.start(id)
self.tmp_containers.append(id)
@@ -317,7 +319,7 @@ class PruneImagesTest(BaseAPIIntegrationTest):
pass
# Ensure busybox does not get pruned
- ctnr = self.client.create_container(BUSYBOX, ['sleep', '9999'])
+ ctnr = self.client.create_container(TEST_IMG, ['sleep', '9999'])
self.tmp_containers.append(ctnr)
self.client.pull('hello-world', tag='latest')
@@ -341,7 +343,7 @@ class SaveLoadImagesTest(BaseAPIIntegrationTest):
@requires_api_version('1.23')
def test_get_image_load_image(self):
with tempfile.TemporaryFile() as f:
- stream = self.client.get_image(BUSYBOX)
+ stream = self.client.get_image(TEST_IMG)
for chunk in stream:
f.write(chunk)
@@ -349,7 +351,7 @@ class SaveLoadImagesTest(BaseAPIIntegrationTest):
result = self.client.load_image(f.read())
success = False
- result_line = 'Loaded image: {}\n'.format(BUSYBOX)
+ result_line = 'Loaded image: {}\n'.format(TEST_IMG)
for data in result:
print(data)
if 'stream' in data:
diff --git a/tests/integration/api_network_test.py b/tests/integration/api_network_test.py
index b6726d0..0f26827 100644
--- a/tests/integration/api_network_test.py
+++ b/tests/integration/api_network_test.py
@@ -3,13 +3,13 @@ from docker.types import IPAMConfig, IPAMPool
import pytest
from ..helpers import random_name, requires_api_version
-from .base import BaseAPIIntegrationTest, BUSYBOX
+from .base import BaseAPIIntegrationTest, TEST_IMG
class TestNetworks(BaseAPIIntegrationTest):
def tearDown(self):
- super(TestNetworks, self).tearDown()
self.client.leave_swarm(force=True)
+ super(TestNetworks, self).tearDown()
def create_network(self, *args, **kwargs):
net_name = random_name()
@@ -92,7 +92,7 @@ class TestNetworks(BaseAPIIntegrationTest):
def test_connect_and_disconnect_container(self):
net_name, net_id = self.create_network()
- container = self.client.create_container(BUSYBOX, 'top')
+ container = self.client.create_container(TEST_IMG, 'top')
self.tmp_containers.append(container)
self.client.start(container)
@@ -119,7 +119,7 @@ class TestNetworks(BaseAPIIntegrationTest):
def test_connect_and_force_disconnect_container(self):
net_name, net_id = self.create_network()
- container = self.client.create_container(BUSYBOX, 'top')
+ container = self.client.create_container(TEST_IMG, 'top')
self.tmp_containers.append(container)
self.client.start(container)
@@ -144,7 +144,7 @@ class TestNetworks(BaseAPIIntegrationTest):
def test_connect_with_aliases(self):
net_name, net_id = self.create_network()
- container = self.client.create_container(BUSYBOX, 'top')
+ container = self.client.create_container(TEST_IMG, 'top')
self.tmp_containers.append(container)
self.client.start(container)
@@ -161,7 +161,7 @@ class TestNetworks(BaseAPIIntegrationTest):
net_name, net_id = self.create_network()
container = self.client.create_container(
- image=BUSYBOX,
+ image=TEST_IMG,
command='top',
host_config=self.client.create_host_config(network_mode=net_name),
)
@@ -181,7 +181,7 @@ class TestNetworks(BaseAPIIntegrationTest):
net_name, net_id = self.create_network()
container = self.client.create_container(
- image=BUSYBOX,
+ image=TEST_IMG,
command='top',
host_config=self.client.create_host_config(
network_mode=net_name,
@@ -211,7 +211,7 @@ class TestNetworks(BaseAPIIntegrationTest):
),
)
container = self.client.create_container(
- image=BUSYBOX, command='top',
+ image=TEST_IMG, command='top',
host_config=self.client.create_host_config(network_mode=net_name),
networking_config=self.client.create_networking_config({
net_name: self.client.create_endpoint_config(
@@ -237,7 +237,7 @@ class TestNetworks(BaseAPIIntegrationTest):
),
)
container = self.client.create_container(
- image=BUSYBOX, command='top',
+ image=TEST_IMG, command='top',
host_config=self.client.create_host_config(network_mode=net_name),
networking_config=self.client.create_networking_config({
net_name: self.client.create_endpoint_config(
@@ -257,7 +257,7 @@ class TestNetworks(BaseAPIIntegrationTest):
@requires_api_version('1.24')
def test_create_with_linklocal_ips(self):
container = self.client.create_container(
- BUSYBOX, 'top',
+ TEST_IMG, 'top',
networking_config=self.client.create_networking_config(
{
'bridge': self.client.create_endpoint_config(
diff --git a/tests/integration/api_plugin_test.py b/tests/integration/api_plugin_test.py
index 1150b09..38f9d12 100644
--- a/tests/integration/api_plugin_test.py
+++ b/tests/integration/api_plugin_test.py
@@ -3,7 +3,7 @@ import os
import docker
import pytest
-from .base import BaseAPIIntegrationTest, TEST_API_VERSION
+from .base import BaseAPIIntegrationTest
from ..helpers import requires_api_version
SSHFS = 'vieux/sshfs:latest'
@@ -13,27 +13,27 @@ SSHFS = 'vieux/sshfs:latest'
class PluginTest(BaseAPIIntegrationTest):
@classmethod
def teardown_class(cls):
- c = docker.APIClient(
- version=TEST_API_VERSION, timeout=60,
- **docker.utils.kwargs_from_env()
- )
+ client = cls.get_client_instance()
try:
- c.remove_plugin(SSHFS, force=True)
+ client.remove_plugin(SSHFS, force=True)
except docker.errors.APIError:
pass
def teardown_method(self, method):
+ client = self.get_client_instance()
try:
- self.client.disable_plugin(SSHFS)
+ client.disable_plugin(SSHFS)
except docker.errors.APIError:
pass
for p in self.tmp_plugins:
try:
- self.client.remove_plugin(p, force=True)
+ client.remove_plugin(p, force=True)
except docker.errors.APIError:
pass
+ client.close()
+
def ensure_plugin_installed(self, plugin_name):
try:
return self.client.inspect_plugin(plugin_name)
diff --git a/tests/integration/api_service_test.py b/tests/integration/api_service_test.py
index 85f9dcc..b6b7ec5 100644
--- a/tests/integration/api_service_test.py
+++ b/tests/integration/api_service_test.py
@@ -10,7 +10,7 @@ import six
from ..helpers import (
force_leave_swarm, requires_api_version, requires_experimental
)
-from .base import BaseAPIIntegrationTest, BUSYBOX
+from .base import BaseAPIIntegrationTest, TEST_IMG
class ServiceTest(BaseAPIIntegrationTest):
@@ -60,7 +60,7 @@ class ServiceTest(BaseAPIIntegrationTest):
name = self.get_service_name()
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['echo', 'hello']
+ TEST_IMG, ['echo', 'hello']
)
task_tmpl = docker.types.TaskTemplate(container_spec)
return name, self.client.create_service(
@@ -156,7 +156,7 @@ class ServiceTest(BaseAPIIntegrationTest):
def test_create_service_custom_log_driver(self):
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['echo', 'hello']
+ TEST_IMG, ['echo', 'hello']
)
log_cfg = docker.types.DriverConfig('none')
task_tmpl = docker.types.TaskTemplate(
@@ -174,7 +174,7 @@ class ServiceTest(BaseAPIIntegrationTest):
def test_create_service_with_volume_mount(self):
vol_name = self.get_service_name()
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['ls'],
+ TEST_IMG, ['ls'],
mounts=[
docker.types.Mount(target='/test', source=vol_name)
]
@@ -194,7 +194,7 @@ class ServiceTest(BaseAPIIntegrationTest):
assert mount['Type'] == 'volume'
def test_create_service_with_resources_constraints(self):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
resources = docker.types.Resources(
cpu_limit=4000000, mem_limit=3 * 1024 * 1024 * 1024,
cpu_reservation=3500000, mem_reservation=2 * 1024 * 1024 * 1024
@@ -214,7 +214,7 @@ class ServiceTest(BaseAPIIntegrationTest):
]
def _create_service_with_generic_resources(self, generic_resources):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
resources = docker.types.Resources(
generic_resources=generic_resources
@@ -265,7 +265,7 @@ class ServiceTest(BaseAPIIntegrationTest):
self._create_service_with_generic_resources(test_input)
def test_create_service_with_update_config(self):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(container_spec)
update_config = docker.types.UpdateConfig(
parallelism=10, delay=5, failure_action='pause'
@@ -281,6 +281,20 @@ class ServiceTest(BaseAPIIntegrationTest):
assert update_config['Delay'] == uc['Delay']
assert update_config['FailureAction'] == uc['FailureAction']
+ @requires_api_version('1.28')
+ def test_create_service_with_failure_action_rollback(self):
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
+ task_tmpl = docker.types.TaskTemplate(container_spec)
+ update_config = docker.types.UpdateConfig(failure_action='rollback')
+ name = self.get_service_name()
+ svc_id = self.client.create_service(
+ task_tmpl, update_config=update_config, name=name
+ )
+ svc_info = self.client.inspect_service(svc_id)
+ assert 'UpdateConfig' in svc_info['Spec']
+ uc = svc_info['Spec']['UpdateConfig']
+ assert update_config['FailureAction'] == uc['FailureAction']
+
@requires_api_version('1.25')
def test_create_service_with_update_config_monitor(self):
container_spec = docker.types.ContainerSpec('busybox', ['true'])
@@ -298,8 +312,29 @@ class ServiceTest(BaseAPIIntegrationTest):
assert update_config['Monitor'] == uc['Monitor']
assert update_config['MaxFailureRatio'] == uc['MaxFailureRatio']
+ @requires_api_version('1.28')
+ def test_create_service_with_rollback_config(self):
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
+ task_tmpl = docker.types.TaskTemplate(container_spec)
+ rollback_cfg = docker.types.RollbackConfig(
+ parallelism=10, delay=5, failure_action='pause',
+ monitor=300000000, max_failure_ratio=0.4
+ )
+ name = self.get_service_name()
+ svc_id = self.client.create_service(
+ task_tmpl, rollback_config=rollback_cfg, name=name
+ )
+ svc_info = self.client.inspect_service(svc_id)
+ assert 'RollbackConfig' in svc_info['Spec']
+ rc = svc_info['Spec']['RollbackConfig']
+ assert rollback_cfg['Parallelism'] == rc['Parallelism']
+ assert rollback_cfg['Delay'] == rc['Delay']
+ assert rollback_cfg['FailureAction'] == rc['FailureAction']
+ assert rollback_cfg['Monitor'] == rc['Monitor']
+ assert rollback_cfg['MaxFailureRatio'] == rc['MaxFailureRatio']
+
def test_create_service_with_restart_policy(self):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
policy = docker.types.RestartPolicy(
docker.types.RestartPolicy.condition_types.ANY,
delay=5, max_attempts=5
@@ -322,7 +357,7 @@ class ServiceTest(BaseAPIIntegrationTest):
'dockerpytest_2', driver='overlay', ipam={'Driver': 'default'}
)
self.tmp_networks.append(net2['Id'])
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
svc_id = self.client.create_service(
@@ -336,9 +371,38 @@ class ServiceTest(BaseAPIIntegrationTest):
{'Target': net1['Id']}, {'Target': net2['Id']}
]
+ def test_create_service_with_network_attachment_config(self):
+ network = self.client.create_network(
+ 'dockerpytest_1', driver='overlay', ipam={'Driver': 'default'}
+ )
+ self.tmp_networks.append(network['Id'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
+ network_config = docker.types.NetworkAttachmentConfig(
+ target='dockerpytest_1',
+ aliases=['dockerpytest_1_alias'],
+ options={
+ 'foo': 'bar'
+ }
+ )
+ task_tmpl = docker.types.TaskTemplate(
+ container_spec,
+ networks=[network_config]
+ )
+ name = self.get_service_name()
+ svc_id = self.client.create_service(
+ task_tmpl, name=name
+ )
+ svc_info = self.client.inspect_service(svc_id)
+ assert 'Networks' in svc_info['Spec']['TaskTemplate']
+ service_networks_info = svc_info['Spec']['TaskTemplate']['Networks']
+ assert len(service_networks_info) == 1
+ assert service_networks_info[0]['Target'] == network['Id']
+ assert service_networks_info[0]['Aliases'] == ['dockerpytest_1_alias']
+ assert service_networks_info[0]['DriverOpts'] == {'foo': 'bar'}
+
def test_create_service_with_placement(self):
node_id = self.client.nodes()[0]['ID']
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(
container_spec, placement=['node.id=={}'.format(node_id)]
)
@@ -351,7 +415,7 @@ class ServiceTest(BaseAPIIntegrationTest):
def test_create_service_with_placement_object(self):
node_id = self.client.nodes()[0]['ID']
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
placemt = docker.types.Placement(
constraints=['node.id=={}'.format(node_id)]
)
@@ -366,7 +430,7 @@ class ServiceTest(BaseAPIIntegrationTest):
@requires_api_version('1.30')
def test_create_service_with_placement_platform(self):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
placemt = docker.types.Placement(platforms=[('x86_64', 'linux')])
task_tmpl = docker.types.TaskTemplate(
container_spec, placement=placemt
@@ -379,7 +443,7 @@ class ServiceTest(BaseAPIIntegrationTest):
@requires_api_version('1.27')
def test_create_service_with_placement_preferences(self):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
placemt = docker.types.Placement(preferences=[
{'Spread': {'SpreadDescriptor': 'com.dockerpy.test'}}
])
@@ -392,8 +456,23 @@ class ServiceTest(BaseAPIIntegrationTest):
assert 'Placement' in svc_info['Spec']['TaskTemplate']
assert svc_info['Spec']['TaskTemplate']['Placement'] == placemt
+ @requires_api_version('1.27')
+ def test_create_service_with_placement_preferences_tuple(self):
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
+ placemt = docker.types.Placement(preferences=(
+ ('spread', 'com.dockerpy.test'),
+ ))
+ task_tmpl = docker.types.TaskTemplate(
+ container_spec, placement=placemt
+ )
+ name = self.get_service_name()
+ svc_id = self.client.create_service(task_tmpl, name=name)
+ svc_info = self.client.inspect_service(svc_id)
+ assert 'Placement' in svc_info['Spec']['TaskTemplate']
+ assert svc_info['Spec']['TaskTemplate']['Placement'] == placemt
+
def test_create_service_with_endpoint_spec(self):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
endpoint_spec = docker.types.EndpointSpec(ports={
@@ -423,7 +502,7 @@ class ServiceTest(BaseAPIIntegrationTest):
@requires_api_version('1.32')
def test_create_service_with_endpoint_spec_host_publish_mode(self):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
endpoint_spec = docker.types.EndpointSpec(ports={
@@ -443,7 +522,7 @@ class ServiceTest(BaseAPIIntegrationTest):
def test_create_service_with_env(self):
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['true'], env={'DOCKER_PY_TEST': 1}
+ TEST_IMG, ['true'], env={'DOCKER_PY_TEST': 1}
)
task_tmpl = docker.types.TaskTemplate(
container_spec,
@@ -459,7 +538,7 @@ class ServiceTest(BaseAPIIntegrationTest):
@requires_api_version('1.29')
def test_create_service_with_update_order(self):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(container_spec)
update_config = docker.types.UpdateConfig(
parallelism=10, delay=5, order='start-first'
@@ -478,7 +557,7 @@ class ServiceTest(BaseAPIIntegrationTest):
@requires_api_version('1.25')
def test_create_service_with_tty(self):
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['true'], tty=True
+ TEST_IMG, ['true'], tty=True
)
task_tmpl = docker.types.TaskTemplate(
container_spec,
@@ -495,7 +574,7 @@ class ServiceTest(BaseAPIIntegrationTest):
@requires_api_version('1.25')
def test_create_service_with_tty_dict(self):
container_spec = {
- 'Image': BUSYBOX,
+ 'Image': TEST_IMG,
'Command': ['true'],
'TTY': True
}
@@ -511,7 +590,7 @@ class ServiceTest(BaseAPIIntegrationTest):
def test_create_service_global_mode(self):
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['echo', 'hello']
+ TEST_IMG, ['echo', 'hello']
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
@@ -524,7 +603,7 @@ class ServiceTest(BaseAPIIntegrationTest):
def test_create_service_replicated_mode(self):
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['echo', 'hello']
+ TEST_IMG, ['echo', 'hello']
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
@@ -717,7 +796,7 @@ class ServiceTest(BaseAPIIntegrationTest):
search=['local'], options=['debug']
)
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['sleep', '999'], dns_config=dns_config
+ TEST_IMG, ['sleep', '999'], dns_config=dns_config
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
@@ -737,7 +816,7 @@ class ServiceTest(BaseAPIIntegrationTest):
start_period=3 * second, interval=int(second / 2),
)
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['sleep', '999'], healthcheck=hc
+ TEST_IMG, ['sleep', '999'], healthcheck=hc
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
@@ -754,7 +833,7 @@ class ServiceTest(BaseAPIIntegrationTest):
@requires_api_version('1.28')
def test_create_service_with_readonly(self):
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['sleep', '999'], read_only=True
+ TEST_IMG, ['sleep', '999'], read_only=True
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
@@ -768,7 +847,7 @@ class ServiceTest(BaseAPIIntegrationTest):
@requires_api_version('1.28')
def test_create_service_with_stop_signal(self):
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['sleep', '999'], stop_signal='SIGINT'
+ TEST_IMG, ['sleep', '999'], stop_signal='SIGINT'
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
@@ -786,7 +865,7 @@ class ServiceTest(BaseAPIIntegrationTest):
def test_create_service_with_privileges(self):
priv = docker.types.Privileges(selinux_disable=True)
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['sleep', '999'], privileges=priv
+ TEST_IMG, ['sleep', '999'], privileges=priv
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
@@ -800,6 +879,20 @@ class ServiceTest(BaseAPIIntegrationTest):
)
assert privileges['SELinuxContext']['Disable'] is True
+ @requires_api_version('1.38')
+ def test_create_service_with_init(self):
+ container_spec = docker.types.ContainerSpec(
+ 'busybox', ['sleep', '999'], init=True
+ )
+ task_tmpl = docker.types.TaskTemplate(container_spec)
+ name = self.get_service_name()
+ svc_id = self.client.create_service(task_tmpl, name=name)
+ svc_info = self.client.inspect_service(svc_id)
+ assert 'Init' in svc_info['Spec']['TaskTemplate']['ContainerSpec']
+ assert (
+ svc_info['Spec']['TaskTemplate']['ContainerSpec']['Init'] is True
+ )
+
@requires_api_version('1.25')
def test_update_service_with_defaults_name(self):
container_spec = docker.types.ContainerSpec(
@@ -928,7 +1021,7 @@ class ServiceTest(BaseAPIIntegrationTest):
assert labels['container.label'] == 'SampleLabel'
def test_update_service_with_defaults_update_config(self):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(container_spec)
update_config = docker.types.UpdateConfig(
parallelism=10, delay=5, failure_action='pause'
@@ -967,7 +1060,7 @@ class ServiceTest(BaseAPIIntegrationTest):
'dockerpytest_2', driver='overlay', ipam={'Driver': 'default'}
)
self.tmp_networks.append(net2['Id'])
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
svc_id = self.client.create_service(
@@ -1006,7 +1099,7 @@ class ServiceTest(BaseAPIIntegrationTest):
]
def test_update_service_with_defaults_endpoint_spec(self):
- container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
endpoint_spec = docker.types.EndpointSpec(ports={
@@ -1070,7 +1163,7 @@ class ServiceTest(BaseAPIIntegrationTest):
start_period=3 * second, interval=int(second / 2),
)
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['sleep', '999'], healthcheck=hc
+ TEST_IMG, ['sleep', '999'], healthcheck=hc
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
@@ -1085,7 +1178,7 @@ class ServiceTest(BaseAPIIntegrationTest):
)
container_spec = docker.types.ContainerSpec(
- BUSYBOX, ['sleep', '999'], healthcheck={}
+ TEST_IMG, ['sleep', '999'], healthcheck={}
)
task_tmpl = docker.types.TaskTemplate(container_spec)
diff --git a/tests/integration/api_swarm_test.py b/tests/integration/api_swarm_test.py
index dbf3786..f1cbc26 100644
--- a/tests/integration/api_swarm_test.py
+++ b/tests/integration/api_swarm_test.py
@@ -13,14 +13,13 @@ class SwarmTest(BaseAPIIntegrationTest):
self._unlock_key = None
def tearDown(self):
- super(SwarmTest, self).tearDown()
try:
if self._unlock_key:
self.client.unlock_swarm(self._unlock_key)
except docker.errors.APIError:
pass
-
force_leave_swarm(self.client)
+ super(SwarmTest, self).tearDown()
@requires_api_version('1.24')
def test_init_swarm_simple(self):
@@ -36,6 +35,35 @@ class SwarmTest(BaseAPIIntegrationTest):
version_2 = self.client.inspect_swarm()['Version']['Index']
assert version_2 != version_1
+ @requires_api_version('1.39')
+ def test_init_swarm_custom_addr_pool_defaults(self):
+ assert self.init_swarm()
+ results = self.client.inspect_swarm()
+ assert set(results['DefaultAddrPool']) == {'10.0.0.0/8'}
+ assert results['SubnetSize'] == 24
+
+ @requires_api_version('1.39')
+ def test_init_swarm_custom_addr_pool_only_pool(self):
+ assert self.init_swarm(default_addr_pool=['2.0.0.0/16'])
+ results = self.client.inspect_swarm()
+ assert set(results['DefaultAddrPool']) == {'2.0.0.0/16'}
+ assert results['SubnetSize'] == 24
+
+ @requires_api_version('1.39')
+ def test_init_swarm_custom_addr_pool_only_subnet_size(self):
+ assert self.init_swarm(subnet_size=26)
+ results = self.client.inspect_swarm()
+ assert set(results['DefaultAddrPool']) == {'10.0.0.0/8'}
+ assert results['SubnetSize'] == 26
+
+ @requires_api_version('1.39')
+ def test_init_swarm_custom_addr_pool_both_args(self):
+ assert self.init_swarm(default_addr_pool=['2.0.0.0/16', '3.0.0.0/16'],
+ subnet_size=28)
+ results = self.client.inspect_swarm()
+ assert set(results['DefaultAddrPool']) == {'2.0.0.0/16', '3.0.0.0/16'}
+ assert results['SubnetSize'] == 28
+
@requires_api_version('1.24')
def test_init_already_in_cluster(self):
assert self.init_swarm()
@@ -158,12 +186,14 @@ class SwarmTest(BaseAPIIntegrationTest):
@requires_api_version('1.24')
def test_inspect_node(self):
- assert self.init_swarm()
+ node_id = self.init_swarm()
+ assert node_id
nodes_list = self.client.nodes()
assert len(nodes_list) == 1
node = nodes_list[0]
node_data = self.client.inspect_node(node['ID'])
assert node['ID'] == node_data['ID']
+ assert node_id == node['ID']
assert node['Version'] == node_data['Version']
@requires_api_version('1.24')
@@ -205,3 +235,21 @@ class SwarmTest(BaseAPIIntegrationTest):
self.client.remove_node(node_id, True)
assert e.value.response.status_code >= 400
+
+ @requires_api_version('1.25')
+ def test_rotate_manager_unlock_key(self):
+ spec = self.client.create_swarm_spec(autolock_managers=True)
+ assert self.init_swarm(swarm_spec=spec)
+ swarm_info = self.client.inspect_swarm()
+ key_1 = self.client.get_unlock_key()
+ assert self.client.update_swarm(
+ version=swarm_info['Version']['Index'],
+ rotate_manager_unlock_key=True
+ )
+ key_2 = self.client.get_unlock_key()
+ assert key_1['UnlockKey'] != key_2['UnlockKey']
+
+ @requires_api_version('1.30')
+ @pytest.mark.xfail(reason='Can fail if eth0 has multiple IP addresses')
+ def test_init_swarm_data_path_addr(self):
+ assert self.init_swarm(data_path_addr='eth0')
diff --git a/tests/integration/base.py b/tests/integration/base.py
index 56c23ed..a7613f6 100644
--- a/tests/integration/base.py
+++ b/tests/integration/base.py
@@ -3,11 +3,10 @@ import shutil
import unittest
import docker
-from docker.utils import kwargs_from_env
-
from .. import helpers
+from docker.utils import kwargs_from_env
-BUSYBOX = 'busybox:buildroot-2014.02'
+TEST_IMG = 'alpine:3.10'
TEST_API_VERSION = os.environ.get('DOCKER_TEST_API_VERSION')
@@ -29,41 +28,44 @@ class BaseIntegrationTest(unittest.TestCase):
def tearDown(self):
client = docker.from_env(version=TEST_API_VERSION)
- for img in self.tmp_imgs:
- try:
- client.api.remove_image(img)
- except docker.errors.APIError:
- pass
- for container in self.tmp_containers:
- try:
- client.api.remove_container(container, force=True, v=True)
- except docker.errors.APIError:
- pass
- for network in self.tmp_networks:
- try:
- client.api.remove_network(network)
- except docker.errors.APIError:
- pass
- for volume in self.tmp_volumes:
- try:
- client.api.remove_volume(volume)
- except docker.errors.APIError:
- pass
-
- for secret in self.tmp_secrets:
- try:
- client.api.remove_secret(secret)
- except docker.errors.APIError:
- pass
-
- for config in self.tmp_configs:
- try:
- client.api.remove_config(config)
- except docker.errors.APIError:
- pass
-
- for folder in self.tmp_folders:
- shutil.rmtree(folder)
+ try:
+ for img in self.tmp_imgs:
+ try:
+ client.api.remove_image(img)
+ except docker.errors.APIError:
+ pass
+ for container in self.tmp_containers:
+ try:
+ client.api.remove_container(container, force=True, v=True)
+ except docker.errors.APIError:
+ pass
+ for network in self.tmp_networks:
+ try:
+ client.api.remove_network(network)
+ except docker.errors.APIError:
+ pass
+ for volume in self.tmp_volumes:
+ try:
+ client.api.remove_volume(volume)
+ except docker.errors.APIError:
+ pass
+
+ for secret in self.tmp_secrets:
+ try:
+ client.api.remove_secret(secret)
+ except docker.errors.APIError:
+ pass
+
+ for config in self.tmp_configs:
+ try:
+ client.api.remove_config(config)
+ except docker.errors.APIError:
+ pass
+
+ for folder in self.tmp_folders:
+ shutil.rmtree(folder)
+ finally:
+ client.close()
class BaseAPIIntegrationTest(BaseIntegrationTest):
@@ -106,7 +108,7 @@ class BaseAPIIntegrationTest(BaseIntegrationTest):
return container
- def create_and_start(self, image=BUSYBOX, command='top', **kwargs):
+ def create_and_start(self, image=TEST_IMG, command='top', **kwargs):
container = self.client.create_container(
image=image, command=command, **kwargs)
self.tmp_containers.append(container)
diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py
index 4e8d268..ec48835 100644
--- a/tests/integration/conftest.py
+++ b/tests/integration/conftest.py
@@ -7,7 +7,7 @@ import docker.errors
from docker.utils import kwargs_from_env
import pytest
-from .base import BUSYBOX
+from .base import TEST_IMG
@pytest.fixture(autouse=True, scope='session')
@@ -15,15 +15,15 @@ def setup_test_session():
warnings.simplefilter('error')
c = docker.APIClient(version='auto', **kwargs_from_env())
try:
- c.inspect_image(BUSYBOX)
+ c.inspect_image(TEST_IMG)
except docker.errors.NotFound:
- print("\npulling {0}".format(BUSYBOX), file=sys.stderr)
- for data in c.pull(BUSYBOX, stream=True, decode=True):
+ print("\npulling {0}".format(TEST_IMG), file=sys.stderr)
+ for data in c.pull(TEST_IMG, stream=True, decode=True):
status = data.get("status")
progress = data.get("progress")
detail = "{0} - {1}".format(status, progress)
print(detail, file=sys.stderr)
# Double make sure we now have busybox
- c.inspect_image(BUSYBOX)
+ c.inspect_image(TEST_IMG)
c.close()
diff --git a/tests/integration/credentials/__init__.py b/tests/integration/credentials/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/integration/credentials/__init__.py
diff --git a/tests/integration/credentials/store_test.py b/tests/integration/credentials/store_test.py
new file mode 100644
index 0000000..dd543e2
--- /dev/null
+++ b/tests/integration/credentials/store_test.py
@@ -0,0 +1,87 @@
+import os
+import random
+import sys
+
+import pytest
+import six
+from distutils.spawn import find_executable
+
+from docker.credentials import (
+ CredentialsNotFound, Store, StoreError, DEFAULT_LINUX_STORE,
+ DEFAULT_OSX_STORE
+)
+
+
+class TestStore(object):
+ def teardown_method(self):
+ for server in self.tmp_keys:
+ try:
+ self.store.erase(server)
+ except StoreError:
+ pass
+
+ def setup_method(self):
+ self.tmp_keys = []
+ if sys.platform.startswith('linux'):
+ if find_executable('docker-credential-' + DEFAULT_LINUX_STORE):
+ self.store = Store(DEFAULT_LINUX_STORE)
+ elif find_executable('docker-credential-pass'):
+ self.store = Store('pass')
+ else:
+ raise Exception('No supported docker-credential store in PATH')
+ elif sys.platform.startswith('darwin'):
+ self.store = Store(DEFAULT_OSX_STORE)
+
+ def get_random_servername(self):
+ res = 'pycreds_test_{:x}'.format(random.getrandbits(32))
+ self.tmp_keys.append(res)
+ return res
+
+ def test_store_and_get(self):
+ key = self.get_random_servername()
+ self.store.store(server=key, username='user', secret='pass')
+ data = self.store.get(key)
+ assert data == {
+ 'ServerURL': key,
+ 'Username': 'user',
+ 'Secret': 'pass'
+ }
+
+ def test_get_nonexistent(self):
+ key = self.get_random_servername()
+ with pytest.raises(CredentialsNotFound):
+ self.store.get(key)
+
+ def test_store_and_erase(self):
+ key = self.get_random_servername()
+ self.store.store(server=key, username='user', secret='pass')
+ self.store.erase(key)
+ with pytest.raises(CredentialsNotFound):
+ self.store.get(key)
+
+ def test_unicode_strings(self):
+ key = self.get_random_servername()
+ key = six.u(key)
+ self.store.store(server=key, username='user', secret='pass')
+ data = self.store.get(key)
+ assert data
+ self.store.erase(key)
+ with pytest.raises(CredentialsNotFound):
+ self.store.get(key)
+
+ def test_list(self):
+ names = (self.get_random_servername(), self.get_random_servername())
+ self.store.store(names[0], username='sakuya', secret='izayoi')
+ self.store.store(names[1], username='reimu', secret='hakurei')
+ data = self.store.list()
+ assert names[0] in data
+ assert data[names[0]] == 'sakuya'
+ assert names[1] in data
+ assert data[names[1]] == 'reimu'
+
+ def test_execute_with_env_override(self):
+ self.store.exe = 'env'
+ self.store.environment = {'FOO': 'bar'}
+ data = self.store._execute('--null', '')
+ assert b'\0FOO=bar\0' in data
+ assert 'FOO' not in os.environ
diff --git a/tests/integration/credentials/utils_test.py b/tests/integration/credentials/utils_test.py
new file mode 100644
index 0000000..ad55f32
--- /dev/null
+++ b/tests/integration/credentials/utils_test.py
@@ -0,0 +1,22 @@
+import os
+
+from docker.credentials.utils import create_environment_dict
+
+try:
+ from unittest import mock
+except ImportError:
+ import mock
+
+
+@mock.patch.dict(os.environ)
+def test_create_environment_dict():
+ base = {'FOO': 'bar', 'BAZ': 'foobar'}
+ os.environ = base
+ assert create_environment_dict({'FOO': 'baz'}) == {
+ 'FOO': 'baz', 'BAZ': 'foobar',
+ }
+ assert create_environment_dict({'HELLO': 'world'}) == {
+ 'FOO': 'bar', 'BAZ': 'foobar', 'HELLO': 'world',
+ }
+
+ assert os.environ == base
diff --git a/tests/integration/errors_test.py b/tests/integration/errors_test.py
index ac74d72..7bf156a 100644
--- a/tests/integration/errors_test.py
+++ b/tests/integration/errors_test.py
@@ -1,11 +1,11 @@
from docker.errors import APIError
-from .base import BaseAPIIntegrationTest, BUSYBOX
+from .base import BaseAPIIntegrationTest, TEST_IMG
import pytest
class ErrorsTest(BaseAPIIntegrationTest):
def test_api_error_parses_json(self):
- container = self.client.create_container(BUSYBOX, ['sleep', '10'])
+ container = self.client.create_container(TEST_IMG, ['sleep', '10'])
self.client.start(container['Id'])
with pytest.raises(APIError) as cm:
self.client.remove_container(container['Id'])
diff --git a/tests/integration/models_containers_test.py b/tests/integration/models_containers_test.py
index ab41ea5..eac4c97 100644
--- a/tests/integration/models_containers_test.py
+++ b/tests/integration/models_containers_test.py
@@ -1,10 +1,14 @@
+import os
import tempfile
import threading
-import docker
import pytest
-from .base import BaseIntegrationTest, TEST_API_VERSION
-from ..helpers import random_name, requires_api_version
+
+import docker
+from ..helpers import random_name
+from ..helpers import requires_api_version
+from .base import BaseIntegrationTest
+from .base import TEST_API_VERSION
class ContainerCollectionTest(BaseIntegrationTest):
@@ -122,7 +126,9 @@ class ContainerCollectionTest(BaseIntegrationTest):
def test_run_with_auto_remove(self):
client = docker.from_env(version=TEST_API_VERSION)
out = client.containers.run(
- 'alpine', 'echo hello', auto_remove=True
+ # sleep(2) to allow any communication with the container
+ # before it gets removed by the host.
+ 'alpine', 'sh -c "echo hello && sleep 2"', auto_remove=True
)
assert out == b'hello\n'
@@ -131,7 +137,10 @@ class ContainerCollectionTest(BaseIntegrationTest):
client = docker.from_env(version=TEST_API_VERSION)
with pytest.raises(docker.errors.ContainerError) as e:
client.containers.run(
- 'alpine', 'sh -c ">&2 echo error && exit 1"', auto_remove=True
+ # sleep(2) to allow any communication with the container
+ # before it gets removed by the host.
+ 'alpine', 'sh -c ">&2 echo error && sleep 2 && exit 1"',
+ auto_remove=True
)
assert e.value.exit_status == 1
assert e.value.stderr is None
@@ -146,6 +155,8 @@ class ContainerCollectionTest(BaseIntegrationTest):
assert logs[1] == b'world\n'
@pytest.mark.timeout(5)
+ @pytest.mark.skipif(os.environ.get('DOCKER_HOST', '').startswith('ssh://'),
+ reason='No cancellable streams over SSH')
def test_run_with_streamed_logs_and_cancel(self):
client = docker.from_env(version=TEST_API_VERSION)
out = client.containers.run(
@@ -160,6 +171,17 @@ class ContainerCollectionTest(BaseIntegrationTest):
assert logs[0] == b'hello\n'
assert logs[1] == b'world\n'
+ def test_run_with_proxy_config(self):
+ client = docker.from_env(version=TEST_API_VERSION)
+ client.api._proxy_configs = docker.utils.proxy.ProxyConfig(
+ ftp='sakuya.jp:4967'
+ )
+
+ out = client.containers.run('alpine', 'sh -c "env"')
+
+ assert b'FTP_PROXY=sakuya.jp:4967\n' in out
+ assert b'ftp_proxy=sakuya.jp:4967\n' in out
+
def test_get(self):
client = docker.from_env(version=TEST_API_VERSION)
container = client.containers.run("alpine", "sleep 300", detach=True)
@@ -325,6 +347,66 @@ class ContainerTest(BaseIntegrationTest):
'memory_stats', 'blkio_stats']:
assert key in stats
+ def test_ports_target_none(self):
+ client = docker.from_env(version=TEST_API_VERSION)
+ ports = None
+ target_ports = {'2222/tcp': ports}
+ container = client.containers.run(
+ "alpine", "sleep 100", detach=True,
+ ports=target_ports
+ )
+ self.tmp_containers.append(container.id)
+ container.reload() # required to get auto-assigned ports
+ actual_ports = container.ports
+ assert sorted(target_ports.keys()) == sorted(actual_ports.keys())
+ for target_client, target_host in target_ports.items():
+ for actual_port in actual_ports[target_client]:
+ actual_keys = sorted(actual_port.keys())
+ assert sorted(['HostIp', 'HostPort']) == actual_keys
+ assert target_host is ports
+ assert int(actual_port['HostPort']) > 0
+ client.close()
+
+ def test_ports_target_tuple(self):
+ client = docker.from_env(version=TEST_API_VERSION)
+ ports = ('127.0.0.1', 1111)
+ target_ports = {'2222/tcp': ports}
+ container = client.containers.run(
+ "alpine", "sleep 100", detach=True,
+ ports=target_ports
+ )
+ self.tmp_containers.append(container.id)
+ container.reload() # required to get auto-assigned ports
+ actual_ports = container.ports
+ assert sorted(target_ports.keys()) == sorted(actual_ports.keys())
+ for target_client, target_host in target_ports.items():
+ for actual_port in actual_ports[target_client]:
+ actual_keys = sorted(actual_port.keys())
+ assert sorted(['HostIp', 'HostPort']) == actual_keys
+ assert target_host == ports
+ assert int(actual_port['HostPort']) > 0
+ client.close()
+
+ def test_ports_target_list(self):
+ client = docker.from_env(version=TEST_API_VERSION)
+ ports = [1234, 4567]
+ target_ports = {'2222/tcp': ports}
+ container = client.containers.run(
+ "alpine", "sleep 100", detach=True,
+ ports=target_ports
+ )
+ self.tmp_containers.append(container.id)
+ container.reload() # required to get auto-assigned ports
+ actual_ports = container.ports
+ assert sorted(target_ports.keys()) == sorted(actual_ports.keys())
+ for target_client, target_host in target_ports.items():
+ for actual_port in actual_ports[target_client]:
+ actual_keys = sorted(actual_port.keys())
+ assert sorted(['HostIp', 'HostPort']) == actual_keys
+ assert target_host == ports
+ assert int(actual_port['HostPort']) > 0
+ client.close()
+
def test_stop(self):
client = docker.from_env(version=TEST_API_VERSION)
container = client.containers.run("alpine", "top", detach=True)
@@ -362,3 +444,13 @@ class ContainerTest(BaseIntegrationTest):
detach=True)
self.tmp_containers.append(container.id)
assert container.wait()['StatusCode'] == 1
+
+ def test_create_with_volume_driver(self):
+ client = docker.from_env(version=TEST_API_VERSION)
+ container = client.containers.create(
+ 'alpine',
+ 'sleep 300',
+ volume_driver='foo'
+ )
+ self.tmp_containers.append(container.id)
+ assert container.attrs['HostConfig']['VolumeDriver'] == 'foo'
diff --git a/tests/integration/models_images_test.py b/tests/integration/models_images_test.py
index ae735ba..375d972 100644
--- a/tests/integration/models_images_test.py
+++ b/tests/integration/models_images_test.py
@@ -4,7 +4,8 @@ import tempfile
import docker
import pytest
-from .base import BaseIntegrationTest, BUSYBOX, TEST_API_VERSION
+from .base import BaseIntegrationTest, TEST_IMG, TEST_API_VERSION
+from ..helpers import random_name
class ImageCollectionTest(BaseIntegrationTest):
@@ -71,8 +72,8 @@ class ImageCollectionTest(BaseIntegrationTest):
def test_pull_with_tag(self):
client = docker.from_env(version=TEST_API_VERSION)
- image = client.images.pull('alpine', tag='3.3')
- assert 'alpine:3.3' in image.attrs['RepoTags']
+ image = client.images.pull('alpine', tag='3.10')
+ assert 'alpine:3.10' in image.attrs['RepoTags']
def test_pull_with_sha(self):
image_ref = (
@@ -96,7 +97,7 @@ class ImageCollectionTest(BaseIntegrationTest):
def test_save_and_load(self):
client = docker.from_env(version=TEST_API_VERSION)
- image = client.images.get(BUSYBOX)
+ image = client.images.get(TEST_IMG)
with tempfile.TemporaryFile() as f:
stream = image.save()
for chunk in stream:
@@ -108,6 +109,32 @@ class ImageCollectionTest(BaseIntegrationTest):
assert len(result) == 1
assert result[0].id == image.id
+ def test_save_and_load_repo_name(self):
+ client = docker.from_env(version=TEST_API_VERSION)
+ image = client.images.get(TEST_IMG)
+ additional_tag = random_name()
+ image.tag(additional_tag)
+ self.tmp_imgs.append(additional_tag)
+ image.reload()
+ with tempfile.TemporaryFile() as f:
+ stream = image.save(named='{}:latest'.format(additional_tag))
+ for chunk in stream:
+ f.write(chunk)
+
+ f.seek(0)
+ client.images.remove(additional_tag, force=True)
+ result = client.images.load(f.read())
+
+ assert len(result) == 1
+ assert result[0].id == image.id
+ assert '{}:latest'.format(additional_tag) in result[0].tags
+
+ def test_save_name_error(self):
+ client = docker.from_env(version=TEST_API_VERSION)
+ image = client.images.get(TEST_IMG)
+ with pytest.raises(docker.errors.InvalidArgument):
+ image.save(named='sakuya/izayoi')
+
class ImageTest(BaseIntegrationTest):
diff --git a/tests/integration/models_swarm_test.py b/tests/integration/models_swarm_test.py
index f39f0d3..6c1836d 100644
--- a/tests/integration/models_swarm_test.py
+++ b/tests/integration/models_swarm_test.py
@@ -31,3 +31,15 @@ class SwarmTest(unittest.TestCase):
cm.value.response.status_code == 406 or
cm.value.response.status_code == 503
)
+
+ def test_join_on_already_joined_swarm(self):
+ client = docker.from_env(version=TEST_API_VERSION)
+ client.swarm.init()
+ join_token = client.swarm.attrs['JoinTokens']['Manager']
+ with pytest.raises(docker.errors.APIError) as cm:
+ client.swarm.join(
+ remote_addrs=['127.0.0.1'],
+ join_token=join_token,
+ )
+ assert cm.value.response.status_code == 503
+ assert 'This node is already part of a swarm.' in cm.value.explanation
diff --git a/tests/integration/regression_test.py b/tests/integration/regression_test.py
index 0fd4e43..a63883c 100644
--- a/tests/integration/regression_test.py
+++ b/tests/integration/regression_test.py
@@ -4,7 +4,7 @@ import random
import docker
import six
-from .base import BaseAPIIntegrationTest, BUSYBOX
+from .base import BaseAPIIntegrationTest, TEST_IMG
import pytest
@@ -14,12 +14,12 @@ class TestRegressions(BaseAPIIntegrationTest):
with pytest.raises(docker.errors.APIError) as exc:
for line in self.client.build(fileobj=dfile, tag="a/b/c"):
pass
- assert exc.value.response.status_code == 500
+ assert exc.value.is_error()
dfile.close()
def test_542_truncate_ids_client_side(self):
self.client.start(
- self.client.create_container(BUSYBOX, ['true'])
+ self.client.create_container(TEST_IMG, ['true'])
)
result = self.client.containers(all=True, trunc=True)
assert len(result[0]['Id']) == 12
@@ -30,12 +30,12 @@ class TestRegressions(BaseAPIIntegrationTest):
def test_649_handle_timeout_value_none(self):
self.client.timeout = None
- ctnr = self.client.create_container(BUSYBOX, ['sleep', '2'])
+ ctnr = self.client.create_container(TEST_IMG, ['sleep', '2'])
self.client.start(ctnr)
self.client.stop(ctnr)
def test_715_handle_user_param_as_int_value(self):
- ctnr = self.client.create_container(BUSYBOX, ['id', '-u'], user=1000)
+ ctnr = self.client.create_container(TEST_IMG, ['id', '-u'], user=1000)
self.client.start(ctnr)
self.client.wait(ctnr)
logs = self.client.logs(ctnr)
@@ -47,7 +47,7 @@ class TestRegressions(BaseAPIIntegrationTest):
tcp_port, udp_port = random.sample(range(9999, 32000), 2)
ctnr = self.client.create_container(
- BUSYBOX, ['sleep', '9999'], ports=[2000, (2000, 'udp')],
+ TEST_IMG, ['sleep', '9999'], ports=[2000, (2000, 'udp')],
host_config=self.client.create_host_config(
port_bindings={'2000/tcp': tcp_port, '2000/udp': udp_port}
)