mirror of
https://github.com/ansible-collections/community.docker.git
synced 2026-07-29 11:55:04 +00:00
Add typing information, 2/n (#1178)
* Add typing to Docker Stack modules. Clean modules up. * Add typing to Docker Swarm modules. * Add typing to unit tests. * Add more typing. * Add ignore.txt entries.
This commit is contained in:
@@ -14,6 +14,7 @@ import shutil
|
||||
import socket
|
||||
import tarfile
|
||||
import tempfile
|
||||
import typing as t
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
@@ -27,7 +28,11 @@ from ansible_collections.community.docker.plugins.module_utils._api.utils.build
|
||||
)
|
||||
|
||||
|
||||
def make_tree(dirs, files):
|
||||
if t.TYPE_CHECKING:
|
||||
from collections.abc import Collection
|
||||
|
||||
|
||||
def make_tree(dirs: list[str], files: list[str]) -> str:
|
||||
base = tempfile.mkdtemp()
|
||||
|
||||
for path in dirs:
|
||||
@@ -40,11 +45,11 @@ def make_tree(dirs, files):
|
||||
return base
|
||||
|
||||
|
||||
def convert_paths(collection):
|
||||
def convert_paths(collection: Collection[str]) -> set[str]:
|
||||
return set(map(convert_path, collection))
|
||||
|
||||
|
||||
def convert_path(path):
|
||||
def convert_path(path: str) -> str:
|
||||
return path.replace("/", os.path.sep)
|
||||
|
||||
|
||||
@@ -88,26 +93,26 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
|
||||
all_paths = set(dirs + files)
|
||||
|
||||
def setUp(self):
|
||||
def setUp(self) -> None:
|
||||
self.base = make_tree(self.dirs, self.files)
|
||||
|
||||
def tearDown(self):
|
||||
def tearDown(self) -> None:
|
||||
shutil.rmtree(self.base)
|
||||
|
||||
def exclude(self, patterns, dockerfile=None):
|
||||
def exclude(self, patterns: list[str], dockerfile: str | None = None) -> set[str]:
|
||||
return set(exclude_paths(self.base, patterns, dockerfile=dockerfile))
|
||||
|
||||
def test_no_excludes(self):
|
||||
def test_no_excludes(self) -> None:
|
||||
assert self.exclude([""]) == convert_paths(self.all_paths)
|
||||
|
||||
def test_no_dupes(self):
|
||||
def test_no_dupes(self) -> None:
|
||||
paths = exclude_paths(self.base, ["!a.py"])
|
||||
assert sorted(paths) == sorted(set(paths))
|
||||
|
||||
def test_wildcard_exclude(self):
|
||||
def test_wildcard_exclude(self) -> None:
|
||||
assert self.exclude(["*"]) == set(["Dockerfile", ".dockerignore"])
|
||||
|
||||
def test_exclude_dockerfile_dockerignore(self):
|
||||
def test_exclude_dockerfile_dockerignore(self) -> None:
|
||||
"""
|
||||
Even if the .dockerignore file explicitly says to exclude
|
||||
Dockerfile and/or .dockerignore, don't exclude them from
|
||||
@@ -117,7 +122,7 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
self.all_paths
|
||||
)
|
||||
|
||||
def test_exclude_custom_dockerfile(self):
|
||||
def test_exclude_custom_dockerfile(self) -> None:
|
||||
"""
|
||||
If we're using a custom Dockerfile, make sure that's not
|
||||
excluded.
|
||||
@@ -135,33 +140,33 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
set(["foo/Dockerfile3", ".dockerignore"])
|
||||
)
|
||||
|
||||
def test_exclude_dockerfile_child(self):
|
||||
def test_exclude_dockerfile_child(self) -> None:
|
||||
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):
|
||||
def test_single_filename(self) -> None:
|
||||
assert self.exclude(["a.py"]) == convert_paths(self.all_paths - set(["a.py"]))
|
||||
|
||||
def test_single_filename_leading_dot_slash(self):
|
||||
def test_single_filename_leading_dot_slash(self) -> None:
|
||||
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):
|
||||
def test_single_filename_trailing_slash(self) -> None:
|
||||
assert self.exclude(["a.py/"]) == convert_paths(self.all_paths - set(["a.py"]))
|
||||
|
||||
def test_wildcard_filename_start(self):
|
||||
def test_wildcard_filename_start(self) -> None:
|
||||
assert self.exclude(["*.py"]) == convert_paths(
|
||||
self.all_paths - set(["a.py", "b.py", "cde.py"])
|
||||
)
|
||||
|
||||
def test_wildcard_with_exception(self):
|
||||
def test_wildcard_with_exception(self) -> None:
|
||||
assert self.exclude(["*.py", "!b.py"]) == convert_paths(
|
||||
self.all_paths - set(["a.py", "cde.py"])
|
||||
)
|
||||
|
||||
def test_wildcard_with_wildcard_exception(self):
|
||||
def test_wildcard_with_wildcard_exception(self) -> None:
|
||||
assert self.exclude(["*.*", "!*.go"]) == convert_paths(
|
||||
self.all_paths
|
||||
- set(
|
||||
@@ -174,51 +179,51 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
def test_wildcard_filename_end(self):
|
||||
def test_wildcard_filename_end(self) -> None:
|
||||
assert self.exclude(["a.*"]) == convert_paths(
|
||||
self.all_paths - set(["a.py", "a.go"])
|
||||
)
|
||||
|
||||
def test_question_mark(self):
|
||||
def test_question_mark(self) -> None:
|
||||
assert self.exclude(["?.py"]) == convert_paths(
|
||||
self.all_paths - set(["a.py", "b.py"])
|
||||
)
|
||||
|
||||
def test_single_subdir_single_filename(self):
|
||||
def test_single_subdir_single_filename(self) -> None:
|
||||
assert self.exclude(["foo/a.py"]) == convert_paths(
|
||||
self.all_paths - set(["foo/a.py"])
|
||||
)
|
||||
|
||||
def test_single_subdir_single_filename_leading_slash(self):
|
||||
def test_single_subdir_single_filename_leading_slash(self) -> None:
|
||||
assert self.exclude(["/foo/a.py"]) == convert_paths(
|
||||
self.all_paths - set(["foo/a.py"])
|
||||
)
|
||||
|
||||
def test_exclude_include_absolute_path(self):
|
||||
def test_exclude_include_absolute_path(self) -> None:
|
||||
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):
|
||||
def test_single_subdir_with_path_traversal(self) -> None:
|
||||
assert self.exclude(["foo/whoops/../a.py"]) == convert_paths(
|
||||
self.all_paths - set(["foo/a.py"])
|
||||
)
|
||||
|
||||
def test_single_subdir_wildcard_filename(self):
|
||||
def test_single_subdir_wildcard_filename(self) -> None:
|
||||
assert self.exclude(["foo/*.py"]) == convert_paths(
|
||||
self.all_paths - set(["foo/a.py", "foo/b.py"])
|
||||
)
|
||||
|
||||
def test_wildcard_subdir_single_filename(self):
|
||||
def test_wildcard_subdir_single_filename(self) -> None:
|
||||
assert self.exclude(["*/a.py"]) == convert_paths(
|
||||
self.all_paths - set(["foo/a.py", "bar/a.py"])
|
||||
)
|
||||
|
||||
def test_wildcard_subdir_wildcard_filename(self):
|
||||
def test_wildcard_subdir_wildcard_filename(self) -> None:
|
||||
assert self.exclude(["*/*.py"]) == convert_paths(
|
||||
self.all_paths - set(["foo/a.py", "foo/b.py", "bar/a.py"])
|
||||
)
|
||||
|
||||
def test_directory(self):
|
||||
def test_directory(self) -> None:
|
||||
assert self.exclude(["foo"]) == convert_paths(
|
||||
self.all_paths
|
||||
- set(
|
||||
@@ -233,7 +238,7 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
def test_directory_with_trailing_slash(self):
|
||||
def test_directory_with_trailing_slash(self) -> None:
|
||||
assert self.exclude(["foo"]) == convert_paths(
|
||||
self.all_paths
|
||||
- set(
|
||||
@@ -248,13 +253,13 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
def test_directory_with_single_exception(self):
|
||||
def test_directory_with_single_exception(self) -> None:
|
||||
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):
|
||||
def test_directory_with_subdir_exception(self) -> None:
|
||||
assert self.exclude(["foo", "!foo/bar"]) == convert_paths(
|
||||
self.all_paths - set(["foo/a.py", "foo/b.py", "foo", "foo/Dockerfile3"])
|
||||
)
|
||||
@@ -262,17 +267,17 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
@pytest.mark.skipif(
|
||||
not IS_WINDOWS_PLATFORM, reason="Backslash patterns only on Windows"
|
||||
)
|
||||
def test_directory_with_subdir_exception_win32_pathsep(self):
|
||||
def test_directory_with_subdir_exception_win32_pathsep(self) -> None:
|
||||
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):
|
||||
def test_directory_with_wildcard_exception(self) -> None:
|
||||
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):
|
||||
def test_subdirectory(self) -> None:
|
||||
assert self.exclude(["foo/bar"]) == convert_paths(
|
||||
self.all_paths - set(["foo/bar", "foo/bar/a.py"])
|
||||
)
|
||||
@@ -280,12 +285,12 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
@pytest.mark.skipif(
|
||||
not IS_WINDOWS_PLATFORM, reason="Backslash patterns only on Windows"
|
||||
)
|
||||
def test_subdirectory_win32_pathsep(self):
|
||||
def test_subdirectory_win32_pathsep(self) -> None:
|
||||
assert self.exclude(["foo\\bar"]) == convert_paths(
|
||||
self.all_paths - set(["foo/bar", "foo/bar/a.py"])
|
||||
)
|
||||
|
||||
def test_double_wildcard(self):
|
||||
def test_double_wildcard(self) -> None:
|
||||
assert self.exclude(["**/a.py"]) == convert_paths(
|
||||
self.all_paths - set(["a.py", "foo/a.py", "foo/bar/a.py", "bar/a.py"])
|
||||
)
|
||||
@@ -294,7 +299,7 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
self.all_paths - set(["foo/bar", "foo/bar/a.py"])
|
||||
)
|
||||
|
||||
def test_single_and_double_wildcard(self):
|
||||
def test_single_and_double_wildcard(self) -> None:
|
||||
assert self.exclude(["**/target/*/*"]) == convert_paths(
|
||||
self.all_paths
|
||||
- set(
|
||||
@@ -306,7 +311,7 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
def test_trailing_double_wildcard(self):
|
||||
def test_trailing_double_wildcard(self) -> None:
|
||||
assert self.exclude(["subdir/**"]) == convert_paths(
|
||||
self.all_paths
|
||||
- set(
|
||||
@@ -326,7 +331,7 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
def test_double_wildcard_with_exception(self):
|
||||
def test_double_wildcard_with_exception(self) -> None:
|
||||
assert self.exclude(["**", "!bar", "!foo/bar"]) == convert_paths(
|
||||
set(
|
||||
[
|
||||
@@ -340,13 +345,13 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
def test_include_wildcard(self):
|
||||
def test_include_wildcard(self) -> None:
|
||||
# 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()
|
||||
|
||||
def test_last_line_precedence(self):
|
||||
def test_last_line_precedence(self) -> None:
|
||||
base = make_tree(
|
||||
[],
|
||||
[
|
||||
@@ -361,7 +366,7 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
["README.md", "README-bis.md"]
|
||||
)
|
||||
|
||||
def test_parent_directory(self):
|
||||
def test_parent_directory(self) -> None:
|
||||
base = make_tree([], ["a.py", "b.py", "c.py"])
|
||||
# Dockerignore reference stipulates that absolute paths are
|
||||
# equivalent to relative paths, hence /../foo should be
|
||||
@@ -372,7 +377,7 @@ class ExcludePathsTest(unittest.TestCase):
|
||||
|
||||
|
||||
class TarTest(unittest.TestCase):
|
||||
def test_tar_with_excludes(self):
|
||||
def test_tar_with_excludes(self) -> None:
|
||||
dirs = [
|
||||
"foo",
|
||||
"foo/bar",
|
||||
@@ -420,7 +425,7 @@ class TarTest(unittest.TestCase):
|
||||
with tarfile.open(fileobj=archive) as tar_data:
|
||||
assert sorted(tar_data.getnames()) == sorted(expected_names)
|
||||
|
||||
def test_tar_with_empty_directory(self):
|
||||
def test_tar_with_empty_directory(self) -> None:
|
||||
base = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
for d in ["foo", "bar"]:
|
||||
@@ -433,7 +438,7 @@ class TarTest(unittest.TestCase):
|
||||
IS_WINDOWS_PLATFORM or os.geteuid() == 0,
|
||||
reason="root user always has access ; no chmod on Windows",
|
||||
)
|
||||
def test_tar_with_inaccessible_file(self):
|
||||
def test_tar_with_inaccessible_file(self) -> None:
|
||||
base = tempfile.mkdtemp()
|
||||
full_path = os.path.join(base, "foo")
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
@@ -446,7 +451,7 @@ class TarTest(unittest.TestCase):
|
||||
assert f"Can not read file in context: {full_path}" in ei.exconly()
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
||||
def test_tar_with_file_symlinks(self):
|
||||
def test_tar_with_file_symlinks(self) -> None:
|
||||
base = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
with open(os.path.join(base, "foo"), "wt", encoding="utf-8") as f:
|
||||
@@ -458,7 +463,7 @@ class TarTest(unittest.TestCase):
|
||||
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
||||
def test_tar_with_directory_symlinks(self):
|
||||
def test_tar_with_directory_symlinks(self) -> None:
|
||||
base = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
for d in ["foo", "bar"]:
|
||||
@@ -469,7 +474,7 @@ class TarTest(unittest.TestCase):
|
||||
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
||||
def test_tar_with_broken_symlinks(self):
|
||||
def test_tar_with_broken_symlinks(self) -> None:
|
||||
base = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
for d in ["foo", "bar"]:
|
||||
@@ -481,7 +486,7 @@ class TarTest(unittest.TestCase):
|
||||
assert sorted(tar_data.getnames()) == ["bar", "bar/foo", "foo"]
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No UNIX sockets on Win32")
|
||||
def test_tar_socket_file(self):
|
||||
def test_tar_socket_file(self) -> None:
|
||||
base = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
for d in ["foo", "bar"]:
|
||||
@@ -493,7 +498,7 @@ class TarTest(unittest.TestCase):
|
||||
with tarfile.open(fileobj=archive) as tar_data:
|
||||
assert sorted(tar_data.getnames()) == ["bar", "foo"]
|
||||
|
||||
def tar_test_negative_mtime_bug(self):
|
||||
def tar_test_negative_mtime_bug(self) -> None:
|
||||
base = tempfile.mkdtemp()
|
||||
filename = os.path.join(base, "th.txt")
|
||||
self.addCleanup(shutil.rmtree, base)
|
||||
@@ -506,7 +511,7 @@ class TarTest(unittest.TestCase):
|
||||
assert tar_data.getmember("th.txt").mtime == -3600
|
||||
|
||||
@pytest.mark.skipif(IS_WINDOWS_PLATFORM, reason="No symlinks on Windows")
|
||||
def test_tar_directory_link(self):
|
||||
def test_tar_directory_link(self) -> None:
|
||||
dirs = ["a", "b", "a/c"]
|
||||
files = ["a/hello.py", "b/utils.py", "a/c/descend.py"]
|
||||
base = make_tree(dirs, files)
|
||||
|
||||
@@ -12,6 +12,7 @@ import json
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import typing as t
|
||||
import unittest
|
||||
from collections.abc import Callable
|
||||
from unittest import mock
|
||||
@@ -25,55 +26,55 @@ class FindConfigFileTest(unittest.TestCase):
|
||||
mkdir: Callable[[str], os.PathLike[str]]
|
||||
|
||||
@fixture(autouse=True)
|
||||
def tmpdir(self, tmpdir):
|
||||
def tmpdir(self, tmpdir: t.Any) -> None:
|
||||
self.mkdir = tmpdir.mkdir
|
||||
|
||||
def test_find_config_fallback(self):
|
||||
def test_find_config_fallback(self) -> None:
|
||||
tmpdir = self.mkdir("test_find_config_fallback")
|
||||
|
||||
with mock.patch.dict(os.environ, {"HOME": str(tmpdir)}):
|
||||
assert config.find_config_file() is None
|
||||
|
||||
def test_find_config_from_explicit_path(self):
|
||||
def test_find_config_from_explicit_path(self) -> None:
|
||||
tmpdir = self.mkdir("test_find_config_from_explicit_path")
|
||||
config_path = tmpdir.ensure("my-config-file.json")
|
||||
config_path = tmpdir.ensure("my-config-file.json") # type: ignore[attr-defined]
|
||||
|
||||
assert config.find_config_file(str(config_path)) == str(config_path)
|
||||
|
||||
def test_find_config_from_environment(self):
|
||||
def test_find_config_from_environment(self) -> None:
|
||||
tmpdir = self.mkdir("test_find_config_from_environment")
|
||||
config_path = tmpdir.ensure("config.json")
|
||||
config_path = tmpdir.ensure("config.json") # type: ignore[attr-defined]
|
||||
|
||||
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):
|
||||
def test_find_config_from_home_posix(self) -> None:
|
||||
tmpdir = self.mkdir("test_find_config_from_home_posix")
|
||||
config_path = tmpdir.ensure(".docker", "config.json")
|
||||
config_path = tmpdir.ensure(".docker", "config.json") # type: ignore[attr-defined]
|
||||
|
||||
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):
|
||||
def test_find_config_from_home_legacy_name(self) -> None:
|
||||
tmpdir = self.mkdir("test_find_config_from_home_legacy_name")
|
||||
config_path = tmpdir.ensure(".dockercfg")
|
||||
config_path = tmpdir.ensure(".dockercfg") # type: ignore[attr-defined]
|
||||
|
||||
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):
|
||||
def test_find_config_from_home_windows(self) -> None:
|
||||
tmpdir = self.mkdir("test_find_config_from_home_windows")
|
||||
config_path = tmpdir.ensure(".docker", "config.json")
|
||||
config_path = tmpdir.ensure(".docker", "config.json") # type: ignore[attr-defined]
|
||||
|
||||
with mock.patch.dict(os.environ, {"USERPROFILE": str(tmpdir)}):
|
||||
assert config.find_config_file() == str(config_path)
|
||||
|
||||
|
||||
class LoadConfigTest(unittest.TestCase):
|
||||
def test_load_config_no_file(self):
|
||||
def test_load_config_no_file(self) -> None:
|
||||
folder = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, folder)
|
||||
cfg = config.load_general_config(folder)
|
||||
@@ -81,7 +82,7 @@ class LoadConfigTest(unittest.TestCase):
|
||||
assert isinstance(cfg, dict)
|
||||
assert not cfg
|
||||
|
||||
def test_load_config_custom_headers(self):
|
||||
def test_load_config_custom_headers(self) -> None:
|
||||
folder = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, folder)
|
||||
|
||||
@@ -97,7 +98,7 @@ class LoadConfigTest(unittest.TestCase):
|
||||
assert "HttpHeaders" in cfg
|
||||
assert cfg["HttpHeaders"] == {"Name": "Spike", "Surname": "Spiegel"}
|
||||
|
||||
def test_load_config_detach_keys(self):
|
||||
def test_load_config_detach_keys(self) -> None:
|
||||
folder = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, folder)
|
||||
dockercfg_path = os.path.join(folder, "config.json")
|
||||
@@ -108,7 +109,7 @@ class LoadConfigTest(unittest.TestCase):
|
||||
cfg = config.load_general_config(dockercfg_path)
|
||||
assert cfg == config_data
|
||||
|
||||
def test_load_config_from_env(self):
|
||||
def test_load_config_from_env(self) -> None:
|
||||
folder = tempfile.mkdtemp()
|
||||
self.addCleanup(shutil.rmtree, folder)
|
||||
dockercfg_path = os.path.join(folder, "config.json")
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
import unittest
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.api.client import (
|
||||
@@ -22,12 +23,12 @@ from ansible_collections.community.docker.tests.unit.plugins.module_utils._api.c
|
||||
|
||||
|
||||
class DecoratorsTest(unittest.TestCase):
|
||||
def test_update_headers(self):
|
||||
def test_update_headers(self) -> None:
|
||||
sample_headers = {
|
||||
"X-Docker-Locale": "en-US",
|
||||
}
|
||||
|
||||
def f(self, headers=None):
|
||||
def f(self: t.Any, headers: t.Any = None) -> t.Any:
|
||||
return headers
|
||||
|
||||
client = APIClient(version=DEFAULT_DOCKER_API_VERSION)
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
|
||||
from ansible_collections.community.docker.plugins.module_utils._api.utils.json_stream import (
|
||||
json_splitter,
|
||||
json_stream,
|
||||
@@ -15,41 +17,48 @@ from ansible_collections.community.docker.plugins.module_utils._api.utils.json_s
|
||||
)
|
||||
|
||||
|
||||
class TestJsonSplitter:
|
||||
if t.TYPE_CHECKING:
|
||||
T = t.TypeVar("T")
|
||||
|
||||
def test_json_splitter_no_object(self):
|
||||
|
||||
def create_generator(input_sequence: list[T]) -> t.Generator[T]:
|
||||
yield from input_sequence
|
||||
|
||||
|
||||
class TestJsonSplitter:
|
||||
def test_json_splitter_no_object(self) -> None:
|
||||
data = '{"foo": "bar'
|
||||
assert json_splitter(data) is None
|
||||
|
||||
def test_json_splitter_with_object(self):
|
||||
def test_json_splitter_with_object(self) -> None:
|
||||
data = '{"foo": "bar"}\n \n{"next": "obj"}'
|
||||
assert json_splitter(data) == ({"foo": "bar"}, '{"next": "obj"}')
|
||||
|
||||
def test_json_splitter_leading_whitespace(self):
|
||||
def test_json_splitter_leading_whitespace(self) -> None:
|
||||
data = '\n \r{"foo": "bar"}\n\n {"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"]
|
||||
def test_stream_with_non_utf_unicode_character(self) -> None:
|
||||
stream = create_generator([b"\xed\xf3\xf3"])
|
||||
(output,) = stream_as_text(stream)
|
||||
assert output == "���"
|
||||
|
||||
def test_stream_with_utf_character(self):
|
||||
stream = ["ěĝ".encode("utf-8")]
|
||||
def test_stream_with_utf_character(self) -> None:
|
||||
stream = create_generator(["ěĝ".encode("utf-8")])
|
||||
(output,) = stream_as_text(stream)
|
||||
assert output == "ěĝ"
|
||||
|
||||
|
||||
class TestJsonStream:
|
||||
|
||||
def test_with_falsy_entries(self):
|
||||
stream = [
|
||||
'{"one": "two"}\n{}\n',
|
||||
"[1, 2, 3]\n[]\n",
|
||||
]
|
||||
def test_with_falsy_entries(self) -> None:
|
||||
stream = create_generator(
|
||||
[
|
||||
'{"one": "two"}\n{}\n',
|
||||
"[1, 2, 3]\n[]\n",
|
||||
]
|
||||
)
|
||||
output = list(json_stream(stream))
|
||||
assert output == [
|
||||
{"one": "two"},
|
||||
@@ -58,7 +67,9 @@ class TestJsonStream:
|
||||
[],
|
||||
]
|
||||
|
||||
def test_with_leading_whitespace(self):
|
||||
stream = ['\n \r\n {"one": "two"}{"x": 1}', ' {"three": "four"}\t\t{"x": 2}']
|
||||
def test_with_leading_whitespace(self) -> None:
|
||||
stream = create_generator(
|
||||
['\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}]
|
||||
|
||||
@@ -19,132 +19,132 @@ from ansible_collections.community.docker.plugins.module_utils._api.utils.ports
|
||||
|
||||
|
||||
class PortsTest(unittest.TestCase):
|
||||
def test_split_port_with_host_ip(self):
|
||||
def test_split_port_with_host_ip(self) -> None:
|
||||
internal_port, external_port = split_port("127.0.0.1:1000:2000")
|
||||
assert internal_port == ["2000"]
|
||||
assert external_port == [("127.0.0.1", "1000")]
|
||||
|
||||
def test_split_port_with_protocol(self):
|
||||
def test_split_port_with_protocol(self) -> None:
|
||||
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")]
|
||||
|
||||
def test_split_port_with_host_ip_no_port(self):
|
||||
def test_split_port_with_host_ip_no_port(self) -> None:
|
||||
internal_port, external_port = split_port("127.0.0.1::2000")
|
||||
assert internal_port == ["2000"]
|
||||
assert external_port == [("127.0.0.1", None)]
|
||||
|
||||
def test_split_port_range_with_host_ip_no_port(self):
|
||||
def test_split_port_range_with_host_ip_no_port(self) -> None:
|
||||
internal_port, external_port = split_port("127.0.0.1::2000-2001")
|
||||
assert internal_port == ["2000", "2001"]
|
||||
assert external_port == [("127.0.0.1", None), ("127.0.0.1", None)]
|
||||
|
||||
def test_split_port_with_host_port(self):
|
||||
def test_split_port_with_host_port(self) -> None:
|
||||
internal_port, external_port = split_port("1000:2000")
|
||||
assert internal_port == ["2000"]
|
||||
assert external_port == ["1000"]
|
||||
|
||||
def test_split_port_range_with_host_port(self):
|
||||
def test_split_port_range_with_host_port(self) -> None:
|
||||
internal_port, external_port = split_port("1000-1001:2000-2001")
|
||||
assert internal_port == ["2000", "2001"]
|
||||
assert external_port == ["1000", "1001"]
|
||||
|
||||
def test_split_port_random_port_range_with_host_port(self):
|
||||
def test_split_port_random_port_range_with_host_port(self) -> None:
|
||||
internal_port, external_port = split_port("1000-1001:2000")
|
||||
assert internal_port == ["2000"]
|
||||
assert external_port == ["1000-1001"]
|
||||
|
||||
def test_split_port_no_host_port(self):
|
||||
def test_split_port_no_host_port(self) -> None:
|
||||
internal_port, external_port = split_port("2000")
|
||||
assert internal_port == ["2000"]
|
||||
assert external_port is None
|
||||
|
||||
def test_split_port_range_no_host_port(self):
|
||||
def test_split_port_range_no_host_port(self) -> None:
|
||||
internal_port, external_port = split_port("2000-2001")
|
||||
assert internal_port == ["2000", "2001"]
|
||||
assert external_port is None
|
||||
|
||||
def test_split_port_range_with_protocol(self):
|
||||
def test_split_port_range_with_protocol(self) -> None:
|
||||
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):
|
||||
def test_split_port_with_ipv6_address(self) -> None:
|
||||
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):
|
||||
def test_split_port_with_ipv6_square_brackets_address(self) -> None:
|
||||
internal_port, external_port = split_port("[2001:abcd:ef00::2]:1000:2000")
|
||||
assert internal_port == ["2000"]
|
||||
assert external_port == [("2001:abcd:ef00::2", "1000")]
|
||||
|
||||
def test_split_port_invalid(self):
|
||||
def test_split_port_invalid(self) -> None:
|
||||
with pytest.raises(ValueError):
|
||||
split_port("0.0.0.0:1000:2000:tcp")
|
||||
|
||||
def test_split_port_invalid_protocol(self):
|
||||
def test_split_port_invalid_protocol(self) -> None:
|
||||
with pytest.raises(ValueError):
|
||||
split_port("0.0.0.0:1000:2000/ftp")
|
||||
|
||||
def test_non_matching_length_port_ranges(self):
|
||||
def test_non_matching_length_port_ranges(self) -> None:
|
||||
with pytest.raises(ValueError):
|
||||
split_port("0.0.0.0:1000-1010:2000-2002/tcp")
|
||||
|
||||
def test_port_and_range_invalid(self):
|
||||
def test_port_and_range_invalid(self) -> None:
|
||||
with pytest.raises(ValueError):
|
||||
split_port("0.0.0.0:1000:2000-2002/tcp")
|
||||
|
||||
def test_port_only_with_colon(self):
|
||||
def test_port_only_with_colon(self) -> None:
|
||||
with pytest.raises(ValueError):
|
||||
split_port(":80")
|
||||
|
||||
def test_host_only_with_colon(self):
|
||||
def test_host_only_with_colon(self) -> None:
|
||||
with pytest.raises(ValueError):
|
||||
split_port("localhost:")
|
||||
|
||||
def test_with_no_container_port(self):
|
||||
def test_with_no_container_port(self) -> None:
|
||||
with pytest.raises(ValueError):
|
||||
split_port("localhost:80:")
|
||||
|
||||
def test_split_port_empty_string(self):
|
||||
def test_split_port_empty_string(self) -> None:
|
||||
with pytest.raises(ValueError):
|
||||
split_port("")
|
||||
|
||||
def test_split_port_non_string(self):
|
||||
def test_split_port_non_string(self) -> None:
|
||||
assert split_port(1243) == (["1243"], None)
|
||||
|
||||
def test_build_port_bindings_with_one_port(self):
|
||||
def test_build_port_bindings_with_one_port(self) -> None:
|
||||
port_bindings = build_port_bindings(["127.0.0.1:1000:1000"])
|
||||
assert port_bindings["1000"] == [("127.0.0.1", "1000")]
|
||||
|
||||
def test_build_port_bindings_with_matching_internal_ports(self):
|
||||
def test_build_port_bindings_with_matching_internal_ports(self) -> None:
|
||||
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")]
|
||||
|
||||
def test_build_port_bindings_with_nonmatching_internal_ports(self):
|
||||
def test_build_port_bindings_with_nonmatching_internal_ports(self) -> None:
|
||||
port_bindings = build_port_bindings(
|
||||
["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")]
|
||||
|
||||
def test_build_port_bindings_with_port_range(self):
|
||||
def test_build_port_bindings_with_port_range(self) -> None:
|
||||
port_bindings = build_port_bindings(["127.0.0.1:1000-1001:1000-1001"])
|
||||
assert port_bindings["1000"] == [("127.0.0.1", "1000")]
|
||||
assert port_bindings["1001"] == [("127.0.0.1", "1001")]
|
||||
|
||||
def test_build_port_bindings_with_matching_internal_port_ranges(self):
|
||||
def test_build_port_bindings_with_matching_internal_port_ranges(self) -> None:
|
||||
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")]
|
||||
|
||||
def test_build_port_bindings_with_nonmatching_internal_port_ranges(self):
|
||||
def test_build_port_bindings_with_nonmatching_internal_port_ranges(self) -> None:
|
||||
port_bindings = build_port_bindings(
|
||||
["127.0.0.1:1000:1000", "127.0.0.1:2000:2000"]
|
||||
)
|
||||
|
||||
@@ -33,8 +33,7 @@ ENV = {
|
||||
|
||||
|
||||
class ProxyConfigTest(unittest.TestCase):
|
||||
|
||||
def test_from_dict(self):
|
||||
def test_from_dict(self) -> None:
|
||||
config = ProxyConfig.from_dict(
|
||||
{
|
||||
"httpProxy": HTTP,
|
||||
@@ -48,7 +47,7 @@ class ProxyConfigTest(unittest.TestCase):
|
||||
self.assertEqual(CONFIG.ftp, config.ftp)
|
||||
self.assertEqual(CONFIG.no_proxy, config.no_proxy)
|
||||
|
||||
def test_new(self):
|
||||
def test_new(self) -> None:
|
||||
config = ProxyConfig()
|
||||
self.assertIsNone(config.http)
|
||||
self.assertIsNone(config.https)
|
||||
@@ -61,22 +60,24 @@ class ProxyConfigTest(unittest.TestCase):
|
||||
self.assertEqual(config.ftp, "c")
|
||||
self.assertEqual(config.no_proxy, "d")
|
||||
|
||||
def test_truthiness(self):
|
||||
def test_truthiness(self) -> None:
|
||||
assert not ProxyConfig()
|
||||
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):
|
||||
def test_environment(self) -> None:
|
||||
self.assertDictEqual(CONFIG.get_environment(), ENV)
|
||||
empty = ProxyConfig()
|
||||
self.assertDictEqual(empty.get_environment(), {})
|
||||
|
||||
def test_inject_proxy_environment(self):
|
||||
def test_inject_proxy_environment(self) -> None:
|
||||
# Proxy config is non null, env is None.
|
||||
envlist = CONFIG.inject_proxy_environment(None)
|
||||
assert envlist is not None
|
||||
self.assertSetEqual(
|
||||
set(CONFIG.inject_proxy_environment(None)),
|
||||
set(envlist),
|
||||
set(f"{k}={v}" for k, v in ENV.items()),
|
||||
)
|
||||
|
||||
|
||||
@@ -52,13 +52,15 @@ TEST_CERT_DIR = os.path.join(
|
||||
|
||||
|
||||
class KwargsFromEnvTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
os_environ: dict[str, str]
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.os_environ = os.environ.copy()
|
||||
|
||||
def tearDown(self):
|
||||
os.environ = self.os_environ
|
||||
def tearDown(self) -> None:
|
||||
os.environ = self.os_environ # type: ignore
|
||||
|
||||
def test_kwargs_from_env_empty(self):
|
||||
def test_kwargs_from_env_empty(self) -> None:
|
||||
os.environ.update(DOCKER_HOST="", DOCKER_CERT_PATH="")
|
||||
os.environ.pop("DOCKER_TLS_VERIFY", None)
|
||||
|
||||
@@ -66,7 +68,7 @@ class KwargsFromEnvTest(unittest.TestCase):
|
||||
assert kwargs.get("base_url") is None
|
||||
assert kwargs.get("tls") is None
|
||||
|
||||
def test_kwargs_from_env_tls(self):
|
||||
def test_kwargs_from_env_tls(self) -> None:
|
||||
os.environ.update(
|
||||
DOCKER_HOST="tcp://192.168.59.103:2376",
|
||||
DOCKER_CERT_PATH=TEST_CERT_DIR,
|
||||
@@ -90,7 +92,7 @@ class KwargsFromEnvTest(unittest.TestCase):
|
||||
except TypeError as e:
|
||||
self.fail(e)
|
||||
|
||||
def test_kwargs_from_env_tls_verify_false(self):
|
||||
def test_kwargs_from_env_tls_verify_false(self) -> None:
|
||||
os.environ.update(
|
||||
DOCKER_HOST="tcp://192.168.59.103:2376",
|
||||
DOCKER_CERT_PATH=TEST_CERT_DIR,
|
||||
@@ -113,7 +115,7 @@ class KwargsFromEnvTest(unittest.TestCase):
|
||||
except TypeError as e:
|
||||
self.fail(e)
|
||||
|
||||
def test_kwargs_from_env_tls_verify_false_no_cert(self):
|
||||
def test_kwargs_from_env_tls_verify_false_no_cert(self) -> None:
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
cert_dir = os.path.join(temp_dir, ".docker")
|
||||
shutil.copytree(TEST_CERT_DIR, cert_dir)
|
||||
@@ -125,7 +127,7 @@ class KwargsFromEnvTest(unittest.TestCase):
|
||||
kwargs = kwargs_from_env(assert_hostname=True)
|
||||
assert "tcp://192.168.59.103:2376" == kwargs["base_url"]
|
||||
|
||||
def test_kwargs_from_env_no_cert_path(self):
|
||||
def test_kwargs_from_env_no_cert_path(self) -> None:
|
||||
try:
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
cert_dir = os.path.join(temp_dir, ".docker")
|
||||
@@ -142,7 +144,7 @@ class KwargsFromEnvTest(unittest.TestCase):
|
||||
if temp_dir:
|
||||
shutil.rmtree(temp_dir)
|
||||
|
||||
def test_kwargs_from_env_alternate_env(self):
|
||||
def test_kwargs_from_env_alternate_env(self) -> None:
|
||||
# Values in os.environ are entirely ignored if an alternate is
|
||||
# provided
|
||||
os.environ.update(
|
||||
@@ -160,30 +162,32 @@ class KwargsFromEnvTest(unittest.TestCase):
|
||||
|
||||
|
||||
class ConverVolumeBindsTest(unittest.TestCase):
|
||||
def test_convert_volume_binds_empty(self):
|
||||
def test_convert_volume_binds_empty(self) -> None:
|
||||
assert convert_volume_binds({}) == []
|
||||
assert convert_volume_binds([]) == []
|
||||
|
||||
def test_convert_volume_binds_list(self):
|
||||
def test_convert_volume_binds_list(self) -> None:
|
||||
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"}}
|
||||
def test_convert_volume_binds_complete(self) -> None:
|
||||
data: dict[str | bytes, dict[str, str]] = {
|
||||
"/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"}
|
||||
def test_convert_volume_binds_compact(self) -> None:
|
||||
data: dict[str | bytes, str] = {"/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"}}
|
||||
def test_convert_volume_binds_no_mode(self) -> None:
|
||||
data: dict[str | bytes, dict[str, str]] = {"/mnt/vol1": {"bind": "/data"}}
|
||||
assert convert_volume_binds(data) == ["/mnt/vol1:/data:rw"]
|
||||
|
||||
def test_convert_volume_binds_unicode_bytes_input(self):
|
||||
def test_convert_volume_binds_unicode_bytes_input(self) -> None:
|
||||
expected = ["/mnt/지연:/unicode/박:rw"]
|
||||
|
||||
data = {
|
||||
data: dict[str | bytes, dict[str, str | bytes]] = {
|
||||
"/mnt/지연".encode("utf-8"): {
|
||||
"bind": "/unicode/박".encode("utf-8"),
|
||||
"mode": "rw",
|
||||
@@ -191,15 +195,17 @@ class ConverVolumeBindsTest(unittest.TestCase):
|
||||
}
|
||||
assert convert_volume_binds(data) == expected
|
||||
|
||||
def test_convert_volume_binds_unicode_unicode_input(self):
|
||||
def test_convert_volume_binds_unicode_unicode_input(self) -> None:
|
||||
expected = ["/mnt/지연:/unicode/박:rw"]
|
||||
|
||||
data = {"/mnt/지연": {"bind": "/unicode/박", "mode": "rw"}}
|
||||
data: dict[str | bytes, dict[str, str]] = {
|
||||
"/mnt/지연": {"bind": "/unicode/박", "mode": "rw"}
|
||||
}
|
||||
assert convert_volume_binds(data) == expected
|
||||
|
||||
|
||||
class ParseEnvFileTest(unittest.TestCase):
|
||||
def generate_tempfile(self, file_content=None):
|
||||
def generate_tempfile(self, file_content: str) -> str:
|
||||
"""
|
||||
Generates a temporary file for tests with the content
|
||||
of 'file_content' and returns the filename.
|
||||
@@ -209,31 +215,31 @@ class ParseEnvFileTest(unittest.TestCase):
|
||||
local_tempfile.write(file_content.encode("UTF-8"))
|
||||
return local_tempfile.name
|
||||
|
||||
def test_parse_env_file_proper(self):
|
||||
def test_parse_env_file_proper(self) -> None:
|
||||
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"}
|
||||
os.unlink(env_file)
|
||||
|
||||
def test_parse_env_file_with_equals_character(self):
|
||||
def test_parse_env_file_with_equals_character(self) -> None:
|
||||
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"}
|
||||
os.unlink(env_file)
|
||||
|
||||
def test_parse_env_file_commented_line(self):
|
||||
def test_parse_env_file_commented_line(self) -> None:
|
||||
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"}
|
||||
os.unlink(env_file)
|
||||
|
||||
def test_parse_env_file_newline(self):
|
||||
def test_parse_env_file_newline(self) -> None:
|
||||
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"}
|
||||
os.unlink(env_file)
|
||||
|
||||
def test_parse_env_file_invalid_line(self):
|
||||
def test_parse_env_file_invalid_line(self) -> None:
|
||||
env_file = self.generate_tempfile(file_content="USER jdoe")
|
||||
with pytest.raises(DockerException):
|
||||
parse_env_file(env_file)
|
||||
@@ -241,7 +247,7 @@ class ParseEnvFileTest(unittest.TestCase):
|
||||
|
||||
|
||||
class ParseHostTest(unittest.TestCase):
|
||||
def test_parse_host(self):
|
||||
def test_parse_host(self) -> None:
|
||||
invalid_hosts = [
|
||||
"foo://0.0.0.0",
|
||||
"tcp://",
|
||||
@@ -282,16 +288,16 @@ class ParseHostTest(unittest.TestCase):
|
||||
for host in invalid_hosts:
|
||||
msg = f"Should have failed to parse invalid host: {host}"
|
||||
with self.assertRaises(DockerException, msg=msg):
|
||||
parse_host(host, None)
|
||||
parse_host(host)
|
||||
|
||||
for host, expected in valid_hosts.items():
|
||||
self.assertEqual(
|
||||
parse_host(host, None),
|
||||
parse_host(host),
|
||||
expected,
|
||||
msg=f"Failed to parse valid host: {host}",
|
||||
)
|
||||
|
||||
def test_parse_host_empty_value(self):
|
||||
def test_parse_host_empty_value(self) -> None:
|
||||
unix_socket = "http+unix:///var/run/docker.sock"
|
||||
npipe = "npipe:////./pipe/docker_engine"
|
||||
|
||||
@@ -299,17 +305,17 @@ class ParseHostTest(unittest.TestCase):
|
||||
assert parse_host(val, is_win32=False) == unix_socket
|
||||
assert parse_host(val, is_win32=True) == npipe
|
||||
|
||||
def test_parse_host_tls(self):
|
||||
def test_parse_host_tls(self) -> None:
|
||||
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):
|
||||
def test_parse_host_tls_tcp_proto(self) -> None:
|
||||
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):
|
||||
def test_parse_host_trailing_slash(self) -> None:
|
||||
host_value = "tcp://myhost.docker.net:2376/"
|
||||
expected_result = "http://myhost.docker.net:2376"
|
||||
assert parse_host(host_value) == expected_result
|
||||
@@ -318,31 +324,31 @@ class ParseHostTest(unittest.TestCase):
|
||||
class ParseRepositoryTagTest(unittest.TestCase):
|
||||
sha = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||
|
||||
def test_index_image_no_tag(self):
|
||||
def test_index_image_no_tag(self) -> None:
|
||||
assert parse_repository_tag("root") == ("root", None)
|
||||
|
||||
def test_index_image_tag(self):
|
||||
def test_index_image_tag(self) -> None:
|
||||
assert parse_repository_tag("root:tag") == ("root", "tag")
|
||||
|
||||
def test_index_user_image_no_tag(self):
|
||||
def test_index_user_image_no_tag(self) -> None:
|
||||
assert parse_repository_tag("user/repo") == ("user/repo", None)
|
||||
|
||||
def test_index_user_image_tag(self):
|
||||
def test_index_user_image_tag(self) -> None:
|
||||
assert parse_repository_tag("user/repo:tag") == ("user/repo", "tag")
|
||||
|
||||
def test_private_reg_image_no_tag(self):
|
||||
def test_private_reg_image_no_tag(self) -> None:
|
||||
assert parse_repository_tag("url:5000/repo") == ("url:5000/repo", None)
|
||||
|
||||
def test_private_reg_image_tag(self):
|
||||
def test_private_reg_image_tag(self) -> None:
|
||||
assert parse_repository_tag("url:5000/repo:tag") == ("url:5000/repo", "tag")
|
||||
|
||||
def test_index_image_sha(self):
|
||||
def test_index_image_sha(self) -> None:
|
||||
assert parse_repository_tag(f"root@sha256:{self.sha}") == (
|
||||
"root",
|
||||
f"sha256:{self.sha}",
|
||||
)
|
||||
|
||||
def test_private_reg_image_sha(self):
|
||||
def test_private_reg_image_sha(self) -> None:
|
||||
assert parse_repository_tag(f"url:5000/repo@sha256:{self.sha}") == (
|
||||
"url:5000/repo",
|
||||
f"sha256:{self.sha}",
|
||||
@@ -350,7 +356,7 @@ class ParseRepositoryTagTest(unittest.TestCase):
|
||||
|
||||
|
||||
class ParseDeviceTest(unittest.TestCase):
|
||||
def test_dict(self):
|
||||
def test_dict(self) -> None:
|
||||
devices = parse_devices(
|
||||
[
|
||||
{
|
||||
@@ -366,7 +372,7 @@ class ParseDeviceTest(unittest.TestCase):
|
||||
"CgroupPermissions": "r",
|
||||
}
|
||||
|
||||
def test_partial_string_definition(self):
|
||||
def test_partial_string_definition(self) -> None:
|
||||
devices = parse_devices(["/dev/sda1"])
|
||||
assert devices[0] == {
|
||||
"PathOnHost": "/dev/sda1",
|
||||
@@ -374,7 +380,7 @@ class ParseDeviceTest(unittest.TestCase):
|
||||
"CgroupPermissions": "rwm",
|
||||
}
|
||||
|
||||
def test_permissionless_string_definition(self):
|
||||
def test_permissionless_string_definition(self) -> None:
|
||||
devices = parse_devices(["/dev/sda1:/dev/mnt1"])
|
||||
assert devices[0] == {
|
||||
"PathOnHost": "/dev/sda1",
|
||||
@@ -382,7 +388,7 @@ class ParseDeviceTest(unittest.TestCase):
|
||||
"CgroupPermissions": "rwm",
|
||||
}
|
||||
|
||||
def test_full_string_definition(self):
|
||||
def test_full_string_definition(self) -> None:
|
||||
devices = parse_devices(["/dev/sda1:/dev/mnt1:r"])
|
||||
assert devices[0] == {
|
||||
"PathOnHost": "/dev/sda1",
|
||||
@@ -390,7 +396,7 @@ class ParseDeviceTest(unittest.TestCase):
|
||||
"CgroupPermissions": "r",
|
||||
}
|
||||
|
||||
def test_hybrid_list(self):
|
||||
def test_hybrid_list(self) -> None:
|
||||
devices = parse_devices(
|
||||
[
|
||||
"/dev/sda1:/dev/mnt1:rw",
|
||||
@@ -415,12 +421,12 @@ class ParseDeviceTest(unittest.TestCase):
|
||||
|
||||
|
||||
class ParseBytesTest(unittest.TestCase):
|
||||
def test_parse_bytes_valid(self):
|
||||
def test_parse_bytes_valid(self) -> None:
|
||||
assert parse_bytes("512MB") == 536870912
|
||||
assert parse_bytes("512M") == 536870912
|
||||
assert parse_bytes("512m") == 536870912
|
||||
|
||||
def test_parse_bytes_invalid(self):
|
||||
def test_parse_bytes_invalid(self) -> None:
|
||||
with pytest.raises(DockerException):
|
||||
parse_bytes("512MK")
|
||||
with pytest.raises(DockerException):
|
||||
@@ -428,15 +434,15 @@ class ParseBytesTest(unittest.TestCase):
|
||||
with pytest.raises(DockerException):
|
||||
parse_bytes("127.0.0.1K")
|
||||
|
||||
def test_parse_bytes_float(self):
|
||||
def test_parse_bytes_float(self) -> None:
|
||||
assert parse_bytes("1.5k") == 1536
|
||||
|
||||
|
||||
class UtilsTest(unittest.TestCase):
|
||||
longMessage = True
|
||||
|
||||
def test_convert_filters(self):
|
||||
tests = [
|
||||
def test_convert_filters(self) -> None:
|
||||
tests: list[tuple[dict[str, bool | str | int | list[str | int]], str]] = [
|
||||
({"dangling": True}, '{"dangling": ["true"]}'),
|
||||
({"dangling": "true"}, '{"dangling": ["true"]}'),
|
||||
({"exited": 0}, '{"exited": ["0"]}'),
|
||||
@@ -446,7 +452,7 @@ class UtilsTest(unittest.TestCase):
|
||||
for filters, expected in tests:
|
||||
assert convert_filters(filters) == expected
|
||||
|
||||
def test_decode_json_header(self):
|
||||
def test_decode_json_header(self) -> None:
|
||||
obj = {"a": "b", "c": 1}
|
||||
data = base64.urlsafe_b64encode(bytes(json.dumps(obj), "utf-8"))
|
||||
decoded_data = decode_json_header(data)
|
||||
@@ -454,16 +460,16 @@ class UtilsTest(unittest.TestCase):
|
||||
|
||||
|
||||
class SplitCommandTest(unittest.TestCase):
|
||||
def test_split_command_with_unicode(self):
|
||||
def test_split_command_with_unicode(self) -> None:
|
||||
assert split_command("echo μμ") == ["echo", "μμ"]
|
||||
|
||||
|
||||
class FormatEnvironmentTest(unittest.TestCase):
|
||||
def test_format_env_binary_unicode_value(self):
|
||||
def test_format_env_binary_unicode_value(self) -> None:
|
||||
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):
|
||||
def test_format_env_no_value(self) -> None:
|
||||
env_dict = {
|
||||
"FOO": None,
|
||||
"BAR": "",
|
||||
|
||||
Reference in New Issue
Block a user