Skip to content

Commit ed52266

Browse files
committed
Add coverage for sending answers removes future queued answers
1 parent 7b125a1 commit ed52266

3 files changed

Lines changed: 52 additions & 9 deletions

File tree

tests/services/test_info.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ async def test_we_try_four_times_with_random_delay():
764764

765765
# we are going to patch the zeroconf send to check query transmission
766766
request_count = 0
767+
767768
def async_send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT):
768769
"""Sends an outgoing packet."""
769770
nonlocal request_count

tests/test_handlers.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,3 +1460,42 @@ async def test_response_aggregation_random_delay():
14601460
assert info3.dns_pointer() not in outgoing_queue.queue[1].answers
14611461
assert info4.dns_pointer() not in outgoing_queue.queue[1].answers
14621462
assert info5.dns_pointer() in outgoing_queue.queue[1].answers
1463+
1464+
1465+
@pytest.mark.asyncio
1466+
async def test_future_answers_are_removed_on_send():
1467+
"""Verify any future answers scheduled to be sent are removed when we send."""
1468+
type_ = "_mservice._tcp.local."
1469+
name = "xxxyyy"
1470+
registration_name = f"{name}.{type_}"
1471+
1472+
desc = {'path': '/~paulsm/'}
1473+
info = ServiceInfo(
1474+
type_, registration_name, 80, 0, 0, desc, "ash-1.local.", addresses=[socket.inet_aton("10.0.1.2")]
1475+
)
1476+
mocked_zc = unittest.mock.MagicMock()
1477+
outgoing_queue = MulticastOutgoingQueue(mocked_zc, 0, 0)
1478+
1479+
now = current_time_millis()
1480+
with unittest.mock.patch.object(_handlers, "_MULTICAST_DELAY_RANDOM_INTERVAL", (10, 10)):
1481+
outgoing_queue.async_add(now, {info.dns_pointer(): set()})
1482+
1483+
assert len(outgoing_queue.queue) == 1
1484+
1485+
with unittest.mock.patch.object(_handlers, "_MULTICAST_DELAY_RANDOM_INTERVAL", (20, 20)):
1486+
outgoing_queue.async_add(now, {info.dns_pointer(): set()})
1487+
1488+
assert len(outgoing_queue.queue) == 2
1489+
1490+
with unittest.mock.patch.object(_handlers, "_MULTICAST_DELAY_RANDOM_INTERVAL", (200, 200)):
1491+
outgoing_queue.async_add(now, {info.dns_pointer(): set()})
1492+
outgoing_queue.async_add(now, {info.dns_pointer(): set()})
1493+
1494+
assert len(outgoing_queue.queue) == 3
1495+
1496+
await asyncio.sleep(0.1)
1497+
outgoing_queue.async_ready()
1498+
1499+
assert len(outgoing_queue.queue) == 1
1500+
# The answers should all get removed because we just sent them
1501+
assert len(outgoing_queue.queue[0].answers) == 0

zeroconf/_handlers.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -527,18 +527,24 @@ def async_add(self, now: float, answers: _AnswerWithAdditionalsType) -> None:
527527
last_group.answers.update(answers)
528528
return
529529
else:
530-
self.zc.loop.call_later(millis_to_seconds(random_delay), self._async_ready)
530+
self.zc.loop.call_later(millis_to_seconds(random_delay), self.async_ready)
531531
self.queue.append(AnswerGroup(send_after, send_before, answers))
532532

533-
def _async_ready(self) -> None:
533+
def _remove_answers_from_queue(self, answers: _AnswerWithAdditionalsType) -> None:
534+
"""Remove a set of answers from the outgoing queue."""
535+
for pending in self.queue:
536+
for record in answers:
537+
pending.answers.pop(record, None)
538+
539+
def async_ready(self) -> None:
534540
"""Process anything in the queue that is ready."""
535541
assert self.zc.loop is not None
536542
now = current_time_millis()
537543

538544
if len(self.queue) > 1 and self.queue[0].send_before > now:
539545
# There is more than one answer in the queue,
540546
# delay until we have to send it (first answer group reaches send_before)
541-
self.zc.loop.call_later(millis_to_seconds(self.queue[0].send_before - now), self._async_ready)
547+
self.zc.loop.call_later(millis_to_seconds(self.queue[0].send_before - now), self.async_ready)
542548
return
543549

544550
answers: _AnswerWithAdditionalsType = {}
@@ -549,12 +555,9 @@ def _async_ready(self) -> None:
549555
if len(self.queue):
550556
# If there are still groups in the queue that are not ready to send
551557
# be sure we schedule them to go out later
552-
self.zc.loop.call_later(millis_to_seconds(self.queue[0].send_after - now), self._async_ready)
558+
self.zc.loop.call_later(millis_to_seconds(self.queue[0].send_after - now), self.async_ready)
553559

554560
if answers:
555-
# If we have the same answer scheduled to go out, remove it
556-
for pending in self.queue:
557-
for record in answers:
558-
pending.answers.pop(record, None)
559-
561+
# If we have the same answer scheduled to go out, remove them
562+
self._remove_answers_from_queue(answers)
560563
self.zc.async_send(construct_outgoing_multicast_answers(answers))

0 commit comments

Comments
 (0)