Rewrite recorder unittest tests to pytest style test function (#41264)

This commit is contained in:
Ariana Hlavaty 2020-10-06 20:24:13 +01:00 committed by GitHub
parent d35e33610a
commit 1e9e40bf71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 346 additions and 405 deletions

View File

@ -0,0 +1,24 @@
"""Common test tools."""
import pytest
from homeassistant.components.recorder.const import DATA_INSTANCE
from tests.common import get_test_home_assistant, init_recorder_component
@pytest.fixture
def hass_recorder():
"""Home Assistant fixture with in-memory recorder."""
hass = get_test_home_assistant()
def setup_recorder(config=None):
"""Set up with params."""
init_recorder_component(hass, config)
hass.start()
hass.block_till_done()
hass.data[DATA_INSTANCE].block_till_done()
return hass
yield setup_recorder
hass.stop()

View File

@ -1,9 +1,6 @@
"""The tests for the Recorder component.""" """The tests for the Recorder component."""
# pylint: disable=protected-access # pylint: disable=protected-access
from datetime import datetime, timedelta from datetime import datetime, timedelta
import unittest
import pytest
from homeassistant.components.recorder import ( from homeassistant.components.recorder import (
CONFIG_SCHEMA, CONFIG_SCHEMA,
@ -24,47 +21,34 @@ from homeassistant.util import dt as dt_util
from .common import wait_recording_done from .common import wait_recording_done
from tests.async_mock import patch from tests.async_mock import patch
from tests.common import ( from tests.common import async_fire_time_changed, get_test_home_assistant
async_fire_time_changed,
get_test_home_assistant,
init_recorder_component,
)
class TestRecorder(unittest.TestCase): def test_saving_state(hass, hass_recorder):
"""Test the recorder module."""
def setUp(self): # pylint: disable=invalid-name
"""Set up things to be run when tests are started."""
self.hass = get_test_home_assistant()
init_recorder_component(self.hass)
self.hass.start()
self.addCleanup(self.tear_down_cleanup)
def tear_down_cleanup(self):
"""Stop everything that was started."""
self.hass.stop()
def test_saving_state(self):
"""Test saving and restoring a state.""" """Test saving and restoring a state."""
hass = hass_recorder()
entity_id = "test.recorder" entity_id = "test.recorder"
state = "restoring_from_db" state = "restoring_from_db"
attributes = {"test_attr": 5, "test_attr_10": "nice"} attributes = {"test_attr": 5, "test_attr_10": "nice"}
self.hass.states.set(entity_id, state, attributes) hass.states.set(entity_id, state, attributes)
wait_recording_done(self.hass) wait_recording_done(hass)
with session_scope(hass=self.hass) as session: with session_scope(hass=hass) as session:
db_states = list(session.query(States)) db_states = list(session.query(States))
assert len(db_states) == 1 assert len(db_states) == 1
assert db_states[0].event_id > 0 assert db_states[0].event_id > 0
state = db_states[0].to_native() state = db_states[0].to_native()
assert state == _state_empty_context(self.hass, entity_id) assert state == _state_empty_context(hass, entity_id)
def test_saving_event(self):
def test_saving_event(hass, hass_recorder):
"""Test saving and restoring an event.""" """Test saving and restoring an event."""
hass = hass_recorder()
event_type = "EVENT_TEST" event_type = "EVENT_TEST"
event_data = {"test_attr": 5, "test_attr_10": "nice"} event_data = {"test_attr": 5, "test_attr_10": "nice"}
@ -76,18 +60,18 @@ class TestRecorder(unittest.TestCase):
if event.event_type == event_type: if event.event_type == event_type:
events.append(event) events.append(event)
self.hass.bus.listen(MATCH_ALL, event_listener) hass.bus.listen(MATCH_ALL, event_listener)
self.hass.bus.fire(event_type, event_data) hass.bus.fire(event_type, event_data)
wait_recording_done(self.hass) wait_recording_done(hass)
assert len(events) == 1 assert len(events) == 1
event = events[0] event = events[0]
self.hass.data[DATA_INSTANCE].block_till_done() hass.data[DATA_INSTANCE].block_till_done()
with session_scope(hass=self.hass) as session: with session_scope(hass=hass) as session:
db_events = list(session.query(Events).filter_by(event_type=event_type)) db_events = list(session.query(Events).filter_by(event_type=event_type))
assert len(db_events) == 1 assert len(db_events) == 1
db_event = db_events[0].to_native() db_event = db_events[0].to_native()
@ -102,23 +86,6 @@ class TestRecorder(unittest.TestCase):
) )
@pytest.fixture
def hass_recorder():
"""Home Assistant fixture with in-memory recorder."""
hass = get_test_home_assistant()
def setup_recorder(config=None):
"""Set up with params."""
init_recorder_component(hass, config)
hass.start()
hass.block_till_done()
hass.data[DATA_INSTANCE].block_till_done()
return hass
yield setup_recorder
hass.stop()
def _add_entities(hass, entity_ids): def _add_entities(hass, entity_ids):
"""Add entities.""" """Add entities."""
attributes = {"test_attr": 5, "test_attr_10": "nice"} attributes = {"test_attr": 5, "test_attr_10": "nice"}

View File

@ -1,6 +1,5 @@
"""The tests for the Recorder component.""" """The tests for the Recorder component."""
from datetime import datetime from datetime import datetime
import unittest
import pytest import pytest
import pytz import pytz
@ -21,47 +20,14 @@ from homeassistant.exceptions import InvalidEntityFormatError
from homeassistant.util import dt from homeassistant.util import dt
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
ENGINE = None
SESSION = None
def test_from_event_to_db_event():
def setUpModule(): # pylint: disable=invalid-name
"""Set up a database to use."""
global ENGINE
global SESSION
ENGINE = create_engine("sqlite://")
Base.metadata.create_all(ENGINE)
session_factory = sessionmaker(bind=ENGINE)
SESSION = scoped_session(session_factory)
def tearDownModule(): # pylint: disable=invalid-name
"""Close database."""
global ENGINE
global SESSION
ENGINE.dispose()
ENGINE = None
SESSION = None
class TestEvents(unittest.TestCase):
"""Test Events model."""
# pylint: disable=no-self-use
def test_from_event(self):
"""Test converting event to db event.""" """Test converting event to db event."""
event = ha.Event("test_event", {"some_data": 15}) event = ha.Event("test_event", {"some_data": 15})
assert event == Events.from_event(event).to_native() assert event == Events.from_event(event).to_native()
class TestStates(unittest.TestCase): def test_from_event_to_db_state():
"""Test States model."""
# pylint: disable=no-self-use
def test_from_event(self):
"""Test converting event to db state.""" """Test converting event to db state."""
state = ha.State("sensor.temperature", "18") state = ha.State("sensor.temperature", "18")
event = ha.Event( event = ha.Event(
@ -74,7 +40,8 @@ class TestStates(unittest.TestCase):
state.context = ha.Context(id=None) state.context = ha.Context(id=None)
assert state == States.from_event(event).to_native() assert state == States.from_event(event).to_native()
def test_from_event_to_delete_state(self):
def test_from_event_to_delete_state():
"""Test converting deleting state event to db state.""" """Test converting deleting state event to db state."""
event = ha.Event( event = ha.Event(
EVENT_STATE_CHANGED, EVENT_STATE_CHANGED,
@ -93,23 +60,17 @@ class TestStates(unittest.TestCase):
assert db_state.last_updated == event.time_fired assert db_state.last_updated == event.time_fired
class TestRecorderRuns(unittest.TestCase): def test_entity_ids():
"""Test recorder run model.""" """Test if entity ids helper method works."""
engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
session_factory = sessionmaker(bind=engine)
def setUp(self): # pylint: disable=invalid-name session = scoped_session(session_factory)
"""Set up recorder runs."""
self.session = session = SESSION()
session.query(Events).delete() session.query(Events).delete()
session.query(States).delete() session.query(States).delete()
session.query(RecorderRuns).delete() session.query(RecorderRuns).delete()
self.addCleanup(self.tear_down_cleanup)
def tear_down_cleanup(self):
"""Clean up."""
self.session.rollback()
def test_entity_ids(self):
"""Test if entity ids helper method works."""
run = RecorderRuns( run = RecorderRuns(
start=datetime(2016, 7, 9, 11, 0, 0, tzinfo=dt.UTC), start=datetime(2016, 7, 9, 11, 0, 0, tzinfo=dt.UTC),
end=datetime(2016, 7, 9, 23, 0, 0, tzinfo=dt.UTC), end=datetime(2016, 7, 9, 23, 0, 0, tzinfo=dt.UTC),
@ -117,8 +78,8 @@ class TestRecorderRuns(unittest.TestCase):
created=datetime(2016, 7, 9, 11, 0, 0, tzinfo=dt.UTC), created=datetime(2016, 7, 9, 11, 0, 0, tzinfo=dt.UTC),
) )
self.session.add(run) session.add(run)
self.session.commit() session.commit()
before_run = datetime(2016, 7, 9, 8, 0, 0, tzinfo=dt.UTC) before_run = datetime(2016, 7, 9, 8, 0, 0, tzinfo=dt.UTC)
in_run = datetime(2016, 7, 9, 13, 0, 0, tzinfo=dt.UTC) in_run = datetime(2016, 7, 9, 13, 0, 0, tzinfo=dt.UTC)
@ -129,7 +90,7 @@ class TestRecorderRuns(unittest.TestCase):
assert run.to_native() == run assert run.to_native() == run
assert run.entity_ids() == [] assert run.entity_ids() == []
self.session.add( session.add(
States( States(
entity_id="sensor.temperature", entity_id="sensor.temperature",
state="20", state="20",
@ -137,7 +98,7 @@ class TestRecorderRuns(unittest.TestCase):
last_updated=before_run, last_updated=before_run,
) )
) )
self.session.add( session.add(
States( States(
entity_id="sensor.sound", entity_id="sensor.sound",
state="10", state="10",
@ -146,7 +107,7 @@ class TestRecorderRuns(unittest.TestCase):
) )
) )
self.session.add( session.add(
States( States(
entity_id="sensor.humidity", entity_id="sensor.humidity",
state="76", state="76",
@ -154,7 +115,7 @@ class TestRecorderRuns(unittest.TestCase):
last_updated=in_run, last_updated=in_run,
) )
) )
self.session.add( session.add(
States( States(
entity_id="sensor.lux", entity_id="sensor.lux",
state="5", state="5",

View File

@ -1,7 +1,6 @@
"""Test data purging.""" """Test data purging."""
from datetime import datetime, timedelta from datetime import datetime, timedelta
import json import json
import unittest
from homeassistant.components import recorder from homeassistant.components import recorder
from homeassistant.components.recorder.const import DATA_INSTANCE from homeassistant.components.recorder.const import DATA_INSTANCE
@ -13,35 +12,134 @@ from homeassistant.util import dt as dt_util
from .common import wait_recording_done from .common import wait_recording_done
from tests.async_mock import patch from tests.async_mock import patch
from tests.common import get_test_home_assistant, init_recorder_component
class TestRecorderPurge(unittest.TestCase): def test_purge_old_states(hass, hass_recorder):
"""Base class for common recorder tests.""" """Test deleting old states."""
hass = hass_recorder()
_add_test_states(hass)
def setUp(self): # pylint: disable=invalid-name # make sure we start with 6 states
"""Set up things to be run when tests are started.""" with session_scope(hass=hass) as session:
self.hass = get_test_home_assistant() states = session.query(States)
init_recorder_component(self.hass) assert states.count() == 6
self.hass.start()
self.addCleanup(self.tear_down_cleanup)
def tear_down_cleanup(self): # run purge_old_data()
"""Stop everything that was started.""" finished = purge_old_data(hass.data[DATA_INSTANCE], 4, repack=False)
self.hass.stop() assert not finished
assert states.count() == 4
def _add_test_states(self): finished = purge_old_data(hass.data[DATA_INSTANCE], 4, repack=False)
assert not finished
assert states.count() == 2
finished = purge_old_data(hass.data[DATA_INSTANCE], 4, repack=False)
assert finished
assert states.count() == 2
def test_purge_old_events(hass, hass_recorder):
"""Test deleting old events."""
hass = hass_recorder()
_add_test_events(hass)
with session_scope(hass=hass) as session:
events = session.query(Events).filter(Events.event_type.like("EVENT_TEST%"))
assert events.count() == 6
# run purge_old_data()
finished = purge_old_data(hass.data[DATA_INSTANCE], 4, repack=False)
assert not finished
assert events.count() == 4
finished = purge_old_data(hass.data[DATA_INSTANCE], 4, repack=False)
assert not finished
assert events.count() == 2
# we should only have 2 events left
finished = purge_old_data(hass.data[DATA_INSTANCE], 4, repack=False)
assert finished
assert events.count() == 2
def test_purge_method(hass, hass_recorder):
"""Test purge method."""
hass = hass_recorder()
service_data = {"keep_days": 4}
_add_test_events(hass)
_add_test_states(hass)
_add_test_recorder_runs(hass)
# make sure we start with 6 states
with session_scope(hass=hass) as session:
states = session.query(States)
assert states.count() == 6
events = session.query(Events).filter(Events.event_type.like("EVENT_TEST%"))
assert events.count() == 6
recorder_runs = session.query(RecorderRuns)
assert recorder_runs.count() == 7
hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(hass)
# run purge method - no service data, use defaults
hass.services.call("recorder", "purge")
hass.block_till_done()
# Small wait for recorder thread
hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(hass)
# only purged old events
assert states.count() == 4
assert events.count() == 4
# run purge method - correct service data
hass.services.call("recorder", "purge", service_data=service_data)
hass.block_till_done()
# Small wait for recorder thread
hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(hass)
# we should only have 2 states left after purging
assert states.count() == 2
# now we should only have 2 events left
assert events.count() == 2
# now we should only have 3 recorder runs left
assert recorder_runs.count() == 3
assert not ("EVENT_TEST_PURGE" in (event.event_type for event in events.all()))
# run purge method - correct service data, with repack
with patch("homeassistant.components.recorder.purge._LOGGER") as mock_logger:
service_data["repack"] = True
hass.services.call("recorder", "purge", service_data=service_data)
hass.block_till_done()
hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(hass)
assert (
mock_logger.debug.mock_calls[5][1][0]
== "Vacuuming SQL DB to free space"
)
def _add_test_states(hass):
"""Add multiple states to the db for testing.""" """Add multiple states to the db for testing."""
now = datetime.now() now = datetime.now()
five_days_ago = now - timedelta(days=5) five_days_ago = now - timedelta(days=5)
eleven_days_ago = now - timedelta(days=11) eleven_days_ago = now - timedelta(days=11)
attributes = {"test_attr": 5, "test_attr_10": "nice"} attributes = {"test_attr": 5, "test_attr_10": "nice"}
self.hass.block_till_done() hass.block_till_done()
self.hass.data[DATA_INSTANCE].block_till_done() hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(self.hass) wait_recording_done(hass)
with recorder.session_scope(hass=self.hass) as session: with recorder.session_scope(hass=hass) as session:
for event_id in range(6): for event_id in range(6):
if event_id < 2: if event_id < 2:
timestamp = eleven_days_ago timestamp = eleven_days_ago
@ -66,18 +164,19 @@ class TestRecorderPurge(unittest.TestCase):
) )
) )
def _add_test_events(self):
def _add_test_events(hass):
"""Add a few events for testing.""" """Add a few events for testing."""
now = datetime.now() now = datetime.now()
five_days_ago = now - timedelta(days=5) five_days_ago = now - timedelta(days=5)
eleven_days_ago = now - timedelta(days=11) eleven_days_ago = now - timedelta(days=11)
event_data = {"test_attr": 5, "test_attr_10": "nice"} event_data = {"test_attr": 5, "test_attr_10": "nice"}
self.hass.block_till_done() hass.block_till_done()
self.hass.data[DATA_INSTANCE].block_till_done() hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(self.hass) wait_recording_done(hass)
with recorder.session_scope(hass=self.hass) as session: with recorder.session_scope(hass=hass) as session:
for event_id in range(6): for event_id in range(6):
if event_id < 2: if event_id < 2:
timestamp = eleven_days_ago timestamp = eleven_days_ago
@ -99,17 +198,18 @@ class TestRecorderPurge(unittest.TestCase):
) )
) )
def _add_test_recorder_runs(self):
def _add_test_recorder_runs(hass):
"""Add a few recorder_runs for testing.""" """Add a few recorder_runs for testing."""
now = datetime.now() now = datetime.now()
five_days_ago = now - timedelta(days=5) five_days_ago = now - timedelta(days=5)
eleven_days_ago = now - timedelta(days=11) eleven_days_ago = now - timedelta(days=11)
self.hass.block_till_done() hass.block_till_done()
self.hass.data[DATA_INSTANCE].block_till_done() hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(self.hass) wait_recording_done(hass)
with recorder.session_scope(hass=self.hass) as session: with recorder.session_scope(hass=hass) as session:
for rec_id in range(6): for rec_id in range(6):
if rec_id < 2: if rec_id < 2:
timestamp = eleven_days_ago timestamp = eleven_days_ago
@ -125,114 +225,3 @@ class TestRecorderPurge(unittest.TestCase):
end=timestamp + timedelta(days=1), end=timestamp + timedelta(days=1),
) )
) )
def test_purge_old_states(self):
"""Test deleting old states."""
self._add_test_states()
# make sure we start with 6 states
with session_scope(hass=self.hass) as session:
states = session.query(States)
assert states.count() == 6
# run purge_old_data()
finished = purge_old_data(self.hass.data[DATA_INSTANCE], 4, repack=False)
assert not finished
assert states.count() == 4
finished = purge_old_data(self.hass.data[DATA_INSTANCE], 4, repack=False)
assert not finished
assert states.count() == 2
finished = purge_old_data(self.hass.data[DATA_INSTANCE], 4, repack=False)
assert finished
assert states.count() == 2
def test_purge_old_events(self):
"""Test deleting old events."""
self._add_test_events()
with session_scope(hass=self.hass) as session:
events = session.query(Events).filter(Events.event_type.like("EVENT_TEST%"))
assert events.count() == 6
# run purge_old_data()
finished = purge_old_data(self.hass.data[DATA_INSTANCE], 4, repack=False)
assert not finished
assert events.count() == 4
finished = purge_old_data(self.hass.data[DATA_INSTANCE], 4, repack=False)
assert not finished
assert events.count() == 2
# we should only have 2 events left
finished = purge_old_data(self.hass.data[DATA_INSTANCE], 4, repack=False)
assert finished
assert events.count() == 2
def test_purge_method(self):
"""Test purge method."""
service_data = {"keep_days": 4}
self._add_test_events()
self._add_test_states()
self._add_test_recorder_runs()
# make sure we start with 6 states
with session_scope(hass=self.hass) as session:
states = session.query(States)
assert states.count() == 6
events = session.query(Events).filter(Events.event_type.like("EVENT_TEST%"))
assert events.count() == 6
recorder_runs = session.query(RecorderRuns)
assert recorder_runs.count() == 7
self.hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(self.hass)
# run purge method - no service data, use defaults
self.hass.services.call("recorder", "purge")
self.hass.block_till_done()
# Small wait for recorder thread
self.hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(self.hass)
# only purged old events
assert states.count() == 4
assert events.count() == 4
# run purge method - correct service data
self.hass.services.call("recorder", "purge", service_data=service_data)
self.hass.block_till_done()
# Small wait for recorder thread
self.hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(self.hass)
# we should only have 2 states left after purging
assert states.count() == 2
# now we should only have 2 events left
assert events.count() == 2
# now we should only have 3 recorder runs left
assert recorder_runs.count() == 3
assert not (
"EVENT_TEST_PURGE" in (event.event_type for event in events.all())
)
# run purge method - correct service data, with repack
with patch(
"homeassistant.components.recorder.purge._LOGGER"
) as mock_logger:
service_data["repack"] = True
self.hass.services.call("recorder", "purge", service_data=service_data)
self.hass.block_till_done()
self.hass.data[DATA_INSTANCE].block_till_done()
wait_recording_done(self.hass)
assert (
mock_logger.debug.mock_calls[5][1][0]
== "Vacuuming SQL DB to free space"
)