"""init-db / reset-db con _stamp_head REALE su un file SQLite (TieMeasureFlow#80). _stamp_head esegue migrations/env.py, che chiama asyncio.run(): dentro il loop gia' attivo di FastAPI dava RuntimeError -> 500. test_setup.py e test_station_seed.py sostituiscono _stamp_head con un no-op e non lo vedevano: qui NON si fa monkeypatch di _stamp_head. """ import logging.config import sqlite3 import pytest from alembic.config import Config from alembic.script import ScriptDirectory from httpx import ASGITransport, AsyncClient from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine from src.backend.config import settings from src.backend.main import app SETUP_PWD = "test-setup-password" @pytest.fixture def file_db(tmp_path, monkeypatch): """Punta settings, engine e session factory del router setup a un file SQLite.""" import src.backend.api.routers.setup as setup_mod db_file = tmp_path / "t.db" url = f"sqlite+aiosqlite:///{db_file.as_posix()}" # env.py ricava sqlalchemy.url da settings.database_url (property su db_url) monkeypatch.setattr(settings, "db_url", url) monkeypatch.setattr(settings, "setup_password", SETUP_PWD) file_engine = create_async_engine(url, echo=False) monkeypatch.setattr(setup_mod, "engine", file_engine) monkeypatch.setattr( setup_mod, "async_session_factory", async_sessionmaker(file_engine, expire_on_commit=False), ) # env.py chiama fileConfig, che disattiverebbe i logger degli altri test monkeypatch.setattr(logging.config, "fileConfig", lambda *a, **k: None) return db_file, setup_mod, file_engine def _head() -> str: from src.backend.api.routers.setup import _alembic_ini cfg = Config(str(_alembic_ini)) return ScriptDirectory.from_config(cfg).get_current_head() def _versions(db_file) -> list[str]: con = sqlite3.connect(db_file) try: return [r[0] for r in con.execute("SELECT version_num FROM alembic_version")] finally: con.close() @pytest.fixture async def http(): async with AsyncClient(transport=ASGITransport(app=app), base_url="http://testserver") as ac: yield ac @pytest.mark.asyncio async def test_init_db_stamps_head(file_db, http): db_file, _, file_engine = file_db resp = await http.post("/api/setup/init-db", json={"password": SETUP_PWD}) assert resp.status_code == 200, resp.text assert _versions(db_file) == [_head()] await file_engine.dispose() @pytest.mark.asyncio async def test_reset_db_stamps_head(file_db, http): db_file, _, file_engine = file_db resp = await http.post("/api/setup/init-db", json={"password": SETUP_PWD}) assert resp.status_code == 200, resp.text resp = await http.post("/api/setup/reset-db", json={"password": SETUP_PWD, "confirm": True}) assert resp.status_code == 200, resp.text assert _versions(db_file) == [_head()] await file_engine.dispose()