Skip to content

Commit 598f893

Browse files
Merge pull request #55 from tillahoffmann/wait-for-logs
Add option to wait for logs.
2 parents 4f97070 + 1edf987 commit 598f893

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

testcontainers/core/waiting_utils.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
# under the License.
1313

1414

15-
from time import sleep
15+
import re
16+
import time
1617

1718
import blindspin
1819
import crayons
@@ -40,7 +41,7 @@ def wrapper(wrapped, instance, args, kwargs):
4041
try:
4142
return wrapped(*args, **kwargs)
4243
except Exception as e:
43-
sleep(config.SLEEP_TIME)
44+
time.sleep(config.SLEEP_TIME)
4445
exception = e
4546
raise TimeoutException(
4647
"""Wait time exceeded {0} sec.
@@ -55,3 +56,37 @@ def wrapper(wrapped, instance, args, kwargs):
5556
@wait_container_is_ready()
5657
def wait_for(condition):
5758
return condition()
59+
60+
61+
def wait_for_logs(container, predicate, timeout=None, interval=1):
62+
"""
63+
Wait for the container to emit logs satisfying the predicate.
64+
65+
Parameters
66+
----------
67+
container : DockerContainer
68+
Container whose logs to wait for.
69+
predicate : callable or str
70+
Predicate that should be satisfied by the logs. If a string, the it is used as the pattern
71+
for a multiline regular expression search.
72+
timeout : float or None
73+
Number of seconds to wait for the predicate to be satisfied. Defaults to wait indefinitely.
74+
interval : float
75+
Interval at which to poll the logs.
76+
77+
Returns
78+
-------
79+
duration : float
80+
Number of seconds until the predicate was satisfied.
81+
"""
82+
if isinstance(predicate, str):
83+
predicate = re.compile(predicate, re.MULTILINE).search
84+
start = time.time()
85+
while True:
86+
duration = time.time() - start
87+
if predicate(container._container.logs().decode()):
88+
return duration
89+
if timeout and duration > timeout:
90+
raise TimeoutError("container did not emit logs satisfying predicate in %.3f seconds"
91+
% timeout)
92+
time.sleep(interval)

tests/test_core.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import pytest
2+
3+
from testcontainers.core.container import DockerContainer
4+
from testcontainers.core.waiting_utils import wait_for_logs
5+
6+
7+
def test_raise_timeout():
8+
with pytest.raises(TimeoutError):
9+
with DockerContainer("alpine").with_command("sleep 2") as container:
10+
wait_for_logs(container, "Hello from Docker!", timeout=1e-3)
11+
12+
13+
def test_wait_for_hello():
14+
with DockerContainer("hello-world") as container:
15+
wait_for_logs(container, "Hello from Docker!")

tests/test_google.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from testcontainers.google import PubSubContainer
2+
from testcontainers.core.waiting_utils import wait_for_logs
23
from queue import Queue
34

45

56
def test_pubsub_container():
67
with PubSubContainer() as pubsub:
7-
import time; time.sleep(5)
8+
wait_for_logs(pubsub, r"Server started, listening on \d+", timeout=10)
89
# Create a new topic
910
publisher = pubsub.get_publisher_client()
1011
topic_path = publisher.topic_path(pubsub.project, "my-topic")

0 commit comments

Comments
 (0)