mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-31 04:57:23 +08:00
98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
"""整理待处理表 3.0.4 初始迁移的中断恢复测试。"""
|
|
|
|
import importlib
|
|
|
|
import pytest
|
|
import sqlalchemy as sa
|
|
from alembic.migration import MigrationContext
|
|
from alembic.operations import Operations
|
|
|
|
MIGRATION = "database.versions.e3d9f4b7c806_3_0_4"
|
|
|
|
|
|
def _bind_migration(monkeypatch, connection):
|
|
"""把 3.0.4 迁移绑定到隔离 SQLite 连接。"""
|
|
migration = importlib.import_module(MIGRATION)
|
|
monkeypatch.setattr(
|
|
migration,
|
|
"op",
|
|
Operations(MigrationContext.configure(connection)),
|
|
)
|
|
return migration
|
|
|
|
|
|
def test_upgrade_repairs_missing_and_malformed_identity_index(monkeypatch) -> None:
|
|
"""建表后中断或同名错误索引都必须收敛为精确唯一索引。"""
|
|
engine = sa.create_engine("sqlite://")
|
|
with engine.begin() as connection:
|
|
connection.execute(sa.text(
|
|
"CREATE TABLE transferpending ("
|
|
"id INTEGER PRIMARY KEY, storage VARCHAR NOT NULL, "
|
|
"src_path VARCHAR NOT NULL, created_at VARCHAR)"
|
|
))
|
|
migration = _bind_migration(monkeypatch, connection)
|
|
migration.upgrade()
|
|
connection.execute(sa.text(
|
|
"DROP INDEX ux_transferpending_storage_path"
|
|
))
|
|
connection.execute(sa.text(
|
|
"CREATE INDEX ux_transferpending_storage_path "
|
|
"ON transferpending (src_path)"
|
|
))
|
|
|
|
migration.upgrade()
|
|
|
|
index = sa.inspect(connection).get_indexes("transferpending")[0]
|
|
assert index["name"] == "ux_transferpending_storage_path"
|
|
assert index["column_names"] == ["storage", "src_path"]
|
|
assert index["unique"] == 1
|
|
|
|
|
|
def test_upgrade_recreates_empty_partial_table(monkeypatch) -> None:
|
|
"""中断留下的空残表可以无损重建为完整 3.0.4 结构。"""
|
|
engine = sa.create_engine("sqlite://")
|
|
with engine.begin() as connection:
|
|
connection.execute(sa.text(
|
|
"CREATE TABLE transferpending (id INTEGER PRIMARY KEY)"
|
|
))
|
|
migration = _bind_migration(monkeypatch, connection)
|
|
|
|
migration.upgrade()
|
|
|
|
assert {
|
|
column["name"]
|
|
for column in sa.inspect(connection).get_columns("transferpending")
|
|
} == {"id", "storage", "src_path", "created_at"}
|
|
|
|
|
|
def test_upgrade_rejects_nonempty_partial_table(monkeypatch) -> None:
|
|
"""含数据残表无法可靠推断源身份时必须显式拒绝迁移。"""
|
|
engine = sa.create_engine("sqlite://")
|
|
with engine.begin() as connection:
|
|
connection.execute(sa.text(
|
|
"CREATE TABLE transferpending (id INTEGER PRIMARY KEY)"
|
|
))
|
|
connection.execute(sa.text(
|
|
"INSERT INTO transferpending (id) VALUES (1)"
|
|
))
|
|
migration = _bind_migration(monkeypatch, connection)
|
|
|
|
with pytest.raises(RuntimeError, match="含数据的不完整 transferpending"):
|
|
migration.upgrade()
|
|
|
|
|
|
def test_downgrade_tolerates_interrupted_missing_index(monkeypatch) -> None:
|
|
"""索引创建前中断时降级仍应安全删除残留表。"""
|
|
engine = sa.create_engine("sqlite://")
|
|
with engine.begin() as connection:
|
|
connection.execute(sa.text(
|
|
"CREATE TABLE transferpending ("
|
|
"id INTEGER PRIMARY KEY, storage VARCHAR NOT NULL, "
|
|
"src_path VARCHAR NOT NULL, created_at VARCHAR)"
|
|
))
|
|
migration = _bind_migration(monkeypatch, connection)
|
|
|
|
migration.downgrade()
|
|
|
|
assert "transferpending" not in sa.inspect(connection).get_table_names()
|