summaryrefslogtreecommitdiff
path: root/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit')
-rw-r--r--tests/unit/api_container_test.py196
-rw-r--r--tests/unit/api_exec_test.py10
-rw-r--r--tests/unit/api_image_test.py41
-rw-r--r--tests/unit/api_network_test.py28
-rw-r--r--tests/unit/api_test.py103
-rw-r--r--tests/unit/api_volume_test.py4
-rw-r--r--tests/unit/auth_test.py26
-rw-r--r--tests/unit/client_test.py192
-rw-r--r--tests/unit/context_test.py49
-rw-r--r--tests/unit/dockertypes_test.py24
-rw-r--r--tests/unit/errors_test.py22
-rw-r--r--tests/unit/fake_api.py119
-rw-r--r--tests/unit/fake_api_client.py17
-rw-r--r--tests/unit/models_containers_test.py40
-rw-r--r--tests/unit/models_images_test.py43
-rw-r--r--tests/unit/models_resources_test.py2
-rw-r--r--tests/unit/models_secrets_test.py11
-rw-r--r--tests/unit/models_services_test.py15
-rw-r--r--tests/unit/sshadapter_test.py39
-rw-r--r--tests/unit/ssladapter_test.py51
-rw-r--r--tests/unit/swarm_test.py2
-rw-r--r--tests/unit/utils_build_test.py134
-rw-r--r--tests/unit/utils_config_test.py6
-rw-r--r--tests/unit/utils_json_stream_test.py12
-rw-r--r--tests/unit/utils_proxy_test.py7
-rw-r--r--tests/unit/utils_test.py79
26 files changed, 841 insertions, 431 deletions
diff --git a/tests/unit/api_container_test.py b/tests/unit/api_container_test.py
index a7e183c..3a2fbde 100644
--- a/tests/unit/api_container_test.py
+++ b/tests/unit/api_container_test.py
@@ -1,25 +1,19 @@
-# -*- coding: utf-8 -*-
-
import datetime
import json
import signal
import docker
+from docker.api import APIClient
+from unittest import mock
import pytest
-import six
from . import fake_api
from ..helpers import requires_api_version
from .api_test import (
BaseAPIClientTest, url_prefix, fake_request, DEFAULT_TIMEOUT_SECONDS,
- fake_inspect_container
+ fake_inspect_container, url_base
)
-try:
- from unittest import mock
-except ImportError:
- import mock
-
def fake_inspect_container_tty(self, container):
return fake_inspect_container(self, container, tty=True)
@@ -30,7 +24,8 @@ class StartContainerTest(BaseAPIClientTest):
self.client.start(fake_api.FAKE_CONTAINER_ID)
args = fake_request.call_args
- assert args[0][1] == url_prefix + 'containers/3cc2351ab11b/start'
+ assert args[0][1] == (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/start')
assert 'data' not in args[1]
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
@@ -123,7 +118,8 @@ class StartContainerTest(BaseAPIClientTest):
self.client.start({'Id': fake_api.FAKE_CONTAINER_ID})
args = fake_request.call_args
- assert args[0][1] == url_prefix + 'containers/3cc2351ab11b/start'
+ assert args[0][1] == (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/start')
assert 'data' not in args[1]
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
@@ -352,6 +348,22 @@ class CreateContainerTest(BaseAPIClientTest):
assert args[1]['headers'] == {'Content-Type': 'application/json'}
assert args[1]['params'] == {'name': 'marisa-kirisame'}
+ def test_create_container_with_platform(self):
+ self.client.create_container('busybox', 'true',
+ platform='linux')
+
+ args = fake_request.call_args
+ assert args[0][1] == url_prefix + 'containers/create'
+ assert json.loads(args[1]['data']) == json.loads('''
+ {"Tty": false, "Image": "busybox", "Cmd": ["true"],
+ "AttachStdin": false,
+ "AttachStderr": true, "AttachStdout": true,
+ "StdinOnce": false,
+ "OpenStdin": false, "NetworkDisabled": false}
+ ''')
+ assert args[1]['headers'] == {'Content-Type': 'application/json'}
+ assert args[1]['params'] == {'name': None, 'platform': 'linux'}
+
def test_create_container_with_mem_limit_as_int(self):
self.client.create_container(
'busybox', 'true', host_config=self.client.create_host_config(
@@ -767,10 +779,71 @@ class CreateContainerTest(BaseAPIClientTest):
assert args[1]['headers'] == {'Content-Type': 'application/json'}
assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
+ def test_create_container_with_device_requests(self):
+ client = APIClient(version='1.40')
+ fake_api.fake_responses.setdefault(
+ f'{fake_api.prefix}/v1.40/containers/create',
+ fake_api.post_fake_create_container,
+ )
+ client.create_container(
+ 'busybox', 'true', host_config=client.create_host_config(
+ device_requests=[
+ {
+ 'device_ids': [
+ '0',
+ 'GPU-3a23c669-1f69-c64e-cf85-44e9b07e7a2a'
+ ]
+ },
+ {
+ 'driver': 'nvidia',
+ 'Count': -1,
+ 'capabilities': [
+ ['gpu', 'utility']
+ ],
+ 'options': {
+ 'key': 'value'
+ }
+ }
+ ]
+ )
+ )
+
+ args = fake_request.call_args
+ assert args[0][1] == url_base + 'v1.40/' + 'containers/create'
+ expected_payload = self.base_create_payload()
+ expected_payload['HostConfig'] = client.create_host_config()
+ expected_payload['HostConfig']['DeviceRequests'] = [
+ {
+ 'Driver': '',
+ 'Count': 0,
+ 'DeviceIDs': [
+ '0',
+ 'GPU-3a23c669-1f69-c64e-cf85-44e9b07e7a2a'
+ ],
+ 'Capabilities': [],
+ 'Options': {}
+ },
+ {
+ 'Driver': 'nvidia',
+ 'Count': -1,
+ 'DeviceIDs': [],
+ 'Capabilities': [
+ ['gpu', 'utility']
+ ],
+ 'Options': {
+ 'key': 'value'
+ }
+ }
+ ]
+ assert json.loads(args[1]['data']) == expected_payload
+ assert args[1]['headers']['Content-Type'] == 'application/json'
+ assert set(args[1]['headers']) <= {'Content-Type', 'User-Agent'}
+ assert args[1]['timeout'] == DEFAULT_TIMEOUT_SECONDS
+
def test_create_container_with_labels_dict(self):
labels_dict = {
- six.text_type('foo'): six.text_type('1'),
- six.text_type('bar'): six.text_type('2'),
+ 'foo': '1',
+ 'bar': '2',
}
self.client.create_container(
@@ -786,12 +859,12 @@ class CreateContainerTest(BaseAPIClientTest):
def test_create_container_with_labels_list(self):
labels_list = [
- six.text_type('foo'),
- six.text_type('bar'),
+ 'foo',
+ 'bar',
]
labels_dict = {
- six.text_type('foo'): six.text_type(),
- six.text_type('bar'): six.text_type(),
+ 'foo': '',
+ 'bar': '',
}
self.client.create_container(
@@ -951,11 +1024,11 @@ class CreateContainerTest(BaseAPIClientTest):
def test_create_container_with_unicode_envvars(self):
envvars_dict = {
- 'foo': u'☃',
+ 'foo': '☃',
}
expected = [
- u'foo=☃'
+ 'foo=☃'
]
self.client.create_container(
@@ -1024,7 +1097,8 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/resize',
+ (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/resize'),
params={'h': 15, 'w': 120},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1037,7 +1111,8 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/rename',
+ (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/rename'),
params={'name': 'foobar'},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1047,7 +1122,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/wait',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/wait',
timeout=None,
params={}
)
@@ -1057,7 +1132,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/wait',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/wait',
timeout=None,
params={}
)
@@ -1069,14 +1144,14 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/logs',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
'tail': 'all'},
timeout=DEFAULT_TIMEOUT_SECONDS,
stream=False
)
- assert logs == 'Flowering Nights\n(Sakuya Iyazoi)\n'.encode('ascii')
+ assert logs == b'Flowering Nights\n(Sakuya Iyazoi)\n'
def test_logs_with_dict_instead_of_id(self):
with mock.patch('docker.api.client.APIClient.inspect_container',
@@ -1085,14 +1160,14 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/logs',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
'tail': 'all'},
timeout=DEFAULT_TIMEOUT_SECONDS,
stream=False
)
- assert logs == 'Flowering Nights\n(Sakuya Iyazoi)\n'.encode('ascii')
+ assert logs == b'Flowering Nights\n(Sakuya Iyazoi)\n'
def test_log_streaming(self):
with mock.patch('docker.api.client.APIClient.inspect_container',
@@ -1102,7 +1177,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/logs',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
'tail': 'all'},
timeout=DEFAULT_TIMEOUT_SECONDS,
@@ -1117,7 +1192,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/logs',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
params={'timestamps': 0, 'follow': 1, 'stderr': 1, 'stdout': 1,
'tail': 'all'},
timeout=DEFAULT_TIMEOUT_SECONDS,
@@ -1131,7 +1206,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/logs',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
params={'timestamps': 0, 'follow': 1, 'stderr': 1, 'stdout': 1,
'tail': 'all'},
timeout=DEFAULT_TIMEOUT_SECONDS,
@@ -1146,7 +1221,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/logs',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
params={'timestamps': 0, 'follow': 1, 'stderr': 1, 'stdout': 1,
'tail': 'all'},
timeout=DEFAULT_TIMEOUT_SECONDS,
@@ -1162,7 +1237,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/logs',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
'tail': 10},
timeout=DEFAULT_TIMEOUT_SECONDS,
@@ -1178,7 +1253,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/logs',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
'tail': 'all', 'since': ts},
timeout=DEFAULT_TIMEOUT_SECONDS,
@@ -1195,7 +1270,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/logs',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
params={'timestamps': 0, 'follow': 0, 'stderr': 1, 'stdout': 1,
'tail': 'all', 'since': ts},
timeout=DEFAULT_TIMEOUT_SECONDS,
@@ -1221,7 +1296,7 @@ class ContainerTest(BaseAPIClientTest):
assert m.called
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/logs',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/logs',
params={'timestamps': 0, 'follow': 1, 'stderr': 1, 'stdout': 1,
'tail': 'all'},
timeout=DEFAULT_TIMEOUT_SECONDS,
@@ -1233,7 +1308,8 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/changes',
+ (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/changes'),
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1242,7 +1318,8 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/changes',
+ (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/changes'),
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1251,7 +1328,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/json',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/json',
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1262,7 +1339,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/stop',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/stop',
params={'t': timeout},
timeout=(DEFAULT_TIMEOUT_SECONDS + timeout)
)
@@ -1275,7 +1352,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/stop',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/stop',
params={'t': timeout},
timeout=(DEFAULT_TIMEOUT_SECONDS + timeout)
)
@@ -1285,7 +1362,8 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/pause',
+ (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/pause'),
timeout=(DEFAULT_TIMEOUT_SECONDS)
)
@@ -1294,7 +1372,8 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/unpause',
+ (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/unpause'),
timeout=(DEFAULT_TIMEOUT_SECONDS)
)
@@ -1303,7 +1382,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/kill',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/kill',
params={},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1313,7 +1392,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/kill',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/kill',
params={},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1323,7 +1402,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/kill',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/kill',
params={'signal': signal.SIGTERM},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1333,7 +1412,8 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/restart',
+ (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/restart'),
params={'t': 2},
timeout=(DEFAULT_TIMEOUT_SECONDS + 2)
)
@@ -1343,7 +1423,8 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'containers/3cc2351ab11b/restart',
+ (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/restart'),
params={'t': 2},
timeout=(DEFAULT_TIMEOUT_SECONDS + 2)
)
@@ -1353,7 +1434,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'DELETE',
- url_prefix + 'containers/3cc2351ab11b',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID,
params={'v': False, 'link': False, 'force': False},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1363,7 +1444,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'DELETE',
- url_prefix + 'containers/3cc2351ab11b',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID,
params={'v': False, 'link': False, 'force': False},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1373,7 +1454,8 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/export',
+ (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/export'),
stream=True,
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1383,7 +1465,8 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/export',
+ (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/export'),
stream=True,
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1393,7 +1476,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/json',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/json',
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1409,7 +1492,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/stats',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/stats',
timeout=60,
stream=True
)
@@ -1419,7 +1502,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/top',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/top',
params={},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1429,7 +1512,7 @@ class ContainerTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'containers/3cc2351ab11b/top',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID + '/top',
params={'ps_args': 'waux'},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -1441,7 +1524,8 @@ class ContainerTest(BaseAPIClientTest):
blkio_weight=345
)
args = fake_request.call_args
- assert args[0][1] == url_prefix + 'containers/3cc2351ab11b/update'
+ assert args[0][1] == (url_prefix + 'containers/' +
+ fake_api.FAKE_CONTAINER_ID + '/update')
assert json.loads(args[1]['data']) == {
'Memory': 2 * 1024, 'CpuShares': 124, 'BlkioWeight': 345
}
diff --git a/tests/unit/api_exec_test.py b/tests/unit/api_exec_test.py
index a9d2dd5..4504250 100644
--- a/tests/unit/api_exec_test.py
+++ b/tests/unit/api_exec_test.py
@@ -11,7 +11,7 @@ class ExecTest(BaseAPIClientTest):
self.client.exec_create(fake_api.FAKE_CONTAINER_ID, ['ls', '-1'])
args = fake_request.call_args
- assert 'POST' == args[0][0], url_prefix + 'containers/{0}/exec'.format(
+ assert 'POST' == args[0][0], url_prefix + 'containers/{}/exec'.format(
fake_api.FAKE_CONTAINER_ID
)
@@ -32,7 +32,7 @@ class ExecTest(BaseAPIClientTest):
self.client.exec_start(fake_api.FAKE_EXEC_ID)
args = fake_request.call_args
- assert args[0][1] == url_prefix + 'exec/{0}/start'.format(
+ assert args[0][1] == url_prefix + 'exec/{}/start'.format(
fake_api.FAKE_EXEC_ID
)
@@ -51,7 +51,7 @@ class ExecTest(BaseAPIClientTest):
self.client.exec_start(fake_api.FAKE_EXEC_ID, detach=True)
args = fake_request.call_args
- assert args[0][1] == url_prefix + 'exec/{0}/start'.format(
+ assert args[0][1] == url_prefix + 'exec/{}/start'.format(
fake_api.FAKE_EXEC_ID
)
@@ -68,7 +68,7 @@ class ExecTest(BaseAPIClientTest):
self.client.exec_inspect(fake_api.FAKE_EXEC_ID)
args = fake_request.call_args
- assert args[0][1] == url_prefix + 'exec/{0}/json'.format(
+ assert args[0][1] == url_prefix + 'exec/{}/json'.format(
fake_api.FAKE_EXEC_ID
)
@@ -77,7 +77,7 @@ class ExecTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'exec/{0}/resize'.format(fake_api.FAKE_EXEC_ID),
+ url_prefix + f'exec/{fake_api.FAKE_EXEC_ID}/resize',
params={'h': 20, 'w': 60},
timeout=DEFAULT_TIMEOUT_SECONDS
)
diff --git a/tests/unit/api_image_test.py b/tests/unit/api_image_test.py
index 1e2315d..e285932 100644
--- a/tests/unit/api_image_test.py
+++ b/tests/unit/api_image_test.py
@@ -3,16 +3,12 @@ import pytest
from . import fake_api
from docker import auth
+from unittest import mock
from .api_test import (
BaseAPIClientTest, fake_request, DEFAULT_TIMEOUT_SECONDS, url_prefix,
fake_resolve_authconfig
)
-try:
- from unittest import mock
-except ImportError:
- import mock
-
class ImageTest(BaseAPIClientTest):
def test_image_viz(self):
@@ -26,7 +22,18 @@ class ImageTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
url_prefix + 'images/json',
- params={'filter': None, 'only_ids': 0, 'all': 1},
+ params={'only_ids': 0, 'all': 1},
+ timeout=DEFAULT_TIMEOUT_SECONDS
+ )
+
+ def test_images_name(self):
+ self.client.images('foo:bar')
+
+ fake_request.assert_called_with(
+ 'GET',
+ url_prefix + 'images/json',
+ params={'only_ids': 0, 'all': 0,
+ 'filters': '{"reference": ["foo:bar"]}'},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -36,7 +43,7 @@ class ImageTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
url_prefix + 'images/json',
- params={'filter': None, 'only_ids': 1, 'all': 1},
+ params={'only_ids': 1, 'all': 1},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -46,7 +53,7 @@ class ImageTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
url_prefix + 'images/json',
- params={'filter': None, 'only_ids': 1, 'all': 0},
+ params={'only_ids': 1, 'all': 0},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -56,7 +63,7 @@ class ImageTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
url_prefix + 'images/json',
- params={'filter': None, 'only_ids': 0, 'all': 0,
+ params={'only_ids': 0, 'all': 0,
'filters': '{"dangling": ["true"]}'},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -67,7 +74,7 @@ class ImageTest(BaseAPIClientTest):
args = fake_request.call_args
assert args[0][1] == url_prefix + 'images/create'
assert args[1]['params'] == {
- 'tag': None, 'fromImage': 'joffrey/test001'
+ 'tag': 'latest', 'fromImage': 'joffrey/test001'
}
assert not args[1]['stream']
@@ -77,7 +84,7 @@ class ImageTest(BaseAPIClientTest):
args = fake_request.call_args
assert args[0][1] == url_prefix + 'images/create'
assert args[1]['params'] == {
- 'tag': None, 'fromImage': 'joffrey/test001'
+ 'tag': 'latest', 'fromImage': 'joffrey/test001'
}
assert args[1]['stream']
@@ -93,7 +100,7 @@ class ImageTest(BaseAPIClientTest):
'repo': None,
'comment': None,
'tag': None,
- 'container': '3cc2351ab11b',
+ 'container': fake_api.FAKE_CONTAINER_ID,
'author': None,
'changes': None
},
@@ -105,7 +112,7 @@ class ImageTest(BaseAPIClientTest):
fake_request.assert_called_with(
'DELETE',
- url_prefix + 'images/e9aa60c60128',
+ url_prefix + 'images/' + fake_api.FAKE_IMAGE_ID,
params={'force': False, 'noprune': False},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -280,7 +287,7 @@ class ImageTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'images/e9aa60c60128/tag',
+ url_prefix + 'images/' + fake_api.FAKE_IMAGE_ID + '/tag',
params={
'tag': None,
'repo': 'repo',
@@ -298,7 +305,7 @@ class ImageTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'images/e9aa60c60128/tag',
+ url_prefix + 'images/' + fake_api.FAKE_IMAGE_ID + '/tag',
params={
'tag': 'tag',
'repo': 'repo',
@@ -313,7 +320,7 @@ class ImageTest(BaseAPIClientTest):
fake_request.assert_called_with(
'POST',
- url_prefix + 'images/e9aa60c60128/tag',
+ url_prefix + 'images/' + fake_api.FAKE_IMAGE_ID + '/tag',
params={
'tag': None,
'repo': 'repo',
@@ -327,7 +334,7 @@ class ImageTest(BaseAPIClientTest):
fake_request.assert_called_with(
'GET',
- url_prefix + 'images/e9aa60c60128/get',
+ url_prefix + 'images/' + fake_api.FAKE_IMAGE_ID + '/get',
stream=True,
timeout=DEFAULT_TIMEOUT_SECONDS
)
diff --git a/tests/unit/api_network_test.py b/tests/unit/api_network_test.py
index c78554d..8afab73 100644
--- a/tests/unit/api_network_test.py
+++ b/tests/unit/api_network_test.py
@@ -1,14 +1,8 @@
import json
-import six
-
from .api_test import BaseAPIClientTest, url_prefix, response
from docker.types import IPAMConfig, IPAMPool
-
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
class NetworkTest(BaseAPIClientTest):
@@ -103,16 +97,16 @@ class NetworkTest(BaseAPIClientTest):
self.client.remove_network(network_id)
args = delete.call_args
- assert args[0][0] == url_prefix + 'networks/{0}'.format(network_id)
+ assert args[0][0] == url_prefix + f'networks/{network_id}'
def test_inspect_network(self):
network_id = 'abc12345'
network_name = 'foo'
network_data = {
- six.u('name'): network_name,
- six.u('id'): network_id,
- six.u('driver'): 'bridge',
- six.u('containers'): {},
+ 'name': network_name,
+ 'id': network_id,
+ 'driver': 'bridge',
+ 'containers': {},
}
network_response = response(status_code=200, content=network_data)
@@ -123,7 +117,7 @@ class NetworkTest(BaseAPIClientTest):
assert result == network_data
args = get.call_args
- assert args[0][0] == url_prefix + 'networks/{0}'.format(network_id)
+ assert args[0][0] == url_prefix + f'networks/{network_id}'
def test_connect_container_to_network(self):
network_id = 'abc12345'
@@ -136,11 +130,12 @@ class NetworkTest(BaseAPIClientTest):
container={'Id': container_id},
net_id=network_id,
aliases=['foo', 'bar'],
- links=[('baz', 'quux')]
+ links=[('baz', 'quux')],
+ driver_opt={'com.docker-py.setting': 'yes'},
)
assert post.call_args[0][0] == (
- url_prefix + 'networks/{0}/connect'.format(network_id)
+ url_prefix + f'networks/{network_id}/connect'
)
assert json.loads(post.call_args[1]['data']) == {
@@ -148,6 +143,7 @@ class NetworkTest(BaseAPIClientTest):
'EndpointConfig': {
'Aliases': ['foo', 'bar'],
'Links': ['baz:quux'],
+ 'DriverOpts': {'com.docker-py.setting': 'yes'},
},
}
@@ -162,7 +158,7 @@ class NetworkTest(BaseAPIClientTest):
container={'Id': container_id}, net_id=network_id)
assert post.call_args[0][0] == (
- url_prefix + 'networks/{0}/disconnect'.format(network_id)
+ url_prefix + f'networks/{network_id}/disconnect'
)
assert json.loads(post.call_args[1]['data']) == {
'Container': container_id
diff --git a/tests/unit/api_test.py b/tests/unit/api_test.py
index f4d220a..a2348f0 100644
--- a/tests/unit/api_test.py
+++ b/tests/unit/api_test.py
@@ -1,31 +1,28 @@
import datetime
-import json
import io
+import json
import os
import re
import shutil
import socket
+import struct
import tempfile
import threading
import time
import unittest
+import socketserver
+import http.server
import docker
-from docker.api import APIClient
+import pytest
import requests
+from docker.api import APIClient
+from docker.constants import DEFAULT_DOCKER_API_VERSION
from requests.packages import urllib3
-import six
-import struct
+from unittest import mock
from . import fake_api
-import pytest
-
-try:
- from unittest import mock
-except ImportError:
- import mock
-
DEFAULT_TIMEOUT_SECONDS = docker.constants.DEFAULT_TIMEOUT_SECONDS
@@ -34,7 +31,7 @@ def response(status_code=200, content='', headers=None, reason=None, elapsed=0,
request=None, raw=None):
res = requests.Response()
res.status_code = status_code
- if not isinstance(content, six.binary_type):
+ if not isinstance(content, bytes):
content = json.dumps(content).encode('ascii')
res._content = content
res.headers = requests.structures.CaseInsensitiveDict(headers or {})
@@ -60,7 +57,7 @@ def fake_resp(method, url, *args, **kwargs):
elif (url, method) in fake_api.fake_responses:
key = (url, method)
if not key:
- raise Exception('{0} {1}'.format(method, url))
+ raise Exception(f'{method} {url}')
status_code, content = fake_api.fake_responses[key]()
return response(status_code=status_code, content=content)
@@ -85,11 +82,11 @@ def fake_delete(self, url, *args, **kwargs):
def fake_read_from_socket(self, response, stream, tty=False, demux=False):
- return six.binary_type()
+ return bytes()
-url_base = '{0}/'.format(fake_api.prefix)
-url_prefix = '{0}v{1}/'.format(
+url_base = f'{fake_api.prefix}/'
+url_prefix = '{}v{}/'.format(
url_base,
docker.constants.DEFAULT_DOCKER_API_VERSION)
@@ -105,7 +102,7 @@ class BaseAPIClientTest(unittest.TestCase):
_read_from_socket=fake_read_from_socket
)
self.patcher.start()
- self.client = APIClient()
+ self.client = APIClient(version=DEFAULT_DOCKER_API_VERSION)
def tearDown(self):
self.client.close()
@@ -133,20 +130,20 @@ class DockerApiTest(BaseAPIClientTest):
def test_url_valid_resource(self):
url = self.client._url('/hello/{0}/world', 'somename')
- assert url == '{0}{1}'.format(url_prefix, 'hello/somename/world')
+ assert url == '{}{}'.format(url_prefix, 'hello/somename/world')
url = self.client._url(
'/hello/{0}/world/{1}', 'somename', 'someothername'
)
- assert url == '{0}{1}'.format(
+ assert url == '{}{}'.format(
url_prefix, 'hello/somename/world/someothername'
)
url = self.client._url('/hello/{0}/world', 'some?name')
- assert url == '{0}{1}'.format(url_prefix, 'hello/some%3Fname/world')
+ assert url == '{}{}'.format(url_prefix, 'hello/some%3Fname/world')
url = self.client._url("/images/{0}/push", "localhost:5000/image")
- assert url == '{0}{1}'.format(
+ assert url == '{}{}'.format(
url_prefix, 'images/localhost:5000/image/push'
)
@@ -156,13 +153,13 @@ class DockerApiTest(BaseAPIClientTest):
def test_url_no_resource(self):
url = self.client._url('/simple')
- assert url == '{0}{1}'.format(url_prefix, 'simple')
+ assert url == '{}{}'.format(url_prefix, 'simple')
def test_url_unversioned_api(self):
url = self.client._url(
'/hello/{0}/world', 'somename', versioned_api=False
)
- assert url == '{0}{1}'.format(url_base, 'hello/somename/world')
+ assert url == '{}{}'.format(url_base, 'hello/somename/world')
def test_version(self):
self.client.version()
@@ -184,13 +181,13 @@ class DockerApiTest(BaseAPIClientTest):
def test_retrieve_server_version(self):
client = APIClient(version="auto")
- assert isinstance(client._version, six.string_types)
+ assert isinstance(client._version, str)
assert not (client._version == "auto")
client.close()
def test_auto_retrieve_server_version(self):
version = self.client._retrieve_server_version()
- assert isinstance(version, six.string_types)
+ assert isinstance(version, str)
def test_info(self):
self.client.info()
@@ -282,27 +279,37 @@ class DockerApiTest(BaseAPIClientTest):
return socket_adapter.socket_path
def test_url_compatibility_unix(self):
- c = APIClient(base_url="unix://socket")
+ c = APIClient(
+ base_url="unix://socket",
+ version=DEFAULT_DOCKER_API_VERSION)
assert self._socket_path_for_client_session(c) == '/socket'
def test_url_compatibility_unix_triple_slash(self):
- c = APIClient(base_url="unix:///socket")
+ c = APIClient(
+ base_url="unix:///socket",
+ version=DEFAULT_DOCKER_API_VERSION)
assert self._socket_path_for_client_session(c) == '/socket'
def test_url_compatibility_http_unix_triple_slash(self):
- c = APIClient(base_url="http+unix:///socket")
+ c = APIClient(
+ base_url="http+unix:///socket",
+ version=DEFAULT_DOCKER_API_VERSION)
assert self._socket_path_for_client_session(c) == '/socket'
def test_url_compatibility_http(self):
- c = APIClient(base_url="http://hostname:1234")
+ c = APIClient(
+ base_url="http://hostname:1234",
+ version=DEFAULT_DOCKER_API_VERSION)
assert c.base_url == "http://hostname:1234"
def test_url_compatibility_tcp(self):
- c = APIClient(base_url="tcp://hostname:1234")
+ c = APIClient(
+ base_url="tcp://hostname:1234",
+ version=DEFAULT_DOCKER_API_VERSION)
assert c.base_url == "http://hostname:1234"
@@ -311,7 +318,7 @@ class DockerApiTest(BaseAPIClientTest):
fake_request.assert_called_with(
'DELETE',
- url_prefix + 'containers/3cc2351ab11b',
+ url_prefix + 'containers/' + fake_api.FAKE_CONTAINER_ID,
params={'v': False, 'link': True, 'force': False},
timeout=DEFAULT_TIMEOUT_SECONDS
)
@@ -327,8 +334,7 @@ class DockerApiTest(BaseAPIClientTest):
def test_stream_helper_decoding(self):
status_code, content = fake_api.fake_responses[url_prefix + 'events']()
content_str = json.dumps(content)
- if six.PY3:
- content_str = content_str.encode('utf-8')
+ content_str = content_str.encode('utf-8')
body = io.BytesIO(content_str)
# mock a stream interface
@@ -372,7 +378,7 @@ class UnixSocketStreamTest(unittest.TestCase):
self.server_socket = self._setup_socket()
self.stop_server = False
server_thread = threading.Thread(target=self.run_server)
- server_thread.setDaemon(True)
+ server_thread.daemon = True
server_thread.start()
self.response = None
self.request_handler = None
@@ -395,7 +401,7 @@ class UnixSocketStreamTest(unittest.TestCase):
while not self.stop_server:
try:
connection, client_address = self.server_socket.accept()
- except socket.error:
+ except OSError:
# Probably no connection to accept yet
time.sleep(0.01)
continue
@@ -447,7 +453,9 @@ class UnixSocketStreamTest(unittest.TestCase):
b'\r\n'
) + b'\r\n'.join(lines)
- with APIClient(base_url="http+unix://" + self.socket_file) as client:
+ with APIClient(
+ base_url="http+unix://" + self.socket_file,
+ version=DEFAULT_DOCKER_API_VERSION) as client:
for i in range(5):
try:
stream = client.build(
@@ -477,10 +485,10 @@ class TCPSocketStreamTest(unittest.TestCase):
@classmethod
def setup_class(cls):
- cls.server = six.moves.socketserver.ThreadingTCPServer(
+ cls.server = socketserver.ThreadingTCPServer(
('', 0), cls.get_handler_class())
cls.thread = threading.Thread(target=cls.server.serve_forever)
- cls.thread.setDaemon(True)
+ cls.thread.daemon = True
cls.thread.start()
cls.address = 'http://{}:{}'.format(
socket.gethostname(), cls.server.server_address[1])
@@ -496,7 +504,7 @@ class TCPSocketStreamTest(unittest.TestCase):
stdout_data = cls.stdout_data
stderr_data = cls.stderr_data
- class Handler(six.moves.BaseHTTPServer.BaseHTTPRequestHandler, object):
+ class Handler(http.server.BaseHTTPRequestHandler):
def do_POST(self):
resp_data = self.get_resp_data()
self.send_response(101)
@@ -522,7 +530,7 @@ class TCPSocketStreamTest(unittest.TestCase):
data += stderr_data
return data
else:
- raise Exception('Unknown path {0}'.format(path))
+ raise Exception(f'Unknown path {path}')
@staticmethod
def frame_header(stream, data):
@@ -532,7 +540,10 @@ class TCPSocketStreamTest(unittest.TestCase):
def request(self, stream=None, tty=None, demux=None):
assert stream is not None and tty is not None and demux is not None
- with APIClient(base_url=self.address) as client:
+ with APIClient(
+ base_url=self.address,
+ version=DEFAULT_DOCKER_API_VERSION
+ ) as client:
if tty:
url = client._url('/tty')
else:
@@ -597,7 +608,7 @@ class UserAgentTest(unittest.TestCase):
self.patcher.stop()
def test_default_user_agent(self):
- client = APIClient()
+ client = APIClient(version=DEFAULT_DOCKER_API_VERSION)
client.version()
assert self.mock_send.call_count == 1
@@ -606,7 +617,9 @@ class UserAgentTest(unittest.TestCase):
assert headers['User-Agent'] == expected
def test_custom_user_agent(self):
- client = APIClient(user_agent='foo/bar')
+ client = APIClient(
+ user_agent='foo/bar',
+ version=DEFAULT_DOCKER_API_VERSION)
client.version()
assert self.mock_send.call_count == 1
@@ -615,7 +628,7 @@ class UserAgentTest(unittest.TestCase):
class DisableSocketTest(unittest.TestCase):
- class DummySocket(object):
+ class DummySocket:
def __init__(self, timeout=60):
self.timeout = timeout
@@ -626,7 +639,7 @@ class DisableSocketTest(unittest.TestCase):
return self.timeout
def setUp(self):
- self.client = APIClient()
+ self.client = APIClient(version=DEFAULT_DOCKER_API_VERSION)
def test_disable_socket_timeout(self):
"""Test that the timeout is disabled on a generic socket object."""
diff --git a/tests/unit/api_volume_test.py b/tests/unit/api_volume_test.py
index 7850c22..a8d9193 100644
--- a/tests/unit/api_volume_test.py
+++ b/tests/unit/api_volume_test.py
@@ -104,7 +104,7 @@ class VolumeTest(BaseAPIClientTest):
args = fake_request.call_args
assert args[0][0] == 'GET'
- assert args[0][1] == '{0}volumes/{1}'.format(url_prefix, name)
+ assert args[0][1] == f'{url_prefix}volumes/{name}'
def test_remove_volume(self):
name = 'perfectcherryblossom'
@@ -112,4 +112,4 @@ class VolumeTest(BaseAPIClientTest):
args = fake_request.call_args
assert args[0][0] == 'DELETE'
- assert args[0][1] == '{0}volumes/{1}'.format(url_prefix, name)
+ assert args[0][1] == f'{url_prefix}volumes/{name}'
diff --git a/tests/unit/auth_test.py b/tests/unit/auth_test.py
index aac8910..dd5b5f8 100644
--- a/tests/unit/auth_test.py
+++ b/tests/unit/auth_test.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import base64
import json
import os
@@ -10,13 +8,9 @@ import tempfile
import unittest
from docker import auth, credentials, errors
+from unittest import mock
import pytest
-try:
- from unittest import mock
-except ImportError:
- import mock
-
class RegressionTest(unittest.TestCase):
def test_803_urlsafe_encode(self):
@@ -239,7 +233,7 @@ class LoadConfigTest(unittest.TestCase):
cfg_path = os.path.join(folder, '.dockercfg')
auth_ = base64.b64encode(b'sakuya:izayoi').decode('ascii')
with open(cfg_path, 'w') as f:
- f.write('auth = {0}\n'.format(auth_))
+ f.write(f'auth = {auth_}\n')
f.write('email = sakuya@scarlet.net')
cfg = auth.load_config(cfg_path)
@@ -297,13 +291,13 @@ class LoadConfigTest(unittest.TestCase):
self.addCleanup(shutil.rmtree, folder)
dockercfg_path = os.path.join(folder,
- '.{0}.dockercfg'.format(
+ '.{}.dockercfg'.format(
random.randrange(100000)))
registry = 'https://your.private.registry.io'
auth_ = base64.b64encode(b'sakuya:izayoi').decode('ascii')
config = {
registry: {
- 'auth': '{0}'.format(auth_),
+ 'auth': f'{auth_}',
'email': 'sakuya@scarlet.net'
}
}
@@ -329,7 +323,7 @@ class LoadConfigTest(unittest.TestCase):
auth_ = base64.b64encode(b'sakuya:izayoi').decode('ascii')
config = {
registry: {
- 'auth': '{0}'.format(auth_),
+ 'auth': f'{auth_}',
'email': 'sakuya@scarlet.net'
}
}
@@ -357,7 +351,7 @@ class LoadConfigTest(unittest.TestCase):
config = {
'auths': {
registry: {
- 'auth': '{0}'.format(auth_),
+ 'auth': f'{auth_}',
'email': 'sakuya@scarlet.net'
}
}
@@ -386,7 +380,7 @@ class LoadConfigTest(unittest.TestCase):
config = {
'auths': {
registry: {
- 'auth': '{0}'.format(auth_),
+ 'auth': f'{auth_}',
'email': 'sakuya@scarlet.net'
}
}
@@ -794,9 +788,9 @@ class InMemoryStore(credentials.Store):
}
def list(self):
- return dict(
- [(k, v['Username']) for k, v in self.__store.items()]
- )
+ return {
+ k: v['Username'] for k, v in self.__store.items()
+ }
def erase(self, server):
del self.__store[server]
diff --git a/tests/unit/client_test.py b/tests/unit/client_test.py
index cce99c5..e7c7eec 100644
--- a/tests/unit/client_test.py
+++ b/tests/unit/client_test.py
@@ -1,22 +1,20 @@
import datetime
-import docker
-from docker.utils import kwargs_from_env
-from docker.constants import (
- DEFAULT_DOCKER_API_VERSION, DEFAULT_TIMEOUT_SECONDS
-)
import os
import unittest
-from . import fake_api
+import docker
import pytest
+from docker.constants import (
+ DEFAULT_DOCKER_API_VERSION, DEFAULT_TIMEOUT_SECONDS,
+ DEFAULT_MAX_POOL_SIZE, IS_WINDOWS_PLATFORM
+)
+from docker.utils import kwargs_from_env
+from unittest import mock
-try:
- from unittest import mock
-except ImportError:
- import mock
-
+from . import fake_api
TEST_CERT_DIR = os.path.join(os.path.dirname(__file__), 'testdata/certs')
+POOL_SIZE = 20
class ClientTest(unittest.TestCase):
@@ -25,33 +23,33 @@ class ClientTest(unittest.TestCase):
def test_events(self, mock_func):
since = datetime.datetime(2016, 1, 1, 0, 0)
mock_func.return_value = fake_api.get_fake_events()[1]
- client = docker.from_env()
+ client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION)
assert client.events(since=since) == mock_func.return_value
mock_func.assert_called_with(since=since)
@mock.patch('docker.api.APIClient.info')
def test_info(self, mock_func):
mock_func.return_value = fake_api.get_fake_info()[1]
- client = docker.from_env()
+ client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION)
assert client.info() == mock_func.return_value
mock_func.assert_called_with()
@mock.patch('docker.api.APIClient.ping')
def test_ping(self, mock_func):
mock_func.return_value = True
- client = docker.from_env()
+ client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION)
assert client.ping() is True
mock_func.assert_called_with()
@mock.patch('docker.api.APIClient.version')
def test_version(self, mock_func):
mock_func.return_value = fake_api.get_fake_version()[1]
- client = docker.from_env()
+ client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION)
assert client.version() == mock_func.return_value
mock_func.assert_called_with()
def test_call_api_client_method(self):
- client = docker.from_env()
+ client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION)
with pytest.raises(AttributeError) as cm:
client.create_container()
s = cm.exconly()
@@ -65,7 +63,9 @@ class ClientTest(unittest.TestCase):
assert "this method is now on the object APIClient" not in s
def test_call_containers(self):
- client = docker.DockerClient(**kwargs_from_env())
+ client = docker.DockerClient(
+ version=DEFAULT_DOCKER_API_VERSION,
+ **kwargs_from_env())
with pytest.raises(TypeError) as cm:
client.containers()
@@ -74,6 +74,84 @@ class ClientTest(unittest.TestCase):
assert "'ContainerCollection' object is not callable" in s
assert "docker.APIClient" in s
+ @pytest.mark.skipif(
+ IS_WINDOWS_PLATFORM, reason='Unix Connection Pool only on Linux'
+ )
+ @mock.patch("docker.transport.unixconn.UnixHTTPConnectionPool")
+ def test_default_pool_size_unix(self, mock_obj):
+ client = docker.DockerClient(
+ version=DEFAULT_DOCKER_API_VERSION
+ )
+ mock_obj.return_value.urlopen.return_value.status = 200
+ client.ping()
+
+ base_url = "{base_url}/v{version}/_ping".format(
+ base_url=client.api.base_url,
+ version=client.api._version
+ )
+
+ mock_obj.assert_called_once_with(base_url,
+ "/var/run/docker.sock",
+ 60,
+ maxsize=DEFAULT_MAX_POOL_SIZE
+ )
+
+ @pytest.mark.skipif(
+ not IS_WINDOWS_PLATFORM, reason='Npipe Connection Pool only on Windows'
+ )
+ @mock.patch("docker.transport.npipeconn.NpipeHTTPConnectionPool")
+ def test_default_pool_size_win(self, mock_obj):
+ client = docker.DockerClient(
+ version=DEFAULT_DOCKER_API_VERSION
+ )
+ mock_obj.return_value.urlopen.return_value.status = 200
+ client.ping()
+
+ mock_obj.assert_called_once_with("//./pipe/docker_engine",
+ 60,
+ maxsize=DEFAULT_MAX_POOL_SIZE
+ )
+
+ @pytest.mark.skipif(
+ IS_WINDOWS_PLATFORM, reason='Unix Connection Pool only on Linux'
+ )
+ @mock.patch("docker.transport.unixconn.UnixHTTPConnectionPool")
+ def test_pool_size_unix(self, mock_obj):
+ client = docker.DockerClient(
+ version=DEFAULT_DOCKER_API_VERSION,
+ max_pool_size=POOL_SIZE
+ )
+ mock_obj.return_value.urlopen.return_value.status = 200
+ client.ping()
+
+ base_url = "{base_url}/v{version}/_ping".format(
+ base_url=client.api.base_url,
+ version=client.api._version
+ )
+
+ mock_obj.assert_called_once_with(base_url,
+ "/var/run/docker.sock",
+ 60,
+ maxsize=POOL_SIZE
+ )
+
+ @pytest.mark.skipif(
+ not IS_WINDOWS_PLATFORM, reason='Npipe Connection Pool only on Windows'
+ )
+ @mock.patch("docker.transport.npipeconn.NpipeHTTPConnectionPool")
+ def test_pool_size_win(self, mock_obj):
+ client = docker.DockerClient(
+ version=DEFAULT_DOCKER_API_VERSION,
+ max_pool_size=POOL_SIZE
+ )
+ mock_obj.return_value.urlopen.return_value.status = 200
+ client.ping()
+
+ mock_obj.assert_called_once_with("//./pipe/docker_engine",
+ 60,
+ maxsize=POOL_SIZE
+ )
+
class FromEnvTest(unittest.TestCase):
@@ -90,7 +168,7 @@ class FromEnvTest(unittest.TestCase):
os.environ.update(DOCKER_HOST='tcp://192.168.59.103:2376',
DOCKER_CERT_PATH=TEST_CERT_DIR,
DOCKER_TLS_VERIFY='1')
- client = docker.from_env()
+ client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION)
assert client.api.base_url == "https://192.168.59.103:2376"
def test_from_env_with_version(self):
@@ -102,11 +180,85 @@ class FromEnvTest(unittest.TestCase):
assert client.api._version == '2.32'
def test_from_env_without_version_uses_default(self):
- client = docker.from_env()
+ client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION)
assert client.api._version == DEFAULT_DOCKER_API_VERSION
def test_from_env_without_timeout_uses_default(self):
- client = docker.from_env()
+ client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION)
assert client.api.timeout == DEFAULT_TIMEOUT_SECONDS
+
+ @pytest.mark.skipif(
+ IS_WINDOWS_PLATFORM, reason='Unix Connection Pool only on Linux'
+ )
+ @mock.patch("docker.transport.unixconn.UnixHTTPConnectionPool")
+ def test_default_pool_size_from_env_unix(self, mock_obj):
+ client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION)
+ mock_obj.return_value.urlopen.return_value.status = 200
+ client.ping()
+
+ base_url = "{base_url}/v{version}/_ping".format(
+ base_url=client.api.base_url,
+ version=client.api._version
+ )
+
+ mock_obj.assert_called_once_with(base_url,
+ "/var/run/docker.sock",
+ 60,
+ maxsize=DEFAULT_MAX_POOL_SIZE
+ )
+
+ @pytest.mark.skipif(
+ not IS_WINDOWS_PLATFORM, reason='Npipe Connection Pool only on Windows'
+ )
+ @mock.patch("docker.transport.npipeconn.NpipeHTTPConnectionPool")
+ def test_default_pool_size_from_env_win(self, mock_obj):
+ client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION)
+ mock_obj.return_value.urlopen.return_value.status = 200
+ client.ping()
+
+ mock_obj.assert_called_once_with("//./pipe/docker_engine",
+ 60,
+ maxsize=DEFAULT_MAX_POOL_SIZE
+ )
+
+ @pytest.mark.skipif(
+ IS_WINDOWS_PLATFORM, reason='Unix Connection Pool only on Linux'
+ )
+ @mock.patch("docker.transport.unixconn.UnixHTTPConnectionPool")
+ def test_pool_size_from_env_unix(self, mock_obj):
+ client = docker.from_env(
+ version=DEFAULT_DOCKER_API_VERSION,
+ max_pool_size=POOL_SIZE
+ )
+ mock_obj.return_value.urlopen.return_value.status = 200
+ client.ping()
+
+ base_url = "{base_url}/v{version}/_ping".format(
+ base_url=client.api.base_url,
+ version=client.api._version
+ )
+
+ mock_obj.assert_called_once_with(base_url,
+ "/var/run/docker.sock",
+ 60,
+ maxsize=POOL_SIZE
+ )
+
+ @pytest.mark.skipif(
+ not IS_WINDOWS_PLATFORM, reason='Npipe Connection Pool only on Windows'
+ )
+ @mock.patch("docker.transport.npipeconn.NpipeHTTPConnectionPool")
+ def test_pool_size_from_env_win(self, mock_obj):
+ client = docker.from_env(
+ version=DEFAULT_DOCKER_API_VERSION,
+ max_pool_size=POOL_SIZE
+ )
+ mock_obj.return_value.urlopen.return_value.status = 200
+ client.ping()
+
+ mock_obj.assert_called_once_with("//./pipe/docker_engine",
+ 60,
+ maxsize=POOL_SIZE
+ )
diff --git a/tests/unit/context_test.py b/tests/unit/context_test.py
new file mode 100644
index 0000000..6d6d672
--- /dev/null
+++ b/tests/unit/context_test.py
@@ -0,0 +1,49 @@
+import unittest
+import docker
+import pytest
+from docker.constants import DEFAULT_UNIX_SOCKET
+from docker.constants import DEFAULT_NPIPE
+from docker.constants import IS_WINDOWS_PLATFORM
+from docker.context import ContextAPI, Context
+
+
+class BaseContextTest(unittest.TestCase):
+ @pytest.mark.skipif(
+ IS_WINDOWS_PLATFORM, reason='Linux specific path check'
+ )
+ def test_url_compatibility_on_linux(self):
+ c = Context("test")
+ assert c.Host == DEFAULT_UNIX_SOCKET.strip("http+")
+
+ @pytest.mark.skipif(
+ not IS_WINDOWS_PLATFORM, reason='Windows specific path check'
+ )
+ def test_url_compatibility_on_windows(self):
+ c = Context("test")
+ assert c.Host == DEFAULT_NPIPE
+
+ def test_fail_on_default_context_create(self):
+ with pytest.raises(docker.errors.ContextException):
+ ContextAPI.create_context("default")
+
+ def test_default_in_context_list(self):
+ found = False
+ ctx = ContextAPI.contexts()
+ for c in ctx:
+ if c.Name == "default":
+ found = True
+ assert found is True
+
+ def test_get_current_context(self):
+ assert ContextAPI.get_current_context().Name == "default"
+
+ def test_https_host(self):
+ c = Context("test", host="tcp://testdomain:8080", tls=True)
+ assert c.Host == "https://testdomain:8080"
+
+ def test_context_inspect_without_params(self):
+ ctx = ContextAPI.inspect_context()
+ assert ctx["Name"] == "default"
+ assert ctx["Metadata"]["StackOrchestrator"] == "swarm"
+ assert ctx["Endpoints"]["docker"]["Host"] in [
+ DEFAULT_NPIPE, DEFAULT_UNIX_SOCKET.strip("http+")]
diff --git a/tests/unit/dockertypes_test.py b/tests/unit/dockertypes_test.py
index 0689d07..f3d562e 100644
--- a/tests/unit/dockertypes_test.py
+++ b/tests/unit/dockertypes_test.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import unittest
import pytest
@@ -11,11 +9,7 @@ from docker.types import (
IPAMPool, LogConfig, Mount, ServiceMode, Ulimit,
)
from docker.types.services import convert_service_ports
-
-try:
- from unittest import mock
-except: # noqa: E722
- import mock
+from unittest import mock
def create_host_config(*args, **kwargs):
@@ -331,10 +325,26 @@ class ServiceModeTest(unittest.TestCase):
assert mode.mode == 'global'
assert mode.replicas is None
+ def test_replicated_job_simple(self):
+ mode = ServiceMode('replicated-job')
+ assert mode == {'ReplicatedJob': {}}
+ assert mode.mode == 'ReplicatedJob'
+ assert mode.replicas is None
+
+ def test_global_job_simple(self):
+ mode = ServiceMode('global-job')
+ assert mode == {'GlobalJob': {}}
+ assert mode.mode == 'GlobalJob'
+ assert mode.replicas is None
+
def test_global_replicas_error(self):
with pytest.raises(InvalidArgument):
ServiceMode('global', 21)
+ def test_global_job_replicas_simple(self):
+ with pytest.raises(InvalidArgument):
+ ServiceMode('global-job', 21)
+
def test_replicated_replicas(self):
mode = ServiceMode('replicated', 21)
assert mode == {'replicated': {'Replicas': 21}}
diff --git a/tests/unit/errors_test.py b/tests/unit/errors_test.py
index 2134f86..f8c3a66 100644
--- a/tests/unit/errors_test.py
+++ b/tests/unit/errors_test.py
@@ -101,17 +101,17 @@ class APIErrorTest(unittest.TestCase):
assert err.is_error() is True
def test_create_error_from_exception(self):
- resp = requests.Response()
- resp.status_code = 500
- err = APIError('')
+ resp = requests.Response()
+ resp.status_code = 500
+ err = APIError('')
+ try:
+ resp.raise_for_status()
+ except requests.exceptions.HTTPError as e:
try:
- resp.raise_for_status()
- except requests.exceptions.HTTPError as e:
- try:
- create_api_error_from_http_exception(e)
- except APIError as e:
- err = e
- assert err.is_server_error() is True
+ create_api_error_from_http_exception(e)
+ except APIError as e:
+ err = e
+ assert err.is_server_error() is True
class ContainerErrorTest(unittest.TestCase):
@@ -126,7 +126,7 @@ class ContainerErrorTest(unittest.TestCase):
err = ContainerError(container, exit_status, command, image, stderr)
msg = ("Command '{}' in image '{}' returned non-zero exit status {}"
- ).format(command, image, exit_status, stderr)
+ ).format(command, image, exit_status)
assert str(err) == msg
def test_container_with_stderr(self):
diff --git a/tests/unit/fake_api.py b/tests/unit/fake_api.py
index e609b64..6acfb64 100644
--- a/tests/unit/fake_api.py
+++ b/tests/unit/fake_api.py
@@ -1,12 +1,13 @@
-from . import fake_stat
from docker import constants
-CURRENT_VERSION = 'v{0}'.format(constants.DEFAULT_DOCKER_API_VERSION)
+from . import fake_stat
+
+CURRENT_VERSION = f'v{constants.DEFAULT_DOCKER_API_VERSION}'
-FAKE_CONTAINER_ID = '3cc2351ab11b'
-FAKE_IMAGE_ID = 'e9aa60c60128'
-FAKE_EXEC_ID = 'd5d177f121dc'
-FAKE_NETWORK_ID = '33fb6a3462b8'
+FAKE_CONTAINER_ID = '81cf499cc928ce3fedc250a080d2b9b978df20e4517304c45211e8a68b33e254' # noqa: E501
+FAKE_IMAGE_ID = 'sha256:fe7a8fc91d3f17835cbb3b86a1c60287500ab01a53bc79c4497d09f07a3f0688' # noqa: E501
+FAKE_EXEC_ID = 'b098ec855f10434b5c7c973c78484208223a83f663ddaefb0f02a242840cb1c7' # noqa: E501
+FAKE_NETWORK_ID = '1999cfb42e414483841a125ade3c276c3cb80cb3269b14e339354ac63a31b02c' # noqa: E501
FAKE_IMAGE_NAME = 'test_image'
FAKE_TARBALL_PATH = '/path/to/tarball'
FAKE_REPO_NAME = 'repo'
@@ -16,6 +17,8 @@ FAKE_URL = 'myurl'
FAKE_PATH = '/path'
FAKE_VOLUME_NAME = 'perfectcherryblossom'
FAKE_NODE_ID = '24ifsmvkjbyhk'
+FAKE_SECRET_ID = 'epdyrw4tsi03xy3deu8g8ly6o'
+FAKE_SECRET_NAME = 'super_secret'
# Each method is prefixed with HTTP method (get, post...)
# for clarity and readability
@@ -511,102 +514,108 @@ def post_fake_network_disconnect():
return 200, None
+def post_fake_secret():
+ status_code = 200
+ response = {'ID': FAKE_SECRET_ID}
+ return status_code, response
+
+
# Maps real api url to fake response callback
prefix = 'http+docker://localhost'
if constants.IS_WINDOWS_PLATFORM:
prefix = 'http+docker://localnpipe'
fake_responses = {
- '{0}/version'.format(prefix):
+ f'{prefix}/version':
get_fake_version,
- '{1}/{0}/version'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/version':
get_fake_version,
- '{1}/{0}/info'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/info':
get_fake_info,
- '{1}/{0}/auth'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/auth':
post_fake_auth,
- '{1}/{0}/_ping'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/_ping':
get_fake_ping,
- '{1}/{0}/images/search'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/search':
get_fake_search,
- '{1}/{0}/images/json'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/json':
get_fake_images,
- '{1}/{0}/images/test_image/history'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/test_image/history':
get_fake_image_history,
- '{1}/{0}/images/create'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/create':
post_fake_import_image,
- '{1}/{0}/containers/json'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/json':
get_fake_containers,
- '{1}/{0}/containers/3cc2351ab11b/start'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/start':
post_fake_start_container,
- '{1}/{0}/containers/3cc2351ab11b/resize'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/resize':
post_fake_resize_container,
- '{1}/{0}/containers/3cc2351ab11b/json'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/json':
get_fake_inspect_container,
- '{1}/{0}/containers/3cc2351ab11b/rename'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/rename':
post_fake_rename_container,
- '{1}/{0}/images/e9aa60c60128/tag'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/{FAKE_IMAGE_ID}/tag':
post_fake_tag_image,
- '{1}/{0}/containers/3cc2351ab11b/wait'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/wait':
get_fake_wait,
- '{1}/{0}/containers/3cc2351ab11b/logs'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/logs':
get_fake_logs,
- '{1}/{0}/containers/3cc2351ab11b/changes'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/changes':
get_fake_diff,
- '{1}/{0}/containers/3cc2351ab11b/export'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/export':
get_fake_export,
- '{1}/{0}/containers/3cc2351ab11b/update'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/update':
post_fake_update_container,
- '{1}/{0}/containers/3cc2351ab11b/exec'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/exec':
post_fake_exec_create,
- '{1}/{0}/exec/d5d177f121dc/start'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/exec/{FAKE_EXEC_ID}/start':
post_fake_exec_start,
- '{1}/{0}/exec/d5d177f121dc/json'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/exec/{FAKE_EXEC_ID}/json':
get_fake_exec_inspect,
- '{1}/{0}/exec/d5d177f121dc/resize'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/exec/{FAKE_EXEC_ID}/resize':
post_fake_exec_resize,
- '{1}/{0}/containers/3cc2351ab11b/stats'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/stats':
get_fake_stats,
- '{1}/{0}/containers/3cc2351ab11b/top'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/top':
get_fake_top,
- '{1}/{0}/containers/3cc2351ab11b/stop'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/stop':
post_fake_stop_container,
- '{1}/{0}/containers/3cc2351ab11b/kill'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/kill':
post_fake_kill_container,
- '{1}/{0}/containers/3cc2351ab11b/pause'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/pause':
post_fake_pause_container,
- '{1}/{0}/containers/3cc2351ab11b/unpause'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/unpause':
post_fake_unpause_container,
- '{1}/{0}/containers/3cc2351ab11b/restart'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}/restart':
post_fake_restart_container,
- '{1}/{0}/containers/3cc2351ab11b'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/{FAKE_CONTAINER_ID}':
delete_fake_remove_container,
- '{1}/{0}/images/create'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/create':
post_fake_image_create,
- '{1}/{0}/images/e9aa60c60128'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/{FAKE_IMAGE_ID}':
delete_fake_remove_image,
- '{1}/{0}/images/e9aa60c60128/get'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/{FAKE_IMAGE_ID}/get':
get_fake_get_image,
- '{1}/{0}/images/load'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/load':
post_fake_load_image,
- '{1}/{0}/images/test_image/json'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/test_image/json':
get_fake_inspect_image,
- '{1}/{0}/images/test_image/insert'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/test_image/insert':
get_fake_insert_image,
- '{1}/{0}/images/test_image/push'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/images/test_image/push':
post_fake_push,
- '{1}/{0}/commit'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/commit':
post_fake_commit,
- '{1}/{0}/containers/create'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/containers/create':
post_fake_create_container,
- '{1}/{0}/build'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/build':
post_fake_build_container,
- '{1}/{0}/events'.format(CURRENT_VERSION, prefix):
+ f'{prefix}/{CURRENT_VERSION}/events':
get_fake_events,
- ('{1}/{0}/volumes'.format(CURRENT_VERSION, prefix), 'GET'):
+ (f'{prefix}/{CURRENT_VERSION}/volumes', 'GET'):
get_fake_volume_list,
- ('{1}/{0}/volumes/create'.format(CURRENT_VERSION, prefix), 'POST'):
+ (f'{prefix}/{CURRENT_VERSION}/volumes/create', 'POST'):
get_fake_volume,
('{1}/{0}/volumes/{2}'.format(
CURRENT_VERSION, prefix, FAKE_VOLUME_NAME
@@ -620,11 +629,11 @@ fake_responses = {
CURRENT_VERSION, prefix, FAKE_NODE_ID
), 'POST'):
post_fake_update_node,
- ('{1}/{0}/swarm/join'.format(CURRENT_VERSION, prefix), 'POST'):
+ (f'{prefix}/{CURRENT_VERSION}/swarm/join', 'POST'):
post_fake_join_swarm,
- ('{1}/{0}/networks'.format(CURRENT_VERSION, prefix), 'GET'):
+ (f'{prefix}/{CURRENT_VERSION}/networks', 'GET'):
get_fake_network_list,
- ('{1}/{0}/networks/create'.format(CURRENT_VERSION, prefix), 'POST'):
+ (f'{prefix}/{CURRENT_VERSION}/networks/create', 'POST'):
post_fake_network,
('{1}/{0}/networks/{2}'.format(
CURRENT_VERSION, prefix, FAKE_NETWORK_ID
@@ -642,4 +651,6 @@ fake_responses = {
CURRENT_VERSION, prefix, FAKE_NETWORK_ID
), 'POST'):
post_fake_network_disconnect,
+ f'{prefix}/{CURRENT_VERSION}/secrets/create':
+ post_fake_secret,
}
diff --git a/tests/unit/fake_api_client.py b/tests/unit/fake_api_client.py
index 2147bfd..95cf63b 100644
--- a/tests/unit/fake_api_client.py
+++ b/tests/unit/fake_api_client.py
@@ -1,20 +1,17 @@
import copy
-import docker
+import docker
+from docker.constants import DEFAULT_DOCKER_API_VERSION
+from unittest import mock
from . import fake_api
-try:
- from unittest import mock
-except ImportError:
- import mock
-
class CopyReturnMagicMock(mock.MagicMock):
"""
A MagicMock which deep copies every return value.
"""
def _mock_call(self, *args, **kwargs):
- ret = super(CopyReturnMagicMock, self)._mock_call(*args, **kwargs)
+ ret = super()._mock_call(*args, **kwargs)
if isinstance(ret, (dict, list)):
ret = copy.deepcopy(ret)
return ret
@@ -30,7 +27,7 @@ def make_fake_api_client(overrides=None):
if overrides is None:
overrides = {}
- api_client = docker.APIClient()
+ api_client = docker.APIClient(version=DEFAULT_DOCKER_API_VERSION)
mock_attrs = {
'build.return_value': fake_api.FAKE_IMAGE_ID,
'commit.return_value': fake_api.post_fake_commit()[1],
@@ -39,6 +36,7 @@ def make_fake_api_client(overrides=None):
fake_api.post_fake_create_container()[1],
'create_host_config.side_effect': api_client.create_host_config,
'create_network.return_value': fake_api.post_fake_network()[1],
+ 'create_secret.return_value': fake_api.post_fake_secret()[1],
'exec_create.return_value': fake_api.post_fake_exec_create()[1],
'exec_start.return_value': fake_api.post_fake_exec_start()[1],
'images.return_value': fake_api.get_fake_images()[1],
@@ -50,6 +48,7 @@ def make_fake_api_client(overrides=None):
'networks.return_value': fake_api.get_fake_network_list()[1],
'start.return_value': None,
'wait.return_value': {'StatusCode': 0},
+ 'version.return_value': fake_api.get_fake_version()
}
mock_attrs.update(overrides)
mock_client = CopyReturnMagicMock(**mock_attrs)
@@ -62,6 +61,6 @@ def make_fake_client(overrides=None):
"""
Returns a Client with a fake APIClient.
"""
- client = docker.DockerClient()
+ client = docker.DockerClient(version=DEFAULT_DOCKER_API_VERSION)
client.api = make_fake_api_client(overrides)
return client
diff --git a/tests/unit/models_containers_test.py b/tests/unit/models_containers_test.py
index da5f0ab..101708e 100644
--- a/tests/unit/models_containers_test.py
+++ b/tests/unit/models_containers_test.py
@@ -39,6 +39,7 @@ class ContainerCollectionTest(unittest.TestCase):
cap_add=['foo'],
cap_drop=['bar'],
cgroup_parent='foobar',
+ cgroupns='host',
cpu_period=1,
cpu_quota=2,
cpu_shares=5,
@@ -77,6 +78,7 @@ class ContainerCollectionTest(unittest.TestCase):
oom_score_adj=5,
pid_mode='host',
pids_limit=500,
+ platform='linux',
ports={
1111: 4567,
2222: None
@@ -134,6 +136,7 @@ class ContainerCollectionTest(unittest.TestCase):
'BlkioWeight': 2,
'CapAdd': ['foo'],
'CapDrop': ['bar'],
+ 'CgroupnsMode': 'host',
'CgroupParent': 'foobar',
'CpuPeriod': 1,
'CpuQuota': 2,
@@ -186,6 +189,7 @@ class ContainerCollectionTest(unittest.TestCase):
name='somename',
network_disabled=False,
networking_config={'foo': None},
+ platform='linux',
ports=[('1111', 'tcp'), ('2222', 'tcp')],
stdin_open=True,
stop_signal=9,
@@ -233,7 +237,7 @@ class ContainerCollectionTest(unittest.TestCase):
assert container.id == FAKE_CONTAINER_ID
client.api.pull.assert_called_with(
- 'alpine', platform=None, tag=None, stream=True
+ 'alpine', platform=None, tag='latest', all_tags=False, stream=True
)
def test_run_with_error(self):
@@ -314,6 +318,33 @@ class ContainerCollectionTest(unittest.TestCase):
'NetworkMode': 'default'}
)
+ def test_run_platform(self):
+ client = make_fake_client()
+
+ # raise exception on first call, then return normal value
+ client.api.create_container.side_effect = [
+ docker.errors.ImageNotFound(""),
+ client.api.create_container.return_value
+ ]
+
+ client.containers.run(image='alpine', platform='linux/arm64')
+
+ client.api.pull.assert_called_with(
+ 'alpine',
+ tag='latest',
+ all_tags=False,
+ stream=True,
+ platform='linux/arm64',
+ )
+
+ client.api.create_container.assert_called_with(
+ detach=False,
+ platform='linux/arm64',
+ image='alpine',
+ command=None,
+ host_config={'NetworkMode': 'default'},
+ )
+
def test_create(self):
client = make_fake_client()
container = client.containers.create(
@@ -377,6 +408,11 @@ class ContainerCollectionTest(unittest.TestCase):
class ContainerTest(unittest.TestCase):
+ def test_short_id(self):
+ container = Container(attrs={'Id': '8497fe9244dd45cac543eb3c37d8605077'
+ '6800eebef1f3ec2ee111e8ccf12db6'})
+ assert container.short_id == '8497fe9244dd'
+
def test_name(self):
client = make_fake_client()
container = client.containers.get(FAKE_CONTAINER_ID)
@@ -450,7 +486,7 @@ class ContainerTest(unittest.TestCase):
container = client.containers.get(FAKE_CONTAINER_ID)
container.get_archive('foo')
client.api.get_archive.assert_called_with(
- FAKE_CONTAINER_ID, 'foo', DEFAULT_DATA_CHUNK_SIZE
+ FAKE_CONTAINER_ID, 'foo', DEFAULT_DATA_CHUNK_SIZE, False
)
def test_image(self):
diff --git a/tests/unit/models_images_test.py b/tests/unit/models_images_test.py
index fd894ab..3478c3f 100644
--- a/tests/unit/models_images_test.py
+++ b/tests/unit/models_images_test.py
@@ -44,9 +44,25 @@ class ImageCollectionTest(unittest.TestCase):
def test_pull(self):
client = make_fake_client()
- image = client.images.pull('test_image:latest')
+ image = client.images.pull('test_image:test')
client.api.pull.assert_called_with(
- 'test_image', tag='latest', stream=True
+ 'test_image', tag='test', all_tags=False, stream=True
+ )
+ client.api.inspect_image.assert_called_with('test_image:test')
+ assert isinstance(image, Image)
+ assert image.id == FAKE_IMAGE_ID
+
+ def test_pull_tag_precedence(self):
+ client = make_fake_client()
+ image = client.images.pull('test_image:latest', tag='test')
+ client.api.pull.assert_called_with(
+ 'test_image', tag='test', all_tags=False, stream=True
+ )
+ client.api.inspect_image.assert_called_with('test_image:test')
+
+ image = client.images.pull('test_image')
+ client.api.pull.assert_called_with(
+ 'test_image', tag='latest', all_tags=False, stream=True
)
client.api.inspect_image.assert_called_with('test_image:latest')
assert isinstance(image, Image)
@@ -54,9 +70,9 @@ class ImageCollectionTest(unittest.TestCase):
def test_pull_multiple(self):
client = make_fake_client()
- images = client.images.pull('test_image')
+ images = client.images.pull('test_image', all_tags=True)
client.api.pull.assert_called_with(
- 'test_image', tag=None, stream=True
+ 'test_image', tag='latest', all_tags=True, stream=True
)
client.api.images.assert_called_with(
all=False, name='test_image', filters=None
@@ -96,16 +112,21 @@ class ImageCollectionTest(unittest.TestCase):
client.images.search('test')
client.api.search.assert_called_with('test')
+ def test_search_limit(self):
+ client = make_fake_client()
+ client.images.search('test', limit=5)
+ client.api.search.assert_called_with('test', limit=5)
+
class ImageTest(unittest.TestCase):
def test_short_id(self):
image = Image(attrs={'Id': 'sha256:b6846070672ce4e8f1f91564ea6782bd675'
'f69d65a6f73ef6262057ad0a15dcd'})
- assert image.short_id == 'sha256:b684607067'
+ assert image.short_id == 'sha256:b6846070672c'
image = Image(attrs={'Id': 'b6846070672ce4e8f1f91564ea6782bd675'
'f69d65a6f73ef6262057ad0a15dcd'})
- assert image.short_id == 'b684607067'
+ assert image.short_id == 'b6846070672c'
def test_tags(self):
image = Image(attrs={
@@ -129,6 +150,16 @@ class ImageTest(unittest.TestCase):
image.history()
client.api.history.assert_called_with(FAKE_IMAGE_ID)
+ def test_remove(self):
+ client = make_fake_client()
+ image = client.images.get(FAKE_IMAGE_ID)
+ image.remove()
+ client.api.remove_image.assert_called_with(
+ FAKE_IMAGE_ID,
+ force=False,
+ noprune=False,
+ )
+
def test_save(self):
client = make_fake_client()
image = client.images.get(FAKE_IMAGE_ID)
diff --git a/tests/unit/models_resources_test.py b/tests/unit/models_resources_test.py
index 5af24ee..11dea29 100644
--- a/tests/unit/models_resources_test.py
+++ b/tests/unit/models_resources_test.py
@@ -16,7 +16,7 @@ class ModelTest(unittest.TestCase):
def test_hash(self):
client = make_fake_client()
container1 = client.containers.get(FAKE_CONTAINER_ID)
- my_set = set([container1])
+ my_set = {container1}
assert len(my_set) == 1
container2 = client.containers.get(FAKE_CONTAINER_ID)
diff --git a/tests/unit/models_secrets_test.py b/tests/unit/models_secrets_test.py
new file mode 100644
index 0000000..1c261a8
--- /dev/null
+++ b/tests/unit/models_secrets_test.py
@@ -0,0 +1,11 @@
+import unittest
+
+from .fake_api_client import make_fake_client
+from .fake_api import FAKE_SECRET_NAME
+
+
+class CreateServiceTest(unittest.TestCase):
+ def test_secrets_repr(self):
+ client = make_fake_client()
+ secret = client.secrets.create(name="super_secret", data="secret")
+ assert secret.__repr__() == f"<Secret: '{FAKE_SECRET_NAME}'>"
diff --git a/tests/unit/models_services_test.py b/tests/unit/models_services_test.py
index a4ac50c..45c63ac 100644
--- a/tests/unit/models_services_test.py
+++ b/tests/unit/models_services_test.py
@@ -11,6 +11,7 @@ class CreateServiceKwargsTest(unittest.TestCase):
'labels': {'key': 'value'},
'hostname': 'test_host',
'mode': 'global',
+ 'rollback_config': {'rollback': 'config'},
'update_config': {'update': 'config'},
'networks': ['somenet'],
'endpoint_spec': {'blah': 'blah'},
@@ -28,6 +29,8 @@ class CreateServiceKwargsTest(unittest.TestCase):
'constraints': ['foo=bar'],
'preferences': ['bar=baz'],
'platforms': [('x86_64', 'linux')],
+ 'maxreplicas': 1,
+ 'sysctls': {'foo': 'bar'}
})
task_template = kwargs.pop('task_template')
@@ -36,24 +39,26 @@ class CreateServiceKwargsTest(unittest.TestCase):
'name': 'somename',
'labels': {'key': 'value'},
'mode': 'global',
+ 'rollback_config': {'rollback': 'config'},
'update_config': {'update': 'config'},
'endpoint_spec': {'blah': 'blah'},
}
- assert set(task_template.keys()) == set([
+ assert set(task_template.keys()) == {
'ContainerSpec', 'Resources', 'RestartPolicy', 'Placement',
'LogDriver', 'Networks'
- ])
+ }
assert task_template['Placement'] == {
'Constraints': ['foo=bar'],
'Preferences': ['bar=baz'],
'Platforms': [{'Architecture': 'x86_64', 'OS': 'linux'}],
+ 'MaxReplicas': 1,
}
assert task_template['LogDriver'] == {
'Name': 'logdriver',
'Options': {'foo': 'bar'}
}
assert task_template['Networks'] == [{'Target': 'somenet'}]
- assert set(task_template['ContainerSpec'].keys()) == set([
+ assert set(task_template['ContainerSpec'].keys()) == {
'Image', 'Command', 'Args', 'Hostname', 'Env', 'Dir', 'User',
- 'Labels', 'Mounts', 'StopGracePeriod'
- ])
+ 'Labels', 'Mounts', 'StopGracePeriod', 'Sysctls'
+ }
diff --git a/tests/unit/sshadapter_test.py b/tests/unit/sshadapter_test.py
new file mode 100644
index 0000000..874239a
--- /dev/null
+++ b/tests/unit/sshadapter_test.py
@@ -0,0 +1,39 @@
+import unittest
+import docker
+from docker.transport.sshconn import SSHSocket
+
+
+class SSHAdapterTest(unittest.TestCase):
+ @staticmethod
+ def test_ssh_hostname_prefix_trim():
+ conn = docker.transport.SSHHTTPAdapter(
+ base_url="ssh://user@hostname:1234", shell_out=True)
+ assert conn.ssh_host == "user@hostname:1234"
+
+ @staticmethod
+ def test_ssh_parse_url():
+ c = SSHSocket(host="user@hostname:1234")
+ assert c.host == "hostname"
+ assert c.port == "1234"
+ assert c.user == "user"
+
+ @staticmethod
+ def test_ssh_parse_hostname_only():
+ c = SSHSocket(host="hostname")
+ assert c.host == "hostname"
+ assert c.port is None
+ assert c.user is None
+
+ @staticmethod
+ def test_ssh_parse_user_and_hostname():
+ c = SSHSocket(host="user@hostname")
+ assert c.host == "hostname"
+ assert c.port is None
+ assert c.user == "user"
+
+ @staticmethod
+ def test_ssh_parse_hostname_and_port():
+ c = SSHSocket(host="hostname:22")
+ assert c.host == "hostname"
+ assert c.port == "22"
+ assert c.user is None
diff --git a/tests/unit/ssladapter_test.py b/tests/unit/ssladapter_test.py
index 73b7336..d3f2407 100644
--- a/tests/unit/ssladapter_test.py
+++ b/tests/unit/ssladapter_test.py
@@ -1,15 +1,8 @@
import unittest
-from docker.transport import ssladapter
-import pytest
+from ssl import match_hostname, CertificateError
-try:
- from backports.ssl_match_hostname import (
- match_hostname, CertificateError
- )
-except ImportError:
- from ssl import (
- match_hostname, CertificateError
- )
+import pytest
+from docker.transport import ssladapter
try:
from ssl import OP_NO_SSLv3, OP_NO_SSLv2, OP_NO_TLSv1
@@ -32,30 +25,30 @@ class SSLAdapterTest(unittest.TestCase):
class MatchHostnameTest(unittest.TestCase):
cert = {
'issuer': (
- (('countryName', u'US'),),
- (('stateOrProvinceName', u'California'),),
- (('localityName', u'San Francisco'),),
- (('organizationName', u'Docker Inc'),),
- (('organizationalUnitName', u'Docker-Python'),),
- (('commonName', u'localhost'),),
- (('emailAddress', u'info@docker.com'),)
+ (('countryName', 'US'),),
+ (('stateOrProvinceName', 'California'),),
+ (('localityName', 'San Francisco'),),
+ (('organizationName', 'Docker Inc'),),
+ (('organizationalUnitName', 'Docker-Python'),),
+ (('commonName', 'localhost'),),
+ (('emailAddress', 'info@docker.com'),)
),
'notAfter': 'Mar 25 23:08:23 2030 GMT',
- 'notBefore': u'Mar 25 23:08:23 2016 GMT',
- 'serialNumber': u'BD5F894C839C548F',
+ 'notBefore': 'Mar 25 23:08:23 2016 GMT',
+ 'serialNumber': 'BD5F894C839C548F',
'subject': (
- (('countryName', u'US'),),
- (('stateOrProvinceName', u'California'),),
- (('localityName', u'San Francisco'),),
- (('organizationName', u'Docker Inc'),),
- (('organizationalUnitName', u'Docker-Python'),),
- (('commonName', u'localhost'),),
- (('emailAddress', u'info@docker.com'),)
+ (('countryName', 'US'),),
+ (('stateOrProvinceName', 'California'),),
+ (('localityName', 'San Francisco'),),
+ (('organizationName', 'Docker Inc'),),
+ (('organizationalUnitName', 'Docker-Python'),),
+ (('commonName', 'localhost'),),
+ (('emailAddress', 'info@docker.com'),)
),
'subjectAltName': (
- ('DNS', u'localhost'),
- ('DNS', u'*.gensokyo.jp'),
- ('IP Address', u'127.0.0.1'),
+ ('DNS', 'localhost'),
+ ('DNS', '*.gensokyo.jp'),
+ ('IP Address', '127.0.0.1'),
),
'version': 3
}
diff --git a/tests/unit/swarm_test.py b/tests/unit/swarm_test.py
index 4385380..aee1b9e 100644
--- a/tests/unit/swarm_test.py
+++ b/tests/unit/swarm_test.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import json
from . import fake_api
diff --git a/tests/unit/utils_build_test.py b/tests/unit/utils_build_test.py
index 012f15b..fa7d833 100644
--- a/tests/unit/utils_build_test.py
+++ b/tests/unit/utils_build_test.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
import os
import os.path
import shutil
@@ -82,7 +80,7 @@ class ExcludePathsTest(unittest.TestCase):
assert sorted(paths) == sorted(set(paths))
def test_wildcard_exclude(self):
- assert self.exclude(['*']) == set(['Dockerfile', '.dockerignore'])
+ assert self.exclude(['*']) == {'Dockerfile', '.dockerignore'}
def test_exclude_dockerfile_dockerignore(self):
"""
@@ -99,18 +97,18 @@ class ExcludePathsTest(unittest.TestCase):
If we're using a custom Dockerfile, make sure that's not
excluded.
"""
- assert self.exclude(['*'], dockerfile='Dockerfile.alt') == set(
- ['Dockerfile.alt', '.dockerignore']
- )
+ assert self.exclude(['*'], dockerfile='Dockerfile.alt') == {
+ 'Dockerfile.alt', '.dockerignore'
+ }
assert self.exclude(
['*'], dockerfile='foo/Dockerfile3'
- ) == convert_paths(set(['foo/Dockerfile3', '.dockerignore']))
+ ) == convert_paths({'foo/Dockerfile3', '.dockerignore'})
# https://github.com/docker/docker-py/issues/1956
assert self.exclude(
['*'], dockerfile='./foo/Dockerfile3'
- ) == convert_paths(set(['foo/Dockerfile3', '.dockerignore']))
+ ) == convert_paths({'foo/Dockerfile3', '.dockerignore'})
def test_exclude_dockerfile_child(self):
includes = self.exclude(['foo/'], dockerfile='foo/Dockerfile3')
@@ -119,56 +117,56 @@ class ExcludePathsTest(unittest.TestCase):
def test_single_filename(self):
assert self.exclude(['a.py']) == convert_paths(
- self.all_paths - set(['a.py'])
+ self.all_paths - {'a.py'}
)
def test_single_filename_leading_dot_slash(self):
assert self.exclude(['./a.py']) == convert_paths(
- self.all_paths - set(['a.py'])
+ self.all_paths - {'a.py'}
)
# As odd as it sounds, a filename pattern with a trailing slash on the
# end *will* result in that file being excluded.
def test_single_filename_trailing_slash(self):
assert self.exclude(['a.py/']) == convert_paths(
- self.all_paths - set(['a.py'])
+ self.all_paths - {'a.py'}
)
def test_wildcard_filename_start(self):
assert self.exclude(['*.py']) == convert_paths(
- self.all_paths - set(['a.py', 'b.py', 'cde.py'])
+ self.all_paths - {'a.py', 'b.py', 'cde.py'}
)
def test_wildcard_with_exception(self):
assert self.exclude(['*.py', '!b.py']) == convert_paths(
- self.all_paths - set(['a.py', 'cde.py'])
+ self.all_paths - {'a.py', 'cde.py'}
)
def test_wildcard_with_wildcard_exception(self):
assert self.exclude(['*.*', '!*.go']) == convert_paths(
- self.all_paths - set([
+ self.all_paths - {
'a.py', 'b.py', 'cde.py', 'Dockerfile.alt',
- ])
+ }
)
def test_wildcard_filename_end(self):
assert self.exclude(['a.*']) == convert_paths(
- self.all_paths - set(['a.py', 'a.go'])
+ self.all_paths - {'a.py', 'a.go'}
)
def test_question_mark(self):
assert self.exclude(['?.py']) == convert_paths(
- self.all_paths - set(['a.py', 'b.py'])
+ self.all_paths - {'a.py', 'b.py'}
)
def test_single_subdir_single_filename(self):
assert self.exclude(['foo/a.py']) == convert_paths(
- self.all_paths - set(['foo/a.py'])
+ self.all_paths - {'foo/a.py'}
)
def test_single_subdir_single_filename_leading_slash(self):
assert self.exclude(['/foo/a.py']) == convert_paths(
- self.all_paths - set(['foo/a.py'])
+ self.all_paths - {'foo/a.py'}
)
def test_exclude_include_absolute_path(self):
@@ -176,57 +174,57 @@ class ExcludePathsTest(unittest.TestCase):
assert exclude_paths(
base,
['/*', '!/*.py']
- ) == set(['a.py', 'b.py'])
+ ) == {'a.py', 'b.py'}
def test_single_subdir_with_path_traversal(self):
assert self.exclude(['foo/whoops/../a.py']) == convert_paths(
- self.all_paths - set(['foo/a.py'])
+ self.all_paths - {'foo/a.py'}
)
def test_single_subdir_wildcard_filename(self):
assert self.exclude(['foo/*.py']) == convert_paths(
- self.all_paths - set(['foo/a.py', 'foo/b.py'])
+ self.all_paths - {'foo/a.py', 'foo/b.py'}
)
def test_wildcard_subdir_single_filename(self):
assert self.exclude(['*/a.py']) == convert_paths(
- self.all_paths - set(['foo/a.py', 'bar/a.py'])
+ self.all_paths - {'foo/a.py', 'bar/a.py'}
)
def test_wildcard_subdir_wildcard_filename(self):
assert self.exclude(['*/*.py']) == convert_paths(
- self.all_paths - set(['foo/a.py', 'foo/b.py', 'bar/a.py'])
+ self.all_paths - {'foo/a.py', 'foo/b.py', 'bar/a.py'}
)
def test_directory(self):
assert self.exclude(['foo']) == convert_paths(
- self.all_paths - set([
+ self.all_paths - {
'foo', 'foo/a.py', 'foo/b.py', 'foo/bar', 'foo/bar/a.py',
'foo/Dockerfile3'
- ])
+ }
)
def test_directory_with_trailing_slash(self):
assert self.exclude(['foo']) == convert_paths(
- self.all_paths - set([
+ self.all_paths - {
'foo', 'foo/a.py', 'foo/b.py',
'foo/bar', 'foo/bar/a.py', 'foo/Dockerfile3'
- ])
+ }
)
def test_directory_with_single_exception(self):
assert self.exclude(['foo', '!foo/bar/a.py']) == convert_paths(
- self.all_paths - set([
+ self.all_paths - {
'foo/a.py', 'foo/b.py', 'foo', 'foo/bar',
'foo/Dockerfile3'
- ])
+ }
)
def test_directory_with_subdir_exception(self):
assert self.exclude(['foo', '!foo/bar']) == convert_paths(
- self.all_paths - set([
+ self.all_paths - {
'foo/a.py', 'foo/b.py', 'foo', 'foo/Dockerfile3'
- ])
+ }
)
@pytest.mark.skipif(
@@ -234,21 +232,21 @@ class ExcludePathsTest(unittest.TestCase):
)
def test_directory_with_subdir_exception_win32_pathsep(self):
assert self.exclude(['foo', '!foo\\bar']) == convert_paths(
- self.all_paths - set([
+ self.all_paths - {
'foo/a.py', 'foo/b.py', 'foo', 'foo/Dockerfile3'
- ])
+ }
)
def test_directory_with_wildcard_exception(self):
assert self.exclude(['foo', '!foo/*.py']) == convert_paths(
- self.all_paths - set([
+ self.all_paths - {
'foo/bar', 'foo/bar/a.py', 'foo', 'foo/Dockerfile3'
- ])
+ }
)
def test_subdirectory(self):
assert self.exclude(['foo/bar']) == convert_paths(
- self.all_paths - set(['foo/bar', 'foo/bar/a.py'])
+ self.all_paths - {'foo/bar', 'foo/bar/a.py'}
)
@pytest.mark.skipif(
@@ -256,52 +254,52 @@ class ExcludePathsTest(unittest.TestCase):
)
def test_subdirectory_win32_pathsep(self):
assert self.exclude(['foo\\bar']) == convert_paths(
- self.all_paths - set(['foo/bar', 'foo/bar/a.py'])
+ self.all_paths - {'foo/bar', 'foo/bar/a.py'}
)
def test_double_wildcard(self):
assert self.exclude(['**/a.py']) == convert_paths(
- self.all_paths - set(
- ['a.py', 'foo/a.py', 'foo/bar/a.py', 'bar/a.py']
- )
+ self.all_paths - {
+ 'a.py', 'foo/a.py', 'foo/bar/a.py', 'bar/a.py'
+ }
)
assert self.exclude(['foo/**/bar']) == convert_paths(
- self.all_paths - set(['foo/bar', 'foo/bar/a.py'])
+ self.all_paths - {'foo/bar', 'foo/bar/a.py'}
)
def test_single_and_double_wildcard(self):
assert self.exclude(['**/target/*/*']) == convert_paths(
- self.all_paths - set(
- ['target/subdir/file.txt',
- 'subdir/target/subdir/file.txt',
- 'subdir/subdir2/target/subdir/file.txt']
- )
+ self.all_paths - {
+ 'target/subdir/file.txt',
+ 'subdir/target/subdir/file.txt',
+ 'subdir/subdir2/target/subdir/file.txt'
+ }
)
def test_trailing_double_wildcard(self):
assert self.exclude(['subdir/**']) == convert_paths(
- self.all_paths - set(
- ['subdir/file.txt',
- 'subdir/target/file.txt',
- 'subdir/target/subdir/file.txt',
- 'subdir/subdir2/file.txt',
- 'subdir/subdir2/target/file.txt',
- 'subdir/subdir2/target/subdir/file.txt',
- 'subdir/target',
- 'subdir/target/subdir',
- 'subdir/subdir2',
- 'subdir/subdir2/target',
- 'subdir/subdir2/target/subdir']
- )
+ self.all_paths - {
+ 'subdir/file.txt',
+ 'subdir/target/file.txt',
+ 'subdir/target/subdir/file.txt',
+ 'subdir/subdir2/file.txt',
+ 'subdir/subdir2/target/file.txt',
+ 'subdir/subdir2/target/subdir/file.txt',
+ 'subdir/target',
+ 'subdir/target/subdir',
+ 'subdir/subdir2',
+ 'subdir/subdir2/target',
+ 'subdir/subdir2/target/subdir'
+ }
)
def test_double_wildcard_with_exception(self):
assert self.exclude(['**', '!bar', '!foo/bar']) == convert_paths(
- set([
+ {
'foo/bar', 'foo/bar/a.py', 'bar', 'bar/a.py', 'Dockerfile',
'.dockerignore',
- ])
+ }
)
def test_include_wildcard(self):
@@ -324,7 +322,7 @@ class ExcludePathsTest(unittest.TestCase):
assert exclude_paths(
base,
['*.md', '!README*.md', 'README-secret.md']
- ) == set(['README.md', 'README-bis.md'])
+ ) == {'README.md', 'README-bis.md'}
def test_parent_directory(self):
base = make_tree(
@@ -335,12 +333,12 @@ class ExcludePathsTest(unittest.TestCase):
# Dockerignore reference stipulates that absolute paths are
# equivalent to relative paths, hence /../foo should be
# equivalent to ../foo. It also stipulates that paths are run
- # through Go's filepath.Clean, which explicitely "replace
+ # through Go's filepath.Clean, which explicitly "replace
# "/.." by "/" at the beginning of a path".
assert exclude_paths(
base,
['../a.py', '/../b.py']
- ) == set(['c.py'])
+ ) == {'c.py'}
class TarTest(unittest.TestCase):
@@ -374,14 +372,14 @@ class TarTest(unittest.TestCase):
'.dockerignore',
]
- expected_names = set([
+ expected_names = {
'Dockerfile',
'.dockerignore',
'a.go',
'b.py',
'bar',
'bar/a.py',
- ])
+ }
base = make_tree(dirs, files)
self.addCleanup(shutil.rmtree, base)
@@ -413,7 +411,7 @@ class TarTest(unittest.TestCase):
with pytest.raises(IOError) as ei:
tar(base)
- assert 'Can not read file in context: {}'.format(full_path) in (
+ assert f'Can not read file in context: {full_path}' in (
ei.exconly()
)
diff --git a/tests/unit/utils_config_test.py b/tests/unit/utils_config_test.py
index b0934f9..27d5a7c 100644
--- a/tests/unit/utils_config_test.py
+++ b/tests/unit/utils_config_test.py
@@ -5,14 +5,10 @@ import tempfile
import json
from pytest import mark, fixture
+from unittest import mock
from docker.utils import config
-try:
- from unittest import mock
-except ImportError:
- import mock
-
class FindConfigFileTest(unittest.TestCase):
diff --git a/tests/unit/utils_json_stream_test.py b/tests/unit/utils_json_stream_test.py
index f7aefd0..821ebe4 100644
--- a/tests/unit/utils_json_stream_test.py
+++ b/tests/unit/utils_json_stream_test.py
@@ -1,11 +1,7 @@
-# encoding: utf-8
-from __future__ import absolute_import
-from __future__ import unicode_literals
-
from docker.utils.json_stream import json_splitter, stream_as_text, json_stream
-class TestJsonSplitter(object):
+class TestJsonSplitter:
def test_json_splitter_no_object(self):
data = '{"foo": "bar'
@@ -20,7 +16,7 @@ class TestJsonSplitter(object):
assert json_splitter(data) == ({'foo': 'bar'}, '{"next": "obj"}')
-class TestStreamAsText(object):
+class TestStreamAsText:
def test_stream_with_non_utf_unicode_character(self):
stream = [b'\xed\xf3\xf3']
@@ -28,12 +24,12 @@ class TestStreamAsText(object):
assert output == '���'
def test_stream_with_utf_character(self):
- stream = ['ěĝ'.encode('utf-8')]
+ stream = ['ěĝ'.encode()]
output, = stream_as_text(stream)
assert output == 'ěĝ'
-class TestJsonStream(object):
+class TestJsonStream:
def test_with_falsy_entries(self):
stream = [
diff --git a/tests/unit/utils_proxy_test.py b/tests/unit/utils_proxy_test.py
index ff0e14b..2da6040 100644
--- a/tests/unit/utils_proxy_test.py
+++ b/tests/unit/utils_proxy_test.py
@@ -1,7 +1,4 @@
-# -*- coding: utf-8 -*-
-
import unittest
-import six
from docker.utils.proxy import ProxyConfig
@@ -65,7 +62,7 @@ class ProxyConfigTest(unittest.TestCase):
# Proxy config is non null, env is None.
self.assertSetEqual(
set(CONFIG.inject_proxy_environment(None)),
- set(['{}={}'.format(k, v) for k, v in six.iteritems(ENV)]))
+ {f'{k}={v}' for k, v in ENV.items()})
# Proxy config is null, env is None.
self.assertIsNone(ProxyConfig().inject_proxy_environment(None), None)
@@ -74,7 +71,7 @@ class ProxyConfigTest(unittest.TestCase):
# Proxy config is non null, env is non null
actual = CONFIG.inject_proxy_environment(env)
- expected = ['{}={}'.format(k, v) for k, v in six.iteritems(ENV)] + env
+ expected = [f'{k}={v}' for k, v in ENV.items()] + env
# It's important that the first 8 variables are the ones from the proxy
# config, and the last 2 are the ones from the input environment
self.assertSetEqual(set(actual[:8]), set(expected[:8]))
diff --git a/tests/unit/utils_test.py b/tests/unit/utils_test.py
index d9cb002..12cb7bd 100644
--- a/tests/unit/utils_test.py
+++ b/tests/unit/utils_test.py
@@ -1,31 +1,22 @@
-# -*- coding: utf-8 -*-
-
import base64
import json
import os
import os.path
import shutil
-import sys
import tempfile
import unittest
-
+import pytest
from docker.api.client import APIClient
-from docker.constants import IS_WINDOWS_PLATFORM
+from docker.constants import IS_WINDOWS_PLATFORM, DEFAULT_DOCKER_API_VERSION
from docker.errors import DockerException
-from docker.utils import (
- convert_filters, convert_volume_binds, decode_json_header, kwargs_from_env,
- parse_bytes, parse_devices, parse_env_file, parse_host,
- parse_repository_tag, split_command, update_headers,
-)
-
+from docker.utils import (convert_filters, convert_volume_binds,
+ decode_json_header, kwargs_from_env, parse_bytes,
+ parse_devices, parse_env_file, parse_host,
+ parse_repository_tag, split_command, update_headers)
from docker.utils.ports import build_port_bindings, split_port
from docker.utils.utils import format_environment
-import pytest
-
-import six
-
TEST_CERT_DIR = os.path.join(
os.path.dirname(__file__),
'testdata/certs',
@@ -41,7 +32,7 @@ class DecoratorsTest(unittest.TestCase):
def f(self, headers=None):
return headers
- client = APIClient()
+ client = APIClient(version=DEFAULT_DOCKER_API_VERSION)
client._general_configs = {}
g = update_headers(f)
@@ -92,6 +83,7 @@ class KwargsFromEnvTest(unittest.TestCase):
assert kwargs['tls'].verify
parsed_host = parse_host(kwargs['base_url'], IS_WINDOWS_PLATFORM, True)
+ kwargs['version'] = DEFAULT_DOCKER_API_VERSION
try:
client = APIClient(**kwargs)
assert parsed_host == client.base_url
@@ -112,6 +104,7 @@ class KwargsFromEnvTest(unittest.TestCase):
assert kwargs['tls'].assert_hostname is True
assert kwargs['tls'].verify is False
parsed_host = parse_host(kwargs['base_url'], IS_WINDOWS_PLATFORM, True)
+ kwargs['version'] = DEFAULT_DOCKER_API_VERSION
try:
client = APIClient(**kwargs)
assert parsed_host == client.base_url
@@ -199,22 +192,22 @@ class ConverVolumeBindsTest(unittest.TestCase):
assert convert_volume_binds(data) == ['/mnt/vol1:/data:rw']
def test_convert_volume_binds_unicode_bytes_input(self):
- expected = [u'/mnt/지연:/unicode/박:rw']
+ expected = ['/mnt/지연:/unicode/박:rw']
data = {
- u'/mnt/지연'.encode('utf-8'): {
- 'bind': u'/unicode/박'.encode('utf-8'),
+ '/mnt/지연'.encode(): {
+ 'bind': '/unicode/박'.encode(),
'mode': 'rw'
}
}
assert convert_volume_binds(data) == expected
def test_convert_volume_binds_unicode_unicode_input(self):
- expected = [u'/mnt/지연:/unicode/박:rw']
+ expected = ['/mnt/지연:/unicode/박:rw']
data = {
- u'/mnt/지연': {
- 'bind': u'/unicode/박',
+ '/mnt/지연': {
+ 'bind': '/unicode/박',
'mode': 'rw'
}
}
@@ -303,17 +296,24 @@ class ParseHostTest(unittest.TestCase):
'[fd12::82d1]:2375/docker/engine': (
'http://[fd12::82d1]:2375/docker/engine'
),
+ 'ssh://[fd12::82d1]': 'ssh://[fd12::82d1]:22',
+ 'ssh://user@[fd12::82d1]:8765': 'ssh://user@[fd12::82d1]:8765',
'ssh://': 'ssh://127.0.0.1:22',
'ssh://user@localhost:22': 'ssh://user@localhost:22',
'ssh://user@remote': 'ssh://user@remote:22',
}
for host in invalid_hosts:
- with pytest.raises(DockerException):
+ msg = f'Should have failed to parse invalid host: {host}'
+ with self.assertRaises(DockerException, msg=msg):
parse_host(host, None)
for host, expected in valid_hosts.items():
- assert parse_host(host, None) == expected
+ self.assertEqual(
+ parse_host(host, None),
+ expected,
+ msg=f'Failed to parse valid host: {host}',
+ )
def test_parse_host_empty_value(self):
unix_socket = 'http+unix:///var/run/docker.sock'
@@ -363,14 +363,14 @@ class ParseRepositoryTagTest(unittest.TestCase):
)
def test_index_image_sha(self):
- assert parse_repository_tag("root@sha256:{0}".format(self.sha)) == (
- "root", "sha256:{0}".format(self.sha)
+ assert parse_repository_tag(f"root@sha256:{self.sha}") == (
+ "root", f"sha256:{self.sha}"
)
def test_private_reg_image_sha(self):
assert parse_repository_tag(
- "url:5000/repo@sha256:{0}".format(self.sha)
- ) == ("url:5000/repo", "sha256:{0}".format(self.sha))
+ f"url:5000/repo@sha256:{self.sha}"
+ ) == ("url:5000/repo", f"sha256:{self.sha}")
class ParseDeviceTest(unittest.TestCase):
@@ -447,11 +447,7 @@ class ParseBytesTest(unittest.TestCase):
parse_bytes("127.0.0.1K")
def test_parse_bytes_float(self):
- with pytest.raises(DockerException):
- parse_bytes("1.5k")
-
- def test_parse_bytes_maxint(self):
- assert parse_bytes("{0}k".format(sys.maxsize)) == sys.maxsize * 1024
+ assert parse_bytes("1.5k") == 1536
class UtilsTest(unittest.TestCase):
@@ -471,20 +467,13 @@ class UtilsTest(unittest.TestCase):
def test_decode_json_header(self):
obj = {'a': 'b', 'c': 1}
data = None
- if six.PY3:
- data = base64.urlsafe_b64encode(bytes(json.dumps(obj), 'utf-8'))
- else:
- data = base64.urlsafe_b64encode(json.dumps(obj))
+ data = base64.urlsafe_b64encode(bytes(json.dumps(obj), 'utf-8'))
decoded_data = decode_json_header(data)
assert obj == decoded_data
class SplitCommandTest(unittest.TestCase):
def test_split_command_with_unicode(self):
- assert split_command(u'echo μμ') == ['echo', 'μμ']
-
- @pytest.mark.skipif(six.PY3, reason="shlex doesn't support bytes in py3")
- def test_split_command_with_bytes(self):
assert split_command('echo μμ') == ['echo', 'μμ']
@@ -549,6 +538,12 @@ class PortsTest(unittest.TestCase):
assert internal_port == ["2000"]
assert external_port == [("2001:abcd:ef00::2", "1000")]
+ def test_split_port_with_ipv6_square_brackets_address(self):
+ internal_port, external_port = split_port(
+ "[2001:abcd:ef00::2]:1000:2000")
+ assert internal_port == ["2000"]
+ assert external_port == [("2001:abcd:ef00::2", "1000")]
+
def test_split_port_invalid(self):
with pytest.raises(ValueError):
split_port("0.0.0.0:1000:2000:tcp")
@@ -628,7 +623,7 @@ class FormatEnvironmentTest(unittest.TestCase):
env_dict = {
'ARTIST_NAME': b'\xec\x86\xa1\xec\xa7\x80\xec\x9d\x80'
}
- assert format_environment(env_dict) == [u'ARTIST_NAME=송지은']
+ assert format_environment(env_dict) == ['ARTIST_NAME=송지은']
def test_format_env_no_value(self):
env_dict = {