From 5267e4f5dbb8a8fe7ba5d25ae583f85254ac9c4d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 21 Feb 2024 21:02:44 -0600 Subject: [PATCH] Fix race in otbr config flow (#111044) * fix otbr * Update homeassistant/components/otbr/config_flow.py Co-authored-by: Paulus Schoutsen * unique ids should not change * handle missing unique id * handle missing unique id --------- Co-authored-by: Paulus Schoutsen --- homeassistant/components/otbr/config_flow.py | 11 ++--- tests/components/otbr/test_config_flow.py | 47 +++++++++++++++++--- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/otbr/config_flow.py b/homeassistant/components/otbr/config_flow.py index 0248ffdd079..d0d3f1c1060 100644 --- a/homeassistant/components/otbr/config_flow.py +++ b/homeassistant/components/otbr/config_flow.py @@ -144,13 +144,14 @@ class OTBRConfigFlow(ConfigFlow, domain=DOMAIN): for current_entry in current_entries: if current_entry.source != SOURCE_HASSIO: continue - if current_entry.unique_id != discovery_info.uuid: - self.hass.config_entries.async_update_entry( - current_entry, unique_id=discovery_info.uuid - ) current_url = yarl.URL(current_entry.data["url"]) if ( - current_url.host != config["host"] + # The first version did not set a unique_id + # so if the entry does not have a unique_id + # we have to assume it's the first version + current_entry.unique_id + and (current_entry.unique_id != discovery_info.uuid) + or current_url.host != config["host"] or current_url.port == config["port"] ): continue diff --git a/tests/components/otbr/test_config_flow.py b/tests/components/otbr/test_config_flow.py index b827f4b7826..03d54981b1a 100644 --- a/tests/components/otbr/test_config_flow.py +++ b/tests/components/otbr/test_config_flow.py @@ -368,14 +368,14 @@ async def test_hassio_discovery_flow_2x_addons( "homeassistant.components.otbr.async_setup_entry", return_value=True, ) as mock_setup_entry: - results = await asyncio.gather( - hass.config_entries.flow.async_init( - otbr.DOMAIN, context={"source": "hassio"}, data=HASSIO_DATA - ), - hass.config_entries.flow.async_init( - otbr.DOMAIN, context={"source": "hassio"}, data=HASSIO_DATA_2 - ), + result1 = await hass.config_entries.flow.async_init( + otbr.DOMAIN, context={"source": "hassio"}, data=HASSIO_DATA ) + result2 = await hass.config_entries.flow.async_init( + otbr.DOMAIN, context={"source": "hassio"}, data=HASSIO_DATA_2 + ) + + results = [result1, result2] expected_data = { "url": f"http://{HASSIO_DATA.config['host']}:{HASSIO_DATA.config['port']}", @@ -578,6 +578,38 @@ async def test_hassio_discovery_flow_404( assert result["reason"] == "unknown" +async def test_hassio_discovery_flow_new_port_missing_unique_id( + hass: HomeAssistant, +) -> None: + """Test the port can be updated when the unique id is missing.""" + mock_integration(hass, MockModule("hassio")) + + # Setup the config entry + config_entry = MockConfigEntry( + data={ + "url": f"http://{HASSIO_DATA.config['host']}:{HASSIO_DATA.config['port']+1}" + }, + domain=otbr.DOMAIN, + options={}, + source="hassio", + title="Open Thread Border Router", + ) + config_entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + otbr.DOMAIN, context={"source": "hassio"}, data=HASSIO_DATA + ) + + assert result["type"] == FlowResultType.ABORT + assert result["reason"] == "single_instance_allowed" + + expected_data = { + "url": f"http://{HASSIO_DATA.config['host']}:{HASSIO_DATA.config['port']}", + } + config_entry = hass.config_entries.async_entries(otbr.DOMAIN)[0] + assert config_entry.data == expected_data + + async def test_hassio_discovery_flow_new_port(hass: HomeAssistant) -> None: """Test the port can be updated.""" mock_integration(hass, MockModule("hassio")) @@ -591,6 +623,7 @@ async def test_hassio_discovery_flow_new_port(hass: HomeAssistant) -> None: options={}, source="hassio", title="Open Thread Border Router", + unique_id=HASSIO_DATA.uuid, ) config_entry.add_to_hass(hass)