test_pg_test_schema_reset.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. """The PostgreSQL test database is emptied between tests, not rebuilt.
  2. Rebuilding it for every test (DROP SCHEMA + create_all) was 90% of a
  3. PostgreSQL run. It is now built once per worker and emptied, so these pin what
  4. emptying has to give each test: no rows, ids from 1, and the models' schema,
  5. rebuilt when a test changed it. They run only on PostgreSQL.
  6. """
  7. import pytest
  8. from sqlalchemy import text
  9. from backend.tests import conftest
  10. pytestmark = pytest.mark.skipif(conftest.TEST_PG_URL is None, reason="the PostgreSQL test database only")
  11. async def _reset(test_engine):
  12. async with test_engine.begin() as conn:
  13. await conn.execute(text("SELECT 1"))
  14. await conftest._reset_pg_test_schema(conn)
  15. def _printer(n: int, **extra):
  16. from backend.app.models.printer import Printer
  17. return Printer(name=f"p{n}", serial_number=f"S{n}", ip_address=f"10.0.0.{n}", access_code="x", model="X1C", **extra)
  18. async def _add(test_engine, *rows):
  19. from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
  20. async with async_sessionmaker(test_engine, class_=AsyncSession, expire_on_commit=False)() as session:
  21. for row in rows:
  22. session.add(row)
  23. await session.flush()
  24. await session.commit()
  25. async def test_rows_go_and_ids_start_at_one_again(test_engine):
  26. await _add(test_engine, _printer(1), _printer(2))
  27. await _reset(test_engine)
  28. async with test_engine.begin() as conn:
  29. assert (await conn.execute(text("SELECT count(*) FROM printers"))).scalar_one() == 0
  30. fresh = _printer(3)
  31. await _add(test_engine, fresh)
  32. assert fresh.id == 1
  33. async def test_rows_that_reference_each_other_go_too(test_engine):
  34. """locations is emptied before spool, whose rows point at it with no
  35. ON DELETE action: only possible with the foreign-key triggers off."""
  36. from backend.app.models.location import Location
  37. from backend.app.models.spool import Spool
  38. location = Location(name="Shelf", name_key="shelf")
  39. await _add(test_engine, location)
  40. await _add(test_engine, Spool(material="PLA", location_id=location.id))
  41. await _reset(test_engine)
  42. async with test_engine.begin() as conn:
  43. assert (await conn.execute(text("SELECT count(*) FROM spool"))).scalar_one() == 0
  44. assert (await conn.execute(text("SELECT count(*) FROM locations"))).scalar_one() == 0
  45. @pytest.mark.parametrize(
  46. "change",
  47. [
  48. "ALTER TABLE printers ADD COLUMN leftover integer",
  49. "ALTER TABLE printers ALTER COLUMN location SET DEFAULT 'x'",
  50. "CREATE TABLE leftover_table (id integer)",
  51. "CREATE INDEX leftover_index ON printers (name)",
  52. "ALTER TABLE printers DROP CONSTRAINT printers_serial_number_key",
  53. ],
  54. )
  55. async def test_a_schema_a_test_changed_is_rebuilt(test_engine, change):
  56. async with test_engine.begin() as conn:
  57. before = (await conn.execute(text(conftest._PG_SCHEMA_FINGERPRINT))).scalar_one()
  58. await conn.execute(text(change))
  59. await _reset(test_engine)
  60. async with test_engine.begin() as conn:
  61. assert (await conn.execute(text(conftest._PG_SCHEMA_FINGERPRINT))).scalar_one() == before