Skip to content

Commit 6287732

Browse files
committed
Introduce wait_for_healthcheck
1 parent e7feb53 commit 6287732

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed

core/testcontainers/core/container.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import contextlib
2+
import time
23
from os import PathLike
34
from socket import socket
45
from typing import TYPE_CHECKING, Optional, Union
@@ -251,6 +252,17 @@ def _configure(self) -> None:
251252
# placeholder if subclasses want to define this and use the default start method
252253
pass
253254

255+
def wait_for_healthcheck(self, timeout: int = 10):
256+
start_time = time.time()
257+
underlying = self.get_wrapped_container()
258+
while time.time() - start_time < timeout:
259+
underlying.reload()
260+
if underlying.health == "healthy":
261+
break
262+
time.sleep(0.1)
263+
else:
264+
raise NotHealthy()
265+
254266

255267
class Reaper:
256268
_instance: "Optional[Reaper]" = None
@@ -327,3 +339,7 @@ def _create_instance(cls) -> "Reaper":
327339
Reaper._instance = Reaper()
328340

329341
return Reaper._instance
342+
343+
344+
class NotHealthy(Exception):
345+
pass

core/tests/test_container.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import pathlib
2+
import textwrap
3+
14
import pytest
25

3-
from testcontainers.core.container import DockerContainer
6+
from testcontainers.core.container import DockerContainer, NotHealthy
47
from testcontainers.core.docker_client import DockerClient
58
from testcontainers.core.config import ConnectionMode
9+
from testcontainers.core.image import DockerImage
610

711
FAKE_ID = "ABC123"
812

@@ -96,3 +100,66 @@ def test_attribute(init_attr, init_value, class_attr, stored_value):
96100
"""Test that the attributes set through the __init__ function are properly stored."""
97101
with DockerContainer("ubuntu", **{init_attr: init_value}) as container:
98102
assert getattr(container, class_attr) == stored_value
103+
104+
105+
@pytest.fixture(name="with_never_healthy_image")
106+
def with_never_health_image_fixture(tmp_path):
107+
DOCKERFILE = """FROM alpine:latest
108+
HEALTHCHECK --interval=1s CMD test -e /testfile
109+
CMD sleep infinity
110+
"""
111+
dockerfile = tmp_path / "Dockerfile"
112+
dockerfile.write_text(textwrap.dedent(DOCKERFILE))
113+
with DockerImage(tmp_path) as image:
114+
yield image
115+
116+
117+
def test_wait_for_healthcheck_never_healthy(with_never_healthy_image: DockerImage):
118+
# Given
119+
with DockerContainer(image=str(with_never_healthy_image)) as container:
120+
# Expect
121+
with pytest.raises(NotHealthy):
122+
# When
123+
container.wait_for_healthcheck()
124+
125+
126+
@pytest.fixture(name="with_immediately_healthy_image")
127+
def with_immediately_healthy_image_fixture(tmp_path):
128+
DOCKERFILE = """FROM alpine:latest
129+
RUN touch /testfile
130+
131+
HEALTHCHECK --interval=1s CMD test -e /testfile
132+
CMD sleep infinity
133+
"""
134+
dockerfile = tmp_path / "Dockerfile"
135+
dockerfile.write_text(textwrap.dedent(DOCKERFILE))
136+
with DockerImage(tmp_path) as image:
137+
yield image
138+
139+
140+
def test_wait_for_healthcheck_immediate_healthy(with_immediately_healthy_image: DockerImage):
141+
# Given
142+
with DockerContainer(image=str(with_immediately_healthy_image)) as container:
143+
# When
144+
container.wait_for_healthcheck()
145+
146+
147+
@pytest.fixture(name="with_eventually_healthy_image")
148+
def with_eventually_healthy_image_fixture(tmp_path):
149+
DOCKERFILE = """FROM alpine:latest
150+
RUN touch /testfile
151+
152+
HEALTHCHECK --interval=1s CMD test -e /testfile
153+
CMD sleep 4 && touch /testfile
154+
"""
155+
dockerfile = tmp_path / "Dockerfile"
156+
dockerfile.write_text(textwrap.dedent(DOCKERFILE))
157+
with DockerImage(tmp_path) as image:
158+
yield image
159+
160+
161+
def test_wait_for_healthcheck_eventually_healthy(with_eventually_healthy_image: DockerImage):
162+
# Given
163+
with DockerContainer(str(with_eventually_healthy_image)) as container:
164+
# When
165+
container.wait_for_healthcheck()

0 commit comments

Comments
 (0)