Skip to content

Commit e93bc29

Browse files
fix(network): Now able to use Network without context, and has labels to be automatically cleaned up (testcontainers#627) (testcontainers#630)
This PR adds `create` method to the `Network` class to enable a non-context-manager usage. Fixes testcontainers#627 --------- Co-authored-by: Dave Ankin <[email protected]>
1 parent 2e7dbf1 commit e93bc29

File tree

3 files changed

+49
-2
lines changed

3 files changed

+49
-2
lines changed

core/testcontainers/core/docker_client.py

+4
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ def login(self, docker_auth_config: str) -> None:
211211
login_info = self.client.login(**auth_config._asdict())
212212
LOGGER.debug(f"logged in using {login_info}")
213213

214+
def client_networks_create(self, name: str, param: dict):
215+
labels = create_labels("", param.get("labels"))
216+
return self.client.networks.create(name, **{**param, "labels": labels})
217+
214218

215219
def get_docker_host() -> Optional[str]:
216220
return c.tc_properties_get_tc_host() or os.getenv("DOCKER_HOST")

core/testcontainers/core/network.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,13 @@ def connect(self, container_id: str, network_aliases: Optional[list] = None):
3232
def remove(self) -> None:
3333
self._network.remove()
3434

35-
def __enter__(self) -> "Network":
36-
self._network = self._docker.client.networks.create(self.name, **self._docker_network_kw)
35+
def create(self) -> "Network":
36+
self._network = self._docker.client_networks_create(self.name, self._docker_network_kw)
3737
self.id = self._network.id
3838
return self
3939

40+
def __enter__(self) -> "Network":
41+
return self.create()
42+
4043
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
4144
self.remove()

core/tests/test_network.py

+40
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
from http import HTTPStatus
12
from testcontainers.core.container import DockerContainer
23
from testcontainers.core.docker_client import DockerClient
4+
from testcontainers.core.labels import LABEL_SESSION_ID
35
from testcontainers.core.network import Network
46

7+
import docker.errors
8+
import pytest
9+
510
NGINX_ALPINE_SLIM_IMAGE = "nginx:1.25.4-alpine-slim"
611

712

@@ -14,6 +19,31 @@ def test_network_gets_created_and_cleaned_up():
1419
assert not docker.client.networks.list(network.name)
1520

1621

22+
def test_network_create_wo_cm():
23+
network = Network()
24+
network.create()
25+
docker = DockerClient()
26+
networks_list = docker.client.networks.list(network.name)
27+
assert networks_list[0].name == network.name
28+
assert networks_list[0].id == network.id
29+
30+
network.remove()
31+
assert not docker.client.networks.list(network.name)
32+
33+
34+
def test_network_create_errors():
35+
network = Network()
36+
network.create()
37+
38+
# calling create the second time should raise an error
39+
with pytest.raises(docker.errors.APIError) as excinfo:
40+
network.create()
41+
42+
assert excinfo.value.response.status_code == HTTPStatus.CONFLICT
43+
excinfo.match(f"network with name {network.name} already exists")
44+
network.remove()
45+
46+
1747
def test_containers_can_communicate_over_network():
1848
with Network() as network:
1949
with (
@@ -41,3 +71,13 @@ def assert_can_ping(container: DockerContainer, remote_name: str):
4171
status, output = container.exec("ping -c 1 %s" % remote_name)
4272
assert status == 0
4373
assert "64 bytes" in str(output)
74+
75+
76+
def test_network_has_labels():
77+
network = Network()
78+
try:
79+
network.create()
80+
network = network._docker.client.networks.get(network_id=network.id)
81+
assert LABEL_SESSION_ID in network.attrs.get("Labels")
82+
finally:
83+
network.remove()

0 commit comments

Comments
 (0)