dev→main: showcase cascade + filter styling + DB maintenance + gallery filter Phase 2 + showcase decode-gate + CI perf #62

Merged
bvandeusen merged 14 commits from dev into main 2026-06-04 08:27:47 -04:00
Showing only changes of commit c802b26406 - Show all commits
+42 -27
View File
@@ -104,32 +104,51 @@ async def client(app):
_SEED_SNAPSHOT: dict[str, list[dict]] | None = None
@pytest.fixture(scope="session")
def _truncate_engine():
"""Session-scoped sync engine reused by the per-test DB-reset teardown.
Creating a fresh engine + Postgres connection for EVERY test's teardown was
the integration suite's dominant cost — `--durations` showed the 15 slowest
operations in both long shards were all ~1.5-2s teardowns, i.e. the
connect+SCRAM handshake, not test logic. A single pooled connection reused
across teardowns cuts that to the TRUNCATE itself. `pool_pre_ping` guards
against Postgres reaping the idle connection mid-suite (a stale-connection
failure would be a nasty flaky bounce; the ping is sub-millisecond).
`create_engine` is lazy — it opens no connection until first `.begin()` —
so the no-DB unit job instantiates this object but never connects.
"""
eng = create_engine(_sync_database_url(), future=True, pool_pre_ping=True)
yield eng
eng.dispose()
@pytest.fixture(autouse=True)
def _reset_db_after_integration(request):
def _reset_db_after_integration(request, _truncate_engine):
"""Integration tests exercise app/celery code that commits on its own
connection, which the rollback fixtures above can't undo — so data
would leak between tests. Capture the seeded baseline at the first
integration test, then after each integration-marked test truncate
every model table and restore that baseline. Connects to the DB ONLY
for integration-marked tests, so the no-DB fast unit job is untouched.
every model table and restore that baseline. Touches the DB ONLY for
integration-marked tests, so the no-DB fast unit job is untouched.
Uses the session-scoped `_truncate_engine` (pooled, reused) rather than
building a fresh engine per test — see that fixture's docstring.
"""
global _SEED_SNAPSHOT
is_integration = request.node.get_closest_marker("integration") is not None
if is_integration and _SEED_SNAPSHOT is None:
eng = create_engine(_sync_database_url(), future=True)
snap: dict[str, list[dict]] = {}
try:
with eng.connect() as conn:
for t in Base.metadata.sorted_tables:
rows = [
dict(m)
for m in conn.execute(t.select()).mappings().all()
]
if rows:
snap[t.name] = rows
finally:
eng.dispose()
with _truncate_engine.connect() as conn:
for t in Base.metadata.sorted_tables:
rows = [
dict(m)
for m in conn.execute(t.select()).mappings().all()
]
if rows:
snap[t.name] = rows
_SEED_SNAPSHOT = snap
yield
@@ -139,18 +158,14 @@ def _reset_db_after_integration(request):
tables = ", ".join(t.name for t in Base.metadata.sorted_tables)
if not tables:
return
eng = create_engine(_sync_database_url(), future=True)
try:
with eng.begin() as conn:
conn.exec_driver_sql(
f"TRUNCATE {tables} RESTART IDENTITY CASCADE"
)
for t in Base.metadata.sorted_tables:
rows = (_SEED_SNAPSHOT or {}).get(t.name)
if rows:
conn.execute(t.insert(), rows)
finally:
eng.dispose()
with _truncate_engine.begin() as conn:
conn.exec_driver_sql(
f"TRUNCATE {tables} RESTART IDENTITY CASCADE"
)
for t in Base.metadata.sorted_tables:
rows = (_SEED_SNAPSHOT or {}).get(t.name)
if rows:
conn.execute(t.insert(), rows)
@pytest_asyncio.fixture(autouse=True)