mirror of
https://github.com/ansible-collections/community.docker.git
synced 2026-07-29 03:46:55 +00:00
Reformat code with black and isort.
This commit is contained in:
@@ -2,17 +2,20 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from io import StringIO
|
||||
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.compat import mock
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.compat import unittest
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.playbook.play_context import PlayContext
|
||||
from ansible.plugins.loader import connection_loader
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.compat import (
|
||||
mock,
|
||||
unittest,
|
||||
)
|
||||
|
||||
|
||||
class TestDockerConnectionClass(unittest.TestCase):
|
||||
@@ -20,38 +23,69 @@ class TestDockerConnectionClass(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.play_context = PlayContext()
|
||||
self.play_context.prompt = (
|
||||
'[sudo via ansible, key=ouzmdnewuhucvuaabtjmweasarviygqq] password: '
|
||||
"[sudo via ansible, key=ouzmdnewuhucvuaabtjmweasarviygqq] password: "
|
||||
)
|
||||
self.in_stream = StringIO()
|
||||
with mock.patch('ansible_collections.community.docker.plugins.connection.docker.get_bin_path', return_value='docker'):
|
||||
self.dc = connection_loader.get('community.docker.docker', self.play_context, self.in_stream)
|
||||
with mock.patch(
|
||||
"ansible_collections.community.docker.plugins.connection.docker.get_bin_path",
|
||||
return_value="docker",
|
||||
):
|
||||
self.dc = connection_loader.get(
|
||||
"community.docker.docker", self.play_context, self.in_stream
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@mock.patch('ansible_collections.community.docker.plugins.connection.docker.Connection._old_docker_version',
|
||||
return_value=('false', 'garbage', '', 1))
|
||||
@mock.patch('ansible_collections.community.docker.plugins.connection.docker.Connection._new_docker_version',
|
||||
return_value=('docker version', '1.2.3', '', 0))
|
||||
def test_docker_connection_module_too_old(self, mock_new_docker_version, mock_old_docker_version):
|
||||
@mock.patch(
|
||||
"ansible_collections.community.docker.plugins.connection.docker.Connection._old_docker_version",
|
||||
return_value=("false", "garbage", "", 1),
|
||||
)
|
||||
@mock.patch(
|
||||
"ansible_collections.community.docker.plugins.connection.docker.Connection._new_docker_version",
|
||||
return_value=("docker version", "1.2.3", "", 0),
|
||||
)
|
||||
def test_docker_connection_module_too_old(
|
||||
self, mock_new_docker_version, mock_old_docker_version
|
||||
):
|
||||
self.dc._version = None
|
||||
self.dc.remote_user = 'foo'
|
||||
self.assertRaisesRegex(AnsibleError, '^docker connection type requires docker 1.3 or higher$', self.dc._get_actual_user)
|
||||
self.dc.remote_user = "foo"
|
||||
self.assertRaisesRegex(
|
||||
AnsibleError,
|
||||
"^docker connection type requires docker 1.3 or higher$",
|
||||
self.dc._get_actual_user,
|
||||
)
|
||||
|
||||
@mock.patch('ansible_collections.community.docker.plugins.connection.docker.Connection._old_docker_version',
|
||||
return_value=('false', 'garbage', '', 1))
|
||||
@mock.patch('ansible_collections.community.docker.plugins.connection.docker.Connection._new_docker_version',
|
||||
return_value=('docker version', '1.7.0', '', 0))
|
||||
def test_docker_connection_module(self, mock_new_docker_version, mock_old_docker_version):
|
||||
@mock.patch(
|
||||
"ansible_collections.community.docker.plugins.connection.docker.Connection._old_docker_version",
|
||||
return_value=("false", "garbage", "", 1),
|
||||
)
|
||||
@mock.patch(
|
||||
"ansible_collections.community.docker.plugins.connection.docker.Connection._new_docker_version",
|
||||
return_value=("docker version", "1.7.0", "", 0),
|
||||
)
|
||||
def test_docker_connection_module(
|
||||
self, mock_new_docker_version, mock_old_docker_version
|
||||
):
|
||||
self.dc._version = None
|
||||
version = self.dc.docker_version
|
||||
|
||||
# old version and new version fail
|
||||
@mock.patch('ansible_collections.community.docker.plugins.connection.docker.Connection._old_docker_version',
|
||||
return_value=('false', 'garbage', '', 1))
|
||||
@mock.patch('ansible_collections.community.docker.plugins.connection.docker.Connection._new_docker_version',
|
||||
return_value=('false', 'garbage', '', 1))
|
||||
def test_docker_connection_module_wrong_cmd(self, mock_new_docker_version, mock_old_docker_version):
|
||||
@mock.patch(
|
||||
"ansible_collections.community.docker.plugins.connection.docker.Connection._old_docker_version",
|
||||
return_value=("false", "garbage", "", 1),
|
||||
)
|
||||
@mock.patch(
|
||||
"ansible_collections.community.docker.plugins.connection.docker.Connection._new_docker_version",
|
||||
return_value=("false", "garbage", "", 1),
|
||||
)
|
||||
def test_docker_connection_module_wrong_cmd(
|
||||
self, mock_new_docker_version, mock_old_docker_version
|
||||
):
|
||||
self.dc._version = None
|
||||
self.dc.remote_user = 'foo'
|
||||
self.assertRaisesRegex(AnsibleError, '^Docker version check (.*?) failed:', self.dc._get_actual_user)
|
||||
self.dc.remote_user = "foo"
|
||||
self.assertRaisesRegex(
|
||||
AnsibleError,
|
||||
"^Docker version check (.*?) failed:",
|
||||
self.dc._get_actual_user,
|
||||
)
|
||||
|
||||
@@ -2,20 +2,25 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible.inventory.data import InventoryData
|
||||
from ansible.parsing.dataloader import DataLoader
|
||||
from ansible.template import Templar
|
||||
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.compat.mock import create_autospec
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.utils.trust import make_trusted
|
||||
|
||||
from ansible_collections.community.docker.plugins.inventory.docker_containers import InventoryModule
|
||||
from ansible_collections.community.docker.plugins.inventory.docker_containers import (
|
||||
InventoryModule,
|
||||
)
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.compat.mock import (
|
||||
create_autospec,
|
||||
)
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.utils.trust import (
|
||||
make_trusted,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
@@ -33,55 +38,50 @@ def inventory(templar):
|
||||
|
||||
|
||||
LOVING_THARP = {
|
||||
'Id': '7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a',
|
||||
'Name': '/loving_tharp',
|
||||
'Image': 'sha256:349f492ff18add678364a62a67ce9a13487f14293ae0af1baf02398aa432f385',
|
||||
'State': {
|
||||
'Running': True,
|
||||
"Id": "7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a",
|
||||
"Name": "/loving_tharp",
|
||||
"Image": "sha256:349f492ff18add678364a62a67ce9a13487f14293ae0af1baf02398aa432f385",
|
||||
"State": {
|
||||
"Running": True,
|
||||
},
|
||||
'Config': {
|
||||
'Image': 'quay.io/ansible/ubuntu1804-test-container:1.21.0',
|
||||
"Config": {
|
||||
"Image": "quay.io/ansible/ubuntu1804-test-container:1.21.0",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
LOVING_THARP_STACK = {
|
||||
'Id': '7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a',
|
||||
'Name': '/loving_tharp',
|
||||
'Image': 'sha256:349f492ff18add678364a62a67ce9a13487f14293ae0af1baf02398aa432f385',
|
||||
'State': {
|
||||
'Running': True,
|
||||
"Id": "7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a",
|
||||
"Name": "/loving_tharp",
|
||||
"Image": "sha256:349f492ff18add678364a62a67ce9a13487f14293ae0af1baf02398aa432f385",
|
||||
"State": {
|
||||
"Running": True,
|
||||
},
|
||||
'Config': {
|
||||
'Image': 'quay.io/ansible/ubuntu1804-test-container:1.21.0',
|
||||
'Labels': {
|
||||
'com.docker.stack.namespace': 'my_stack',
|
||||
"Config": {
|
||||
"Image": "quay.io/ansible/ubuntu1804-test-container:1.21.0",
|
||||
"Labels": {
|
||||
"com.docker.stack.namespace": "my_stack",
|
||||
},
|
||||
},
|
||||
'NetworkSettings': {
|
||||
'Ports': {
|
||||
'22/tcp': [
|
||||
{
|
||||
'HostIp': '0.0.0.0',
|
||||
'HostPort': '32802'
|
||||
}
|
||||
],
|
||||
"NetworkSettings": {
|
||||
"Ports": {
|
||||
"22/tcp": [{"HostIp": "0.0.0.0", "HostPort": "32802"}],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
LOVING_THARP_SERVICE = {
|
||||
'Id': '7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a',
|
||||
'Name': '/loving_tharp',
|
||||
'Image': 'sha256:349f492ff18add678364a62a67ce9a13487f14293ae0af1baf02398aa432f385',
|
||||
'State': {
|
||||
'Running': True,
|
||||
"Id": "7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a",
|
||||
"Name": "/loving_tharp",
|
||||
"Image": "sha256:349f492ff18add678364a62a67ce9a13487f14293ae0af1baf02398aa432f385",
|
||||
"State": {
|
||||
"Running": True,
|
||||
},
|
||||
'Config': {
|
||||
'Image': 'quay.io/ansible/ubuntu1804-test-container:1.21.0',
|
||||
'Labels': {
|
||||
'com.docker.swarm.service.name': 'my_service',
|
||||
"Config": {
|
||||
"Image": "quay.io/ansible/ubuntu1804-test-container:1.21.0",
|
||||
"Labels": {
|
||||
"com.docker.swarm.service.name": "my_service",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -101,15 +101,17 @@ class FakeClient(object):
|
||||
self.get_results = {}
|
||||
list_reply = []
|
||||
for host in hosts:
|
||||
list_reply.append({
|
||||
'Id': host['Id'],
|
||||
'Names': [host['Name']] if host['Name'] else [],
|
||||
'Image': host['Config']['Image'],
|
||||
'ImageId': host['Image'],
|
||||
})
|
||||
list_reply.append(
|
||||
{
|
||||
"Id": host["Id"],
|
||||
"Names": [host["Name"]] if host["Name"] else [],
|
||||
"Image": host["Config"]["Image"],
|
||||
"ImageId": host["Image"],
|
||||
}
|
||||
)
|
||||
self.get_results[f"/containers/{host['Name']}/json"] = host
|
||||
self.get_results[f"/containers/{host['Id']}/json"] = host
|
||||
self.get_results['/containers/json'] = list_reply
|
||||
self.get_results["/containers/json"] = list_reply
|
||||
|
||||
def get_json(self, url, *param, **kwargs):
|
||||
url = url.format(*param)
|
||||
@@ -119,30 +121,34 @@ class FakeClient(object):
|
||||
def test_populate(inventory, mocker):
|
||||
client = FakeClient(LOVING_THARP)
|
||||
|
||||
inventory.get_option = mocker.MagicMock(side_effect=create_get_option({
|
||||
'verbose_output': True,
|
||||
'connection_type': 'docker-api',
|
||||
'add_legacy_groups': False,
|
||||
'compose': {},
|
||||
'groups': {},
|
||||
'keyed_groups': {},
|
||||
'filters': None,
|
||||
}))
|
||||
inventory.get_option = mocker.MagicMock(
|
||||
side_effect=create_get_option(
|
||||
{
|
||||
"verbose_output": True,
|
||||
"connection_type": "docker-api",
|
||||
"add_legacy_groups": False,
|
||||
"compose": {},
|
||||
"groups": {},
|
||||
"keyed_groups": {},
|
||||
"filters": None,
|
||||
}
|
||||
)
|
||||
)
|
||||
inventory._populate(client)
|
||||
|
||||
host_1 = inventory.inventory.get_host('loving_tharp')
|
||||
host_1 = inventory.inventory.get_host("loving_tharp")
|
||||
host_1_vars = host_1.get_vars()
|
||||
|
||||
assert host_1_vars['ansible_host'] == 'loving_tharp'
|
||||
assert host_1_vars['ansible_connection'] == 'community.docker.docker_api'
|
||||
assert 'ansible_ssh_host' not in host_1_vars
|
||||
assert 'ansible_ssh_port' not in host_1_vars
|
||||
assert 'docker_state' in host_1_vars
|
||||
assert 'docker_config' in host_1_vars
|
||||
assert 'docker_image' in host_1_vars
|
||||
assert host_1_vars["ansible_host"] == "loving_tharp"
|
||||
assert host_1_vars["ansible_connection"] == "community.docker.docker_api"
|
||||
assert "ansible_ssh_host" not in host_1_vars
|
||||
assert "ansible_ssh_port" not in host_1_vars
|
||||
assert "docker_state" in host_1_vars
|
||||
assert "docker_config" in host_1_vars
|
||||
assert "docker_image" in host_1_vars
|
||||
|
||||
assert len(inventory.inventory.groups['ungrouped'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['all'].hosts) == 0
|
||||
assert len(inventory.inventory.groups["ungrouped"].hosts) == 0
|
||||
assert len(inventory.inventory.groups["all"].hosts) == 0
|
||||
assert len(inventory.inventory.groups) == 2
|
||||
assert len(inventory.inventory.hosts) == 1
|
||||
|
||||
@@ -150,39 +156,57 @@ def test_populate(inventory, mocker):
|
||||
def test_populate_service(inventory, mocker):
|
||||
client = FakeClient(LOVING_THARP_SERVICE)
|
||||
|
||||
inventory.get_option = mocker.MagicMock(side_effect=create_get_option({
|
||||
'verbose_output': False,
|
||||
'connection_type': 'docker-cli',
|
||||
'add_legacy_groups': True,
|
||||
'compose': {},
|
||||
'groups': {},
|
||||
'keyed_groups': {},
|
||||
'docker_host': 'unix://var/run/docker.sock',
|
||||
'filters': None,
|
||||
}))
|
||||
inventory.get_option = mocker.MagicMock(
|
||||
side_effect=create_get_option(
|
||||
{
|
||||
"verbose_output": False,
|
||||
"connection_type": "docker-cli",
|
||||
"add_legacy_groups": True,
|
||||
"compose": {},
|
||||
"groups": {},
|
||||
"keyed_groups": {},
|
||||
"docker_host": "unix://var/run/docker.sock",
|
||||
"filters": None,
|
||||
}
|
||||
)
|
||||
)
|
||||
inventory._populate(client)
|
||||
|
||||
host_1 = inventory.inventory.get_host('loving_tharp')
|
||||
host_1 = inventory.inventory.get_host("loving_tharp")
|
||||
host_1_vars = host_1.get_vars()
|
||||
|
||||
assert host_1_vars['ansible_host'] == 'loving_tharp'
|
||||
assert host_1_vars['ansible_connection'] == 'community.docker.docker'
|
||||
assert 'ansible_ssh_host' not in host_1_vars
|
||||
assert 'ansible_ssh_port' not in host_1_vars
|
||||
assert 'docker_state' not in host_1_vars
|
||||
assert 'docker_config' not in host_1_vars
|
||||
assert 'docker_image' not in host_1_vars
|
||||
assert host_1_vars["ansible_host"] == "loving_tharp"
|
||||
assert host_1_vars["ansible_connection"] == "community.docker.docker"
|
||||
assert "ansible_ssh_host" not in host_1_vars
|
||||
assert "ansible_ssh_port" not in host_1_vars
|
||||
assert "docker_state" not in host_1_vars
|
||||
assert "docker_config" not in host_1_vars
|
||||
assert "docker_image" not in host_1_vars
|
||||
|
||||
assert len(inventory.inventory.groups['ungrouped'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['all'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['7bd547963679e'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['image_quay.io/ansible/ubuntu1804-test-container:1.21.0'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['loving_tharp'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['running'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['stopped'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['service_my_service'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['unix://var/run/docker.sock'].hosts) == 1
|
||||
assert len(inventory.inventory.groups["ungrouped"].hosts) == 0
|
||||
assert len(inventory.inventory.groups["all"].hosts) == 0
|
||||
assert len(inventory.inventory.groups["7bd547963679e"].hosts) == 1
|
||||
assert (
|
||||
len(
|
||||
inventory.inventory.groups[
|
||||
"7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a"
|
||||
].hosts
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert (
|
||||
len(
|
||||
inventory.inventory.groups[
|
||||
"image_quay.io/ansible/ubuntu1804-test-container:1.21.0"
|
||||
].hosts
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert len(inventory.inventory.groups["loving_tharp"].hosts) == 1
|
||||
assert len(inventory.inventory.groups["running"].hosts) == 1
|
||||
assert len(inventory.inventory.groups["stopped"].hosts) == 0
|
||||
assert len(inventory.inventory.groups["service_my_service"].hosts) == 1
|
||||
assert len(inventory.inventory.groups["unix://var/run/docker.sock"].hosts) == 1
|
||||
assert len(inventory.inventory.groups) == 10
|
||||
assert len(inventory.inventory.hosts) == 1
|
||||
|
||||
@@ -190,41 +214,59 @@ def test_populate_service(inventory, mocker):
|
||||
def test_populate_stack(inventory, mocker):
|
||||
client = FakeClient(LOVING_THARP_STACK)
|
||||
|
||||
inventory.get_option = mocker.MagicMock(side_effect=create_get_option({
|
||||
'verbose_output': False,
|
||||
'connection_type': 'ssh',
|
||||
'add_legacy_groups': True,
|
||||
'compose': {},
|
||||
'groups': {},
|
||||
'keyed_groups': {},
|
||||
'docker_host': 'unix://var/run/docker.sock',
|
||||
'default_ip': '127.0.0.1',
|
||||
'private_ssh_port': 22,
|
||||
'filters': None,
|
||||
}))
|
||||
inventory.get_option = mocker.MagicMock(
|
||||
side_effect=create_get_option(
|
||||
{
|
||||
"verbose_output": False,
|
||||
"connection_type": "ssh",
|
||||
"add_legacy_groups": True,
|
||||
"compose": {},
|
||||
"groups": {},
|
||||
"keyed_groups": {},
|
||||
"docker_host": "unix://var/run/docker.sock",
|
||||
"default_ip": "127.0.0.1",
|
||||
"private_ssh_port": 22,
|
||||
"filters": None,
|
||||
}
|
||||
)
|
||||
)
|
||||
inventory._populate(client)
|
||||
|
||||
host_1 = inventory.inventory.get_host('loving_tharp')
|
||||
host_1 = inventory.inventory.get_host("loving_tharp")
|
||||
host_1_vars = host_1.get_vars()
|
||||
|
||||
assert host_1_vars['ansible_ssh_host'] == '127.0.0.1'
|
||||
assert host_1_vars['ansible_ssh_port'] == '32802'
|
||||
assert 'ansible_host' not in host_1_vars
|
||||
assert 'ansible_connection' not in host_1_vars
|
||||
assert 'docker_state' not in host_1_vars
|
||||
assert 'docker_config' not in host_1_vars
|
||||
assert 'docker_image' not in host_1_vars
|
||||
assert host_1_vars["ansible_ssh_host"] == "127.0.0.1"
|
||||
assert host_1_vars["ansible_ssh_port"] == "32802"
|
||||
assert "ansible_host" not in host_1_vars
|
||||
assert "ansible_connection" not in host_1_vars
|
||||
assert "docker_state" not in host_1_vars
|
||||
assert "docker_config" not in host_1_vars
|
||||
assert "docker_image" not in host_1_vars
|
||||
|
||||
assert len(inventory.inventory.groups['ungrouped'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['all'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['7bd547963679e'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['image_quay.io/ansible/ubuntu1804-test-container:1.21.0'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['loving_tharp'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['running'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['stopped'].hosts) == 0
|
||||
assert len(inventory.inventory.groups['stack_my_stack'].hosts) == 1
|
||||
assert len(inventory.inventory.groups['unix://var/run/docker.sock'].hosts) == 1
|
||||
assert len(inventory.inventory.groups["ungrouped"].hosts) == 0
|
||||
assert len(inventory.inventory.groups["all"].hosts) == 0
|
||||
assert len(inventory.inventory.groups["7bd547963679e"].hosts) == 1
|
||||
assert (
|
||||
len(
|
||||
inventory.inventory.groups[
|
||||
"7bd547963679e3209cafd52aff21840b755c96fd37abcd7a6e19da8da6a7f49a"
|
||||
].hosts
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert (
|
||||
len(
|
||||
inventory.inventory.groups[
|
||||
"image_quay.io/ansible/ubuntu1804-test-container:1.21.0"
|
||||
].hosts
|
||||
)
|
||||
== 1
|
||||
)
|
||||
assert len(inventory.inventory.groups["loving_tharp"].hosts) == 1
|
||||
assert len(inventory.inventory.groups["running"].hosts) == 1
|
||||
assert len(inventory.inventory.groups["stopped"].hosts) == 0
|
||||
assert len(inventory.inventory.groups["stack_my_stack"].hosts) == 1
|
||||
assert len(inventory.inventory.groups["unix://var/run/docker.sock"].hosts) == 1
|
||||
assert len(inventory.inventory.groups) == 10
|
||||
assert len(inventory.inventory.hosts) == 1
|
||||
|
||||
@@ -232,17 +274,21 @@ def test_populate_stack(inventory, mocker):
|
||||
def test_populate_filter_none(inventory, mocker):
|
||||
client = FakeClient(LOVING_THARP)
|
||||
|
||||
inventory.get_option = mocker.MagicMock(side_effect=create_get_option({
|
||||
'verbose_output': True,
|
||||
'connection_type': 'docker-api',
|
||||
'add_legacy_groups': False,
|
||||
'compose': {},
|
||||
'groups': {},
|
||||
'keyed_groups': {},
|
||||
'filters': [
|
||||
{'exclude': True},
|
||||
],
|
||||
}))
|
||||
inventory.get_option = mocker.MagicMock(
|
||||
side_effect=create_get_option(
|
||||
{
|
||||
"verbose_output": True,
|
||||
"connection_type": "docker-api",
|
||||
"add_legacy_groups": False,
|
||||
"compose": {},
|
||||
"groups": {},
|
||||
"keyed_groups": {},
|
||||
"filters": [
|
||||
{"exclude": True},
|
||||
],
|
||||
}
|
||||
)
|
||||
)
|
||||
inventory._populate(client)
|
||||
|
||||
assert len(inventory.inventory.hosts) == 0
|
||||
@@ -251,22 +297,26 @@ def test_populate_filter_none(inventory, mocker):
|
||||
def test_populate_filter(inventory, mocker):
|
||||
client = FakeClient(LOVING_THARP)
|
||||
|
||||
inventory.get_option = mocker.MagicMock(side_effect=create_get_option({
|
||||
'verbose_output': True,
|
||||
'connection_type': 'docker-api',
|
||||
'add_legacy_groups': False,
|
||||
'compose': {},
|
||||
'groups': {},
|
||||
'keyed_groups': {},
|
||||
'filters': [
|
||||
{'include': make_trusted('docker_state.Running is true')},
|
||||
{'exclude': True},
|
||||
],
|
||||
}))
|
||||
inventory.get_option = mocker.MagicMock(
|
||||
side_effect=create_get_option(
|
||||
{
|
||||
"verbose_output": True,
|
||||
"connection_type": "docker-api",
|
||||
"add_legacy_groups": False,
|
||||
"compose": {},
|
||||
"groups": {},
|
||||
"keyed_groups": {},
|
||||
"filters": [
|
||||
{"include": make_trusted("docker_state.Running is true")},
|
||||
{"exclude": True},
|
||||
],
|
||||
}
|
||||
)
|
||||
)
|
||||
inventory._populate(client)
|
||||
|
||||
host_1 = inventory.inventory.get_host('loving_tharp')
|
||||
host_1 = inventory.inventory.get_host("loving_tharp")
|
||||
host_1_vars = host_1.get_vars()
|
||||
|
||||
assert host_1_vars['ansible_host'] == 'loving_tharp'
|
||||
assert host_1_vars["ansible_host"] == "loving_tharp"
|
||||
assert len(inventory.inventory.hosts) == 1
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import datetime
|
||||
@@ -27,14 +29,21 @@ from socketserver import ThreadingTCPServer
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api import constants, errors
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.api.client import APIClient
|
||||
from ansible_collections.community.docker.tests.unit.plugins.module_utils._api.constants import DEFAULT_DOCKER_API_VERSION
|
||||
from ansible_collections.community.docker.plugins.module_utils._api import (
|
||||
constants,
|
||||
errors,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.api.client import (
|
||||
APIClient,
|
||||
)
|
||||
from ansible_collections.community.docker.tests.unit.plugins.module_utils._api.constants import (
|
||||
DEFAULT_DOCKER_API_VERSION,
|
||||
)
|
||||
from requests.packages import urllib3
|
||||
|
||||
from .. import fake_api
|
||||
|
||||
|
||||
try:
|
||||
from unittest import mock
|
||||
except ImportError:
|
||||
@@ -44,12 +53,19 @@ except ImportError:
|
||||
DEFAULT_TIMEOUT_SECONDS = constants.DEFAULT_TIMEOUT_SECONDS
|
||||
|
||||
|
||||
def response(status_code=200, content='', headers=None, reason=None, elapsed=0,
|
||||
request=None, raw=None):
|
||||
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, bytes):
|
||||
content = json.dumps(content).encode('ascii')
|
||||
content = json.dumps(content).encode("ascii")
|
||||
res._content = content
|
||||
res.headers = requests.structures.CaseInsensitiveDict(headers or {})
|
||||
res.reason = reason
|
||||
@@ -74,7 +90,7 @@ def fake_resp(method, url, *args, **kwargs):
|
||||
elif (url, method) in fake_api.fake_responses:
|
||||
key = (url, method)
|
||||
if not key:
|
||||
raise Exception(f'{method} {url}')
|
||||
raise Exception(f"{method} {url}")
|
||||
status_code, content = fake_api.fake_responses[key]()
|
||||
return response(status_code=status_code, content=content)
|
||||
|
||||
@@ -83,38 +99,38 @@ fake_request = mock.Mock(side_effect=fake_resp)
|
||||
|
||||
|
||||
def fake_get(self, url, *args, **kwargs):
|
||||
return fake_request('GET', url, *args, **kwargs)
|
||||
return fake_request("GET", url, *args, **kwargs)
|
||||
|
||||
|
||||
def fake_post(self, url, *args, **kwargs):
|
||||
return fake_request('POST', url, *args, **kwargs)
|
||||
return fake_request("POST", url, *args, **kwargs)
|
||||
|
||||
|
||||
def fake_put(self, url, *args, **kwargs):
|
||||
return fake_request('PUT', url, *args, **kwargs)
|
||||
return fake_request("PUT", url, *args, **kwargs)
|
||||
|
||||
|
||||
def fake_delete(self, url, *args, **kwargs):
|
||||
return fake_request('DELETE', url, *args, **kwargs)
|
||||
return fake_request("DELETE", url, *args, **kwargs)
|
||||
|
||||
|
||||
def fake_read_from_socket(self, response, stream, tty=False, demux=False):
|
||||
return b""
|
||||
|
||||
|
||||
url_base = f'{fake_api.prefix}/'
|
||||
url_prefix = f'{url_base}v{DEFAULT_DOCKER_API_VERSION}/'
|
||||
url_base = f"{fake_api.prefix}/"
|
||||
url_prefix = f"{url_base}v{DEFAULT_DOCKER_API_VERSION}/"
|
||||
|
||||
|
||||
class BaseAPIClientTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.patcher = mock.patch.multiple(
|
||||
'ansible_collections.community.docker.plugins.module_utils._api.api.client.APIClient',
|
||||
"ansible_collections.community.docker.plugins.module_utils._api.api.client.APIClient",
|
||||
get=fake_get,
|
||||
post=fake_post,
|
||||
put=fake_put,
|
||||
delete=fake_delete,
|
||||
_read_from_socket=fake_read_from_socket
|
||||
_read_from_socket=fake_read_from_socket,
|
||||
)
|
||||
self.patcher.start()
|
||||
self.client = APIClient(version=DEFAULT_DOCKER_API_VERSION)
|
||||
@@ -123,15 +139,20 @@ class BaseAPIClientTest(unittest.TestCase):
|
||||
self.client.close()
|
||||
self.patcher.stop()
|
||||
|
||||
def base_create_payload(self, img='busybox', cmd=None):
|
||||
def base_create_payload(self, img="busybox", cmd=None):
|
||||
if not cmd:
|
||||
cmd = ['true']
|
||||
return {"Tty": False, "Image": img, "Cmd": cmd,
|
||||
"AttachStdin": False,
|
||||
"AttachStderr": True, "AttachStdout": True,
|
||||
"StdinOnce": False,
|
||||
"OpenStdin": False, "NetworkDisabled": False,
|
||||
}
|
||||
cmd = ["true"]
|
||||
return {
|
||||
"Tty": False,
|
||||
"Image": img,
|
||||
"Cmd": cmd,
|
||||
"AttachStdin": False,
|
||||
"AttachStderr": True,
|
||||
"AttachStdout": True,
|
||||
"StdinOnce": False,
|
||||
"OpenStdin": False,
|
||||
"NetworkDisabled": False,
|
||||
}
|
||||
|
||||
|
||||
class DockerApiTest(BaseAPIClientTest):
|
||||
@@ -139,55 +160,48 @@ class DockerApiTest(BaseAPIClientTest):
|
||||
with pytest.raises(errors.DockerException) as excinfo:
|
||||
APIClient(version=1.12)
|
||||
|
||||
assert str(
|
||||
excinfo.value
|
||||
) == 'Version parameter must be a string or None. Found float'
|
||||
assert (
|
||||
str(excinfo.value)
|
||||
== "Version parameter must be a string or None. Found float"
|
||||
)
|
||||
|
||||
def test_url_valid_resource(self):
|
||||
url = self.client._url('/hello/{0}/world', 'somename')
|
||||
assert url == f'{url_prefix}hello/somename/world'
|
||||
url = self.client._url("/hello/{0}/world", "somename")
|
||||
assert url == f"{url_prefix}hello/somename/world"
|
||||
|
||||
url = self.client._url(
|
||||
'/hello/{0}/world/{1}', 'somename', 'someothername'
|
||||
)
|
||||
assert url == f'{url_prefix}hello/somename/world/someothername'
|
||||
url = self.client._url("/hello/{0}/world/{1}", "somename", "someothername")
|
||||
assert url == f"{url_prefix}hello/somename/world/someothername"
|
||||
|
||||
url = self.client._url('/hello/{0}/world', 'some?name')
|
||||
assert url == f'{url_prefix}hello/some%3Fname/world'
|
||||
url = self.client._url("/hello/{0}/world", "some?name")
|
||||
assert url == f"{url_prefix}hello/some%3Fname/world"
|
||||
|
||||
url = self.client._url("/images/{0}/push", "localhost:5000/image")
|
||||
assert url == f'{url_prefix}images/localhost:5000/image/push'
|
||||
assert url == f"{url_prefix}images/localhost:5000/image/push"
|
||||
|
||||
def test_url_invalid_resource(self):
|
||||
with pytest.raises(ValueError):
|
||||
self.client._url('/hello/{0}/world', ['sakuya', 'izayoi'])
|
||||
self.client._url("/hello/{0}/world", ["sakuya", "izayoi"])
|
||||
|
||||
def test_url_no_resource(self):
|
||||
url = self.client._url('/simple')
|
||||
assert url == f'{url_prefix}simple'
|
||||
url = self.client._url("/simple")
|
||||
assert url == f"{url_prefix}simple"
|
||||
|
||||
def test_url_unversioned_api(self):
|
||||
url = self.client._url(
|
||||
'/hello/{0}/world', 'somename', versioned_api=False
|
||||
)
|
||||
assert url == f'{url_base}hello/somename/world'
|
||||
url = self.client._url("/hello/{0}/world", "somename", versioned_api=False)
|
||||
assert url == f"{url_base}hello/somename/world"
|
||||
|
||||
def test_version(self):
|
||||
self.client.version()
|
||||
|
||||
fake_request.assert_called_with(
|
||||
'GET',
|
||||
url_prefix + 'version',
|
||||
timeout=DEFAULT_TIMEOUT_SECONDS
|
||||
"GET", url_prefix + "version", timeout=DEFAULT_TIMEOUT_SECONDS
|
||||
)
|
||||
|
||||
def test_version_no_api_version(self):
|
||||
self.client.version(False)
|
||||
|
||||
fake_request.assert_called_with(
|
||||
'GET',
|
||||
url_base + 'version',
|
||||
timeout=DEFAULT_TIMEOUT_SECONDS
|
||||
"GET", url_base + "version", timeout=DEFAULT_TIMEOUT_SECONDS
|
||||
)
|
||||
|
||||
def test_retrieve_server_version(self):
|
||||
@@ -204,95 +218,94 @@ class DockerApiTest(BaseAPIClientTest):
|
||||
self.client.info()
|
||||
|
||||
fake_request.assert_called_with(
|
||||
'GET',
|
||||
url_prefix + 'info',
|
||||
timeout=DEFAULT_TIMEOUT_SECONDS
|
||||
"GET", url_prefix + "info", timeout=DEFAULT_TIMEOUT_SECONDS
|
||||
)
|
||||
|
||||
def test_search(self):
|
||||
self.client.get_json('/images/search', params={'term': 'busybox'})
|
||||
self.client.get_json("/images/search", params={"term": "busybox"})
|
||||
|
||||
fake_request.assert_called_with(
|
||||
'GET',
|
||||
url_prefix + 'images/search',
|
||||
params={'term': 'busybox'},
|
||||
timeout=DEFAULT_TIMEOUT_SECONDS
|
||||
"GET",
|
||||
url_prefix + "images/search",
|
||||
params={"term": "busybox"},
|
||||
timeout=DEFAULT_TIMEOUT_SECONDS,
|
||||
)
|
||||
|
||||
def test_login(self):
|
||||
self.client.login('sakuya', 'izayoi')
|
||||
self.client.login("sakuya", "izayoi")
|
||||
args = fake_request.call_args
|
||||
assert args[0][0] == 'POST'
|
||||
assert args[0][1] == url_prefix + 'auth'
|
||||
assert json.loads(args[1]['data']) == {
|
||||
'username': 'sakuya', 'password': 'izayoi'
|
||||
assert args[0][0] == "POST"
|
||||
assert args[0][1] == url_prefix + "auth"
|
||||
assert json.loads(args[1]["data"]) == {
|
||||
"username": "sakuya",
|
||||
"password": "izayoi",
|
||||
}
|
||||
assert args[1]['headers'] == {'Content-Type': 'application/json'}
|
||||
assert self.client._auth_configs.auths['docker.io'] == {
|
||||
'email': None,
|
||||
'password': 'izayoi',
|
||||
'username': 'sakuya',
|
||||
'serveraddress': None,
|
||||
assert args[1]["headers"] == {"Content-Type": "application/json"}
|
||||
assert self.client._auth_configs.auths["docker.io"] == {
|
||||
"email": None,
|
||||
"password": "izayoi",
|
||||
"username": "sakuya",
|
||||
"serveraddress": None,
|
||||
}
|
||||
|
||||
def _socket_path_for_client_session(self, client):
|
||||
socket_adapter = client.get_adapter('http+docker://')
|
||||
socket_adapter = client.get_adapter("http+docker://")
|
||||
return socket_adapter.socket_path
|
||||
|
||||
def test_url_compatibility_unix(self):
|
||||
c = APIClient(
|
||||
base_url="unix://socket",
|
||||
version=DEFAULT_DOCKER_API_VERSION)
|
||||
c = APIClient(base_url="unix://socket", version=DEFAULT_DOCKER_API_VERSION)
|
||||
|
||||
assert self._socket_path_for_client_session(c) == '/socket'
|
||||
assert self._socket_path_for_client_session(c) == "/socket"
|
||||
|
||||
def test_url_compatibility_unix_triple_slash(self):
|
||||
c = APIClient(
|
||||
base_url="unix:///socket",
|
||||
version=DEFAULT_DOCKER_API_VERSION)
|
||||
c = APIClient(base_url="unix:///socket", version=DEFAULT_DOCKER_API_VERSION)
|
||||
|
||||
assert self._socket_path_for_client_session(c) == '/socket'
|
||||
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",
|
||||
version=DEFAULT_DOCKER_API_VERSION)
|
||||
base_url="http+unix:///socket", version=DEFAULT_DOCKER_API_VERSION
|
||||
)
|
||||
|
||||
assert self._socket_path_for_client_session(c) == '/socket'
|
||||
assert self._socket_path_for_client_session(c) == "/socket"
|
||||
|
||||
def test_url_compatibility_http(self):
|
||||
c = APIClient(
|
||||
base_url="http://hostname:1234",
|
||||
version=DEFAULT_DOCKER_API_VERSION)
|
||||
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",
|
||||
version=DEFAULT_DOCKER_API_VERSION)
|
||||
base_url="tcp://hostname:1234", version=DEFAULT_DOCKER_API_VERSION
|
||||
)
|
||||
|
||||
assert c.base_url == "http://hostname:1234"
|
||||
|
||||
def test_remove_link(self):
|
||||
self.client.delete_call('/containers/{0}', '3cc2351ab11b', params={'v': False, 'link': True, 'force': False})
|
||||
self.client.delete_call(
|
||||
"/containers/{0}",
|
||||
"3cc2351ab11b",
|
||||
params={"v": False, "link": True, "force": False},
|
||||
)
|
||||
|
||||
fake_request.assert_called_with(
|
||||
'DELETE',
|
||||
url_prefix + 'containers/3cc2351ab11b',
|
||||
params={'v': False, 'link': True, 'force': False},
|
||||
timeout=DEFAULT_TIMEOUT_SECONDS
|
||||
"DELETE",
|
||||
url_prefix + "containers/3cc2351ab11b",
|
||||
params={"v": False, "link": True, "force": False},
|
||||
timeout=DEFAULT_TIMEOUT_SECONDS,
|
||||
)
|
||||
|
||||
def test_stream_helper_decoding(self):
|
||||
status_code, content = fake_api.fake_responses[url_prefix + 'events']()
|
||||
content_str = json.dumps(content).encode('utf-8')
|
||||
status_code, content = fake_api.fake_responses[url_prefix + "events"]()
|
||||
content_str = json.dumps(content).encode("utf-8")
|
||||
body = io.BytesIO(content_str)
|
||||
|
||||
# mock a stream interface
|
||||
raw_resp = urllib3.HTTPResponse(body=body)
|
||||
setattr(raw_resp._fp, 'chunked', True)
|
||||
setattr(raw_resp._fp, 'chunk_left', len(body.getvalue()) - 1)
|
||||
setattr(raw_resp._fp, "chunked", True)
|
||||
setattr(raw_resp._fp, "chunk_left", len(body.getvalue()) - 1)
|
||||
|
||||
# pass `decode=False` to the helper
|
||||
raw_resp._fp.seek(0)
|
||||
@@ -307,11 +320,11 @@ class DockerApiTest(BaseAPIClientTest):
|
||||
assert result == content
|
||||
|
||||
# non-chunked response, pass `decode=False` to the helper
|
||||
setattr(raw_resp._fp, 'chunked', False)
|
||||
setattr(raw_resp._fp, "chunked", False)
|
||||
raw_resp._fp.seek(0)
|
||||
resp = response(status_code=status_code, content=content, raw=raw_resp)
|
||||
result = next(self.client._stream_helper(resp))
|
||||
assert result == content_str.decode('utf-8')
|
||||
assert result == content_str.decode("utf-8")
|
||||
|
||||
# non-chunked response, pass `decode=True` to the helper
|
||||
raw_resp._fp.seek(0)
|
||||
@@ -326,7 +339,7 @@ class UnixSocketStreamTest(unittest.TestCase):
|
||||
self.build_context = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, socket_dir)
|
||||
self.addCleanup(shutil.rmtree, self.build_context)
|
||||
self.socket_file = os.path.join(socket_dir, 'test_sock.sock')
|
||||
self.socket_file = os.path.join(socket_dir, "test_sock.sock")
|
||||
self.server_socket = self._setup_socket()
|
||||
self.stop_server = False
|
||||
server_thread = threading.Thread(target=self.run_server)
|
||||
@@ -367,17 +380,17 @@ class UnixSocketStreamTest(unittest.TestCase):
|
||||
self.server_socket.close()
|
||||
|
||||
def early_response_sending_handler(self, connection):
|
||||
data = b''
|
||||
data = b""
|
||||
headers = None
|
||||
|
||||
connection.sendall(self.response)
|
||||
while not headers:
|
||||
data += connection.recv(2048)
|
||||
parts = data.split(b'\r\n\r\n', 1)
|
||||
parts = data.split(b"\r\n\r\n", 1)
|
||||
if len(parts) == 2:
|
||||
headers, data = parts
|
||||
|
||||
mo = re.search(r'Content-Length: ([0-9]+)', headers.decode())
|
||||
mo = re.search(r"Content-Length: ([0-9]+)", headers.decode())
|
||||
assert mo
|
||||
content_length = int(mo.group(1))
|
||||
|
||||
@@ -387,77 +400,78 @@ class UnixSocketStreamTest(unittest.TestCase):
|
||||
|
||||
data += connection.recv(2048)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
constants.IS_WINDOWS_PLATFORM, reason='Unix only'
|
||||
)
|
||||
@pytest.mark.skipif(constants.IS_WINDOWS_PLATFORM, reason="Unix only")
|
||||
def test_early_stream_response(self):
|
||||
self.request_handler = self.early_response_sending_handler
|
||||
lines = []
|
||||
for i in range(0, 50):
|
||||
line = str(i).encode()
|
||||
lines += [f'{len(line):x}'.encode(), line]
|
||||
lines.append(b'0')
|
||||
lines.append(b'')
|
||||
lines += [f"{len(line):x}".encode(), line]
|
||||
lines.append(b"0")
|
||||
lines.append(b"")
|
||||
|
||||
self.response = (
|
||||
b'HTTP/1.1 200 OK\r\n'
|
||||
b'Transfer-Encoding: chunked\r\n'
|
||||
b'\r\n'
|
||||
) + b'\r\n'.join(lines)
|
||||
b"HTTP/1.1 200 OK\r\n" b"Transfer-Encoding: chunked\r\n" b"\r\n"
|
||||
) + b"\r\n".join(lines)
|
||||
|
||||
with APIClient(
|
||||
base_url="http+unix://" + self.socket_file,
|
||||
version=DEFAULT_DOCKER_API_VERSION) as client:
|
||||
base_url="http+unix://" + self.socket_file,
|
||||
version=DEFAULT_DOCKER_API_VERSION,
|
||||
) as client:
|
||||
for i in range(5):
|
||||
try:
|
||||
params = {
|
||||
't': None,
|
||||
'remote': None,
|
||||
'q': False,
|
||||
'nocache': False,
|
||||
'rm': False,
|
||||
'forcerm': False,
|
||||
'pull': False,
|
||||
'dockerfile': 'Dockerfile',
|
||||
"t": None,
|
||||
"remote": None,
|
||||
"q": False,
|
||||
"nocache": False,
|
||||
"rm": False,
|
||||
"forcerm": False,
|
||||
"pull": False,
|
||||
"dockerfile": "Dockerfile",
|
||||
}
|
||||
headers = {'Content-Type': 'application/tar'}
|
||||
data = b'...'
|
||||
response = client._post(client._url('/build'), params=params, headers=headers, data=data, stream=True)
|
||||
headers = {"Content-Type": "application/tar"}
|
||||
data = b"..."
|
||||
response = client._post(
|
||||
client._url("/build"),
|
||||
params=params,
|
||||
headers=headers,
|
||||
data=data,
|
||||
stream=True,
|
||||
)
|
||||
stream = client._stream_helper(response, decode=False)
|
||||
break
|
||||
except requests.ConnectionError as e:
|
||||
if i == 4:
|
||||
raise e
|
||||
|
||||
assert list(stream) == [
|
||||
str(i).encode() for i in range(50)
|
||||
]
|
||||
assert list(stream) == [str(i).encode() for i in range(50)]
|
||||
|
||||
|
||||
@pytest.mark.skip(
|
||||
'This test requires starting a networking server and tries to access it. '
|
||||
'This does not work with network separation with Docker-based unit tests, '
|
||||
'but it does work with podman-based unit tests.'
|
||||
"This test requires starting a networking server and tries to access it. "
|
||||
"This does not work with network separation with Docker-based unit tests, "
|
||||
"but it does work with podman-based unit tests."
|
||||
)
|
||||
class TCPSocketStreamTest(unittest.TestCase):
|
||||
stdout_data = b'''
|
||||
stdout_data = b"""
|
||||
Now, those children out there, they're jumping through the
|
||||
flames in the hope that the god of the fire will make them fruitful.
|
||||
Really, you can't blame them. After all, what girl would not prefer the
|
||||
child of a god to that of some acne-scarred artisan?
|
||||
'''
|
||||
stderr_data = b'''
|
||||
"""
|
||||
stderr_data = b"""
|
||||
And what of the true God? To whose glory churches and monasteries have been
|
||||
built on these islands for generations past? Now shall what of Him?
|
||||
'''
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.server = ThreadingTCPServer(('', 0), cls.get_handler_class())
|
||||
cls.server = ThreadingTCPServer(("", 0), cls.get_handler_class())
|
||||
cls.thread = threading.Thread(target=cls.server.serve_forever)
|
||||
cls.thread.daemon = True
|
||||
cls.thread.start()
|
||||
cls.address = f'http://{socket.gethostname()}:{cls.server.server_address[1]}'
|
||||
cls.address = f"http://{socket.gethostname()}:{cls.server.server_address[1]}"
|
||||
|
||||
@classmethod
|
||||
def teardown_class(cls):
|
||||
@@ -474,10 +488,9 @@ class TCPSocketStreamTest(unittest.TestCase):
|
||||
def do_POST(self):
|
||||
resp_data = self.get_resp_data()
|
||||
self.send_response(101)
|
||||
self.send_header(
|
||||
'Content-Type', 'application/vnd.docker.raw-stream')
|
||||
self.send_header('Connection', 'Upgrade')
|
||||
self.send_header('Upgrade', 'tcp')
|
||||
self.send_header("Content-Type", "application/vnd.docker.raw-stream")
|
||||
self.send_header("Connection", "Upgrade")
|
||||
self.send_header("Upgrade", "tcp")
|
||||
self.end_headers()
|
||||
self.wfile.flush()
|
||||
time.sleep(0.2)
|
||||
@@ -485,22 +498,22 @@ class TCPSocketStreamTest(unittest.TestCase):
|
||||
self.wfile.flush()
|
||||
|
||||
def get_resp_data(self):
|
||||
path = self.path.split('/')[-1]
|
||||
if path == 'tty':
|
||||
path = self.path.split("/")[-1]
|
||||
if path == "tty":
|
||||
return stdout_data + stderr_data
|
||||
elif path == 'no-tty':
|
||||
data = b''
|
||||
elif path == "no-tty":
|
||||
data = b""
|
||||
data += self.frame_header(1, stdout_data)
|
||||
data += stdout_data
|
||||
data += self.frame_header(2, stderr_data)
|
||||
data += stderr_data
|
||||
return data
|
||||
else:
|
||||
raise Exception(f'Unknown path {path}')
|
||||
raise Exception(f"Unknown path {path}")
|
||||
|
||||
@staticmethod
|
||||
def frame_header(stream, data):
|
||||
return struct.pack('>BxxxL', stream, len(data))
|
||||
return struct.pack(">BxxxL", stream, len(data))
|
||||
|
||||
return Handler
|
||||
|
||||
@@ -511,12 +524,11 @@ class TCPSocketStreamTest(unittest.TestCase):
|
||||
version=DEFAULT_DOCKER_API_VERSION,
|
||||
) as client:
|
||||
if tty:
|
||||
url = client._url('/tty')
|
||||
url = client._url("/tty")
|
||||
else:
|
||||
url = client._url('/no-tty')
|
||||
url = client._url("/no-tty")
|
||||
resp = client._post(url, stream=True)
|
||||
return client._read_from_socket(
|
||||
resp, stream=stream, tty=tty, demux=demux)
|
||||
return client._read_from_socket(resp, stream=stream, tty=tty, demux=demux)
|
||||
|
||||
def test_read_from_socket_tty(self):
|
||||
res = self.request(stream=True, tty=True, demux=False)
|
||||
@@ -565,8 +577,8 @@ class UserAgentTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.patcher = mock.patch.object(
|
||||
APIClient,
|
||||
'send',
|
||||
return_value=fake_resp("GET", f"{fake_api.prefix}/version")
|
||||
"send",
|
||||
return_value=fake_resp("GET", f"{fake_api.prefix}/version"),
|
||||
)
|
||||
self.mock_send = self.patcher.start()
|
||||
|
||||
@@ -579,18 +591,16 @@ class UserAgentTest(unittest.TestCase):
|
||||
|
||||
assert self.mock_send.call_count == 1
|
||||
headers = self.mock_send.call_args[0][0].headers
|
||||
expected = 'ansible-community.docker'
|
||||
assert headers['User-Agent'] == expected
|
||||
expected = "ansible-community.docker"
|
||||
assert headers["User-Agent"] == expected
|
||||
|
||||
def test_custom_user_agent(self):
|
||||
client = APIClient(
|
||||
user_agent='foo/bar',
|
||||
version=DEFAULT_DOCKER_API_VERSION)
|
||||
client = APIClient(user_agent="foo/bar", version=DEFAULT_DOCKER_API_VERSION)
|
||||
client.version()
|
||||
|
||||
assert self.mock_send.call_count == 1
|
||||
headers = self.mock_send.call_args[0][0].headers
|
||||
assert headers['User-Agent'] == 'foo/bar'
|
||||
assert headers["User-Agent"] == "foo/bar"
|
||||
|
||||
|
||||
class DisableSocketTest(unittest.TestCase):
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DEFAULT_DOCKER_API_VERSION = '1.45'
|
||||
DEFAULT_DOCKER_API_VERSION = "1.45"
|
||||
|
||||
@@ -7,31 +7,36 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api import constants
|
||||
from ansible_collections.community.docker.tests.unit.plugins.module_utils._api.constants import DEFAULT_DOCKER_API_VERSION
|
||||
from ansible_collections.community.docker.tests.unit.plugins.module_utils._api.constants import (
|
||||
DEFAULT_DOCKER_API_VERSION,
|
||||
)
|
||||
|
||||
from . import fake_stat
|
||||
|
||||
CURRENT_VERSION = f'v{DEFAULT_DOCKER_API_VERSION}'
|
||||
|
||||
FAKE_CONTAINER_ID = '3cc2351ab11b'
|
||||
FAKE_IMAGE_ID = 'e9aa60c60128'
|
||||
FAKE_EXEC_ID = 'd5d177f121dc'
|
||||
FAKE_NETWORK_ID = '33fb6a3462b8'
|
||||
FAKE_IMAGE_NAME = 'test_image'
|
||||
FAKE_TARBALL_PATH = '/path/to/tarball'
|
||||
FAKE_REPO_NAME = 'repo'
|
||||
FAKE_TAG_NAME = 'tag'
|
||||
FAKE_FILE_NAME = 'file'
|
||||
FAKE_URL = 'myurl'
|
||||
FAKE_PATH = '/path'
|
||||
FAKE_VOLUME_NAME = 'perfectcherryblossom'
|
||||
FAKE_NODE_ID = '24ifsmvkjbyhk'
|
||||
FAKE_SECRET_ID = 'epdyrw4tsi03xy3deu8g8ly6o'
|
||||
FAKE_SECRET_NAME = 'super_secret'
|
||||
CURRENT_VERSION = f"v{DEFAULT_DOCKER_API_VERSION}"
|
||||
|
||||
FAKE_CONTAINER_ID = "3cc2351ab11b"
|
||||
FAKE_IMAGE_ID = "e9aa60c60128"
|
||||
FAKE_EXEC_ID = "d5d177f121dc"
|
||||
FAKE_NETWORK_ID = "33fb6a3462b8"
|
||||
FAKE_IMAGE_NAME = "test_image"
|
||||
FAKE_TARBALL_PATH = "/path/to/tarball"
|
||||
FAKE_REPO_NAME = "repo"
|
||||
FAKE_TAG_NAME = "tag"
|
||||
FAKE_FILE_NAME = "file"
|
||||
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
|
||||
@@ -40,31 +45,33 @@ FAKE_SECRET_NAME = 'super_secret'
|
||||
def get_fake_version():
|
||||
status_code = 200
|
||||
response = {
|
||||
'ApiVersion': '1.35',
|
||||
'Arch': 'amd64',
|
||||
'BuildTime': '2018-01-10T20:09:37.000000000+00:00',
|
||||
'Components': [{
|
||||
'Details': {
|
||||
'ApiVersion': '1.35',
|
||||
'Arch': 'amd64',
|
||||
'BuildTime': '2018-01-10T20:09:37.000000000+00:00',
|
||||
'Experimental': 'false',
|
||||
'GitCommit': '03596f5',
|
||||
'GoVersion': 'go1.9.2',
|
||||
'KernelVersion': '4.4.0-112-generic',
|
||||
'MinAPIVersion': '1.12',
|
||||
'Os': 'linux'
|
||||
},
|
||||
'Name': 'Engine',
|
||||
'Version': '18.01.0-ce'
|
||||
}],
|
||||
'GitCommit': '03596f5',
|
||||
'GoVersion': 'go1.9.2',
|
||||
'KernelVersion': '4.4.0-112-generic',
|
||||
'MinAPIVersion': '1.12',
|
||||
'Os': 'linux',
|
||||
'Platform': {'Name': ''},
|
||||
'Version': '18.01.0-ce'
|
||||
"ApiVersion": "1.35",
|
||||
"Arch": "amd64",
|
||||
"BuildTime": "2018-01-10T20:09:37.000000000+00:00",
|
||||
"Components": [
|
||||
{
|
||||
"Details": {
|
||||
"ApiVersion": "1.35",
|
||||
"Arch": "amd64",
|
||||
"BuildTime": "2018-01-10T20:09:37.000000000+00:00",
|
||||
"Experimental": "false",
|
||||
"GitCommit": "03596f5",
|
||||
"GoVersion": "go1.9.2",
|
||||
"KernelVersion": "4.4.0-112-generic",
|
||||
"MinAPIVersion": "1.12",
|
||||
"Os": "linux",
|
||||
},
|
||||
"Name": "Engine",
|
||||
"Version": "18.01.0-ce",
|
||||
}
|
||||
],
|
||||
"GitCommit": "03596f5",
|
||||
"GoVersion": "go1.9.2",
|
||||
"KernelVersion": "4.4.0-112-generic",
|
||||
"MinAPIVersion": "1.12",
|
||||
"Os": "linux",
|
||||
"Platform": {"Name": ""},
|
||||
"Version": "18.01.0-ce",
|
||||
}
|
||||
|
||||
return status_code, response
|
||||
@@ -72,16 +79,20 @@ def get_fake_version():
|
||||
|
||||
def get_fake_info():
|
||||
status_code = 200
|
||||
response = {'Containers': 1, 'Images': 1, 'Debug': False,
|
||||
'MemoryLimit': False, 'SwapLimit': False,
|
||||
'IPv4Forwarding': True}
|
||||
response = {
|
||||
"Containers": 1,
|
||||
"Images": 1,
|
||||
"Debug": False,
|
||||
"MemoryLimit": False,
|
||||
"SwapLimit": False,
|
||||
"IPv4Forwarding": True,
|
||||
}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_auth():
|
||||
status_code = 200
|
||||
response = {'Status': 'Login Succeeded',
|
||||
'IdentityToken': '9cbaf023786cd7'}
|
||||
response = {"Status": "Login Succeeded", "IdentityToken": "9cbaf023786cd7"}
|
||||
return status_code, response
|
||||
|
||||
|
||||
@@ -91,34 +102,28 @@ def get_fake_ping():
|
||||
|
||||
def get_fake_search():
|
||||
status_code = 200
|
||||
response = [{'Name': 'busybox', 'Description': 'Fake Description'}]
|
||||
response = [{"Name": "busybox", "Description": "Fake Description"}]
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_images():
|
||||
status_code = 200
|
||||
response = [{
|
||||
'Id': FAKE_IMAGE_ID,
|
||||
'Created': '2 days ago',
|
||||
'Repository': 'busybox',
|
||||
'RepoTags': ['busybox:latest', 'busybox:1.0'],
|
||||
}]
|
||||
response = [
|
||||
{
|
||||
"Id": FAKE_IMAGE_ID,
|
||||
"Created": "2 days ago",
|
||||
"Repository": "busybox",
|
||||
"RepoTags": ["busybox:latest", "busybox:1.0"],
|
||||
}
|
||||
]
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_image_history():
|
||||
status_code = 200
|
||||
response = [
|
||||
{
|
||||
"Id": "b750fe79269d",
|
||||
"Created": 1364102658,
|
||||
"CreatedBy": "/bin/bash"
|
||||
},
|
||||
{
|
||||
"Id": "27cf78414709",
|
||||
"Created": 1364068391,
|
||||
"CreatedBy": ""
|
||||
}
|
||||
{"Id": "b750fe79269d", "Created": 1364102658, "CreatedBy": "/bin/bash"},
|
||||
{"Id": "27cf78414709", "Created": 1364068391, "CreatedBy": ""},
|
||||
]
|
||||
|
||||
return status_code, response
|
||||
@@ -126,64 +131,63 @@ def get_fake_image_history():
|
||||
|
||||
def post_fake_import_image():
|
||||
status_code = 200
|
||||
response = 'Import messages...'
|
||||
response = "Import messages..."
|
||||
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_containers():
|
||||
status_code = 200
|
||||
response = [{
|
||||
'Id': FAKE_CONTAINER_ID,
|
||||
'Image': 'busybox:latest',
|
||||
'Created': '2 days ago',
|
||||
'Command': 'true',
|
||||
'Status': 'fake status'
|
||||
}]
|
||||
response = [
|
||||
{
|
||||
"Id": FAKE_CONTAINER_ID,
|
||||
"Image": "busybox:latest",
|
||||
"Created": "2 days ago",
|
||||
"Command": "true",
|
||||
"Status": "fake status",
|
||||
}
|
||||
]
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_start_container():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_resize_container():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_create_container():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_inspect_container(tty=False):
|
||||
status_code = 200
|
||||
response = {
|
||||
'Id': FAKE_CONTAINER_ID,
|
||||
'Config': {'Labels': {'foo': 'bar'}, 'Privileged': True, 'Tty': tty},
|
||||
'ID': FAKE_CONTAINER_ID,
|
||||
'Image': 'busybox:latest',
|
||||
'Name': 'foobar',
|
||||
"Id": FAKE_CONTAINER_ID,
|
||||
"Config": {"Labels": {"foo": "bar"}, "Privileged": True, "Tty": tty},
|
||||
"ID": FAKE_CONTAINER_ID,
|
||||
"Image": "busybox:latest",
|
||||
"Name": "foobar",
|
||||
"State": {
|
||||
"Status": "running",
|
||||
"Running": True,
|
||||
"Pid": 0,
|
||||
"ExitCode": 0,
|
||||
"StartedAt": "2013-09-25T14:01:18.869545111+02:00",
|
||||
"Ghost": False
|
||||
"Ghost": False,
|
||||
},
|
||||
"HostConfig": {
|
||||
"LogConfig": {
|
||||
"Type": "json-file",
|
||||
"Config": {}
|
||||
},
|
||||
"LogConfig": {"Type": "json-file", "Config": {}},
|
||||
},
|
||||
"MacAddress": "02:42:ac:11:00:0a"
|
||||
"MacAddress": "02:42:ac:11:00:0a",
|
||||
}
|
||||
return status_code, response
|
||||
|
||||
@@ -191,13 +195,12 @@ def get_fake_inspect_container(tty=False):
|
||||
def get_fake_inspect_image():
|
||||
status_code = 200
|
||||
response = {
|
||||
'Id': FAKE_IMAGE_ID,
|
||||
'Parent': "27cf784147099545",
|
||||
'Created': "2013-03-23T22:24:18.818426-07:00",
|
||||
'Container': FAKE_CONTAINER_ID,
|
||||
'Config': {'Labels': {'bar': 'foo'}},
|
||||
'ContainerConfig':
|
||||
{
|
||||
"Id": FAKE_IMAGE_ID,
|
||||
"Parent": "27cf784147099545",
|
||||
"Created": "2013-03-23T22:24:18.818426-07:00",
|
||||
"Container": FAKE_CONTAINER_ID,
|
||||
"Config": {"Labels": {"bar": "foo"}},
|
||||
"ContainerConfig": {
|
||||
"Hostname": "",
|
||||
"User": "",
|
||||
"Memory": 0,
|
||||
@@ -215,118 +218,128 @@ def get_fake_inspect_image():
|
||||
"Image": "base",
|
||||
"Volumes": "",
|
||||
"VolumesFrom": "",
|
||||
"WorkingDir": ""
|
||||
"WorkingDir": "",
|
||||
},
|
||||
'Size': 6823592
|
||||
"Size": 6823592,
|
||||
}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_insert_image():
|
||||
status_code = 200
|
||||
response = {'StatusCode': 0}
|
||||
response = {"StatusCode": 0}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_wait():
|
||||
status_code = 200
|
||||
response = {'StatusCode': 0}
|
||||
response = {"StatusCode": 0}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_logs():
|
||||
status_code = 200
|
||||
response = (b'\x01\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x02\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x01\x00\x00\x00\x00\x00\x00\x11Flowering Nights\n'
|
||||
b'\x01\x00\x00\x00\x00\x00\x00\x10(Sakuya Iyazoi)\n')
|
||||
response = (
|
||||
b"\x01\x00\x00\x00\x00\x00\x00\x00"
|
||||
b"\x02\x00\x00\x00\x00\x00\x00\x00"
|
||||
b"\x01\x00\x00\x00\x00\x00\x00\x11Flowering Nights\n"
|
||||
b"\x01\x00\x00\x00\x00\x00\x00\x10(Sakuya Iyazoi)\n"
|
||||
)
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_diff():
|
||||
status_code = 200
|
||||
response = [{'Path': '/test', 'Kind': 1}]
|
||||
response = [{"Path": "/test", "Kind": 1}]
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_events():
|
||||
status_code = 200
|
||||
response = [{'status': 'stop', 'id': FAKE_CONTAINER_ID,
|
||||
'from': FAKE_IMAGE_ID, 'time': 1423247867}]
|
||||
response = [
|
||||
{
|
||||
"status": "stop",
|
||||
"id": FAKE_CONTAINER_ID,
|
||||
"from": FAKE_IMAGE_ID,
|
||||
"time": 1423247867,
|
||||
}
|
||||
]
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_export():
|
||||
status_code = 200
|
||||
response = 'Byte Stream....'
|
||||
response = "Byte Stream...."
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_exec_create():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_EXEC_ID}
|
||||
response = {"Id": FAKE_EXEC_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_exec_start():
|
||||
status_code = 200
|
||||
response = (b'\x01\x00\x00\x00\x00\x00\x00\x11bin\nboot\ndev\netc\n'
|
||||
b'\x01\x00\x00\x00\x00\x00\x00\x12lib\nmnt\nproc\nroot\n'
|
||||
b'\x01\x00\x00\x00\x00\x00\x00\x0csbin\nusr\nvar\n')
|
||||
response = (
|
||||
b"\x01\x00\x00\x00\x00\x00\x00\x11bin\nboot\ndev\netc\n"
|
||||
b"\x01\x00\x00\x00\x00\x00\x00\x12lib\nmnt\nproc\nroot\n"
|
||||
b"\x01\x00\x00\x00\x00\x00\x00\x0csbin\nusr\nvar\n"
|
||||
)
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_exec_resize():
|
||||
status_code = 201
|
||||
return status_code, ''
|
||||
return status_code, ""
|
||||
|
||||
|
||||
def get_fake_exec_inspect():
|
||||
return 200, {
|
||||
'OpenStderr': True,
|
||||
'OpenStdout': True,
|
||||
'Container': get_fake_inspect_container()[1],
|
||||
'Running': False,
|
||||
'ProcessConfig': {
|
||||
'arguments': ['hello world'],
|
||||
'tty': False,
|
||||
'entrypoint': 'echo',
|
||||
'privileged': False,
|
||||
'user': ''
|
||||
"OpenStderr": True,
|
||||
"OpenStdout": True,
|
||||
"Container": get_fake_inspect_container()[1],
|
||||
"Running": False,
|
||||
"ProcessConfig": {
|
||||
"arguments": ["hello world"],
|
||||
"tty": False,
|
||||
"entrypoint": "echo",
|
||||
"privileged": False,
|
||||
"user": "",
|
||||
},
|
||||
'ExitCode': 0,
|
||||
'ID': FAKE_EXEC_ID,
|
||||
'OpenStdin': False
|
||||
"ExitCode": 0,
|
||||
"ID": FAKE_EXEC_ID,
|
||||
"OpenStdin": False,
|
||||
}
|
||||
|
||||
|
||||
def post_fake_stop_container():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_kill_container():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_pause_container():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_unpause_container():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_restart_container():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
@@ -337,55 +350,55 @@ def post_fake_rename_container():
|
||||
|
||||
def delete_fake_remove_container():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_image_create():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_IMAGE_ID}
|
||||
response = {"Id": FAKE_IMAGE_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def delete_fake_remove_image():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_IMAGE_ID}
|
||||
response = {"Id": FAKE_IMAGE_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def get_fake_get_image():
|
||||
status_code = 200
|
||||
response = 'Byte Stream....'
|
||||
response = "Byte Stream...."
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_load_image():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_IMAGE_ID}
|
||||
response = {"Id": FAKE_IMAGE_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_commit():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_push():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_IMAGE_ID}
|
||||
response = {"Id": FAKE_IMAGE_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_build_container():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_CONTAINER_ID}
|
||||
response = {"Id": FAKE_CONTAINER_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
def post_fake_tag_image():
|
||||
status_code = 200
|
||||
response = {'Id': FAKE_IMAGE_ID}
|
||||
response = {"Id": FAKE_IMAGE_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
@@ -397,27 +410,27 @@ def get_fake_stats():
|
||||
|
||||
def get_fake_top():
|
||||
return 200, {
|
||||
'Processes': [
|
||||
"Processes": [
|
||||
[
|
||||
'root',
|
||||
'26501',
|
||||
'6907',
|
||||
'0',
|
||||
'10:32',
|
||||
'pts/55',
|
||||
'00:00:00',
|
||||
'sleep 60',
|
||||
"root",
|
||||
"26501",
|
||||
"6907",
|
||||
"0",
|
||||
"10:32",
|
||||
"pts/55",
|
||||
"00:00:00",
|
||||
"sleep 60",
|
||||
],
|
||||
],
|
||||
'Titles': [
|
||||
'UID',
|
||||
'PID',
|
||||
'PPID',
|
||||
'C',
|
||||
'STIME',
|
||||
'TTY',
|
||||
'TIME',
|
||||
'CMD',
|
||||
"Titles": [
|
||||
"UID",
|
||||
"PID",
|
||||
"PPID",
|
||||
"C",
|
||||
"STIME",
|
||||
"TTY",
|
||||
"TIME",
|
||||
"CMD",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -425,18 +438,19 @@ def get_fake_top():
|
||||
def get_fake_volume_list():
|
||||
status_code = 200
|
||||
response = {
|
||||
'Volumes': [
|
||||
"Volumes": [
|
||||
{
|
||||
'Name': 'perfectcherryblossom',
|
||||
'Driver': 'local',
|
||||
'Mountpoint': '/var/lib/docker/volumes/perfectcherryblossom',
|
||||
'Scope': 'local'
|
||||
}, {
|
||||
'Name': 'subterraneananimism',
|
||||
'Driver': 'local',
|
||||
'Mountpoint': '/var/lib/docker/volumes/subterraneananimism',
|
||||
'Scope': 'local'
|
||||
}
|
||||
"Name": "perfectcherryblossom",
|
||||
"Driver": "local",
|
||||
"Mountpoint": "/var/lib/docker/volumes/perfectcherryblossom",
|
||||
"Scope": "local",
|
||||
},
|
||||
{
|
||||
"Name": "subterraneananimism",
|
||||
"Driver": "local",
|
||||
"Mountpoint": "/var/lib/docker/volumes/subterraneananimism",
|
||||
"Scope": "local",
|
||||
},
|
||||
]
|
||||
}
|
||||
return status_code, response
|
||||
@@ -445,13 +459,11 @@ def get_fake_volume_list():
|
||||
def get_fake_volume():
|
||||
status_code = 200
|
||||
response = {
|
||||
'Name': 'perfectcherryblossom',
|
||||
'Driver': 'local',
|
||||
'Mountpoint': '/var/lib/docker/volumes/perfectcherryblossom',
|
||||
'Labels': {
|
||||
'com.example.some-label': 'some-value'
|
||||
},
|
||||
'Scope': 'local'
|
||||
"Name": "perfectcherryblossom",
|
||||
"Driver": "local",
|
||||
"Mountpoint": "/var/lib/docker/volumes/perfectcherryblossom",
|
||||
"Labels": {"com.example.some-label": "some-value"},
|
||||
"Scope": "local",
|
||||
}
|
||||
return status_code, response
|
||||
|
||||
@@ -461,7 +473,7 @@ def fake_remove_volume():
|
||||
|
||||
|
||||
def post_fake_update_container():
|
||||
return 200, {'Warnings': []}
|
||||
return 200, {"Warnings": []}
|
||||
|
||||
|
||||
def post_fake_update_node():
|
||||
@@ -473,38 +485,33 @@ def post_fake_join_swarm():
|
||||
|
||||
|
||||
def get_fake_network_list():
|
||||
return 200, [{
|
||||
"Name": "bridge",
|
||||
"Id": FAKE_NETWORK_ID,
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"EnableIPv6": False,
|
||||
"Internal": False,
|
||||
"IPAM": {
|
||||
"Driver": "default",
|
||||
"Config": [
|
||||
{
|
||||
"Subnet": "172.17.0.0/16"
|
||||
return 200, [
|
||||
{
|
||||
"Name": "bridge",
|
||||
"Id": FAKE_NETWORK_ID,
|
||||
"Scope": "local",
|
||||
"Driver": "bridge",
|
||||
"EnableIPv6": False,
|
||||
"Internal": False,
|
||||
"IPAM": {"Driver": "default", "Config": [{"Subnet": "172.17.0.0/16"}]},
|
||||
"Containers": {
|
||||
FAKE_CONTAINER_ID: {
|
||||
"EndpointID": "ed2419a97c1d99",
|
||||
"MacAddress": "02:42:ac:11:00:02",
|
||||
"IPv4Address": "172.17.0.2/16",
|
||||
"IPv6Address": "",
|
||||
}
|
||||
]
|
||||
},
|
||||
"Containers": {
|
||||
FAKE_CONTAINER_ID: {
|
||||
"EndpointID": "ed2419a97c1d99",
|
||||
"MacAddress": "02:42:ac:11:00:02",
|
||||
"IPv4Address": "172.17.0.2/16",
|
||||
"IPv6Address": ""
|
||||
}
|
||||
},
|
||||
"Options": {
|
||||
"com.docker.network.bridge.default_bridge": "true",
|
||||
"com.docker.network.bridge.enable_icc": "true",
|
||||
"com.docker.network.bridge.enable_ip_masquerade": "true",
|
||||
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
|
||||
"com.docker.network.bridge.name": "docker0",
|
||||
"com.docker.network.driver.mtu": "1500"
|
||||
},
|
||||
"Options": {
|
||||
"com.docker.network.bridge.default_bridge": "true",
|
||||
"com.docker.network.bridge.enable_icc": "true",
|
||||
"com.docker.network.bridge.enable_ip_masquerade": "true",
|
||||
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
|
||||
"com.docker.network.bridge.name": "docker0",
|
||||
"com.docker.network.driver.mtu": "1500",
|
||||
},
|
||||
}
|
||||
}]
|
||||
]
|
||||
|
||||
|
||||
def get_fake_network():
|
||||
@@ -529,127 +536,85 @@ def post_fake_network_disconnect():
|
||||
|
||||
def post_fake_secret():
|
||||
status_code = 200
|
||||
response = {'ID': FAKE_SECRET_ID}
|
||||
response = {"ID": FAKE_SECRET_ID}
|
||||
return status_code, response
|
||||
|
||||
|
||||
# Maps real api url to fake response callback
|
||||
prefix = 'http+docker://localhost'
|
||||
prefix = "http+docker://localhost"
|
||||
if constants.IS_WINDOWS_PLATFORM:
|
||||
prefix = 'http+docker://localnpipe'
|
||||
prefix = "http+docker://localnpipe"
|
||||
|
||||
fake_responses = {
|
||||
f'{prefix}/version':
|
||||
get_fake_version,
|
||||
f'{prefix}/{CURRENT_VERSION}/version':
|
||||
get_fake_version,
|
||||
f'{prefix}/{CURRENT_VERSION}/info':
|
||||
get_fake_info,
|
||||
f'{prefix}/{CURRENT_VERSION}/auth':
|
||||
post_fake_auth,
|
||||
f'{prefix}/{CURRENT_VERSION}/_ping':
|
||||
get_fake_ping,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/search':
|
||||
get_fake_search,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/json':
|
||||
get_fake_images,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/test_image/history':
|
||||
get_fake_image_history,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/create':
|
||||
post_fake_import_image,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/json':
|
||||
get_fake_containers,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/start':
|
||||
post_fake_start_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/resize':
|
||||
post_fake_resize_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/json':
|
||||
get_fake_inspect_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/rename':
|
||||
post_fake_rename_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/e9aa60c60128/tag':
|
||||
post_fake_tag_image,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/wait':
|
||||
get_fake_wait,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/logs':
|
||||
get_fake_logs,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/changes':
|
||||
get_fake_diff,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/export':
|
||||
get_fake_export,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/update':
|
||||
post_fake_update_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/exec':
|
||||
post_fake_exec_create,
|
||||
f'{prefix}/{CURRENT_VERSION}/exec/d5d177f121dc/start':
|
||||
post_fake_exec_start,
|
||||
f'{prefix}/{CURRENT_VERSION}/exec/d5d177f121dc/json':
|
||||
get_fake_exec_inspect,
|
||||
f'{prefix}/{CURRENT_VERSION}/exec/d5d177f121dc/resize':
|
||||
post_fake_exec_resize,
|
||||
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/stats':
|
||||
get_fake_stats,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/top':
|
||||
get_fake_top,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/stop':
|
||||
post_fake_stop_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/kill':
|
||||
post_fake_kill_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/pause':
|
||||
post_fake_pause_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/unpause':
|
||||
post_fake_unpause_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/restart':
|
||||
post_fake_restart_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b':
|
||||
delete_fake_remove_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/create':
|
||||
post_fake_image_create,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/e9aa60c60128':
|
||||
delete_fake_remove_image,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/e9aa60c60128/get':
|
||||
get_fake_get_image,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/load':
|
||||
post_fake_load_image,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/test_image/json':
|
||||
get_fake_inspect_image,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/test_image/insert':
|
||||
get_fake_insert_image,
|
||||
f'{prefix}/{CURRENT_VERSION}/images/test_image/push':
|
||||
post_fake_push,
|
||||
f'{prefix}/{CURRENT_VERSION}/commit':
|
||||
post_fake_commit,
|
||||
f'{prefix}/{CURRENT_VERSION}/containers/create':
|
||||
post_fake_create_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/build':
|
||||
post_fake_build_container,
|
||||
f'{prefix}/{CURRENT_VERSION}/events':
|
||||
get_fake_events,
|
||||
(f'{prefix}/{CURRENT_VERSION}/volumes', 'GET'):
|
||||
get_fake_volume_list,
|
||||
(f'{prefix}/{CURRENT_VERSION}/volumes/create', 'POST'):
|
||||
get_fake_volume,
|
||||
(f'{prefix}/{CURRENT_VERSION}/volumes/{FAKE_VOLUME_NAME}', 'GET'):
|
||||
get_fake_volume,
|
||||
(f'{prefix}/{CURRENT_VERSION}/volumes/{FAKE_VOLUME_NAME}', 'DELETE'):
|
||||
fake_remove_volume,
|
||||
(f'{prefix}/{CURRENT_VERSION}/nodes/{FAKE_NODE_ID}/update?version=1', 'POST'):
|
||||
post_fake_update_node,
|
||||
(f'{prefix}/{CURRENT_VERSION}/swarm/join', 'POST'):
|
||||
post_fake_join_swarm,
|
||||
(f'{prefix}/{CURRENT_VERSION}/networks', 'GET'):
|
||||
get_fake_network_list,
|
||||
(f'{prefix}/{CURRENT_VERSION}/networks/create', 'POST'):
|
||||
post_fake_network,
|
||||
(f'{prefix}/{CURRENT_VERSION}/networks/{FAKE_NETWORK_ID}', 'GET'):
|
||||
get_fake_network,
|
||||
(f'{prefix}/{CURRENT_VERSION}/networks/{FAKE_NETWORK_ID}', 'DELETE'):
|
||||
delete_fake_network,
|
||||
(f'{prefix}/{CURRENT_VERSION}/networks/{FAKE_NETWORK_ID}/connect', 'POST'):
|
||||
post_fake_network_connect,
|
||||
(f'{prefix}/{CURRENT_VERSION}/networks/{FAKE_NETWORK_ID}/disconnect', 'POST'):
|
||||
post_fake_network_disconnect,
|
||||
f'{prefix}/{CURRENT_VERSION}/secrets/create':
|
||||
post_fake_secret,
|
||||
f"{prefix}/version": get_fake_version,
|
||||
f"{prefix}/{CURRENT_VERSION}/version": get_fake_version,
|
||||
f"{prefix}/{CURRENT_VERSION}/info": get_fake_info,
|
||||
f"{prefix}/{CURRENT_VERSION}/auth": post_fake_auth,
|
||||
f"{prefix}/{CURRENT_VERSION}/_ping": get_fake_ping,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/search": get_fake_search,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/json": get_fake_images,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/test_image/history": get_fake_image_history,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/create": post_fake_import_image,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/json": get_fake_containers,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/start": post_fake_start_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/resize": post_fake_resize_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/json": get_fake_inspect_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/rename": post_fake_rename_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/e9aa60c60128/tag": post_fake_tag_image,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/wait": get_fake_wait,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/logs": get_fake_logs,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/changes": get_fake_diff,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/export": get_fake_export,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/update": post_fake_update_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/exec": post_fake_exec_create,
|
||||
f"{prefix}/{CURRENT_VERSION}/exec/d5d177f121dc/start": post_fake_exec_start,
|
||||
f"{prefix}/{CURRENT_VERSION}/exec/d5d177f121dc/json": get_fake_exec_inspect,
|
||||
f"{prefix}/{CURRENT_VERSION}/exec/d5d177f121dc/resize": post_fake_exec_resize,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/stats": get_fake_stats,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/top": get_fake_top,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/stop": post_fake_stop_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/kill": post_fake_kill_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/pause": post_fake_pause_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/unpause": post_fake_unpause_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b/restart": post_fake_restart_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/3cc2351ab11b": delete_fake_remove_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/create": post_fake_image_create,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/e9aa60c60128": delete_fake_remove_image,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/e9aa60c60128/get": get_fake_get_image,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/load": post_fake_load_image,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/test_image/json": get_fake_inspect_image,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/test_image/insert": get_fake_insert_image,
|
||||
f"{prefix}/{CURRENT_VERSION}/images/test_image/push": post_fake_push,
|
||||
f"{prefix}/{CURRENT_VERSION}/commit": post_fake_commit,
|
||||
f"{prefix}/{CURRENT_VERSION}/containers/create": post_fake_create_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/build": post_fake_build_container,
|
||||
f"{prefix}/{CURRENT_VERSION}/events": get_fake_events,
|
||||
(f"{prefix}/{CURRENT_VERSION}/volumes", "GET"): get_fake_volume_list,
|
||||
(f"{prefix}/{CURRENT_VERSION}/volumes/create", "POST"): get_fake_volume,
|
||||
(f"{prefix}/{CURRENT_VERSION}/volumes/{FAKE_VOLUME_NAME}", "GET"): get_fake_volume,
|
||||
(
|
||||
f"{prefix}/{CURRENT_VERSION}/volumes/{FAKE_VOLUME_NAME}",
|
||||
"DELETE",
|
||||
): fake_remove_volume,
|
||||
(
|
||||
f"{prefix}/{CURRENT_VERSION}/nodes/{FAKE_NODE_ID}/update?version=1",
|
||||
"POST",
|
||||
): post_fake_update_node,
|
||||
(f"{prefix}/{CURRENT_VERSION}/swarm/join", "POST"): post_fake_join_swarm,
|
||||
(f"{prefix}/{CURRENT_VERSION}/networks", "GET"): get_fake_network_list,
|
||||
(f"{prefix}/{CURRENT_VERSION}/networks/create", "POST"): post_fake_network,
|
||||
(f"{prefix}/{CURRENT_VERSION}/networks/{FAKE_NETWORK_ID}", "GET"): get_fake_network,
|
||||
(
|
||||
f"{prefix}/{CURRENT_VERSION}/networks/{FAKE_NETWORK_ID}",
|
||||
"DELETE",
|
||||
): delete_fake_network,
|
||||
(
|
||||
f"{prefix}/{CURRENT_VERSION}/networks/{FAKE_NETWORK_ID}/connect",
|
||||
"POST",
|
||||
): post_fake_network_connect,
|
||||
(
|
||||
f"{prefix}/{CURRENT_VERSION}/networks/{FAKE_NETWORK_ID}/disconnect",
|
||||
"POST",
|
||||
): post_fake_network_disconnect,
|
||||
f"{prefix}/{CURRENT_VERSION}/secrets/create": post_fake_secret,
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
OBJ = {
|
||||
@@ -20,26 +22,17 @@ OBJ = {
|
||||
"tx_bytes": 1176,
|
||||
"tx_packets": 13,
|
||||
"tx_errors": 0,
|
||||
"tx_dropped": 0
|
||||
"tx_dropped": 0,
|
||||
},
|
||||
"cpu_stats": {
|
||||
"cpu_usage": {
|
||||
"total_usage": 157260874053,
|
||||
"percpu_usage": [
|
||||
52196306950,
|
||||
24118413549,
|
||||
53292684398,
|
||||
27653469156
|
||||
],
|
||||
"percpu_usage": [52196306950, 24118413549, 53292684398, 27653469156],
|
||||
"usage_in_kernelmode": 37140000000,
|
||||
"usage_in_usermode": 62140000000
|
||||
"usage_in_usermode": 62140000000,
|
||||
},
|
||||
"system_cpu_usage": 3.0881377e+14,
|
||||
"throttling_data": {
|
||||
"periods": 0,
|
||||
"throttled_periods": 0,
|
||||
"throttled_time": 0
|
||||
}
|
||||
"system_cpu_usage": 3.0881377e14,
|
||||
"throttling_data": {"periods": 0, "throttled_periods": 0, "throttled_time": 0},
|
||||
},
|
||||
"memory_stats": {
|
||||
"usage": 179314688,
|
||||
@@ -48,7 +41,7 @@ OBJ = {
|
||||
"active_anon": 90804224,
|
||||
"active_file": 2195456,
|
||||
"cache": 3096576,
|
||||
"hierarchical_memory_limit": 1.844674407371e+19,
|
||||
"hierarchical_memory_limit": 1.844674407371e19,
|
||||
"inactive_anon": 85516288,
|
||||
"inactive_file": 798720,
|
||||
"mapped_file": 2646016,
|
||||
@@ -73,73 +66,31 @@ OBJ = {
|
||||
"total_unevictable": 0,
|
||||
"total_writeback": 0,
|
||||
"unevictable": 0,
|
||||
"writeback": 0
|
||||
"writeback": 0,
|
||||
},
|
||||
"failcnt": 0,
|
||||
"limit": 8039038976
|
||||
"limit": 8039038976,
|
||||
},
|
||||
"blkio_stats": {
|
||||
"io_service_bytes_recursive": [
|
||||
{
|
||||
"major": 8,
|
||||
"minor": 0,
|
||||
"op": "Read",
|
||||
"value": 72843264
|
||||
}, {
|
||||
"major": 8,
|
||||
"minor": 0,
|
||||
"op": "Write",
|
||||
"value": 4096
|
||||
}, {
|
||||
"major": 8,
|
||||
"minor": 0,
|
||||
"op": "Sync",
|
||||
"value": 4096
|
||||
}, {
|
||||
"major": 8,
|
||||
"minor": 0,
|
||||
"op": "Async",
|
||||
"value": 72843264
|
||||
}, {
|
||||
"major": 8,
|
||||
"minor": 0,
|
||||
"op": "Total",
|
||||
"value": 72847360
|
||||
}
|
||||
{"major": 8, "minor": 0, "op": "Read", "value": 72843264},
|
||||
{"major": 8, "minor": 0, "op": "Write", "value": 4096},
|
||||
{"major": 8, "minor": 0, "op": "Sync", "value": 4096},
|
||||
{"major": 8, "minor": 0, "op": "Async", "value": 72843264},
|
||||
{"major": 8, "minor": 0, "op": "Total", "value": 72847360},
|
||||
],
|
||||
"io_serviced_recursive": [
|
||||
{
|
||||
"major": 8,
|
||||
"minor": 0,
|
||||
"op": "Read",
|
||||
"value": 10581
|
||||
}, {
|
||||
"major": 8,
|
||||
"minor": 0,
|
||||
"op": "Write",
|
||||
"value": 1
|
||||
}, {
|
||||
"major": 8,
|
||||
"minor": 0,
|
||||
"op": "Sync",
|
||||
"value": 1
|
||||
}, {
|
||||
"major": 8,
|
||||
"minor": 0,
|
||||
"op": "Async",
|
||||
"value": 10581
|
||||
}, {
|
||||
"major": 8,
|
||||
"minor": 0,
|
||||
"op": "Total",
|
||||
"value": 10582
|
||||
}
|
||||
{"major": 8, "minor": 0, "op": "Read", "value": 10581},
|
||||
{"major": 8, "minor": 0, "op": "Write", "value": 1},
|
||||
{"major": 8, "minor": 0, "op": "Sync", "value": 1},
|
||||
{"major": 8, "minor": 0, "op": "Async", "value": 10581},
|
||||
{"major": 8, "minor": 0, "op": "Total", "value": 10582},
|
||||
],
|
||||
"io_queue_recursive": [],
|
||||
"io_service_time_recursive": [],
|
||||
"io_wait_time_recursive": [],
|
||||
"io_merged_recursive": [],
|
||||
"io_time_recursive": [],
|
||||
"sectors_recursive": []
|
||||
}
|
||||
"sectors_recursive": [],
|
||||
},
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,34 +7,35 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api import errors
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.constants import (
|
||||
DEFAULT_NPIPE,
|
||||
DEFAULT_UNIX_SOCKET,
|
||||
IS_WINDOWS_PLATFORM,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.context.api import ContextAPI
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.context.context import Context
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.context.api import (
|
||||
ContextAPI,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.context.context import (
|
||||
Context,
|
||||
)
|
||||
|
||||
|
||||
class BaseContextTest(unittest.TestCase):
|
||||
@pytest.mark.skipif(
|
||||
IS_WINDOWS_PLATFORM, reason='Linux specific path check'
|
||||
)
|
||||
@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[5:]
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not IS_WINDOWS_PLATFORM, reason='Windows specific path check'
|
||||
)
|
||||
@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
|
||||
|
||||
@@ -7,17 +7,19 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import unittest
|
||||
|
||||
import requests
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.errors import (
|
||||
APIError, DockerException,
|
||||
create_unexpected_kwargs_error,
|
||||
APIError,
|
||||
DockerException,
|
||||
create_api_error_from_http_exception,
|
||||
create_unexpected_kwargs_error,
|
||||
)
|
||||
|
||||
|
||||
@@ -32,90 +34,90 @@ class APIErrorTest(unittest.TestCase):
|
||||
"""The status_code property is present with 200 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 200
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.status_code == 200
|
||||
|
||||
def test_status_code_400(self):
|
||||
"""The status_code property is present with 400 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 400
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.status_code == 400
|
||||
|
||||
def test_status_code_500(self):
|
||||
"""The status_code property is present with 500 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 500
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.status_code == 500
|
||||
|
||||
def test_is_server_error_200(self):
|
||||
"""Report not server error on 200 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 200
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.is_server_error() is False
|
||||
|
||||
def test_is_server_error_300(self):
|
||||
"""Report not server error on 300 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 300
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.is_server_error() is False
|
||||
|
||||
def test_is_server_error_400(self):
|
||||
"""Report not server error on 400 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 400
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.is_server_error() is False
|
||||
|
||||
def test_is_server_error_500(self):
|
||||
"""Report server error on 500 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 500
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.is_server_error() is True
|
||||
|
||||
def test_is_client_error_500(self):
|
||||
"""Report not client error on 500 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 500
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.is_client_error() is False
|
||||
|
||||
def test_is_client_error_400(self):
|
||||
"""Report client error on 400 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 400
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.is_client_error() is True
|
||||
|
||||
def test_is_error_300(self):
|
||||
"""Report no error on 300 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 300
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.is_error() is False
|
||||
|
||||
def test_is_error_400(self):
|
||||
"""Report error on 400 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 400
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.is_error() is True
|
||||
|
||||
def test_is_error_500(self):
|
||||
"""Report error on 500 response."""
|
||||
resp = requests.Response()
|
||||
resp.status_code = 500
|
||||
err = APIError('', response=resp)
|
||||
err = APIError("", response=resp)
|
||||
assert err.is_error() is True
|
||||
|
||||
def test_create_error_from_exception(self):
|
||||
resp = requests.Response()
|
||||
resp.status_code = 500
|
||||
err = APIError('')
|
||||
err = APIError("")
|
||||
try:
|
||||
resp.raise_for_status()
|
||||
except requests.exceptions.HTTPError as e:
|
||||
@@ -128,9 +130,9 @@ class APIErrorTest(unittest.TestCase):
|
||||
|
||||
class CreateUnexpectedKwargsErrorTest(unittest.TestCase):
|
||||
def test_create_unexpected_kwargs_error_single(self):
|
||||
e = create_unexpected_kwargs_error('f', {'foo': 'bar'})
|
||||
e = create_unexpected_kwargs_error("f", {"foo": "bar"})
|
||||
assert str(e) == "f() got an unexpected keyword argument 'foo'"
|
||||
|
||||
def test_create_unexpected_kwargs_error_multiple(self):
|
||||
e = create_unexpected_kwargs_error('f', {'foo': 'bar', 'baz': 'bosh'})
|
||||
e = create_unexpected_kwargs_error("f", {"foo": "bar", "baz": "bosh"})
|
||||
assert str(e) == "f() got unexpected keyword arguments 'baz', 'foo'"
|
||||
|
||||
@@ -7,19 +7,23 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import unittest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.transport.sshconn import SSHSocket, SSHHTTPAdapter
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.transport.sshconn import (
|
||||
SSHHTTPAdapter,
|
||||
SSHSocket,
|
||||
)
|
||||
|
||||
|
||||
class SSHAdapterTest(unittest.TestCase):
|
||||
@staticmethod
|
||||
def test_ssh_hostname_prefix_trim():
|
||||
conn = SSHHTTPAdapter(
|
||||
base_url="ssh://user@hostname:1234", shell_out=True)
|
||||
conn = SSHHTTPAdapter(base_url="ssh://user@hostname:1234", shell_out=True)
|
||||
assert conn.ssh_host == "user@hostname:1234"
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -7,30 +7,30 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.transport import (
|
||||
ssladapter,
|
||||
)
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.transport import ssladapter
|
||||
|
||||
HAS_MATCH_HOSTNAME = True
|
||||
try:
|
||||
from backports.ssl_match_hostname import (
|
||||
match_hostname, CertificateError
|
||||
)
|
||||
from backports.ssl_match_hostname import CertificateError, match_hostname
|
||||
except ImportError:
|
||||
try:
|
||||
from ssl import (
|
||||
match_hostname, CertificateError
|
||||
)
|
||||
from ssl import CertificateError, match_hostname
|
||||
except ImportError:
|
||||
HAS_MATCH_HOSTNAME = False
|
||||
|
||||
try:
|
||||
from ssl import OP_NO_SSLv3, OP_NO_SSLv2, OP_NO_TLSv1
|
||||
from ssl import OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1
|
||||
except ImportError:
|
||||
OP_NO_SSLv2 = 0x1000000
|
||||
OP_NO_SSLv3 = 0x2000000
|
||||
@@ -47,51 +47,51 @@ class SSLAdapterTest(unittest.TestCase):
|
||||
assert not ssl_context.options & OP_NO_TLSv1
|
||||
|
||||
|
||||
@pytest.mark.skipif(not HAS_MATCH_HOSTNAME, reason='match_hostname is not available')
|
||||
@pytest.mark.skipif(not HAS_MATCH_HOSTNAME, reason="match_hostname is not available")
|
||||
class MatchHostnameTest(unittest.TestCase):
|
||||
cert = {
|
||||
'issuer': (
|
||||
(('countryName', 'US'),),
|
||||
(('stateOrProvinceName', 'California'),),
|
||||
(('localityName', 'San Francisco'),),
|
||||
(('organizationName', 'Docker Inc'),),
|
||||
(('organizationalUnitName', 'Docker-Python'),),
|
||||
(('commonName', 'localhost'),),
|
||||
(('emailAddress', 'info@docker.com'),)
|
||||
"issuer": (
|
||||
(("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': 'Mar 25 23:08:23 2016 GMT',
|
||||
'serialNumber': 'BD5F894C839C548F',
|
||||
'subject': (
|
||||
(('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": "Mar 25 23:08:23 2016 GMT",
|
||||
"serialNumber": "BD5F894C839C548F",
|
||||
"subject": (
|
||||
(("countryName", "US"),),
|
||||
(("stateOrProvinceName", "California"),),
|
||||
(("localityName", "San Francisco"),),
|
||||
(("organizationName", "Docker Inc"),),
|
||||
(("organizationalUnitName", "Docker-Python"),),
|
||||
(("commonName", "localhost"),),
|
||||
(("emailAddress", "info@docker.com"),),
|
||||
),
|
||||
'subjectAltName': (
|
||||
('DNS', 'localhost'),
|
||||
('DNS', '*.gensokyo.jp'),
|
||||
('IP Address', '127.0.0.1'),
|
||||
"subjectAltName": (
|
||||
("DNS", "localhost"),
|
||||
("DNS", "*.gensokyo.jp"),
|
||||
("IP Address", "127.0.0.1"),
|
||||
),
|
||||
'version': 3
|
||||
"version": 3,
|
||||
}
|
||||
|
||||
def test_match_ip_address_success(self):
|
||||
assert match_hostname(self.cert, '127.0.0.1') is None
|
||||
assert match_hostname(self.cert, "127.0.0.1") is None
|
||||
|
||||
def test_match_localhost_success(self):
|
||||
assert match_hostname(self.cert, 'localhost') is None
|
||||
assert match_hostname(self.cert, "localhost") is None
|
||||
|
||||
def test_match_dns_success(self):
|
||||
assert match_hostname(self.cert, 'touhou.gensokyo.jp') is None
|
||||
assert match_hostname(self.cert, "touhou.gensokyo.jp") is None
|
||||
|
||||
def test_match_ip_address_failure(self):
|
||||
with pytest.raises(CertificateError):
|
||||
match_hostname(self.cert, '192.168.0.25')
|
||||
match_hostname(self.cert, "192.168.0.25")
|
||||
|
||||
def test_match_dns_failure(self):
|
||||
with pytest.raises(CertificateError):
|
||||
match_hostname(self.cert, 'foobar.co.uk')
|
||||
match_hostname(self.cert, "foobar.co.uk")
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
@@ -19,9 +21,13 @@ import tempfile
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.constants import IS_WINDOWS_PLATFORM
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.build import exclude_paths, tar
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.constants import (
|
||||
IS_WINDOWS_PLATFORM,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.build import (
|
||||
exclude_paths,
|
||||
tar,
|
||||
)
|
||||
|
||||
|
||||
def make_tree(dirs, files):
|
||||
@@ -31,7 +37,7 @@ def make_tree(dirs, files):
|
||||
os.makedirs(os.path.join(base, path))
|
||||
|
||||
for path in files:
|
||||
with open(os.path.join(base, path), 'w') as f:
|
||||
with open(os.path.join(base, path), "w") as f:
|
||||
f.write("content")
|
||||
|
||||
return base
|
||||
@@ -42,45 +48,45 @@ def convert_paths(collection):
|
||||
|
||||
|
||||
def convert_path(path):
|
||||
return path.replace('/', os.path.sep)
|
||||
return path.replace("/", os.path.sep)
|
||||
|
||||
|
||||
class ExcludePathsTest(unittest.TestCase):
|
||||
dirs = [
|
||||
'foo',
|
||||
'foo/bar',
|
||||
'bar',
|
||||
'target',
|
||||
'target/subdir',
|
||||
'subdir',
|
||||
'subdir/target',
|
||||
'subdir/target/subdir',
|
||||
'subdir/subdir2',
|
||||
'subdir/subdir2/target',
|
||||
'subdir/subdir2/target/subdir'
|
||||
"foo",
|
||||
"foo/bar",
|
||||
"bar",
|
||||
"target",
|
||||
"target/subdir",
|
||||
"subdir",
|
||||
"subdir/target",
|
||||
"subdir/target/subdir",
|
||||
"subdir/subdir2",
|
||||
"subdir/subdir2/target",
|
||||
"subdir/subdir2/target/subdir",
|
||||
]
|
||||
|
||||
files = [
|
||||
'Dockerfile',
|
||||
'Dockerfile.alt',
|
||||
'.dockerignore',
|
||||
'a.py',
|
||||
'a.go',
|
||||
'b.py',
|
||||
'cde.py',
|
||||
'foo/a.py',
|
||||
'foo/b.py',
|
||||
'foo/bar/a.py',
|
||||
'bar/a.py',
|
||||
'foo/Dockerfile3',
|
||||
'target/file.txt',
|
||||
'target/subdir/file.txt',
|
||||
'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',
|
||||
"Dockerfile",
|
||||
"Dockerfile.alt",
|
||||
".dockerignore",
|
||||
"a.py",
|
||||
"a.go",
|
||||
"b.py",
|
||||
"cde.py",
|
||||
"foo/a.py",
|
||||
"foo/b.py",
|
||||
"foo/bar/a.py",
|
||||
"bar/a.py",
|
||||
"foo/Dockerfile3",
|
||||
"target/file.txt",
|
||||
"target/subdir/file.txt",
|
||||
"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",
|
||||
]
|
||||
|
||||
all_paths = set(dirs + files)
|
||||
@@ -95,14 +101,14 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
return set(exclude_paths(self.base, patterns, dockerfile=dockerfile))
|
||||
|
||||
def test_no_excludes(self):
|
||||
assert self.exclude(['']) == convert_paths(self.all_paths)
|
||||
assert self.exclude([""]) == convert_paths(self.all_paths)
|
||||
|
||||
def test_no_dupes(self):
|
||||
paths = exclude_paths(self.base, ['!a.py'])
|
||||
paths = exclude_paths(self.base, ["!a.py"])
|
||||
assert sorted(paths) == sorted(set(paths))
|
||||
|
||||
def test_wildcard_exclude(self):
|
||||
assert self.exclude(['*']) == set(['Dockerfile', '.dockerignore'])
|
||||
assert self.exclude(["*"]) == set(["Dockerfile", ".dockerignore"])
|
||||
|
||||
def test_exclude_dockerfile_dockerignore(self):
|
||||
"""
|
||||
@@ -110,7 +116,7 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
Dockerfile and/or .dockerignore, don't exclude them from
|
||||
the actual tar file.
|
||||
"""
|
||||
assert self.exclude(['Dockerfile', '.dockerignore']) == convert_paths(
|
||||
assert self.exclude(["Dockerfile", ".dockerignore"]) == convert_paths(
|
||||
self.all_paths
|
||||
)
|
||||
|
||||
@@ -119,287 +125,296 @@ 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") == set(
|
||||
["Dockerfile.alt", ".dockerignore"]
|
||||
)
|
||||
|
||||
assert self.exclude(
|
||||
['*'], dockerfile='foo/Dockerfile3'
|
||||
) == convert_paths(set(['foo/Dockerfile3', '.dockerignore']))
|
||||
assert self.exclude(["*"], dockerfile="foo/Dockerfile3") == convert_paths(
|
||||
set(["foo/Dockerfile3", ".dockerignore"])
|
||||
)
|
||||
|
||||
# https://github.com/docker/docker-py/issues/1956
|
||||
assert self.exclude(
|
||||
['*'], dockerfile='./foo/Dockerfile3'
|
||||
) == convert_paths(set(['foo/Dockerfile3', '.dockerignore']))
|
||||
assert self.exclude(["*"], dockerfile="./foo/Dockerfile3") == convert_paths(
|
||||
set(["foo/Dockerfile3", ".dockerignore"])
|
||||
)
|
||||
|
||||
def test_exclude_dockerfile_child(self):
|
||||
includes = self.exclude(['foo/'], dockerfile='foo/Dockerfile3')
|
||||
assert convert_path('foo/Dockerfile3') in includes
|
||||
assert convert_path('foo/a.py') not in includes
|
||||
includes = self.exclude(["foo/"], dockerfile="foo/Dockerfile3")
|
||||
assert convert_path("foo/Dockerfile3") in includes
|
||||
assert convert_path("foo/a.py") not in includes
|
||||
|
||||
def test_single_filename(self):
|
||||
assert self.exclude(['a.py']) == convert_paths(
|
||||
self.all_paths - set(['a.py'])
|
||||
)
|
||||
assert self.exclude(["a.py"]) == convert_paths(self.all_paths - set(["a.py"]))
|
||||
|
||||
def test_single_filename_leading_dot_slash(self):
|
||||
assert self.exclude(['./a.py']) == convert_paths(
|
||||
self.all_paths - set(['a.py'])
|
||||
)
|
||||
assert self.exclude(["./a.py"]) == convert_paths(self.all_paths - set(["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'])
|
||||
)
|
||||
assert self.exclude(["a.py/"]) == convert_paths(self.all_paths - set(["a.py"]))
|
||||
|
||||
def test_wildcard_filename_start(self):
|
||||
assert self.exclude(['*.py']) == convert_paths(
|
||||
self.all_paths - set(['a.py', 'b.py', 'cde.py'])
|
||||
assert self.exclude(["*.py"]) == convert_paths(
|
||||
self.all_paths - set(["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'])
|
||||
assert self.exclude(["*.py", "!b.py"]) == convert_paths(
|
||||
self.all_paths - set(["a.py", "cde.py"])
|
||||
)
|
||||
|
||||
def test_wildcard_with_wildcard_exception(self):
|
||||
assert self.exclude(['*.*', '!*.go']) == convert_paths(
|
||||
self.all_paths - set([
|
||||
'a.py', 'b.py', 'cde.py', 'Dockerfile.alt',
|
||||
])
|
||||
assert self.exclude(["*.*", "!*.go"]) == convert_paths(
|
||||
self.all_paths
|
||||
- set(
|
||||
[
|
||||
"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'])
|
||||
assert self.exclude(["a.*"]) == convert_paths(
|
||||
self.all_paths - set(["a.py", "a.go"])
|
||||
)
|
||||
|
||||
def test_question_mark(self):
|
||||
assert self.exclude(['?.py']) == convert_paths(
|
||||
self.all_paths - set(['a.py', 'b.py'])
|
||||
assert self.exclude(["?.py"]) == convert_paths(
|
||||
self.all_paths - set(["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'])
|
||||
assert self.exclude(["foo/a.py"]) == convert_paths(
|
||||
self.all_paths - set(["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'])
|
||||
assert self.exclude(["/foo/a.py"]) == convert_paths(
|
||||
self.all_paths - set(["foo/a.py"])
|
||||
)
|
||||
|
||||
def test_exclude_include_absolute_path(self):
|
||||
base = make_tree([], ['a.py', 'b.py'])
|
||||
assert exclude_paths(
|
||||
base,
|
||||
['/*', '!/*.py']
|
||||
) == set(['a.py', 'b.py'])
|
||||
base = make_tree([], ["a.py", "b.py"])
|
||||
assert exclude_paths(base, ["/*", "!/*.py"]) == set(["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'])
|
||||
assert self.exclude(["foo/whoops/../a.py"]) == convert_paths(
|
||||
self.all_paths - set(["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'])
|
||||
assert self.exclude(["foo/*.py"]) == convert_paths(
|
||||
self.all_paths - set(["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'])
|
||||
assert self.exclude(["*/a.py"]) == convert_paths(
|
||||
self.all_paths - set(["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'])
|
||||
assert self.exclude(["*/*.py"]) == convert_paths(
|
||||
self.all_paths - set(["foo/a.py", "foo/b.py", "bar/a.py"])
|
||||
)
|
||||
|
||||
def test_directory(self):
|
||||
assert self.exclude(['foo']) == convert_paths(
|
||||
self.all_paths - set([
|
||||
'foo', 'foo/a.py', 'foo/b.py', 'foo/bar', 'foo/bar/a.py',
|
||||
'foo/Dockerfile3'
|
||||
])
|
||||
assert self.exclude(["foo"]) == convert_paths(
|
||||
self.all_paths
|
||||
- set(
|
||||
[
|
||||
"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([
|
||||
'foo', 'foo/a.py', 'foo/b.py',
|
||||
'foo/bar', 'foo/bar/a.py', 'foo/Dockerfile3'
|
||||
])
|
||||
assert self.exclude(["foo"]) == convert_paths(
|
||||
self.all_paths
|
||||
- set(
|
||||
[
|
||||
"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([
|
||||
'foo/a.py', 'foo/b.py', 'foo', 'foo/bar',
|
||||
'foo/Dockerfile3'
|
||||
])
|
||||
assert self.exclude(["foo", "!foo/bar/a.py"]) == convert_paths(
|
||||
self.all_paths
|
||||
- set(["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([
|
||||
'foo/a.py', 'foo/b.py', 'foo', 'foo/Dockerfile3'
|
||||
])
|
||||
assert self.exclude(["foo", "!foo/bar"]) == convert_paths(
|
||||
self.all_paths - set(["foo/a.py", "foo/b.py", "foo", "foo/Dockerfile3"])
|
||||
)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not IS_WINDOWS_PLATFORM, reason='Backslash patterns only on Windows'
|
||||
not IS_WINDOWS_PLATFORM, reason="Backslash patterns only on Windows"
|
||||
)
|
||||
def test_directory_with_subdir_exception_win32_pathsep(self):
|
||||
assert self.exclude(['foo', '!foo\\bar']) == convert_paths(
|
||||
self.all_paths - set([
|
||||
'foo/a.py', 'foo/b.py', 'foo', 'foo/Dockerfile3'
|
||||
])
|
||||
assert self.exclude(["foo", "!foo\\bar"]) == convert_paths(
|
||||
self.all_paths - set(["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([
|
||||
'foo/bar', 'foo/bar/a.py', 'foo', 'foo/Dockerfile3'
|
||||
])
|
||||
assert self.exclude(["foo", "!foo/*.py"]) == convert_paths(
|
||||
self.all_paths - set(["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'])
|
||||
assert self.exclude(["foo/bar"]) == convert_paths(
|
||||
self.all_paths - set(["foo/bar", "foo/bar/a.py"])
|
||||
)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not IS_WINDOWS_PLATFORM, reason='Backslash patterns only on Windows'
|
||||
not IS_WINDOWS_PLATFORM, reason="Backslash patterns only on Windows"
|
||||
)
|
||||
def test_subdirectory_win32_pathsep(self):
|
||||
assert self.exclude(['foo\\bar']) == convert_paths(
|
||||
self.all_paths - set(['foo/bar', 'foo/bar/a.py'])
|
||||
assert self.exclude(["foo\\bar"]) == convert_paths(
|
||||
self.all_paths - set(["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'
|
||||
])
|
||||
assert self.exclude(["**/a.py"]) == convert_paths(
|
||||
self.all_paths - set(["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'])
|
||||
assert self.exclude(["foo/**/bar"]) == convert_paths(
|
||||
self.all_paths - set(["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',
|
||||
])
|
||||
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",
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
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',
|
||||
])
|
||||
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",
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
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',
|
||||
])
|
||||
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):
|
||||
# This may be surprising but it matches the CLI's behavior
|
||||
# (tested with 18.05.0-ce on linux)
|
||||
base = make_tree(['a'], ['a/b.py'])
|
||||
assert exclude_paths(
|
||||
base,
|
||||
['*', '!*/b.py']
|
||||
) == set()
|
||||
base = make_tree(["a"], ["a/b.py"])
|
||||
assert exclude_paths(base, ["*", "!*/b.py"]) == set()
|
||||
|
||||
def test_last_line_precedence(self):
|
||||
base = make_tree(
|
||||
[],
|
||||
['garbage.md',
|
||||
'trash.md',
|
||||
'README.md',
|
||||
'README-bis.md',
|
||||
'README-secret.md'])
|
||||
assert exclude_paths(
|
||||
base,
|
||||
['*.md', '!README*.md', 'README-secret.md']
|
||||
) == set(['README.md', 'README-bis.md'])
|
||||
[
|
||||
"garbage.md",
|
||||
"trash.md",
|
||||
"README.md",
|
||||
"README-bis.md",
|
||||
"README-secret.md",
|
||||
],
|
||||
)
|
||||
assert exclude_paths(base, ["*.md", "!README*.md", "README-secret.md"]) == set(
|
||||
["README.md", "README-bis.md"]
|
||||
)
|
||||
|
||||
def test_parent_directory(self):
|
||||
base = make_tree(
|
||||
[],
|
||||
['a.py',
|
||||
'b.py',
|
||||
'c.py'])
|
||||
base = make_tree([], ["a.py", "b.py", "c.py"])
|
||||
# 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 explicitly "replace
|
||||
# "/.." by "/" at the beginning of a path".
|
||||
assert exclude_paths(
|
||||
base,
|
||||
['../a.py', '/../b.py']
|
||||
) == set(['c.py'])
|
||||
assert exclude_paths(base, ["../a.py", "/../b.py"]) == set(["c.py"])
|
||||
|
||||
|
||||
class TarTest(unittest.TestCase):
|
||||
def test_tar_with_excludes(self):
|
||||
dirs = [
|
||||
'foo',
|
||||
'foo/bar',
|
||||
'bar',
|
||||
"foo",
|
||||
"foo/bar",
|
||||
"bar",
|
||||
]
|
||||
|
||||
files = [
|
||||
'Dockerfile',
|
||||
'Dockerfile.alt',
|
||||
'.dockerignore',
|
||||
'a.py',
|
||||
'a.go',
|
||||
'b.py',
|
||||
'cde.py',
|
||||
'foo/a.py',
|
||||
'foo/b.py',
|
||||
'foo/bar/a.py',
|
||||
'bar/a.py',
|
||||
"Dockerfile",
|
||||
"Dockerfile.alt",
|
||||
".dockerignore",
|
||||
"a.py",
|
||||
"a.go",
|
||||
"b.py",
|
||||
"cde.py",
|
||||
"foo/a.py",
|
||||
"foo/b.py",
|
||||
"foo/bar/a.py",
|
||||
"bar/a.py",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
'*.py',
|
||||
'!b.py',
|
||||
'!a.go',
|
||||
'foo',
|
||||
'Dockerfile*',
|
||||
'.dockerignore',
|
||||
"*.py",
|
||||
"!b.py",
|
||||
"!a.go",
|
||||
"foo",
|
||||
"Dockerfile*",
|
||||
".dockerignore",
|
||||
]
|
||||
|
||||
expected_names = set([
|
||||
'Dockerfile',
|
||||
'.dockerignore',
|
||||
'a.go',
|
||||
'b.py',
|
||||
'bar',
|
||||
'bar/a.py',
|
||||
])
|
||||
expected_names = set(
|
||||
[
|
||||
"Dockerfile",
|
||||
".dockerignore",
|
||||
"a.go",
|
||||
"b.py",
|
||||
"bar",
|
||||
"bar/a.py",
|
||||
]
|
||||
)
|
||||
|
||||
base = make_tree(dirs, files)
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
@@ -411,99 +426,99 @@ class TarTest(unittest.TestCase):
|
||||
def test_tar_with_empty_directory(self):
|
||||
base = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
for d in ['foo', 'bar']:
|
||||
for d in ["foo", "bar"]:
|
||||
os.makedirs(os.path.join(base, d))
|
||||
with tar(base) as archive:
|
||||
tar_data = tarfile.open(fileobj=archive)
|
||||
assert sorted(tar_data.getnames()) == ['bar', 'foo']
|
||||
assert sorted(tar_data.getnames()) == ["bar", "foo"]
|
||||
|
||||
@pytest.mark.skipif(
|
||||
IS_WINDOWS_PLATFORM or os.geteuid() == 0,
|
||||
reason='root user always has access ; no chmod on Windows'
|
||||
reason="root user always has access ; no chmod on Windows",
|
||||
)
|
||||
def test_tar_with_inaccessible_file(self):
|
||||
base = tempfile.mkdtemp()
|
||||
full_path = os.path.join(base, 'foo')
|
||||
full_path = os.path.join(base, "foo")
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
with open(full_path, 'w') as f:
|
||||
f.write('content')
|
||||
with open(full_path, "w") as f:
|
||||
f.write("content")
|
||||
os.chmod(full_path, 0o222)
|
||||
with pytest.raises(IOError) as ei:
|
||||
tar(base)
|
||||
|
||||
assert f'Can not read file in context: {full_path}' in ei.exconly()
|
||||
assert f"Can not read file in context: {full_path}" in ei.exconly()
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='No symlinks on Windows')
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
||||
def test_tar_with_file_symlinks(self):
|
||||
base = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
with open(os.path.join(base, 'foo'), 'w') as f:
|
||||
with open(os.path.join(base, "foo"), "w") as f:
|
||||
f.write("content")
|
||||
os.makedirs(os.path.join(base, 'bar'))
|
||||
os.symlink('../foo', os.path.join(base, 'bar/foo'))
|
||||
os.makedirs(os.path.join(base, "bar"))
|
||||
os.symlink("../foo", os.path.join(base, "bar/foo"))
|
||||
with tar(base) as archive:
|
||||
tar_data = tarfile.open(fileobj=archive)
|
||||
assert sorted(tar_data.getnames()) == ['bar', 'bar/foo', 'foo']
|
||||
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='No symlinks on Windows')
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
||||
def test_tar_with_directory_symlinks(self):
|
||||
base = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
for d in ['foo', 'bar']:
|
||||
for d in ["foo", "bar"]:
|
||||
os.makedirs(os.path.join(base, d))
|
||||
os.symlink('../foo', os.path.join(base, 'bar/foo'))
|
||||
os.symlink("../foo", os.path.join(base, "bar/foo"))
|
||||
with tar(base) as archive:
|
||||
tar_data = tarfile.open(fileobj=archive)
|
||||
assert sorted(tar_data.getnames()) == ['bar', 'bar/foo', 'foo']
|
||||
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='No symlinks on Windows')
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
||||
def test_tar_with_broken_symlinks(self):
|
||||
base = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
for d in ['foo', 'bar']:
|
||||
for d in ["foo", "bar"]:
|
||||
os.makedirs(os.path.join(base, d))
|
||||
|
||||
os.symlink('../baz', os.path.join(base, 'bar/foo'))
|
||||
os.symlink("../baz", os.path.join(base, "bar/foo"))
|
||||
with tar(base) as archive:
|
||||
tar_data = tarfile.open(fileobj=archive)
|
||||
assert sorted(tar_data.getnames()) == ['bar', 'bar/foo', 'foo']
|
||||
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='No UNIX sockets on Win32')
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No UNIX sockets on Win32")
|
||||
def test_tar_socket_file(self):
|
||||
base = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
for d in ['foo', 'bar']:
|
||||
for d in ["foo", "bar"]:
|
||||
os.makedirs(os.path.join(base, d))
|
||||
sock = socket.socket(socket.AF_UNIX)
|
||||
self.addCleanup(sock.close)
|
||||
sock.bind(os.path.join(base, 'test.sock'))
|
||||
sock.bind(os.path.join(base, "test.sock"))
|
||||
with tar(base) as archive:
|
||||
tar_data = tarfile.open(fileobj=archive)
|
||||
assert sorted(tar_data.getnames()) == ['bar', 'foo']
|
||||
assert sorted(tar_data.getnames()) == ["bar", "foo"]
|
||||
|
||||
def tar_test_negative_mtime_bug(self):
|
||||
base = tempfile.mkdtemp()
|
||||
filename = os.path.join(base, 'th.txt')
|
||||
filename = os.path.join(base, "th.txt")
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
with open(filename, 'w') as f:
|
||||
f.write('Invisible Full Moon')
|
||||
with open(filename, "w") as f:
|
||||
f.write("Invisible Full Moon")
|
||||
os.utime(filename, (12345, -3600.0))
|
||||
with tar(base) as archive:
|
||||
tar_data = tarfile.open(fileobj=archive)
|
||||
assert tar_data.getnames() == ['th.txt']
|
||||
assert tar_data.getmember('th.txt').mtime == -3600
|
||||
assert tar_data.getnames() == ["th.txt"]
|
||||
assert tar_data.getmember("th.txt").mtime == -3600
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason='No symlinks on Windows')
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
||||
def test_tar_directory_link(self):
|
||||
dirs = ['a', 'b', 'a/c']
|
||||
files = ['a/hello.py', 'b/utils.py', 'a/c/descend.py']
|
||||
dirs = ["a", "b", "a/c"]
|
||||
files = ["a/hello.py", "b/utils.py", "a/c/descend.py"]
|
||||
base = make_tree(dirs, files)
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
os.symlink(os.path.join(base, 'b'), os.path.join(base, 'a/c/b'))
|
||||
os.symlink(os.path.join(base, "b"), os.path.join(base, "a/c/b"))
|
||||
with tar(base) as archive:
|
||||
tar_data = tarfile.open(fileobj=archive)
|
||||
names = tar_data.getnames()
|
||||
for member in dirs + files:
|
||||
assert member in names
|
||||
assert 'a/c/b' in names
|
||||
assert 'a/c/b/utils.py' not in names
|
||||
assert "a/c/b" in names
|
||||
assert "a/c/b/utils.py" not in names
|
||||
|
||||
@@ -7,18 +7,20 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import json
|
||||
import os
|
||||
import unittest
|
||||
import shutil
|
||||
import tempfile
|
||||
import json
|
||||
|
||||
from pytest import mark, fixture
|
||||
import unittest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils import config
|
||||
from pytest import fixture, mark
|
||||
|
||||
|
||||
try:
|
||||
from unittest import mock
|
||||
@@ -33,46 +35,46 @@ class FindConfigFileTest(unittest.TestCase):
|
||||
self.mkdir = tmpdir.mkdir
|
||||
|
||||
def test_find_config_fallback(self):
|
||||
tmpdir = self.mkdir('test_find_config_fallback')
|
||||
tmpdir = self.mkdir("test_find_config_fallback")
|
||||
|
||||
with mock.patch.dict(os.environ, {'HOME': str(tmpdir)}):
|
||||
with mock.patch.dict(os.environ, {"HOME": str(tmpdir)}):
|
||||
assert config.find_config_file() is None
|
||||
|
||||
def test_find_config_from_explicit_path(self):
|
||||
tmpdir = self.mkdir('test_find_config_from_explicit_path')
|
||||
config_path = tmpdir.ensure('my-config-file.json')
|
||||
tmpdir = self.mkdir("test_find_config_from_explicit_path")
|
||||
config_path = tmpdir.ensure("my-config-file.json")
|
||||
|
||||
assert config.find_config_file(str(config_path)) == str(config_path)
|
||||
|
||||
def test_find_config_from_environment(self):
|
||||
tmpdir = self.mkdir('test_find_config_from_environment')
|
||||
config_path = tmpdir.ensure('config.json')
|
||||
tmpdir = self.mkdir("test_find_config_from_environment")
|
||||
config_path = tmpdir.ensure("config.json")
|
||||
|
||||
with mock.patch.dict(os.environ, {'DOCKER_CONFIG': str(tmpdir)}):
|
||||
with mock.patch.dict(os.environ, {"DOCKER_CONFIG": str(tmpdir)}):
|
||||
assert config.find_config_file() == str(config_path)
|
||||
|
||||
@mark.skipif("sys.platform == 'win32'")
|
||||
def test_find_config_from_home_posix(self):
|
||||
tmpdir = self.mkdir('test_find_config_from_home_posix')
|
||||
config_path = tmpdir.ensure('.docker', 'config.json')
|
||||
tmpdir = self.mkdir("test_find_config_from_home_posix")
|
||||
config_path = tmpdir.ensure(".docker", "config.json")
|
||||
|
||||
with mock.patch.dict(os.environ, {'HOME': str(tmpdir)}):
|
||||
with mock.patch.dict(os.environ, {"HOME": str(tmpdir)}):
|
||||
assert config.find_config_file() == str(config_path)
|
||||
|
||||
@mark.skipif("sys.platform == 'win32'")
|
||||
def test_find_config_from_home_legacy_name(self):
|
||||
tmpdir = self.mkdir('test_find_config_from_home_legacy_name')
|
||||
config_path = tmpdir.ensure('.dockercfg')
|
||||
tmpdir = self.mkdir("test_find_config_from_home_legacy_name")
|
||||
config_path = tmpdir.ensure(".dockercfg")
|
||||
|
||||
with mock.patch.dict(os.environ, {'HOME': str(tmpdir)}):
|
||||
with mock.patch.dict(os.environ, {"HOME": str(tmpdir)}):
|
||||
assert config.find_config_file() == str(config_path)
|
||||
|
||||
@mark.skipif("sys.platform != 'win32'")
|
||||
def test_find_config_from_home_windows(self):
|
||||
tmpdir = self.mkdir('test_find_config_from_home_windows')
|
||||
config_path = tmpdir.ensure('.docker', 'config.json')
|
||||
tmpdir = self.mkdir("test_find_config_from_home_windows")
|
||||
config_path = tmpdir.ensure(".docker", "config.json")
|
||||
|
||||
with mock.patch.dict(os.environ, {'USERPROFILE': str(tmpdir)}):
|
||||
with mock.patch.dict(os.environ, {"USERPROFILE": str(tmpdir)}):
|
||||
assert config.find_config_file() == str(config_path)
|
||||
|
||||
|
||||
@@ -89,32 +91,24 @@ class LoadConfigTest(unittest.TestCase):
|
||||
folder = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, folder)
|
||||
|
||||
dockercfg_path = os.path.join(folder, 'config.json')
|
||||
dockercfg_path = os.path.join(folder, "config.json")
|
||||
config_data = {
|
||||
'HttpHeaders': {
|
||||
'Name': 'Spike',
|
||||
'Surname': 'Spiegel'
|
||||
},
|
||||
"HttpHeaders": {"Name": "Spike", "Surname": "Spiegel"},
|
||||
}
|
||||
|
||||
with open(dockercfg_path, 'w') as f:
|
||||
with open(dockercfg_path, "w") as f:
|
||||
json.dump(config_data, f)
|
||||
|
||||
cfg = config.load_general_config(dockercfg_path)
|
||||
assert 'HttpHeaders' in cfg
|
||||
assert cfg['HttpHeaders'] == {
|
||||
'Name': 'Spike',
|
||||
'Surname': 'Spiegel'
|
||||
}
|
||||
assert "HttpHeaders" in cfg
|
||||
assert cfg["HttpHeaders"] == {"Name": "Spike", "Surname": "Spiegel"}
|
||||
|
||||
def test_load_config_detach_keys(self):
|
||||
folder = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, folder)
|
||||
dockercfg_path = os.path.join(folder, 'config.json')
|
||||
config_data = {
|
||||
'detachKeys': 'ctrl-q, ctrl-u, ctrl-i'
|
||||
}
|
||||
with open(dockercfg_path, 'w') as f:
|
||||
dockercfg_path = os.path.join(folder, "config.json")
|
||||
config_data = {"detachKeys": "ctrl-q, ctrl-u, ctrl-i"}
|
||||
with open(dockercfg_path, "w") as f:
|
||||
json.dump(config_data, f)
|
||||
|
||||
cfg = config.load_general_config(dockercfg_path)
|
||||
@@ -123,13 +117,11 @@ class LoadConfigTest(unittest.TestCase):
|
||||
def test_load_config_from_env(self):
|
||||
folder = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, folder)
|
||||
dockercfg_path = os.path.join(folder, 'config.json')
|
||||
config_data = {
|
||||
'detachKeys': 'ctrl-q, ctrl-u, ctrl-i'
|
||||
}
|
||||
with open(dockercfg_path, 'w') as f:
|
||||
dockercfg_path = os.path.join(folder, "config.json")
|
||||
config_data = {"detachKeys": "ctrl-q, ctrl-u, ctrl-i"}
|
||||
with open(dockercfg_path, "w") as f:
|
||||
json.dump(config_data, f)
|
||||
|
||||
with mock.patch.dict(os.environ, {'DOCKER_CONFIG': folder}):
|
||||
with mock.patch.dict(os.environ, {"DOCKER_CONFIG": folder}):
|
||||
cfg = config.load_general_config(None)
|
||||
assert cfg == config_data
|
||||
|
||||
@@ -7,20 +7,28 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import unittest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.api.client import APIClient
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.decorators import update_headers
|
||||
from ansible_collections.community.docker.tests.unit.plugins.module_utils._api.constants import DEFAULT_DOCKER_API_VERSION
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.api.client import (
|
||||
APIClient,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.decorators import (
|
||||
update_headers,
|
||||
)
|
||||
from ansible_collections.community.docker.tests.unit.plugins.module_utils._api.constants import (
|
||||
DEFAULT_DOCKER_API_VERSION,
|
||||
)
|
||||
|
||||
|
||||
class DecoratorsTest(unittest.TestCase):
|
||||
def test_update_headers(self):
|
||||
sample_headers = {
|
||||
'X-Docker-Locale': 'en-US',
|
||||
"X-Docker-Locale": "en-US",
|
||||
}
|
||||
|
||||
def f(self, headers=None):
|
||||
@@ -32,17 +40,15 @@ class DecoratorsTest(unittest.TestCase):
|
||||
g = update_headers(f)
|
||||
assert g(client, headers=None) is None
|
||||
assert g(client, headers={}) == {}
|
||||
assert g(client, headers={'Content-type': 'application/json'}) == {
|
||||
'Content-type': 'application/json',
|
||||
assert g(client, headers={"Content-type": "application/json"}) == {
|
||||
"Content-type": "application/json",
|
||||
}
|
||||
|
||||
client._general_configs = {
|
||||
'HttpHeaders': sample_headers
|
||||
}
|
||||
client._general_configs = {"HttpHeaders": sample_headers}
|
||||
|
||||
assert g(client, headers=None) == sample_headers
|
||||
assert g(client, headers={}) == sample_headers
|
||||
assert g(client, headers={'Content-type': 'application/json'}) == {
|
||||
'Content-type': 'application/json',
|
||||
'X-Docker-Locale': 'en-US',
|
||||
assert g(client, headers={"Content-type": "application/json"}) == {
|
||||
"Content-type": "application/json",
|
||||
"X-Docker-Locale": "en-US",
|
||||
}
|
||||
|
||||
@@ -7,10 +7,16 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.json_stream import json_splitter, stream_as_text, json_stream
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.json_stream import (
|
||||
json_splitter,
|
||||
json_stream,
|
||||
stream_as_text,
|
||||
)
|
||||
|
||||
|
||||
class TestJsonSplitter:
|
||||
@@ -21,24 +27,24 @@ class TestJsonSplitter:
|
||||
|
||||
def test_json_splitter_with_object(self):
|
||||
data = '{"foo": "bar"}\n \n{"next": "obj"}'
|
||||
assert json_splitter(data) == ({'foo': 'bar'}, '{"next": "obj"}')
|
||||
assert json_splitter(data) == ({"foo": "bar"}, '{"next": "obj"}')
|
||||
|
||||
def test_json_splitter_leading_whitespace(self):
|
||||
data = '\n \r{"foo": "bar"}\n\n {"next": "obj"}'
|
||||
assert json_splitter(data) == ({'foo': 'bar'}, '{"next": "obj"}')
|
||||
assert json_splitter(data) == ({"foo": "bar"}, '{"next": "obj"}')
|
||||
|
||||
|
||||
class TestStreamAsText:
|
||||
|
||||
def test_stream_with_non_utf_unicode_character(self):
|
||||
stream = [b'\xed\xf3\xf3']
|
||||
output, = stream_as_text(stream)
|
||||
assert output == '���'
|
||||
stream = [b"\xed\xf3\xf3"]
|
||||
(output,) = stream_as_text(stream)
|
||||
assert output == "���"
|
||||
|
||||
def test_stream_with_utf_character(self):
|
||||
stream = ['ěĝ'.encode('utf-8')]
|
||||
output, = stream_as_text(stream)
|
||||
assert output == 'ěĝ'
|
||||
stream = ["ěĝ".encode("utf-8")]
|
||||
(output,) = stream_as_text(stream)
|
||||
assert output == "ěĝ"
|
||||
|
||||
|
||||
class TestJsonStream:
|
||||
@@ -50,21 +56,13 @@ class TestJsonStream:
|
||||
]
|
||||
output = list(json_stream(stream))
|
||||
assert output == [
|
||||
{'one': 'two'},
|
||||
{"one": "two"},
|
||||
{},
|
||||
[1, 2, 3],
|
||||
[],
|
||||
]
|
||||
|
||||
def test_with_leading_whitespace(self):
|
||||
stream = [
|
||||
'\n \r\n {"one": "two"}{"x": 1}',
|
||||
' {"three": "four"}\t\t{"x": 2}'
|
||||
]
|
||||
stream = ['\n \r\n {"one": "two"}{"x": 1}', ' {"three": "four"}\t\t{"x": 2}']
|
||||
output = list(json_stream(stream))
|
||||
assert output == [
|
||||
{'one': 'two'},
|
||||
{'x': 1},
|
||||
{'three': 'four'},
|
||||
{'x': 2}
|
||||
]
|
||||
assert output == [{"one": "two"}, {"x": 1}, {"three": "four"}, {"x": 2}]
|
||||
|
||||
@@ -7,14 +7,18 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.ports import build_port_bindings, split_port
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.ports import (
|
||||
build_port_bindings,
|
||||
split_port,
|
||||
)
|
||||
|
||||
|
||||
class PortsTest(unittest.TestCase):
|
||||
@@ -24,10 +28,8 @@ class PortsTest(unittest.TestCase):
|
||||
assert external_port == [("127.0.0.1", "1000")]
|
||||
|
||||
def test_split_port_with_protocol(self):
|
||||
for protocol in ['tcp', 'udp', 'sctp']:
|
||||
internal_port, external_port = split_port(
|
||||
"127.0.0.1:1000:2000/" + protocol
|
||||
)
|
||||
for protocol in ["tcp", "udp", "sctp"]:
|
||||
internal_port, external_port = split_port("127.0.0.1:1000:2000/" + protocol)
|
||||
assert internal_port == ["2000/" + protocol]
|
||||
assert external_port == [("127.0.0.1", "1000")]
|
||||
|
||||
@@ -67,20 +69,17 @@ class PortsTest(unittest.TestCase):
|
||||
assert external_port is None
|
||||
|
||||
def test_split_port_range_with_protocol(self):
|
||||
internal_port, external_port = split_port(
|
||||
"127.0.0.1:1000-1001:2000-2001/udp")
|
||||
internal_port, external_port = split_port("127.0.0.1:1000-1001:2000-2001/udp")
|
||||
assert internal_port == ["2000/udp", "2001/udp"]
|
||||
assert external_port == [("127.0.0.1", "1000"), ("127.0.0.1", "1001")]
|
||||
|
||||
def test_split_port_with_ipv6_address(self):
|
||||
internal_port, external_port = split_port(
|
||||
"2001:abcd:ef00::2:1000:2000")
|
||||
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_with_ipv6_square_brackets_address(self):
|
||||
internal_port, external_port = split_port(
|
||||
"[2001:abcd:ef00::2]:1000:2000")
|
||||
internal_port, external_port = split_port("[2001:abcd:ef00::2]:1000:2000")
|
||||
assert internal_port == ["2000"]
|
||||
assert external_port == [("2001:abcd:ef00::2", "1000")]
|
||||
|
||||
@@ -117,7 +116,7 @@ class PortsTest(unittest.TestCase):
|
||||
split_port("")
|
||||
|
||||
def test_split_port_non_string(self):
|
||||
assert split_port(1243) == (['1243'], None)
|
||||
assert split_port(1243) == (["1243"], None)
|
||||
|
||||
def test_build_port_bindings_with_one_port(self):
|
||||
port_bindings = build_port_bindings(["127.0.0.1:1000:1000"])
|
||||
@@ -125,14 +124,14 @@ class PortsTest(unittest.TestCase):
|
||||
|
||||
def test_build_port_bindings_with_matching_internal_ports(self):
|
||||
port_bindings = build_port_bindings(
|
||||
["127.0.0.1:1000:1000", "127.0.0.1:2000:1000"])
|
||||
assert port_bindings["1000"] == [
|
||||
("127.0.0.1", "1000"), ("127.0.0.1", "2000")
|
||||
]
|
||||
["127.0.0.1:1000:1000", "127.0.0.1:2000:1000"]
|
||||
)
|
||||
assert port_bindings["1000"] == [("127.0.0.1", "1000"), ("127.0.0.1", "2000")]
|
||||
|
||||
def test_build_port_bindings_with_nonmatching_internal_ports(self):
|
||||
port_bindings = build_port_bindings(
|
||||
["127.0.0.1:1000:1000", "127.0.0.1:2000:2000"])
|
||||
["127.0.0.1:1000:1000", "127.0.0.1:2000:2000"]
|
||||
)
|
||||
assert port_bindings["1000"] == [("127.0.0.1", "1000")]
|
||||
assert port_bindings["2000"] == [("127.0.0.1", "2000")]
|
||||
|
||||
@@ -143,16 +142,14 @@ class PortsTest(unittest.TestCase):
|
||||
|
||||
def test_build_port_bindings_with_matching_internal_port_ranges(self):
|
||||
port_bindings = build_port_bindings(
|
||||
["127.0.0.1:1000-1001:1000-1001", "127.0.0.1:2000-2001:1000-1001"])
|
||||
assert port_bindings["1000"] == [
|
||||
("127.0.0.1", "1000"), ("127.0.0.1", "2000")
|
||||
]
|
||||
assert port_bindings["1001"] == [
|
||||
("127.0.0.1", "1001"), ("127.0.0.1", "2001")
|
||||
]
|
||||
["127.0.0.1:1000-1001:1000-1001", "127.0.0.1:2000-2001:1000-1001"]
|
||||
)
|
||||
assert port_bindings["1000"] == [("127.0.0.1", "1000"), ("127.0.0.1", "2000")]
|
||||
assert port_bindings["1001"] == [("127.0.0.1", "1001"), ("127.0.0.1", "2001")]
|
||||
|
||||
def test_build_port_bindings_with_nonmatching_internal_port_ranges(self):
|
||||
port_bindings = build_port_bindings(
|
||||
["127.0.0.1:1000:1000", "127.0.0.1:2000:2000"])
|
||||
["127.0.0.1:1000:1000", "127.0.0.1:2000:2000"]
|
||||
)
|
||||
assert port_bindings["1000"] == [("127.0.0.1", "1000")]
|
||||
assert port_bindings["2000"] == [("127.0.0.1", "2000")]
|
||||
|
||||
@@ -7,40 +7,46 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import unittest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.proxy import ProxyConfig
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.proxy import (
|
||||
ProxyConfig,
|
||||
)
|
||||
|
||||
|
||||
HTTP = 'http://test:80'
|
||||
HTTPS = 'https://test:443'
|
||||
FTP = 'ftp://user:password@host:23'
|
||||
NO_PROXY = 'localhost,.localdomain'
|
||||
HTTP = "http://test:80"
|
||||
HTTPS = "https://test:443"
|
||||
FTP = "ftp://user:password@host:23"
|
||||
NO_PROXY = "localhost,.localdomain"
|
||||
CONFIG = ProxyConfig(http=HTTP, https=HTTPS, ftp=FTP, no_proxy=NO_PROXY)
|
||||
ENV = {
|
||||
'http_proxy': HTTP,
|
||||
'HTTP_PROXY': HTTP,
|
||||
'https_proxy': HTTPS,
|
||||
'HTTPS_PROXY': HTTPS,
|
||||
'ftp_proxy': FTP,
|
||||
'FTP_PROXY': FTP,
|
||||
'no_proxy': NO_PROXY,
|
||||
'NO_PROXY': NO_PROXY,
|
||||
"http_proxy": HTTP,
|
||||
"HTTP_PROXY": HTTP,
|
||||
"https_proxy": HTTPS,
|
||||
"HTTPS_PROXY": HTTPS,
|
||||
"ftp_proxy": FTP,
|
||||
"FTP_PROXY": FTP,
|
||||
"no_proxy": NO_PROXY,
|
||||
"NO_PROXY": NO_PROXY,
|
||||
}
|
||||
|
||||
|
||||
class ProxyConfigTest(unittest.TestCase):
|
||||
|
||||
def test_from_dict(self):
|
||||
config = ProxyConfig.from_dict({
|
||||
'httpProxy': HTTP,
|
||||
'httpsProxy': HTTPS,
|
||||
'ftpProxy': FTP,
|
||||
'noProxy': NO_PROXY
|
||||
})
|
||||
config = ProxyConfig.from_dict(
|
||||
{
|
||||
"httpProxy": HTTP,
|
||||
"httpsProxy": HTTPS,
|
||||
"ftpProxy": FTP,
|
||||
"noProxy": NO_PROXY,
|
||||
}
|
||||
)
|
||||
self.assertEqual(CONFIG.http, config.http)
|
||||
self.assertEqual(CONFIG.https, config.https)
|
||||
self.assertEqual(CONFIG.ftp, config.ftp)
|
||||
@@ -53,18 +59,18 @@ class ProxyConfigTest(unittest.TestCase):
|
||||
self.assertIsNone(config.ftp)
|
||||
self.assertIsNone(config.no_proxy)
|
||||
|
||||
config = ProxyConfig(http='a', https='b', ftp='c', no_proxy='d')
|
||||
self.assertEqual(config.http, 'a')
|
||||
self.assertEqual(config.https, 'b')
|
||||
self.assertEqual(config.ftp, 'c')
|
||||
self.assertEqual(config.no_proxy, 'd')
|
||||
config = ProxyConfig(http="a", https="b", ftp="c", no_proxy="d")
|
||||
self.assertEqual(config.http, "a")
|
||||
self.assertEqual(config.https, "b")
|
||||
self.assertEqual(config.ftp, "c")
|
||||
self.assertEqual(config.no_proxy, "d")
|
||||
|
||||
def test_truthiness(self):
|
||||
assert not ProxyConfig()
|
||||
assert ProxyConfig(http='non-zero')
|
||||
assert ProxyConfig(https='non-zero')
|
||||
assert ProxyConfig(ftp='non-zero')
|
||||
assert ProxyConfig(no_proxy='non-zero')
|
||||
assert ProxyConfig(http="non-zero")
|
||||
assert ProxyConfig(https="non-zero")
|
||||
assert ProxyConfig(ftp="non-zero")
|
||||
assert ProxyConfig(no_proxy="non-zero")
|
||||
|
||||
def test_environment(self):
|
||||
self.assertDictEqual(CONFIG.get_environment(), ENV)
|
||||
@@ -75,16 +81,17 @@ class ProxyConfigTest(unittest.TestCase):
|
||||
# Proxy config is non null, env is None.
|
||||
self.assertSetEqual(
|
||||
set(CONFIG.inject_proxy_environment(None)),
|
||||
set(f'{k}={v}' for k, v in ENV.items()))
|
||||
set(f"{k}={v}" for k, v in ENV.items()),
|
||||
)
|
||||
|
||||
# Proxy config is null, env is None.
|
||||
self.assertIsNone(ProxyConfig().inject_proxy_environment(None), None)
|
||||
|
||||
env = ['FOO=BAR', 'BAR=BAZ']
|
||||
env = ["FOO=BAR", "BAR=BAZ"]
|
||||
|
||||
# Proxy config is non null, env is non null
|
||||
actual = CONFIG.inject_proxy_environment(env)
|
||||
expected = [f'{k}={v}' for k, v in ENV.items()] + 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]))
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
# It is licensed under the Apache 2.0 license (see LICENSES/Apache-2.0.txt in this collection)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import base64
|
||||
@@ -19,22 +21,36 @@ import tempfile
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.api.client import APIClient
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.constants import IS_WINDOWS_PLATFORM
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.errors import DockerException
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.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, format_environment,
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.api.client import (
|
||||
APIClient,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.constants import (
|
||||
IS_WINDOWS_PLATFORM,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.errors import (
|
||||
DockerException,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.utils import (
|
||||
convert_filters,
|
||||
convert_volume_binds,
|
||||
decode_json_header,
|
||||
format_environment,
|
||||
kwargs_from_env,
|
||||
parse_bytes,
|
||||
parse_devices,
|
||||
parse_env_file,
|
||||
parse_host,
|
||||
parse_repository_tag,
|
||||
split_command,
|
||||
)
|
||||
from ansible_collections.community.docker.tests.unit.plugins.module_utils._api.constants import (
|
||||
DEFAULT_DOCKER_API_VERSION,
|
||||
)
|
||||
from ansible_collections.community.docker.tests.unit.plugins.module_utils._api.constants import DEFAULT_DOCKER_API_VERSION
|
||||
|
||||
|
||||
TEST_CERT_DIR = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'testdata/certs',
|
||||
"testdata/certs",
|
||||
)
|
||||
|
||||
|
||||
@@ -46,84 +62,85 @@ class KwargsFromEnvTest(unittest.TestCase):
|
||||
os.environ = self.os_environ
|
||||
|
||||
def test_kwargs_from_env_empty(self):
|
||||
os.environ.update(DOCKER_HOST='',
|
||||
DOCKER_CERT_PATH='')
|
||||
os.environ.pop('DOCKER_TLS_VERIFY', None)
|
||||
os.environ.update(DOCKER_HOST="", DOCKER_CERT_PATH="")
|
||||
os.environ.pop("DOCKER_TLS_VERIFY", None)
|
||||
|
||||
kwargs = kwargs_from_env()
|
||||
assert kwargs.get('base_url') is None
|
||||
assert kwargs.get('tls') is None
|
||||
assert kwargs.get("base_url") is None
|
||||
assert kwargs.get("tls") is None
|
||||
|
||||
def test_kwargs_from_env_tls(self):
|
||||
os.environ.update(DOCKER_HOST='tcp://192.168.59.103:2376',
|
||||
DOCKER_CERT_PATH=TEST_CERT_DIR,
|
||||
DOCKER_TLS_VERIFY='1')
|
||||
os.environ.update(
|
||||
DOCKER_HOST="tcp://192.168.59.103:2376",
|
||||
DOCKER_CERT_PATH=TEST_CERT_DIR,
|
||||
DOCKER_TLS_VERIFY="1",
|
||||
)
|
||||
kwargs = kwargs_from_env(assert_hostname=False)
|
||||
assert 'tcp://192.168.59.103:2376' == kwargs['base_url']
|
||||
assert 'ca.pem' in kwargs['tls'].ca_cert
|
||||
assert 'cert.pem' in kwargs['tls'].cert[0]
|
||||
assert 'key.pem' in kwargs['tls'].cert[1]
|
||||
assert kwargs['tls'].assert_hostname is False
|
||||
assert kwargs['tls'].verify
|
||||
assert "tcp://192.168.59.103:2376" == kwargs["base_url"]
|
||||
assert "ca.pem" in kwargs["tls"].ca_cert
|
||||
assert "cert.pem" in kwargs["tls"].cert[0]
|
||||
assert "key.pem" in kwargs["tls"].cert[1]
|
||||
assert kwargs["tls"].assert_hostname is False
|
||||
assert kwargs["tls"].verify
|
||||
|
||||
parsed_host = parse_host(kwargs['base_url'], IS_WINDOWS_PLATFORM, True)
|
||||
kwargs['version'] = DEFAULT_DOCKER_API_VERSION
|
||||
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
|
||||
assert kwargs['tls'].ca_cert == client.verify
|
||||
assert kwargs['tls'].cert == client.cert
|
||||
assert kwargs["tls"].ca_cert == client.verify
|
||||
assert kwargs["tls"].cert == client.cert
|
||||
except TypeError as e:
|
||||
self.fail(e)
|
||||
|
||||
def test_kwargs_from_env_tls_verify_false(self):
|
||||
os.environ.update(DOCKER_HOST='tcp://192.168.59.103:2376',
|
||||
DOCKER_CERT_PATH=TEST_CERT_DIR,
|
||||
DOCKER_TLS_VERIFY='')
|
||||
os.environ.update(
|
||||
DOCKER_HOST="tcp://192.168.59.103:2376",
|
||||
DOCKER_CERT_PATH=TEST_CERT_DIR,
|
||||
DOCKER_TLS_VERIFY="",
|
||||
)
|
||||
kwargs = kwargs_from_env(assert_hostname=True)
|
||||
assert 'tcp://192.168.59.103:2376' == kwargs['base_url']
|
||||
assert 'ca.pem' in kwargs['tls'].ca_cert
|
||||
assert 'cert.pem' in kwargs['tls'].cert[0]
|
||||
assert 'key.pem' in kwargs['tls'].cert[1]
|
||||
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
|
||||
assert "tcp://192.168.59.103:2376" == kwargs["base_url"]
|
||||
assert "ca.pem" in kwargs["tls"].ca_cert
|
||||
assert "cert.pem" in kwargs["tls"].cert[0]
|
||||
assert "key.pem" in kwargs["tls"].cert[1]
|
||||
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
|
||||
assert kwargs['tls'].cert == client.cert
|
||||
assert not kwargs['tls'].verify
|
||||
assert kwargs["tls"].cert == client.cert
|
||||
assert not kwargs["tls"].verify
|
||||
except TypeError as e:
|
||||
self.fail(e)
|
||||
|
||||
def test_kwargs_from_env_tls_verify_false_no_cert(self):
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
cert_dir = os.path.join(temp_dir, '.docker')
|
||||
cert_dir = os.path.join(temp_dir, ".docker")
|
||||
shutil.copytree(TEST_CERT_DIR, cert_dir)
|
||||
|
||||
os.environ.update(DOCKER_HOST='tcp://192.168.59.103:2376',
|
||||
HOME=temp_dir,
|
||||
DOCKER_TLS_VERIFY='')
|
||||
os.environ.pop('DOCKER_CERT_PATH', None)
|
||||
os.environ.update(
|
||||
DOCKER_HOST="tcp://192.168.59.103:2376", HOME=temp_dir, DOCKER_TLS_VERIFY=""
|
||||
)
|
||||
os.environ.pop("DOCKER_CERT_PATH", None)
|
||||
kwargs = kwargs_from_env(assert_hostname=True)
|
||||
assert 'tcp://192.168.59.103:2376' == kwargs['base_url']
|
||||
assert "tcp://192.168.59.103:2376" == kwargs["base_url"]
|
||||
|
||||
def test_kwargs_from_env_no_cert_path(self):
|
||||
try:
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
cert_dir = os.path.join(temp_dir, '.docker')
|
||||
cert_dir = os.path.join(temp_dir, ".docker")
|
||||
shutil.copytree(TEST_CERT_DIR, cert_dir)
|
||||
|
||||
os.environ.update(HOME=temp_dir,
|
||||
DOCKER_CERT_PATH='',
|
||||
DOCKER_TLS_VERIFY='1')
|
||||
os.environ.update(HOME=temp_dir, DOCKER_CERT_PATH="", DOCKER_TLS_VERIFY="1")
|
||||
|
||||
kwargs = kwargs_from_env()
|
||||
assert kwargs['tls'].verify
|
||||
assert cert_dir in kwargs['tls'].ca_cert
|
||||
assert cert_dir in kwargs['tls'].cert[0]
|
||||
assert cert_dir in kwargs['tls'].cert[1]
|
||||
assert kwargs["tls"].verify
|
||||
assert cert_dir in kwargs["tls"].ca_cert
|
||||
assert cert_dir in kwargs["tls"].cert[0]
|
||||
assert cert_dir in kwargs["tls"].cert[1]
|
||||
finally:
|
||||
if temp_dir:
|
||||
shutil.rmtree(temp_dir)
|
||||
@@ -132,15 +149,17 @@ class KwargsFromEnvTest(unittest.TestCase):
|
||||
# Values in os.environ are entirely ignored if an alternate is
|
||||
# provided
|
||||
os.environ.update(
|
||||
DOCKER_HOST='tcp://192.168.59.103:2376',
|
||||
DOCKER_HOST="tcp://192.168.59.103:2376",
|
||||
DOCKER_CERT_PATH=TEST_CERT_DIR,
|
||||
DOCKER_TLS_VERIFY=''
|
||||
DOCKER_TLS_VERIFY="",
|
||||
)
|
||||
kwargs = kwargs_from_env(environment={
|
||||
'DOCKER_HOST': 'http://docker.gensokyo.jp:2581',
|
||||
})
|
||||
assert 'http://docker.gensokyo.jp:2581' == kwargs['base_url']
|
||||
assert 'tls' not in kwargs
|
||||
kwargs = kwargs_from_env(
|
||||
environment={
|
||||
"DOCKER_HOST": "http://docker.gensokyo.jp:2581",
|
||||
}
|
||||
)
|
||||
assert "http://docker.gensokyo.jp:2581" == kwargs["base_url"]
|
||||
assert "tls" not in kwargs
|
||||
|
||||
|
||||
class ConverVolumeBindsTest(unittest.TestCase):
|
||||
@@ -149,52 +168,36 @@ class ConverVolumeBindsTest(unittest.TestCase):
|
||||
assert convert_volume_binds([]) == []
|
||||
|
||||
def test_convert_volume_binds_list(self):
|
||||
data = ['/a:/a:ro', '/b:/c:z']
|
||||
data = ["/a:/a:ro", "/b:/c:z"]
|
||||
assert convert_volume_binds(data) == data
|
||||
|
||||
def test_convert_volume_binds_complete(self):
|
||||
data = {
|
||||
'/mnt/vol1': {
|
||||
'bind': '/data',
|
||||
'mode': 'ro'
|
||||
}
|
||||
}
|
||||
assert convert_volume_binds(data) == ['/mnt/vol1:/data:ro']
|
||||
data = {"/mnt/vol1": {"bind": "/data", "mode": "ro"}}
|
||||
assert convert_volume_binds(data) == ["/mnt/vol1:/data:ro"]
|
||||
|
||||
def test_convert_volume_binds_compact(self):
|
||||
data = {
|
||||
'/mnt/vol1': '/data'
|
||||
}
|
||||
assert convert_volume_binds(data) == ['/mnt/vol1:/data:rw']
|
||||
data = {"/mnt/vol1": "/data"}
|
||||
assert convert_volume_binds(data) == ["/mnt/vol1:/data:rw"]
|
||||
|
||||
def test_convert_volume_binds_no_mode(self):
|
||||
data = {
|
||||
'/mnt/vol1': {
|
||||
'bind': '/data'
|
||||
}
|
||||
}
|
||||
assert convert_volume_binds(data) == ['/mnt/vol1:/data:rw']
|
||||
data = {"/mnt/vol1": {"bind": "/data"}}
|
||||
assert convert_volume_binds(data) == ["/mnt/vol1:/data:rw"]
|
||||
|
||||
def test_convert_volume_binds_unicode_bytes_input(self):
|
||||
expected = ['/mnt/지연:/unicode/박:rw']
|
||||
expected = ["/mnt/지연:/unicode/박:rw"]
|
||||
|
||||
data = {
|
||||
'/mnt/지연'.encode('utf-8'): {
|
||||
'bind': '/unicode/박'.encode('utf-8'),
|
||||
'mode': 'rw'
|
||||
"/mnt/지연".encode("utf-8"): {
|
||||
"bind": "/unicode/박".encode("utf-8"),
|
||||
"mode": "rw",
|
||||
}
|
||||
}
|
||||
assert convert_volume_binds(data) == expected
|
||||
|
||||
def test_convert_volume_binds_unicode_unicode_input(self):
|
||||
expected = ['/mnt/지연:/unicode/박:rw']
|
||||
expected = ["/mnt/지연:/unicode/박:rw"]
|
||||
|
||||
data = {
|
||||
'/mnt/지연': {
|
||||
'bind': '/unicode/박',
|
||||
'mode': 'rw'
|
||||
}
|
||||
}
|
||||
data = {"/mnt/지연": {"bind": "/unicode/박", "mode": "rw"}}
|
||||
assert convert_volume_binds(data) == expected
|
||||
|
||||
|
||||
@@ -206,41 +209,36 @@ class ParseEnvFileTest(unittest.TestCase):
|
||||
Don't forget to unlink the file with os.unlink() after.
|
||||
"""
|
||||
local_tempfile = tempfile.NamedTemporaryFile(delete=False)
|
||||
local_tempfile.write(file_content.encode('UTF-8'))
|
||||
local_tempfile.write(file_content.encode("UTF-8"))
|
||||
local_tempfile.close()
|
||||
return local_tempfile.name
|
||||
|
||||
def test_parse_env_file_proper(self):
|
||||
env_file = self.generate_tempfile(
|
||||
file_content='USER=jdoe\nPASS=secret')
|
||||
env_file = self.generate_tempfile(file_content="USER=jdoe\nPASS=secret")
|
||||
get_parse_env_file = parse_env_file(env_file)
|
||||
assert get_parse_env_file == {'USER': 'jdoe', 'PASS': 'secret'}
|
||||
assert get_parse_env_file == {"USER": "jdoe", "PASS": "secret"}
|
||||
os.unlink(env_file)
|
||||
|
||||
def test_parse_env_file_with_equals_character(self):
|
||||
env_file = self.generate_tempfile(
|
||||
file_content='USER=jdoe\nPASS=sec==ret')
|
||||
env_file = self.generate_tempfile(file_content="USER=jdoe\nPASS=sec==ret")
|
||||
get_parse_env_file = parse_env_file(env_file)
|
||||
assert get_parse_env_file == {'USER': 'jdoe', 'PASS': 'sec==ret'}
|
||||
assert get_parse_env_file == {"USER": "jdoe", "PASS": "sec==ret"}
|
||||
os.unlink(env_file)
|
||||
|
||||
def test_parse_env_file_commented_line(self):
|
||||
env_file = self.generate_tempfile(
|
||||
file_content='USER=jdoe\n#PASS=secret')
|
||||
env_file = self.generate_tempfile(file_content="USER=jdoe\n#PASS=secret")
|
||||
get_parse_env_file = parse_env_file(env_file)
|
||||
assert get_parse_env_file == {'USER': 'jdoe'}
|
||||
assert get_parse_env_file == {"USER": "jdoe"}
|
||||
os.unlink(env_file)
|
||||
|
||||
def test_parse_env_file_newline(self):
|
||||
env_file = self.generate_tempfile(
|
||||
file_content='\nUSER=jdoe\n\n\nPASS=secret')
|
||||
env_file = self.generate_tempfile(file_content="\nUSER=jdoe\n\n\nPASS=secret")
|
||||
get_parse_env_file = parse_env_file(env_file)
|
||||
assert get_parse_env_file == {'USER': 'jdoe', 'PASS': 'secret'}
|
||||
assert get_parse_env_file == {"USER": "jdoe", "PASS": "secret"}
|
||||
os.unlink(env_file)
|
||||
|
||||
def test_parse_env_file_invalid_line(self):
|
||||
env_file = self.generate_tempfile(
|
||||
file_content='USER jdoe')
|
||||
env_file = self.generate_tempfile(file_content="USER jdoe")
|
||||
with pytest.raises(DockerException):
|
||||
parse_env_file(env_file)
|
||||
os.unlink(env_file)
|
||||
@@ -249,46 +247,44 @@ class ParseEnvFileTest(unittest.TestCase):
|
||||
class ParseHostTest(unittest.TestCase):
|
||||
def test_parse_host(self):
|
||||
invalid_hosts = [
|
||||
'foo://0.0.0.0',
|
||||
'tcp://',
|
||||
'udp://127.0.0.1',
|
||||
'udp://127.0.0.1:2375',
|
||||
'ssh://:22/path',
|
||||
'tcp://netloc:3333/path?q=1',
|
||||
'unix:///sock/path#fragment',
|
||||
'https://netloc:3333/path;params',
|
||||
'ssh://:clearpassword@host:22',
|
||||
"foo://0.0.0.0",
|
||||
"tcp://",
|
||||
"udp://127.0.0.1",
|
||||
"udp://127.0.0.1:2375",
|
||||
"ssh://:22/path",
|
||||
"tcp://netloc:3333/path?q=1",
|
||||
"unix:///sock/path#fragment",
|
||||
"https://netloc:3333/path;params",
|
||||
"ssh://:clearpassword@host:22",
|
||||
]
|
||||
|
||||
valid_hosts = {
|
||||
'0.0.0.1:5555': 'http://0.0.0.1:5555',
|
||||
':6666': 'http://127.0.0.1:6666',
|
||||
'tcp://:7777': 'http://127.0.0.1:7777',
|
||||
'http://:7777': 'http://127.0.0.1:7777',
|
||||
'https://kokia.jp:2375': 'https://kokia.jp:2375',
|
||||
'unix:///var/run/docker.sock': 'http+unix:///var/run/docker.sock',
|
||||
'unix://': 'http+unix:///var/run/docker.sock',
|
||||
'12.234.45.127:2375/docker/engine': (
|
||||
'http://12.234.45.127:2375/docker/engine'
|
||||
"0.0.0.1:5555": "http://0.0.0.1:5555",
|
||||
":6666": "http://127.0.0.1:6666",
|
||||
"tcp://:7777": "http://127.0.0.1:7777",
|
||||
"http://:7777": "http://127.0.0.1:7777",
|
||||
"https://kokia.jp:2375": "https://kokia.jp:2375",
|
||||
"unix:///var/run/docker.sock": "http+unix:///var/run/docker.sock",
|
||||
"unix://": "http+unix:///var/run/docker.sock",
|
||||
"12.234.45.127:2375/docker/engine": (
|
||||
"http://12.234.45.127:2375/docker/engine"
|
||||
),
|
||||
'somehost.net:80/service/swarm': (
|
||||
'http://somehost.net:80/service/swarm'
|
||||
"somehost.net:80/service/swarm": ("http://somehost.net:80/service/swarm"),
|
||||
"npipe:////./pipe/docker_engine": "npipe:////./pipe/docker_engine",
|
||||
"[fd12::82d1]:2375": "http://[fd12::82d1]:2375",
|
||||
"https://[fd12:5672::12aa]:1090": "https://[fd12:5672::12aa]:1090",
|
||||
"[fd12::82d1]:2375/docker/engine": (
|
||||
"http://[fd12::82d1]:2375/docker/engine"
|
||||
),
|
||||
'npipe:////./pipe/docker_engine': 'npipe:////./pipe/docker_engine',
|
||||
'[fd12::82d1]:2375': 'http://[fd12::82d1]:2375',
|
||||
'https://[fd12:5672::12aa]:1090': 'https://[fd12:5672::12aa]:1090',
|
||||
'[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',
|
||||
"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:
|
||||
msg = f'Should have failed to parse invalid host: {host}'
|
||||
msg = f"Should have failed to parse invalid host: {host}"
|
||||
with self.assertRaises(DockerException, msg=msg):
|
||||
parse_host(host, None)
|
||||
|
||||
@@ -296,35 +292,35 @@ class ParseHostTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
parse_host(host, None),
|
||||
expected,
|
||||
msg=f'Failed to parse valid host: {host}',
|
||||
msg=f"Failed to parse valid host: {host}",
|
||||
)
|
||||
|
||||
def test_parse_host_empty_value(self):
|
||||
unix_socket = 'http+unix:///var/run/docker.sock'
|
||||
npipe = 'npipe:////./pipe/docker_engine'
|
||||
unix_socket = "http+unix:///var/run/docker.sock"
|
||||
npipe = "npipe:////./pipe/docker_engine"
|
||||
|
||||
for val in [None, '']:
|
||||
for val in [None, ""]:
|
||||
assert parse_host(val, is_win32=False) == unix_socket
|
||||
assert parse_host(val, is_win32=True) == npipe
|
||||
|
||||
def test_parse_host_tls(self):
|
||||
host_value = 'myhost.docker.net:3348'
|
||||
expected_result = 'https://myhost.docker.net:3348'
|
||||
host_value = "myhost.docker.net:3348"
|
||||
expected_result = "https://myhost.docker.net:3348"
|
||||
assert parse_host(host_value, tls=True) == expected_result
|
||||
|
||||
def test_parse_host_tls_tcp_proto(self):
|
||||
host_value = 'tcp://myhost.docker.net:3348'
|
||||
expected_result = 'https://myhost.docker.net:3348'
|
||||
host_value = "tcp://myhost.docker.net:3348"
|
||||
expected_result = "https://myhost.docker.net:3348"
|
||||
assert parse_host(host_value, tls=True) == expected_result
|
||||
|
||||
def test_parse_host_trailing_slash(self):
|
||||
host_value = 'tcp://myhost.docker.net:2376/'
|
||||
expected_result = 'http://myhost.docker.net:2376'
|
||||
host_value = "tcp://myhost.docker.net:2376/"
|
||||
expected_result = "http://myhost.docker.net:2376"
|
||||
assert parse_host(host_value) == expected_result
|
||||
|
||||
|
||||
class ParseRepositoryTagTest(unittest.TestCase):
|
||||
sha = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
||||
sha = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
|
||||
def test_index_image_no_tag(self):
|
||||
assert parse_repository_tag("root") == ("root", None)
|
||||
@@ -342,77 +338,83 @@ class ParseRepositoryTagTest(unittest.TestCase):
|
||||
assert parse_repository_tag("url:5000/repo") == ("url:5000/repo", None)
|
||||
|
||||
def test_private_reg_image_tag(self):
|
||||
assert parse_repository_tag("url:5000/repo:tag") == (
|
||||
"url:5000/repo", "tag"
|
||||
)
|
||||
assert parse_repository_tag("url:5000/repo:tag") == ("url:5000/repo", "tag")
|
||||
|
||||
def test_index_image_sha(self):
|
||||
assert parse_repository_tag(f"root@sha256:{self.sha}") == (
|
||||
"root", f"sha256:{self.sha}"
|
||||
"root",
|
||||
f"sha256:{self.sha}",
|
||||
)
|
||||
|
||||
def test_private_reg_image_sha(self):
|
||||
assert parse_repository_tag(
|
||||
f"url:5000/repo@sha256:{self.sha}"
|
||||
) == ("url:5000/repo", f"sha256:{self.sha}")
|
||||
assert parse_repository_tag(f"url:5000/repo@sha256:{self.sha}") == (
|
||||
"url:5000/repo",
|
||||
f"sha256:{self.sha}",
|
||||
)
|
||||
|
||||
|
||||
class ParseDeviceTest(unittest.TestCase):
|
||||
def test_dict(self):
|
||||
devices = parse_devices([{
|
||||
'PathOnHost': '/dev/sda1',
|
||||
'PathInContainer': '/dev/mnt1',
|
||||
'CgroupPermissions': 'r'
|
||||
}])
|
||||
devices = parse_devices(
|
||||
[
|
||||
{
|
||||
"PathOnHost": "/dev/sda1",
|
||||
"PathInContainer": "/dev/mnt1",
|
||||
"CgroupPermissions": "r",
|
||||
}
|
||||
]
|
||||
)
|
||||
assert devices[0] == {
|
||||
'PathOnHost': '/dev/sda1',
|
||||
'PathInContainer': '/dev/mnt1',
|
||||
'CgroupPermissions': 'r'
|
||||
"PathOnHost": "/dev/sda1",
|
||||
"PathInContainer": "/dev/mnt1",
|
||||
"CgroupPermissions": "r",
|
||||
}
|
||||
|
||||
def test_partial_string_definition(self):
|
||||
devices = parse_devices(['/dev/sda1'])
|
||||
devices = parse_devices(["/dev/sda1"])
|
||||
assert devices[0] == {
|
||||
'PathOnHost': '/dev/sda1',
|
||||
'PathInContainer': '/dev/sda1',
|
||||
'CgroupPermissions': 'rwm'
|
||||
"PathOnHost": "/dev/sda1",
|
||||
"PathInContainer": "/dev/sda1",
|
||||
"CgroupPermissions": "rwm",
|
||||
}
|
||||
|
||||
def test_permissionless_string_definition(self):
|
||||
devices = parse_devices(['/dev/sda1:/dev/mnt1'])
|
||||
devices = parse_devices(["/dev/sda1:/dev/mnt1"])
|
||||
assert devices[0] == {
|
||||
'PathOnHost': '/dev/sda1',
|
||||
'PathInContainer': '/dev/mnt1',
|
||||
'CgroupPermissions': 'rwm'
|
||||
"PathOnHost": "/dev/sda1",
|
||||
"PathInContainer": "/dev/mnt1",
|
||||
"CgroupPermissions": "rwm",
|
||||
}
|
||||
|
||||
def test_full_string_definition(self):
|
||||
devices = parse_devices(['/dev/sda1:/dev/mnt1:r'])
|
||||
devices = parse_devices(["/dev/sda1:/dev/mnt1:r"])
|
||||
assert devices[0] == {
|
||||
'PathOnHost': '/dev/sda1',
|
||||
'PathInContainer': '/dev/mnt1',
|
||||
'CgroupPermissions': 'r'
|
||||
"PathOnHost": "/dev/sda1",
|
||||
"PathInContainer": "/dev/mnt1",
|
||||
"CgroupPermissions": "r",
|
||||
}
|
||||
|
||||
def test_hybrid_list(self):
|
||||
devices = parse_devices([
|
||||
'/dev/sda1:/dev/mnt1:rw',
|
||||
{
|
||||
'PathOnHost': '/dev/sda2',
|
||||
'PathInContainer': '/dev/mnt2',
|
||||
'CgroupPermissions': 'r'
|
||||
}
|
||||
])
|
||||
devices = parse_devices(
|
||||
[
|
||||
"/dev/sda1:/dev/mnt1:rw",
|
||||
{
|
||||
"PathOnHost": "/dev/sda2",
|
||||
"PathInContainer": "/dev/mnt2",
|
||||
"CgroupPermissions": "r",
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
assert devices[0] == {
|
||||
'PathOnHost': '/dev/sda1',
|
||||
'PathInContainer': '/dev/mnt1',
|
||||
'CgroupPermissions': 'rw'
|
||||
"PathOnHost": "/dev/sda1",
|
||||
"PathInContainer": "/dev/mnt1",
|
||||
"CgroupPermissions": "rw",
|
||||
}
|
||||
assert devices[1] == {
|
||||
'PathOnHost': '/dev/sda2',
|
||||
'PathInContainer': '/dev/mnt2',
|
||||
'CgroupPermissions': 'r'
|
||||
"PathOnHost": "/dev/sda2",
|
||||
"PathInContainer": "/dev/mnt2",
|
||||
"CgroupPermissions": "r",
|
||||
}
|
||||
|
||||
|
||||
@@ -439,37 +441,35 @@ class UtilsTest(unittest.TestCase):
|
||||
|
||||
def test_convert_filters(self):
|
||||
tests = [
|
||||
({'dangling': True}, '{"dangling": ["true"]}'),
|
||||
({'dangling': "true"}, '{"dangling": ["true"]}'),
|
||||
({'exited': 0}, '{"exited": ["0"]}'),
|
||||
({'exited': [0, 1]}, '{"exited": ["0", "1"]}'),
|
||||
({"dangling": True}, '{"dangling": ["true"]}'),
|
||||
({"dangling": "true"}, '{"dangling": ["true"]}'),
|
||||
({"exited": 0}, '{"exited": ["0"]}'),
|
||||
({"exited": [0, 1]}, '{"exited": ["0", "1"]}'),
|
||||
]
|
||||
|
||||
for filters, expected in tests:
|
||||
assert convert_filters(filters) == expected
|
||||
|
||||
def test_decode_json_header(self):
|
||||
obj = {'a': 'b', 'c': 1}
|
||||
data = base64.urlsafe_b64encode(bytes(json.dumps(obj), 'utf-8'))
|
||||
obj = {"a": "b", "c": 1}
|
||||
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('echo μμ') == ['echo', 'μμ']
|
||||
assert split_command("echo μμ") == ["echo", "μμ"]
|
||||
|
||||
|
||||
class FormatEnvironmentTest(unittest.TestCase):
|
||||
def test_format_env_binary_unicode_value(self):
|
||||
env_dict = {
|
||||
'ARTIST_NAME': b'\xec\x86\xa1\xec\xa7\x80\xec\x9d\x80'
|
||||
}
|
||||
assert format_environment(env_dict) == ['ARTIST_NAME=송지은']
|
||||
env_dict = {"ARTIST_NAME": b"\xec\x86\xa1\xec\xa7\x80\xec\x9d\x80"}
|
||||
assert format_environment(env_dict) == ["ARTIST_NAME=송지은"]
|
||||
|
||||
def test_format_env_no_value(self):
|
||||
env_dict = {
|
||||
'FOO': None,
|
||||
'BAR': '',
|
||||
"FOO": None,
|
||||
"BAR": "",
|
||||
}
|
||||
assert sorted(format_environment(env_dict)) == ['BAR=', 'FOO']
|
||||
assert sorted(format_environment(env_dict)) == ["BAR=", "FOO"]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,11 +2,12 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._logfmt import (
|
||||
InvalidLogFmt,
|
||||
parse_line,
|
||||
@@ -19,42 +20,42 @@ SUCCESS_TEST_CASES = [
|
||||
' created for project \\"influxdb\\".\\nSet `external: true` to use an existing network"',
|
||||
{},
|
||||
{
|
||||
'time': '2024-02-02T08:14:10+01:00',
|
||||
'level': 'warning',
|
||||
'msg': 'a network with name influxNetwork exists but was not created for project "influxdb".\nSet `external: true` to use an existing network',
|
||||
"time": "2024-02-02T08:14:10+01:00",
|
||||
"level": "warning",
|
||||
"msg": 'a network with name influxNetwork exists but was not created for project "influxdb".\nSet `external: true` to use an existing network',
|
||||
},
|
||||
),
|
||||
(
|
||||
'time="2024-02-02T08:14:10+01:00" level=warning msg="a network with name influxNetwork exists but was not'
|
||||
' created for project \\"influxdb\\".\\nSet `external: true` to use an existing network"',
|
||||
{'logrus_mode': True},
|
||||
{"logrus_mode": True},
|
||||
{
|
||||
'time': '2024-02-02T08:14:10+01:00',
|
||||
'level': 'warning',
|
||||
'msg': 'a network with name influxNetwork exists but was not created for project "influxdb".\nSet `external: true` to use an existing network',
|
||||
"time": "2024-02-02T08:14:10+01:00",
|
||||
"level": "warning",
|
||||
"msg": 'a network with name influxNetwork exists but was not created for project "influxdb".\nSet `external: true` to use an existing network',
|
||||
},
|
||||
),
|
||||
(
|
||||
'foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf',
|
||||
{},
|
||||
{
|
||||
'foo': 'bar',
|
||||
'a': '14',
|
||||
'baz': 'hello kitty',
|
||||
'cool%story': 'bro',
|
||||
'f': None,
|
||||
'%^asdf': None,
|
||||
"foo": "bar",
|
||||
"a": "14",
|
||||
"baz": "hello kitty",
|
||||
"cool%story": "bro",
|
||||
"f": None,
|
||||
"%^asdf": None,
|
||||
},
|
||||
),
|
||||
(
|
||||
'{"foo":"bar"}',
|
||||
{},
|
||||
{
|
||||
'{': None,
|
||||
'foo': None,
|
||||
':': None,
|
||||
'bar': None,
|
||||
'}': None,
|
||||
"{": None,
|
||||
"foo": None,
|
||||
":": None,
|
||||
"bar": None,
|
||||
"}": None,
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -63,35 +64,35 @@ SUCCESS_TEST_CASES = [
|
||||
FAILURE_TEST_CASES = [
|
||||
(
|
||||
'foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf',
|
||||
{'logrus_mode': True},
|
||||
{"logrus_mode": True},
|
||||
'Key must always be followed by "=" in logrus mode',
|
||||
),
|
||||
(
|
||||
'{}',
|
||||
{'logrus_mode': True},
|
||||
"{}",
|
||||
{"logrus_mode": True},
|
||||
'Key must always be followed by "=" in logrus mode',
|
||||
),
|
||||
(
|
||||
'[]',
|
||||
{'logrus_mode': True},
|
||||
"[]",
|
||||
{"logrus_mode": True},
|
||||
'Key must always be followed by "=" in logrus mode',
|
||||
),
|
||||
(
|
||||
'{"foo=bar": "baz=bam"}',
|
||||
{'logrus_mode': True},
|
||||
{"logrus_mode": True},
|
||||
'Key must always be followed by "=" in logrus mode',
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('line, kwargs, result', SUCCESS_TEST_CASES)
|
||||
@pytest.mark.parametrize("line, kwargs, result", SUCCESS_TEST_CASES)
|
||||
def test_parse_line_success(line, kwargs, result):
|
||||
res = parse_line(line, **kwargs)
|
||||
print(repr(res))
|
||||
assert res == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize('line, kwargs, message', FAILURE_TEST_CASES)
|
||||
@pytest.mark.parametrize("line, kwargs, message", FAILURE_TEST_CASES)
|
||||
def test_parse_line_success(line, kwargs, message):
|
||||
with pytest.raises(InvalidLogFmt) as exc:
|
||||
parse_line(line, **kwargs)
|
||||
|
||||
@@ -2,27 +2,31 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._scramble import (
|
||||
scramble,
|
||||
unscramble,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('plaintext, key, scrambled', [
|
||||
('', b'0', '=S='),
|
||||
('hello', b'\x00', '=S=aGVsbG8='),
|
||||
('hello', b'\x01', '=S=aWRtbW4='),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"plaintext, key, scrambled",
|
||||
[
|
||||
("", b"0", "=S="),
|
||||
("hello", b"\x00", "=S=aGVsbG8="),
|
||||
("hello", b"\x01", "=S=aWRtbW4="),
|
||||
],
|
||||
)
|
||||
def test_scramble_unscramble(plaintext, key, scrambled):
|
||||
scrambled_ = scramble(plaintext, key)
|
||||
print(f'{scrambled_!r} == {scrambled!r}')
|
||||
print(f"{scrambled_!r} == {scrambled!r}")
|
||||
assert scrambled_ == scrambled
|
||||
|
||||
plaintext_ = unscramble(scrambled, key)
|
||||
print(f'{plaintext_!r} == {plaintext!r}')
|
||||
print(f"{plaintext_!r} == {plaintext!r}")
|
||||
assert plaintext_ == plaintext
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils.compose_v2 import (
|
||||
Event,
|
||||
parse_events,
|
||||
@@ -17,60 +18,60 @@ from .compose_v2_test_cases import EVENT_TEST_CASES
|
||||
|
||||
EXTRA_TEST_CASES = [
|
||||
(
|
||||
'2.24.2-manual-build-dry-run',
|
||||
'2.24.2',
|
||||
"2.24.2-manual-build-dry-run",
|
||||
"2.24.2",
|
||||
True,
|
||||
False,
|
||||
' DRY-RUN MODE - build service foobar \n'
|
||||
' DRY-RUN MODE - ==> ==> writing image dryRun-8843d7f92416211de9ebb963ff4ce28125932878 \n'
|
||||
' DRY-RUN MODE - ==> ==> naming to my-python \n'
|
||||
' DRY-RUN MODE - Network compose_default Creating\n'
|
||||
' DRY-RUN MODE - Network compose_default Created\n'
|
||||
' DRY-RUN MODE - Container compose-foobar-1 Creating\n'
|
||||
' DRY-RUN MODE - Container compose-foobar-1 Created\n'
|
||||
' DRY-RUN MODE - Container ompose-foobar-1 Starting\n'
|
||||
' DRY-RUN MODE - Container ompose-foobar-1 Started\n',
|
||||
" DRY-RUN MODE - build service foobar \n"
|
||||
" DRY-RUN MODE - ==> ==> writing image dryRun-8843d7f92416211de9ebb963ff4ce28125932878 \n"
|
||||
" DRY-RUN MODE - ==> ==> naming to my-python \n"
|
||||
" DRY-RUN MODE - Network compose_default Creating\n"
|
||||
" DRY-RUN MODE - Network compose_default Created\n"
|
||||
" DRY-RUN MODE - Container compose-foobar-1 Creating\n"
|
||||
" DRY-RUN MODE - Container compose-foobar-1 Created\n"
|
||||
" DRY-RUN MODE - Container ompose-foobar-1 Starting\n"
|
||||
" DRY-RUN MODE - Container ompose-foobar-1 Started\n",
|
||||
[
|
||||
Event(
|
||||
'service',
|
||||
'foobar',
|
||||
'Building',
|
||||
"service",
|
||||
"foobar",
|
||||
"Building",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'network',
|
||||
'compose_default',
|
||||
'Creating',
|
||||
"network",
|
||||
"compose_default",
|
||||
"Creating",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'network',
|
||||
'compose_default',
|
||||
'Created',
|
||||
"network",
|
||||
"compose_default",
|
||||
"Created",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'container',
|
||||
'compose-foobar-1',
|
||||
'Creating',
|
||||
"container",
|
||||
"compose-foobar-1",
|
||||
"Creating",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'container',
|
||||
'compose-foobar-1',
|
||||
'Created',
|
||||
"container",
|
||||
"compose-foobar-1",
|
||||
"Created",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'container',
|
||||
'ompose-foobar-1',
|
||||
'Starting',
|
||||
"container",
|
||||
"ompose-foobar-1",
|
||||
"Starting",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'container',
|
||||
'ompose-foobar-1',
|
||||
'Started',
|
||||
"container",
|
||||
"ompose-foobar-1",
|
||||
"Started",
|
||||
None,
|
||||
),
|
||||
],
|
||||
@@ -78,100 +79,100 @@ EXTRA_TEST_CASES = [
|
||||
),
|
||||
(
|
||||
# https://github.com/ansible-collections/community.docker/issues/785
|
||||
'2.20.0-manual-pull',
|
||||
'2.20.0',
|
||||
"2.20.0-manual-pull",
|
||||
"2.20.0",
|
||||
False,
|
||||
False,
|
||||
'4f4fb700ef54 Waiting\n'
|
||||
'238022553356 Downloading 541B/541B\n'
|
||||
'972e292d3a60 Downloading 106kB/10.43MB\n'
|
||||
'f2543dc9f0a9 Downloading 25.36kB/2.425MB\n'
|
||||
'972e292d3a60 Downloading 5.925MB/10.43MB\n'
|
||||
'f2543dc9f0a9 Downloading 2.219MB/2.425MB\n'
|
||||
'f2543dc9f0a9 Extracting 32.77kB/2.425MB\n'
|
||||
'4f4fb700ef54 Downloading 32B/32B\n'
|
||||
'f2543dc9f0a9 Extracting 2.425MB/2.425MB\n'
|
||||
'972e292d3a60 Extracting 131.1kB/10.43MB\n'
|
||||
'972e292d3a60 Extracting 10.43MB/10.43MB\n'
|
||||
'238022553356 Extracting 541B/541B\n'
|
||||
'4f4fb700ef54 Extracting 32B/32B\n',
|
||||
"4f4fb700ef54 Waiting\n"
|
||||
"238022553356 Downloading 541B/541B\n"
|
||||
"972e292d3a60 Downloading 106kB/10.43MB\n"
|
||||
"f2543dc9f0a9 Downloading 25.36kB/2.425MB\n"
|
||||
"972e292d3a60 Downloading 5.925MB/10.43MB\n"
|
||||
"f2543dc9f0a9 Downloading 2.219MB/2.425MB\n"
|
||||
"f2543dc9f0a9 Extracting 32.77kB/2.425MB\n"
|
||||
"4f4fb700ef54 Downloading 32B/32B\n"
|
||||
"f2543dc9f0a9 Extracting 2.425MB/2.425MB\n"
|
||||
"972e292d3a60 Extracting 131.1kB/10.43MB\n"
|
||||
"972e292d3a60 Extracting 10.43MB/10.43MB\n"
|
||||
"238022553356 Extracting 541B/541B\n"
|
||||
"4f4fb700ef54 Extracting 32B/32B\n",
|
||||
[
|
||||
Event(
|
||||
'image-layer',
|
||||
'4f4fb700ef54',
|
||||
'Waiting',
|
||||
"image-layer",
|
||||
"4f4fb700ef54",
|
||||
"Waiting",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'238022553356',
|
||||
'Downloading',
|
||||
"image-layer",
|
||||
"238022553356",
|
||||
"Downloading",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'972e292d3a60',
|
||||
'Downloading',
|
||||
"image-layer",
|
||||
"972e292d3a60",
|
||||
"Downloading",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'f2543dc9f0a9',
|
||||
'Downloading',
|
||||
"image-layer",
|
||||
"f2543dc9f0a9",
|
||||
"Downloading",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'972e292d3a60',
|
||||
'Downloading',
|
||||
"image-layer",
|
||||
"972e292d3a60",
|
||||
"Downloading",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'f2543dc9f0a9',
|
||||
'Downloading',
|
||||
"image-layer",
|
||||
"f2543dc9f0a9",
|
||||
"Downloading",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'f2543dc9f0a9',
|
||||
'Extracting',
|
||||
"image-layer",
|
||||
"f2543dc9f0a9",
|
||||
"Extracting",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'4f4fb700ef54',
|
||||
'Downloading',
|
||||
"image-layer",
|
||||
"4f4fb700ef54",
|
||||
"Downloading",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'f2543dc9f0a9',
|
||||
'Extracting',
|
||||
"image-layer",
|
||||
"f2543dc9f0a9",
|
||||
"Extracting",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'972e292d3a60',
|
||||
'Extracting',
|
||||
"image-layer",
|
||||
"972e292d3a60",
|
||||
"Extracting",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'972e292d3a60',
|
||||
'Extracting',
|
||||
"image-layer",
|
||||
"972e292d3a60",
|
||||
"Extracting",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'238022553356',
|
||||
'Extracting',
|
||||
"image-layer",
|
||||
"238022553356",
|
||||
"Extracting",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'image-layer',
|
||||
'4f4fb700ef54',
|
||||
'Extracting',
|
||||
"image-layer",
|
||||
"4f4fb700ef54",
|
||||
"Extracting",
|
||||
None,
|
||||
),
|
||||
],
|
||||
@@ -179,8 +180,8 @@ EXTRA_TEST_CASES = [
|
||||
),
|
||||
(
|
||||
# https://github.com/ansible-collections/community.docker/issues/787
|
||||
'2.20.3-logrus-warn',
|
||||
'2.20.3',
|
||||
"2.20.3-logrus-warn",
|
||||
"2.20.3",
|
||||
False,
|
||||
False,
|
||||
'time="2024-02-02T08:14:10+01:00" level=warning msg="a network with name influxNetwork exists but was not'
|
||||
@@ -192,8 +193,8 @@ EXTRA_TEST_CASES = [
|
||||
),
|
||||
(
|
||||
# https://github.com/ansible-collections/community.docker/issues/807
|
||||
'2.20.3-image-warning-error',
|
||||
'2.20.3',
|
||||
"2.20.3-image-warning-error",
|
||||
"2.20.3",
|
||||
False,
|
||||
True,
|
||||
" dummy3 Warning \n"
|
||||
@@ -203,50 +204,48 @@ EXTRA_TEST_CASES = [
|
||||
" dummy5 Error Bar baz bam \n",
|
||||
[
|
||||
Event(
|
||||
'unknown',
|
||||
'dummy',
|
||||
'Error',
|
||||
"unknown",
|
||||
"dummy",
|
||||
"Error",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'unknown',
|
||||
'dummy5',
|
||||
'Error',
|
||||
'Bar baz bam',
|
||||
"unknown",
|
||||
"dummy5",
|
||||
"Error",
|
||||
"Bar baz bam",
|
||||
),
|
||||
],
|
||||
[
|
||||
'Unspecified warning for dummy3',
|
||||
'Unspecified warning for dummy2',
|
||||
'dummy4: Foo bar',
|
||||
"Unspecified warning for dummy3",
|
||||
"Unspecified warning for dummy2",
|
||||
"dummy4: Foo bar",
|
||||
],
|
||||
),
|
||||
(
|
||||
# https://github.com/ansible-collections/community.docker/issues/911
|
||||
'2.28.1-image-pull-skipped',
|
||||
'2.28.1',
|
||||
"2.28.1-image-pull-skipped",
|
||||
"2.28.1",
|
||||
False,
|
||||
False,
|
||||
" bash_1 Skipped \n"
|
||||
" bash_2 Pulling \n"
|
||||
" bash_2 Pulled \n",
|
||||
" bash_1 Skipped \n" " bash_2 Pulling \n" " bash_2 Pulled \n",
|
||||
[
|
||||
Event(
|
||||
'unknown',
|
||||
'bash_1',
|
||||
'Skipped',
|
||||
"unknown",
|
||||
"bash_1",
|
||||
"Skipped",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'service',
|
||||
'bash_2',
|
||||
'Pulling',
|
||||
"service",
|
||||
"bash_2",
|
||||
"Pulling",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'service',
|
||||
'bash_2',
|
||||
'Pulled',
|
||||
"service",
|
||||
"bash_2",
|
||||
"Pulled",
|
||||
None,
|
||||
),
|
||||
],
|
||||
@@ -254,30 +253,30 @@ EXTRA_TEST_CASES = [
|
||||
),
|
||||
(
|
||||
# https://github.com/ansible-collections/community.docker/issues/948
|
||||
'2.28.1-unknown', # TODO: find out actual version!
|
||||
'2.28.1', # TODO: find out actual version!
|
||||
"2.28.1-unknown", # TODO: find out actual version!
|
||||
"2.28.1", # TODO: find out actual version!
|
||||
False,
|
||||
True,
|
||||
" prometheus Pulling \n"
|
||||
" prometheus Pulled \n"
|
||||
"network internet-monitoring-front-tier was found but has incorrect label com.docker.compose.network set to \"internet-monitoring-front-tier\"\n",
|
||||
'network internet-monitoring-front-tier was found but has incorrect label com.docker.compose.network set to "internet-monitoring-front-tier"\n',
|
||||
[
|
||||
Event(
|
||||
'service',
|
||||
'prometheus',
|
||||
'Pulling',
|
||||
"service",
|
||||
"prometheus",
|
||||
"Pulling",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'service',
|
||||
'prometheus',
|
||||
'Pulled',
|
||||
"service",
|
||||
"prometheus",
|
||||
"Pulled",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'unknown',
|
||||
'',
|
||||
'Error',
|
||||
"unknown",
|
||||
"",
|
||||
"Error",
|
||||
'network internet-monitoring-front-tier was found but has incorrect label com.docker.compose.network set to "internet-monitoring-front-tier"',
|
||||
),
|
||||
],
|
||||
@@ -285,8 +284,8 @@ EXTRA_TEST_CASES = [
|
||||
),
|
||||
(
|
||||
# https://github.com/ansible-collections/community.docker/issues/978
|
||||
'2.28.1-unknown', # TODO: find out actual version!
|
||||
'2.28.1', # TODO: find out actual version!
|
||||
"2.28.1-unknown", # TODO: find out actual version!
|
||||
"2.28.1", # TODO: find out actual version!
|
||||
False,
|
||||
True,
|
||||
" Network create_users_db_default Creating\n"
|
||||
@@ -299,52 +298,52 @@ EXTRA_TEST_CASES = [
|
||||
"container create_users_db-init exited (0)\n",
|
||||
[
|
||||
Event(
|
||||
'network',
|
||||
'create_users_db_default',
|
||||
'Creating',
|
||||
"network",
|
||||
"create_users_db_default",
|
||||
"Creating",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'network',
|
||||
'create_users_db_default',
|
||||
'Created',
|
||||
"network",
|
||||
"create_users_db_default",
|
||||
"Created",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'container',
|
||||
'create_users_db-init',
|
||||
'Creating',
|
||||
"container",
|
||||
"create_users_db-init",
|
||||
"Creating",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'container',
|
||||
'create_users_db-init',
|
||||
'Created',
|
||||
"container",
|
||||
"create_users_db-init",
|
||||
"Created",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'container',
|
||||
'create_users_db-init',
|
||||
'Starting',
|
||||
"container",
|
||||
"create_users_db-init",
|
||||
"Starting",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'container',
|
||||
'create_users_db-init',
|
||||
'Started',
|
||||
"container",
|
||||
"create_users_db-init",
|
||||
"Started",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'container',
|
||||
'create_users_db-init',
|
||||
'Waiting',
|
||||
"container",
|
||||
"create_users_db-init",
|
||||
"Waiting",
|
||||
None,
|
||||
),
|
||||
Event(
|
||||
'unknown',
|
||||
'',
|
||||
'Error',
|
||||
'container create_users_db-init exited (0)',
|
||||
"unknown",
|
||||
"",
|
||||
"Error",
|
||||
"container create_users_db-init exited (0)",
|
||||
),
|
||||
],
|
||||
[],
|
||||
@@ -355,17 +354,21 @@ _ALL_TEST_CASES = EVENT_TEST_CASES + EXTRA_TEST_CASES
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'test_id, compose_version, dry_run, nonzero_rc, stderr, events, warnings',
|
||||
"test_id, compose_version, dry_run, nonzero_rc, stderr, events, warnings",
|
||||
_ALL_TEST_CASES,
|
||||
ids=[tc[0] for tc in _ALL_TEST_CASES],
|
||||
)
|
||||
def test_parse_events(test_id, compose_version, dry_run, nonzero_rc, stderr, events, warnings):
|
||||
def test_parse_events(
|
||||
test_id, compose_version, dry_run, nonzero_rc, stderr, events, warnings
|
||||
):
|
||||
collected_warnings = []
|
||||
|
||||
def collect_warning(msg):
|
||||
collected_warnings.append(msg)
|
||||
|
||||
collected_events = parse_events(stderr, dry_run=dry_run, warn_function=collect_warning, nonzero_rc=nonzero_rc)
|
||||
collected_events = parse_events(
|
||||
stderr, dry_run=dry_run, warn_function=collect_warning, nonzero_rc=nonzero_rc
|
||||
)
|
||||
|
||||
print(collected_events)
|
||||
print(collected_warnings)
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils.copy import (
|
||||
_stream_generator_to_fileobj,
|
||||
)
|
||||
@@ -16,54 +17,57 @@ def _simple_generator(sequence):
|
||||
yield from sequence
|
||||
|
||||
|
||||
@pytest.mark.parametrize('chunks, read_sizes', [
|
||||
(
|
||||
[
|
||||
(1, b'1'),
|
||||
(1, b'2'),
|
||||
(1, b'3'),
|
||||
(1, b'4'),
|
||||
],
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
),
|
||||
(
|
||||
[
|
||||
(1, b'123'),
|
||||
(1, b'456'),
|
||||
(1, b'789'),
|
||||
],
|
||||
[
|
||||
1,
|
||||
4,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
]
|
||||
),
|
||||
(
|
||||
[
|
||||
(10 * 1024 * 1024, b'0'),
|
||||
(10 * 1024 * 1024, b'1'),
|
||||
],
|
||||
[
|
||||
1024 * 1024 - 5,
|
||||
5 * 1024 * 1024 - 3,
|
||||
10 * 1024 * 1024 - 2,
|
||||
2 * 1024 * 1024 - 1,
|
||||
2 * 1024 * 1024 + 5 + 3 + 2 + 1,
|
||||
]
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"chunks, read_sizes",
|
||||
[
|
||||
(
|
||||
[
|
||||
(1, b"1"),
|
||||
(1, b"2"),
|
||||
(1, b"3"),
|
||||
(1, b"4"),
|
||||
],
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
],
|
||||
),
|
||||
(
|
||||
[
|
||||
(1, b"123"),
|
||||
(1, b"456"),
|
||||
(1, b"789"),
|
||||
],
|
||||
[
|
||||
1,
|
||||
4,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
],
|
||||
),
|
||||
(
|
||||
[
|
||||
(10 * 1024 * 1024, b"0"),
|
||||
(10 * 1024 * 1024, b"1"),
|
||||
],
|
||||
[
|
||||
1024 * 1024 - 5,
|
||||
5 * 1024 * 1024 - 3,
|
||||
10 * 1024 * 1024 - 2,
|
||||
2 * 1024 * 1024 - 1,
|
||||
2 * 1024 * 1024 + 5 + 3 + 2 + 1,
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test__stream_generator_to_fileobj(chunks, read_sizes):
|
||||
chunks = [count * data for count, data in chunks]
|
||||
stream = _simple_generator(chunks)
|
||||
expected = b''.join(chunks)
|
||||
expected = b"".join(chunks)
|
||||
|
||||
buffer = b''
|
||||
buffer = b""
|
||||
totally_read = 0
|
||||
f = _stream_generator_to_fileobj(stream)
|
||||
for read_size in read_sizes:
|
||||
@@ -72,5 +76,5 @@ def test__stream_generator_to_fileobj(chunks, read_sizes):
|
||||
buffer += chunk
|
||||
totally_read += read_size
|
||||
|
||||
assert buffer == expected[:len(buffer)]
|
||||
assert buffer == expected[: len(buffer)]
|
||||
assert min(totally_read, len(expected)) == len(buffer)
|
||||
|
||||
@@ -2,16 +2,18 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
import tarfile
|
||||
|
||||
import pytest
|
||||
from ansible_collections.community.docker.plugins.module_utils.image_archive import (
|
||||
ImageArchiveInvalidException,
|
||||
api_image_id,
|
||||
archived_image_manifest,
|
||||
ImageArchiveInvalidException
|
||||
)
|
||||
|
||||
from ..test_support.docker_image_archive_stubbing import (
|
||||
@@ -23,18 +25,17 @@ from ..test_support.docker_image_archive_stubbing import (
|
||||
|
||||
@pytest.fixture
|
||||
def tar_file_name(tmpdir):
|
||||
'''
|
||||
"""
|
||||
Return the name of a non-existing tar file in an existing temporary directory.
|
||||
'''
|
||||
"""
|
||||
|
||||
# Cast to str required by Python 2.x
|
||||
return str(tmpdir.join('foo.tar'))
|
||||
return str(tmpdir.join("foo.tar"))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('expected, value', [
|
||||
('sha256:foo', 'foo'),
|
||||
('sha256:bar', 'bar')
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"expected, value", [("sha256:foo", "foo"), ("sha256:bar", "bar")]
|
||||
)
|
||||
def test_api_image_id_from_archive_id(expected, value):
|
||||
assert api_image_id(value) == expected
|
||||
|
||||
@@ -74,15 +75,11 @@ def test_archived_image_manifest_raises_when_tar_missing_manifest(tar_file_name)
|
||||
raise AssertionError()
|
||||
except ImageArchiveInvalidException as e:
|
||||
assert isinstance(e.__cause__, KeyError)
|
||||
assert 'manifest.json' in str(e.__cause__)
|
||||
assert "manifest.json" in str(e.__cause__)
|
||||
|
||||
|
||||
def test_archived_image_manifest_raises_when_manifest_missing_id(tar_file_name):
|
||||
manifest = [
|
||||
{
|
||||
'foo': 'bar'
|
||||
}
|
||||
]
|
||||
manifest = [{"foo": "bar"}]
|
||||
|
||||
write_imitation_archive_with_manifest(tar_file_name, manifest)
|
||||
|
||||
@@ -91,4 +88,4 @@ def test_archived_image_manifest_raises_when_manifest_missing_id(tar_file_name):
|
||||
raise AssertionError()
|
||||
except ImageArchiveInvalidException as e:
|
||||
assert isinstance(e.__cause__, KeyError)
|
||||
assert 'Config' in str(e.__cause__)
|
||||
assert "Config" in str(e.__cause__)
|
||||
|
||||
@@ -2,521 +2,452 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils.util import (
|
||||
compare_dict_allow_more_present,
|
||||
compare_generic,
|
||||
convert_duration_to_nanosecond,
|
||||
parse_healthcheck
|
||||
parse_healthcheck,
|
||||
)
|
||||
|
||||
|
||||
DICT_ALLOW_MORE_PRESENT = (
|
||||
{
|
||||
'av': {},
|
||||
'bv': {'a': 1},
|
||||
'result': True
|
||||
},
|
||||
{
|
||||
'av': {'a': 1},
|
||||
'bv': {'a': 1, 'b': 2},
|
||||
'result': True
|
||||
},
|
||||
{
|
||||
'av': {'a': 1},
|
||||
'bv': {'b': 2},
|
||||
'result': False
|
||||
},
|
||||
{
|
||||
'av': {'a': 1},
|
||||
'bv': {'a': None, 'b': 1},
|
||||
'result': False
|
||||
},
|
||||
{
|
||||
'av': {'a': None},
|
||||
'bv': {'b': 1},
|
||||
'result': False
|
||||
},
|
||||
{"av": {}, "bv": {"a": 1}, "result": True},
|
||||
{"av": {"a": 1}, "bv": {"a": 1, "b": 2}, "result": True},
|
||||
{"av": {"a": 1}, "bv": {"b": 2}, "result": False},
|
||||
{"av": {"a": 1}, "bv": {"a": None, "b": 1}, "result": False},
|
||||
{"av": {"a": None}, "bv": {"b": 1}, "result": False},
|
||||
)
|
||||
|
||||
COMPARE_GENERIC = [
|
||||
########################################################################################
|
||||
# value
|
||||
{
|
||||
'a': 1,
|
||||
'b': 2,
|
||||
'method': 'strict',
|
||||
'type': 'value',
|
||||
'result': False
|
||||
},
|
||||
{
|
||||
'a': 'hello',
|
||||
'b': 'hello',
|
||||
'method': 'strict',
|
||||
'type': 'value',
|
||||
'result': True
|
||||
},
|
||||
{
|
||||
'a': None,
|
||||
'b': 'hello',
|
||||
'method': 'strict',
|
||||
'type': 'value',
|
||||
'result': False
|
||||
},
|
||||
{
|
||||
'a': None,
|
||||
'b': None,
|
||||
'method': 'strict',
|
||||
'type': 'value',
|
||||
'result': True
|
||||
},
|
||||
{
|
||||
'a': 1,
|
||||
'b': 2,
|
||||
'method': 'ignore',
|
||||
'type': 'value',
|
||||
'result': True
|
||||
},
|
||||
{
|
||||
'a': None,
|
||||
'b': 2,
|
||||
'method': 'ignore',
|
||||
'type': 'value',
|
||||
'result': True
|
||||
},
|
||||
{"a": 1, "b": 2, "method": "strict", "type": "value", "result": False},
|
||||
{"a": "hello", "b": "hello", "method": "strict", "type": "value", "result": True},
|
||||
{"a": None, "b": "hello", "method": "strict", "type": "value", "result": False},
|
||||
{"a": None, "b": None, "method": "strict", "type": "value", "result": True},
|
||||
{"a": 1, "b": 2, "method": "ignore", "type": "value", "result": True},
|
||||
{"a": None, "b": 2, "method": "ignore", "type": "value", "result": True},
|
||||
########################################################################################
|
||||
# list
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
"a": [
|
||||
"x",
|
||||
],
|
||||
'b': [
|
||||
'y',
|
||||
"b": [
|
||||
"y",
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'list',
|
||||
'result': False
|
||||
"method": "strict",
|
||||
"type": "list",
|
||||
"result": False,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
"a": [
|
||||
"x",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
'x',
|
||||
"b": [
|
||||
"x",
|
||||
"x",
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'list',
|
||||
'result': False
|
||||
"method": "strict",
|
||||
"type": "list",
|
||||
"result": False,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'y',
|
||||
"a": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
'y',
|
||||
"b": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'list',
|
||||
'result': True
|
||||
"method": "strict",
|
||||
"type": "list",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'y',
|
||||
"a": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'b': [
|
||||
'y',
|
||||
'x',
|
||||
"b": [
|
||||
"y",
|
||||
"x",
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'list',
|
||||
'result': False
|
||||
"method": "strict",
|
||||
"type": "list",
|
||||
"result": False,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'y',
|
||||
"a": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
"b": [
|
||||
"x",
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'list',
|
||||
'result': False
|
||||
"method": "allow_more_present",
|
||||
"type": "list",
|
||||
"result": False,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
"a": [
|
||||
"x",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
'y',
|
||||
"b": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'list',
|
||||
'result': True
|
||||
"method": "allow_more_present",
|
||||
"type": "list",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'x',
|
||||
'y',
|
||||
"a": [
|
||||
"x",
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
'y',
|
||||
"b": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'list',
|
||||
'result': False
|
||||
"method": "allow_more_present",
|
||||
"type": "list",
|
||||
"result": False,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'z',
|
||||
"a": [
|
||||
"x",
|
||||
"z",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
'y',
|
||||
'x',
|
||||
'z',
|
||||
"b": [
|
||||
"x",
|
||||
"y",
|
||||
"x",
|
||||
"z",
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'list',
|
||||
'result': True
|
||||
"method": "allow_more_present",
|
||||
"type": "list",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'y',
|
||||
"a": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'b': [
|
||||
'y',
|
||||
'x',
|
||||
"b": [
|
||||
"y",
|
||||
"x",
|
||||
],
|
||||
'method': 'ignore',
|
||||
'type': 'list',
|
||||
'result': True
|
||||
"method": "ignore",
|
||||
"type": "list",
|
||||
"result": True,
|
||||
},
|
||||
########################################################################################
|
||||
# set
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
"a": [
|
||||
"x",
|
||||
],
|
||||
'b': [
|
||||
'y',
|
||||
"b": [
|
||||
"y",
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'set',
|
||||
'result': False
|
||||
"method": "strict",
|
||||
"type": "set",
|
||||
"result": False,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
"a": [
|
||||
"x",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
'x',
|
||||
"b": [
|
||||
"x",
|
||||
"x",
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'set',
|
||||
'result': True
|
||||
"method": "strict",
|
||||
"type": "set",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'y',
|
||||
"a": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
'y',
|
||||
"b": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'set',
|
||||
'result': True
|
||||
"method": "strict",
|
||||
"type": "set",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'y',
|
||||
"a": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'b': [
|
||||
'y',
|
||||
'x',
|
||||
"b": [
|
||||
"y",
|
||||
"x",
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'set',
|
||||
'result': True
|
||||
"method": "strict",
|
||||
"type": "set",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'y',
|
||||
"a": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
"b": [
|
||||
"x",
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'set',
|
||||
'result': False
|
||||
"method": "allow_more_present",
|
||||
"type": "set",
|
||||
"result": False,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
"a": [
|
||||
"x",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
'y',
|
||||
"b": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'set',
|
||||
'result': True
|
||||
"method": "allow_more_present",
|
||||
"type": "set",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'x',
|
||||
'y',
|
||||
"a": [
|
||||
"x",
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
'y',
|
||||
"b": [
|
||||
"x",
|
||||
"y",
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'set',
|
||||
'result': True
|
||||
"method": "allow_more_present",
|
||||
"type": "set",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'z',
|
||||
"a": [
|
||||
"x",
|
||||
"z",
|
||||
],
|
||||
'b': [
|
||||
'x',
|
||||
'y',
|
||||
'x',
|
||||
'z',
|
||||
"b": [
|
||||
"x",
|
||||
"y",
|
||||
"x",
|
||||
"z",
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'set',
|
||||
'result': True
|
||||
"method": "allow_more_present",
|
||||
"type": "set",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
'x',
|
||||
'a',
|
||||
"a": [
|
||||
"x",
|
||||
"a",
|
||||
],
|
||||
'b': [
|
||||
'y',
|
||||
'z',
|
||||
"b": [
|
||||
"y",
|
||||
"z",
|
||||
],
|
||||
'method': 'ignore',
|
||||
'type': 'set',
|
||||
'result': True
|
||||
"method": "ignore",
|
||||
"type": "set",
|
||||
"result": True,
|
||||
},
|
||||
########################################################################################
|
||||
# set(dict)
|
||||
{
|
||||
'a': [
|
||||
{'x': 1},
|
||||
"a": [
|
||||
{"x": 1},
|
||||
],
|
||||
'b': [
|
||||
{'y': 1},
|
||||
"b": [
|
||||
{"y": 1},
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'set(dict)',
|
||||
'result': False
|
||||
"method": "strict",
|
||||
"type": "set(dict)",
|
||||
"result": False,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
{'x': 1},
|
||||
"a": [
|
||||
{"x": 1},
|
||||
],
|
||||
'b': [
|
||||
{'x': 1},
|
||||
"b": [
|
||||
{"x": 1},
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'set(dict)',
|
||||
'result': True
|
||||
"method": "strict",
|
||||
"type": "set(dict)",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
{'x': 1},
|
||||
"a": [
|
||||
{"x": 1},
|
||||
],
|
||||
'b': [
|
||||
{'x': 1, 'y': 2},
|
||||
"b": [
|
||||
{"x": 1, "y": 2},
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'set(dict)',
|
||||
'result': True
|
||||
"method": "strict",
|
||||
"type": "set(dict)",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
{'x': 1},
|
||||
{'x': 2, 'y': 3},
|
||||
"a": [
|
||||
{"x": 1},
|
||||
{"x": 2, "y": 3},
|
||||
],
|
||||
'b': [
|
||||
{'x': 1},
|
||||
{'x': 2, 'y': 3},
|
||||
"b": [
|
||||
{"x": 1},
|
||||
{"x": 2, "y": 3},
|
||||
],
|
||||
'method': 'strict',
|
||||
'type': 'set(dict)',
|
||||
'result': True
|
||||
"method": "strict",
|
||||
"type": "set(dict)",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
{'x': 1},
|
||||
"a": [
|
||||
{"x": 1},
|
||||
],
|
||||
'b': [
|
||||
{'x': 1, 'z': 2},
|
||||
{'x': 2, 'y': 3},
|
||||
"b": [
|
||||
{"x": 1, "z": 2},
|
||||
{"x": 2, "y": 3},
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'set(dict)',
|
||||
'result': True
|
||||
"method": "allow_more_present",
|
||||
"type": "set(dict)",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
{'x': 1, 'y': 2},
|
||||
"a": [
|
||||
{"x": 1, "y": 2},
|
||||
],
|
||||
'b': [
|
||||
{'x': 1},
|
||||
{'x': 2, 'y': 3},
|
||||
"b": [
|
||||
{"x": 1},
|
||||
{"x": 2, "y": 3},
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'set(dict)',
|
||||
'result': False
|
||||
"method": "allow_more_present",
|
||||
"type": "set(dict)",
|
||||
"result": False,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
{'x': 1, 'y': 3},
|
||||
"a": [
|
||||
{"x": 1, "y": 3},
|
||||
],
|
||||
'b': [
|
||||
{'x': 1},
|
||||
{'x': 1, 'y': 3, 'z': 4},
|
||||
"b": [
|
||||
{"x": 1},
|
||||
{"x": 1, "y": 3, "z": 4},
|
||||
],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'set(dict)',
|
||||
'result': True
|
||||
"method": "allow_more_present",
|
||||
"type": "set(dict)",
|
||||
"result": True,
|
||||
},
|
||||
{
|
||||
'a': [
|
||||
{'x': 1},
|
||||
{'x': 2, 'y': 3},
|
||||
"a": [
|
||||
{"x": 1},
|
||||
{"x": 2, "y": 3},
|
||||
],
|
||||
'b': [
|
||||
{'x': 1},
|
||||
"b": [
|
||||
{"x": 1},
|
||||
],
|
||||
'method': 'ignore',
|
||||
'type': 'set(dict)',
|
||||
'result': True
|
||||
"method": "ignore",
|
||||
"type": "set(dict)",
|
||||
"result": True,
|
||||
},
|
||||
########################################################################################
|
||||
# dict
|
||||
{"a": {"x": 1}, "b": {"y": 1}, "method": "strict", "type": "dict", "result": False},
|
||||
{
|
||||
'a': {'x': 1},
|
||||
'b': {'y': 1},
|
||||
'method': 'strict',
|
||||
'type': 'dict',
|
||||
'result': False
|
||||
"a": {"x": 1},
|
||||
"b": {"x": 1, "y": 2},
|
||||
"method": "strict",
|
||||
"type": "dict",
|
||||
"result": False,
|
||||
},
|
||||
{"a": {"x": 1}, "b": {"x": 1}, "method": "strict", "type": "dict", "result": True},
|
||||
{
|
||||
"a": {"x": 1, "z": 2},
|
||||
"b": {"x": 1, "y": 2},
|
||||
"method": "strict",
|
||||
"type": "dict",
|
||||
"result": False,
|
||||
},
|
||||
{
|
||||
'a': {'x': 1},
|
||||
'b': {'x': 1, 'y': 2},
|
||||
'method': 'strict',
|
||||
'type': 'dict',
|
||||
'result': False
|
||||
"a": {"x": 1, "z": 2},
|
||||
"b": {"x": 1, "y": 2},
|
||||
"method": "ignore",
|
||||
"type": "dict",
|
||||
"result": True,
|
||||
},
|
||||
] + [
|
||||
{
|
||||
'a': {'x': 1},
|
||||
'b': {'x': 1},
|
||||
'method': 'strict',
|
||||
'type': 'dict',
|
||||
'result': True
|
||||
},
|
||||
{
|
||||
'a': {'x': 1, 'z': 2},
|
||||
'b': {'x': 1, 'y': 2},
|
||||
'method': 'strict',
|
||||
'type': 'dict',
|
||||
'result': False
|
||||
},
|
||||
{
|
||||
'a': {'x': 1, 'z': 2},
|
||||
'b': {'x': 1, 'y': 2},
|
||||
'method': 'ignore',
|
||||
'type': 'dict',
|
||||
'result': True
|
||||
},
|
||||
] + [{
|
||||
'a': entry['av'],
|
||||
'b': entry['bv'],
|
||||
'method': 'allow_more_present',
|
||||
'type': 'dict',
|
||||
'result': entry['result']
|
||||
} for entry in DICT_ALLOW_MORE_PRESENT]
|
||||
"a": entry["av"],
|
||||
"b": entry["bv"],
|
||||
"method": "allow_more_present",
|
||||
"type": "dict",
|
||||
"result": entry["result"],
|
||||
}
|
||||
for entry in DICT_ALLOW_MORE_PRESENT
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("entry", DICT_ALLOW_MORE_PRESENT)
|
||||
def test_dict_allow_more_present(entry):
|
||||
assert compare_dict_allow_more_present(entry['av'], entry['bv']) == entry['result']
|
||||
assert compare_dict_allow_more_present(entry["av"], entry["bv"]) == entry["result"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("entry", COMPARE_GENERIC)
|
||||
def test_compare_generic(entry):
|
||||
assert compare_generic(entry['a'], entry['b'], entry['method'], entry['type']) == entry['result']
|
||||
assert (
|
||||
compare_generic(entry["a"], entry["b"], entry["method"], entry["type"])
|
||||
== entry["result"]
|
||||
)
|
||||
|
||||
|
||||
def test_convert_duration_to_nanosecond():
|
||||
nanoseconds = convert_duration_to_nanosecond('5s')
|
||||
nanoseconds = convert_duration_to_nanosecond("5s")
|
||||
assert nanoseconds == 5000000000
|
||||
nanoseconds = convert_duration_to_nanosecond('1m5s')
|
||||
nanoseconds = convert_duration_to_nanosecond("1m5s")
|
||||
assert nanoseconds == 65000000000
|
||||
with pytest.raises(ValueError):
|
||||
convert_duration_to_nanosecond([1, 2, 3])
|
||||
with pytest.raises(ValueError):
|
||||
convert_duration_to_nanosecond('10x')
|
||||
convert_duration_to_nanosecond("10x")
|
||||
|
||||
|
||||
def test_parse_healthcheck():
|
||||
result, disabled = parse_healthcheck({
|
||||
'test': 'sleep 1',
|
||||
'interval': '1s',
|
||||
})
|
||||
result, disabled = parse_healthcheck(
|
||||
{
|
||||
"test": "sleep 1",
|
||||
"interval": "1s",
|
||||
}
|
||||
)
|
||||
assert disabled is False
|
||||
assert result == {
|
||||
'test': ['CMD-SHELL', 'sleep 1'],
|
||||
'interval': 1000000000
|
||||
}
|
||||
assert result == {"test": ["CMD-SHELL", "sleep 1"], "interval": 1000000000}
|
||||
|
||||
result, disabled = parse_healthcheck({
|
||||
'test': ['NONE'],
|
||||
})
|
||||
result, disabled = parse_healthcheck(
|
||||
{
|
||||
"test": ["NONE"],
|
||||
}
|
||||
)
|
||||
assert result is None
|
||||
assert disabled
|
||||
|
||||
result, disabled = parse_healthcheck({
|
||||
'test': 'sleep 1',
|
||||
'interval': '1s423ms'
|
||||
})
|
||||
assert result == {
|
||||
'test': ['CMD-SHELL', 'sleep 1'],
|
||||
'interval': 1423000000
|
||||
}
|
||||
result, disabled = parse_healthcheck({"test": "sleep 1", "interval": "1s423ms"})
|
||||
assert result == {"test": ["CMD-SHELL", "sleep 1"], "interval": 1423000000}
|
||||
assert disabled is False
|
||||
|
||||
result, disabled = parse_healthcheck({
|
||||
'test': 'sleep 1',
|
||||
'interval': '1h1m2s3ms4us'
|
||||
})
|
||||
assert result == {
|
||||
'test': ['CMD-SHELL', 'sleep 1'],
|
||||
'interval': 3662003004000
|
||||
}
|
||||
result, disabled = parse_healthcheck(
|
||||
{"test": "sleep 1", "interval": "1h1m2s3ms4us"}
|
||||
)
|
||||
assert result == {"test": ["CMD-SHELL", "sleep 1"], "interval": 3662003004000}
|
||||
assert disabled is False
|
||||
|
||||
@@ -2,53 +2,66 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.modules.docker_container_copy_into import parse_modern, parse_octal_string_only
|
||||
from ansible_collections.community.docker.plugins.modules.docker_container_copy_into import (
|
||||
parse_modern,
|
||||
parse_octal_string_only,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", [
|
||||
('0777', 0o777),
|
||||
('777', 0o777),
|
||||
('0o777', 0o777),
|
||||
('0755', 0o755),
|
||||
('755', 0o755),
|
||||
('0o755', 0o755),
|
||||
('0644', 0o644),
|
||||
('644', 0o644),
|
||||
('0o644', 0o644),
|
||||
(' 0644 ', 0o644),
|
||||
(' 644 ', 0o644),
|
||||
(' 0o644 ', 0o644),
|
||||
('-1', -1),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"input, expected",
|
||||
[
|
||||
("0777", 0o777),
|
||||
("777", 0o777),
|
||||
("0o777", 0o777),
|
||||
("0755", 0o755),
|
||||
("755", 0o755),
|
||||
("0o755", 0o755),
|
||||
("0644", 0o644),
|
||||
("644", 0o644),
|
||||
("0o644", 0o644),
|
||||
(" 0644 ", 0o644),
|
||||
(" 644 ", 0o644),
|
||||
(" 0o644 ", 0o644),
|
||||
("-1", -1),
|
||||
],
|
||||
)
|
||||
def test_parse_string(input, expected):
|
||||
assert parse_modern(input) == expected
|
||||
assert parse_octal_string_only(input) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input", [
|
||||
0o777,
|
||||
0o755,
|
||||
0o644,
|
||||
12345,
|
||||
123456789012345678901234567890123456789012345678901234567890,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"input",
|
||||
[
|
||||
0o777,
|
||||
0o755,
|
||||
0o644,
|
||||
12345,
|
||||
123456789012345678901234567890123456789012345678901234567890,
|
||||
],
|
||||
)
|
||||
def test_parse_int(input):
|
||||
assert parse_modern(input) == input
|
||||
with pytest.raises(TypeError, match=f"^must be an octal string, got {input}L?$"):
|
||||
parse_octal_string_only(input)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input", [
|
||||
1.0,
|
||||
755.5,
|
||||
[],
|
||||
{},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"input",
|
||||
[
|
||||
1.0,
|
||||
755.5,
|
||||
[],
|
||||
{},
|
||||
],
|
||||
)
|
||||
def test_parse_bad_type(input):
|
||||
with pytest.raises(TypeError, match="^must be an octal string or an integer, got "):
|
||||
parse_modern(input)
|
||||
@@ -56,11 +69,14 @@ def test_parse_bad_type(input):
|
||||
parse_octal_string_only(input)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input", [
|
||||
"foo",
|
||||
"8",
|
||||
"9",
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"input",
|
||||
[
|
||||
"foo",
|
||||
"8",
|
||||
"9",
|
||||
],
|
||||
)
|
||||
def test_parse_bad_value(input):
|
||||
with pytest.raises(ValueError):
|
||||
parse_modern(input)
|
||||
|
||||
@@ -2,14 +2,18 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.modules.docker_image import ImageManager
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils.image_archive import api_image_id
|
||||
from ansible_collections.community.docker.plugins.module_utils.image_archive import (
|
||||
api_image_id,
|
||||
)
|
||||
from ansible_collections.community.docker.plugins.modules.docker_image import (
|
||||
ImageManager,
|
||||
)
|
||||
|
||||
from ..test_support.docker_image_archive_stubbing import (
|
||||
write_imitation_archive,
|
||||
@@ -18,7 +22,7 @@ from ..test_support.docker_image_archive_stubbing import (
|
||||
|
||||
|
||||
def assert_no_logging(msg):
|
||||
raise AssertionError(f'Should not have logged anything but logged {msg}')
|
||||
raise AssertionError(f"Should not have logged anything but logged {msg}")
|
||||
|
||||
|
||||
def capture_logging(messages):
|
||||
@@ -34,76 +38,81 @@ def tar_file_name(tmpdir):
|
||||
Return the name of a non-existing tar file in an existing temporary directory.
|
||||
"""
|
||||
|
||||
return tmpdir.join('foo.tar')
|
||||
return tmpdir.join("foo.tar")
|
||||
|
||||
|
||||
def test_archived_image_action_when_missing(tar_file_name):
|
||||
fake_name = 'a:latest'
|
||||
fake_id = 'a1'
|
||||
fake_name = "a:latest"
|
||||
fake_id = "a1"
|
||||
|
||||
expected = f'Archived image {fake_name} to {tar_file_name}, since none present'
|
||||
expected = f"Archived image {fake_name} to {tar_file_name}, since none present"
|
||||
|
||||
actual = ImageManager.archived_image_action(assert_no_logging, tar_file_name, fake_name, api_image_id(fake_id))
|
||||
actual = ImageManager.archived_image_action(
|
||||
assert_no_logging, tar_file_name, fake_name, api_image_id(fake_id)
|
||||
)
|
||||
|
||||
assert actual == expected
|
||||
|
||||
|
||||
def test_archived_image_action_when_current(tar_file_name):
|
||||
fake_name = 'b:latest'
|
||||
fake_id = 'b2'
|
||||
fake_name = "b:latest"
|
||||
fake_id = "b2"
|
||||
|
||||
write_imitation_archive(tar_file_name, fake_id, [fake_name])
|
||||
|
||||
actual = ImageManager.archived_image_action(assert_no_logging, tar_file_name, fake_name, api_image_id(fake_id))
|
||||
actual = ImageManager.archived_image_action(
|
||||
assert_no_logging, tar_file_name, fake_name, api_image_id(fake_id)
|
||||
)
|
||||
|
||||
assert actual is None
|
||||
|
||||
|
||||
def test_archived_image_action_when_invalid(tar_file_name):
|
||||
fake_name = 'c:1.2.3'
|
||||
fake_id = 'c3'
|
||||
fake_name = "c:1.2.3"
|
||||
fake_id = "c3"
|
||||
|
||||
write_irrelevant_tar(tar_file_name)
|
||||
|
||||
expected = f'Archived image {fake_name} to {tar_file_name}, overwriting an unreadable archive file'
|
||||
expected = f"Archived image {fake_name} to {tar_file_name}, overwriting an unreadable archive file"
|
||||
|
||||
actual_log = []
|
||||
actual = ImageManager.archived_image_action(
|
||||
capture_logging(actual_log),
|
||||
tar_file_name,
|
||||
fake_name,
|
||||
api_image_id(fake_id)
|
||||
capture_logging(actual_log), tar_file_name, fake_name, api_image_id(fake_id)
|
||||
)
|
||||
|
||||
assert actual == expected
|
||||
|
||||
assert len(actual_log) == 1
|
||||
assert actual_log[0].startswith('Unable to extract manifest summary from archive')
|
||||
assert actual_log[0].startswith("Unable to extract manifest summary from archive")
|
||||
|
||||
|
||||
def test_archived_image_action_when_obsolete_by_id(tar_file_name):
|
||||
fake_name = 'd:0.0.1'
|
||||
old_id = 'e5'
|
||||
new_id = 'd4'
|
||||
fake_name = "d:0.0.1"
|
||||
old_id = "e5"
|
||||
new_id = "d4"
|
||||
|
||||
write_imitation_archive(tar_file_name, old_id, [fake_name])
|
||||
|
||||
expected = f'Archived image {fake_name} to {tar_file_name}, overwriting archive with image {old_id} named {fake_name}'
|
||||
actual = ImageManager.archived_image_action(assert_no_logging, tar_file_name, fake_name, api_image_id(new_id))
|
||||
expected = f"Archived image {fake_name} to {tar_file_name}, overwriting archive with image {old_id} named {fake_name}"
|
||||
actual = ImageManager.archived_image_action(
|
||||
assert_no_logging, tar_file_name, fake_name, api_image_id(new_id)
|
||||
)
|
||||
|
||||
assert actual == expected
|
||||
|
||||
|
||||
def test_archived_image_action_when_obsolete_by_name(tar_file_name):
|
||||
old_name = 'hi'
|
||||
new_name = 'd:0.0.1'
|
||||
fake_id = 'd4'
|
||||
old_name = "hi"
|
||||
new_name = "d:0.0.1"
|
||||
fake_id = "d4"
|
||||
|
||||
write_imitation_archive(tar_file_name, fake_id, [old_name])
|
||||
|
||||
expected = f'Archived image {new_name} to {tar_file_name}, overwriting archive with image {fake_id} named {old_name}'
|
||||
actual = ImageManager.archived_image_action(assert_no_logging, tar_file_name, new_name, api_image_id(fake_id))
|
||||
expected = f"Archived image {new_name} to {tar_file_name}, overwriting archive with image {fake_id} named {old_name}"
|
||||
actual = ImageManager.archived_image_action(
|
||||
assert_no_logging, tar_file_name, new_name, api_image_id(fake_id)
|
||||
)
|
||||
|
||||
print(f'actual : {actual}')
|
||||
print(f'expected : {expected}')
|
||||
print(f"actual : {actual}")
|
||||
print(f"expected : {expected}")
|
||||
assert actual == expected
|
||||
|
||||
@@ -2,20 +2,26 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.modules.docker_image_build import _quote_csv
|
||||
from ansible_collections.community.docker.plugins.modules.docker_image_build import (
|
||||
_quote_csv,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input, expected", [
|
||||
('', ''),
|
||||
(' ', '" "'),
|
||||
(',', '","'),
|
||||
('"', '""""'),
|
||||
('\rhello, "hi" !\n', '"\rhello, ""hi"" !\n"'),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"input, expected",
|
||||
[
|
||||
("", ""),
|
||||
(" ", '" "'),
|
||||
(",", '","'),
|
||||
('"', '""""'),
|
||||
('\rhello, "hi" !\n', '"\rhello, ""hi"" !\n"'),
|
||||
],
|
||||
)
|
||||
def test__quote_csv(input, expected):
|
||||
assert _quote_csv(input) == expected
|
||||
|
||||
@@ -4,31 +4,40 @@
|
||||
|
||||
"""Unit tests for docker_network."""
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.docker.plugins.modules.docker_network import validate_cidr
|
||||
from ansible_collections.community.docker.plugins.modules.docker_network import (
|
||||
validate_cidr,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cidr,expected", [
|
||||
('192.168.0.1/16', 'ipv4'),
|
||||
('192.168.0.1/24', 'ipv4'),
|
||||
('192.168.0.1/32', 'ipv4'),
|
||||
('fdd1:ac8c:0557:7ce2::/64', 'ipv6'),
|
||||
('fdd1:ac8c:0557:7ce2::/128', 'ipv6'),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"cidr,expected",
|
||||
[
|
||||
("192.168.0.1/16", "ipv4"),
|
||||
("192.168.0.1/24", "ipv4"),
|
||||
("192.168.0.1/32", "ipv4"),
|
||||
("fdd1:ac8c:0557:7ce2::/64", "ipv6"),
|
||||
("fdd1:ac8c:0557:7ce2::/128", "ipv6"),
|
||||
],
|
||||
)
|
||||
def test_validate_cidr_positives(cidr, expected):
|
||||
assert validate_cidr(cidr) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cidr", [
|
||||
'192.168.0.1',
|
||||
'192.168.0.1/34',
|
||||
'192.168.0.1/asd',
|
||||
'fdd1:ac8c:0557:7ce2::',
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"cidr",
|
||||
[
|
||||
"192.168.0.1",
|
||||
"192.168.0.1/34",
|
||||
"192.168.0.1/asd",
|
||||
"fdd1:ac8c:0557:7ce2::",
|
||||
],
|
||||
)
|
||||
def test_validate_cidr_negatives(cidr):
|
||||
with pytest.raises(ValueError) as e:
|
||||
validate_cidr(cidr)
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
@@ -22,16 +24,18 @@ def docker_module_mock(mocker):
|
||||
docker_errors_module_mock = mocker.MagicMock()
|
||||
docker_errors_module_mock.APIError = APIErrorMock
|
||||
mock_modules = {
|
||||
'docker': docker_module_mock,
|
||||
'docker.utils': docker_utils_module_mock,
|
||||
'docker.errors': docker_errors_module_mock,
|
||||
"docker": docker_module_mock,
|
||||
"docker.utils": docker_utils_module_mock,
|
||||
"docker.errors": docker_errors_module_mock,
|
||||
}
|
||||
return mocker.patch.dict('sys.modules', **mock_modules)
|
||||
return mocker.patch.dict("sys.modules", **mock_modules)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def docker_swarm_service():
|
||||
from ansible_collections.community.docker.plugins.modules import docker_swarm_service
|
||||
from ansible_collections.community.docker.plugins.modules import (
|
||||
docker_swarm_service,
|
||||
)
|
||||
|
||||
return docker_swarm_service
|
||||
|
||||
@@ -39,9 +43,9 @@ def docker_swarm_service():
|
||||
def test_retry_on_out_of_sequence_error(mocker, docker_swarm_service):
|
||||
run_mock = mocker.MagicMock(
|
||||
side_effect=APIErrorMock(
|
||||
message='',
|
||||
message="",
|
||||
response=None,
|
||||
explanation='rpc error: code = Unknown desc = update out of sequence',
|
||||
explanation="rpc error: code = Unknown desc = update out of sequence",
|
||||
)
|
||||
)
|
||||
manager = docker_swarm_service.DockerServiceManager(client=None)
|
||||
@@ -53,7 +57,7 @@ def test_retry_on_out_of_sequence_error(mocker, docker_swarm_service):
|
||||
|
||||
def test_no_retry_on_general_api_error(mocker, docker_swarm_service):
|
||||
run_mock = mocker.MagicMock(
|
||||
side_effect=APIErrorMock(message='', response=None, explanation='some error')
|
||||
side_effect=APIErrorMock(message="", response=None, explanation="some error")
|
||||
)
|
||||
manager = docker_swarm_service.DockerServiceManager(client=None)
|
||||
manager.run = run_mock
|
||||
@@ -63,62 +67,57 @@ def test_no_retry_on_general_api_error(mocker, docker_swarm_service):
|
||||
|
||||
|
||||
def test_get_docker_environment(mocker, docker_swarm_service):
|
||||
env_file_result = {'TEST1': 'A', 'TEST2': 'B', 'TEST3': 'C'}
|
||||
env_dict = {'TEST3': 'CC', 'TEST4': 'D'}
|
||||
env_file_result = {"TEST1": "A", "TEST2": "B", "TEST3": "C"}
|
||||
env_dict = {"TEST3": "CC", "TEST4": "D"}
|
||||
env_string = "TEST3=CC,TEST4=D"
|
||||
|
||||
env_list = ['TEST3=CC', 'TEST4=D']
|
||||
expected_result = sorted(['TEST1=A', 'TEST2=B', 'TEST3=CC', 'TEST4=D'])
|
||||
env_list = ["TEST3=CC", "TEST4=D"]
|
||||
expected_result = sorted(["TEST1=A", "TEST2=B", "TEST3=CC", "TEST4=D"])
|
||||
mocker.patch.object(
|
||||
docker_swarm_service, 'parse_env_file', return_value=env_file_result
|
||||
docker_swarm_service, "parse_env_file", return_value=env_file_result
|
||||
)
|
||||
mocker.patch.object(
|
||||
docker_swarm_service,
|
||||
'format_environment',
|
||||
side_effect=lambda d: [f'{key}={value}' for key, value in d.items()],
|
||||
"format_environment",
|
||||
side_effect=lambda d: [f"{key}={value}" for key, value in d.items()],
|
||||
)
|
||||
# Test with env dict and file
|
||||
result = docker_swarm_service.get_docker_environment(
|
||||
env_dict, env_files=['dummypath']
|
||||
env_dict, env_files=["dummypath"]
|
||||
)
|
||||
assert result == expected_result
|
||||
# Test with env list and file
|
||||
result = docker_swarm_service.get_docker_environment(
|
||||
env_list,
|
||||
env_files=['dummypath']
|
||||
env_list, env_files=["dummypath"]
|
||||
)
|
||||
assert result == expected_result
|
||||
# Test with env string and file
|
||||
result = docker_swarm_service.get_docker_environment(
|
||||
env_string, env_files=['dummypath']
|
||||
env_string, env_files=["dummypath"]
|
||||
)
|
||||
assert result == expected_result
|
||||
|
||||
assert result == expected_result
|
||||
# Test with empty env
|
||||
result = docker_swarm_service.get_docker_environment(
|
||||
[], env_files=None
|
||||
)
|
||||
result = docker_swarm_service.get_docker_environment([], env_files=None)
|
||||
assert result == []
|
||||
# Test with empty env_files
|
||||
result = docker_swarm_service.get_docker_environment(
|
||||
None, env_files=[]
|
||||
)
|
||||
result = docker_swarm_service.get_docker_environment(None, env_files=[])
|
||||
assert result == []
|
||||
|
||||
|
||||
def test_get_nanoseconds_from_raw_option(docker_swarm_service):
|
||||
value = docker_swarm_service.get_nanoseconds_from_raw_option('test', None)
|
||||
value = docker_swarm_service.get_nanoseconds_from_raw_option("test", None)
|
||||
assert value is None
|
||||
|
||||
value = docker_swarm_service.get_nanoseconds_from_raw_option('test', '1m30s535ms')
|
||||
value = docker_swarm_service.get_nanoseconds_from_raw_option("test", "1m30s535ms")
|
||||
assert value == 90535000000
|
||||
|
||||
value = docker_swarm_service.get_nanoseconds_from_raw_option('test', 10000000000)
|
||||
value = docker_swarm_service.get_nanoseconds_from_raw_option("test", 10000000000)
|
||||
assert value == 10000000000
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
docker_swarm_service.get_nanoseconds_from_raw_option('test', [])
|
||||
docker_swarm_service.get_nanoseconds_from_raw_option("test", [])
|
||||
|
||||
|
||||
def test_has_dict_changed(docker_swarm_service):
|
||||
@@ -126,50 +125,17 @@ def test_has_dict_changed(docker_swarm_service):
|
||||
{"a": 1},
|
||||
{"a": 1},
|
||||
)
|
||||
assert not docker_swarm_service.has_dict_changed(
|
||||
{"a": 1},
|
||||
{"a": 1, "b": 2}
|
||||
)
|
||||
assert docker_swarm_service.has_dict_changed(
|
||||
{"a": 1},
|
||||
{"a": 2, "b": 2}
|
||||
)
|
||||
assert docker_swarm_service.has_dict_changed(
|
||||
{"a": 1, "b": 1},
|
||||
{"a": 1}
|
||||
)
|
||||
assert not docker_swarm_service.has_dict_changed(
|
||||
None,
|
||||
{"a": 2, "b": 2}
|
||||
)
|
||||
assert docker_swarm_service.has_dict_changed(
|
||||
{},
|
||||
{"a": 2, "b": 2}
|
||||
)
|
||||
assert docker_swarm_service.has_dict_changed(
|
||||
{"a": 1},
|
||||
{}
|
||||
)
|
||||
assert docker_swarm_service.has_dict_changed(
|
||||
{"a": 1},
|
||||
None
|
||||
)
|
||||
assert not docker_swarm_service.has_dict_changed(
|
||||
{},
|
||||
{}
|
||||
)
|
||||
assert not docker_swarm_service.has_dict_changed(
|
||||
None,
|
||||
None
|
||||
)
|
||||
assert not docker_swarm_service.has_dict_changed(
|
||||
{},
|
||||
None
|
||||
)
|
||||
assert not docker_swarm_service.has_dict_changed(
|
||||
None,
|
||||
{}
|
||||
)
|
||||
assert not docker_swarm_service.has_dict_changed({"a": 1}, {"a": 1, "b": 2})
|
||||
assert docker_swarm_service.has_dict_changed({"a": 1}, {"a": 2, "b": 2})
|
||||
assert docker_swarm_service.has_dict_changed({"a": 1, "b": 1}, {"a": 1})
|
||||
assert not docker_swarm_service.has_dict_changed(None, {"a": 2, "b": 2})
|
||||
assert docker_swarm_service.has_dict_changed({}, {"a": 2, "b": 2})
|
||||
assert docker_swarm_service.has_dict_changed({"a": 1}, {})
|
||||
assert docker_swarm_service.has_dict_changed({"a": 1}, None)
|
||||
assert not docker_swarm_service.has_dict_changed({}, {})
|
||||
assert not docker_swarm_service.has_dict_changed(None, None)
|
||||
assert not docker_swarm_service.has_dict_changed({}, None)
|
||||
assert not docker_swarm_service.has_dict_changed(None, {})
|
||||
|
||||
|
||||
def test_has_list_changed(docker_swarm_service):
|
||||
@@ -192,65 +158,45 @@ def test_has_list_changed(docker_swarm_service):
|
||||
|
||||
# Check list sorting
|
||||
assert not docker_swarm_service.has_list_changed([1, 2], [2, 1])
|
||||
assert docker_swarm_service.has_list_changed(
|
||||
[1, 2],
|
||||
[2, 1],
|
||||
sort_lists=False
|
||||
)
|
||||
assert docker_swarm_service.has_list_changed([1, 2], [2, 1], sort_lists=False)
|
||||
|
||||
# Check type matching
|
||||
assert docker_swarm_service.has_list_changed([None, 1], [2, 1])
|
||||
assert docker_swarm_service.has_list_changed([2, 1], [None, 1])
|
||||
assert docker_swarm_service.has_list_changed(
|
||||
"command --with args",
|
||||
['command', '--with', 'args']
|
||||
"command --with args", ["command", "--with", "args"]
|
||||
)
|
||||
assert docker_swarm_service.has_list_changed(
|
||||
['sleep', '3400'],
|
||||
['sleep', '3600'],
|
||||
sort_lists=False
|
||||
["sleep", "3400"], ["sleep", "3600"], sort_lists=False
|
||||
)
|
||||
|
||||
# List comparisons with dictionaries
|
||||
assert not docker_swarm_service.has_list_changed(
|
||||
[{'a': 1}],
|
||||
[{'a': 1}],
|
||||
sort_key='a'
|
||||
[{"a": 1}], [{"a": 1}], sort_key="a"
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.has_list_changed(
|
||||
[{'a': 1}, {'a': 2}],
|
||||
[{'a': 1}, {'a': 2}],
|
||||
sort_key='a'
|
||||
[{"a": 1}, {"a": 2}], [{"a": 1}, {"a": 2}], sort_key="a"
|
||||
)
|
||||
|
||||
with pytest.raises(Exception):
|
||||
docker_swarm_service.has_list_changed(
|
||||
[{'a': 1}, {'a': 2}],
|
||||
[{'a': 1}, {'a': 2}]
|
||||
[{"a": 1}, {"a": 2}], [{"a": 1}, {"a": 2}]
|
||||
)
|
||||
|
||||
# List sort checking with sort key
|
||||
assert not docker_swarm_service.has_list_changed(
|
||||
[{'a': 1}, {'a': 2}],
|
||||
[{'a': 2}, {'a': 1}],
|
||||
sort_key='a'
|
||||
[{"a": 1}, {"a": 2}], [{"a": 2}, {"a": 1}], sort_key="a"
|
||||
)
|
||||
assert docker_swarm_service.has_list_changed(
|
||||
[{'a': 1}, {'a': 2}],
|
||||
[{'a': 2}, {'a': 1}],
|
||||
sort_lists=False
|
||||
[{"a": 1}, {"a": 2}], [{"a": 2}, {"a": 1}], sort_lists=False
|
||||
)
|
||||
|
||||
assert docker_swarm_service.has_list_changed(
|
||||
[{'a': 1}, {'a': 2}, {'a': 3}],
|
||||
[{'a': 2}, {'a': 1}],
|
||||
sort_key='a'
|
||||
[{"a": 1}, {"a": 2}, {"a": 3}], [{"a": 2}, {"a": 1}], sort_key="a"
|
||||
)
|
||||
assert docker_swarm_service.has_list_changed(
|
||||
[{'a': 1}, {'a': 2}],
|
||||
[{'a': 1}, {'a': 2}, {'a': 3}],
|
||||
sort_lists=False
|
||||
[{"a": 1}, {"a": 2}], [{"a": 1}, {"a": 2}, {"a": 3}], sort_lists=False
|
||||
)
|
||||
|
||||
# Additional dictionary elements
|
||||
@@ -263,7 +209,7 @@ def test_has_list_changed(docker_swarm_service):
|
||||
{"src": 1, "dst": 2, "protocol": "tcp"},
|
||||
{"src": 1, "dst": 2, "protocol": "udp"},
|
||||
],
|
||||
sort_key='dst'
|
||||
sort_key="dst",
|
||||
)
|
||||
assert not docker_swarm_service.has_list_changed(
|
||||
[
|
||||
@@ -274,7 +220,7 @@ def test_has_list_changed(docker_swarm_service):
|
||||
{"src": 1, "dst": 2, "protocol": "udp"},
|
||||
{"src": 1, "dst": 3, "protocol": "tcp"},
|
||||
],
|
||||
sort_key='dst'
|
||||
sort_key="dst",
|
||||
)
|
||||
assert docker_swarm_service.has_list_changed(
|
||||
[
|
||||
@@ -287,7 +233,7 @@ def test_has_list_changed(docker_swarm_service):
|
||||
{"src": 1, "dst": 2, "protocol": "tcp"},
|
||||
{"src": 3, "dst": 4, "protocol": "tcp"},
|
||||
],
|
||||
sort_key='dst'
|
||||
sort_key="dst",
|
||||
)
|
||||
assert docker_swarm_service.has_list_changed(
|
||||
[
|
||||
@@ -298,7 +244,7 @@ def test_has_list_changed(docker_swarm_service):
|
||||
{"src": 1, "dst": 2, "protocol": "tcp"},
|
||||
{"src": 1, "dst": 2, "protocol": "udp"},
|
||||
],
|
||||
sort_key='dst'
|
||||
sort_key="dst",
|
||||
)
|
||||
assert docker_swarm_service.has_list_changed(
|
||||
[
|
||||
@@ -309,206 +255,148 @@ def test_has_list_changed(docker_swarm_service):
|
||||
{"src": 1, "dst": 2, "protocol": "udp"},
|
||||
{"src": 1, "dst": 2, "protocol": "tcp"},
|
||||
],
|
||||
sort_key='dst'
|
||||
sort_key="dst",
|
||||
)
|
||||
assert not docker_swarm_service.has_list_changed(
|
||||
[{'id': '123', 'aliases': []}],
|
||||
[{'id': '123'}],
|
||||
sort_key='id'
|
||||
[{"id": "123", "aliases": []}], [{"id": "123"}], sort_key="id"
|
||||
)
|
||||
|
||||
|
||||
def test_have_networks_changed(docker_swarm_service):
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
None,
|
||||
None
|
||||
assert not docker_swarm_service.have_networks_changed(None, None)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed([], None)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed([{"id": 1}], [{"id": 1}])
|
||||
|
||||
assert docker_swarm_service.have_networks_changed(
|
||||
[{"id": 1}], [{"id": 1}, {"id": 2}]
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[],
|
||||
None
|
||||
[{"id": 1}, {"id": 2}], [{"id": 1}, {"id": 2}]
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[{'id': 1}],
|
||||
[{'id': 1}]
|
||||
[{"id": 1}, {"id": 2}], [{"id": 2}, {"id": 1}]
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[{"id": 1}, {"id": 2, "aliases": []}], [{"id": 1}, {"id": 2}]
|
||||
)
|
||||
|
||||
assert docker_swarm_service.have_networks_changed(
|
||||
[{'id': 1}],
|
||||
[{'id': 1}, {'id': 2}]
|
||||
[{"id": 1}, {"id": 2, "aliases": ["alias1"]}], [{"id": 1}, {"id": 2}]
|
||||
)
|
||||
|
||||
assert docker_swarm_service.have_networks_changed(
|
||||
[{"id": 1}, {"id": 2, "aliases": ["alias1", "alias2"]}],
|
||||
[{"id": 1}, {"id": 2, "aliases": ["alias1"]}],
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[{'id': 1}, {'id': 2}],
|
||||
[{'id': 1}, {'id': 2}]
|
||||
[{"id": 1}, {"id": 2, "aliases": ["alias1", "alias2"]}],
|
||||
[{"id": 1}, {"id": 2, "aliases": ["alias1", "alias2"]}],
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[{'id': 1}, {'id': 2}],
|
||||
[{'id': 2}, {'id': 1}]
|
||||
[{"id": 1}, {"id": 2, "aliases": ["alias1", "alias2"]}],
|
||||
[{"id": 1}, {"id": 2, "aliases": ["alias2", "alias1"]}],
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[{"id": 1, "options": {}}, {"id": 2, "aliases": ["alias1", "alias2"]}],
|
||||
[{"id": 1}, {"id": 2, "aliases": ["alias2", "alias1"]}],
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2, 'aliases': []}
|
||||
{"id": 1, "options": {"option1": "value1"}},
|
||||
{"id": 2, "aliases": ["alias1", "alias2"]},
|
||||
],
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2}
|
||||
]
|
||||
{"id": 1, "options": {"option1": "value1"}},
|
||||
{"id": 2, "aliases": ["alias2", "alias1"]},
|
||||
],
|
||||
)
|
||||
|
||||
assert docker_swarm_service.have_networks_changed(
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2, 'aliases': ['alias1']}
|
||||
{"id": 1, "options": {"option1": "value1"}},
|
||||
{"id": 2, "aliases": ["alias1", "alias2"]},
|
||||
],
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2}
|
||||
]
|
||||
)
|
||||
|
||||
assert docker_swarm_service.have_networks_changed(
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2, 'aliases': ['alias1', 'alias2']}
|
||||
{"id": 1, "options": {"option1": "value2"}},
|
||||
{"id": 2, "aliases": ["alias2", "alias1"]},
|
||||
],
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2, 'aliases': ['alias1']}
|
||||
]
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2, 'aliases': ['alias1', 'alias2']}
|
||||
],
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2, 'aliases': ['alias1', 'alias2']}
|
||||
]
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2, 'aliases': ['alias1', 'alias2']}
|
||||
],
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2, 'aliases': ['alias2', 'alias1']}
|
||||
]
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[
|
||||
{'id': 1, 'options': {}},
|
||||
{'id': 2, 'aliases': ['alias1', 'alias2']}],
|
||||
[
|
||||
{'id': 1},
|
||||
{'id': 2, 'aliases': ['alias2', 'alias1']}
|
||||
]
|
||||
)
|
||||
|
||||
assert not docker_swarm_service.have_networks_changed(
|
||||
[
|
||||
{'id': 1, 'options': {'option1': 'value1'}},
|
||||
{'id': 2, 'aliases': ['alias1', 'alias2']}],
|
||||
[
|
||||
{'id': 1, 'options': {'option1': 'value1'}},
|
||||
{'id': 2, 'aliases': ['alias2', 'alias1']}
|
||||
]
|
||||
)
|
||||
|
||||
assert docker_swarm_service.have_networks_changed(
|
||||
[
|
||||
{'id': 1, 'options': {'option1': 'value1'}},
|
||||
{'id': 2, 'aliases': ['alias1', 'alias2']}],
|
||||
[
|
||||
{'id': 1, 'options': {'option1': 'value2'}},
|
||||
{'id': 2, 'aliases': ['alias2', 'alias1']}
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_get_docker_networks(docker_swarm_service):
|
||||
network_names = [
|
||||
'network_1',
|
||||
'network_2',
|
||||
'network_3',
|
||||
'network_4',
|
||||
"network_1",
|
||||
"network_2",
|
||||
"network_3",
|
||||
"network_4",
|
||||
]
|
||||
networks = [
|
||||
network_names[0],
|
||||
{'name': network_names[1]},
|
||||
{'name': network_names[2], 'aliases': ['networkalias1']},
|
||||
{'name': network_names[3], 'aliases': ['networkalias2'], 'options': {'foo': 'bar'}},
|
||||
{"name": network_names[1]},
|
||||
{"name": network_names[2], "aliases": ["networkalias1"]},
|
||||
{
|
||||
"name": network_names[3],
|
||||
"aliases": ["networkalias2"],
|
||||
"options": {"foo": "bar"},
|
||||
},
|
||||
]
|
||||
network_ids = {
|
||||
network_names[0]: '1',
|
||||
network_names[1]: '2',
|
||||
network_names[2]: '3',
|
||||
network_names[3]: '4',
|
||||
network_names[0]: "1",
|
||||
network_names[1]: "2",
|
||||
network_names[2]: "3",
|
||||
network_names[3]: "4",
|
||||
}
|
||||
parsed_networks = docker_swarm_service.get_docker_networks(
|
||||
networks,
|
||||
network_ids
|
||||
)
|
||||
parsed_networks = docker_swarm_service.get_docker_networks(networks, network_ids)
|
||||
assert len(parsed_networks) == 4
|
||||
for i, network in enumerate(parsed_networks):
|
||||
assert 'name' not in network
|
||||
assert 'id' in network
|
||||
assert "name" not in network
|
||||
assert "id" in network
|
||||
expected_name = network_names[i]
|
||||
assert network['id'] == network_ids[expected_name]
|
||||
assert network["id"] == network_ids[expected_name]
|
||||
if i == 2:
|
||||
assert network['aliases'] == ['networkalias1']
|
||||
assert network["aliases"] == ["networkalias1"]
|
||||
if i == 3:
|
||||
assert network['aliases'] == ['networkalias2']
|
||||
assert network["aliases"] == ["networkalias2"]
|
||||
if i == 3:
|
||||
assert 'foo' in network['options']
|
||||
assert "foo" in network["options"]
|
||||
# Test missing name
|
||||
with pytest.raises(TypeError):
|
||||
docker_swarm_service.get_docker_networks([{'invalid': 'err'}], {'err': 1})
|
||||
docker_swarm_service.get_docker_networks([{"invalid": "err"}], {"err": 1})
|
||||
# test for invalid aliases type
|
||||
with pytest.raises(TypeError):
|
||||
docker_swarm_service.get_docker_networks(
|
||||
[{'name': 'test', 'aliases': 1}],
|
||||
{'test': 1}
|
||||
[{"name": "test", "aliases": 1}], {"test": 1}
|
||||
)
|
||||
# Test invalid aliases elements
|
||||
with pytest.raises(TypeError):
|
||||
docker_swarm_service.get_docker_networks(
|
||||
[{'name': 'test', 'aliases': [1]}],
|
||||
{'test': 1}
|
||||
[{"name": "test", "aliases": [1]}], {"test": 1}
|
||||
)
|
||||
# Test for invalid options type
|
||||
with pytest.raises(TypeError):
|
||||
docker_swarm_service.get_docker_networks(
|
||||
[{'name': 'test', 'options': 1}],
|
||||
{'test': 1}
|
||||
[{"name": "test", "options": 1}], {"test": 1}
|
||||
)
|
||||
# Test for invalid networks type
|
||||
with pytest.raises(TypeError):
|
||||
docker_swarm_service.get_docker_networks(
|
||||
1,
|
||||
{'test': 1}
|
||||
)
|
||||
docker_swarm_service.get_docker_networks(1, {"test": 1})
|
||||
# Test for non existing networks
|
||||
with pytest.raises(ValueError):
|
||||
docker_swarm_service.get_docker_networks(
|
||||
[{'name': 'idontexist'}],
|
||||
{'test': 1}
|
||||
)
|
||||
docker_swarm_service.get_docker_networks([{"name": "idontexist"}], {"test": 1})
|
||||
# Test empty values
|
||||
assert docker_swarm_service.get_docker_networks([], {}) == []
|
||||
assert docker_swarm_service.get_docker_networks(None, {}) is None
|
||||
# Test invalid options
|
||||
with pytest.raises(TypeError):
|
||||
docker_swarm_service.get_docker_networks(
|
||||
[{'name': 'test', 'nonexisting_option': 'foo'}],
|
||||
{'test': '1'}
|
||||
[{"name": "test", "nonexisting_option": "foo"}], {"test": "1"}
|
||||
)
|
||||
|
||||
@@ -5,31 +5,34 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.utils.trust import (
|
||||
make_untrusted as _make_untrusted,
|
||||
make_trusted as _make_trusted,
|
||||
is_trusted as _is_trusted,
|
||||
SUPPORTS_DATA_TAGGING,
|
||||
)
|
||||
|
||||
from ansible_collections.community.docker.plugins.plugin_utils.unsafe import (
|
||||
make_unsafe,
|
||||
)
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.utils.trust import (
|
||||
SUPPORTS_DATA_TAGGING,
|
||||
)
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.utils.trust import (
|
||||
is_trusted as _is_trusted,
|
||||
)
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.utils.trust import (
|
||||
make_trusted as _make_trusted,
|
||||
)
|
||||
from ansible_collections.community.internal_test_tools.tests.unit.utils.trust import (
|
||||
make_untrusted as _make_untrusted,
|
||||
)
|
||||
|
||||
|
||||
TEST_MAKE_UNSAFE = [
|
||||
(
|
||||
_make_trusted('text'),
|
||||
_make_trusted("text"),
|
||||
[],
|
||||
[
|
||||
(),
|
||||
],
|
||||
),
|
||||
(
|
||||
_make_trusted('{{text}}'),
|
||||
_make_trusted("{{text}}"),
|
||||
[
|
||||
(),
|
||||
],
|
||||
@@ -37,59 +40,63 @@ TEST_MAKE_UNSAFE = [
|
||||
),
|
||||
(
|
||||
{
|
||||
_make_trusted('skey'): _make_trusted('value'),
|
||||
_make_trusted('ukey'): _make_trusted('{{value}}'),
|
||||
_make_trusted("skey"): _make_trusted("value"),
|
||||
_make_trusted("ukey"): _make_trusted("{{value}}"),
|
||||
1: [
|
||||
_make_trusted('value'),
|
||||
_make_trusted('{{value}}'),
|
||||
_make_trusted("value"),
|
||||
_make_trusted("{{value}}"),
|
||||
{
|
||||
1.0: _make_trusted('{{value}}'),
|
||||
2.0: _make_trusted('value'),
|
||||
1.0: _make_trusted("{{value}}"),
|
||||
2.0: _make_trusted("value"),
|
||||
},
|
||||
],
|
||||
},
|
||||
[
|
||||
('ukey', ),
|
||||
("ukey",),
|
||||
(1, 1),
|
||||
(1, 2, 1.0),
|
||||
],
|
||||
[
|
||||
('skey', ),
|
||||
("skey",),
|
||||
(1, 0),
|
||||
(1, 2, 2.0),
|
||||
],
|
||||
),
|
||||
(
|
||||
[_make_trusted('value'), _make_trusted('{{value}}')],
|
||||
[_make_trusted("value"), _make_trusted("{{value}}")],
|
||||
[
|
||||
(1, ),
|
||||
(1,),
|
||||
],
|
||||
[
|
||||
(0, ),
|
||||
(0,),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
if not SUPPORTS_DATA_TAGGING:
|
||||
TEST_MAKE_UNSAFE.extend([
|
||||
(
|
||||
_make_trusted(b"text"),
|
||||
[],
|
||||
[
|
||||
(),
|
||||
],
|
||||
),
|
||||
(
|
||||
_make_trusted(b"{{text}}"),
|
||||
[
|
||||
(),
|
||||
],
|
||||
[],
|
||||
),
|
||||
])
|
||||
TEST_MAKE_UNSAFE.extend(
|
||||
[
|
||||
(
|
||||
_make_trusted(b"text"),
|
||||
[],
|
||||
[
|
||||
(),
|
||||
],
|
||||
),
|
||||
(
|
||||
_make_trusted(b"{{text}}"),
|
||||
[
|
||||
(),
|
||||
],
|
||||
[],
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value, check_unsafe_paths, check_safe_paths", TEST_MAKE_UNSAFE)
|
||||
@pytest.mark.parametrize(
|
||||
"value, check_unsafe_paths, check_safe_paths", TEST_MAKE_UNSAFE
|
||||
)
|
||||
def test_make_unsafe(value, check_unsafe_paths, check_safe_paths):
|
||||
unsafe_value = make_unsafe(value)
|
||||
assert unsafe_value == value
|
||||
@@ -108,16 +115,16 @@ def test_make_unsafe(value, check_unsafe_paths, check_safe_paths):
|
||||
def test_make_unsafe_idempotence():
|
||||
assert make_unsafe(None) is None
|
||||
|
||||
unsafe_str = _make_untrusted('{{test}}')
|
||||
unsafe_str = _make_untrusted("{{test}}")
|
||||
assert id(make_unsafe(unsafe_str)) == id(unsafe_str)
|
||||
|
||||
safe_str = _make_trusted('{{test}}')
|
||||
safe_str = _make_trusted("{{test}}")
|
||||
assert id(make_unsafe(safe_str)) != id(safe_str)
|
||||
|
||||
|
||||
def test_make_unsafe_dict_key():
|
||||
value = {
|
||||
_make_trusted('test'): 2,
|
||||
_make_trusted("test"): 2,
|
||||
}
|
||||
if not SUPPORTS_DATA_TAGGING:
|
||||
value[_make_trusted(b"test")] = 1
|
||||
@@ -127,7 +134,7 @@ def test_make_unsafe_dict_key():
|
||||
assert _is_trusted(obj)
|
||||
|
||||
value = {
|
||||
_make_trusted('{{test}}'): 2,
|
||||
_make_trusted("{{test}}"): 2,
|
||||
}
|
||||
if not SUPPORTS_DATA_TAGGING:
|
||||
value[_make_trusted(b"{{test}}")] = 1
|
||||
@@ -138,7 +145,7 @@ def test_make_unsafe_dict_key():
|
||||
|
||||
|
||||
def test_make_unsafe_set():
|
||||
value = set([_make_trusted('test')])
|
||||
value = set([_make_trusted("test")])
|
||||
if not SUPPORTS_DATA_TAGGING:
|
||||
value.add(_make_trusted(b"test"))
|
||||
unsafe_value = make_unsafe(value)
|
||||
@@ -146,7 +153,7 @@ def test_make_unsafe_set():
|
||||
for obj in unsafe_value:
|
||||
assert _is_trusted(obj)
|
||||
|
||||
value = set([_make_trusted('{{test}}')])
|
||||
value = set([_make_trusted("{{test}}")])
|
||||
if not SUPPORTS_DATA_TAGGING:
|
||||
value.add(_make_trusted(b"{{test}}"))
|
||||
unsafe_value = make_unsafe(value)
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import json
|
||||
@@ -11,7 +13,7 @@ from tempfile import TemporaryFile
|
||||
|
||||
|
||||
def write_imitation_archive(file_name, image_id, repo_tags):
|
||||
'''
|
||||
"""
|
||||
Write a tar file meeting these requirements:
|
||||
|
||||
* Has a file manifest.json
|
||||
@@ -24,24 +26,19 @@ def write_imitation_archive(file_name, image_id, repo_tags):
|
||||
:type image_id: str
|
||||
:param repo_tags: list of fake image:tag's
|
||||
:type repo_tags: list
|
||||
'''
|
||||
"""
|
||||
|
||||
manifest = [
|
||||
{
|
||||
'Config': f'{image_id}.json',
|
||||
'RepoTags': repo_tags
|
||||
}
|
||||
]
|
||||
manifest = [{"Config": f"{image_id}.json", "RepoTags": repo_tags}]
|
||||
|
||||
write_imitation_archive_with_manifest(file_name, manifest)
|
||||
|
||||
|
||||
def write_imitation_archive_with_manifest(file_name, manifest):
|
||||
with tarfile.open(file_name, 'w') as tf:
|
||||
with tarfile.open(file_name, "w") as tf:
|
||||
with TemporaryFile() as f:
|
||||
f.write(json.dumps(manifest).encode('utf-8'))
|
||||
f.write(json.dumps(manifest).encode("utf-8"))
|
||||
|
||||
ti = tarfile.TarInfo('manifest.json')
|
||||
ti = tarfile.TarInfo("manifest.json")
|
||||
ti.size = f.tell()
|
||||
|
||||
f.seek(0)
|
||||
@@ -49,19 +46,19 @@ def write_imitation_archive_with_manifest(file_name, manifest):
|
||||
|
||||
|
||||
def write_irrelevant_tar(file_name):
|
||||
'''
|
||||
"""
|
||||
Create a tar file that does not match the spec for "docker image save" / "docker image load" commands.
|
||||
|
||||
:param file_name: Name of tar file to create
|
||||
:type file_name: str
|
||||
'''
|
||||
"""
|
||||
|
||||
tf = tarfile.open(file_name, 'w')
|
||||
tf = tarfile.open(file_name, "w")
|
||||
try:
|
||||
with TemporaryFile() as f:
|
||||
f.write('Hello, world.'.encode('utf-8'))
|
||||
f.write("Hello, world.".encode("utf-8"))
|
||||
|
||||
ti = tarfile.TarInfo('hi.txt')
|
||||
ti = tarfile.TarInfo("hi.txt")
|
||||
ti.size = f.tell()
|
||||
|
||||
f.seek(0)
|
||||
|
||||
Reference in New Issue
Block a user