From 70b358bca1adda27fa2e234f477e375d11b6cc66 Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Wed, 24 Apr 2024 15:13:33 +0200 Subject: [PATCH] Always reload after a successful reauth flow (#116026) * Always reload after a succesfull reauth-flow * Add test, fix CI failures * Add kwarg to prevent reloading and tests * Do not reload entry for bond if it exists * Remove mocks on internals * Rename kwarg to always_reload * Update tests/components/weatherflow_cloud/test_config_flow.py * Update tests/components/homeworks/test_config_flow.py * Update tests/components/homeworks/test_config_flow.py * Rename to option to reload_even_if_entry_is_unchanged --- homeassistant/components/bond/config_flow.py | 5 +- .../components/homeworks/config_flow.py | 5 +- .../weatherflow_cloud/config_flow.py | 1 + homeassistant/config_entries.py | 3 +- tests/test_config_entries.py | 96 ++++++++++++++++--- 5 files changed, 92 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/bond/config_flow.py b/homeassistant/components/bond/config_flow.py index 45170a0404f..a12d3057258 100644 --- a/homeassistant/components/bond/config_flow.py +++ b/homeassistant/components/bond/config_flow.py @@ -113,7 +113,10 @@ class BondConfigFlow(ConfigFlow, domain=DOMAIN): ): updates[CONF_ACCESS_TOKEN] = token return self.async_update_reload_and_abort( - entry, data={**entry.data, **updates}, reason="already_configured" + entry, + data={**entry.data, **updates}, + reason="already_configured", + reload_even_if_entry_is_unchanged=False, ) self._discovered = {CONF_HOST: host, CONF_NAME: bond_id} diff --git a/homeassistant/components/homeworks/config_flow.py b/homeassistant/components/homeworks/config_flow.py index b9515c306d6..f447860c53f 100644 --- a/homeassistant/components/homeworks/config_flow.py +++ b/homeassistant/components/homeworks/config_flow.py @@ -690,7 +690,10 @@ class HomeworksConfigFlowHandler(ConfigFlow, domain=DOMAIN): CONF_PORT: user_input[CONF_PORT], } return self.async_update_reload_and_abort( - entry, options=new_options, reason="reconfigure_successful" + entry, + options=new_options, + reason="reconfigure_successful", + reload_even_if_entry_is_unchanged=False, ) return self.async_show_form( diff --git a/homeassistant/components/weatherflow_cloud/config_flow.py b/homeassistant/components/weatherflow_cloud/config_flow.py index 4c905a8451e..e8972c320ed 100644 --- a/homeassistant/components/weatherflow_cloud/config_flow.py +++ b/homeassistant/components/weatherflow_cloud/config_flow.py @@ -50,6 +50,7 @@ class WeatherFlowCloudConfigFlow(ConfigFlow, domain=DOMAIN): existing_entry, data={CONF_API_TOKEN: api_token}, reason="reauth_successful", + reload_even_if_entry_is_unchanged=False, ) return self.async_show_form( diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 0637e5f7c87..056814bbc4d 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -2399,6 +2399,7 @@ class ConfigFlow(ConfigEntryBaseFlow): data: Mapping[str, Any] | UndefinedType = UNDEFINED, options: Mapping[str, Any] | UndefinedType = UNDEFINED, reason: str = "reauth_successful", + reload_even_if_entry_is_unchanged: bool = True, ) -> ConfigFlowResult: """Update config entry, reload config entry and finish config flow.""" result = self.hass.config_entries.async_update_entry( @@ -2408,7 +2409,7 @@ class ConfigFlow(ConfigEntryBaseFlow): data=data, options=options, ) - if result: + if reload_even_if_entry_is_unchanged or result: self.hass.config_entries.async_schedule_reload(entry.entry_id) return self.async_abort(reason=reason) diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index 63dea5ea735..68f770631ed 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -4504,24 +4504,86 @@ def test_raise_trying_to_add_same_config_entry_twice( assert f"An entry with the id {entry.entry_id} already exists" in caplog.text +@pytest.mark.parametrize( + ( + "title", + "unique_id", + "data_vendor", + "options_vendor", + "kwargs", + "calls_entry_load_unload", + ), + [ + ( + ("Test", "Updated title"), + ("1234", "5678"), + ("data", "data2"), + ("options", "options2"), + {}, + (2, 1), + ), + ( + ("Test", "Test"), + ("1234", "1234"), + ("data", "data"), + ("options", "options"), + {}, + (2, 1), + ), + ( + ("Test", "Updated title"), + ("1234", "5678"), + ("data", "data2"), + ("options", "options2"), + {"reload_even_if_entry_is_unchanged": True}, + (2, 1), + ), + ( + ("Test", "Test"), + ("1234", "1234"), + ("data", "data"), + ("options", "options"), + {"reload_even_if_entry_is_unchanged": False}, + (1, 0), + ), + ], + ids=[ + "changed_entry_default", + "unchanged_entry_default", + "changed_entry_explicit_reload", + "changed_entry_no_reload", + ], +) async def test_update_entry_and_reload( - hass: HomeAssistant, manager: config_entries.ConfigEntries + hass: HomeAssistant, + manager: config_entries.ConfigEntries, + title: tuple[str, str], + unique_id: tuple[str, str], + data_vendor: tuple[str, str], + options_vendor: tuple[str, str], + kwargs: dict[str, Any], + calls_entry_load_unload: tuple[int, int], ) -> None: """Test updating an entry and reloading.""" entry = MockConfigEntry( domain="comp", - unique_id="1234", - title="Test", - data={"vendor": "data"}, - options={"vendor": "options"}, + unique_id=unique_id[0], + title=title[0], + data={"vendor": data_vendor[0]}, + options={"vendor": options_vendor[0]}, ) entry.add_to_hass(hass) - mock_integration( - hass, MockModule("comp", async_setup_entry=AsyncMock(return_value=True)) + comp = MockModule( + "comp", + async_setup_entry=AsyncMock(return_value=True), + async_unload_entry=AsyncMock(return_value=True), ) + mock_integration(hass, comp) mock_platform(hass, "comp.config_flow", None) + await hass.config_entries.async_setup(entry.entry_id) + class MockFlowHandler(config_entries.ConfigFlow): """Define a mock flow handler.""" @@ -4531,23 +4593,27 @@ async def test_update_entry_and_reload( """Mock Reauth.""" return self.async_update_reload_and_abort( entry=entry, - unique_id="5678", - title="Updated Title", - data={"vendor": "data2"}, - options={"vendor": "options2"}, + unique_id=unique_id[1], + title=title[1], + data={"vendor": data_vendor[1]}, + options={"vendor": options_vendor[1]}, + **kwargs, ) with patch.dict(config_entries.HANDLERS, {"comp": MockFlowHandler}): task = await manager.flow.async_init("comp", context={"source": "reauth"}) await hass.async_block_till_done() - assert entry.title == "Updated Title" - assert entry.unique_id == "5678" - assert entry.data == {"vendor": "data2"} - assert entry.options == {"vendor": "options2"} + assert entry.title == title[1] + assert entry.unique_id == unique_id[1] + assert entry.data == {"vendor": data_vendor[1]} + assert entry.options == {"vendor": options_vendor[1]} assert entry.state == config_entries.ConfigEntryState.LOADED assert task["type"] == FlowResultType.ABORT assert task["reason"] == "reauth_successful" + # Assert entry was reloaded + assert len(comp.async_setup_entry.mock_calls) == calls_entry_load_unload[0] + assert len(comp.async_unload_entry.mock_calls) == calls_entry_load_unload[1] @pytest.mark.parametrize("unique_id", [["blah", "bleh"], {"key": "value"}])