summaryrefslogtreecommitdiff
path: root/tests/integration
diff options
context:
space:
mode:
Diffstat (limited to 'tests/integration')
-rw-r--r--tests/integration/api_build_test.py29
-rw-r--r--tests/integration/api_client_test.py2
-rw-r--r--tests/integration/api_config_test.py17
-rw-r--r--tests/integration/api_container_test.py136
-rw-r--r--tests/integration/api_exec_test.py2
-rw-r--r--tests/integration/api_image_test.py23
-rw-r--r--tests/integration/api_network_test.py23
-rw-r--r--tests/integration/api_plugin_test.py4
-rw-r--r--tests/integration/api_secret_test.py4
-rw-r--r--tests/integration/api_service_test.py131
-rw-r--r--tests/integration/api_swarm_test.py4
-rw-r--r--tests/integration/base.py4
-rw-r--r--tests/integration/conftest.py6
-rw-r--r--tests/integration/context_api_test.py59
-rw-r--r--tests/integration/credentials/store_test.py13
-rw-r--r--tests/integration/credentials/utils_test.py6
-rw-r--r--tests/integration/models_images_test.py30
-rw-r--r--tests/integration/models_services_test.py45
-rw-r--r--tests/integration/regression_test.py11
19 files changed, 384 insertions, 165 deletions
diff --git a/tests/integration/api_build_test.py b/tests/integration/api_build_test.py
index 5712812..606c3b7 100644
--- a/tests/integration/api_build_test.py
+++ b/tests/integration/api_build_test.py
@@ -7,7 +7,6 @@ from docker import errors
from docker.utils.proxy import ProxyConfig
import pytest
-import six
from .base import BaseAPIIntegrationTest, TEST_IMG
from ..helpers import random_name, requires_api_version, requires_experimental
@@ -71,9 +70,8 @@ class BuildTest(BaseAPIIntegrationTest):
assert len(logs) > 0
def test_build_from_stringio(self):
- if six.PY3:
- return
- script = io.StringIO(six.text_type('\n').join([
+ return
+ script = io.StringIO('\n'.join([
'FROM busybox',
'RUN mkdir -p /tmp/test',
'EXPOSE 8080',
@@ -83,8 +81,7 @@ class BuildTest(BaseAPIIntegrationTest):
stream = self.client.build(fileobj=script)
logs = ''
for chunk in stream:
- if six.PY3:
- chunk = chunk.decode('utf-8')
+ chunk = chunk.decode('utf-8')
logs += chunk
assert logs != ''
@@ -103,7 +100,9 @@ class BuildTest(BaseAPIIntegrationTest):
'ignored',
'Dockerfile',
'.dockerignore',
+ ' ignored-with-spaces ', # check that spaces are trimmed
'!ignored/subdir/excepted-file',
+ '! ignored/subdir/excepted-with-spaces '
'', # empty line,
'#*', # comment line
]))
@@ -114,6 +113,9 @@ class BuildTest(BaseAPIIntegrationTest):
with open(os.path.join(base_dir, '#file.txt'), 'w') as f:
f.write('this file should not be ignored')
+ with open(os.path.join(base_dir, 'ignored-with-spaces'), 'w') as f:
+ f.write("this file should be ignored")
+
subdir = os.path.join(base_dir, 'ignored', 'subdir')
os.makedirs(subdir)
with open(os.path.join(subdir, 'file'), 'w') as f:
@@ -122,6 +124,9 @@ class BuildTest(BaseAPIIntegrationTest):
with open(os.path.join(subdir, 'excepted-file'), 'w') as f:
f.write("this file should not be ignored")
+ with open(os.path.join(subdir, 'excepted-with-spaces'), 'w') as f:
+ f.write("this file should not be ignored")
+
tag = 'docker-py-test-build-with-dockerignore'
stream = self.client.build(
path=base_dir,
@@ -135,11 +140,11 @@ class BuildTest(BaseAPIIntegrationTest):
self.client.wait(c)
logs = self.client.logs(c)
- if six.PY3:
- logs = logs.decode('utf-8')
+ logs = logs.decode('utf-8')
assert sorted(list(filter(None, logs.split('\n')))) == sorted([
'/test/#file.txt',
+ '/test/ignored/subdir/excepted-with-spaces',
'/test/ignored/subdir/excepted-file',
'/test/not-ignored'
])
@@ -339,10 +344,8 @@ class BuildTest(BaseAPIIntegrationTest):
assert self.client.inspect_image(img_name)
ctnr = self.run_container(img_name, 'cat /hosts-file')
- self.tmp_containers.append(ctnr)
logs = self.client.logs(ctnr)
- if six.PY3:
- logs = logs.decode('utf-8')
+ logs = logs.decode('utf-8')
assert '127.0.0.1\textrahost.local.test' in logs
assert '127.0.0.1\thello.world.test' in logs
@@ -377,7 +380,7 @@ class BuildTest(BaseAPIIntegrationTest):
snippet = 'Ancient Temple (Mystic Oriental Dream ~ Ancient Temple)'
script = io.BytesIO(b'\n'.join([
b'FROM busybox',
- 'RUN sh -c ">&2 echo \'{0}\'"'.format(snippet).encode('utf-8')
+ f'RUN sh -c ">&2 echo \'{snippet}\'"'.encode('utf-8')
]))
stream = self.client.build(
@@ -441,7 +444,7 @@ class BuildTest(BaseAPIIntegrationTest):
@requires_api_version('1.32')
@requires_experimental(until=None)
def test_build_invalid_platform(self):
- script = io.BytesIO('FROM busybox\n'.encode('ascii'))
+ script = io.BytesIO(b'FROM busybox\n')
with pytest.raises(errors.APIError) as excinfo:
stream = self.client.build(fileobj=script, platform='foobar')
diff --git a/tests/integration/api_client_test.py b/tests/integration/api_client_test.py
index 9e348f3..d1622fa 100644
--- a/tests/integration/api_client_test.py
+++ b/tests/integration/api_client_test.py
@@ -72,6 +72,6 @@ class UnixconnTest(unittest.TestCase):
client.close()
del client
- assert len(w) == 0, "No warnings produced: {0}".format(
+ assert len(w) == 0, "No warnings produced: {}".format(
w[0].message
)
diff --git a/tests/integration/api_config_test.py b/tests/integration/api_config_test.py
index 0ffd767..982ec46 100644
--- a/tests/integration/api_config_test.py
+++ b/tests/integration/api_config_test.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import docker
import pytest
@@ -31,7 +29,7 @@ class ConfigAPITest(BaseAPIIntegrationTest):
def test_create_config_unicode_data(self):
config_id = self.client.create_config(
- 'favorite_character', u'いざよいさくや'
+ 'favorite_character', 'いざよいさくや'
)
self.tmp_configs.append(config_id)
assert 'ID' in config_id
@@ -70,3 +68,16 @@ class ConfigAPITest(BaseAPIIntegrationTest):
data = self.client.configs(filters={'name': ['favorite_character']})
assert len(data) == 1
assert data[0]['ID'] == config_id['ID']
+
+ @requires_api_version('1.37')
+ def test_create_config_with_templating(self):
+ config_id = self.client.create_config(
+ 'favorite_character', 'sakuya izayoi',
+ templating={'name': 'golang'}
+ )
+ self.tmp_configs.append(config_id)
+ assert 'ID' in config_id
+ data = self.client.inspect_config(config_id)
+ assert data['Spec']['Name'] == 'favorite_character'
+ assert 'Templating' in data['Spec']
+ assert data['Spec']['Templating']['Name'] == 'golang'
diff --git a/tests/integration/api_container_test.py b/tests/integration/api_container_test.py
index 1ba3eaa..8f69e41 100644
--- a/tests/integration/api_container_test.py
+++ b/tests/integration/api_container_test.py
@@ -7,7 +7,6 @@ from datetime import datetime
import pytest
import requests
-import six
import docker
from .. import helpers
@@ -35,7 +34,7 @@ class ListContainersTest(BaseAPIIntegrationTest):
assert len(retrieved) == 1
retrieved = retrieved[0]
assert 'Command' in retrieved
- assert retrieved['Command'] == six.text_type('true')
+ assert retrieved['Command'] == 'true'
assert 'Image' in retrieved
assert re.search(r'alpine:.*', retrieved['Image'])
assert 'Status' in retrieved
@@ -104,13 +103,11 @@ class CreateContainerTest(BaseAPIIntegrationTest):
self.client.start(container3_id)
assert self.client.wait(container3_id)['StatusCode'] == 0
- logs = self.client.logs(container3_id)
- if six.PY3:
- logs = logs.decode('utf-8')
- assert '{0}_NAME='.format(link_env_prefix1) in logs
- assert '{0}_ENV_FOO=1'.format(link_env_prefix1) in logs
- assert '{0}_NAME='.format(link_env_prefix2) in logs
- assert '{0}_ENV_FOO=1'.format(link_env_prefix2) in logs
+ logs = self.client.logs(container3_id).decode('utf-8')
+ assert f'{link_env_prefix1}_NAME=' in logs
+ assert f'{link_env_prefix1}_ENV_FOO=1' in logs
+ assert f'{link_env_prefix2}_NAME=' in logs
+ assert f'{link_env_prefix2}_ENV_FOO=1' in logs
def test_create_with_restart_policy(self):
container = self.client.create_container(
@@ -227,9 +224,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
self.client.start(container)
self.client.wait(container)
- logs = self.client.logs(container)
- if six.PY3:
- logs = logs.decode('utf-8')
+ logs = self.client.logs(container).decode('utf-8')
groups = logs.strip().split(' ')
assert '1000' in groups
assert '1001' in groups
@@ -244,9 +239,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
self.client.start(container)
self.client.wait(container)
- logs = self.client.logs(container)
- if six.PY3:
- logs = logs.decode('utf-8')
+ logs = self.client.logs(container).decode('utf-8')
groups = logs.strip().split(' ')
assert '1000' in groups
@@ -273,11 +266,14 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_invalid_log_driver_raises_exception(self):
log_config = docker.types.LogConfig(
- type='asdf-nope',
+ type='asdf',
config={}
)
- expected_msg = "logger: no log driver named 'asdf-nope' is registered"
+ expected_msgs = [
+ "logger: no log driver named 'asdf' is registered",
+ "error looking up logging plugin asdf: plugin \"asdf\" not found",
+ ]
with pytest.raises(docker.errors.APIError) as excinfo:
# raises an internal server error 500
container = self.client.create_container(
@@ -287,7 +283,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
)
self.client.start(container)
- assert excinfo.value.explanation == expected_msg
+ assert excinfo.value.explanation in expected_msgs
def test_valid_no_log_driver_specified(self):
log_config = docker.types.LogConfig(
@@ -464,16 +460,13 @@ class CreateContainerTest(BaseAPIIntegrationTest):
def test_create_with_device_cgroup_rules(self):
rule = 'c 7:128 rwm'
ctnr = self.client.create_container(
- TEST_IMG, 'cat /sys/fs/cgroup/devices/devices.list',
- host_config=self.client.create_host_config(
+ TEST_IMG, 'true', host_config=self.client.create_host_config(
device_cgroup_rules=[rule]
)
)
self.tmp_containers.append(ctnr)
config = self.client.inspect_container(ctnr)
assert config['HostConfig']['DeviceCgroupRules'] == [rule]
- 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(
@@ -491,7 +484,7 @@ class CreateContainerTest(BaseAPIIntegrationTest):
)
class VolumeBindTest(BaseAPIIntegrationTest):
def setUp(self):
- super(VolumeBindTest, self).setUp()
+ super().setUp()
self.mount_dest = '/mnt'
@@ -512,10 +505,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
TEST_IMG,
['ls', self.mount_dest],
)
- logs = self.client.logs(container)
-
- if six.PY3:
- logs = logs.decode('utf-8')
+ logs = self.client.logs(container).decode('utf-8')
assert self.filename in logs
inspect_data = self.client.inspect_container(container)
self.check_container_data(inspect_data, True)
@@ -531,10 +521,8 @@ class VolumeBindTest(BaseAPIIntegrationTest):
TEST_IMG,
['ls', self.mount_dest],
)
- logs = self.client.logs(container)
+ logs = self.client.logs(container).decode('utf-8')
- if six.PY3:
- logs = logs.decode('utf-8')
assert self.filename in logs
inspect_data = self.client.inspect_container(container)
@@ -551,9 +539,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
host_config=host_config
)
assert container
- logs = self.client.logs(container)
- if six.PY3:
- logs = logs.decode('utf-8')
+ logs = self.client.logs(container).decode('utf-8')
assert self.filename in logs
inspect_data = self.client.inspect_container(container)
self.check_container_data(inspect_data, True)
@@ -570,9 +556,7 @@ class VolumeBindTest(BaseAPIIntegrationTest):
host_config=host_config
)
assert container
- logs = self.client.logs(container)
- if six.PY3:
- logs = logs.decode('utf-8')
+ logs = self.client.logs(container).decode('utf-8')
assert self.filename in logs
inspect_data = self.client.inspect_container(container)
self.check_container_data(inspect_data, False)
@@ -631,7 +615,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(
- TEST_IMG, 'sh -c "echo {0} > /vol1/data.txt"'.format(data),
+ TEST_IMG, f'sh -c "echo {data} > /vol1/data.txt"',
volumes=['/vol1']
)
self.tmp_containers.append(ctnr)
@@ -642,15 +626,14 @@ class ArchiveTest(BaseAPIIntegrationTest):
for d in strm:
destination.write(d)
destination.seek(0)
- retrieved_data = helpers.untar_file(destination, 'data.txt')
- if six.PY3:
- retrieved_data = retrieved_data.decode('utf-8')
+ retrieved_data = helpers.untar_file(destination, 'data.txt')\
+ .decode('utf-8')
assert data == retrieved_data.strip()
def test_get_file_stat_from_container(self):
data = 'The Maid and the Pocket Watch of Blood'
ctnr = self.client.create_container(
- TEST_IMG, 'sh -c "echo -n {0} > /vol1/data.txt"'.format(data),
+ TEST_IMG, f'sh -c "echo -n {data} > /vol1/data.txt"',
volumes=['/vol1']
)
self.tmp_containers.append(ctnr)
@@ -669,7 +652,7 @@ class ArchiveTest(BaseAPIIntegrationTest):
test_file.seek(0)
ctnr = self.client.create_container(
TEST_IMG,
- 'cat {0}'.format(
+ 'cat {}'.format(
os.path.join('/vol1/', os.path.basename(test_file.name))
),
volumes=['/vol1']
@@ -680,9 +663,6 @@ class ArchiveTest(BaseAPIIntegrationTest):
self.client.start(ctnr)
self.client.wait(ctnr)
logs = self.client.logs(ctnr)
- if six.PY3:
- logs = logs.decode('utf-8')
- data = data.decode('utf-8')
assert logs.strip() == data
def test_copy_directory_to_container(self):
@@ -697,9 +677,7 @@ class ArchiveTest(BaseAPIIntegrationTest):
self.client.put_archive(ctnr, '/vol1', test_tar)
self.client.start(ctnr)
self.client.wait(ctnr)
- logs = self.client.logs(ctnr)
- if six.PY3:
- logs = logs.decode('utf-8')
+ logs = self.client.logs(ctnr).decode('utf-8')
results = logs.strip().split()
assert 'a.py' in results
assert 'b.py' in results
@@ -720,7 +698,7 @@ class RenameContainerTest(BaseAPIIntegrationTest):
if version == '1.5.0':
assert name == inspect['Name']
else:
- assert '/{0}'.format(name) == inspect['Name']
+ assert f'/{name}' == inspect['Name']
class StartContainerTest(BaseAPIIntegrationTest):
@@ -826,7 +804,7 @@ class LogsTest(BaseAPIIntegrationTest):
def test_logs(self):
snippet = 'Flowering Nights (Sakuya Iyazoi)'
container = self.client.create_container(
- TEST_IMG, 'echo {0}'.format(snippet)
+ TEST_IMG, f'echo {snippet}'
)
id = container['Id']
self.tmp_containers.append(id)
@@ -840,7 +818,7 @@ class LogsTest(BaseAPIIntegrationTest):
snippet = '''Line1
Line2'''
container = self.client.create_container(
- TEST_IMG, 'echo "{0}"'.format(snippet)
+ TEST_IMG, f'echo "{snippet}"'
)
id = container['Id']
self.tmp_containers.append(id)
@@ -853,12 +831,12 @@ Line2'''
def test_logs_streaming_and_follow(self):
snippet = 'Flowering Nights (Sakuya Iyazoi)'
container = self.client.create_container(
- TEST_IMG, 'echo {0}'.format(snippet)
+ TEST_IMG, f'echo {snippet}'
)
id = container['Id']
self.tmp_containers.append(id)
self.client.start(id)
- logs = six.binary_type()
+ logs = b''
for chunk in self.client.logs(id, stream=True, follow=True):
logs += chunk
@@ -873,12 +851,12 @@ Line2'''
def test_logs_streaming_and_follow_and_cancel(self):
snippet = 'Flowering Nights (Sakuya Iyazoi)'
container = self.client.create_container(
- TEST_IMG, 'sh -c "echo \\"{0}\\" && sleep 3"'.format(snippet)
+ TEST_IMG, f'sh -c "echo \\"{snippet}\\" && sleep 3"'
)
id = container['Id']
self.tmp_containers.append(id)
self.client.start(id)
- logs = six.binary_type()
+ logs = b''
generator = self.client.logs(id, stream=True, follow=True)
threading.Timer(1, generator.close).start()
@@ -891,7 +869,7 @@ Line2'''
def test_logs_with_dict_instead_of_id(self):
snippet = 'Flowering Nights (Sakuya Iyazoi)'
container = self.client.create_container(
- TEST_IMG, 'echo {0}'.format(snippet)
+ TEST_IMG, f'echo {snippet}'
)
id = container['Id']
self.tmp_containers.append(id)
@@ -904,7 +882,7 @@ Line2'''
def test_logs_with_tail_0(self):
snippet = 'Flowering Nights (Sakuya Iyazoi)'
container = self.client.create_container(
- TEST_IMG, 'echo "{0}"'.format(snippet)
+ TEST_IMG, f'echo "{snippet}"'
)
id = container['Id']
self.tmp_containers.append(id)
@@ -918,7 +896,7 @@ Line2'''
def test_logs_with_until(self):
snippet = 'Shanghai Teahouse (Hong Meiling)'
container = self.client.create_container(
- TEST_IMG, 'echo "{0}"'.format(snippet)
+ TEST_IMG, f'echo "{snippet}"'
)
self.tmp_containers.append(container)
@@ -1102,6 +1080,8 @@ class PortTest(BaseAPIIntegrationTest):
class ContainerTopTest(BaseAPIIntegrationTest):
+ @pytest.mark.xfail(reason='Output of docker top depends on host distro, '
+ 'and is not formalized.')
def test_top(self):
container = self.client.create_container(
TEST_IMG, ['sleep', '60']
@@ -1112,9 +1092,7 @@ class ContainerTopTest(BaseAPIIntegrationTest):
self.client.start(container)
res = self.client.top(container)
if not IS_WINDOWS_PLATFORM:
- assert res['Titles'] == [
- 'UID', 'PID', 'PPID', 'C', 'STIME', 'TTY', 'TIME', 'CMD'
- ]
+ assert res['Titles'] == ['PID', 'USER', 'TIME', 'COMMAND']
assert len(res['Processes']) == 1
assert res['Processes'][0][-1] == 'sleep 60'
self.client.kill(container)
@@ -1122,6 +1100,8 @@ class ContainerTopTest(BaseAPIIntegrationTest):
@pytest.mark.skipif(
IS_WINDOWS_PLATFORM, reason='No psargs support on windows'
)
+ @pytest.mark.xfail(reason='Output of docker top depends on host distro, '
+ 'and is not formalized.')
def test_top_with_psargs(self):
container = self.client.create_container(
TEST_IMG, ['sleep', '60'])
@@ -1129,11 +1109,8 @@ class ContainerTopTest(BaseAPIIntegrationTest):
self.tmp_containers.append(container)
self.client.start(container)
- res = self.client.top(container, 'waux')
- assert res['Titles'] == [
- 'USER', 'PID', '%CPU', '%MEM', 'VSZ', 'RSS',
- 'TTY', 'STAT', 'START', 'TIME', 'COMMAND'
- ]
+ res = self.client.top(container, '-eopid,user')
+ assert res['Titles'] == ['PID', 'USER']
assert len(res['Processes']) == 1
assert res['Processes'][0][10] == 'sleep 60'
@@ -1220,10 +1197,10 @@ class AttachContainerTest(BaseAPIIntegrationTest):
sock = self.client.attach_socket(container, ws=False)
assert sock.fileno() > -1
- def test_run_container_reading_socket(self):
+ def test_run_container_reading_socket_http(self):
line = 'hi there and stuff and things, words!'
# `echo` appends CRLF, `printf` doesn't
- command = "printf '{0}'".format(line)
+ command = f"printf '{line}'"
container = self.client.create_container(TEST_IMG, command,
detach=True, tty=False)
self.tmp_containers.append(container)
@@ -1240,12 +1217,33 @@ class AttachContainerTest(BaseAPIIntegrationTest):
data = read_exactly(pty_stdout, next_size)
assert data.decode('utf-8') == line
+ @pytest.mark.xfail(condition=bool(os.environ.get('DOCKER_CERT_PATH', '')),
+ reason='DOCKER_CERT_PATH not respected for websockets')
+ def test_run_container_reading_socket_ws(self):
+ line = 'hi there and stuff and things, words!'
+ # `echo` appends CRLF, `printf` doesn't
+ command = f"printf '{line}'"
+ container = self.client.create_container(TEST_IMG, command,
+ detach=True, tty=False)
+ self.tmp_containers.append(container)
+
+ opts = {"stdout": 1, "stream": 1, "logs": 1}
+ pty_stdout = self.client.attach_socket(container, opts, ws=True)
+ self.addCleanup(pty_stdout.close)
+
+ self.client.start(container)
+
+ data = pty_stdout.recv()
+ assert data.decode('utf-8') == line
+
+ @pytest.mark.timeout(10)
def test_attach_no_stream(self):
container = self.client.create_container(
TEST_IMG, 'echo hello'
)
self.tmp_containers.append(container)
self.client.start(container)
+ self.client.wait(container, condition='not-running')
output = self.client.attach(container, stream=False, logs=True)
assert output == 'hello\n'.encode(encoding='ascii')
@@ -1507,7 +1505,7 @@ class LinkTest(BaseAPIIntegrationTest):
# Remove link
linked_name = self.client.inspect_container(container2_id)['Name'][1:]
- link_name = '%s/%s' % (linked_name, link_alias)
+ link_name = f'{linked_name}/{link_alias}'
self.client.remove_container(link_name, link=True)
# Link is gone
diff --git a/tests/integration/api_exec_test.py b/tests/integration/api_exec_test.py
index 554e862..4d7748f 100644
--- a/tests/integration/api_exec_test.py
+++ b/tests/integration/api_exec_test.py
@@ -239,7 +239,7 @@ class ExecDemuxTest(BaseAPIIntegrationTest):
)
def setUp(self):
- super(ExecDemuxTest, self).setUp()
+ super().setUp()
self.container = self.client.create_container(
TEST_IMG, 'cat', detach=True, stdin_open=True
)
diff --git a/tests/integration/api_image_test.py b/tests/integration/api_image_test.py
index 2bc96ab..6a6686e 100644
--- a/tests/integration/api_image_test.py
+++ b/tests/integration/api_image_test.py
@@ -7,9 +7,8 @@ import tempfile
import threading
import pytest
-import six
-from six.moves import BaseHTTPServer
-from six.moves import socketserver
+from http.server import SimpleHTTPRequestHandler
+import socketserver
import docker
@@ -33,7 +32,7 @@ class ListImagesTest(BaseAPIIntegrationTest):
def test_images_quiet(self):
res1 = self.client.images(quiet=True)
- assert type(res1[0]) == six.text_type
+ assert type(res1[0]) == str
class PullImageTest(BaseAPIIntegrationTest):
@@ -42,9 +41,9 @@ class PullImageTest(BaseAPIIntegrationTest):
self.client.remove_image('hello-world')
except docker.errors.APIError:
pass
- res = self.client.pull('hello-world', tag='latest')
+ res = self.client.pull('hello-world')
self.tmp_imgs.append('hello-world')
- assert type(res) == six.text_type
+ assert type(res) == str
assert len(self.client.images('hello-world')) >= 1
img_info = self.client.inspect_image('hello-world')
assert 'Id' in img_info
@@ -55,7 +54,7 @@ class PullImageTest(BaseAPIIntegrationTest):
except docker.errors.APIError:
pass
stream = self.client.pull(
- 'hello-world', tag='latest', stream=True, decode=True)
+ 'hello-world', stream=True, decode=True)
self.tmp_imgs.append('hello-world')
for chunk in stream:
assert isinstance(chunk, dict)
@@ -266,14 +265,14 @@ class ImportImageTest(BaseAPIIntegrationTest):
output = self.client.load_image(data)
assert any([
line for line in output
- if 'Loaded image: {}'.format(test_img) in line.get('stream', '')
+ if f'Loaded image: {test_img}' in line.get('stream', '')
])
@contextlib.contextmanager
def temporary_http_file_server(self, stream):
'''Serve data from an IO stream over HTTP.'''
- class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
+ class Handler(SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-Type', 'application/x-tar')
@@ -282,10 +281,10 @@ class ImportImageTest(BaseAPIIntegrationTest):
server = socketserver.TCPServer(('', 0), Handler)
thread = threading.Thread(target=server.serve_forever)
- thread.setDaemon(True)
+ thread.daemon = True
thread.start()
- yield 'http://%s:%s' % (socket.gethostname(), server.server_address[1])
+ yield f'http://{socket.gethostname()}:{server.server_address[1]}'
server.shutdown()
@@ -351,7 +350,7 @@ class SaveLoadImagesTest(BaseAPIIntegrationTest):
result = self.client.load_image(f.read())
success = False
- result_line = 'Loaded image: {}\n'.format(TEST_IMG)
+ result_line = f'Loaded image: {TEST_IMG}\n'
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 4b5e6fc..78d54e2 100644
--- a/tests/integration/api_network_test.py
+++ b/tests/integration/api_network_test.py
@@ -9,7 +9,7 @@ from .base import BaseAPIIntegrationTest, TEST_IMG
class TestNetworks(BaseAPIIntegrationTest):
def tearDown(self):
self.client.leave_swarm(force=True)
- super(TestNetworks, self).tearDown()
+ super().tearDown()
def create_network(self, *args, **kwargs):
net_name = random_name()
@@ -275,6 +275,27 @@ class TestNetworks(BaseAPIIntegrationTest):
assert 'LinkLocalIPs' in net_cfg['IPAMConfig']
assert net_cfg['IPAMConfig']['LinkLocalIPs'] == ['169.254.8.8']
+ @requires_api_version('1.32')
+ def test_create_with_driveropt(self):
+ container = self.client.create_container(
+ TEST_IMG, 'top',
+ networking_config=self.client.create_networking_config(
+ {
+ 'bridge': self.client.create_endpoint_config(
+ driver_opt={'com.docker-py.setting': 'on'}
+ )
+ }
+ ),
+ host_config=self.client.create_host_config(network_mode='bridge')
+ )
+ self.tmp_containers.append(container)
+ self.client.start(container)
+ container_data = self.client.inspect_container(container)
+ net_cfg = container_data['NetworkSettings']['Networks']['bridge']
+ assert 'DriverOpts' in net_cfg
+ assert 'com.docker-py.setting' in net_cfg['DriverOpts']
+ assert net_cfg['DriverOpts']['com.docker-py.setting'] == 'on'
+
@requires_api_version('1.22')
def test_create_with_links(self):
net_name, net_id = self.create_network()
diff --git a/tests/integration/api_plugin_test.py b/tests/integration/api_plugin_test.py
index 38f9d12..3ecb028 100644
--- a/tests/integration/api_plugin_test.py
+++ b/tests/integration/api_plugin_test.py
@@ -22,13 +22,13 @@ class PluginTest(BaseAPIIntegrationTest):
def teardown_method(self, method):
client = self.get_client_instance()
try:
- client.disable_plugin(SSHFS)
+ client.disable_plugin(SSHFS, True)
except docker.errors.APIError:
pass
for p in self.tmp_plugins:
try:
- client.remove_plugin(p, force=True)
+ client.remove_plugin(p)
except docker.errors.APIError:
pass
diff --git a/tests/integration/api_secret_test.py b/tests/integration/api_secret_test.py
index b3d93b8..fd98543 100644
--- a/tests/integration/api_secret_test.py
+++ b/tests/integration/api_secret_test.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import docker
import pytest
@@ -31,7 +29,7 @@ class SecretAPITest(BaseAPIIntegrationTest):
def test_create_secret_unicode_data(self):
secret_id = self.client.create_secret(
- 'favorite_character', u'いざよいさくや'
+ 'favorite_character', 'いざよいさくや'
)
self.tmp_secrets.append(secret_id)
assert 'ID' in secret_id
diff --git a/tests/integration/api_service_test.py b/tests/integration/api_service_test.py
index b6b7ec5..8ce7c9d 100644
--- a/tests/integration/api_service_test.py
+++ b/tests/integration/api_service_test.py
@@ -1,11 +1,8 @@
-# -*- coding: utf-8 -*-
-
import random
import time
import docker
import pytest
-import six
from ..helpers import (
force_leave_swarm, requires_api_version, requires_experimental
@@ -31,10 +28,10 @@ class ServiceTest(BaseAPIIntegrationTest):
self.client.remove_service(service['ID'])
except docker.errors.APIError:
pass
- super(ServiceTest, self).tearDown()
+ super().tearDown()
def get_service_name(self):
- return 'dockerpytest_{0:x}'.format(random.getrandbits(64))
+ return f'dockerpytest_{random.getrandbits(64):x}'
def get_service_container(self, service_name, attempts=20, interval=0.5,
include_stopped=False):
@@ -55,7 +52,7 @@ class ServiceTest(BaseAPIIntegrationTest):
def create_simple_service(self, name=None, labels=None):
if name:
- name = 'dockerpytest_{0}'.format(name)
+ name = f'dockerpytest_{name}'
else:
name = self.get_service_name()
@@ -150,7 +147,7 @@ class ServiceTest(BaseAPIIntegrationTest):
else:
break
- if six.PY3:
+ if log_line is not None:
log_line = log_line.decode('utf-8')
assert 'hello\n' in log_line
@@ -404,20 +401,20 @@ class ServiceTest(BaseAPIIntegrationTest):
node_id = self.client.nodes()[0]['ID']
container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(
- container_spec, placement=['node.id=={}'.format(node_id)]
+ container_spec, placement=[f'node.id=={node_id}']
)
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'] ==
- {'Constraints': ['node.id=={}'.format(node_id)]})
+ {'Constraints': [f'node.id=={node_id}']})
def test_create_service_with_placement_object(self):
node_id = self.client.nodes()[0]['ID']
container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
placemt = docker.types.Placement(
- constraints=['node.id=={}'.format(node_id)]
+ constraints=[f'node.id=={node_id}']
)
task_tmpl = docker.types.TaskTemplate(
container_spec, placement=placemt
@@ -471,6 +468,19 @@ class ServiceTest(BaseAPIIntegrationTest):
assert 'Placement' in svc_info['Spec']['TaskTemplate']
assert svc_info['Spec']['TaskTemplate']['Placement'] == placemt
+ @requires_api_version('1.40')
+ def test_create_service_with_placement_maxreplicas(self):
+ container_spec = docker.types.ContainerSpec(TEST_IMG, ['true'])
+ placemt = docker.types.Placement(maxreplicas=1)
+ 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(TEST_IMG, ['true'])
task_tmpl = docker.types.TaskTemplate(container_spec)
@@ -496,7 +506,7 @@ class ServiceTest(BaseAPIIntegrationTest):
assert port['TargetPort'] == 1990
assert port['Protocol'] == 'udp'
else:
- self.fail('Invalid port specification: {0}'.format(port))
+ self.fail(f'Invalid port specification: {port}')
assert len(ports) == 3
@@ -616,6 +626,39 @@ class ServiceTest(BaseAPIIntegrationTest):
assert 'Replicated' in svc_info['Spec']['Mode']
assert svc_info['Spec']['Mode']['Replicated'] == {'Replicas': 5}
+ @requires_api_version('1.41')
+ def test_create_service_global_job_mode(self):
+ container_spec = docker.types.ContainerSpec(
+ TEST_IMG, ['echo', 'hello']
+ )
+ task_tmpl = docker.types.TaskTemplate(container_spec)
+ name = self.get_service_name()
+ svc_id = self.client.create_service(
+ task_tmpl, name=name, mode='global-job'
+ )
+ svc_info = self.client.inspect_service(svc_id)
+ assert 'Mode' in svc_info['Spec']
+ assert 'GlobalJob' in svc_info['Spec']['Mode']
+
+ @requires_api_version('1.41')
+ def test_create_service_replicated_job_mode(self):
+ container_spec = docker.types.ContainerSpec(
+ TEST_IMG, ['echo', 'hello']
+ )
+ task_tmpl = docker.types.TaskTemplate(container_spec)
+ name = self.get_service_name()
+ svc_id = self.client.create_service(
+ task_tmpl, name=name,
+ mode=docker.types.ServiceMode('replicated-job', 5)
+ )
+ svc_info = self.client.inspect_service(svc_id)
+ assert 'Mode' in svc_info['Spec']
+ assert 'ReplicatedJob' in svc_info['Spec']['Mode']
+ assert svc_info['Spec']['Mode']['ReplicatedJob'] == {
+ 'MaxConcurrent': 1,
+ 'TotalCompletions': 5
+ }
+
@requires_api_version('1.25')
def test_update_service_force_update(self):
container_spec = docker.types.ContainerSpec(
@@ -658,14 +701,14 @@ class ServiceTest(BaseAPIIntegrationTest):
container = self.get_service_container(name)
assert container is not None
exec_id = self.client.exec_create(
- container, 'cat /run/secrets/{0}'.format(secret_name)
+ container, f'cat /run/secrets/{secret_name}'
)
assert self.client.exec_start(exec_id) == secret_data
@requires_api_version('1.25')
def test_create_service_with_unicode_secret(self):
secret_name = 'favorite_touhou'
- secret_data = u'東方花映塚'
+ secret_data = '東方花映塚'
secret_id = self.client.create_secret(secret_name, secret_data)
self.tmp_secrets.append(secret_id)
secret_ref = docker.types.SecretReference(secret_id, secret_name)
@@ -683,7 +726,7 @@ class ServiceTest(BaseAPIIntegrationTest):
container = self.get_service_container(name)
assert container is not None
exec_id = self.client.exec_create(
- container, 'cat /run/secrets/{0}'.format(secret_name)
+ container, f'cat /run/secrets/{secret_name}'
)
container_secret = self.client.exec_start(exec_id)
container_secret = container_secret.decode('utf-8')
@@ -710,14 +753,14 @@ class ServiceTest(BaseAPIIntegrationTest):
container = self.get_service_container(name)
assert container is not None
exec_id = self.client.exec_create(
- container, 'cat /{0}'.format(config_name)
+ container, f'cat /{config_name}'
)
assert self.client.exec_start(exec_id) == config_data
@requires_api_version('1.30')
def test_create_service_with_unicode_config(self):
config_name = 'favorite_touhou'
- config_data = u'東方花映塚'
+ config_data = '東方花映塚'
config_id = self.client.create_config(config_name, config_data)
self.tmp_configs.append(config_id)
config_ref = docker.types.ConfigReference(config_id, config_name)
@@ -735,7 +778,7 @@ class ServiceTest(BaseAPIIntegrationTest):
container = self.get_service_container(name)
assert container is not None
exec_id = self.client.exec_create(
- container, 'cat /{0}'.format(config_name)
+ container, f'cat /{config_name}'
)
container_config = self.client.exec_start(exec_id)
container_config = container_config.decode('utf-8')
@@ -1124,7 +1167,7 @@ class ServiceTest(BaseAPIIntegrationTest):
assert port['TargetPort'] == 1990
assert port['Protocol'] == 'udp'
else:
- self.fail('Invalid port specification: {0}'.format(port))
+ self.fail(f'Invalid port specification: {port}')
assert len(ports) == 3
@@ -1151,7 +1194,7 @@ class ServiceTest(BaseAPIIntegrationTest):
assert port['TargetPort'] == 1990
assert port['Protocol'] == 'udp'
else:
- self.fail('Invalid port specification: {0}'.format(port))
+ self.fail(f'Invalid port specification: {port}')
assert len(ports) == 3
@@ -1346,3 +1389,53 @@ class ServiceTest(BaseAPIIntegrationTest):
self.client.update_service(*args, **kwargs)
else:
raise
+
+ @requires_api_version('1.41')
+ def test_create_service_cap_add(self):
+ name = self.get_service_name()
+ container_spec = docker.types.ContainerSpec(
+ TEST_IMG, ['echo', 'hello'], cap_add=['CAP_SYSLOG']
+ )
+ task_tmpl = docker.types.TaskTemplate(container_spec)
+ svc_id = self.client.create_service(task_tmpl, name=name)
+ assert self.client.inspect_service(svc_id)
+ services = self.client.services(filters={'name': name})
+ assert len(services) == 1
+ assert services[0]['ID'] == svc_id['ID']
+ spec = services[0]['Spec']['TaskTemplate']['ContainerSpec']
+ assert 'CAP_SYSLOG' in spec['CapabilityAdd']
+
+ @requires_api_version('1.41')
+ def test_create_service_cap_drop(self):
+ name = self.get_service_name()
+ container_spec = docker.types.ContainerSpec(
+ TEST_IMG, ['echo', 'hello'], cap_drop=['CAP_SYSLOG']
+ )
+ task_tmpl = docker.types.TaskTemplate(container_spec)
+ svc_id = self.client.create_service(task_tmpl, name=name)
+ assert self.client.inspect_service(svc_id)
+ services = self.client.services(filters={'name': name})
+ assert len(services) == 1
+ assert services[0]['ID'] == svc_id['ID']
+ spec = services[0]['Spec']['TaskTemplate']['ContainerSpec']
+ assert 'CAP_SYSLOG' in spec['CapabilityDrop']
+
+ @requires_api_version('1.40')
+ def test_create_service_with_sysctl(self):
+ name = self.get_service_name()
+ sysctls = {
+ 'net.core.somaxconn': '1024',
+ 'net.ipv4.tcp_syncookies': '0',
+ }
+ container_spec = docker.types.ContainerSpec(
+ TEST_IMG, ['echo', 'hello'], sysctls=sysctls
+ )
+ task_tmpl = docker.types.TaskTemplate(container_spec)
+ svc_id = self.client.create_service(task_tmpl, name=name)
+ assert self.client.inspect_service(svc_id)
+ services = self.client.services(filters={'name': name})
+ assert len(services) == 1
+ assert services[0]['ID'] == svc_id['ID']
+ spec = services[0]['Spec']['TaskTemplate']['ContainerSpec']
+ assert spec['Sysctls']['net.core.somaxconn'] == '1024'
+ assert spec['Sysctls']['net.ipv4.tcp_syncookies'] == '0'
diff --git a/tests/integration/api_swarm_test.py b/tests/integration/api_swarm_test.py
index f1cbc26..48c0592 100644
--- a/tests/integration/api_swarm_test.py
+++ b/tests/integration/api_swarm_test.py
@@ -8,7 +8,7 @@ from .base import BaseAPIIntegrationTest
class SwarmTest(BaseAPIIntegrationTest):
def setUp(self):
- super(SwarmTest, self).setUp()
+ super().setUp()
force_leave_swarm(self.client)
self._unlock_key = None
@@ -19,7 +19,7 @@ class SwarmTest(BaseAPIIntegrationTest):
except docker.errors.APIError:
pass
force_leave_swarm(self.client)
- super(SwarmTest, self).tearDown()
+ super().tearDown()
@requires_api_version('1.24')
def test_init_swarm_simple(self):
diff --git a/tests/integration/base.py b/tests/integration/base.py
index a7613f6..031079c 100644
--- a/tests/integration/base.py
+++ b/tests/integration/base.py
@@ -75,11 +75,11 @@ class BaseAPIIntegrationTest(BaseIntegrationTest):
"""
def setUp(self):
- super(BaseAPIIntegrationTest, self).setUp()
+ super().setUp()
self.client = self.get_client_instance()
def tearDown(self):
- super(BaseAPIIntegrationTest, self).tearDown()
+ super().tearDown()
self.client.close()
@staticmethod
diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py
index ec48835..ae94595 100644
--- a/tests/integration/conftest.py
+++ b/tests/integration/conftest.py
@@ -1,5 +1,3 @@
-from __future__ import print_function
-
import sys
import warnings
@@ -17,11 +15,11 @@ def setup_test_session():
try:
c.inspect_image(TEST_IMG)
except docker.errors.NotFound:
- print("\npulling {0}".format(TEST_IMG), file=sys.stderr)
+ print(f"\npulling {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)
+ detail = f"{status} - {progress}"
print(detail, file=sys.stderr)
# Double make sure we now have busybox
diff --git a/tests/integration/context_api_test.py b/tests/integration/context_api_test.py
new file mode 100644
index 0000000..a2a12a5
--- /dev/null
+++ b/tests/integration/context_api_test.py
@@ -0,0 +1,59 @@
+import os
+import tempfile
+import pytest
+from docker import errors
+from docker.context import ContextAPI
+from docker.tls import TLSConfig
+from .base import BaseAPIIntegrationTest
+
+
+class ContextLifecycleTest(BaseAPIIntegrationTest):
+ def test_lifecycle(self):
+ assert ContextAPI.get_context().Name == "default"
+ assert not ContextAPI.get_context("test")
+ assert ContextAPI.get_current_context().Name == "default"
+
+ dirpath = tempfile.mkdtemp()
+ ca = tempfile.NamedTemporaryFile(
+ prefix=os.path.join(dirpath, "ca.pem"), mode="r")
+ cert = tempfile.NamedTemporaryFile(
+ prefix=os.path.join(dirpath, "cert.pem"), mode="r")
+ key = tempfile.NamedTemporaryFile(
+ prefix=os.path.join(dirpath, "key.pem"), mode="r")
+
+ # create context 'test
+ docker_tls = TLSConfig(
+ client_cert=(cert.name, key.name),
+ ca_cert=ca.name)
+ ContextAPI.create_context(
+ "test", tls_cfg=docker_tls)
+
+ # check for a context 'test' in the context store
+ assert any([ctx.Name == "test" for ctx in ContextAPI.contexts()])
+ # retrieve a context object for 'test'
+ assert ContextAPI.get_context("test")
+ # remove context
+ ContextAPI.remove_context("test")
+ with pytest.raises(errors.ContextNotFound):
+ ContextAPI.inspect_context("test")
+ # check there is no 'test' context in store
+ assert not ContextAPI.get_context("test")
+
+ ca.close()
+ key.close()
+ cert.close()
+
+ def test_context_remove(self):
+ ContextAPI.create_context("test")
+ assert ContextAPI.inspect_context("test")["Name"] == "test"
+
+ ContextAPI.remove_context("test")
+ with pytest.raises(errors.ContextNotFound):
+ ContextAPI.inspect_context("test")
+
+ def test_load_context_without_orchestrator(self):
+ ContextAPI.create_context("test")
+ ctx = ContextAPI.get_context("test")
+ assert ctx
+ assert ctx.Name == "test"
+ assert ctx.Orchestrator is None
diff --git a/tests/integration/credentials/store_test.py b/tests/integration/credentials/store_test.py
index dd543e2..213cf30 100644
--- a/tests/integration/credentials/store_test.py
+++ b/tests/integration/credentials/store_test.py
@@ -1,10 +1,9 @@
import os
import random
+import shutil
import sys
import pytest
-import six
-from distutils.spawn import find_executable
from docker.credentials import (
CredentialsNotFound, Store, StoreError, DEFAULT_LINUX_STORE,
@@ -12,7 +11,7 @@ from docker.credentials import (
)
-class TestStore(object):
+class TestStore:
def teardown_method(self):
for server in self.tmp_keys:
try:
@@ -23,9 +22,9 @@ class TestStore(object):
def setup_method(self):
self.tmp_keys = []
if sys.platform.startswith('linux'):
- if find_executable('docker-credential-' + DEFAULT_LINUX_STORE):
+ if shutil.which('docker-credential-' + DEFAULT_LINUX_STORE):
self.store = Store(DEFAULT_LINUX_STORE)
- elif find_executable('docker-credential-pass'):
+ elif shutil.which('docker-credential-pass'):
self.store = Store('pass')
else:
raise Exception('No supported docker-credential store in PATH')
@@ -33,7 +32,7 @@ class TestStore(object):
self.store = Store(DEFAULT_OSX_STORE)
def get_random_servername(self):
- res = 'pycreds_test_{:x}'.format(random.getrandbits(32))
+ res = f'pycreds_test_{random.getrandbits(32):x}'
self.tmp_keys.append(res)
return res
@@ -61,7 +60,7 @@ class TestStore(object):
def test_unicode_strings(self):
key = self.get_random_servername()
- key = six.u(key)
+ key = key
self.store.store(server=key, username='user', secret='pass')
data = self.store.get(key)
assert data
diff --git a/tests/integration/credentials/utils_test.py b/tests/integration/credentials/utils_test.py
index ad55f32..acf018d 100644
--- a/tests/integration/credentials/utils_test.py
+++ b/tests/integration/credentials/utils_test.py
@@ -1,11 +1,7 @@
import os
from docker.credentials.utils import create_environment_dict
-
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
@mock.patch.dict(os.environ)
diff --git a/tests/integration/models_images_test.py b/tests/integration/models_images_test.py
index 375d972..94aa201 100644
--- a/tests/integration/models_images_test.py
+++ b/tests/integration/models_images_test.py
@@ -13,8 +13,8 @@ class ImageCollectionTest(BaseIntegrationTest):
def test_build(self):
client = docker.from_env(version=TEST_API_VERSION)
image, _ = client.images.build(fileobj=io.BytesIO(
- "FROM alpine\n"
- "CMD echo hello world".encode('ascii')
+ b"FROM alpine\n"
+ b"CMD echo hello world"
))
self.tmp_imgs.append(image.id)
assert client.containers.run(image) == b"hello world\n"
@@ -24,8 +24,8 @@ class ImageCollectionTest(BaseIntegrationTest):
client = docker.from_env(version=TEST_API_VERSION)
with pytest.raises(docker.errors.BuildError) as cm:
client.images.build(fileobj=io.BytesIO(
- "FROM alpine\n"
- "RUN exit 1".encode('ascii')
+ b"FROM alpine\n"
+ b"RUN exit 1"
))
assert (
"The command '/bin/sh -c exit 1' returned a non-zero code: 1"
@@ -36,8 +36,8 @@ class ImageCollectionTest(BaseIntegrationTest):
client = docker.from_env(version=TEST_API_VERSION)
image, _ = client.images.build(
tag='some-tag', fileobj=io.BytesIO(
- "FROM alpine\n"
- "CMD echo hello world".encode('ascii')
+ b"FROM alpine\n"
+ b"CMD echo hello world"
)
)
self.tmp_imgs.append(image.id)
@@ -47,8 +47,8 @@ class ImageCollectionTest(BaseIntegrationTest):
client = docker.from_env(version=TEST_API_VERSION)
image, _ = client.images.build(
tag='dup-txt-tag', fileobj=io.BytesIO(
- "FROM alpine\n"
- "CMD echo Successfully built abcd1234".encode('ascii')
+ b"FROM alpine\n"
+ b"CMD echo Successfully built abcd1234"
)
)
self.tmp_imgs.append(image.id)
@@ -86,9 +86,11 @@ class ImageCollectionTest(BaseIntegrationTest):
def test_pull_multiple(self):
client = docker.from_env(version=TEST_API_VERSION)
- images = client.images.pull('hello-world')
- assert len(images) == 1
- assert 'hello-world:latest' in images[0].attrs['RepoTags']
+ images = client.images.pull('hello-world', all_tags=True)
+ assert len(images) >= 1
+ assert any([
+ 'hello-world:latest' in img.attrs['RepoTags'] for img in images
+ ])
def test_load_error(self):
client = docker.from_env(version=TEST_API_VERSION)
@@ -117,7 +119,7 @@ class ImageCollectionTest(BaseIntegrationTest):
self.tmp_imgs.append(additional_tag)
image.reload()
with tempfile.TemporaryFile() as f:
- stream = image.save(named='{}:latest'.format(additional_tag))
+ stream = image.save(named=f'{additional_tag}:latest')
for chunk in stream:
f.write(chunk)
@@ -127,7 +129,7 @@ class ImageCollectionTest(BaseIntegrationTest):
assert len(result) == 1
assert result[0].id == image.id
- assert '{}:latest'.format(additional_tag) in result[0].tags
+ assert f'{additional_tag}:latest' in result[0].tags
def test_save_name_error(self):
client = docker.from_env(version=TEST_API_VERSION)
@@ -141,7 +143,7 @@ class ImageTest(BaseIntegrationTest):
def test_tag_and_remove(self):
repo = 'dockersdk.tests.images.test_tag'
tag = 'some-tag'
- identifier = '{}:{}'.format(repo, tag)
+ identifier = f'{repo}:{tag}'
client = docker.from_env(version=TEST_API_VERSION)
image = client.images.pull('alpine:latest')
diff --git a/tests/integration/models_services_test.py b/tests/integration/models_services_test.py
index 36caa85..f1439a4 100644
--- a/tests/integration/models_services_test.py
+++ b/tests/integration/models_services_test.py
@@ -30,13 +30,18 @@ class ServiceTest(unittest.TestCase):
# ContainerSpec arguments
image="alpine",
command="sleep 300",
- container_labels={'container': 'label'}
+ container_labels={'container': 'label'},
+ rollback_config={'order': 'start-first'}
)
assert service.name == name
assert service.attrs['Spec']['Labels']['foo'] == 'bar'
container_spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec']
assert "alpine" in container_spec['Image']
assert container_spec['Labels'] == {'container': 'label'}
+ spec_rollback = service.attrs['Spec'].get('RollbackConfig', None)
+ assert spec_rollback is not None
+ assert ('Order' in spec_rollback and
+ spec_rollback['Order'] == 'start-first')
def test_create_with_network(self):
client = docker.from_env(version=TEST_API_VERSION)
@@ -333,3 +338,41 @@ class ServiceTest(unittest.TestCase):
assert service.force_update()
service.reload()
assert service.version > initial_version
+
+ @helpers.requires_api_version('1.41')
+ def test_create_cap_add(self):
+ client = docker.from_env(version=TEST_API_VERSION)
+ name = helpers.random_name()
+ service = client.services.create(
+ name=name,
+ labels={'foo': 'bar'},
+ image="alpine",
+ command="sleep 300",
+ container_labels={'container': 'label'},
+ cap_add=["CAP_SYSLOG"]
+ )
+ assert service.name == name
+ assert service.attrs['Spec']['Labels']['foo'] == 'bar'
+ container_spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec']
+ assert "alpine" in container_spec['Image']
+ assert container_spec['Labels'] == {'container': 'label'}
+ assert "CAP_SYSLOG" in container_spec["CapabilityAdd"]
+
+ @helpers.requires_api_version('1.41')
+ def test_create_cap_drop(self):
+ client = docker.from_env(version=TEST_API_VERSION)
+ name = helpers.random_name()
+ service = client.services.create(
+ name=name,
+ labels={'foo': 'bar'},
+ image="alpine",
+ command="sleep 300",
+ container_labels={'container': 'label'},
+ cap_drop=["CAP_SYSLOG"]
+ )
+ assert service.name == name
+ assert service.attrs['Spec']['Labels']['foo'] == 'bar'
+ container_spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec']
+ assert "alpine" in container_spec['Image']
+ assert container_spec['Labels'] == {'container': 'label'}
+ assert "CAP_SYSLOG" in container_spec["CapabilityDrop"]
diff --git a/tests/integration/regression_test.py b/tests/integration/regression_test.py
index a63883c..10313a6 100644
--- a/tests/integration/regression_test.py
+++ b/tests/integration/regression_test.py
@@ -2,13 +2,13 @@ import io
import random
import docker
-import six
from .base import BaseAPIIntegrationTest, TEST_IMG
import pytest
class TestRegressions(BaseAPIIntegrationTest):
+ @pytest.mark.xfail(True, reason='Docker API always returns chunked resp')
def test_443_handle_nonchunked_response_in_stream(self):
dfile = io.BytesIO()
with pytest.raises(docker.errors.APIError) as exc:
@@ -39,8 +39,7 @@ class TestRegressions(BaseAPIIntegrationTest):
self.client.start(ctnr)
self.client.wait(ctnr)
logs = self.client.logs(ctnr)
- if six.PY3:
- logs = logs.decode('utf-8')
+ logs = logs.decode('utf-8')
assert logs == '1000\n'
def test_792_explicit_port_protocol(self):
@@ -56,10 +55,10 @@ class TestRegressions(BaseAPIIntegrationTest):
self.client.start(ctnr)
assert self.client.port(
ctnr, 2000
- )[0]['HostPort'] == six.text_type(tcp_port)
+ )[0]['HostPort'] == str(tcp_port)
assert self.client.port(
ctnr, '2000/tcp'
- )[0]['HostPort'] == six.text_type(tcp_port)
+ )[0]['HostPort'] == str(tcp_port)
assert self.client.port(
ctnr, '2000/udp'
- )[0]['HostPort'] == six.text_type(udp_port)
+ )[0]['HostPort'] == str(udp_port)