fix(tests): the rule-version round trip must not touch Postgres after dispose (#3240)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / integration (push) Successful in 30s
CI & Build / Python tests (push) Successful in 1m5s
CI & Build / Build & push image (push) Successful in 23s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / integration (push) Successful in 30s
CI & Build / Python tests (push) Successful in 1m5s
CI & Build / Build & push image (push) Successful in 23s
`_dispose_engine` is a usefixtures entry, so it sets up AFTER an autouse fixture and tears down BEFORE it. The purge running after this file's `yield` therefore opened a fresh pooled connection that the closing loop immediately orphaned, and the next test to touch Postgres died on "Future attached to a different loop" — two of this file's own tests and test_run_maintenance_vacuums_real_tables, which shares nothing with it but the engine. The autouse fixture is setup-only now, matching its sibling in test_integration_backup_note_roundtrip.py, and the cleanup moved into `restored`, whose teardown runs while the engine is still live. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -67,10 +67,16 @@ async def _purge_restored() -> None:
|
||||
@pytest_asyncio.fixture(autouse=True)
|
||||
async def _no_leftovers():
|
||||
"""The usernames are fixed, so a previous failed run would leave rows that
|
||||
make the fixtures below pick the wrong user — or hit `.one()` with two."""
|
||||
await _purge_restored()
|
||||
await _purge_books(OWNER_USERNAME)
|
||||
yield
|
||||
make the fixtures below pick the wrong user — or hit `.one()` with two.
|
||||
|
||||
SETUP ONLY, and that is not a stylistic choice. `_dispose_engine` is a
|
||||
usefixtures entry, so it sets up AFTER this autouse one and therefore
|
||||
tears down BEFORE it. Any database call here after a `yield` would open a
|
||||
fresh pooled connection that the closing loop then orphans, and the next
|
||||
test to touch Postgres dies on "Future attached to a different loop" —
|
||||
including tests in other files. Cleanup belongs in the fixtures below,
|
||||
whose teardowns run while the engine is still live.
|
||||
"""
|
||||
await _purge_restored()
|
||||
await _purge_books(OWNER_USERNAME)
|
||||
|
||||
@@ -173,6 +179,12 @@ async def source():
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def restored(source):
|
||||
"""Runs the real restore, then hands back the new rows.
|
||||
|
||||
The restore mints a NEW user from the payload, so the restored corpus is
|
||||
entirely separate from the source one — which is what makes the id
|
||||
assertions below able to fail.
|
||||
"""
|
||||
await backup.restore_full_backup(source["payload"])
|
||||
async with async_session() as s:
|
||||
user = (await s.execute(
|
||||
@@ -192,7 +204,11 @@ async def restored(source):
|
||||
select(RuleVersion).where(RuleVersion.rule_id == rule.id)
|
||||
.order_by(RuleVersion.id)
|
||||
)).scalars().all()
|
||||
return {"user": user, "rule": rule, "versions": versions, "source": source}
|
||||
yield {"user": user, "rule": rule, "versions": versions, "source": source}
|
||||
|
||||
# Here rather than in the autouse fixture: this teardown still runs while
|
||||
# the engine is live. See _no_leftovers.
|
||||
await _purge_restored()
|
||||
|
||||
|
||||
async def test_both_snapshots_come_back(restored):
|
||||
|
||||
Reference in New Issue
Block a user