Add action exceptions to UptimeRobot integration (#143587)

* Add action exceptions to UptimeRobot integration

* fix tests and strings
This commit is contained in:
Simone Chemelli 2025-05-26 20:47:46 +03:00 committed by GitHub
parent c3dec7fb2f
commit 6003f3d135
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 47 additions and 28 deletions

View File

@ -26,9 +26,7 @@ rules:
unique-config-entry: done unique-config-entry: done
# Silver # Silver
action-exceptions: action-exceptions: done
status: todo
comment: we should not swallow the exception in switch.py
config-entry-unloading: done config-entry-unloading: done
docs-configuration-parameters: done docs-configuration-parameters: done
docs-installation-parameters: done docs-installation-parameters: done

View File

@ -45,5 +45,10 @@
} }
} }
} }
},
"exceptions": {
"api_exception": {
"message": "Could not turn on/off monitoring: {error}"
}
} }
} }

View File

@ -12,9 +12,10 @@ from homeassistant.components.switch import (
SwitchEntityDescription, SwitchEntityDescription,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import API_ATTR_OK, LOGGER from .const import API_ATTR_OK, DOMAIN
from .coordinator import UptimeRobotConfigEntry from .coordinator import UptimeRobotConfigEntry
from .entity import UptimeRobotEntity from .entity import UptimeRobotEntity
@ -57,16 +58,21 @@ class UptimeRobotSwitch(UptimeRobotEntity, SwitchEntity):
try: try:
response = await self.api.async_edit_monitor(**kwargs) response = await self.api.async_edit_monitor(**kwargs)
except UptimeRobotAuthenticationException: except UptimeRobotAuthenticationException:
LOGGER.debug("API authentication error, calling reauth")
self.coordinator.config_entry.async_start_reauth(self.hass) self.coordinator.config_entry.async_start_reauth(self.hass)
return return
except UptimeRobotException as exception: except UptimeRobotException as exception:
LOGGER.error("API exception: %s", exception) raise HomeAssistantError(
return translation_domain=DOMAIN,
translation_key="api_exception",
translation_placeholders={"error": repr(exception)},
) from exception
if response.status != API_ATTR_OK: if response.status != API_ATTR_OK:
LOGGER.error("API exception: %s", response.error.message, exc_info=True) raise HomeAssistantError(
return translation_domain=DOMAIN,
translation_key="api_exception",
translation_placeholders={"error": response.error.message},
)
await self.coordinator.async_request_refresh() await self.coordinator.async_request_refresh()

View File

@ -3,7 +3,7 @@
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
from pyuptimerobot import UptimeRobotAuthenticationException from pyuptimerobot import UptimeRobotAuthenticationException, UptimeRobotException
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.const import ( from homeassistant.const import (
@ -14,6 +14,7 @@ from homeassistant.const import (
STATE_ON, STATE_ON,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from .common import ( from .common import (
MOCK_UPTIMEROBOT_CONFIG_ENTRY_DATA, MOCK_UPTIMEROBOT_CONFIG_ENTRY_DATA,
@ -128,18 +129,20 @@ async def test_authentication_error(
assert config_entry_reauth.assert_called assert config_entry_reauth.assert_called
async def test_refresh_data( async def test_action_execution_failure(hass: HomeAssistant) -> None:
hass: HomeAssistant, caplog: pytest.LogCaptureFixture """Test turning switch on/off failure."""
) -> None:
"""Test authentication error turning switch on/off."""
await setup_uptimerobot_integration(hass) await setup_uptimerobot_integration(hass)
entity = hass.states.get(UPTIMEROBOT_SWITCH_TEST_ENTITY) entity = hass.states.get(UPTIMEROBOT_SWITCH_TEST_ENTITY)
assert entity.state == STATE_ON assert entity.state == STATE_ON
with patch( with (
"homeassistant.helpers.update_coordinator.DataUpdateCoordinator.async_request_refresh" patch(
) as coordinator_refresh: "pyuptimerobot.UptimeRobot.async_edit_monitor",
side_effect=UptimeRobotException,
),
pytest.raises(HomeAssistantError) as exc_info,
):
await hass.services.async_call( await hass.services.async_call(
SWITCH_DOMAIN, SWITCH_DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
@ -147,12 +150,14 @@ async def test_refresh_data(
blocking=True, blocking=True,
) )
assert coordinator_refresh.assert_called assert exc_info.value.translation_domain == "uptimerobot"
assert exc_info.value.translation_key == "api_exception"
assert exc_info.value.translation_placeholders == {
"error": "UptimeRobotException()"
}
async def test_switch_api_failure( async def test_switch_api_failure(hass: HomeAssistant) -> None:
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test general exception turning switch on/off.""" """Test general exception turning switch on/off."""
await setup_uptimerobot_integration(hass) await setup_uptimerobot_integration(hass)
@ -163,11 +168,16 @@ async def test_switch_api_failure(
"pyuptimerobot.UptimeRobot.async_edit_monitor", "pyuptimerobot.UptimeRobot.async_edit_monitor",
return_value=mock_uptimerobot_api_response(key=MockApiResponseKey.ERROR), return_value=mock_uptimerobot_api_response(key=MockApiResponseKey.ERROR),
): ):
await hass.services.async_call( with pytest.raises(HomeAssistantError) as exc_info:
SWITCH_DOMAIN, await hass.services.async_call(
SERVICE_TURN_OFF, SWITCH_DOMAIN,
{ATTR_ENTITY_ID: UPTIMEROBOT_SWITCH_TEST_ENTITY}, SERVICE_TURN_OFF,
blocking=True, {ATTR_ENTITY_ID: UPTIMEROBOT_SWITCH_TEST_ENTITY},
) blocking=True,
)
assert "API exception" in caplog.text assert exc_info.value.translation_domain == "uptimerobot"
assert exc_info.value.translation_key == "api_exception"
assert exc_info.value.translation_placeholders == {
"error": "test error from API."
}