mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/jxxghp/MoviePilot.git
synced 2026-09-20 08:03:34 +08:00
81 lines
3.7 KiB
Python
81 lines
3.7 KiB
Python
"""Agent 写工具持久回执的 SQLite 迁移与模型一致性测试。"""
|
|
|
|
import importlib
|
|
|
|
import sqlalchemy as sa
|
|
from alembic.migration import MigrationContext
|
|
from alembic.operations import Operations
|
|
from sqlalchemy.dialects import postgresql
|
|
from sqlalchemy.schema import CreateTable
|
|
|
|
from app.db.models.agentinvocation import AgentInvocation
|
|
|
|
MIGRATION = "database.versions.b2d4f6a8c1e3_3_0_33"
|
|
|
|
|
|
def _bind_migration(monkeypatch, connection):
|
|
"""将迁移指令绑定到测试独占数据库。"""
|
|
migration = importlib.import_module(MIGRATION)
|
|
monkeypatch.setattr(migration, "op", Operations(MigrationContext.configure(connection)))
|
|
return migration
|
|
|
|
|
|
def test_invocation_migration_upgrade_and_downgrade_are_replay_safe(monkeypatch):
|
|
"""已有 SQLite 能重复升级和降级,原有业务表保持不变。"""
|
|
engine = sa.create_engine("sqlite://")
|
|
with engine.begin() as connection:
|
|
connection.execute(sa.text("CREATE TABLE existing_data (id INTEGER PRIMARY KEY)"))
|
|
migration = _bind_migration(monkeypatch, connection)
|
|
migration.upgrade()
|
|
migration.upgrade()
|
|
inspector = sa.inspect(connection)
|
|
assert "agentinvocation" in inspector.get_table_names()
|
|
assert {column["name"] for column in inspector.get_columns("agentinvocation")} == {
|
|
column.name for column in AgentInvocation.__table__.columns
|
|
}
|
|
indexes = {index["name"]: index for index in inspector.get_indexes("agentinvocation")}
|
|
identity = indexes["ix_agentinvocation_identity"]
|
|
assert identity["unique"]
|
|
assert identity["column_names"] == ["principal_id", "session_id", "invocation_id"]
|
|
assert inspector.get_check_constraints("agentinvocation")[0]["name"] == "ck_agentinvocation_status"
|
|
connection.execute(sa.insert(AgentInvocation).values(
|
|
principal_id="owner", session_id="session", invocation_id="call",
|
|
tool_name="moviepilot_api", arguments_digest="a" * 64, claim_token="b" * 32,
|
|
status="pending", summary="已确认提交", created_at="2026-09-09T00:00:00+00:00",
|
|
updated_at="2026-09-09T00:00:00+00:00",
|
|
))
|
|
assert connection.execute(sa.select(AgentInvocation.status)).scalar_one() == "pending"
|
|
migration.downgrade()
|
|
migration.downgrade()
|
|
assert sa.inspect(connection).get_table_names() == ["existing_data"]
|
|
engine.dispose()
|
|
|
|
|
|
def test_invocation_migration_accepts_current_model_tables(monkeypatch):
|
|
"""全新数据库 create_all 后运行 Alembic 不应重复创建表或索引。"""
|
|
engine = sa.create_engine("sqlite://")
|
|
with engine.begin() as connection:
|
|
AgentInvocation.__table__.create(connection)
|
|
migration = _bind_migration(monkeypatch, connection)
|
|
migration.upgrade()
|
|
migration.upgrade()
|
|
actual = {
|
|
(index["name"], tuple(index["column_names"]), bool(index["unique"]))
|
|
for index in sa.inspect(connection).get_indexes("agentinvocation")
|
|
}
|
|
expected = {
|
|
(index.name, tuple(column.name for column in index.columns), index.unique)
|
|
for index in AgentInvocation.__table__.indexes
|
|
}
|
|
assert actual == expected
|
|
engine.dispose()
|
|
|
|
|
|
def test_invocation_migration_uses_postgresql_identity():
|
|
"""PostgreSQL 独立迁移保留宿主主键 Identity 约定。"""
|
|
migration = importlib.import_module(MIGRATION)
|
|
table = sa.Table("agentinvocation", sa.MetaData(), migration._id_column("postgresql"))
|
|
assert table.c.id.identity.start == 1
|
|
assert table.c.id.identity.cycle is True
|
|
assert "GENERATED BY DEFAULT AS IDENTITY" in str(CreateTable(table).compile(dialect=postgresql.dialect()))
|