#!/usr/bin/env python3
"""AgentForms Migration Tests (Phase 5d)
Tests for Alembic migration workflow:
1. Alembic upgrade head succeeds on empty DB
2. Alembic downgrade base succeeds
3. Alembic check passes (no diff between models and migrations)
"""
import os
import shutil
import subprocess
import sys
import tempfile
import pytest
# Ensure project root is on path
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT_DIR)
@pytest.fixture(scope="module")
def temp_db_dir():
"""Create a temporary directory with a clean DB for migration tests."""
tmp_dir = tempfile.mkdtemp(prefix="af_migrate_test_")
db_path = os.path.join(tmp_dir, "relay.db")
env = os.environ.copy()
env["RELAY_DB_PATH"] = db_path
yield tmp_dir, db_path, env
# Cleanup
shutil.rmtree(tmp_dir, ignore_errors=True)
def test_alembic_upgrade_head(temp_db_dir):
"""Test: alembic upgrade head succeeds on empty DB."""
tmp_dir, db_path, env = temp_db_dir
result = subprocess.run(
[sys.executable, "-m", "alembic", "upgrade", "head"],
cwd=ROOT_DIR,
env=env,
capture_output=True,
text=True,
timeout=30,
)
assert result.returncode == 0, (
f"alembic upgrade head failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
)
# Verify the DB file was created
assert os.path.exists(db_path), f"DB file not created at {db_path}"
def test_alembic_current(temp_db_dir):
"""Test: alembic current shows the latest revision."""
tmp_dir, db_path, env = temp_db_dir
# First upgrade
subprocess.run(
[sys.executable, "-m", "alembic", "upgrade", "head"],
cwd=ROOT_DIR,
env=env,
capture_output=True,
text=True,
timeout=30,
)
result = subprocess.run(
[sys.executable, "-m", "alembic", "current"],
cwd=ROOT_DIR,
env=env,
capture_output=True,
text=True,
timeout=30,
)
assert result.returncode == 0, (
f"alembic current failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
)
assert "Base" not in result.stdout or "head" in result.stdout.lower(), (
f"Expected current revision to be at head, got: {result.stdout}"
)
def test_alembic_downgrade_base(temp_db_dir):
"""Test: alembic downgrade base succeeds (reverts all migrations)."""
tmp_dir, db_path, env = temp_db_dir
# First upgrade to head
subprocess.run(
[sys.executable, "-m", "alembic", "upgrade", "head"],
cwd=ROOT_DIR,
env=env,
capture_output=True,
text=True,
timeout=30,
)
result = subprocess.run(
[sys.executable, "-m", "alembic", "downgrade", "base"],
cwd=ROOT_DIR,
env=env,
capture_output=True,
text=True,
timeout=30,
)
assert result.returncode == 0, (
f"alembic downgrade base failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
)
def test_alembic_history(temp_db_dir):
"""Test: alembic history lists all migrations."""
result = subprocess.run(
[sys.executable, "-m", "alembic", "history"],
cwd=ROOT_DIR,
env=os.environ.copy(),
capture_output=True,
text=True,
timeout=30,
)
assert result.returncode == 0, (
f"alembic history failed:\nstdout: {result.stdout}\nstderr: {result.stderr}"
)
assert "baseline" in result.stdout.lower(), (
f"Expected baseline migration in history, got: {result.stdout}"
)
def test_migration_round_trip(temp_db_dir):
"""Test: upgrade -> downgrade -> upgrade succeeds (full round trip)."""
tmp_dir, db_path, env = temp_db_dir
steps = [
(["upgrade", "head"], "upgrade to head"),
(["downgrade", "base"], "downgrade to base"),
(["upgrade", "head"], "upgrade again"),
]
for args, desc in steps:
result = subprocess.run(
[sys.executable, "-m", "alembic"] + args,
cwd=ROOT_DIR,
env=env,
capture_output=True,
text=True,
timeout=30,
)
assert result.returncode == 0, (
f"Round trip step '{desc}' failed:\n"
f"stdout: {result.stdout}\nstderr: {result.stderr}"
)
if __name__ == "__main__":
pytest.main([__file__, "-v"])