From 0096df78a52a00975b885405458420799437bc9b Mon Sep 17 00:00:00 2001 From: Brian Bjarke Jensen Date: Mon, 29 Jun 2026 15:00:45 +0200 Subject: [PATCH] Avoid testcontainers Redis deprecation warning in integration tests. Use a local RedisTestContainer with wait strategies instead of the deprecated RedisContainer, and keep conftest focused on fixtures. Co-authored-by: Cursor --- tests/integration/conftest.py | 23 ++++++++------- tests/integration/redis_container_test.py | 36 +++++++++++++++++++++++ 2 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 tests/integration/redis_container_test.py diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 9b4bfc6..933cd07 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -1,16 +1,19 @@ """Integration tests configuration.""" +import logging import os from collections.abc import Generator + import pytest import redis import structlog -import logging from minio import Minio - -from testcontainers.redis import RedisContainer from testcontainers.minio import MinioContainer +from tests.integration.redis_container_test import REDIS_PORT, RedisTestContainer + +collect_ignore = ["redis_container_test.py"] + MINIO_ACCESS_KEY = "minioadmin" MINIO_SECRET_KEY = "minioadmin" MINIO_BUCKET = "test-bucket" @@ -37,16 +40,16 @@ def configure_logging() -> None: @pytest.fixture(scope="session") -def redis_container() -> Generator[str]: +def redis_container() -> Generator[str, None, None]: """Set up a Redis container for testing and yield the Redis URI.""" # Start container - container = RedisContainer( + container = RedisTestContainer( image="redis/redis-stack:7.2.0-v0", ) container.start() # Set environment variable for Redis URI redis_host = container.get_container_host_ip() - redis_port = container.get_exposed_port(6379) + redis_port = container.get_exposed_port(REDIS_PORT) redis_uri = f"redis://{redis_host}:{redis_port}" yield redis_uri @@ -56,7 +59,7 @@ def redis_container() -> Generator[str]: @pytest.fixture(scope="session") -def minio_container() -> Generator[dict[str, str]]: +def minio_container() -> Generator[dict[str, str], None, None]: """Set up a Minio container for testing and yield the Minio URI.""" # Start container container = MinioContainer( @@ -86,7 +89,7 @@ def minio_container() -> Generator[dict[str, str]]: def set_environment_variables( redis_container: str, minio_container: dict[str, str], -) -> Generator[dict[str, str]]: +) -> Generator[dict[str, str], None, None]: """Set environment variables needed for tests.""" # Build environment variables dictionary env_vars = {"REDIS_URI": redis_container} @@ -103,7 +106,7 @@ def set_environment_variables( @pytest.fixture(scope="session") -def raw_redis_client(redis_container: str) -> Generator[redis.Redis]: +def raw_redis_client(redis_container: str) -> Generator[redis.Redis, None, None]: """Provide a raw Redis client connected to the test Redis container.""" # Connect client client = redis.Redis.from_url( @@ -119,7 +122,7 @@ def raw_redis_client(redis_container: str) -> Generator[redis.Redis]: @pytest.fixture(scope="session") -def raw_minio_client(minio_container: dict[str, str]) -> Generator[Minio]: +def raw_minio_client(minio_container: dict[str, str]) -> Generator[Minio, None, None]: """Provide a raw Minio client connected to the test Minio container.""" # Connect client client = Minio( diff --git a/tests/integration/redis_container_test.py b/tests/integration/redis_container_test.py new file mode 100644 index 0000000..51e6712 --- /dev/null +++ b/tests/integration/redis_container_test.py @@ -0,0 +1,36 @@ +"""Redis test container without testcontainers' deprecated wait decorator.""" + +from typing import Any, cast + +import redis +from testcontainers.core.container import DockerContainer +from testcontainers.core.waiting_utils import WaitStrategy, WaitStrategyTarget + +REDIS_PORT = 6379 + + +class _RedisPingWaitStrategy(WaitStrategy): + def __init__(self) -> None: + super().__init__() + self.with_transient_exceptions(redis.exceptions.ConnectionError) + + def wait_until_ready(self, container: WaitStrategyTarget) -> None: + redis_container = cast("RedisTestContainer", container) + if not self._poll(lambda: redis_container.get_client().ping()): + raise redis.exceptions.ConnectionError("Could not connect to Redis") + + +class RedisTestContainer(DockerContainer): + """Redis container using wait strategies instead of the deprecated decorator.""" + + def __init__(self, image: str, port: int = REDIS_PORT) -> None: + super().__init__(image, _wait_strategy=_RedisPingWaitStrategy()) + self.port = port + self.with_exposed_ports(self.port) + + def get_client(self, **kwargs: Any) -> redis.Redis: + return redis.Redis( + host=self.get_container_host_ip(), + port=self.get_exposed_port(self.port), + **kwargs, + )