Fix uncaught Duco diagnostics client errors (#173191)

This commit is contained in:
Ronald van der Meer
2026-06-07 07:27:02 +02:00
committed by GitHub
parent fd8789d599
commit 4fe93f9c64
2 changed files with 43 additions and 15 deletions
+7 -1
View File
@@ -3,7 +3,7 @@
from dataclasses import asdict
from typing import Any
from duco_connectivity.exceptions import DucoConnectionError
from duco_connectivity.exceptions import DucoConnectionError, DucoError
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.const import CONF_HOST
@@ -52,6 +52,12 @@ async def async_get_config_entry_diagnostics(
translation_domain=DOMAIN,
translation_key="connection_error",
) from err
except DucoError as err:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="api_error",
translation_placeholders={"error": repr(err)},
) from err
api_info: dict[str, Any] = {"public_api_version": api_info_obj.public_api_version}
if api_info_obj.reported_api_version is not None:
+36 -14
View File
@@ -4,7 +4,12 @@ from dataclasses import replace
from http import HTTPStatus
from unittest.mock import AsyncMock
from duco_connectivity import ApiInfo, DucoConnectionError
from duco_connectivity import ApiInfo
from duco_connectivity.exceptions import (
DucoConnectionError,
DucoError,
DucoResponseError,
)
import pytest
from syrupy.assertion import SnapshotAssertion
@@ -16,6 +21,29 @@ from tests.common import MockConfigEntry
from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator
CLIENT_ERROR_CASES = [
pytest.param(
"async_get_api_info",
DucoConnectionError("Server disconnected"),
id="api-info-connection-error",
),
pytest.param(
"async_get_lan_info",
DucoConnectionError("Server disconnected"),
id="lan-info-connection-error",
),
pytest.param(
"async_get_diagnostics",
DucoResponseError(500, "/info", "bad response"),
id="diagnostics-response-error",
),
pytest.param(
"async_get_write_requests_remaining",
DucoResponseError(500, "/info", "bad response"),
id="write-budget-response-error",
),
]
@pytest.mark.usefixtures("init_integration")
async def test_diagnostics(
@@ -34,25 +62,19 @@ async def test_diagnostics(
@pytest.mark.usefixtures("init_integration")
@pytest.mark.parametrize(
"failing_method",
[
"async_get_api_info",
"async_get_lan_info",
"async_get_diagnostics",
"async_get_write_requests_remaining",
],
("failing_method", "raised_error"),
CLIENT_ERROR_CASES,
)
async def test_diagnostics_connection_error(
async def test_diagnostics_client_error(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_config_entry: MockConfigEntry,
mock_duco_client: AsyncMock,
failing_method: str,
raised_error: DucoError,
) -> None:
"""Test that a connection error during diagnostics returns a 500 response."""
getattr(mock_duco_client, failing_method).side_effect = DucoConnectionError(
"Server disconnected"
)
"""Test that client errors during diagnostics return a 500 response."""
getattr(mock_duco_client, failing_method).side_effect = raised_error
assert await async_setup_component(hass, DIAGNOSTICS_DOMAIN, {})
await hass.async_block_till_done()
client = await hass_client()
@@ -70,7 +92,7 @@ async def test_diagnostics_without_optional_software_version(
) -> None:
"""Test that an optional software version is omitted from diagnostics."""
# BoardInfo is a frozen dataclass, so the mock must be updated before
# integration setup — the coordinator stores board_info during async_setup.
# integration setup - the coordinator stores board_info during async_setup.
mock_duco_client.async_get_board_info.return_value = replace(
mock_duco_client.async_get_board_info.return_value,
software_version=None,