Stop waiting for setup retry upon discovery (#72738)

This commit is contained in:
J. Nick Koston 2022-05-30 17:24:34 -10:00 committed by GitHub
parent ec44a63a84
commit f9bd384e6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 22 deletions

View File

@ -108,7 +108,7 @@ class ConfigEntryState(Enum):
DEFAULT_DISCOVERY_UNIQUE_ID = "default_discovery_unique_id" DEFAULT_DISCOVERY_UNIQUE_ID = "default_discovery_unique_id"
DISCOVERY_NOTIFICATION_ID = "config_entry_discovery" DISCOVERY_NOTIFICATION_ID = "config_entry_discovery"
DISCOVERY_SOURCES = ( DISCOVERY_SOURCES = {
SOURCE_DHCP, SOURCE_DHCP,
SOURCE_DISCOVERY, SOURCE_DISCOVERY,
SOURCE_HOMEKIT, SOURCE_HOMEKIT,
@ -119,7 +119,7 @@ DISCOVERY_SOURCES = (
SOURCE_UNIGNORE, SOURCE_UNIGNORE,
SOURCE_USB, SOURCE_USB,
SOURCE_ZEROCONF, SOURCE_ZEROCONF,
) }
RECONFIGURE_NOTIFICATION_ID = "config_entry_reconfigure" RECONFIGURE_NOTIFICATION_ID = "config_entry_reconfigure"
@ -1242,24 +1242,36 @@ class ConfigFlow(data_entry_flow.FlowHandler):
return return
for entry in self._async_current_entries(include_ignore=True): for entry in self._async_current_entries(include_ignore=True):
if entry.unique_id == self.unique_id: if entry.unique_id != self.unique_id:
if updates is not None: continue
changed = self.hass.config_entries.async_update_entry( should_reload = False
entry, data={**entry.data, **updates} if (
) updates is not None
if ( and self.hass.config_entries.async_update_entry(
changed entry, data={**entry.data, **updates}
and reload_on_update )
and entry.state and reload_on_update
in (ConfigEntryState.LOADED, ConfigEntryState.SETUP_RETRY) and entry.state
): in (ConfigEntryState.LOADED, ConfigEntryState.SETUP_RETRY)
self.hass.async_create_task( ):
self.hass.config_entries.async_reload(entry.entry_id) # Existing config entry present, and the
) # entry data just changed
# Allow ignored entries to be configured on manual user step should_reload = True
if entry.source == SOURCE_IGNORE and self.source == SOURCE_USER: elif (
continue self.source in DISCOVERY_SOURCES
raise data_entry_flow.AbortFlow("already_configured") and entry.state is ConfigEntryState.SETUP_RETRY
):
# Existing config entry present in retry state, and we
# just discovered the unique id so we know its online
should_reload = True
# Allow ignored entries to be configured on manual user step
if entry.source == SOURCE_IGNORE and self.source == SOURCE_USER:
continue
if should_reload:
self.hass.async_create_task(
self.hass.config_entries.async_reload(entry.entry_id)
)
raise data_entry_flow.AbortFlow("already_configured")
async def async_set_unique_id( async def async_set_unique_id(
self, unique_id: str | None = None, *, raise_on_progress: bool = True self, unique_id: str | None = None, *, raise_on_progress: bool = True

View File

@ -1,4 +1,6 @@
"""Test the config manager.""" """Test the config manager."""
from __future__ import annotations
import asyncio import asyncio
from datetime import timedelta from datetime import timedelta
import logging import logging
@ -7,6 +9,7 @@ from unittest.mock import AsyncMock, Mock, patch
import pytest import pytest
from homeassistant import config_entries, data_entry_flow, loader from homeassistant import config_entries, data_entry_flow, loader
from homeassistant.components import dhcp
from homeassistant.components.hassio import HassioServiceInfo from homeassistant.components.hassio import HassioServiceInfo
from homeassistant.const import ( from homeassistant.const import (
EVENT_COMPONENT_LOADED, EVENT_COMPONENT_LOADED,
@ -14,7 +17,7 @@ from homeassistant.const import (
EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_STOP,
) )
from homeassistant.core import CoreState, Event, callback from homeassistant.core import CoreState, Event, callback
from homeassistant.data_entry_flow import RESULT_TYPE_ABORT, BaseServiceInfo from homeassistant.data_entry_flow import RESULT_TYPE_ABORT, BaseServiceInfo, FlowResult
from homeassistant.exceptions import ( from homeassistant.exceptions import (
ConfigEntryAuthFailed, ConfigEntryAuthFailed,
ConfigEntryNotReady, ConfigEntryNotReady,
@ -1644,7 +1647,7 @@ async def test_unique_id_update_existing_entry_without_reload(hass, manager):
async def async_step_user(self, user_input=None): async def async_step_user(self, user_input=None):
"""Test user step.""" """Test user step."""
await self.async_set_unique_id("mock-unique-id") await self.async_set_unique_id("mock-unique-id")
await self._abort_if_unique_id_configured( self._abort_if_unique_id_configured(
updates={"host": "1.1.1.1"}, reload_on_update=False updates={"host": "1.1.1.1"}, reload_on_update=False
) )
@ -1725,6 +1728,75 @@ async def test_unique_id_update_existing_entry_with_reload(hass, manager):
assert len(async_reload.mock_calls) == 0 assert len(async_reload.mock_calls) == 0
async def test_unique_id_from_discovery_in_setup_retry(hass, manager):
"""Test that we reload when in a setup retry state from discovery."""
hass.config.components.add("comp")
unique_id = "34:ea:34:b4:3b:5a"
host = "0.0.0.0"
entry = MockConfigEntry(
domain="comp",
data={"additional": "data", "host": host},
unique_id=unique_id,
state=config_entries.ConfigEntryState.SETUP_RETRY,
)
entry.add_to_hass(hass)
mock_integration(
hass,
MockModule("comp"),
)
mock_entity_platform(hass, "config_flow.comp", None)
class TestFlow(config_entries.ConfigFlow):
"""Test flow."""
VERSION = 1
async def async_step_dhcp(
self, discovery_info: dhcp.DhcpServiceInfo
) -> FlowResult:
"""Test dhcp step."""
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()
async def async_step_user(self, user_input: dict | None = None) -> FlowResult:
"""Test user step."""
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()
# Verify we do not reload from a user source
with patch.dict(config_entries.HANDLERS, {"comp": TestFlow}), patch(
"homeassistant.config_entries.ConfigEntries.async_reload"
) as async_reload:
result = await manager.flow.async_init(
"comp", context={"source": config_entries.SOURCE_USER}
)
await hass.async_block_till_done()
assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
assert len(async_reload.mock_calls) == 0
# Verify do reload from a discovery source
with patch.dict(config_entries.HANDLERS, {"comp": TestFlow}), patch(
"homeassistant.config_entries.ConfigEntries.async_reload"
) as async_reload:
discovery_result = await manager.flow.async_init(
"comp",
context={"source": config_entries.SOURCE_DHCP},
data=dhcp.DhcpServiceInfo(
hostname="any",
ip=host,
macaddress=unique_id,
),
)
await hass.async_block_till_done()
assert discovery_result["type"] == RESULT_TYPE_ABORT
assert discovery_result["reason"] == "already_configured"
assert len(async_reload.mock_calls) == 1
async def test_unique_id_not_update_existing_entry(hass, manager): async def test_unique_id_not_update_existing_entry(hass, manager):
"""Test that we do not update an entry if existing entry has the data.""" """Test that we do not update an entry if existing entry has the data."""
hass.config.components.add("comp") hass.config.components.add("comp")