hugin/server/tests/test_migration.py
2026-10-27 08:33:21 +01:00

46 lines
2 KiB
Python

"""Migrationen passen zu den Modellen, auf SQLite und PostgreSQL (→ KONZEPT.md 18)."""
import hashlib
from alembic.autogenerate import compare_metadata
from alembic.script import ScriptDirectory
from alembic.runtime.migration import MigrationContext
from sqlalchemy import create_engine
from hugin_app.migration import FOLDER, VERSION_TABLE, migrate
from hugin_app.store.models import Base
def test_migrations_match_models(database_url):
migrate(database_url)
engine = create_engine(database_url)
try:
with engine.connect() as connection:
context = MigrationContext.configure(connection, opts={"version_table": VERSION_TABLE})
differences = [u for u in compare_metadata(context, Base.metadata)
if not (isinstance(u, tuple) and u[0] == "remove_table" and u[1].name == VERSION_TABLE)]
finally:
engine.dispose()
assert differences == [], "Modelle geändert ohne Migration: uv run alembic revision --autogenerate …"
# Ausgelieferte Migrationen bleiben, wie sie sind: Datenbanken kennen ihre Revision. Eine
# geänderte oder ersetzte Migration lässt bestehende Datenbanken nicht mehr migrieren
# („Can't locate revision“). Änderungen am Schema nur als neue Migration; neue Dateien hier
# mit Prüfsumme eintragen, sobald sie ausgeliefert sind.
RELEASED = {
"0001_initial_tables.py": "ff511bb66729de1998602be87a1714b37d20dff58265542c9bbce11b5fbacbde",
}
def test_released_migrations_unchanged():
for name, digest in RELEASED.items():
path = FOLDER / "versions" / name
assert path.exists(), f"{name} fehlt: ausgelieferte Migrationen nie löschen oder umbenennen"
assert hashlib.sha256(path.read_bytes()).hexdigest() == digest, (
f"{name} wurde geändert: ausgelieferte Migrationen nie ändern, sondern eine neue anlegen")
def test_migrations_form_one_chain():
scripts = ScriptDirectory(str(FOLDER))
assert len(scripts.get_heads()) == 1, f"mehrere Enden: {scripts.get_heads()}; mit alembic merge zusammenführen"