testcontainers / testcontainers-python

Testcontainers is a Python library that providing a friendly API to run Docker container. It is designed to create runtime environment to use during your automatic tests.
https://testcontainers-python.readthedocs.io/en/latest/
Apache License 2.0
1.53k stars 280 forks source link

Bug: postgres container expects English log line to ensure started #695

Open dhofstetter opened 1 week ago

dhofstetter commented 1 week ago

Describe the bug

When starting a Postgres Testcontainer, the implementation expects a log line like the latter to ensure its properly started

.*database system is ready to accept connections.*

In case you have a custom Postgres image (e.g. with lang/locales changed) this log line might not appear as expected.

To Reproduce

FROM postgres:16

RUN locale-gen de_AT.utf8 \
    && localedef -i de_AT -c -f UTF-8 -A /usr/share/locale/locale.alias de_AT.UTF-8
ENV LANG=de_AT.utf8

use the dockerfile above, and the log lines are more like

2024-09-03 15:35:48.551 UTC [1] LOG:  erwarte Verbindungen auf IPv4-Adresse »0.0.0.0«, Port 5432
2024-09-03 15:35:48.551 UTC [1] LOG:  erwarte Verbindungen auf IPv6-Adresse »::«, Port 5432
2024-09-03 15:35:48.554 UTC [1] LOG:  erwarte Verbindungen auf Unix-Socket »/var/run/postgresql/.s.PGSQL.5432«
2024-09-03 15:35:48.557 UTC [63] LOG:  Datenbanksystem wurde am 2024-09-03 15:35:48 UTC heruntergefahren
2024-09-03 15:35:48.561 UTC [1] LOG:  Datenbanksystem ist bereit, um Verbindungen anzunehmen

I think that using pg_isready is sufficient - so changing the code of PostgresContainer to

@wait_container_is_ready()
    def _connect(self) -> None:
        # postgres itself logs these messages to the standard error stream:
        #
        # $ /opt/homebrew/opt/postgresql@14/bin/postgres -D /opt/homebrew/var/postgresql@14 \
        # > | grep -o -a -m 1 -h 'database system is ready to accept connections'
        # 2024-08-03 00:13:02.799 EDT [70226] LOG:  starting PostgreSQL 14.11 (Homebrew) ....
        # 2024-08-03 00:13:02.804 EDT [70226] LOG:  listening on IPv4 address "127.0.0.1", port 5432
        # ...
        # ^C2024-08-03 00:13:04.226 EDT [70226] LOG:  received fast shutdown request
        # ...
        #
        # $ /opt/homebrew/opt/postgresql@14/bin/postgres -D /opt/homebrew/var/postgresql@14 2>&1 \
        # > | grep -o -a -m 1 -h 'database system is ready to accept connections'
        # database system is ready to accept connections
        #
        # and the setup script inside docker library postgres
        # uses pg_ctl:
        # https://github.com/docker-library/postgres/blob/66da3846b40396249936938ee17e9684e6968a57/16/alpine3.20/docker-entrypoint.sh#L261-L282
        # which prints logs to stdout:
        # https://www.postgresql.org/docs/current/app-pg-ctl.html#:~:text=the%20server%27s%20standard%20output%20and%20standard%20error%20are%20sent%20to%20pg_ctl%27s%20standard%20output
        #
        # so we must wait for both the setup and real startup:
        predicate_streams_and = True

        # as the wait for logs is commented out, we can start all kinds of containers (even non English ones)
        #wait_for_logs(
        #    self,
        #    ".*database system is ready to accept connections.*",
        #    c.max_tries,
        #    c.sleep_time,
        #    predicate_streams_and=predicate_streams_and,
        #    #
        #)

        count = 0
        while count < c.max_tries:
            status, _ = self.exec(f"pg_isready -hlocalhost -p{self.port} -U{self.username}")
            if status == 0:
                return

            sleep(c.sleep_time)
            count += 1

        raise RuntimeError("Postgres could not get into a ready state")

works like a charm.

alexanderankin commented 1 week ago

sounds good, i would merge a pull request that specifies the reason for this change in a comment + linking to this issue. perhaps maybe also a test with a different locale as described above.

apologies, did not consider this case in my testing, we have been trying to rely on logs as a more reliable/universal way to detect most of the community containers