From deb6a6a381b3f8c4c688a831083bed6dc6315769 Mon Sep 17 00:00:00 2001 From: David Ankin Date: Wed, 16 Oct 2024 09:04:12 -0400 Subject: [PATCH 1/3] fix: update wait_for_logs to not throw on "created" wait_for_logs has a mode for throwing on exit, it will now no longer treat "created" as an exit status --- core/testcontainers/core/waiting_utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/testcontainers/core/waiting_utils.py b/core/testcontainers/core/waiting_utils.py index 2bd7806ba..de8fccfb2 100644 --- a/core/testcontainers/core/waiting_utils.py +++ b/core/testcontainers/core/waiting_utils.py @@ -77,6 +77,9 @@ def wait_for(condition: Callable[..., bool]) -> bool: return condition() +_NOT_EXITED_STATUSES = {"running", "created"} + + def wait_for_logs( container: "DockerContainer", predicate: Union[Callable, str], @@ -118,6 +121,6 @@ def wait_for_logs( return duration if duration > timeout: raise TimeoutError(f"Container did not emit logs satisfying predicate in {timeout:.3f} " "seconds") - if raise_on_exit and container.get_wrapped_container().status != "running": + if raise_on_exit and container.get_wrapped_container().status not in _NOT_EXITED_STATUSES: raise RuntimeError("Container exited before emitting logs satisfying predicate") time.sleep(interval) From 08bf23f2b27ccdb0a9209414eb61592e4574038c Mon Sep 17 00:00:00 2001 From: Marc Schmitzer Date: Thu, 17 Oct 2024 11:07:20 +0200 Subject: [PATCH 2/3] fix(core): Reload container in wait_for_logs before checking status The status is cached on the Model instance. Without the reload, we always see the first value that was loaded. --- core/testcontainers/core/waiting_utils.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/testcontainers/core/waiting_utils.py b/core/testcontainers/core/waiting_utils.py index de8fccfb2..a08702ef4 100644 --- a/core/testcontainers/core/waiting_utils.py +++ b/core/testcontainers/core/waiting_utils.py @@ -106,6 +106,7 @@ def wait_for_logs( """ if isinstance(predicate, str): predicate = re.compile(predicate, re.MULTILINE).search + wrapped = container.get_wrapped_container() start = time.time() while True: duration = time.time() - start @@ -121,6 +122,8 @@ def wait_for_logs( return duration if duration > timeout: raise TimeoutError(f"Container did not emit logs satisfying predicate in {timeout:.3f} " "seconds") - if raise_on_exit and container.get_wrapped_container().status not in _NOT_EXITED_STATUSES: - raise RuntimeError("Container exited before emitting logs satisfying predicate") + if raise_on_exit: + wrapped.reload() + if wrapped.status not in _NOT_EXITED_STATUSES: + raise RuntimeError("Container exited before emitting logs satisfying predicate") time.sleep(interval) From e2631d598e69c6e7a52ab58fb5ac427d90e9db81 Mon Sep 17 00:00:00 2001 From: Marc Schmitzer Date: Thu, 17 Oct 2024 11:11:13 +0200 Subject: [PATCH 3/3] fix(core): Don't call "logs" twice in wait_for_logs --- core/testcontainers/core/waiting_utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/testcontainers/core/waiting_utils.py b/core/testcontainers/core/waiting_utils.py index a08702ef4..8966e5f99 100644 --- a/core/testcontainers/core/waiting_utils.py +++ b/core/testcontainers/core/waiting_utils.py @@ -110,8 +110,9 @@ def wait_for_logs( start = time.time() while True: duration = time.time() - start - stdout = container.get_logs()[0].decode() - stderr = container.get_logs()[1].decode() + stdout, stderr = container.get_logs() + stdout = stdout.decode() + stderr = stderr.decode() predicate_result = ( predicate(stdout) or predicate(stderr) if predicate_streams_and is False