joule-moq-relay: the cascade tests wait for a refusal, not only for what got through #610
Loading…
Reference in a new issue
No description provided.
Delete branch "test/relay-door-race"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
receipts_are_checked_at_every_doorfailed once in CI on linux-arm64 (#605, job 75036):cascade.rs:406, "the edge's door refused the tampered object", left: 0, right: 1. This changes only the test. The relay does what the test claims; the test read the counter before the relay had any reason to have set it.Cause
In
session.rs, every incoming subgroup stream (one per group per track) is read in its own spawned task (uni_loop→data_stream→upstream_subgroup). A media object's door verdict (Door::object, which may wait up to the rule'shold_msfor its bundle) and therefused()call that incrementsstats.refused_at_doorboth happen in that group's task. The refused object is never fanned out, so nothing the subscriber receives comes after the refusal.The test collected at the edge until it had G receipt objects and G-1 media groups, which the other groups' tasks are enough to supply. Then it read
refused_at_doorat once. Under load, group BAD's task can still be on its way to the door at that moment, and the read sees 0. Groups also reach the subscriber out of order: with the door disabled (below), the media groups arrived as[1, 4, 3, 0, 2, 5]and[0, 1, 5, 2, 3, 4].The vote test (
co_performance_votes_are_counted_once_in_chain_order) reads a counter in the same way. Infloor.rs, seq 1 waits for seq 0. Seq 0's step counts it and wakes seq 1's task, and seq 1 is refused there, when it steps again (refused_inputsis incremented in that step). Meanwhile seq 0 is forwarded by its own task. The test readrefused_inputsonce seq 0 had reached both watchers, after a one-second quiet period. That has not failed in CI, but nothing orders the refusal before that read.Fix
Both tests now wait for the refusal with
until(STEP, …)(20 s), then still count it exactly:refused_at_door == 1and(edge, home) refused inputs == (1, 0).The other reads in
cascade.rswere checked and left as they are:relay_loops,no_upstream,seek_refusedandforwarded_upstreamare incremented before the reply the test waits for.two_relaysandfloor_oncecome after the delivery of every object that could have been refused.!media_e.contains(&BAD)absence check cannot fail spuriously.Evidence
All runs are on the macOS build host. The load ran under
taskpolicy -c <QoS>: 4 busy loops beside 4 test instances at once, each phase capped at 4 minutes.2bef11f71cascade.rs:406, the CI messageAt this load, the natural rate is about 1 in 228 reads. To show the race without waiting for that rate, the window was widened with scratch delays in the relay, not committed: 300 ms before a door refusal is counted, and 1.5 s before a woken floor input is decided.
:406(same message as CI):855The fixed tests still fail when the property they check is broken (scratch mutations, not committed):
door_on = false): 2/2 fail at:404, because the tampered group was forwarded;:409) after 20 s;:861) after 20 s.cargo test -p joule-moq-relayatcbdf2f203on the build host exits 0. Every test binary passes, includingcascade(12 passed).🤖 Generated with Claude Code