mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Restore input_select and test helper proposal (#6148)
* Restore input_select and test helper proposal * DB still active
This commit is contained in:
parent
8983b826c4
commit
aee8758fc1
@ -13,6 +13,7 @@ from homeassistant.const import ATTR_ENTITY_ID, CONF_ICON, CONF_NAME
|
|||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
|
from homeassistant.helpers.restore_state import async_get_last_state
|
||||||
|
|
||||||
|
|
||||||
DOMAIN = 'input_select'
|
DOMAIN = 'input_select'
|
||||||
@ -194,6 +195,16 @@ class InputSelect(Entity):
|
|||||||
self._options = options
|
self._options = options
|
||||||
self._icon = icon
|
self._icon = icon
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def async_added_to_hass(self):
|
||||||
|
"""Called when entity about to be added to hass."""
|
||||||
|
state = yield from async_get_last_state(self.hass, self.entity_id)
|
||||||
|
if not state:
|
||||||
|
return
|
||||||
|
if state.state not in self._options:
|
||||||
|
return
|
||||||
|
self._current_option = state.state
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self):
|
def should_poll(self):
|
||||||
"""If entity should be polled."""
|
"""If entity should be polled."""
|
||||||
|
@ -297,6 +297,9 @@ class Recorder(threading.Thread):
|
|||||||
"""Tell the recorder to shut down."""
|
"""Tell the recorder to shut down."""
|
||||||
global _INSTANCE # pylint: disable=global-statement
|
global _INSTANCE # pylint: disable=global-statement
|
||||||
self.queue.put(None)
|
self.queue.put(None)
|
||||||
|
if not self.start_recording.is_set():
|
||||||
|
_LOGGER.warning("Recorder never started correctly")
|
||||||
|
self.start_recording.set()
|
||||||
self.join()
|
self.join()
|
||||||
_INSTANCE = None
|
_INSTANCE = None
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ from homeassistant import core as ha, loader
|
|||||||
from homeassistant.bootstrap import (
|
from homeassistant.bootstrap import (
|
||||||
setup_component, async_prepare_setup_component)
|
setup_component, async_prepare_setup_component)
|
||||||
from homeassistant.helpers.entity import ToggleEntity
|
from homeassistant.helpers.entity import ToggleEntity
|
||||||
|
from homeassistant.helpers.restore_state import DATA_RESTORE_CACHE
|
||||||
from homeassistant.util.unit_system import METRIC_SYSTEM
|
from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||||
import homeassistant.util.dt as date_util
|
import homeassistant.util.dt as date_util
|
||||||
import homeassistant.util.yaml as yaml
|
import homeassistant.util.yaml as yaml
|
||||||
@ -88,6 +89,7 @@ def async_test_home_assistant(loop):
|
|||||||
hass = ha.HomeAssistant(loop)
|
hass = ha.HomeAssistant(loop)
|
||||||
|
|
||||||
def async_add_job(target, *args):
|
def async_add_job(target, *args):
|
||||||
|
"""Add a magic mock."""
|
||||||
if isinstance(target, MagicMock):
|
if isinstance(target, MagicMock):
|
||||||
return
|
return
|
||||||
hass._async_add_job_tracking(target, *args)
|
hass._async_add_job_tracking(target, *args)
|
||||||
@ -459,24 +461,19 @@ def init_recorder_component(hass, add_config=None, db_ready_callback=None):
|
|||||||
config = dict(add_config) if add_config else {}
|
config = dict(add_config) if add_config else {}
|
||||||
config[recorder.CONF_DB_URL] = 'sqlite://' # In memory DB
|
config[recorder.CONF_DB_URL] = 'sqlite://' # In memory DB
|
||||||
|
|
||||||
saved_recorder = recorder.Recorder
|
|
||||||
|
|
||||||
class Recorder2(saved_recorder):
|
|
||||||
"""Recorder with a callback after db_ready."""
|
|
||||||
|
|
||||||
def _setup_connection(self):
|
|
||||||
"""Setup the connection and run the callback."""
|
|
||||||
super(Recorder2, self)._setup_connection()
|
|
||||||
if db_ready_callback:
|
|
||||||
_LOGGER.debug('db_ready_callback start (db_ready not set,'
|
|
||||||
'never use get_instance in the callback)')
|
|
||||||
db_ready_callback()
|
|
||||||
_LOGGER.debug('db_ready_callback completed')
|
|
||||||
|
|
||||||
with patch('homeassistant.components.recorder.Recorder',
|
|
||||||
side_effect=Recorder2):
|
|
||||||
assert setup_component(hass, recorder.DOMAIN,
|
assert setup_component(hass, recorder.DOMAIN,
|
||||||
{recorder.DOMAIN: config})
|
{recorder.DOMAIN: config})
|
||||||
assert recorder.DOMAIN in hass.config.components
|
assert recorder.DOMAIN in hass.config.components
|
||||||
recorder.get_instance().block_till_db_ready()
|
recorder.get_instance().block_till_db_ready()
|
||||||
_LOGGER.info("In-memory recorder successfully started")
|
_LOGGER.info("In-memory recorder successfully started")
|
||||||
|
|
||||||
|
|
||||||
|
def mock_restore_cache(hass, states):
|
||||||
|
"""Mock the DATA_RESTORE_CACHE."""
|
||||||
|
hass.data[DATA_RESTORE_CACHE] = {
|
||||||
|
state.entity_id: state for state in states}
|
||||||
|
_LOGGER.debug('Restore cache: %s', hass.data[DATA_RESTORE_CACHE])
|
||||||
|
assert len(hass.data[DATA_RESTORE_CACHE]) == len(states), \
|
||||||
|
"Duplicate entity_id? {}".format(states)
|
||||||
|
hass.state = ha.CoreState.starting
|
||||||
|
hass.config.components.add(recorder.DOMAIN)
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
"""The tests for the Input select component."""
|
"""The tests for the Input select component."""
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
|
import asyncio
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from tests.common import get_test_home_assistant
|
from tests.common import get_test_home_assistant, mock_restore_cache
|
||||||
|
|
||||||
from homeassistant.bootstrap import setup_component
|
from homeassistant.core import State
|
||||||
|
from homeassistant.bootstrap import setup_component, async_setup_component
|
||||||
from homeassistant.components.input_select import (
|
from homeassistant.components.input_select import (
|
||||||
ATTR_OPTIONS, DOMAIN, SERVICE_SET_OPTIONS,
|
ATTR_OPTIONS, DOMAIN, SERVICE_SET_OPTIONS,
|
||||||
select_option, select_next, select_previous)
|
select_option, select_next, select_previous)
|
||||||
@ -211,3 +213,35 @@ class TestInputSelect(unittest.TestCase):
|
|||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
state = self.hass.states.get(entity_id)
|
state = self.hass.states.get(entity_id)
|
||||||
self.assertEqual('test2', state.state)
|
self.assertEqual('test2', state.state)
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_restore_state(hass):
|
||||||
|
"""Ensure states are restored on startup."""
|
||||||
|
mock_restore_cache(hass, (
|
||||||
|
State('input_select.s1', 'last option'),
|
||||||
|
State('input_select.s2', 'bad option'),
|
||||||
|
))
|
||||||
|
|
||||||
|
options = {
|
||||||
|
'options': [
|
||||||
|
'first option',
|
||||||
|
'middle option',
|
||||||
|
'last option',
|
||||||
|
],
|
||||||
|
'initial': 'middle option',
|
||||||
|
}
|
||||||
|
|
||||||
|
yield from async_setup_component(hass, DOMAIN, {
|
||||||
|
DOMAIN: {
|
||||||
|
's1': options,
|
||||||
|
's2': options,
|
||||||
|
}})
|
||||||
|
|
||||||
|
state = hass.states.get('input_select.s1')
|
||||||
|
assert state
|
||||||
|
assert state.state == 'last option'
|
||||||
|
|
||||||
|
state = hass.states.get('input_select.s2')
|
||||||
|
assert state
|
||||||
|
assert state.state == 'middle option'
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
"""The tests for the Restore component."""
|
"""The tests for the Restore component."""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from datetime import timedelta
|
||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
|
|
||||||
|
from homeassistant.bootstrap import setup_component
|
||||||
from homeassistant.const import EVENT_HOMEASSISTANT_START
|
from homeassistant.const import EVENT_HOMEASSISTANT_START
|
||||||
from homeassistant.core import CoreState, State
|
from homeassistant.core import CoreState, split_entity_id, State
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
from homeassistant.components import input_boolean, recorder
|
||||||
from homeassistant.helpers.restore_state import (
|
from homeassistant.helpers.restore_state import (
|
||||||
async_get_last_state, DATA_RESTORE_CACHE)
|
async_get_last_state, DATA_RESTORE_CACHE)
|
||||||
|
|
||||||
|
from tests.common import get_test_home_assistant, init_recorder_component
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_caching_data(hass):
|
def test_caching_data(hass):
|
||||||
@ -40,3 +44,67 @@ def test_caching_data(hass):
|
|||||||
yield from hass.async_block_till_done()
|
yield from hass.async_block_till_done()
|
||||||
|
|
||||||
assert DATA_RESTORE_CACHE not in hass.data
|
assert DATA_RESTORE_CACHE not in hass.data
|
||||||
|
|
||||||
|
|
||||||
|
def _add_data_in_last_run(entities):
|
||||||
|
"""Add test data in the last recorder_run."""
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
t_now = dt_util.utcnow() - timedelta(minutes=10)
|
||||||
|
t_min_1 = t_now - timedelta(minutes=20)
|
||||||
|
t_min_2 = t_now - timedelta(minutes=30)
|
||||||
|
|
||||||
|
recorder_runs = recorder.get_model('RecorderRuns')
|
||||||
|
states = recorder.get_model('States')
|
||||||
|
with recorder.session_scope() as session:
|
||||||
|
run = recorder_runs(
|
||||||
|
start=t_min_2,
|
||||||
|
end=t_now,
|
||||||
|
created=t_min_2
|
||||||
|
)
|
||||||
|
recorder._INSTANCE._commit(session, run)
|
||||||
|
|
||||||
|
for entity_id, state in entities.items():
|
||||||
|
dbstate = states(
|
||||||
|
entity_id=entity_id,
|
||||||
|
domain=split_entity_id(entity_id)[0],
|
||||||
|
state=state,
|
||||||
|
attributes='{}',
|
||||||
|
last_changed=t_min_1,
|
||||||
|
last_updated=t_min_1,
|
||||||
|
created=t_min_1)
|
||||||
|
recorder._INSTANCE._commit(session, dbstate)
|
||||||
|
|
||||||
|
|
||||||
|
def test_filling_the_cache():
|
||||||
|
"""Test filling the cache from the DB."""
|
||||||
|
test_entity_id1 = 'input_boolean.b1'
|
||||||
|
test_entity_id2 = 'input_boolean.b2'
|
||||||
|
|
||||||
|
hass = get_test_home_assistant()
|
||||||
|
hass.state = CoreState.starting
|
||||||
|
|
||||||
|
init_recorder_component(hass)
|
||||||
|
|
||||||
|
_add_data_in_last_run({
|
||||||
|
test_entity_id1: 'on',
|
||||||
|
test_entity_id2: 'off',
|
||||||
|
})
|
||||||
|
|
||||||
|
hass.block_till_done()
|
||||||
|
setup_component(hass, input_boolean.DOMAIN, {
|
||||||
|
input_boolean.DOMAIN: {
|
||||||
|
'b1': None,
|
||||||
|
'b2': None,
|
||||||
|
}})
|
||||||
|
|
||||||
|
hass.start()
|
||||||
|
|
||||||
|
state = hass.states.get('input_boolean.b1')
|
||||||
|
assert state
|
||||||
|
assert state.state == 'on'
|
||||||
|
|
||||||
|
state = hass.states.get('input_boolean.b2')
|
||||||
|
assert state
|
||||||
|
assert state.state == 'off'
|
||||||
|
|
||||||
|
hass.stop()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user