hass-core/tests/components/test_history.py
Paulus Schoutsen 609d7ebea5 Migrate core from threads to async awesomeness (#3248)
* Add event loop to the core

* Add block_till_done to HA core object

* Fix some tests

* Linting core

* Fix statemachine tests

* Core test fixes

* fix block_till_done to wait for loop and queue to empty

* fix test_core for passing, and correct start/stop/block_till_done

* Fix remote tests

* Fix tests: block_till_done

* Fix linting

* Fix more tests

* Fix final linting

* Fix remote test

* remove unnecessary import

* reduce sleep to avoid slowing down the tests excessively

* fix remaining tests to wait for non-threadsafe operations

* Add async_ doc strings for event loop / coroutine info

* Fix command line test to block for the right timeout

* Fix py3.4.2 loop var access

* Fix SERVICE_CALL_LIMIT being in effect for other tests

* Fix lint errors

* Fix lint error with proper placement

* Fix slave start to not start a timer

* Add asyncio compatible listeners.

* Increase min Python version to 3.4.2

* Move async backports to util

* Add backported async tests

* Fix linting

* Simplify Python version check

* Fix lint

* Remove unneeded try/except and queue listener appproriately.

* Fix tuple vs. list unorderable error on version compare.

* Fix version tests
2016-09-12 19:16:14 -07:00

205 lines
7.3 KiB
Python

"""The tests the History component."""
# pylint: disable=protected-access,too-many-public-methods
from datetime import timedelta
import unittest
from unittest.mock import patch, sentinel
import homeassistant.core as ha
import homeassistant.util.dt as dt_util
from homeassistant.components import history, recorder
from tests.common import (
mock_http_component, mock_state_change_event, get_test_home_assistant)
class TestComponentHistory(unittest.TestCase):
"""Test History component."""
def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
def tearDown(self): # pylint: disable=invalid-name
"""Stop everything that was started."""
self.hass.stop()
def init_recorder(self):
"""Initialize the recorder."""
db_uri = 'sqlite://'
with patch('homeassistant.core.Config.path', return_value=db_uri):
recorder.setup(self.hass, config={
"recorder": {
"db_url": db_uri}})
self.hass.start()
recorder._INSTANCE.block_till_db_ready()
self.wait_recording_done()
def wait_recording_done(self):
"""Block till recording is done."""
self.hass.block_till_done()
recorder._INSTANCE.block_till_done()
def test_setup(self):
"""Test setup method of history."""
mock_http_component(self.hass)
self.assertTrue(history.setup(self.hass, {}))
def test_last_5_states(self):
"""Test retrieving the last 5 states."""
self.init_recorder()
states = []
entity_id = 'test.last_5_states'
for i in range(7):
self.hass.states.set(entity_id, "State {}".format(i))
self.wait_recording_done()
if i > 1:
states.append(self.hass.states.get(entity_id))
self.assertEqual(
list(reversed(states)), history.last_5_states(entity_id))
def test_get_states(self):
"""Test getting states at a specific point in time."""
self.init_recorder()
states = []
now = dt_util.utcnow()
with patch('homeassistant.components.recorder.dt_util.utcnow',
return_value=now):
for i in range(5):
state = ha.State(
'test.point_in_time_{}'.format(i % 5),
"State {}".format(i),
{'attribute_test': i})
mock_state_change_event(self.hass, state)
states.append(state)
self.wait_recording_done()
future = now + timedelta(seconds=1)
with patch('homeassistant.components.recorder.dt_util.utcnow',
return_value=future):
for i in range(5):
state = ha.State(
'test.point_in_time_{}'.format(i % 5),
"State {}".format(i),
{'attribute_test': i})
mock_state_change_event(self.hass, state)
self.wait_recording_done()
# Get states returns everything before POINT
self.assertEqual(states,
sorted(history.get_states(future),
key=lambda state: state.entity_id))
# Test get_state here because we have a DB setup
self.assertEqual(
states[0], history.get_state(future, states[0].entity_id))
def test_state_changes_during_period(self):
"""Test state change during period."""
self.init_recorder()
entity_id = 'media_player.test'
def set_state(state):
self.hass.states.set(entity_id, state)
self.wait_recording_done()
return self.hass.states.get(entity_id)
start = dt_util.utcnow()
point = start + timedelta(seconds=1)
end = point + timedelta(seconds=1)
with patch('homeassistant.components.recorder.dt_util.utcnow',
return_value=start):
set_state('idle')
set_state('YouTube')
with patch('homeassistant.components.recorder.dt_util.utcnow',
return_value=point):
states = [
set_state('idle'),
set_state('Netflix'),
set_state('Plex'),
set_state('YouTube'),
]
with patch('homeassistant.components.recorder.dt_util.utcnow',
return_value=end):
set_state('Netflix')
set_state('Plex')
hist = history.state_changes_during_period(start, end, entity_id)
self.assertEqual(states, hist[entity_id])
def test_get_significant_states(self):
"""Test that only significant states are returned.
We inject a bunch of state updates from media player, zone and
thermostat. We should get back every thermostat change that
includes an attribute change, but only the state updates for
media player (attribute changes are not significant and not returned).
"""
self.init_recorder()
mp = 'media_player.test'
therm = 'thermostat.test'
zone = 'zone.home'
script_nc = 'script.cannot_cancel_this_one'
script_c = 'script.can_cancel_this_one'
def set_state(entity_id, state, **kwargs):
self.hass.states.set(entity_id, state, **kwargs)
self.wait_recording_done()
return self.hass.states.get(entity_id)
zero = dt_util.utcnow()
one = zero + timedelta(seconds=1)
two = one + timedelta(seconds=1)
three = two + timedelta(seconds=1)
four = three + timedelta(seconds=1)
states = {therm: [], mp: [], script_c: []}
with patch('homeassistant.components.recorder.dt_util.utcnow',
return_value=one):
states[mp].append(
set_state(mp, 'idle',
attributes={'media_title': str(sentinel.mt1)}))
states[mp].append(
set_state(mp, 'YouTube',
attributes={'media_title': str(sentinel.mt2)}))
states[therm].append(
set_state(therm, 20, attributes={'current_temperature': 19.5}))
with patch('homeassistant.components.recorder.dt_util.utcnow',
return_value=two):
# This state will be skipped only different in time
set_state(mp, 'YouTube',
attributes={'media_title': str(sentinel.mt3)})
# This state will be skipped because domain blacklisted
set_state(zone, 'zoning')
set_state(script_nc, 'off')
states[script_c].append(
set_state(script_c, 'off', attributes={'can_cancel': True}))
states[therm].append(
set_state(therm, 21, attributes={'current_temperature': 19.8}))
with patch('homeassistant.components.recorder.dt_util.utcnow',
return_value=three):
states[mp].append(
set_state(mp, 'Netflix',
attributes={'media_title': str(sentinel.mt4)}))
# Attributes changed even though state is the same
states[therm].append(
set_state(therm, 21, attributes={'current_temperature': 20}))
hist = history.get_significant_states(zero, four)
assert states == hist