From c6edc7ae4f8bdcd6fbb13dcd9d73433705e087a0 Mon Sep 17 00:00:00 2001 From: Guido Schmitz Date: Fri, 23 Apr 2021 13:48:24 +0200 Subject: [PATCH] Clean up devolo Home Control config flow (#49585) --- .../devolo_home_control/config_flow.py | 24 ++++++++------ .../devolo_home_control/exceptions.py | 6 ++++ .../devolo_home_control/test_config_flow.py | 31 ++++++++++++++++--- 3 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 homeassistant/components/devolo_home_control/exceptions.py diff --git a/homeassistant/components/devolo_home_control/config_flow.py b/homeassistant/components/devolo_home_control/config_flow.py index 43bacfed639..49abba7723d 100644 --- a/homeassistant/components/devolo_home_control/config_flow.py +++ b/homeassistant/components/devolo_home_control/config_flow.py @@ -1,6 +1,4 @@ """Config flow to configure the devolo home control integration.""" -import logging - import voluptuous as vol from homeassistant import config_entries @@ -15,8 +13,7 @@ from .const import ( # pylint:disable=unused-import DOMAIN, SUPPORTED_MODEL_TYPES, ) - -_LOGGER = logging.getLogger(__name__) +from .exceptions import CredentialsInvalid class DevoloHomeControlFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): @@ -39,8 +36,11 @@ class DevoloHomeControlFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): vol.Required(CONF_MYDEVOLO, default=DEFAULT_MYDEVOLO) ] = str if user_input is None: - return self._show_form(user_input) - return await self._connect_mydevolo(user_input) + return self._show_form(step_id="user") + try: + return await self._connect_mydevolo(user_input) + except CredentialsInvalid: + return self._show_form(step_id="user", errors={"base": "invalid_auth"}) async def async_step_zeroconf(self, discovery_info: DiscoveryInfoType): """Handle zeroconf discovery.""" @@ -54,7 +54,12 @@ class DevoloHomeControlFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Handle a flow initiated by zeroconf.""" if user_input is None: return self._show_form(step_id="zeroconf_confirm") - return await self._connect_mydevolo(user_input) + try: + return await self._connect_mydevolo(user_input) + except CredentialsInvalid: + return self._show_form( + step_id="zeroconf_confirm", errors={"base": "invalid_auth"} + ) async def _connect_mydevolo(self, user_input): """Connect to mydevolo.""" @@ -63,8 +68,7 @@ class DevoloHomeControlFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): mydevolo.credentials_valid ) if not credentials_valid: - return self._show_form({"base": "invalid_auth"}) - _LOGGER.debug("Credentials valid") + raise CredentialsInvalid uuid = await self.hass.async_add_executor_job(mydevolo.uuid) await self.async_set_unique_id(uuid) self._abort_if_unique_id_configured() @@ -79,7 +83,7 @@ class DevoloHomeControlFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): ) @callback - def _show_form(self, errors=None, step_id="user"): + def _show_form(self, step_id, errors=None): """Show the form to the user.""" return self.async_show_form( step_id=step_id, diff --git a/homeassistant/components/devolo_home_control/exceptions.py b/homeassistant/components/devolo_home_control/exceptions.py new file mode 100644 index 00000000000..378efa41cc5 --- /dev/null +++ b/homeassistant/components/devolo_home_control/exceptions.py @@ -0,0 +1,6 @@ +"""Custom exceptions for the devolo_home_control integration.""" +from homeassistant.exceptions import HomeAssistantError + + +class CredentialsInvalid(HomeAssistantError): + """Given credentials are invalid.""" diff --git a/tests/components/devolo_home_control/test_config_flow.py b/tests/components/devolo_home_control/test_config_flow.py index 0b02cb9f4a1..7765e7335e4 100644 --- a/tests/components/devolo_home_control/test_config_flow.py +++ b/tests/components/devolo_home_control/test_config_flow.py @@ -22,20 +22,22 @@ async def test_form(hass): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_USER} ) - assert result["type"] == "form" + assert result["step_id"] == "user" + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"] == {} await _setup(hass, result) @pytest.mark.credentials_invalid -async def test_form_invalid_credentials(hass): +async def test_form_invalid_credentials_user(hass): """Test if we get the error message on invalid credentials.""" await setup.async_setup_component(hass, "persistent_notification", {}) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_USER} ) - assert result["type"] == "form" + assert result["step_id"] == "user" + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"] == {} result = await hass.config_entries.flow.async_configure( @@ -98,7 +100,7 @@ async def test_form_advanced_options(hass): assert len(mock_setup_entry.mock_calls) == 1 -async def test_show_zeroconf_form(hass): +async def test_form_zeroconf(hass): """Test that the zeroconf confirmation form is served.""" result = await hass.config_entries.flow.async_init( DOMAIN, @@ -112,6 +114,27 @@ async def test_show_zeroconf_form(hass): await _setup(hass, result) +@pytest.mark.credentials_invalid +async def test_form_invalid_credentials_zeroconf(hass): + """Test if we get the error message on invalid credentials.""" + await setup.async_setup_component(hass, "persistent_notification", {}) + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_ZEROCONF}, + data=DISCOVERY_INFO, + ) + + assert result["step_id"] == "zeroconf_confirm" + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {"username": "test-username", "password": "test-password"}, + ) + + assert result["errors"] == {"base": "invalid_auth"} + + async def test_zeroconf_wrong_device(hass): """Test that the zeroconf ignores wrong devices.""" result = await hass.config_entries.flow.async_init(