From 668626b920af178a6a2850474cb4993d1e93aa58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Diego=20Rodr=C3=ADguez=20Royo?= Date: Mon, 28 Oct 2024 16:48:56 +0100 Subject: [PATCH] Add ServiceValidationError to Home Connect (#129309) Co-authored-by: Joost Lekkerkerker --- .../components/home_connect/__init__.py | 11 +++ .../components/home_connect/const.py | 5 ++ .../components/home_connect/light.py | 59 +++++++++++++-- .../components/home_connect/number.py | 30 ++++++-- .../components/home_connect/strings.json | 44 +++++++++++ .../components/home_connect/switch.py | 73 ++++++++++++++++--- homeassistant/components/home_connect/time.py | 27 +++++-- tests/components/home_connect/test_light.py | 13 +++- tests/components/home_connect/test_number.py | 20 ++--- tests/components/home_connect/test_switch.py | 43 +++++++++-- tests/components/home_connect/test_time.py | 20 ++--- 11 files changed, 285 insertions(+), 60 deletions(-) diff --git a/homeassistant/components/home_connect/__init__.py b/homeassistant/components/home_connect/__init__.py index 693ac3d5396..c60515eb57f 100644 --- a/homeassistant/components/home_connect/__init__.py +++ b/homeassistant/components/home_connect/__init__.py @@ -303,3 +303,14 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> _LOGGER.debug("Migration to version %s successful", config_entry.version) return True + + +def get_dict_from_home_connect_error(err: api.HomeConnectError) -> dict[str, Any]: + """Return a dict from a Home Connect error.""" + return ( + err.args[0] + if len(err.args) > 0 and isinstance(err.args[0], dict) + else {"description": err.args[0]} + if len(err.args) > 0 and isinstance(err.args[0], str) + else {} + ) diff --git a/homeassistant/components/home_connect/const.py b/homeassistant/components/home_connect/const.py index 71f10156c36..e49a56b9b97 100644 --- a/homeassistant/components/home_connect/const.py +++ b/homeassistant/components/home_connect/const.py @@ -114,6 +114,11 @@ ATTR_STEPSIZE = "stepsize" ATTR_UNIT = "unit" ATTR_VALUE = "value" +SVE_TRANSLATION_PLACEHOLDER_APPLIANCE_NAME = "appliance_name" +SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID = "entity_id" +SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY = "setting_key" +SVE_TRANSLATION_PLACEHOLDER_VALUE = "value" + OLD_NEW_UNIQUE_ID_SUFFIX_MAP = { "ChildLock": BSH_CHILD_LOCK_STATE, "Operation State": BSH_OPERATION_STATE, diff --git a/homeassistant/components/home_connect/light.py b/homeassistant/components/home_connect/light.py index dfae7fdaa20..873e7d24f93 100644 --- a/homeassistant/components/home_connect/light.py +++ b/homeassistant/components/home_connect/light.py @@ -17,9 +17,11 @@ from homeassistant.components.light import ( ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers.entity_platform import AddEntitiesCallback import homeassistant.util.color as color_util +from . import get_dict_from_home_connect_error from .api import ConfigEntryAuth, HomeConnectDevice from .const import ( ATTR_VALUE, @@ -35,6 +37,7 @@ from .const import ( REFRIGERATION_EXTERNAL_LIGHT_POWER, REFRIGERATION_INTERNAL_LIGHT_BRIGHTNESS, REFRIGERATION_INTERNAL_LIGHT_POWER, + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID, ) from .entity import HomeConnectEntity @@ -149,8 +152,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity): self.device.appliance.set_setting, self.bsh_key, True ) except HomeConnectError as err: - _LOGGER.error("Error while trying to turn on light: %s", err) - return + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="turn_on_light", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id, + }, + ) from err if self._custom_color_key: if ( ATTR_RGB_COLOR in kwargs or ATTR_HS_COLOR in kwargs @@ -162,8 +171,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity): self._enable_custom_color_value_key, ) except HomeConnectError as err: - _LOGGER.error("Error while trying selecting custom color: %s", err) - return + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="select_light_custom_color", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id, + }, + ) from err if ATTR_RGB_COLOR in kwargs: hex_val = color_util.color_rgb_to_hex(*kwargs[ATTR_RGB_COLOR]) @@ -174,7 +189,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity): f"#{hex_val}", ) except HomeConnectError as err: - _LOGGER.error("Error while trying setting the color: %s", err) + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="set_light_color", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id, + }, + ) from err elif (ATTR_BRIGHTNESS in kwargs or ATTR_HS_COLOR in kwargs) and ( self._attr_brightness is not None or ATTR_BRIGHTNESS in kwargs ): @@ -199,7 +221,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity): f"#{hex_val}", ) except HomeConnectError as err: - _LOGGER.error("Error while trying setting the color: %s", err) + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="set_light_color", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id, + }, + ) from err elif self._brightness_key and ATTR_BRIGHTNESS in kwargs: _LOGGER.debug( @@ -217,7 +246,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity): self.device.appliance.set_setting, self._brightness_key, brightness ) except HomeConnectError as err: - _LOGGER.error("Error while trying set the brightness: %s", err) + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="set_light_brightness", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id, + }, + ) from err self.async_entity_update() @@ -229,7 +265,14 @@ class HomeConnectLight(HomeConnectEntity, LightEntity): self.device.appliance.set_setting, self.bsh_key, False ) except HomeConnectError as err: - _LOGGER.error("Error while trying to turn off light: %s", err) + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="turn_off_light", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id, + }, + ) from err self.async_entity_update() async def async_update(self) -> None: diff --git a/homeassistant/components/home_connect/number.py b/homeassistant/components/home_connect/number.py index 43220461404..ad853df77d0 100644 --- a/homeassistant/components/home_connect/number.py +++ b/homeassistant/components/home_connect/number.py @@ -13,10 +13,21 @@ from homeassistant.components.number import ( ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import get_dict_from_home_connect_error from .api import ConfigEntryAuth -from .const import ATTR_CONSTRAINTS, ATTR_STEPSIZE, ATTR_UNIT, ATTR_VALUE, DOMAIN +from .const import ( + ATTR_CONSTRAINTS, + ATTR_STEPSIZE, + ATTR_UNIT, + ATTR_VALUE, + DOMAIN, + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID, + SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY, + SVE_TRANSLATION_PLACEHOLDER_VALUE, +) from .entity import HomeConnectEntity _LOGGER = logging.getLogger(__name__) @@ -109,13 +120,16 @@ class HomeConnectNumberEntity(HomeConnectEntity, NumberEntity): value, ) except HomeConnectError as err: - _LOGGER.error( - "Error setting value %s to %s for %s: %s", - value, - self.bsh_key, - self.entity_id, - err, - ) + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="set_setting", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id, + SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY: self.bsh_key, + SVE_TRANSLATION_PLACEHOLDER_VALUE: str(value), + }, + ) from err async def async_fetch_constraints(self) -> None: """Fetch the max and min values and step for the number entity.""" diff --git a/homeassistant/components/home_connect/strings.json b/homeassistant/components/home_connect/strings.json index f4fa4dc5f86..f1e5e789de1 100644 --- a/homeassistant/components/home_connect/strings.json +++ b/homeassistant/components/home_connect/strings.json @@ -21,6 +21,50 @@ "default": "[%key:common::config_flow::create_entry::authenticated%]" } }, + "exceptions": { + "turn_on_light": { + "message": "Error while trying to turn on {entity_id}: {description}" + }, + "turn_off_light": { + "message": "Error while trying to turn off {entity_id}: {description}" + }, + "set_light_brightness": { + "message": "Error while trying to set brightness of {entity_id}: {description}" + }, + "select_light_custom_color": { + "message": "Error while trying to select custom color of {entity_id}: {description}" + }, + "set_light_color": { + "message": "Error while trying to set color of {entity_id}: {description}" + }, + "set_light_effect": { + "message": "Error while trying to set effect of {entity_id}: {description}" + }, + "set_setting": { + "message": "Error while trying to set \"{value}\" to \"{key}\" setting for {entity_id}: {description}" + }, + "turn_on": { + "message": "Error while trying to turn on {entity_id} ({key}): {description}" + }, + "turn_off": { + "message": "Error while trying to turn off {entity_id} ({key}): {description}" + }, + "start_program": { + "message": "Error while trying to start program {program}: {description}" + }, + "stop_program": { + "message": "Error while trying to stop program {program}: {description}" + }, + "power_on": { + "message": "Error while trying to turn on {appliance_name}: {description}" + }, + "power_off": { + "message": "Error while trying to turn off {appliance_name} with value \"{value}\": {description}" + }, + "turn_off_not_supported": { + "message": "{appliance_name} does not support turning off or entering standby mode." + } + }, "services": { "start_program": { "name": "Start program", diff --git a/homeassistant/components/home_connect/switch.py b/homeassistant/components/home_connect/switch.py index 8401c130c48..1d26c7a6727 100644 --- a/homeassistant/components/home_connect/switch.py +++ b/homeassistant/components/home_connect/switch.py @@ -9,8 +9,10 @@ from homeconnect.api import HomeConnectError from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import get_dict_from_home_connect_error from .api import ConfigEntryAuth from .const import ( ATTR_VALUE, @@ -25,6 +27,10 @@ from .const import ( REFRIGERATION_DISPENSER, REFRIGERATION_SUPERMODEFREEZER, REFRIGERATION_SUPERMODEREFRIGERATOR, + SVE_TRANSLATION_PLACEHOLDER_APPLIANCE_NAME, + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID, + SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY, + SVE_TRANSLATION_PLACEHOLDER_VALUE, ) from .entity import HomeConnectDevice, HomeConnectEntity @@ -139,9 +145,16 @@ class HomeConnectSwitch(HomeConnectEntity, SwitchEntity): self.device.appliance.set_setting, self.entity_description.key, True ) except HomeConnectError as err: - _LOGGER.error("Error while trying to turn on: %s", err) self._attr_available = False - return + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="turn_on", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id, + SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY: self.bsh_key, + }, + ) from err self._attr_available = True self.async_entity_update() @@ -157,7 +170,15 @@ class HomeConnectSwitch(HomeConnectEntity, SwitchEntity): except HomeConnectError as err: _LOGGER.error("Error while trying to turn off: %s", err) self._attr_available = False - return + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="turn_off", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id, + SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY: self.bsh_key, + }, + ) from err self._attr_available = True self.async_entity_update() @@ -200,7 +221,14 @@ class HomeConnectProgramSwitch(HomeConnectEntity, SwitchEntity): self.device.appliance.start_program, self.program_name ) except HomeConnectError as err: - _LOGGER.error("Error while trying to start program: %s", err) + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="start_program", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + "program": self.program_name, + }, + ) from err self.async_entity_update() async def async_turn_off(self, **kwargs: Any) -> None: @@ -209,7 +237,14 @@ class HomeConnectProgramSwitch(HomeConnectEntity, SwitchEntity): try: await self.hass.async_add_executor_job(self.device.appliance.stop_program) except HomeConnectError as err: - _LOGGER.error("Error while trying to stop program: %s", err) + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="stop_program", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + "program": self.program_name, + }, + ) from err self.async_entity_update() async def async_update(self) -> None: @@ -255,15 +290,27 @@ class HomeConnectPowerSwitch(HomeConnectEntity, SwitchEntity): self.device.appliance.set_setting, BSH_POWER_STATE, BSH_POWER_ON ) except HomeConnectError as err: - _LOGGER.error("Error while trying to turn on device: %s", err) self._attr_is_on = False + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="power_on", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_APPLIANCE_NAME: self.device.appliance.name, + }, + ) from err self.async_entity_update() async def async_turn_off(self, **kwargs: Any) -> None: """Switch the device off.""" if self.power_off_state is None: - _LOGGER.debug("This appliance type does not support turning off") - return + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="turn_off_not_supported", + translation_placeholders={ + SVE_TRANSLATION_PLACEHOLDER_APPLIANCE_NAME: self.device.appliance.name + }, + ) _LOGGER.debug("tried to switch off %s", self.name) try: await self.hass.async_add_executor_job( @@ -272,8 +319,16 @@ class HomeConnectPowerSwitch(HomeConnectEntity, SwitchEntity): self.power_off_state, ) except HomeConnectError as err: - _LOGGER.error("Error while trying to turn off device: %s", err) self._attr_is_on = True + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="power_off", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_APPLIANCE_NAME: self.device.appliance.name, + SVE_TRANSLATION_PLACEHOLDER_VALUE: self.power_off_state, + }, + ) from err self.async_entity_update() async def async_update(self) -> None: diff --git a/homeassistant/components/home_connect/time.py b/homeassistant/components/home_connect/time.py index ee471f0b1ea..946a2354938 100644 --- a/homeassistant/components/home_connect/time.py +++ b/homeassistant/components/home_connect/time.py @@ -8,10 +8,18 @@ from homeconnect.api import HomeConnectError from homeassistant.components.time import TimeEntity, TimeEntityDescription from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers.entity_platform import AddEntitiesCallback +from . import get_dict_from_home_connect_error from .api import ConfigEntryAuth -from .const import ATTR_VALUE, DOMAIN +from .const import ( + ATTR_VALUE, + DOMAIN, + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID, + SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY, + SVE_TRANSLATION_PLACEHOLDER_VALUE, +) from .entity import HomeConnectEntity _LOGGER = logging.getLogger(__name__) @@ -75,13 +83,16 @@ class HomeConnectTimeEntity(HomeConnectEntity, TimeEntity): time_to_seconds(value), ) except HomeConnectError as err: - _LOGGER.error( - "Error setting value %s to %s for %s: %s", - value, - self.bsh_key, - self.entity_id, - err, - ) + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="set_setting", + translation_placeholders={ + **get_dict_from_home_connect_error(err), + SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID: self.entity_id, + SVE_TRANSLATION_PLACEHOLDER_SETTING_KEY: self.bsh_key, + SVE_TRANSLATION_PLACEHOLDER_VALUE: str(value), + }, + ) from err async def async_update(self) -> None: """Update the Time setting status.""" diff --git a/tests/components/home_connect/test_light.py b/tests/components/home_connect/test_light.py index 7383609f50b..7a9747929c9 100644 --- a/tests/components/home_connect/test_light.py +++ b/tests/components/home_connect/test_light.py @@ -27,6 +27,7 @@ from homeassistant.const import ( Platform, ) from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from .conftest import get_all_appliances @@ -232,6 +233,7 @@ async def test_light_functionality( "mock_attr", "attr_side_effect", "problematic_appliance", + "exception_match", ), [ ( @@ -246,6 +248,7 @@ async def test_light_functionality( "set_setting", [HomeConnectError, HomeConnectError], "Hood", + r"Error.*turn.*on.*", ), ( "light.hood_functional_light", @@ -260,6 +263,7 @@ async def test_light_functionality( "set_setting", [HomeConnectError, HomeConnectError], "Hood", + r"Error.*turn.*on.*", ), ( "light.hood_functional_light", @@ -271,6 +275,7 @@ async def test_light_functionality( "set_setting", [HomeConnectError, HomeConnectError], "Hood", + r"Error.*turn.*off.*", ), ( "light.hood_ambient_light", @@ -285,6 +290,7 @@ async def test_light_functionality( "set_setting", [HomeConnectError, HomeConnectError], "Hood", + r"Error.*turn.*on.*", ), ( "light.hood_ambient_light", @@ -299,6 +305,7 @@ async def test_light_functionality( "set_setting", [HomeConnectError, None, HomeConnectError], "Hood", + r"Error.*set.*color.*", ), ], indirect=["problematic_appliance"], @@ -311,6 +318,7 @@ async def test_switch_exception_handling( mock_attr: str, attr_side_effect: list, problematic_appliance: Mock, + exception_match: str, bypass_throttle: Generator[None], hass: HomeAssistant, integration_setup: Callable[[], Awaitable[bool]], @@ -333,5 +341,8 @@ async def test_switch_exception_handling( problematic_appliance.status.update(status) service_data["entity_id"] = entity_id - await hass.services.async_call(LIGHT_DOMAIN, service, service_data, blocking=True) + with pytest.raises(ServiceValidationError, match=exception_match): + await hass.services.async_call( + LIGHT_DOMAIN, service, service_data, blocking=True + ) assert getattr(problematic_appliance, mock_attr).call_count == len(attr_side_effect) diff --git a/tests/components/home_connect/test_number.py b/tests/components/home_connect/test_number.py index fc17df7b32c..d822f791e40 100644 --- a/tests/components/home_connect/test_number.py +++ b/tests/components/home_connect/test_number.py @@ -24,6 +24,7 @@ from homeassistant.components.number import ( from homeassistant.config_entries import ConfigEntryState from homeassistant.const import ATTR_ENTITY_ID, Platform from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from .conftest import get_all_appliances @@ -160,13 +161,14 @@ async def test_number_entity_error( with pytest.raises(HomeConnectError): getattr(problematic_appliance, mock_attr)() - await hass.services.async_call( - NUMBER_DOMAIN, - SERVICE_SET_VALUE, - { - ATTR_ENTITY_ID: entity_id, - SERVICE_ATTR_VALUE: DEFAULT_MIN_VALUE, - }, - blocking=True, - ) + with pytest.raises(ServiceValidationError, match=r"Error.*set.*setting.*"): + await hass.services.async_call( + NUMBER_DOMAIN, + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: entity_id, + SERVICE_ATTR_VALUE: DEFAULT_MIN_VALUE, + }, + blocking=True, + ) assert getattr(problematic_appliance, mock_attr).call_count == 2 diff --git a/tests/components/home_connect/test_switch.py b/tests/components/home_connect/test_switch.py index 1f1da1cd790..1f3ce0ad756 100644 --- a/tests/components/home_connect/test_switch.py +++ b/tests/components/home_connect/test_switch.py @@ -26,6 +26,7 @@ from homeassistant.const import ( Platform, ) from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from .conftest import get_all_appliances @@ -153,7 +154,14 @@ async def test_switch_functionality( @pytest.mark.parametrize( - ("entity_id", "status", "service", "mock_attr", "problematic_appliance"), + ( + "entity_id", + "status", + "service", + "mock_attr", + "problematic_appliance", + "exception_match", + ), [ ( "switch.dishwasher_program_mix", @@ -161,6 +169,7 @@ async def test_switch_functionality( SERVICE_TURN_ON, "start_program", "Dishwasher", + r"Error.*start.*program.*", ), ( "switch.dishwasher_program_mix", @@ -168,6 +177,7 @@ async def test_switch_functionality( SERVICE_TURN_OFF, "stop_program", "Dishwasher", + r"Error.*stop.*program.*", ), ( "switch.dishwasher_power", @@ -175,6 +185,7 @@ async def test_switch_functionality( SERVICE_TURN_ON, "set_setting", "Dishwasher", + r"Error.*turn.*on.*appliance.*", ), ( "switch.dishwasher_power", @@ -182,6 +193,7 @@ async def test_switch_functionality( SERVICE_TURN_OFF, "set_setting", "Dishwasher", + r"Error.*turn.*off.*appliance.*value.*", ), ( "switch.dishwasher_child_lock", @@ -189,6 +201,7 @@ async def test_switch_functionality( SERVICE_TURN_ON, "set_setting", "Dishwasher", + r"Error.*turn.*on.*key.*", ), ( "switch.dishwasher_child_lock", @@ -196,6 +209,7 @@ async def test_switch_functionality( SERVICE_TURN_OFF, "set_setting", "Dishwasher", + r"Error.*turn.*off.*key.*", ), ], indirect=["problematic_appliance"], @@ -205,6 +219,7 @@ async def test_switch_exception_handling( status: dict, service: str, mock_attr: str, + exception_match: str, bypass_throttle: Generator[None], hass: HomeAssistant, integration_setup: Callable[[], Awaitable[bool]], @@ -227,9 +242,10 @@ async def test_switch_exception_handling( with pytest.raises(HomeConnectError): getattr(problematic_appliance, mock_attr)() - await hass.services.async_call( - SWITCH_DOMAIN, service, {"entity_id": entity_id}, blocking=True - ) + with pytest.raises(ServiceValidationError, match=exception_match): + await hass.services.async_call( + SWITCH_DOMAIN, service, {"entity_id": entity_id}, blocking=True + ) assert getattr(problematic_appliance, mock_attr).call_count == 2 @@ -289,7 +305,14 @@ async def test_ent_desc_switch_functionality( @pytest.mark.parametrize( - ("entity_id", "status", "service", "mock_attr", "problematic_appliance"), + ( + "entity_id", + "status", + "service", + "mock_attr", + "problematic_appliance", + "exception_match", + ), [ ( "switch.fridgefreezer_freezer_super_mode", @@ -297,6 +320,7 @@ async def test_ent_desc_switch_functionality( SERVICE_TURN_ON, "set_setting", "FridgeFreezer", + r"Error.*turn.*on.*key.*", ), ( "switch.fridgefreezer_freezer_super_mode", @@ -304,6 +328,7 @@ async def test_ent_desc_switch_functionality( SERVICE_TURN_OFF, "set_setting", "FridgeFreezer", + r"Error.*turn.*off.*key.*", ), ], indirect=["problematic_appliance"], @@ -313,6 +338,7 @@ async def test_ent_desc_switch_exception_handling( status: dict, service: str, mock_attr: str, + exception_match: str, bypass_throttle: Generator[None], hass: HomeAssistant, integration_setup: Callable[[], Awaitable[bool]], @@ -341,7 +367,8 @@ async def test_ent_desc_switch_exception_handling( getattr(problematic_appliance, mock_attr)() problematic_appliance.status.update(status) - await hass.services.async_call( - SWITCH_DOMAIN, service, {ATTR_ENTITY_ID: entity_id}, blocking=True - ) + with pytest.raises(ServiceValidationError, match=exception_match): + await hass.services.async_call( + SWITCH_DOMAIN, service, {ATTR_ENTITY_ID: entity_id}, blocking=True + ) assert getattr(problematic_appliance, mock_attr).call_count == 2 diff --git a/tests/components/home_connect/test_time.py b/tests/components/home_connect/test_time.py index 29619bacb82..2beab32c556 100644 --- a/tests/components/home_connect/test_time.py +++ b/tests/components/home_connect/test_time.py @@ -12,6 +12,7 @@ from homeassistant.components.time import DOMAIN as TIME_DOMAIN, SERVICE_SET_VAL from homeassistant.config_entries import ConfigEntryState from homeassistant.const import ATTR_ENTITY_ID, ATTR_TIME, Platform from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from .conftest import get_all_appliances @@ -134,13 +135,14 @@ async def test_time_entity_error( with pytest.raises(HomeConnectError): getattr(problematic_appliance, mock_attr)() - await hass.services.async_call( - TIME_DOMAIN, - SERVICE_SET_VALUE, - { - ATTR_ENTITY_ID: entity_id, - ATTR_TIME: time(minute=1), - }, - blocking=True, - ) + with pytest.raises(ServiceValidationError, match=r"Error.*set.*setting.*"): + await hass.services.async_call( + TIME_DOMAIN, + SERVICE_SET_VALUE, + { + ATTR_ENTITY_ID: entity_id, + ATTR_TIME: time(minute=1), + }, + blocking=True, + ) assert getattr(problematic_appliance, mock_attr).call_count == 2