107 lines
3.2 KiB
Python
107 lines
3.2 KiB
Python
import asyncio
|
|
import os
|
|
import sys
|
|
from collections.abc import AsyncIterator, Iterator
|
|
from pathlib import Path
|
|
|
|
import httpx2
|
|
import pytest
|
|
import pytest_asyncio
|
|
from fastapi import FastAPI
|
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
|
from testcontainers.community.postgres import PostgresContainer
|
|
from testcontainers.core.container import DockerContainer
|
|
from testcontainers.core.wait_strategies import LogMessageWaitStrategy
|
|
|
|
from app.api import router
|
|
from app.auth import get_settings
|
|
from app.config import Settings
|
|
from app.db import Base, get_session
|
|
|
|
PROJECT_ROOT = Path(__file__).parents[2]
|
|
|
|
|
|
async def migrate_to_head(database_url: str) -> None:
|
|
process = await asyncio.create_subprocess_exec(
|
|
sys.executable,
|
|
"-m",
|
|
"alembic",
|
|
"upgrade",
|
|
"head",
|
|
cwd=PROJECT_ROOT,
|
|
env={**os.environ, "DATABASE_URL": database_url},
|
|
)
|
|
assert await process.wait() == 0
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def postgres_url() -> Iterator[str]:
|
|
with PostgresContainer("postgres:16-alpine", driver=None) as postgres:
|
|
url = postgres.get_connection_url(driver=None)
|
|
yield url.replace("postgresql://", "postgresql+asyncpg://", 1)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def rabbitmq_url() -> Iterator[str]:
|
|
rabbitmq = (
|
|
DockerContainer("rabbitmq:3.13-alpine")
|
|
.with_exposed_ports(5672)
|
|
.with_env("RABBITMQ_DEFAULT_USER", "payments")
|
|
.with_env("RABBITMQ_DEFAULT_PASS", "payments")
|
|
.waiting_for(LogMessageWaitStrategy("Server startup complete").with_startup_timeout(60))
|
|
)
|
|
with rabbitmq:
|
|
host = rabbitmq.get_container_host_ip()
|
|
port = rabbitmq.get_exposed_port(5672)
|
|
yield f"amqp://payments:payments@{host}:{port}/"
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def database(
|
|
postgres_url: str,
|
|
) -> AsyncIterator[async_sessionmaker[AsyncSession]]:
|
|
engine = create_async_engine(postgres_url)
|
|
async with engine.begin() as connection:
|
|
await connection.run_sync(Base.metadata.drop_all)
|
|
await connection.exec_driver_sql("DROP TABLE IF EXISTS alembic_version")
|
|
await engine.dispose()
|
|
|
|
await migrate_to_head(postgres_url)
|
|
|
|
engine = create_async_engine(postgres_url)
|
|
factory = async_sessionmaker(engine, expire_on_commit=False)
|
|
try:
|
|
yield factory
|
|
finally:
|
|
await engine.dispose()
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def db_session(
|
|
database: async_sessionmaker[AsyncSession],
|
|
) -> AsyncIterator[AsyncSession]:
|
|
async with database() as session:
|
|
yield session
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def api_client(
|
|
database: async_sessionmaker[AsyncSession],
|
|
) -> AsyncIterator[httpx2.AsyncClient]:
|
|
app = FastAPI()
|
|
app.include_router(router)
|
|
|
|
async def override_session() -> AsyncIterator[AsyncSession]:
|
|
async with database() as session:
|
|
yield session
|
|
|
|
app.dependency_overrides[get_session] = override_session
|
|
app.dependency_overrides[get_settings] = lambda: Settings(api_key="test-key")
|
|
|
|
transport = httpx2.ASGITransport(app=app)
|
|
async with httpx2.AsyncClient(
|
|
transport=transport,
|
|
base_url="http://testserver",
|
|
) as client:
|
|
yield client
|