TestSyncProductToStripeAnswers presses the sync action once per branch
and writes testdata/operator_sync_stripe/<branch>.golden with the
answer (status, toast, alerts), the outbox entries of the product and
its prices, both mappings, and the ordered statement names of the
request, the page's reads included. The 14 branches: Stripe not
configured, unknown product, no active price, price read fails, price
of another product, default price with nothing mapped, requested price
of a reachable product, price already synced, price sync pending,
product create in flight, dead-lettered creates retried, product
create dead-lettered and another price pressed, transaction cannot
begin, and the readiness panel naming a dead-lettered sync. Pending and
dead-lettered states are made by pressing the action and then marking
the entries dead-lettered through the outbox activity, as the workflow
does. The first caller of world.MapProductIn outside its own test is
the reachable-product branch.
TestSyncProductToStripeRechecksUnderTheLock holds the product's
advisory lock in a side transaction, presses the action, waits until
the press queues on the lock, then commits what a competing sync
writes: a pending sync (the press answers "already in progress" and
adds no entry beyond the competitor's two) or a synced price (it
answers "already synced" and adds none).
What the goldens pin that is a defect or a surprise:
- An unknown product answers with the products page and "Product not
found"; the handler's own "Failed to load the product." never shows.
- A failed read of the product's prices is answered as "Add an active
price before syncing to Stripe.", the same as no price.
- A price that is already synced is answered after the price-mapping
read alone: no outbox probe, no transaction.
- Pressing a second price while the product's own create is
dead-lettered resets the product's entry ("Retrying ...") and
enqueues nothing for the second price, which has no mapping or entry
afterwards.
- A press that finds the product's create in flight rolls back after
the page's reads.
No production file changes and no output changes. The test names of
./internal/server and ./internal/testkit/... are the parent's 1526
plus these 18 (2 tests, 16 subtests), all passing, each side run after
a reset of the test database. The new test files pass three runs in a
row, and a run without -update leaves the goldens unchanged.
25 breaks of operator_billing.go and operator_products.go, each caught
by the new tests. One record was corrected to compile before the
counting run: the check that refuses another product's price left its
variable unused, so the break keeps the variable in use.
Unprobed, with the reason:
- the seven "sync-stripe: ..." log lines: no test reads a log;
- a failure after a successful begin (the mapping writes, the enqueue,
the commit, the reset of dead-lettered entries): it needs a
statement to fail inside the transaction and no hook exists;
- "Failed to load the product.": it renders only when the page's own
read of the product then succeeds, after the handler's read failed;
- a failed read of the price mapping before the lock: it reads as no
mapping and is not distinguished;
- the stale and other-environment mappings, which
TestSyncProductToStripeCreatesAgainWhenUnreachable pins.