Ensure entry_id is set on reauth/reconfigure flows (#129319)

* Ensure entry_id is set on reauth/reconfigure flows

* Improve

* Improve

* Use report helper

* Adjust deprecation date

* Update config_entries.py

* Improve message and adjust tests

* Apply suggestions from code review

Co-authored-by: G Johansson <goran.johansson@shiftit.se>

---------

Co-authored-by: G Johansson <goran.johansson@shiftit.se>
pull/129479/head^2
epenet 2024-11-01 10:29:58 +01:00 committed by GitHub
parent 5430eca93e
commit b626c9b450
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 86 additions and 5 deletions

View File

@ -1260,13 +1260,24 @@ class ConfigEntriesFlowManager(
if not context or "source" not in context:
raise KeyError("Context not set or doesn't have a source set")
# reauth/reconfigure flows should be linked to a config entry
if (source := context["source"]) in {
SOURCE_REAUTH,
SOURCE_RECONFIGURE,
} and "entry_id" not in context:
# Deprecated in 2024.12, should fail in 2025.12
report(
f"initialises a {source} flow without a link to the config entry",
error_if_integration=False,
error_if_core=True,
)
flow_id = ulid_util.ulid_now()
# Avoid starting a config flow on an integration that only supports
# a single config entry, but which already has an entry
if (
context.get("source")
not in {SOURCE_IGNORE, SOURCE_REAUTH, SOURCE_RECONFIGURE}
source not in {SOURCE_IGNORE, SOURCE_REAUTH, SOURCE_RECONFIGURE}
and self.config_entries.async_has_entries(handler, include_ignore=False)
and await _support_single_config_entry_only(self.hass, handler)
):
@ -1280,7 +1291,7 @@ class ConfigEntriesFlowManager(
loop = self.hass.loop
if context["source"] == SOURCE_IMPORT:
if source == SOURCE_IMPORT:
self._pending_import_flows[handler][flow_id] = loop.create_future()
cancel_init_future = loop.create_future()

View File

@ -37,7 +37,7 @@ from homeassistant.exceptions import (
ConfigEntryNotReady,
HomeAssistantError,
)
from homeassistant.helpers import entity_registry as er, issue_registry as ir
from homeassistant.helpers import entity_registry as er, frame, issue_registry as ir
from homeassistant.helpers.discovery_flow import DiscoveryKey
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.json import json_dumps
@ -4779,6 +4779,74 @@ async def test_reauth(
assert len(hass.config_entries.flow.async_progress()) == 1
@pytest.mark.parametrize(
"source", [config_entries.SOURCE_REAUTH, config_entries.SOURCE_RECONFIGURE]
)
async def test_reauth_reconfigure_missing_entry(
hass: HomeAssistant,
manager: config_entries.ConfigEntries,
source: str,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test the async_reauth_helper."""
entry = MockConfigEntry(title="test_title", domain="test")
entry.add_to_hass(hass)
mock_setup_entry = AsyncMock(return_value=True)
mock_integration(hass, MockModule("test", async_setup_entry=mock_setup_entry))
mock_platform(hass, "test.config_flow", None)
await manager.async_setup(entry.entry_id)
await hass.async_block_till_done()
with pytest.raises(
RuntimeError,
match=f"Detected code that initialises a {source} flow without a link "
"to the config entry. Please report this issue.",
):
await manager.flow.async_init("test", context={"source": source})
await hass.async_block_till_done()
flows = hass.config_entries.flow.async_progress()
assert len(flows) == 0
@pytest.mark.usefixtures("mock_integration_frame")
@pytest.mark.parametrize(
"source", [config_entries.SOURCE_REAUTH, config_entries.SOURCE_RECONFIGURE]
)
async def test_reauth_reconfigure_missing_entry_component(
hass: HomeAssistant,
manager: config_entries.ConfigEntries,
source: str,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test the async_reauth_helper."""
entry = MockConfigEntry(title="test_title", domain="test")
entry.add_to_hass(hass)
mock_setup_entry = AsyncMock(return_value=True)
mock_integration(hass, MockModule("test", async_setup_entry=mock_setup_entry))
mock_platform(hass, "test.config_flow", None)
await manager.async_setup(entry.entry_id)
await hass.async_block_till_done()
with patch.object(frame, "_REPORTED_INTEGRATIONS", set()):
await manager.flow.async_init("test", context={"source": source})
await hass.async_block_till_done()
# Flow still created, but deprecation logged
flows = hass.config_entries.flow.async_progress()
assert len(flows) == 1
assert flows[0]["context"]["source"] == source
assert (
f"Detected that integration 'hue' initialises a {source} flow"
" without a link to the config entry at homeassistant/components" in caplog.text
)
async def test_reconfigure(
hass: HomeAssistant, manager: config_entries.ConfigEntries
) -> None:
@ -5012,7 +5080,9 @@ async def test_initializing_flows_canceled_on_shutdown(
config_entries.HANDLERS, {"comp": MockFlowHandler, "test": MockFlowHandler}
):
task = asyncio.create_task(
manager.flow.async_init("test", context={"source": "reauth"})
manager.flow.async_init(
"test", context={"source": "reauth", "entry_id": "abc"}
)
)
await hass.async_block_till_done()
manager.flow.async_shutdown()