Skip to content

Commit

Permalink
Fix zeroconf reconnect logic
Browse files Browse the repository at this point in the history
- Trigger on A record updates since they happen more often
- Fix logic reversal in accept_zeroconf_records
  • Loading branch information
bdraco committed Nov 6, 2023
1 parent 0eb26e5 commit 2710b3b
Showing 1 changed file with 57 additions and 40 deletions.
97 changes: 57 additions & 40 deletions tests/test_reconnect_logic.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import asyncio
import logging
from ipaddress import ip_address
from unittest.mock import MagicMock, patch

import pytest
from zeroconf import Zeroconf, current_time_millis ,RecordUpdate, DNSPointer, DNSAddress,DNSRecord
from zeroconf.const import _TYPE_PTR,_CLASS_IN,_TYPE_A
from zeroconf import (
DNSAddress,
DNSPointer,
DNSRecord,
RecordUpdate,
Zeroconf,
current_time_millis,
)
from zeroconf.asyncio import AsyncZeroconf
from ipaddress import ip_address
from zeroconf.const import _CLASS_IN, _TYPE_A, _TYPE_PTR

from aioesphomeapi import APIConnectionError
from aioesphomeapi.client import APIClient
from aioesphomeapi.reconnect_logic import ReconnectLogic, ReconnectLogicState

import logging

logging.getLogger("aioesphomeapi").setLevel(logging.DEBUG)


def _get_mock_zeroconf() -> MagicMock:
return MagicMock(spec=Zeroconf)

Expand Down Expand Up @@ -267,33 +275,48 @@ async def on_connect_fail(connect_exception: Exception) -> None:
@pytest.mark.parametrize(
("record", "should_trigger_zeroconf", "log_text"),
(
(DNSPointer(
"_esphomelib._tcp.local.",
_TYPE_PTR,
_CLASS_IN,
1000,
"mydevice._esphomelib._tcp.local."
), True,"received mDNS record"),
(
DNSPointer(
"_esphomelib._tcp.local.",
_TYPE_PTR,
_CLASS_IN,
1000,
"wrong_name._esphomelib._tcp.local."
), False,""),
"_esphomelib._tcp.local.",
_TYPE_PTR,
_CLASS_IN,
1000,
"mydevice._esphomelib._tcp.local.",
),
True,
"received mDNS record",
),
(
DNSPointer(
"_esphomelib._tcp.local.",
_TYPE_PTR,
_CLASS_IN,
1000,
"wrong_name._esphomelib._tcp.local.",
),
False,
"",
),
(
DNSAddress(
"mydevice.local.",
_TYPE_A,
_CLASS_IN,
1000,
ip_address("1.2.3.4").packed
), True,"received mDNS record"),
)
"mydevice.local.",
_TYPE_A,
_CLASS_IN,
1000,
ip_address("1.2.3.4").packed,
),
True,
"received mDNS record",
),
),
)
@pytest.mark.asyncio
async def test_reconnect_zeroconf(caplog: pytest.LogCaptureFixture, record: DNSRecord, should_trigger_zeroconf: bool, log_text: str) -> None:
async def test_reconnect_zeroconf(
caplog: pytest.LogCaptureFixture,
record: DNSRecord,
should_trigger_zeroconf: bool,
log_text: str,
) -> None:
"""Test that reconnect logic retry."""
on_disconnect_called = []
on_connect_called = []
Expand All @@ -320,9 +343,7 @@ async def on_connect_fail(connect_exception: Exception) -> None:
nonlocal on_connect_called
on_connect_fail_called.append(connect_exception)


mock_zeroconf = MagicMock(spec=Zeroconf)

mock_zeroconf = MagicMock(spec=Zeroconf)

rl = ReconnectLogic(
client=cli,
Expand All @@ -342,30 +363,26 @@ async def slow_connect_fail(*args, **kwargs):
async def quick_connect_fail(*args, **kwargs):
raise APIConnectionError

with patch.object(cli, "start_connection", side_effect=quick_connect_fail) as mock_start_connection:
with patch.object(
cli, "start_connection", side_effect=quick_connect_fail
) as mock_start_connection:
await rl.start()
await asyncio.sleep(0)

assert mock_start_connection.call_count == 1

with patch.object(cli, "start_connection", side_effect=slow_connect_fail) as mock_start_connection:
with patch.object(
cli, "start_connection", side_effect=slow_connect_fail
) as mock_start_connection:
await asyncio.sleep(0)

assert mock_start_connection.call_count == 0

rl.async_update_records(
mock_zeroconf,
current_time_millis(),
[
RecordUpdate(
record,
None
)
]
mock_zeroconf, current_time_millis(), [RecordUpdate(record, None)]
)
await asyncio.sleep(0)
assert mock_start_connection.call_count == int(should_trigger_zeroconf)
assert log_text in caplog.text


await rl.stop()

0 comments on commit 2710b3b

Please sign in to comment.