AgentEvalTool/tests/unit/test_campaign_run_identity_migration.py

86 lines
3.7 KiB
Python

"""Verify durable Campaign child-Run identity migration semantics."""
import importlib
import sqlalchemy as sa
from alembic.migration import MigrationContext
from alembic.operations import Operations
def _legacy_eval_runs(connection) -> None:
connection.execute(sa.text("CREATE TABLE campaigns (id VARCHAR PRIMARY KEY)"))
connection.execute(
sa.text(
"CREATE TABLE eval_runs ("
"id VARCHAR PRIMARY KEY, campaign_id VARCHAR NULL, "
"status VARCHAR NOT NULL)"
)
)
connection.execute(sa.text("INSERT INTO eval_runs (id, campaign_id, status) VALUES ('old', NULL, 'completed')"))
def test_campaign_run_identity_migration_is_nullable_unique_and_reversible(tmp_path):
engine = sa.create_engine(f"sqlite:///{tmp_path / 'campaign-run-identity.db'}")
migration = importlib.import_module(
"migrations.versions.c2f4a6b8d0e1_add_campaign_run_identity"
)
with engine.begin() as connection:
_legacy_eval_runs(connection)
operations = Operations(MigrationContext.configure(connection))
migration.op = operations
migration.upgrade()
inspector = sa.inspect(connection)
columns = {column["name"]: column for column in inspector.get_columns("eval_runs")}
assert columns["campaign_plan_index"]["nullable"] is True
assert columns["campaign_occurrence_index"]["nullable"] is True
assert connection.execute(sa.text("SELECT campaign_plan_index, campaign_occurrence_index FROM eval_runs WHERE id='old'")) .one() == (None, None)
indexes = inspector.get_indexes("eval_runs")
assert any(
index["name"] == "uq_eval_runs_campaign_occurrence"
and bool(index["unique"])
and index["column_names"] == ["campaign_id", "campaign_plan_index", "campaign_occurrence_index"]
for index in indexes
)
connection.execute(
sa.text(
"INSERT INTO eval_runs (id, campaign_id, campaign_plan_index, campaign_occurrence_index, status) "
"VALUES ('child-1', 'campaign-1', 0, 0, 'pending')"
)
)
try:
connection.execute(
sa.text(
"INSERT INTO eval_runs (id, campaign_id, campaign_plan_index, campaign_occurrence_index, status) "
"VALUES ('child-duplicate', 'campaign-1', 0, 0, 'pending')"
)
)
except sa.exc.IntegrityError:
pass
else: # pragma: no cover - assertion guard
raise AssertionError("Campaign child identity must be unique")
migration.downgrade()
assert "campaign_plan_index" not in {column["name"] for column in sa.inspect(connection).get_columns("eval_runs")}
assert "campaign_occurrence_index" not in {column["name"] for column in sa.inspect(connection).get_columns("eval_runs")}
def test_fresh_schema_exposes_same_identity_columns_and_unique_index(tmp_path):
"""SQLModel's fresh-database path matches the Alembic contract."""
from agenteval.storage.db import EvalRunDB # noqa: F401 - register table
from sqlmodel import SQLModel, create_engine
engine = create_engine(f"sqlite:///{tmp_path / 'fresh.db'}")
SQLModel.metadata.create_all(engine)
inspector = sa.inspect(engine)
columns = {column["name"] for column in inspector.get_columns("eval_runs")}
assert {"campaign_plan_index", "campaign_occurrence_index"} <= columns
assert any(
index["name"] == "uq_eval_runs_campaign_occurrence"
and bool(index["unique"])
and index["column_names"] == ["campaign_id", "campaign_plan_index", "campaign_occurrence_index"]
for index in inspector.get_indexes("eval_runs")
)