diff --git a/core/tests/test_config.py b/core/tests/test_config.py new file mode 100644 index 00000000..a6597fd4 --- /dev/null +++ b/core/tests/test_config.py @@ -0,0 +1,62 @@ +from testcontainers.core.config import TestcontainersConfiguration as TCC, TC_FILE + +from pytest import MonkeyPatch, mark, LogCaptureFixture + +import logging +import tempfile + + +def test_read_tc_properties(monkeypatch: MonkeyPatch) -> None: + with tempfile.TemporaryDirectory() as tmpdirname: + file = f"{tmpdirname}/{TC_FILE}" + with open(file, "w") as f: + f.write("tc.host=some_value\n") + + monkeypatch.setattr("testcontainers.core.config.TC_GLOBAL", file) + + config = TCC() + assert config.tc_properties == {"tc.host": "some_value"} + + +@mark.parametrize("docker_auth_config_env", ["key=value", ""]) +@mark.parametrize("warning_dict", [{}, {"key": "value"}, {"DOCKER_AUTH_CONFIG": "TEST"}]) +@mark.parametrize("warning_dict_post", [{}, {"key": "value"}, {"DOCKER_AUTH_CONFIG": "TEST"}]) +def test_docker_auth_config( + caplog: LogCaptureFixture, + monkeypatch: MonkeyPatch, + docker_auth_config_env: str, + warning_dict: dict[str, str], + warning_dict_post: dict[str, str], +) -> None: + monkeypatch.setattr("testcontainers.core.config._WARNINGS", warning_dict) + monkeypatch.setenv("DOCKER_AUTH_CONFIG", docker_auth_config_env) + caplog.set_level(logging.WARNING) + + config = TCC() + if not docker_auth_config_env: + assert config.docker_auth_config == "" + assert caplog.text == "" + else: + assert config.docker_auth_config == docker_auth_config_env + + if "DOCKER_AUTH_CONFIG" in warning_dict: + assert warning_dict["DOCKER_AUTH_CONFIG"] in caplog.text + + if warning_dict == {}: + monkeypatch.setattr("testcontainers.core.config._WARNINGS", warning_dict_post) + + config.docker_auth_config = "new_value" + assert config.docker_auth_config == "new_value" + + +def test_tc_properties_get_tc_host() -> None: + config = TCC() + config.tc_properties = {"tc.host": "some_value"} + assert config.tc_properties_get_tc_host() == "some_value" + + +def test_timeout() -> None: + config = TCC() + config.max_tries = 2 + config.sleep_time = 3 + assert config.timeout == 6 diff --git a/core/tests/test_core.py b/core/tests/test_core.py index 8d0c7794..42321e28 100644 --- a/core/tests/test_core.py +++ b/core/tests/test_core.py @@ -1,19 +1,4 @@ -import pytest -import tempfile -import random -import os - -from pathlib import Path -from typing import Optional - from testcontainers.core.container import DockerContainer -from testcontainers.core.image import DockerImage -from testcontainers.core.waiting_utils import wait_for_logs - - -def test_timeout_is_raised_when_waiting_for_logs(): - with pytest.raises(TimeoutError), DockerContainer("alpine").with_command("sleep 2") as container: - wait_for_logs(container, "Hello from Docker!", timeout=1e-3) def test_garbage_collection_is_defensive(): @@ -26,69 +11,9 @@ def test_garbage_collection_is_defensive(): del container -def test_wait_for_hello(): - with DockerContainer("hello-world") as container: - wait_for_logs(container, "Hello from Docker!") - - -def test_can_get_logs(): +def test_get_logs(): with DockerContainer("hello-world") as container: - wait_for_logs(container, "Hello from Docker!") stdout, stderr = container.get_logs() assert isinstance(stdout, bytes) assert isinstance(stderr, bytes) - assert stdout, "There should be something on stdout" - - -@pytest.mark.parametrize("test_cleanup", [True, False]) -@pytest.mark.parametrize("test_image_tag", [None, "test-image:latest"]) -def test_docker_image(test_image_tag: Optional[str], test_cleanup: bool, check_for_image): - with tempfile.TemporaryDirectory() as temp_directory: - # It's important to use a random string to avoid image caching - random_string = "Hello from Docker Image! " + str(random.randint(0, 1000)) - with open(f"{temp_directory}/Dockerfile", "w") as f: - f.write( - f""" - FROM alpine:latest - CMD echo "{random_string}" - """ - ) - with DockerImage(path=temp_directory, tag=test_image_tag, clean_up=test_cleanup) as image: - image_short_id = image.short_id - assert image.tag is test_image_tag, f"Expected {test_image_tag}, got {image.tag}" - assert image.short_id is not None, "Short ID should not be None" - logs = image.get_logs() - assert isinstance(logs, list), "Logs should be a list" - assert logs[0] == {"stream": "Step 1/2 : FROM alpine:latest"} - assert logs[3] == {"stream": f'Step 2/2 : CMD echo "{random_string}"'} - with DockerContainer(str(image)) as container: - assert container._container.image.short_id.endswith(image_short_id), "Image ID mismatch" - assert container.get_logs() == ((random_string + "\n").encode(), b""), "Container logs mismatch" - - check_for_image(image_short_id, test_cleanup) - - -@pytest.mark.parametrize("dockerfile_path", [None, Path("subdir/my.Dockerfile")]) -def test_docker_image_with_custom_dockerfile_path(dockerfile_path: Optional[Path]): - with tempfile.TemporaryDirectory() as temp_directory: - temp_dir_path = Path(temp_directory) - if dockerfile_path: - os.makedirs(temp_dir_path / dockerfile_path.parent, exist_ok=True) - dockerfile_rel_path = dockerfile_path - dockerfile_kwargs = {"dockerfile_path": dockerfile_path} - else: - dockerfile_rel_path = Path("Dockerfile") # default - dockerfile_kwargs = {} - - with open(temp_dir_path / dockerfile_rel_path, "x") as f: - f.write( - f""" - FROM alpine:latest - CMD echo "Hello world!" - """ - ) - with DockerImage(path=temp_directory, tag="test", clean_up=True, no_cache=True, **dockerfile_kwargs) as image: - image_short_id = image.short_id - with DockerContainer(str(image)) as container: - assert container._container.image.short_id.endswith(image_short_id), "Image ID mismatch" - assert container.get_logs() == (("Hello world!\n").encode(), b""), "Container logs mismatch" + assert "Hello from Docker".encode() in stdout, "There should be something on stdout" diff --git a/core/tests/test_image.py b/core/tests/test_image.py new file mode 100644 index 00000000..da35eda0 --- /dev/null +++ b/core/tests/test_image.py @@ -0,0 +1,66 @@ +import pytest +import tempfile +import random +import os + +from pathlib import Path +from typing import Optional + +from testcontainers.core.container import DockerContainer +from testcontainers.core.image import DockerImage + + +@pytest.mark.parametrize("test_cleanup", [True, False]) +@pytest.mark.parametrize("test_image_tag", [None, "test-image:latest"]) +def test_docker_image(test_image_tag: Optional[str], test_cleanup: bool, check_for_image) -> None: + with tempfile.TemporaryDirectory() as temp_directory: + # It's important to use a random string to avoid image caching + random_string = "Hello from Docker Image! " + str(random.randint(0, 1000)) + with open(f"{temp_directory}/Dockerfile", "w") as f: + f.write( + f""" + FROM alpine:latest + CMD echo "{random_string}" + """ + ) + with DockerImage(path=temp_directory, tag=test_image_tag, clean_up=test_cleanup) as image: + image_short_id = image.short_id + assert image.tag is test_image_tag, f"Expected {test_image_tag}, got {image.tag}" + assert image.short_id is not None, "Short ID should not be None" + assert image.get_wrapped_image() is not None + logs = image.get_logs() + assert isinstance(logs, list), "Logs should be a list" + assert logs[0] == {"stream": "Step 1/2 : FROM alpine:latest"} + assert logs[3] == {"stream": f'Step 2/2 : CMD echo "{random_string}"'} + with DockerContainer(str(image)) as container: + assert container._container.image.short_id.endswith(image_short_id), "Image ID mismatch" + assert container.get_logs() == ((random_string + "\n").encode(), b""), "Container logs mismatch" + + check_for_image(image_short_id, test_cleanup) + + +@pytest.mark.parametrize("dockerfile_path", [None, Path("subdir/my.Dockerfile")]) +def test_docker_image_with_custom_dockerfile_path(dockerfile_path: Optional[Path]) -> None: + with tempfile.TemporaryDirectory() as temp_directory: + temp_dir_path = Path(temp_directory) + if dockerfile_path: + os.makedirs(temp_dir_path / dockerfile_path.parent, exist_ok=True) + dockerfile_rel_path = dockerfile_path + dockerfile_kwargs = {"dockerfile_path": dockerfile_path} + else: + dockerfile_rel_path = Path("Dockerfile") # default + dockerfile_kwargs = {} + + with open(temp_dir_path / dockerfile_rel_path, "x") as f: + f.write( + f""" + FROM alpine:latest + CMD echo "Hello world!" + """ + ) + with DockerImage(path=temp_directory, tag="test", clean_up=True, no_cache=True, **dockerfile_kwargs) as image: + image_short_id = image.short_id + assert image.get_wrapped_image() is not None + with DockerContainer(str(image)) as container: + assert container._container.image.short_id.endswith(image_short_id), "Image ID mismatch" + assert container.get_logs() == (("Hello world!\n").encode(), b""), "Container logs mismatch" diff --git a/core/tests/test_utils.py b/core/tests/test_utils.py new file mode 100644 index 00000000..01134327 --- /dev/null +++ b/core/tests/test_utils.py @@ -0,0 +1,53 @@ +from pytest import MonkeyPatch, raises, mark + +from testcontainers.core import utils + + +def test_setup_logger() -> None: + assert utils.setup_logger("test") is not None + + +@mark.parametrize("platform, expected", [("linux", "linux"), ("linux2", "linux"), ("darwin", "mac"), ("win32", "win")]) +def test_os_name(monkeypatch: MonkeyPatch, platform: str, expected: str) -> None: + assert utils.os_name() is not None + monkeypatch.setattr("sys.platform", platform) + assert utils.os_name() == expected + + +def test_is_mac(monkeypatch: MonkeyPatch) -> None: + monkeypatch.setattr("testcontainers.core.utils.os_name", lambda: "mac") + assert utils.is_mac() + + +def test_is_linux(monkeypatch: MonkeyPatch) -> None: + monkeypatch.setattr("testcontainers.core.utils.os_name", lambda: "linux") + assert utils.is_linux() + + +def test_is_windows(monkeypatch: MonkeyPatch) -> None: + monkeypatch.setattr("testcontainers.core.utils.os_name", lambda: "win") + assert utils.is_windows() + + +def test_is_arm(monkeypatch: MonkeyPatch) -> None: + assert not utils.is_arm() + monkeypatch.setattr("platform.machine", lambda: "arm64") + assert utils.is_arm() + monkeypatch.setattr("platform.machine", lambda: "aarch64") + assert utils.is_arm() + + +def test_inside_container(monkeypatch: MonkeyPatch) -> None: + assert not utils.inside_container() + monkeypatch.setattr("os.path.exists", lambda _: True) + assert utils.inside_container() + + +def test_raise_for_deprecated_parameters() -> None: + kwargs = {"key": "value"} + current = "key" + replacement = "new_key" + with raises(ValueError) as e: + result = utils.raise_for_deprecated_parameter(kwargs, current, replacement) + assert str(e.value) == "Parameter 'deprecated' is deprecated and should be replaced by 'replacement'." + assert result == {} diff --git a/core/tests/test_waiting_utils.py b/core/tests/test_waiting_utils.py new file mode 100644 index 00000000..1e684fc4 --- /dev/null +++ b/core/tests/test_waiting_utils.py @@ -0,0 +1,14 @@ +import pytest + +from testcontainers.core.container import DockerContainer +from testcontainers.core.waiting_utils import wait_for_logs + + +def test_wait_for_logs() -> None: + with DockerContainer("hello-world") as container: + wait_for_logs(container, "Hello from Docker!") + + +def test_timeout_is_raised_when_waiting_for_logs() -> None: + with pytest.raises(TimeoutError), DockerContainer("alpine").with_command("sleep 2") as container: + wait_for_logs(container, "Hello from Docker!", timeout=1e-3)