feat(backend): harden db_migrate — rollback test, non-sql filter test, doc convention
This commit is contained in:
@@ -6,6 +6,7 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import sqlalchemy as sa
|
||||
import sqlalchemy.exc
|
||||
|
||||
from cyclone import db_migrate
|
||||
|
||||
@@ -64,4 +65,51 @@ def test_run_raises_on_missing_version_header(tmp_path: Path, monkeypatch: pytes
|
||||
|
||||
engine = _fresh_engine(tmp_path)
|
||||
with pytest.raises(RuntimeError, match="missing '-- version"):
|
||||
db_migrate.run(engine)
|
||||
db_migrate.run(engine)
|
||||
|
||||
|
||||
def test_run_rolls_back_version_on_failed_statement(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""If a DDL statement fails, the version bump must also roll back."""
|
||||
monkeypatch.setattr(db_migrate, "MIGRATIONS_DIR", tmp_path)
|
||||
(tmp_path / "0001_initial.sql").write_text(
|
||||
"-- version: 1\nCREATE TABLE t (id INTEGER);\n"
|
||||
)
|
||||
|
||||
engine = _fresh_engine(tmp_path)
|
||||
db_migrate.run(engine) # applies 0001, user_version=1
|
||||
assert _user_version(engine) == 1
|
||||
|
||||
# Now drop in a second migration whose DDL conflicts with the first.
|
||||
# The runner should apply 0001 and 0002 in one call; 0002 fails, the
|
||||
# transaction rolls back, and user_version must stay at 1 (not bump to 2).
|
||||
(tmp_path / "0002_bad.sql").write_text(
|
||||
"-- version: 2\nCREATE TABLE t (id INTEGER);\n" # table already exists!
|
||||
)
|
||||
|
||||
with pytest.raises(sqlalchemy.exc.SQLAlchemyError):
|
||||
db_migrate.run(engine)
|
||||
|
||||
assert _user_version(engine) == 1 # bumped atomically, rolled back on failure
|
||||
|
||||
|
||||
def test_run_ignores_non_sql_files(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""README.md and similar files in MIGRATIONS_DIR must not be executed."""
|
||||
monkeypatch.setattr(db_migrate, "MIGRATIONS_DIR", tmp_path)
|
||||
(tmp_path / "0001_initial.sql").write_text(
|
||||
"-- version: 1\nCREATE TABLE t (id INTEGER);\n"
|
||||
)
|
||||
(tmp_path / "README.md").write_text("Don't run me!\nCREATE TABLE should_not_exist (x INT);\n")
|
||||
|
||||
engine = _fresh_engine(tmp_path)
|
||||
db_migrate.run(engine)
|
||||
|
||||
with engine.connect() as c:
|
||||
rows = c.exec_driver_sql(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='should_not_exist'"
|
||||
).all()
|
||||
assert len(rows) == 0
|
||||
assert _user_version(engine) == 1
|
||||
Reference in New Issue
Block a user