From 0e04cd6b35a30acc08f95a399c4253a6bc9990da Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker Date: Wed, 15 Nov 2023 13:15:31 +0100 Subject: [PATCH] Add reauth flow to Trafikverket Weatherstation (#104027) * Add reauth flow to Trafikverket Weatherstation * Add tests --- .../config_flow.py | 49 ++++++++- .../trafikverket_weatherstation/strings.json | 8 +- .../test_config_flow.py | 102 ++++++++++++++++++ 3 files changed, 157 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/trafikverket_weatherstation/config_flow.py b/homeassistant/components/trafikverket_weatherstation/config_flow.py index f8f86298045..89cbd373665 100644 --- a/homeassistant/components/trafikverket_weatherstation/config_flow.py +++ b/homeassistant/components/trafikverket_weatherstation/config_flow.py @@ -1,6 +1,9 @@ """Adds config flow for Trafikverket Weather integration.""" from __future__ import annotations +from collections.abc import Mapping +from typing import Any + from pytrafikverket.exceptions import ( InvalidAuthentication, MultipleWeatherStationsFound, @@ -23,7 +26,7 @@ class TVWeatherConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): VERSION = 1 - entry: config_entries.ConfigEntry + entry: config_entries.ConfigEntry | None = None async def validate_input(self, sensor_api: str, station: str) -> None: """Validate input from user input.""" @@ -71,3 +74,47 @@ class TVWeatherConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ), errors=errors, ) + + async def async_step_reauth(self, entry_data: Mapping[str, Any]) -> FlowResult: + """Handle re-authentication with Trafikverket.""" + + self.entry = self.hass.config_entries.async_get_entry(self.context["entry_id"]) + return await self.async_step_reauth_confirm() + + async def async_step_reauth_confirm( + self, user_input: dict[str, Any] | None = None + ) -> FlowResult: + """Confirm re-authentication with Trafikverket.""" + errors: dict[str, str] = {} + + if user_input: + api_key = user_input[CONF_API_KEY] + + assert self.entry is not None + + try: + await self.validate_input(api_key, self.entry.data[CONF_STATION]) + except InvalidAuthentication: + errors["base"] = "invalid_auth" + except NoWeatherStationFound: + errors["base"] = "invalid_station" + except MultipleWeatherStationsFound: + errors["base"] = "more_stations" + except Exception: # pylint: disable=broad-exception-caught + errors["base"] = "cannot_connect" + else: + self.hass.config_entries.async_update_entry( + self.entry, + data={ + **self.entry.data, + CONF_API_KEY: api_key, + }, + ) + await self.hass.config_entries.async_reload(self.entry.entry_id) + return self.async_abort(reason="reauth_successful") + + return self.async_show_form( + step_id="reauth_confirm", + data_schema=vol.Schema({vol.Required(CONF_API_KEY): cv.string}), + errors=errors, + ) diff --git a/homeassistant/components/trafikverket_weatherstation/strings.json b/homeassistant/components/trafikverket_weatherstation/strings.json index 9ff1b077f33..e7e279ba2d5 100644 --- a/homeassistant/components/trafikverket_weatherstation/strings.json +++ b/homeassistant/components/trafikverket_weatherstation/strings.json @@ -1,7 +1,8 @@ { "config": { "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_account%]" + "already_configured": "[%key:common::config_flow::abort::already_configured_account%]", + "reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]" }, "error": { "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", @@ -15,6 +16,11 @@ "api_key": "[%key:common::config_flow::data::api_key%]", "station": "Station" } + }, + "reauth_confirm": { + "data": { + "api_key": "[%key:common::config_flow::data::api_key%]" + } } } }, diff --git a/tests/components/trafikverket_weatherstation/test_config_flow.py b/tests/components/trafikverket_weatherstation/test_config_flow.py index 36c30b33b53..e55e04d8411 100644 --- a/tests/components/trafikverket_weatherstation/test_config_flow.py +++ b/tests/components/trafikverket_weatherstation/test_config_flow.py @@ -15,6 +15,8 @@ from homeassistant.const import CONF_API_KEY from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResultType +from tests.common import MockConfigEntry + DOMAIN = "trafikverket_weatherstation" CONF_STATION = "station" @@ -97,3 +99,103 @@ async def test_flow_fails( ) assert result4["errors"] == {"base": base_error} + + +async def test_reauth_flow(hass: HomeAssistant) -> None: + """Test a reauthentication flow.""" + entry = MockConfigEntry( + domain=DOMAIN, + data={ + CONF_API_KEY: "1234567890", + CONF_STATION: "Vallby", + }, + ) + entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={ + "source": config_entries.SOURCE_REAUTH, + "entry_id": entry.entry_id, + }, + data=entry.data, + ) + assert result["step_id"] == "reauth_confirm" + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {} + + with patch( + "homeassistant.components.trafikverket_weatherstation.config_flow.TrafikverketWeather.async_get_weather", + ), patch( + "homeassistant.components.trafikverket_weatherstation.async_setup_entry", + return_value=True, + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_API_KEY: "1234567891"}, + ) + await hass.async_block_till_done() + + assert result["type"] == FlowResultType.ABORT + assert result["reason"] == "reauth_successful" + assert entry.data == {"api_key": "1234567891", "station": "Vallby"} + + +@pytest.mark.parametrize( + ("side_effect", "base_error"), + [ + ( + InvalidAuthentication, + "invalid_auth", + ), + ( + NoWeatherStationFound, + "invalid_station", + ), + ( + MultipleWeatherStationsFound, + "more_stations", + ), + ( + Exception, + "cannot_connect", + ), + ], +) +async def test_reauth_flow_fails( + hass: HomeAssistant, side_effect: Exception, base_error: str +) -> None: + """Test a reauthentication flow.""" + entry = MockConfigEntry( + domain=DOMAIN, + data={ + CONF_API_KEY: "1234567890", + CONF_STATION: "Vallby", + }, + ) + entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={ + "source": config_entries.SOURCE_REAUTH, + "entry_id": entry.entry_id, + }, + data=entry.data, + ) + assert result["step_id"] == "reauth_confirm" + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {} + + with patch( + "homeassistant.components.trafikverket_weatherstation.config_flow.TrafikverketWeather.async_get_weather", + side_effect=side_effect(), + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + {CONF_API_KEY: "1234567891"}, + ) + await hass.async_block_till_done() + + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {"base": base_error}