Skip to content

Commit f9167cf

Browse files
committed
test: drain multicast queues before TOCTOU race assertion
`test_service_info_async_request` patches `_is_complete` to False to keep the loop running. With `quick_timing` registrations complete within ~30ms, leaving multicast responses pending in `out_queue` / `out_delay_queue` that snapshot the records as they were *before* `async_update_service` swapped the registry to `new_info`. When those stale answers flush after `_clear_cache`, they re-cache `xxxyyy._test1-srvc-type._tcp.local. -> ash-1.local. -> 10.0.1.2` and set the AsyncServiceInfo's server to `ash-1.local.`. The patched `_is_complete=False` loop then keeps asking for A records for `ash-1.local.`, which nothing in the registry answers, so the assertion fails: AssertionError: assert [b'\\n\\x00\\x01\\x02'] == [b'\\n\\x00\\x01\\x03'] Sleep 1.5s before clearing the cache so both queues drain (max ~620ms for `out_queue` and ~1320ms for `out_delay_queue`) and only the up-to-date registry state is left for the loop to observe.
1 parent dd341a3 commit f9167cf

1 file changed

Lines changed: 10 additions & 0 deletions

File tree

tests/test_asyncio.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,16 @@ async def test_service_info_async_request(quick_timing: None) -> None:
695695
assert aiosinfos[1] is not None
696696
assert aiosinfos[1].addresses == [socket.inet_aton("10.0.1.5")]
697697

698+
# Drain the multicast outgoing queues before clearing the cache.
699+
# Responses to the earlier `async_get_service_info` queries can
700+
# sit in `out_queue` (up to ~620ms) or `out_delay_queue`
701+
# (up to ~1320ms) carrying snapshots of the records taken
702+
# *before* `async_update_service` swapped the registry to
703+
# `new_info`. If those stale answers flush after `_clear_cache`,
704+
# they poison `aiosinfo.server` with `ash-1.local.` and the
705+
# `_is_complete=False` loop never recovers because subsequent
706+
# queries ask for an A record nobody answers.
707+
await asyncio.sleep(1.5)
698708
aiosinfo = AsyncServiceInfo(type_, registration_name)
699709
_clear_cache(aiozc.zeroconf)
700710
# Generating the race condition is almost impossible

0 commit comments

Comments
 (0)