"""PostgreSQL and session-lifecycle integration coverage.""" from __future__ import annotations import asyncio import sys from pathlib import Path import pytest import pytest_asyncio from alembic import command from alembic.config import Config from sqlalchemy import text from ragcore.config import Settings from ragcore.infrastructure.database import ( create_database_engine, create_session_factory, session_scope, ) REPOSITORY_ROOT = Path(__file__).resolve().parents[3] @pytest.fixture(scope="session") def event_loop_policy(): if sys.platform == "win32": return asyncio.WindowsSelectorEventLoopPolicy() return asyncio.get_event_loop_policy() @pytest.fixture(scope="module") def alembic_config() -> Config: return Config(str(REPOSITORY_ROOT / "alembic.ini")) @pytest_asyncio.fixture async def session_factory(): engine = create_database_engine(Settings(env="test")) try: yield create_session_factory(engine) finally: await engine.dispose() def test_empty_database_can_upgrade_downgrade_and_upgrade(alembic_config: Config) -> None: command.upgrade(alembic_config, "head") command.downgrade(alembic_config, "base") command.upgrade(alembic_config, "head") @pytest.mark.asyncio async def test_postgresql_session_executes_query(session_factory) -> None: async with session_scope(session_factory) as session: result = await session.execute(text("SELECT 1")) assert result.scalar_one() == 1 class _RecordingSession: def __init__(self) -> None: self.closed = False self.rolled_back = False async def __aenter__(self) -> _RecordingSession: return self async def __aexit__(self, *_: object) -> None: self.closed = True async def rollback(self) -> None: self.rolled_back = True class _RecordingFactory: def __init__(self, session: _RecordingSession) -> None: self.session = session def __call__(self) -> _RecordingSession: return self.session @pytest.mark.asyncio async def test_session_scope_rolls_back_and_closes_on_failure() -> None: recording_session = _RecordingSession() with pytest.raises(RuntimeError, match="boom"): async with session_scope(_RecordingFactory(recording_session)): raise RuntimeError("boom") assert recording_session.rolled_back assert recording_session.closed