Compare commits

...

8 Commits

Author SHA1 Message Date
G Johansson 6a367d3386 type 2026-05-10 14:16:24 +00:00
G Johansson 3a81bfb233 Move to debug 2026-05-10 14:15:27 +00:00
G Johansson 79d60847f2 Fix 2026-05-10 14:08:44 +00:00
G Johansson 5b1ad7dd32 fix 2026-05-10 14:07:19 +00:00
G Johansson fd6a42396a Add to test 2026-05-10 14:02:51 +00:00
G Johansson 733937f435 close resolver 2026-05-10 13:56:57 +00:00
G Johansson ddc8343272 Fix 2026-05-10 13:49:31 +00:00
G Johansson 2969d62ae3 Handle aiodns pycares exceptions "leaking" 2026-05-07 19:31:56 +00:00
3 changed files with 34 additions and 22 deletions
+15 -13
View File
@@ -1,11 +1,9 @@
"""Adds config flow for dnsip integration."""
import asyncio
import contextlib
from typing import Any, Literal
import aiodns
from aiodns.error import DNSError
import voluptuous as vol
from homeassistant.config_entries import (
@@ -61,15 +59,16 @@ async def async_validate_hostname(
async def async_check(
hostname: str, resolver: str, qtype: Literal["A", "AAAA"], port: int = 53
) -> bool:
"""Return if able to resolve hostname."""
result: bool = False
with contextlib.suppress(DNSError):
_resolver = aiodns.DNSResolver(
nameservers=[resolver], udp_port=port, tcp_port=port
)
result = bool(await _resolver.query(hostname, qtype))
) -> list:
"""Return list of hostnames."""
_resolver = aiodns.DNSResolver(
nameservers=[resolver], udp_port=port, tcp_port=port
)
try:
result = await _resolver.query(hostname, qtype)
finally:
await _resolver.close()
return result
result: dict[str, bool] = {}
@@ -78,11 +77,14 @@ async def async_validate_hostname(
async_check(hostname, resolver_ipv4, "A", port=port),
async_check(hostname, resolver_ipv6, "AAAA", port=port_ipv6),
async_check(hostname, resolver_ipv4, "AAAA", port=port),
return_exceptions=True,
)
result[CONF_IPV4] = tasks[0]
result[CONF_IPV6] = tasks[1]
result[CONF_IPV6_V4] = tasks[2]
result[CONF_IPV4] = bool(tasks[0]) if not isinstance(tasks[0], Exception) else False
result[CONF_IPV6] = bool(tasks[1]) if not isinstance(tasks[1], Exception) else False
result[CONF_IPV6_V4] = (
bool(tasks[2]) if not isinstance(tasks[2], Exception) else False
)
return result
+9 -7
View File
@@ -7,7 +7,7 @@ import logging
from typing import Literal
import aiodns
from aiodns.error import DNSError
from pycares import AresError
from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
@@ -114,18 +114,20 @@ class WanIpSensor(SensorEntity):
async def async_update(self) -> None:
"""Get the current DNS IP address for hostname."""
if self.resolver._closed: # noqa: SLF001
self.create_dns_resolver()
response = None
try:
async with asyncio.timeout(10):
if self.resolver._closed: # noqa: SLF001
self.create_dns_resolver()
response = await self.resolver.query(self.hostname, self.querytype)
except TimeoutError as err:
_LOGGER.debug("Timeout while resolving host: %s", err)
await self.resolver.close()
except DNSError as err:
_LOGGER.warning("Exception while resolving host: %s", err)
await self.resolver.close()
if self.resolver:
await self.resolver.close()
except (aiodns.error.DNSError, AresError, asyncio.CancelledError) as err:
_LOGGER.debug("Exception while resolving host: %s", err)
if self.resolver:
await self.resolver.close()
if response:
sorted_ips = sort_ips(
+10 -2
View File
@@ -3,6 +3,7 @@
from unittest.mock import patch
from aiodns.error import DNSError
from pycares import AresError
import pytest
from homeassistant import config_entries
@@ -121,7 +122,14 @@ async def test_form_adv(hass: HomeAssistant) -> None:
assert len(mock_setup_entry.mock_calls) == 1
async def test_form_error(hass: HomeAssistant) -> None:
@pytest.mark.parametrize(
"error",
[
(DNSError),
(AresError),
],
)
async def test_form_error(hass: HomeAssistant, error: type[Exception]) -> None:
"""Test validate url fails."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
@@ -129,7 +137,7 @@ async def test_form_error(hass: HomeAssistant) -> None:
with patch(
"homeassistant.components.dnsip.config_flow.aiodns.DNSResolver",
side_effect=DNSError("Did not find"),
side_effect=error("Did not find"),
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],