Real Postgres in a container. No solutions.md before submitting.
Exercise 1 — The test environment
- Bring up the
docker-compose.test.yml(Postgres 16 on 5433 + Redis on 6380) and run the integration suite withDATABASE_URLpointing there. Paste the complete command (env var + pytest). - Lie on purpose: run the outbox's partial-index test (25) against SQLite (
override_settingsor a SQLite test DB). What happens and why? Document the lie concretely (does the test pass and lie, or fail honestly?). - Add the version check to the conftest: if the test DB isn't Postgres 16,
pytest.failat boot with a clear message (27: fail-fast).
Exercise 2 — One seat, one winner
- Implement the concurrency test (ThreadPoolExecutor +
transaction=True) with N=2, then N=10 threads over the SAME seat: exactly 1 winner, 9SeatUnavailable. - Measure: how long does the N=10 test take? Note the number as the baseline (36 will compare it under load).
- The
nowaitvariant (10): the same test withselect_for_update(nowait=True)— the losers fail IMMEDIATELY with LockNotAvailable. Which checkout UX do you prefer and why? (2 lines: wait-block vs reject-retry).
Exercise 3 — The outbox and ledger seams
- The outbox atomicity test with a REAL TX: force a failure in the middle of
reservar()'s transaction (a trigger/constraint that explodes) and verify zero published events. No transaction mocks: the DB decides. - The ledger constraint's test (31): insert a duplicate
(org, mes)and verifyIntegrityError— and thatliquidar_mes's code turns it into a skip, not a crash (theget_or_create). - The resumable saga's test (32): create a PENDING saga with intent_id, "kill" the process (simulate with an uncaught exception), resume, and verify ONE charge in the fake gateway with the Idempotency-Key.
Exercise 4 — Isolation
- Break isolation on purpose: a test that writes to Redis DB 0 (the dev one) and another that depends on that key. Run the second alone: red? Run the whole suite: green by ordering? Document the smell and fix it (prefix + DB 15).
- Run the integration suite with
pytest -p no:randomlyand then with randomization (pytest-randomly): did any dependent test surface? The test that only passes in order: fix it or kill it. - The conftest's final rule: an
autousefixture verifying that NO test writes to the dev DB (the URL must containtf_test). How would you implement the guard in the fixture?
Exercise 5 — The guarantees table
- Write the guarantees table (§5) for YOUR project with the real state: each row with its test (or "missing"). How many guarantees sold to the business have no policy?
- Implement the most critical missing one (pick: advisory lock, ledger's UniqueConstraint, or resumable saga) and paste it.
- Run the whole suite and time it per layer: units X s, integration Y s, e2e Z s. Does it meet the budget (10s / 2min / 10min)? If not: which test is in the wrong layer?
Submit
Paste the test compose, the N=10 test with its ms, the outbox atomicity test and the guarantees table with its gaps. Next: Lesson 35 — E2E and contract testing.