From ccfc8daf6e029412badf56a54dd4a01d575e1431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Do=C4=9Fukan=20=C3=87a=C4=9Fatay?= Date: Sun, 30 Jun 2024 23:30:31 +0200 Subject: [PATCH 1/2] feat(network): Add create method to Network class (#627) This PR adds `create` method to the `Network` class to enable a non-context-manager usage. Fixes #627 --- core/testcontainers/core/network.py | 5 ++++- core/tests/test_network.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/core/testcontainers/core/network.py b/core/testcontainers/core/network.py index 9903d0710..27b747c14 100644 --- a/core/testcontainers/core/network.py +++ b/core/testcontainers/core/network.py @@ -32,10 +32,13 @@ def connect(self, container_id: str, network_aliases: Optional[list] = None): def remove(self) -> None: self._network.remove() - def __enter__(self) -> "Network": + def create(self) -> "Network": self._network = self._docker.client.networks.create(self.name, **self._docker_network_kw) self.id = self._network.id return self + def __enter__(self) -> "Network": + return self.create() + def __exit__(self, exc_type, exc_val, exc_tb) -> None: self.remove() diff --git a/core/tests/test_network.py b/core/tests/test_network.py index 4b0764d4d..09c88cb3a 100644 --- a/core/tests/test_network.py +++ b/core/tests/test_network.py @@ -1,7 +1,11 @@ +from http import HTTPStatus from testcontainers.core.container import DockerContainer from testcontainers.core.docker_client import DockerClient from testcontainers.core.network import Network +import docker.errors +import pytest + NGINX_ALPINE_SLIM_IMAGE = "nginx:1.25.4-alpine-slim" @@ -14,6 +18,31 @@ def test_network_gets_created_and_cleaned_up(): assert not docker.client.networks.list(network.name) +def test_network_create_wo_cm(): + network = Network() + network.create() + docker = DockerClient() + networks_list = docker.client.networks.list(network.name) + assert networks_list[0].name == network.name + assert networks_list[0].id == network.id + + network.remove() + assert not docker.client.networks.list(network.name) + + +def test_network_create_errors(): + network = Network() + network.create() + + # calling create the second time should raise an error + with pytest.raises(docker.errors.APIError) as excinfo: + network.create() + + assert excinfo.value.response.status_code == HTTPStatus.CONFLICT + excinfo.match(f"network with name {network.name} already exists") + network.remove() + + def test_containers_can_communicate_over_network(): with Network() as network: with ( From 2995ccb0fcc37b3279402e690b44b80b4d1714cd Mon Sep 17 00:00:00 2001 From: Dave Ankin Date: Mon, 1 Jul 2024 04:57:59 -0400 Subject: [PATCH 2/2] make sure networks are also labelled for cleanup --- core/testcontainers/core/docker_client.py | 4 ++++ core/testcontainers/core/network.py | 2 +- core/tests/test_network.py | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/core/testcontainers/core/docker_client.py b/core/testcontainers/core/docker_client.py index 9b7fe7479..286e1ef9f 100644 --- a/core/testcontainers/core/docker_client.py +++ b/core/testcontainers/core/docker_client.py @@ -211,6 +211,10 @@ def login(self, docker_auth_config: str) -> None: login_info = self.client.login(**auth_config._asdict()) LOGGER.debug(f"logged in using {login_info}") + def client_networks_create(self, name: str, param: dict): + labels = create_labels("", param.get("labels")) + return self.client.networks.create(name, **{**param, "labels": labels}) + def get_docker_host() -> Optional[str]: return c.tc_properties_get_tc_host() or os.getenv("DOCKER_HOST") diff --git a/core/testcontainers/core/network.py b/core/testcontainers/core/network.py index 27b747c14..d149d5e48 100644 --- a/core/testcontainers/core/network.py +++ b/core/testcontainers/core/network.py @@ -33,7 +33,7 @@ def remove(self) -> None: self._network.remove() def create(self) -> "Network": - self._network = self._docker.client.networks.create(self.name, **self._docker_network_kw) + self._network = self._docker.client_networks_create(self.name, self._docker_network_kw) self.id = self._network.id return self diff --git a/core/tests/test_network.py b/core/tests/test_network.py index 09c88cb3a..7191153bb 100644 --- a/core/tests/test_network.py +++ b/core/tests/test_network.py @@ -1,6 +1,7 @@ from http import HTTPStatus from testcontainers.core.container import DockerContainer from testcontainers.core.docker_client import DockerClient +from testcontainers.core.labels import LABEL_SESSION_ID from testcontainers.core.network import Network import docker.errors @@ -70,3 +71,13 @@ def assert_can_ping(container: DockerContainer, remote_name: str): status, output = container.exec("ping -c 1 %s" % remote_name) assert status == 0 assert "64 bytes" in str(output) + + +def test_network_has_labels(): + network = Network() + try: + network.create() + network = network._docker.client.networks.get(network_id=network.id) + assert LABEL_SESSION_ID in network.attrs.get("Labels") + finally: + network.remove()