Raise exceptions in HEOS custom actions (#136546)

This commit is contained in:
Andrew Sayre 2025-01-28 07:08:40 -06:00 committed by GitHub
parent 79de8114d3
commit c4f8de8fd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 43 additions and 35 deletions

View File

@ -7,7 +7,7 @@ import voluptuous as vol
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import config_validation as cv, issue_registry as ir from homeassistant.helpers import config_validation as cv, issue_registry as ir
from .const import ( from .const import (
@ -46,7 +46,6 @@ def register(hass: HomeAssistant):
def _get_controller(hass: HomeAssistant) -> Heos: def _get_controller(hass: HomeAssistant) -> Heos:
"""Get the HEOS controller instance.""" """Get the HEOS controller instance."""
_LOGGER.warning( _LOGGER.warning(
"Actions 'heos.sign_in' and 'heos.sign_out' are deprecated and will be removed in the 2025.8.0 release" "Actions 'heos.sign_in' and 'heos.sign_out' are deprecated and will be removed in the 2025.8.0 release"
) )
@ -79,16 +78,25 @@ async def _sign_in_handler(service: ServiceCall) -> None:
try: try:
await controller.sign_in(username, password) await controller.sign_in(username, password)
except CommandAuthenticationError as err: except CommandAuthenticationError as err:
_LOGGER.error("Sign in failed: %s", err) raise ServiceValidationError(
translation_domain=DOMAIN, translation_key="sign_in_auth_error"
) from err
except HeosError as err: except HeosError as err:
_LOGGER.error("Unable to sign in: %s", err) raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="sign_in_error",
translation_placeholders={"error": str(err)},
) from err
async def _sign_out_handler(service: ServiceCall) -> None: async def _sign_out_handler(service: ServiceCall) -> None:
"""Sign out of the HEOS account.""" """Sign out of the HEOS account."""
controller = _get_controller(service.hass) controller = _get_controller(service.hass)
try: try:
await controller.sign_out() await controller.sign_out()
except HeosError as err: except HeosError as err:
_LOGGER.error("Unable to sign out: %s", err) raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="sign_out_error",
translation_placeholders={"error": str(err)},
) from err

View File

@ -100,6 +100,15 @@
"integration_not_loaded": { "integration_not_loaded": {
"message": "The HEOS integration is not loaded" "message": "The HEOS integration is not loaded"
}, },
"sign_in_auth_error": {
"message": "Failed to sign in: Invalid username and/or password"
},
"sign_in_error": {
"message": "Unable to sign in: {error}"
},
"sign_out_error": {
"message": "Unable to sign out: {error}"
},
"not_heos_media_player": { "not_heos_media_player": {
"message": "Entity {entity_id} is not a HEOS media player entity" "message": "Entity {entity_id} is not a HEOS media player entity"
}, },

View File

@ -11,7 +11,7 @@ from homeassistant.components.heos.const import (
SERVICE_SIGN_OUT, SERVICE_SIGN_OUT,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
@ -34,10 +34,7 @@ async def test_sign_in(
async def test_sign_in_failed( async def test_sign_in_failed(
hass: HomeAssistant, hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
config_entry: MockConfigEntry,
controller: Heos,
caplog: pytest.LogCaptureFixture,
) -> None: ) -> None:
"""Test sign-in service logs error when not connected.""" """Test sign-in service logs error when not connected."""
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
@ -47,22 +44,19 @@ async def test_sign_in_failed(
"", "Invalid credentials", 6 "", "Invalid credentials", 6
) )
await hass.services.async_call( with pytest.raises(ServiceValidationError):
DOMAIN, await hass.services.async_call(
SERVICE_SIGN_IN, DOMAIN,
{ATTR_USERNAME: "test@test.com", ATTR_PASSWORD: "password"}, SERVICE_SIGN_IN,
blocking=True, {ATTR_USERNAME: "test@test.com", ATTR_PASSWORD: "password"},
) blocking=True,
)
controller.sign_in.assert_called_once_with("test@test.com", "password") controller.sign_in.assert_called_once_with("test@test.com", "password")
assert "Sign in failed: Invalid credentials (6)" in caplog.text
async def test_sign_in_unknown_error( async def test_sign_in_unknown_error(
hass: HomeAssistant, hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
config_entry: MockConfigEntry,
controller: Heos,
caplog: pytest.LogCaptureFixture,
) -> None: ) -> None:
"""Test sign-in service logs error for failure.""" """Test sign-in service logs error for failure."""
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
@ -70,15 +64,15 @@ async def test_sign_in_unknown_error(
controller.sign_in.side_effect = HeosError() controller.sign_in.side_effect = HeosError()
await hass.services.async_call( with pytest.raises(HomeAssistantError):
DOMAIN, await hass.services.async_call(
SERVICE_SIGN_IN, DOMAIN,
{ATTR_USERNAME: "test@test.com", ATTR_PASSWORD: "password"}, SERVICE_SIGN_IN,
blocking=True, {ATTR_USERNAME: "test@test.com", ATTR_PASSWORD: "password"},
) blocking=True,
)
controller.sign_in.assert_called_once_with("test@test.com", "password") controller.sign_in.assert_called_once_with("test@test.com", "password")
assert "Unable to sign in" in caplog.text
async def test_sign_in_not_loaded_raises( async def test_sign_in_not_loaded_raises(
@ -123,17 +117,14 @@ async def test_sign_out_not_loaded_raises(
async def test_sign_out_unknown_error( async def test_sign_out_unknown_error(
hass: HomeAssistant, hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
config_entry: MockConfigEntry,
controller: Heos,
caplog: pytest.LogCaptureFixture,
) -> None: ) -> None:
"""Test the sign-out service.""" """Test the sign-out service."""
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id) assert await hass.config_entries.async_setup(config_entry.entry_id)
controller.sign_out.side_effect = HeosError() controller.sign_out.side_effect = HeosError()
await hass.services.async_call(DOMAIN, SERVICE_SIGN_OUT, {}, blocking=True) with pytest.raises(HomeAssistantError):
await hass.services.async_call(DOMAIN, SERVICE_SIGN_OUT, {}, blocking=True)
assert controller.sign_out.call_count == 1 assert controller.sign_out.call_count == 1
assert "Unable to sign out" in caplog.text