test_migrations.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. from __future__ import annotations
  2. import hashlib
  3. import os
  4. from io import StringIO
  5. from pathlib import Path
  6. import pytest
  7. from alembic import command
  8. from alembic.config import Config
  9. from sqlalchemy import create_engine, inspect, text
  10. from sqlalchemy.ext.asyncio import create_async_engine
  11. def test_alembic_upgrade_and_downgrade(tmp_path: Path, monkeypatch: object) -> None:
  12. root = Path(__file__).parents[1]
  13. database = tmp_path / "migration.db"
  14. url = f"sqlite+aiosqlite:///{database}"
  15. monkeypatch.setenv("SCRIPT_BUILD_WRITE_DATABASE_URL", url) # type: ignore[attr-defined]
  16. config = Config(str(root / "alembic.ini"))
  17. command.upgrade(config, "head")
  18. sync_engine = create_engine(f"sqlite:///{database}")
  19. expected = {
  20. "script_build_mission_binding",
  21. "script_build_input_snapshot",
  22. "script_build_artifact_version",
  23. "script_build_publication",
  24. }
  25. assert expected <= set(inspect(sync_engine).get_table_names())
  26. command.downgrade(config, "base")
  27. assert not (expected & set(inspect(sync_engine).get_table_names()))
  28. sync_engine.dispose()
  29. def test_migration_checksum_manifest() -> None:
  30. root = Path(__file__).parents[1]
  31. manifest = root / "migrations" / "CHECKSUMS.sha256"
  32. lines = [line.split(maxsplit=1) for line in manifest.read_text(encoding="utf-8").splitlines()]
  33. assert lines
  34. for expected, relative in lines:
  35. path = root / relative
  36. assert hashlib.sha256(path.read_bytes()).hexdigest() == expected
  37. def test_mysql_offline_sql_compiles_without_credentials(monkeypatch: object) -> None:
  38. root = Path(__file__).parents[1]
  39. output = StringIO()
  40. monkeypatch.setenv( # type: ignore[attr-defined]
  41. "SCRIPT_BUILD_WRITE_DATABASE_URL", "mysql+asyncmy://"
  42. )
  43. config = Config(str(root / "alembic.ini"), output_buffer=output)
  44. command.upgrade(config, "head", sql=True)
  45. sql = output.getvalue()
  46. assert sql.count("CREATE TABLE script_build_") == 4
  47. assert "script_build_paragraph" not in sql
  48. assert "script_build_element" not in sql
  49. @pytest.mark.mysql
  50. @pytest.mark.asyncio
  51. async def test_explicit_mysql_dsn_is_reachable() -> None:
  52. dsn = os.environ.get("SCRIPT_BUILD_TEST_MYSQL_DSN")
  53. if not dsn:
  54. pytest.skip("SCRIPT_BUILD_TEST_MYSQL_DSN is not configured")
  55. engine = create_async_engine(dsn, pool_pre_ping=True)
  56. try:
  57. async with engine.connect() as connection:
  58. assert await connection.scalar(text("SELECT 1")) == 1
  59. finally:
  60. await engine.dispose()