Add state check to config entry setup to ensure it cannot be setup twice (#117193)

pull/118049/head
J. Nick Koston 2024-05-10 17:09:28 -05:00 committed by Franck Nijhof
parent 8128449879
commit 750ec261be
No known key found for this signature in database
GPG Key ID: D62583BA8AB11CA3
3 changed files with 56 additions and 7 deletions

View File

@ -514,6 +514,15 @@ class ConfigEntry:
# Only store setup result as state if it was not forwarded.
if domain_is_integration := self.domain == integration.domain:
if self.state in (
ConfigEntryState.LOADED,
ConfigEntryState.SETUP_IN_PROGRESS,
):
raise OperationNotAllowed(
f"The config entry {self.title} ({self.domain}) with entry_id"
f" {self.entry_id} cannot be setup because is already loaded in the"
f" {self.state} state"
)
self._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None)
if self.supports_unload is None:

View File

@ -196,7 +196,7 @@ async def test_flow_ssdp_discovery_changed_udn_match_mac(hass: HomeAssistant) ->
CONFIG_ENTRY_MAC_ADDRESS: TEST_MAC_ADDRESS,
},
source=config_entries.SOURCE_SSDP,
state=config_entries.ConfigEntryState.LOADED,
state=config_entries.ConfigEntryState.NOT_LOADED,
)
entry.add_to_hass(hass)
@ -228,7 +228,7 @@ async def test_flow_ssdp_discovery_changed_udn_match_host(hass: HomeAssistant) -
CONFIG_ENTRY_HOST: TEST_HOST,
},
source=config_entries.SOURCE_SSDP,
state=config_entries.ConfigEntryState.LOADED,
state=config_entries.ConfigEntryState.NOT_LOADED,
)
entry.add_to_hass(hass)
@ -266,7 +266,7 @@ async def test_flow_ssdp_discovery_changed_udn_but_st_differs(
CONFIG_ENTRY_MAC_ADDRESS: TEST_MAC_ADDRESS,
},
source=config_entries.SOURCE_SSDP,
state=config_entries.ConfigEntryState.LOADED,
state=config_entries.ConfigEntryState.NOT_LOADED,
)
entry.add_to_hass(hass)
@ -320,7 +320,7 @@ async def test_flow_ssdp_discovery_changed_location(hass: HomeAssistant) -> None
CONFIG_ENTRY_MAC_ADDRESS: TEST_MAC_ADDRESS,
},
source=config_entries.SOURCE_SSDP,
state=config_entries.ConfigEntryState.LOADED,
state=config_entries.ConfigEntryState.NOT_LOADED,
)
entry.add_to_hass(hass)

View File

@ -469,7 +469,7 @@ async def test_remove_entry(
]
# Setup entry
await entry.async_setup(hass)
await manager.async_setup(entry.entry_id)
await hass.async_block_till_done()
# Check entity state got added
@ -1696,7 +1696,9 @@ async def test_entry_reload_succeed(
hass: HomeAssistant, manager: config_entries.ConfigEntries
) -> None:
"""Test that we can reload an entry."""
entry = MockConfigEntry(domain="comp", state=config_entries.ConfigEntryState.LOADED)
entry = MockConfigEntry(
domain="comp", state=config_entries.ConfigEntryState.NOT_LOADED
)
entry.add_to_hass(hass)
async_setup = AsyncMock(return_value=True)
@ -1720,6 +1722,42 @@ async def test_entry_reload_succeed(
assert entry.state is config_entries.ConfigEntryState.LOADED
@pytest.mark.parametrize(
"state",
[
config_entries.ConfigEntryState.LOADED,
config_entries.ConfigEntryState.SETUP_IN_PROGRESS,
],
)
async def test_entry_cannot_be_loaded_twice(
hass: HomeAssistant, state: config_entries.ConfigEntryState
) -> None:
"""Test that a config entry cannot be loaded twice."""
entry = MockConfigEntry(domain="comp", state=state)
entry.add_to_hass(hass)
async_setup = AsyncMock(return_value=True)
async_setup_entry = AsyncMock(return_value=True)
async_unload_entry = AsyncMock(return_value=True)
mock_integration(
hass,
MockModule(
"comp",
async_setup=async_setup,
async_setup_entry=async_setup_entry,
async_unload_entry=async_unload_entry,
),
)
mock_platform(hass, "comp.config_flow", None)
with pytest.raises(config_entries.OperationNotAllowed, match=str(state)):
await entry.async_setup(hass)
assert len(async_setup.mock_calls) == 0
assert len(async_setup_entry.mock_calls) == 0
assert entry.state is state
@pytest.mark.parametrize(
"state",
[
@ -4088,7 +4126,9 @@ async def test_entry_reload_concurrency_not_setup_setup(
hass: HomeAssistant, manager: config_entries.ConfigEntries
) -> None:
"""Test multiple reload calls do not cause a reload race."""
entry = MockConfigEntry(domain="comp", state=config_entries.ConfigEntryState.LOADED)
entry = MockConfigEntry(
domain="comp", state=config_entries.ConfigEntryState.NOT_LOADED
)
entry.add_to_hass(hass)
async_setup = AsyncMock(return_value=True)