test_name_conflict_3 failed once on macos-14 in the "Run tests with features" step of this run (PR #494, commit a59ea60). It passed in the "Run tests with debugs" step of the same job, on ubuntu and windows, and on the next run. The failing assertion is tests/mdns_test.rs:2145:
thread 'test_name_conflict_3' panicked at 'assertion failed: `(left == right)`
left: `2`,
right: `3`', tests/mdns_test.rs:2145:5
The code under test is not touched by #494; this is a pre-existing race on the responder side. Filing it so the analysis isn't lost.
What the log shows
The client received three ServiceResolved events, but for only two distinct fullnames — server3 never renamed its instance:
Resolved a service: 1789187024318121._conflict-3._udp.local. host conflict3_host.local. IP {192.168.64.4} <- server1
Resolved a service: 1789187024318121._conflict-3._udp.local. host conflict3_host-3.local. IP {192.168.64.6} <- server3
Resolved a service: 1789187024318121 (2)._conflict-3._udp.local. host conflict3_host-2.local. IP {192.168.64.5} <- server2
The string 1789187024318121 (3) appears nowhere in the 22k-line job log. Server3's SRV probe completed without ever logging found conflict name ... TYPE_SRV:
probe of '1789187024318121._conflict-3._udp.local.' finished: move 2 records to active. (1 waiting services)
So two daemons announced the same instance name, the client resolved both, and the test's HashSet<String> of fullnames deduplicated to 2.
Sequence
- Server3 registers with an SRV that is byte-identical to server1's — same instance name, same host
conflict3_host.local., same port. Per RFC 6762 §8.1 identical records are not a conflict, so the initial SRV probe passes.
- Server3's A record conflicts with server1 (→ host renamed to
conflict3_host-2.local.) and then with server2 (→ conflict3_host-3.local.). Each rename rewrites the SRV's target and restarts the SRV probe (service_info.rs:1335), opening a fresh ~750 ms window in which server1 must re-multicast its SRV for server3 to see that the rdata now differs.
- Server1 has just multicast that SRV answering the earlier probe rounds, and the responder enforces the RFC 6762 §6 one-second multicast rate limit (
service_info.rs:1187). If the throttle outlasts the restarted probe window, server3 hears nothing and declares the name free.
- The window was further perturbed — the log shows server3 losing a tiebreak on the SRV name:
tiebreaking '1789187024318121._conflict-3._udp.local.': LOST, will wait for one second
and test_name_conflict_resolution and test_tiebreaking were probing concurrently in the same second on the same interface (_conflict-test._udp, _tiebreaking._udp), which is exactly the load that makes step 3 bite on a slow runner.
A contributing factor on the test side: the server3 monitor loop at tests/mdns_test.rs:2112 breaks on the first NameChange event, which was the A-record rename. It never waits to observe the SRV/instance rename before starting the client browse.
Root cause in the daemon
RFC 6762 §6 exempts probe answers from the one-second rule:
In the special case of answering probe queries (Section 8.1) with a unique record, a Multicast DNS responder is only required to delay its transmission as necessary to ensure an interval of at least 250 ms since the last time the record was multicast on that interface.
DnsRegistry::apply_multicast_rate_limit (service_info.rs:1201) applies a flat MULTICAST_RATE_LIMIT_MILLIS = 1000 window to every response and drops the throttled record from the answer instead of delaying it. It is applied at all three response paths (service_daemon.rs ~3575, ~3629, ~5007) with no distinction for queries whose authority section shows the querier is probing our name. So when server1 receives server3's restarted SRV probe within a second of its last multicast of that SRV, the conflicting record is silently removed from the reply, and server3 never learns the name is taken.
Possible fixes
Daemon side (the real issue — duplicate instance names on the wire):
- In
handle_query, detect a probe query (non-empty authority section carrying a record with our active name) and, for the unique records it names, apply the §6 probe-answer floor of 250 ms instead of 1 s — and delay rather than drop if inside that floor.
Test side (makes the test honest even if the daemon fix lands separately):
- For server3, wait for the
NameChange whose rr_type is SRV (the instance rename), not the first NameChange of any type.
- Consider not running the three conflict tests concurrently, or give each its own hostname so they don't share probe traffic.
Note for anyone reproducing on macOS: cargo test must be run from Terminal.app — multicast is blocked for other apps.
test_name_conflict_3failed once onmacos-14in the "Run tests with features" step of this run (PR #494, commita59ea60). It passed in the "Run tests with debugs" step of the same job, on ubuntu and windows, and on the next run. The failing assertion istests/mdns_test.rs:2145:The code under test is not touched by #494; this is a pre-existing race on the responder side. Filing it so the analysis isn't lost.
What the log shows
The client received three
ServiceResolvedevents, but for only two distinct fullnames — server3 never renamed its instance:The string
1789187024318121 (3)appears nowhere in the 22k-line job log. Server3's SRV probe completed without ever loggingfound conflict name ... TYPE_SRV:So two daemons announced the same instance name, the client resolved both, and the test's
HashSet<String>of fullnames deduplicated to 2.Sequence
conflict3_host.local., same port. Per RFC 6762 §8.1 identical records are not a conflict, so the initial SRV probe passes.conflict3_host-2.local.) and then with server2 (→conflict3_host-3.local.). Each rename rewrites the SRV's target and restarts the SRV probe (service_info.rs:1335), opening a fresh ~750 ms window in which server1 must re-multicast its SRV for server3 to see that the rdata now differs.service_info.rs:1187). If the throttle outlasts the restarted probe window, server3 hears nothing and declares the name free.test_name_conflict_resolutionandtest_tiebreakingwere probing concurrently in the same second on the same interface (_conflict-test._udp,_tiebreaking._udp), which is exactly the load that makes step 3 bite on a slow runner.A contributing factor on the test side: the server3 monitor loop at
tests/mdns_test.rs:2112breaks on the firstNameChangeevent, which was the A-record rename. It never waits to observe the SRV/instance rename before starting the client browse.Root cause in the daemon
RFC 6762 §6 exempts probe answers from the one-second rule:
DnsRegistry::apply_multicast_rate_limit(service_info.rs:1201) applies a flatMULTICAST_RATE_LIMIT_MILLIS = 1000window to every response and drops the throttled record from the answer instead of delaying it. It is applied at all three response paths (service_daemon.rs~3575, ~3629, ~5007) with no distinction for queries whose authority section shows the querier is probing our name. So when server1 receives server3's restarted SRV probe within a second of its last multicast of that SRV, the conflicting record is silently removed from the reply, and server3 never learns the name is taken.Possible fixes
Daemon side (the real issue — duplicate instance names on the wire):
handle_query, detect a probe query (non-empty authority section carrying a record with our active name) and, for the unique records it names, apply the §6 probe-answer floor of 250 ms instead of 1 s — and delay rather than drop if inside that floor.Test side (makes the test honest even if the daemon fix lands separately):
NameChangewhoserr_typeisSRV(the instance rename), not the firstNameChangeof any type.Note for anyone reproducing on macOS:
cargo testmust be run from Terminal.app — multicast is blocked for other apps.