Skip to content

Commit 31b0b07

Browse files
committed
Image clean is now optional
1 parent 532ae3a commit 31b0b07

File tree

3 files changed

+47
-17
lines changed

3 files changed

+47
-17
lines changed

core/testcontainers/core/generic.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ class CustomContainer(DockerContainer):
9999
:param tag: Tag for the image to be built (default: None)
100100
"""
101101

102-
def __init__(self, path: str, tag: Optional[str]) -> None:
103-
self.docker_image = DockerImage(path=path, tag=tag).build()
102+
def __init__(self, path: str, tag: Optional[str], image_cleanup: bool = True) -> None:
103+
self.docker_image = DockerImage(path=path, tag=tag, clean_up=image_cleanup).build()
104104
super().__init__(str(self.docker_image))
105105

106106
def get_url(self) -> str:

core/testcontainers/core/image.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ def __init__(
3030
path: str,
3131
docker_client_kw: Optional[dict] = None,
3232
tag: Optional[str] = None,
33+
clean_up: bool = True,
3334
**kwargs,
3435
) -> None:
3536
self.tag = tag
3637
self.path = path
3738
self.id = None
3839
self._docker = DockerClient(**(docker_client_kw or {}))
40+
self.clean_up = clean_up
3941
self._kwargs = kwargs
4042

4143
def build(self, **kwargs) -> Self:
@@ -46,7 +48,7 @@ def build(self, **kwargs) -> Self:
4648
return self
4749

4850
@property
49-
def short_id(self):
51+
def short_id(self) -> str:
5052
"""
5153
The ID of the image truncated to 12 characters, without the ``sha256:`` prefix.
5254
"""
@@ -61,7 +63,8 @@ def remove(self, force=True, noprune=False) -> None:
6163
:param force: Remove the image even if it is in use
6264
:param noprune: Do not delete untagged parent images
6365
"""
64-
if self._image:
66+
if self._image and self.clean_up:
67+
logger.info(f"Cleanup - Removing image {self.short_id}")
6568
self._image.remove(force=force, noprune=noprune)
6669
self.get_docker_client().client.close()
6770

core/tests/test_core.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import pytest
22
import tempfile
3+
import random
4+
5+
from typing import Optional
36

47
from testcontainers.core.container import DockerContainer
58
from testcontainers.core.image import DockerImage
69
from testcontainers.core.waiting_utils import wait_for_logs
710
from testcontainers.core.generic import CustomContainer
11+
from testcontainers.core.docker_client import DockerClient
812

913

1014
def test_timeout_is_raised_when_waiting_for_logs():
@@ -36,41 +40,64 @@ def test_can_get_logs():
3640
assert stdout, "There should be something on stdout"
3741

3842

43+
def check_for_image(image_short_id: str) -> bool:
44+
"""
45+
Check if the image with the given short_id is present in the list of images
46+
"""
47+
client = DockerClient()
48+
images = client.client.images.list()
49+
return any(image.short_id.endswith(image_short_id) for image in images)
50+
51+
52+
@pytest.mark.parametrize("test_cleanup", [True, False])
3953
@pytest.mark.parametrize("test_image_tag", [None, "test-image:latest"])
40-
def test_docker_image(test_image_tag):
54+
def test_docker_image(test_image_tag: Optional[str], test_cleanup: bool):
4155
with tempfile.TemporaryDirectory() as temp_directory:
56+
# It's important to use a random string to avoid image caching
57+
random_string = "Hello from Docker Image! " + str(random.randint(0, 1000))
4258
with open(f"{temp_directory}/Dockerfile", "w") as f:
4359
f.write(
44-
"""
60+
f"""
4561
FROM alpine:latest
46-
CMD echo "Hello from Docker Image!"
62+
CMD echo "{random_string}"
4763
"""
4864
)
4965
f.close()
50-
with DockerImage(path=temp_directory, tag=test_image_tag) as image:
66+
with DockerImage(path=temp_directory, tag=test_image_tag, clean_up=test_cleanup) as image:
67+
image_short_id = image.short_id
5168
assert image.tag is test_image_tag
5269
assert image.short_id is not None
5370
logs = image.get_logs()
5471
assert isinstance(logs, list)
5572
assert logs[0] == {"stream": "Step 1/2 : FROM alpine:latest"}
56-
assert logs[3] == {"stream": 'Step 2/2 : CMD echo "Hello from Docker Image!"'}
73+
assert logs[3] == {"stream": f'Step 2/2 : CMD echo "{random_string}"'}
5774
with DockerContainer(str(image)) as container:
58-
wait_for_logs(container, "Hello from Docker Image!")
59-
assert container._container.image.short_id.endswith(image.short_id)
75+
wait_for_logs(container, random_string)
76+
assert container._container.image.short_id.endswith(image_short_id)
6077

78+
if not test_cleanup:
79+
assert check_for_image(image_short_id)
6180

81+
82+
@pytest.mark.parametrize("test_image_cleanup", [True, False])
6283
@pytest.mark.parametrize("test_image_tag", [None, "custom-image:test"])
63-
def test_custom_container(test_image_tag):
84+
def test_custom_container(test_image_tag: Optional[str], test_image_cleanup: bool):
6485
with tempfile.TemporaryDirectory() as temp_directory:
86+
# It's important to use a random string to avoid image caching
87+
random_string = "This is a custom Docker Image! " + str(random.randint(0, 1000))
6588
with open(f"{temp_directory}/Dockerfile", "w") as f:
6689
f.write(
67-
"""
90+
f"""
6891
FROM alpine:latest
69-
CMD echo "This is a custom Docker Image!"
92+
CMD echo "{random_string}"
7093
"""
7194
)
7295
f.close()
73-
with CustomContainer(path=temp_directory, tag=test_image_tag) as server:
96+
with CustomContainer(path=temp_directory, tag=test_image_tag, image_cleanup=test_image_cleanup) as server:
97+
image_short_id = server.docker_image.short_id
7498
image_build_logs = server.docker_image.get_logs()
75-
assert image_build_logs[3] == {"stream": 'Step 2/2 : CMD echo "This is a custom Docker Image!"'}
76-
wait_for_logs(server, "This is a custom Docker Image!")
99+
assert image_build_logs[3] == {"stream": f'Step 2/2 : CMD echo "{random_string}"'}
100+
wait_for_logs(server, random_string)
101+
102+
if not test_image_cleanup:
103+
assert check_for_image(image_short_id)

0 commit comments

Comments
 (0)