async def test_caching_data(hass): """Test that we cache data.""" now = dt_util.utcnow() stored_states = [ StoredState(State("input_boolean.b0", "on"), None, now), StoredState(State("input_boolean.b1", "on"), None, now), StoredState(State("input_boolean.b2", "on"), None, now), ] data = await RestoreStateData.async_get_instance(hass) await hass.async_block_till_done() await data.store.async_save([state.as_dict() for state in stored_states]) # Emulate a fresh load hass.data.pop(DATA_RESTORE_STATE_TASK) entity = RestoreEntity() entity.hass = hass entity.entity_id = "input_boolean.b1" # Mock that only b1 is present this run with patch("homeassistant.helpers.restore_state.Store.async_save" ) as mock_write_data: state = await entity.async_get_last_state() await hass.async_block_till_done() assert state is not None assert state.entity_id == "input_boolean.b1" assert state.state == "on" assert mock_write_data.called
async def test_caching_data(hass): """Test that we cache data.""" now = dt_util.utcnow() stored_states = [ StoredState(State('input_boolean.b0', 'on'), now), StoredState(State('input_boolean.b1', 'on'), now), StoredState(State('input_boolean.b2', 'on'), now), ] data = await RestoreStateData.async_get_instance(hass) await data.store.async_save([state.as_dict() for state in stored_states]) # Emulate a fresh load hass.data[DATA_RESTORE_STATE_TASK] = None entity = RestoreEntity() entity.hass = hass entity.entity_id = 'input_boolean.b1' # Mock that only b1 is present this run with patch('homeassistant.helpers.restore_state.Store.async_save' ) as mock_write_data: state = await entity.async_get_last_state() assert state is not None assert state.entity_id == 'input_boolean.b1' assert state.state == 'on' assert mock_write_data.called
async def test_restore_active_resume(hass): """Test entity restore logic when timer is active and end time is after startup.""" events = async_capture_events(hass, EVENT_TIMER_RESTARTED) assert not events utc_now = utcnow() finish = utc_now + timedelta(seconds=30) simulated_utc_now = utc_now + timedelta(seconds=15) stored_state = StoredState( State( "timer.test", STATUS_ACTIVE, { ATTR_DURATION: "0:00:30", ATTR_FINISHES_AT: finish.isoformat() }, ), None, utc_now, ) data = await RestoreStateData.async_get_instance(hass) await hass.async_block_till_done() await data.store.async_save([stored_state.as_dict()]) # Emulate a fresh load hass.data.pop(DATA_RESTORE_STATE_TASK) entity = Timer({ CONF_ID: "test", CONF_NAME: "test", CONF_DURATION: "0:01:00", CONF_RESTORE: True, }) entity.hass = hass entity.entity_id = "timer.test" # In patch make sure we ignore microseconds with patch( "homeassistant.components.timer.dt_util.utcnow", return_value=simulated_utc_now.replace(microsecond=999), ): await entity.async_added_to_hass() await hass.async_block_till_done() assert entity.state == STATUS_ACTIVE assert entity.extra_state_attributes[ATTR_DURATION] == "0:00:30" assert entity.extra_state_attributes[ATTR_REMAINING] == "0:00:15" assert entity.extra_state_attributes[ATTR_FINISHES_AT] == finish.isoformat( ) assert entity.extra_state_attributes[ATTR_RESTORE] assert len(events) == 1
async def test_hass_starting(hass): """Test that we cache data.""" hass.state = CoreState.starting now = dt_util.utcnow() stored_states = [ StoredState(State("input_boolean.b0", "on"), None, now), StoredState(State("input_boolean.b1", "on"), None, now), StoredState(State("input_boolean.b2", "on"), None, now), ] data = await RestoreStateData.async_get_instance(hass) await hass.async_block_till_done() await data.store.async_save([state.as_dict() for state in stored_states]) # Emulate a fresh load hass.state = CoreState.not_running hass.data.pop(DATA_RESTORE_STATE_TASK) entity = RestoreEntity() entity.hass = hass entity.entity_id = "input_boolean.b1" # Mock that only b1 is present this run states = [State("input_boolean.b1", "on")] with patch("homeassistant.helpers.restore_state.Store.async_save" ) as mock_write_data, patch.object(hass.states, "async_all", return_value=states): state = await entity.async_get_last_state() await hass.async_block_till_done() assert state is not None assert state.entity_id == "input_boolean.b1" assert state.state == "on" # Assert that no data was written yet, since hass is still starting. assert not mock_write_data.called # Finish hass startup with patch("homeassistant.helpers.restore_state.Store.async_save" ) as mock_write_data: hass.bus.async_fire(EVENT_HOMEASSISTANT_START) await hass.async_block_till_done() # Assert that this session states were written assert mock_write_data.called
async def test_restore_active_finished_outside_grace(hass): """Test entity restore logic: timer is active, ended while Home Assistant was stopped.""" events = async_capture_events(hass, EVENT_TIMER_FINISHED) assert not events utc_now = utcnow() finish = utc_now + timedelta(seconds=30) simulated_utc_now = utc_now + timedelta(seconds=46) stored_state = StoredState( State( "timer.test", STATUS_ACTIVE, { ATTR_DURATION: "0:00:30", ATTR_FINISHES_AT: finish.isoformat() }, ), None, utc_now, ) data = await RestoreStateData.async_get_instance(hass) await hass.async_block_till_done() await data.store.async_save([stored_state.as_dict()]) # Emulate a fresh load hass.data.pop(DATA_RESTORE_STATE_TASK) entity = Timer({ CONF_ID: "test", CONF_NAME: "test", CONF_DURATION: "0:01:00", CONF_RESTORE: True, }) entity.hass = hass entity.entity_id = "timer.test" with patch("homeassistant.components.timer.dt_util.utcnow", return_value=simulated_utc_now): await entity.async_added_to_hass() await hass.async_block_till_done() assert entity.state == STATUS_IDLE assert entity.extra_state_attributes[ATTR_DURATION] == "0:00:30" assert ATTR_REMAINING not in entity.extra_state_attributes assert ATTR_FINISHES_AT not in entity.extra_state_attributes assert entity.extra_state_attributes[ATTR_RESTORE] assert len(events) == 1
async def test_restore_paused(hass): """Test entity restore logic when timer is paused.""" utc_now = utcnow() stored_state = StoredState( State( "timer.test", STATUS_PAUSED, { ATTR_DURATION: "0:00:30", ATTR_REMAINING: "0:00:15" }, ), None, utc_now, ) data = await RestoreStateData.async_get_instance(hass) await hass.async_block_till_done() await data.store.async_save([stored_state.as_dict()]) # Emulate a fresh load hass.data.pop(DATA_RESTORE_STATE_TASK) entity = Timer({ CONF_ID: "test", CONF_NAME: "test", CONF_DURATION: "0:01:00", CONF_RESTORE: True, }) entity.hass = hass entity.entity_id = "timer.test" await entity.async_added_to_hass() await hass.async_block_till_done() assert entity.state == STATUS_PAUSED assert entity.extra_state_attributes[ATTR_DURATION] == "0:00:30" assert entity.extra_state_attributes[ATTR_REMAINING] == "0:00:15" assert ATTR_FINISHES_AT not in entity.extra_state_attributes assert entity.extra_state_attributes[ATTR_RESTORE]
async def test_dump_data(hass): """Test that we cache data.""" states = [ State("input_boolean.b0", "on"), State("input_boolean.b1", "on"), State("input_boolean.b2", "on"), State("input_boolean.b5", "unavailable", {"restored": True}), ] entity = Entity() entity.hass = hass entity.entity_id = "input_boolean.b0" await entity.async_internal_added_to_hass() entity = RestoreEntity() entity.hass = hass entity.entity_id = "input_boolean.b1" await entity.async_internal_added_to_hass() data = await RestoreStateData.async_get_instance(hass) now = dt_util.utcnow() data.last_states = { "input_boolean.b0": StoredState(State("input_boolean.b0", "off"), None, now), "input_boolean.b1": StoredState(State("input_boolean.b1", "off"), None, now), "input_boolean.b2": StoredState(State("input_boolean.b2", "off"), None, now), "input_boolean.b3": StoredState(State("input_boolean.b3", "off"), None, now), "input_boolean.b4": StoredState( State("input_boolean.b4", "off"), None, datetime(1985, 10, 26, 1, 22, tzinfo=dt_util.UTC), ), "input_boolean.b5": StoredState(State("input_boolean.b5", "off"), None, now), } with patch("homeassistant.helpers.restore_state.Store.async_save" ) as mock_write_data, patch.object(hass.states, "async_all", return_value=states): await data.async_dump_states() assert mock_write_data.called args = mock_write_data.mock_calls[0][1] written_states = args[0] # b0 should not be written, since it didn't extend RestoreEntity # b1 should be written, since it is present in the current run # b2 should not be written, since it is not registered with the helper # b3 should be written, since it is still not expired # b4 should not be written, since it is now expired # b5 should be written, since current state is restored by entity registry assert len(written_states) == 3 assert written_states[0]["state"]["entity_id"] == "input_boolean.b1" assert written_states[0]["state"]["state"] == "on" assert written_states[1]["state"]["entity_id"] == "input_boolean.b3" assert written_states[1]["state"]["state"] == "off" assert written_states[2]["state"]["entity_id"] == "input_boolean.b5" assert written_states[2]["state"]["state"] == "off" # Test that removed entities are not persisted await entity.async_remove() with patch("homeassistant.helpers.restore_state.Store.async_save" ) as mock_write_data, patch.object(hass.states, "async_all", return_value=states): await data.async_dump_states() assert mock_write_data.called args = mock_write_data.mock_calls[0][1] written_states = args[0] assert len(written_states) == 2 assert written_states[0]["state"]["entity_id"] == "input_boolean.b3" assert written_states[0]["state"]["state"] == "off" assert written_states[1]["state"]["entity_id"] == "input_boolean.b5" assert written_states[1]["state"]["state"] == "off"
async def test_dump_data(hass): """Test that we cache data.""" states = [ State('input_boolean.b0', 'on'), State('input_boolean.b1', 'on'), State('input_boolean.b2', 'on'), ] entity = Entity() entity.hass = hass entity.entity_id = 'input_boolean.b0' await entity.async_internal_added_to_hass() entity = RestoreEntity() entity.hass = hass entity.entity_id = 'input_boolean.b1' await entity.async_internal_added_to_hass() data = await RestoreStateData.async_get_instance(hass) now = dt_util.utcnow() data.last_states = { 'input_boolean.b0': StoredState(State('input_boolean.b0', 'off'), now), 'input_boolean.b1': StoredState(State('input_boolean.b1', 'off'), now), 'input_boolean.b2': StoredState(State('input_boolean.b2', 'off'), now), 'input_boolean.b3': StoredState(State('input_boolean.b3', 'off'), now), 'input_boolean.b4': StoredState(State('input_boolean.b4', 'off'), datetime(1985, 10, 26, 1, 22, tzinfo=dt_util.UTC)), } with patch('homeassistant.helpers.restore_state.Store.async_save' ) as mock_write_data, patch.object(hass.states, 'async_all', return_value=states): await data.async_dump_states() assert mock_write_data.called args = mock_write_data.mock_calls[0][1] written_states = args[0] # b0 should not be written, since it didn't extend RestoreEntity # b1 should be written, since it is present in the current run # b2 should not be written, since it is not registered with the helper # b3 should be written, since it is still not expired # b4 should not be written, since it is now expired assert len(written_states) == 2 assert written_states[0]['state']['entity_id'] == 'input_boolean.b1' assert written_states[0]['state']['state'] == 'on' assert written_states[1]['state']['entity_id'] == 'input_boolean.b3' assert written_states[1]['state']['state'] == 'off' # Test that removed entities are not persisted await entity.async_remove() with patch('homeassistant.helpers.restore_state.Store.async_save' ) as mock_write_data, patch.object(hass.states, 'async_all', return_value=states): await data.async_dump_states() assert mock_write_data.called args = mock_write_data.mock_calls[0][1] written_states = args[0] assert len(written_states) == 1 assert written_states[0]['state']['entity_id'] == 'input_boolean.b3' assert written_states[0]['state']['state'] == 'off'