Two milestones: a note can carry its own check (317), and a rule keeps what it used to say (323) #135

Merged
bvandeusen merged 23 commits from dev into main 2026-08-31 00:01:15 -04:00
Showing only changes of commit 7a0dc93270 - Show all commits
@@ -67,10 +67,16 @@ async def _purge_restored() -> None:
@pytest_asyncio.fixture(autouse=True) @pytest_asyncio.fixture(autouse=True)
async def _no_leftovers(): async def _no_leftovers():
"""The usernames are fixed, so a previous failed run would leave rows that """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.""" make the fixtures below pick the wrong user — or hit `.one()` with two.
await _purge_restored()
await _purge_books(OWNER_USERNAME) SETUP ONLY, and that is not a stylistic choice. `_dispose_engine` is a
yield 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_restored()
await _purge_books(OWNER_USERNAME) await _purge_books(OWNER_USERNAME)
@@ -173,6 +179,12 @@ async def source():
@pytest_asyncio.fixture @pytest_asyncio.fixture
async def restored(source): 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"]) await backup.restore_full_backup(source["payload"])
async with async_session() as s: async with async_session() as s:
user = (await s.execute( user = (await s.execute(
@@ -192,7 +204,11 @@ async def restored(source):
select(RuleVersion).where(RuleVersion.rule_id == rule.id) select(RuleVersion).where(RuleVersion.rule_id == rule.id)
.order_by(RuleVersion.id) .order_by(RuleVersion.id)
)).scalars().all() )).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): async def test_both_snapshots_come_back(restored):