test_billing_run_id_migration.py 1.7 KB

123456789101112131415161718192021222324252627282930313233343536
  1. """Migration coverage for durable per-dispatch billing identities."""
  2. import pytest
  3. from sqlalchemy import text
  4. from sqlalchemy.ext.asyncio import create_async_engine
  5. import backend.app.models # noqa: F401 - populate Base.metadata
  6. import backend.app.models.external_link # noqa: F401 - required by a legacy ALTER in run_migrations
  7. import backend.app.models.print_log # noqa: F401 - required by a legacy ALTER in run_migrations
  8. from backend.app.core.database import Base, run_migrations
  9. @pytest.mark.asyncio
  10. async def test_billing_run_columns_and_legacy_archive_index_are_migrated(tmp_path):
  11. engine = create_async_engine(f"sqlite+aiosqlite:///{tmp_path / 'billing-run.db'}")
  12. try:
  13. async with engine.begin() as conn:
  14. await conn.run_sync(Base.metadata.create_all)
  15. await run_migrations(conn)
  16. queue_columns = {row[1] for row in (await conn.execute(text("PRAGMA table_info(print_queue)"))).all()}
  17. archive_columns = {row[1] for row in (await conn.execute(text("PRAGMA table_info(print_archives)"))).all()}
  18. notification_columns = {
  19. row[1] for row in (await conn.execute(text("PRAGMA table_info(notification_providers)"))).all()
  20. }
  21. archive_index_sql = await conn.scalar(
  22. text("SELECT sql FROM sqlite_master WHERE type = 'index' AND name = 'uq_wallet_transactions_archive'")
  23. )
  24. assert "billing_run_id" in queue_columns
  25. assert "billing_run_id" in archive_columns
  26. assert "on_billing_charge_failed" in notification_columns
  27. assert archive_index_sql is not None
  28. assert "WHERE print_run_id IS NULL" in archive_index_sql
  29. finally:
  30. await engine.dispose()