diff --git a/homeassistant/helpers/restore_state.py b/homeassistant/helpers/restore_state.py index 3350ed7a073..67b2d329af1 100644 --- a/homeassistant/helpers/restore_state.py +++ b/homeassistant/helpers/restore_state.py @@ -177,10 +177,18 @@ class RestoreStateData: self.hass.async_create_task(_async_dump_states()) # Dump states periodically - async_track_time_interval(self.hass, _async_dump_states, STATE_DUMP_INTERVAL) + cancel_interval = async_track_time_interval( + self.hass, _async_dump_states, STATE_DUMP_INTERVAL + ) + + async def _async_dump_states_at_stop(*_: Any) -> None: + cancel_interval() + await self.async_dump_states() # Dump states when stopping hass - self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_dump_states) + self.hass.bus.async_listen_once( + EVENT_HOMEASSISTANT_STOP, _async_dump_states_at_stop + ) @callback def async_restore_entity_added(self, entity_id: str) -> None: diff --git a/tests/helpers/test_restore_state.py b/tests/helpers/test_restore_state.py index 1a2fb2f57b5..1d3be2ca98d 100644 --- a/tests/helpers/test_restore_state.py +++ b/tests/helpers/test_restore_state.py @@ -1,8 +1,8 @@ """The tests for the Restore component.""" -from datetime import datetime +from datetime import datetime, timedelta from unittest.mock import patch -from homeassistant.const import EVENT_HOMEASSISTANT_START +from homeassistant.const import EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP from homeassistant.core import CoreState, State from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity import Entity @@ -15,6 +15,8 @@ from homeassistant.helpers.restore_state import ( ) from homeassistant.util import dt as dt_util +from tests.common import async_fire_time_changed + async def test_caching_data(hass): """Test that we cache data.""" @@ -50,6 +52,52 @@ async def test_caching_data(hass): assert mock_write_data.called +async def test_periodic_write(hass): + """Test that we write periodiclly but not after stop.""" + data = await RestoreStateData.async_get_instance(hass) + await hass.async_block_till_done() + await data.store.async_save([]) + + # Emulate a fresh load + hass.data[DATA_RESTORE_STATE_TASK] = None + + entity = RestoreEntity() + entity.hass = hass + entity.entity_id = "input_boolean.b1" + + with patch( + "homeassistant.helpers.restore_state.Store.async_save" + ) as mock_write_data: + await entity.async_get_last_state() + await hass.async_block_till_done() + + assert mock_write_data.called + + with patch( + "homeassistant.helpers.restore_state.Store.async_save" + ) as mock_write_data: + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=15)) + await hass.async_block_till_done() + + assert mock_write_data.called + + with patch( + "homeassistant.helpers.restore_state.Store.async_save" + ) as mock_write_data: + hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP) + await hass.async_block_till_done() + + assert mock_write_data.called + + with patch( + "homeassistant.helpers.restore_state.Store.async_save" + ) as mock_write_data: + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=30)) + await hass.async_block_till_done() + + assert not mock_write_data.called + + async def test_hass_starting(hass): """Test that we cache data.""" hass.state = CoreState.starting