mirror of
https://github.com/home-assistant/core.git
synced 2026-02-15 07:36:16 +00:00
Clarify behavior of ConfigEntry.async_on_state_change (#151628)
This commit is contained in:
@@ -1178,7 +1178,13 @@ class ConfigEntry[_DataT = Any]:
|
||||
|
||||
@callback
|
||||
def async_on_state_change(self, func: CALLBACK_TYPE) -> CALLBACK_TYPE:
|
||||
"""Add a function to call when a config entry changes its state."""
|
||||
"""Add a function to call when a config entry changes its state.
|
||||
|
||||
Note: async_on_unload listeners are called before the state is changed to
|
||||
NOT_LOADED when unloading a config entry. This means the passed function
|
||||
will not be called after a config entry has been unloaded, the last call
|
||||
will be after the state is changed to UNLOAD_IN_PROGRESS.
|
||||
"""
|
||||
if self._on_state_change is None:
|
||||
self._on_state_change = []
|
||||
self._on_state_change.append(func)
|
||||
|
||||
@@ -4784,6 +4784,68 @@ async def test_entry_state_change_calls_listener(
|
||||
assert entry.state is target_state
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("source_state", "target_state", "transition_method_name", "call_count"),
|
||||
[
|
||||
(
|
||||
config_entries.ConfigEntryState.NOT_LOADED,
|
||||
config_entries.ConfigEntryState.LOADED,
|
||||
"async_setup",
|
||||
2,
|
||||
),
|
||||
(
|
||||
config_entries.ConfigEntryState.LOADED,
|
||||
config_entries.ConfigEntryState.NOT_LOADED,
|
||||
"async_unload",
|
||||
1,
|
||||
),
|
||||
(
|
||||
config_entries.ConfigEntryState.LOADED,
|
||||
config_entries.ConfigEntryState.LOADED,
|
||||
"async_reload",
|
||||
1,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_entry_state_change_wrapped_in_on_unload(
|
||||
hass: HomeAssistant,
|
||||
manager: config_entries.ConfigEntries,
|
||||
source_state: config_entries.ConfigEntryState,
|
||||
target_state: config_entries.ConfigEntryState,
|
||||
transition_method_name: str,
|
||||
call_count: int,
|
||||
) -> None:
|
||||
"""Test listeners get called on entry state changes.
|
||||
|
||||
This test wraps the listener in async_on_unload, the expectation is that
|
||||
`async_on_unload` is called before the state changes to NOT_LOADED so the
|
||||
listener is not called when the entry is unloaded.
|
||||
"""
|
||||
entry = MockConfigEntry(domain="comp", state=source_state)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"comp",
|
||||
async_setup=AsyncMock(return_value=True),
|
||||
async_setup_entry=AsyncMock(return_value=True),
|
||||
async_unload_entry=AsyncMock(return_value=True),
|
||||
),
|
||||
)
|
||||
mock_platform(hass, "comp.config_flow", None)
|
||||
hass.config.components.add("comp")
|
||||
|
||||
mock_state_change_callback = Mock()
|
||||
entry.async_on_unload(entry.async_on_state_change(mock_state_change_callback))
|
||||
|
||||
transition_method = getattr(manager, transition_method_name)
|
||||
await transition_method(entry.entry_id)
|
||||
|
||||
assert len(mock_state_change_callback.mock_calls) == call_count
|
||||
assert entry.state is target_state
|
||||
|
||||
|
||||
async def test_entry_state_change_listener_removed(
|
||||
hass: HomeAssistant,
|
||||
manager: config_entries.ConfigEntries,
|
||||
|
||||
Reference in New Issue
Block a user