58 lines
1.9 KiB
Python
58 lines
1.9 KiB
Python
from collections.abc import Generator
|
|
|
|
import pytest
|
|
|
|
# Attempt import of testcontainers
|
|
postgres_container_cls = None
|
|
try:
|
|
try:
|
|
from testcontainers.community.postgres import PostgresContainer as _PostgresContainer
|
|
|
|
postgres_container_cls = _PostgresContainer
|
|
except ImportError:
|
|
from testcontainers.postgres import PostgresContainer as _PostgresContainer
|
|
|
|
postgres_container_cls = _PostgresContainer
|
|
except ImportError:
|
|
postgres_container_cls = None
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def postgres_container_url() -> Generator[str]:
|
|
"""Provides a disposable PostgreSQL 16 container URL strictly via Docker testcontainers.
|
|
|
|
Scoped to session to avoid duplicating container startup across tests.
|
|
No ambient admin or SQLite fallbacks.
|
|
"""
|
|
if postgres_container_cls is None:
|
|
raise RuntimeError(
|
|
"testcontainers package is required for PostgreSQL integration tests. "
|
|
"SQLite/localhost fallbacks are strictly prohibited."
|
|
)
|
|
|
|
try:
|
|
container = postgres_container_cls("postgres:16-alpine")
|
|
container.start()
|
|
host = container.get_container_host_ip()
|
|
port = container.get_exposed_port(5432)
|
|
user = container.username
|
|
password = container.password
|
|
dbname = container.dbname
|
|
url = f"postgresql+asyncpg://{user}:{password}@{host}:{port}/{dbname}"
|
|
try:
|
|
yield url
|
|
finally:
|
|
container.stop()
|
|
except Exception as exc:
|
|
raise RuntimeError(
|
|
f"Failed to start PostgreSQL testcontainer: {exc}. "
|
|
"Docker daemon must be running and accessible for integration tests. "
|
|
"SQLite/localhost fallbacks are prohibited."
|
|
) from exc
|
|
|
|
|
|
@pytest.fixture
|
|
def temp_postgres_db(postgres_container_url: str) -> str:
|
|
"""Yields disposable PostgreSQL container database URL."""
|
|
return postgres_container_url
|