1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-02 08:26:41 +01:00

Add entity-unavailable and log-when-unavailable (#165486)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
David Bishop
2026-03-13 13:20:55 -07:00
committed by GitHub
parent 54ad67b810
commit bfe15a55c9
3 changed files with 95 additions and 7 deletions

View File

@@ -46,11 +46,18 @@ class LitterRobotDataUpdateCoordinator(DataUpdateCoordinator[None]):
async def _async_update_data(self) -> None:
"""Update all device states from the Litter-Robot API."""
await self.account.refresh_robots()
await self.account.load_pets()
for pet in self.account.pets:
# Need to fetch weight history for `get_visits_since`
await pet.fetch_weight_history()
try:
await self.account.refresh_robots()
await self.account.load_pets()
for pet in self.account.pets:
# Need to fetch weight history for `get_visits_since`
await pet.fetch_weight_history()
except LitterRobotLoginException as ex:
raise ConfigEntryAuthFailed("Invalid credentials") from ex
except LitterRobotException as ex:
raise UpdateFailed(
f"Unable to fetch data from the Whisker API: {ex}"
) from ex
async def _async_setup(self) -> None:
"""Set up the coordinator."""

View File

@@ -29,9 +29,9 @@ rules:
status: done
comment: No options to configure
docs-installation-parameters: done
entity-unavailable: todo
entity-unavailable: done
integration-owner: done
log-when-unavailable: todo
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: done
test-coverage:

View File

@@ -0,0 +1,81 @@
"""Tests for the Litter-Robot coordinator."""
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
from pylitterbot.exceptions import LitterRobotException, LitterRobotLoginException
from homeassistant.components.litterrobot.const import DOMAIN
from homeassistant.components.litterrobot.coordinator import UPDATE_INTERVAL
from homeassistant.components.vacuum import DOMAIN as VACUUM_DOMAIN
from homeassistant.config_entries import SOURCE_REAUTH
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from .common import VACUUM_ENTITY_ID
from .conftest import setup_integration
from tests.common import async_fire_time_changed
async def test_coordinator_update_error(
hass: HomeAssistant,
mock_account: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test entities become unavailable when coordinator update fails."""
await setup_integration(hass, mock_account, VACUUM_DOMAIN)
assert (state := hass.states.get(VACUUM_ENTITY_ID))
assert state.state != STATE_UNAVAILABLE
# Simulate an API error during update
mock_account.refresh_robots.side_effect = LitterRobotException("Unable to connect")
freezer.tick(UPDATE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert (state := hass.states.get(VACUUM_ENTITY_ID))
assert state.state == STATE_UNAVAILABLE
# Recover
mock_account.refresh_robots.side_effect = None
freezer.tick(UPDATE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert (state := hass.states.get(VACUUM_ENTITY_ID))
assert state.state != STATE_UNAVAILABLE
async def test_coordinator_update_auth_error(
hass: HomeAssistant,
mock_account: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test reauthentication flow is triggered on login error during update."""
entry = await setup_integration(hass, mock_account, VACUUM_DOMAIN)
assert (state := hass.states.get(VACUUM_ENTITY_ID))
assert state.state != STATE_UNAVAILABLE
# Simulate an authentication error during update
mock_account.refresh_robots.side_effect = LitterRobotLoginException(
"Invalid credentials"
)
freezer.tick(UPDATE_INTERVAL)
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert (state := hass.states.get(VACUUM_ENTITY_ID))
assert state.state == STATE_UNAVAILABLE
# Ensure a reauthentication flow was triggered
flows = hass.config_entries.flow.async_progress()
assert len(flows) == 1
flow = flows[0]
assert flow["step_id"] == "reauth_confirm"
assert flow["handler"] == DOMAIN
assert flow["context"].get("source") == SOURCE_REAUTH
assert flow["context"].get("entry_id") == entry.entry_id