"""Migration runner + SQLite pragma sanity tests.""" from __future__ import annotations import sqlite3 from pathlib import Path import pytest from cerbero_bite.state.db import ( connect, current_version, list_migrations, run_migrations, transaction, ) def test_list_migrations_is_ordered_and_starts_with_0001() -> None: migs = list_migrations() assert migs, "expected at least one migration file" versions = [m[0] for m in migs] assert versions == sorted(versions) assert versions[0] == 1 def test_run_migrations_creates_full_schema(tmp_path: Path) -> None: db_path = tmp_path / "state.sqlite" conn = connect(db_path) try: new_version = run_migrations(conn) assert new_version == max(m[0] for m in list_migrations()) # Sanity: every documented table is present. existing = { row["name"] for row in conn.execute( "SELECT name FROM sqlite_master WHERE type='table'" ).fetchall() } assert { "positions", "instructions", "decisions", "dvol_history", "manual_actions", "system_state", } <= existing finally: conn.close() def test_run_migrations_is_idempotent(tmp_path: Path) -> None: db_path = tmp_path / "state.sqlite" conn = connect(db_path) try: run_migrations(conn) first = current_version(conn) run_migrations(conn) # second call must be a no-op assert current_version(conn) == first finally: conn.close() def test_pragmas_applied(tmp_path: Path) -> None: db_path = tmp_path / "state.sqlite" conn = connect(db_path) try: run_migrations(conn) assert conn.execute("PRAGMA foreign_keys").fetchone()[0] == 1 # WAL is sticky on the file: confirm via the journal_mode pragma. mode = conn.execute("PRAGMA journal_mode").fetchone()[0] assert mode.lower() == "wal" finally: conn.close() def test_transaction_rolls_back_on_exception(tmp_path: Path) -> None: db_path = tmp_path / "state.sqlite" conn = connect(db_path) try: run_migrations(conn) with pytest.raises(RuntimeError, match="boom"), transaction(conn): conn.execute( "INSERT INTO system_state(id, last_health_check, " "config_version, started_at) VALUES (1, '2026-04-27', " "'1.0.0', '2026-04-27')" ) raise RuntimeError("boom") # Row was rolled back. rows = conn.execute("SELECT COUNT(*) FROM system_state").fetchone()[0] assert rows == 0 finally: conn.close() def test_foreign_key_enforcement(tmp_path: Path) -> None: db_path = tmp_path / "state.sqlite" conn = connect(db_path) try: run_migrations(conn) # Inserting an instruction without a parent position must fail. with pytest.raises(sqlite3.IntegrityError): conn.execute( "INSERT INTO instructions(instruction_id, proposal_id, kind, " "payload_json, sent_at) VALUES (?, ?, ?, ?, ?)", ("i1", "missing", "open_combo", "{}", "2026-04-27"), ) finally: conn.close()