From 02e719292dc96c217529e24e50fbbacb06bb547e Mon Sep 17 00:00:00 2001 From: Marco <46717884+marcodutto@users.noreply.github.com> Date: Tue, 15 Sep 2026 16:56:44 +0200 Subject: [PATCH] Retry Smarty coordinator update after transient failure (#182309) --- .../components/smarty/coordinator.py | 5 +- tests/components/smarty/test_sensor.py | 46 ++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/smarty/coordinator.py b/homeassistant/components/smarty/coordinator.py index 2de862f5c649..ba54ba403b11 100644 --- a/homeassistant/components/smarty/coordinator.py +++ b/homeassistant/components/smarty/coordinator.py @@ -45,4 +45,7 @@ class SmartyCoordinator(DataUpdateCoordinator[None]): async def _async_update_data(self) -> None: """Fetch data from Smarty.""" if not await self.hass.async_add_executor_job(self.client.update): - raise UpdateFailed("Failed to update Smarty data") + raise UpdateFailed( + "Failed to update Smarty data", + retry_after=2 if self.last_update_success else None, + ) diff --git a/tests/components/smarty/test_sensor.py b/tests/components/smarty/test_sensor.py index 7ec44886952e..5a7a9ba6ba4a 100644 --- a/tests/components/smarty/test_sensor.py +++ b/tests/components/smarty/test_sensor.py @@ -1,7 +1,9 @@ """Tests for the Smarty sensor platform.""" +from datetime import timedelta from unittest.mock import AsyncMock, patch +from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion @@ -11,7 +13,7 @@ from homeassistant.helpers import entity_registry as er from . import setup_integration -from tests.common import MockConfigEntry, snapshot_platform +from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform @pytest.mark.freeze_time("2023-10-21") @@ -27,3 +29,45 @@ async def test_all_entities( await setup_integration(hass, mock_config_entry) await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + +async def test_retry_after_failure( + hass: HomeAssistant, + mock_smarty: AsyncMock, + mock_config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, +) -> None: + """Test retrying once after a transient update failure.""" + with patch("homeassistant.components.smarty.PLATFORMS", [Platform.SENSOR]): + await setup_integration(hass, mock_config_entry) + + mock_smarty.update.reset_mock() + mock_smarty.update.side_effect = [False, False, True] + + # First scheduled update fails after the normal 30-second interval. + freezer.tick(timedelta(seconds=30)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert mock_smarty.update.call_count == 1 + + # The coordinator retries after 2 seconds. + freezer.tick(timedelta(seconds=2)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert mock_smarty.update.call_count == 2 + + # A second consecutive failure falls back to the normal interval. + freezer.tick(timedelta(seconds=2)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert mock_smarty.update.call_count == 2 + + # The next update occurs after the normal 30-second interval. + freezer.tick(timedelta(seconds=28)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert mock_smarty.update.call_count == 3