Skip to content

Commit

Permalink
Add checks for config entry state in async_config_entry_first_refresh (
Browse files Browse the repository at this point in the history
  • Loading branch information
epenet authored Oct 16, 2024
1 parent 1ad3a96 commit e5a07da
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 0 deletions.
12 changes: 12 additions & 0 deletions homeassistant/helpers/update_coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,18 @@ async def async_config_entry_first_refresh(self) -> None:
error_if_core=True,
error_if_integration=False,
)
elif (
self.config_entry.state
is not config_entries.ConfigEntryState.SETUP_IN_PROGRESS
):
report(
"uses `async_config_entry_first_refresh`, which is only supported "
f"when entry state is {config_entries.ConfigEntryState.SETUP_IN_PROGRESS}, "
f"but it is in state {self.config_entry.state}, "
"This will stop working in Home Assistant 2025.11",
error_if_core=True,
error_if_integration=False,
)
if await self.__wrap_async_setup():
await self._async_refresh(
log_failures=False, raise_on_auth_failed=True, raise_on_entry_error=True
Expand Down
7 changes: 7 additions & 0 deletions tests/components/rainforest_raven/test_coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pytest

from homeassistant.components.rainforest_raven.coordinator import RAVEnDataCoordinator
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady

Expand All @@ -18,6 +19,7 @@
async def test_coordinator_device_info(hass: HomeAssistant) -> None:
"""Test reporting device information from the coordinator."""
entry = create_mock_entry()
entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None)
coordinator = RAVEnDataCoordinator(hass, entry)

assert coordinator.device_fw_version is None
Expand All @@ -44,6 +46,7 @@ async def test_coordinator_cache_device(
) -> None:
"""Test that the device isn't re-opened for subsequent refreshes."""
entry = create_mock_entry()
entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None)
coordinator = RAVEnDataCoordinator(hass, entry)

await coordinator.async_config_entry_first_refresh()
Expand All @@ -60,6 +63,7 @@ async def test_coordinator_device_error_setup(
) -> None:
"""Test handling of a device error during initialization."""
entry = create_mock_entry()
entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None)
coordinator = RAVEnDataCoordinator(hass, entry)

mock_device.get_network_info.side_effect = RAVEnConnectionError
Expand All @@ -72,6 +76,7 @@ async def test_coordinator_device_error_update(
) -> None:
"""Test handling of a device error during an update."""
entry = create_mock_entry()
entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None)
coordinator = RAVEnDataCoordinator(hass, entry)

await coordinator.async_config_entry_first_refresh()
Expand All @@ -87,6 +92,7 @@ async def test_coordinator_device_timeout_update(
) -> None:
"""Test handling of a device timeout during an update."""
entry = create_mock_entry()
entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None)
coordinator = RAVEnDataCoordinator(hass, entry)

await coordinator.async_config_entry_first_refresh()
Expand All @@ -102,6 +108,7 @@ async def test_coordinator_comm_error(
) -> None:
"""Test handling of an error parsing or reading raw device data."""
entry = create_mock_entry()
entry._async_set_state(hass, ConfigEntryState.SETUP_IN_PROGRESS, None)
coordinator = RAVEnDataCoordinator(hass, entry)

mock_device.synchronize.side_effect = RAVEnConnectionError
Expand Down
49 changes: 49 additions & 0 deletions tests/helpers/test_update_coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,9 @@ async def test_async_config_entry_first_refresh_failure(
a decreasing level of logging once the first message is logged.
"""
entry = MockConfigEntry()
entry._async_set_state(
hass, config_entries.ConfigEntryState.SETUP_IN_PROGRESS, None
)
crd = get_crd(hass, DEFAULT_UPDATE_INTERVAL, entry)
setattr(crd, method, AsyncMock(side_effect=err_msg[0]))

Expand Down Expand Up @@ -586,6 +589,9 @@ async def test_async_config_entry_first_refresh_failure_passed_through(
a decreasing level of logging once the first message is logged.
"""
entry = MockConfigEntry()
entry._async_set_state(
hass, config_entries.ConfigEntryState.SETUP_IN_PROGRESS, None
)
crd = get_crd(hass, DEFAULT_UPDATE_INTERVAL, entry)
setattr(crd, method, AsyncMock(side_effect=err_msg[0]))

Expand All @@ -600,6 +606,9 @@ async def test_async_config_entry_first_refresh_failure_passed_through(
async def test_async_config_entry_first_refresh_success(hass: HomeAssistant) -> None:
"""Test first refresh successfully."""
entry = MockConfigEntry()
entry._async_set_state(
hass, config_entries.ConfigEntryState.SETUP_IN_PROGRESS, None
)
crd = get_crd(hass, DEFAULT_UPDATE_INTERVAL, entry)
crd.setup_method = AsyncMock()
await crd.async_config_entry_first_refresh()
Expand All @@ -608,6 +617,46 @@ async def test_async_config_entry_first_refresh_success(hass: HomeAssistant) ->
crd.setup_method.assert_called_once()


async def test_async_config_entry_first_refresh_invalid_state(
hass: HomeAssistant,
) -> None:
"""Test first refresh fails due to invalid state."""
entry = MockConfigEntry()
crd = get_crd(hass, DEFAULT_UPDATE_INTERVAL, entry)
crd.setup_method = AsyncMock()
with pytest.raises(
RuntimeError,
match="Detected code that uses `async_config_entry_first_refresh`, which "
"is only supported when entry state is ConfigEntryState.SETUP_IN_PROGRESS, "
"but it is in state ConfigEntryState.NOT_LOADED. This will stop working "
"in Home Assistant 2025.11. Please report this issue.",
):
await crd.async_config_entry_first_refresh()

assert crd.last_update_success is True
crd.setup_method.assert_not_called()


@pytest.mark.usefixtures("mock_integration_frame")
async def test_async_config_entry_first_refresh_invalid_state_in_integration(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test first refresh successfully, despite wrong state."""
entry = MockConfigEntry()
crd = get_crd(hass, DEFAULT_UPDATE_INTERVAL, entry)
crd.setup_method = AsyncMock()

await crd.async_config_entry_first_refresh()
assert crd.last_update_success is True
crd.setup_method.assert_called()
assert (
"Detected that integration 'hue' uses `async_config_entry_first_refresh`, which "
"is only supported when entry state is ConfigEntryState.SETUP_IN_PROGRESS, "
"but it is in state ConfigEntryState.NOT_LOADED, This will stop working "
"in Home Assistant 2025.11"
) in caplog.text


async def test_async_config_entry_first_refresh_no_entry(hass: HomeAssistant) -> None:
"""Test first refresh successfully."""
crd = get_crd(hass, DEFAULT_UPDATE_INTERVAL, None)
Expand Down

0 comments on commit e5a07da

Please sign in to comment.