From 1ddd31673a9cb2e34239ad79650032c15700d9b0 Mon Sep 17 00:00:00 2001 From: Jan-Philipp Benecke Date: Tue, 26 Nov 2024 09:09:56 +0100 Subject: [PATCH] Add reconfigure flow to SABnzbd (#131555) * Add reconfigure flow to SABnzbd * Process code review * Add suggested values --- .../components/sabnzbd/config_flow.py | 40 +++++++----- homeassistant/components/sabnzbd/strings.json | 3 + tests/components/sabnzbd/test_config_flow.py | 61 +++++++++++++++++++ 3 files changed, 90 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/sabnzbd/config_flow.py b/homeassistant/components/sabnzbd/config_flow.py index 846f7b2b467..72b3f92409f 100644 --- a/homeassistant/components/sabnzbd/config_flow.py +++ b/homeassistant/components/sabnzbd/config_flow.py @@ -7,7 +7,11 @@ from typing import Any import voluptuous as vol -from homeassistant.config_entries import ConfigFlow, ConfigFlowResult +from homeassistant.config_entries import ( + SOURCE_RECONFIGURE, + ConfigFlow, + ConfigFlowResult, +) from homeassistant.const import CONF_API_KEY, CONF_URL from homeassistant.helpers.selector import ( TextSelector, @@ -41,31 +45,39 @@ class SABnzbdConfigFlow(ConfigFlow, domain=DOMAIN): VERSION = 1 - async def _async_validate_input(self, user_input): - """Validate the user input allows us to connect.""" - errors = {} - sab_api = await get_client(self.hass, user_input) - if not sab_api: - errors["base"] = "cannot_connect" - - return errors + async def async_step_reconfigure( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle reconfiguration flow.""" + return await self.async_step_user(user_input) async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Handle a flow initialized by the user.""" - errors = {} - if user_input is not None: - errors = await self._async_validate_input(user_input) - if not errors: + if user_input is not None: + sab_api = await get_client(self.hass, user_input) + if not sab_api: + errors["base"] = "cannot_connect" + else: + if self.source == SOURCE_RECONFIGURE: + return self.async_update_reload_and_abort( + self._get_reconfigure_entry(), data_updates=user_input + ) + return self.async_create_entry( title=user_input[CONF_API_KEY][:12], data=user_input ) return self.async_show_form( step_id="user", - data_schema=USER_SCHEMA, + data_schema=self.add_suggested_values_to_schema( + USER_SCHEMA, + self._get_reconfigure_entry().data + if self.source == SOURCE_RECONFIGURE + else user_input, + ), errors=errors, ) diff --git a/homeassistant/components/sabnzbd/strings.json b/homeassistant/components/sabnzbd/strings.json index 742c327ed23..78a8b88486e 100644 --- a/homeassistant/components/sabnzbd/strings.json +++ b/homeassistant/components/sabnzbd/strings.json @@ -15,6 +15,9 @@ "error": { "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "invalid_api_key": "[%key:common::config_flow::error::invalid_api_key%]" + }, + "abort": { + "reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]" } }, "entity": { diff --git a/tests/components/sabnzbd/test_config_flow.py b/tests/components/sabnzbd/test_config_flow.py index 969e379160c..8bf28e2c0cd 100644 --- a/tests/components/sabnzbd/test_config_flow.py +++ b/tests/components/sabnzbd/test_config_flow.py @@ -12,6 +12,8 @@ from homeassistant.const import CONF_API_KEY, CONF_URL from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType +from tests.common import MockConfigEntry + VALID_CONFIG = { CONF_API_KEY: "edc3eee7330e4fdda04489e3fbc283d0", CONF_URL: "http://localhost:8080", @@ -71,3 +73,62 @@ async def test_auth_error(hass: HomeAssistant, sabnzbd: AsyncMock) -> None: CONF_API_KEY: "edc3eee7330e4fdda04489e3fbc283d0", CONF_URL: "http://localhost:8080", } + + +async def test_reconfigure_successful( + hass: HomeAssistant, config_entry: MockConfigEntry +) -> None: + """Test reconfiguring a SABnzbd entry.""" + result = await config_entry.start_reconfigure_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_URL: "http://10.10.10.10:8080", CONF_API_KEY: "new_key"}, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + assert config_entry.data == { + CONF_URL: "http://10.10.10.10:8080", + CONF_API_KEY: "new_key", + } + + +async def test_reconfigure_error( + hass: HomeAssistant, config_entry: MockConfigEntry, sabnzbd: AsyncMock +) -> None: + """Test reconfiguring a SABnzbd entry.""" + result = await config_entry.start_reconfigure_flow(hass) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + # set side effect and check if error is handled + sabnzbd.check_available.side_effect = SabnzbdApiException("Some error") + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_URL: "http://10.10.10.10:8080", CONF_API_KEY: "new_key"}, + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + assert result["errors"] == {"base": "cannot_connect"} + + # reset side effect and check if we can recover + sabnzbd.check_available.side_effect = None + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_URL: "http://10.10.10.10:8080", CONF_API_KEY: "new_key"}, + ) + + assert "errors" not in result + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "reconfigure_successful" + assert config_entry.data == { + CONF_URL: "http://10.10.10.10:8080", + CONF_API_KEY: "new_key", + }