Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion custom_components/poollab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,17 @@ async def _async_update_poollab(self):
# Raising ConfigEntryAuthFailed will cancel future updates
# and start a config flow with SOURCE_REAUTH (async_step_reauth)
raise ConfigEntryAuthFailed from err
except TimeoutError as err:
raise UpdateFailed(
"PoolLab cloud request timed out; "
"no new measurements were fetched. Home Assistant will retry automatically."
) from err
except Exception as err:
raise UpdateFailed(f"Unknown error communicating with API: {err}") from err
detail = str(err).strip() or "no error message provided"
raise UpdateFailed(
f"PoolLab API request failed ({type(err).__name__}): {detail}. "
"Home Assistant will retry automatically."
) from err

def add_entity_ref(self, entity) -> None:
"""Add an entity reference to the coordinator."""
Expand Down
65 changes: 65 additions & 0 deletions tests/test_coordinator_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""Regression tests for PoolLab API error messages."""

import asyncio
from unittest.mock import AsyncMock, Mock

import pytest

from homeassistant.helpers.update_coordinator import UpdateFailed

from custom_components.poollab import PoolLabCoordinator
from custom_components.poollab.poollab import PoolLabApi


@pytest.mark.parametrize(
("error", "expected_message"),
[
(
TimeoutError(),
"PoolLab cloud request timed out; "
"no new measurements were fetched. Home Assistant will retry automatically.",
),
(
RuntimeError(),
"PoolLab API request failed (RuntimeError): no error message provided. "
"Home Assistant will retry automatically.",
),
(
ConnectionError("Connection lost"),
"PoolLab API request failed (ConnectionError): Connection lost. "
"Home Assistant will retry automatically.",
),
],
)
async def test_api_failure_has_useful_message(hass, error, expected_message):
"""Report the failure type even when the exception message is empty."""
api = Mock(spec=PoolLabApi)
api.request = AsyncMock(side_effect=error)
coordinator = PoolLabCoordinator(hass, api)

with pytest.raises(UpdateFailed) as exc_info:
await coordinator._async_update_poollab()

assert str(exc_info.value) == expected_message
assert exc_info.value.__cause__ is error
api.request.assert_awaited_once()


async def test_request_deadline_has_timeout_message(hass, monkeypatch):
"""An expired request deadline must use the timeout-specific message."""
timeout = asyncio.timeout
monkeypatch.setattr(
"custom_components.poollab.asyncio.timeout", lambda _: timeout(0)
)

async def pending_request():
await asyncio.sleep(0)

api = Mock(spec=PoolLabApi)
api.request = AsyncMock(side_effect=pending_request)
coordinator = PoolLabCoordinator(hass, api)

with pytest.raises(UpdateFailed, match="cloud request timed out;"):
await coordinator._async_update_poollab()

assert api.request.await_count == 1
Loading