From 436575410a2906a695b96af66ff55c9ccb8e09a7 Mon Sep 17 00:00:00 2001 From: David Ankin Date: Fri, 27 Sep 2024 04:47:32 -0400 Subject: [PATCH 1/2] fix: postgres use psql instead of logs (#704) logs may be dependent on a particular locale fixes: #703, #695 --- .../testcontainers/postgres/__init__.py | 54 ++++--------------- modules/postgres/tests/test_postgres.py | 12 ++++- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/modules/postgres/testcontainers/postgres/__init__.py b/modules/postgres/testcontainers/postgres/__init__.py index c9ba2a22..bde21d5b 100644 --- a/modules/postgres/testcontainers/postgres/__init__.py +++ b/modules/postgres/testcontainers/postgres/__init__.py @@ -11,13 +11,11 @@ # License for the specific language governing permissions and limitations # under the License. import os -from time import sleep from typing import Optional -from testcontainers.core.config import testcontainers_config as c from testcontainers.core.generic import DbContainer from testcontainers.core.utils import raise_for_deprecated_parameter -from testcontainers.core.waiting_utils import wait_container_is_ready, wait_for_logs +from testcontainers.core.waiting_utils import wait_container_is_ready _UNSET = object() @@ -91,45 +89,13 @@ def get_connection_url(self, host: Optional[str] = None, driver: Optional[str] = @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 - - wait_for_logs( - self, - ".*database system is ready to accept connections.*", - c.max_tries, - c.sleep_time, - predicate_streams_and=predicate_streams_and, - # + escaped_single_password = self.password.replace("'", "'\"'\"'") + result = self.exec( + [ + "sh", + "-c", + f"PGPASSWORD='{escaped_single_password}' psql --username {self.username} --dbname {self.dbname} --host 127.0.0.1 -c 'select version();'", + ] ) - - 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") + if result.exit_code: + raise ConnectionError("pg_isready is not ready yet") diff --git a/modules/postgres/tests/test_postgres.py b/modules/postgres/tests/test_postgres.py index 42bcfe85..6bbd0ba7 100644 --- a/modules/postgres/tests/test_postgres.py +++ b/modules/postgres/tests/test_postgres.py @@ -1,9 +1,9 @@ from pathlib import Path import pytest +import sqlalchemy from testcontainers.postgres import PostgresContainer -import sqlalchemy # https://www.postgresql.org/support/versioning/ @@ -46,6 +46,16 @@ def test_docker_run_postgres_with_driver_pg8000(): connection.execute(sqlalchemy.text("select 1=1")) +def test_password_with_quotes(): + postgres_container = PostgresContainer("postgres:9.5", password="'''''") + with postgres_container as postgres: + engine = sqlalchemy.create_engine(postgres.get_connection_url()) + with engine.begin() as connection: + result = connection.execute(sqlalchemy.text("select version()")) + for row in result: + assert row[0].lower().startswith("postgresql 9.5") + + # This is a feature in the generic DbContainer class # but it can't be tested on its own # so is tested in various database modules: From 85d6078f9bcc99050c0173e459208402aa4f5026 Mon Sep 17 00:00:00 2001 From: David Ankin Date: Fri, 27 Sep 2024 04:49:17 -0400 Subject: [PATCH 2/2] fix: mysql typo (#705) fixes #689 --- modules/mysql/testcontainers/mysql/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mysql/testcontainers/mysql/__init__.py b/modules/mysql/testcontainers/mysql/__init__.py index 46efbcfb..c4449593 100644 --- a/modules/mysql/testcontainers/mysql/__init__.py +++ b/modules/mysql/testcontainers/mysql/__init__.py @@ -46,7 +46,7 @@ class MySqlContainer(DbContainer): The optional :code:`seed` parameter enables arbitrary SQL files to be loaded. This is perfect for schema and sample data. This works by mounting the seed to - `/docker-entrypoint-initdb./d`, which containerized MySQL are set up to load + `/docker-entrypoint-initdb.d/`, which containerized MySQL are set up to load automatically. .. doctest::