fix(test): install one global capture subscriber; delete schema migrations #411

Merged
KofTwentyTwo merged 4 commits from fix/test-flakes-tracing-race into dev 2026-08-14 14:46:38 +00:00
4 Commits
Author SHA1 Message Date
james.maes bbebd576d8 fix(test): time out outbox mutations in real time, not on a paused clock
The two hung-mutation tests paused the Tokio clock so auto-advance would
jump the 30s per-item timeout. That cannot be made reliable: the executor
does real SQLite I/O on a blocking pool inside the same window, and
auto-advance fires whenever the runtime looks idle. It also fires sqlx's
own pool-acquire timer, which defaults to the same 30 seconds -- turning a
healthy list_pending_mutations into PoolTimedOut, whose error arm returns
an all-zero summary. That is exactly the shape CI reported: completed 0
and failed 0 both as expected, retried 0 instead of 1.

Make the per-item timeout an overridable method on RemoteExecutionEnv and
give the hanging test env 250ms, so the tests wait it out in real time and
no test pauses the clock. The hang is infinite, so a loaded runner makes
these slower, never wrong.

50 runs at --test-threads=2 under 16-way CPU load: 0 failures.
2026-08-12 13:10:12 -05:00
james.maes 15226b62a1 refactor(store): create the schema, never migrate it
Four ALTER TABLE helpers upgraded a pre-existing on-disk schema: smtp
columns, TLS-mode columns, the DAV collection_url, and the messages
identity columns. Every column they add is already declared in the
CREATE TABLE IF NOT EXISTS in the same migrate(), so on any database
this engine actually creates they were unconditional no-ops.

Nothing is released and every store is a local development database, so
there is no older schema to meet. Delete the helpers and the three tests
that existed only to exercise them.

backfill_message_fts stays: salvage restores rows straight into messages,
bypassing save_email's index write, so a recovered database really does
have content the trigram index has never seen. Its doc no longer claims
the legacy justification.

Removes 495 lines, and with them the migrate_logs flake outright.
2026-08-12 12:32:20 -05:00
james.maes 1cd1bcc13c fix(test): capture logs through a global subscriber in 4 more crates
Ports the nunciod fix (99a8d1a) to nuncio-cal, nuncio-contacts,
nuncio-store, and nuncio-filter: install the tracing capture
subscriber once as the process default and route events to a
per-thread buffer, instead of a thread-local subscriber that a
racing callsite's cached Interest::never() can permanently defeat
under a parallel test harness.

nuncio-cal and nuncio-contacts get the same structured Recorder
shape as nunciod. nuncio-store gains a formatted-text test_tracing
helper (its assertions match on rendered level tags and substrings)
used by vault.rs; the two migration-log CapturedLogs sites in db.rs
are left untouched because those tests are being deleted separately.
nuncio-filter keeps its dependency-free hand-rolled Subscriber but
makes it global and per-thread-routed, replacing the local
CapturingSubscriber in engine.rs and webhook.rs.
2026-08-12 12:26:46 -05:00
james.maes 99a8d1a96f fix(test): capture logs through one global subscriber, not a thread-local
tracing resolves a callsite's Interest once per process and caches it. A
callsite first executed on a thread with no subscriber caches never and is
skipped forever, before any thread-local subscriber is consulted. Under the
parallel harness, whichever thread reached a callsite first decided whether
any other test could capture it, so every log-capture assertion in this
crate was a coin flip -- reproducible at --test-threads=2, which is what CI
runners give us.

Install the capture layer once as the global default and route events to a
per-thread recorder instead. Rebuild the interest cache once at install so
callsites already resolved against the no-op dispatcher are recoverable.

Measured on nunciod: ~90% of runs red at --test-threads=2 before, 0/12 after.
2026-08-12 11:47:34 -05:00