Drop use of async_setup_recorder_instance fixture in recorder purge tests (#121193)

This commit is contained in:
Erik Montnemery 2024-07-04 17:39:24 +02:00 committed by GitHub
parent a1e6f8c2ec
commit 6df15ad8fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 229 additions and 264 deletions

View file

@ -12,7 +12,7 @@ from sqlalchemy.exc import DatabaseError, OperationalError
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
from voluptuous.error import MultipleInvalid from voluptuous.error import MultipleInvalid
from homeassistant.components import recorder from homeassistant.components.recorder import DOMAIN as RECORDER_DOMAIN, Recorder
from homeassistant.components.recorder.const import SupportedDialect from homeassistant.components.recorder.const import SupportedDialect
from homeassistant.components.recorder.db_schema import ( from homeassistant.components.recorder.db_schema import (
Events, Events,
@ -35,7 +35,6 @@ from homeassistant.components.recorder.tasks import PurgeTask
from homeassistant.components.recorder.util import session_scope from homeassistant.components.recorder.util import session_scope
from homeassistant.const import EVENT_STATE_CHANGED, EVENT_THEMES_UPDATED, STATE_ON from homeassistant.const import EVENT_STATE_CHANGED, EVENT_THEMES_UPDATED, STATE_ON
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from .common import ( from .common import (
@ -58,6 +57,13 @@ TEST_EVENT_TYPES = (
) )
@pytest.fixture
async def mock_recorder_before_hass(
async_test_recorder: RecorderInstanceGenerator,
) -> None:
"""Set up recorder."""
@pytest.fixture(name="use_sqlite") @pytest.fixture(name="use_sqlite")
def mock_use_sqlite(request: pytest.FixtureRequest) -> Generator[None]: def mock_use_sqlite(request: pytest.FixtureRequest) -> Generator[None]:
"""Pytest fixture to switch purge method.""" """Pytest fixture to switch purge method."""
@ -70,20 +76,15 @@ def mock_use_sqlite(request: pytest.FixtureRequest) -> Generator[None]:
yield yield
async def test_purge_big_database( async def test_purge_big_database(hass: HomeAssistant, recorder_mock: Recorder) -> None:
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant
) -> None:
"""Test deleting 2/3 old states from a big database.""" """Test deleting 2/3 old states from a big database."""
instance = await async_setup_recorder_instance(hass)
for _ in range(12): for _ in range(12):
await _add_test_states(hass, wait_recording_done=False) await _add_test_states(hass, wait_recording_done=False)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
with ( with (
patch.object(instance, "max_bind_vars", 72), patch.object(recorder_mock, "max_bind_vars", 72),
patch.object(instance.database_engine, "max_bind_vars", 72), patch.object(recorder_mock.database_engine, "max_bind_vars", 72),
session_scope(hass=hass) as session, session_scope(hass=hass) as session,
): ):
states = session.query(States) states = session.query(States)
@ -94,7 +95,7 @@ async def test_purge_big_database(
purge_before = dt_util.utcnow() - timedelta(days=4) purge_before = dt_util.utcnow() - timedelta(days=4)
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
states_batch_size=1, states_batch_size=1,
events_batch_size=1, events_batch_size=1,
@ -105,12 +106,8 @@ async def test_purge_big_database(
assert state_attributes.count() == 1 assert state_attributes.count() == 1
async def test_purge_old_states( async def test_purge_old_states(hass: HomeAssistant, recorder_mock: Recorder) -> None:
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant
) -> None:
"""Test deleting old states.""" """Test deleting old states."""
instance = await async_setup_recorder_instance(hass)
await _add_test_states(hass) await _add_test_states(hass)
# make sure we start with 6 states # make sure we start with 6 states
@ -125,13 +122,13 @@ async def test_purge_old_states(
events = session.query(Events).filter(Events.event_type == "state_changed") events = session.query(Events).filter(Events.event_type == "state_changed")
assert events.count() == 0 assert events.count() == 0
assert "test.recorder2" in instance.states_manager._last_committed_id assert "test.recorder2" in recorder_mock.states_manager._last_committed_id
purge_before = dt_util.utcnow() - timedelta(days=4) purge_before = dt_util.utcnow() - timedelta(days=4)
# run purge_old_data() # run purge_old_data()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
states_batch_size=1, states_batch_size=1,
events_batch_size=1, events_batch_size=1,
@ -141,7 +138,7 @@ async def test_purge_old_states(
assert states.count() == 2 assert states.count() == 2
assert state_attributes.count() == 1 assert state_attributes.count() == 1
assert "test.recorder2" in instance.states_manager._last_committed_id assert "test.recorder2" in recorder_mock.states_manager._last_committed_id
states_after_purge = list(session.query(States)) states_after_purge = list(session.query(States))
# Since these states are deleted in batches, we can't guarantee the order # Since these states are deleted in batches, we can't guarantee the order
@ -153,17 +150,17 @@ async def test_purge_old_states(
assert dontpurgeme_5.old_state_id == dontpurgeme_4.state_id assert dontpurgeme_5.old_state_id == dontpurgeme_4.state_id
assert dontpurgeme_4.old_state_id is None assert dontpurgeme_4.old_state_id is None
finished = purge_old_data(instance, purge_before, repack=False) finished = purge_old_data(recorder_mock, purge_before, repack=False)
assert finished assert finished
assert states.count() == 2 assert states.count() == 2
assert state_attributes.count() == 1 assert state_attributes.count() == 1
assert "test.recorder2" in instance.states_manager._last_committed_id assert "test.recorder2" in recorder_mock.states_manager._last_committed_id
# run purge_old_data again # run purge_old_data again
purge_before = dt_util.utcnow() purge_before = dt_util.utcnow()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
states_batch_size=1, states_batch_size=1,
events_batch_size=1, events_batch_size=1,
@ -173,7 +170,7 @@ async def test_purge_old_states(
assert states.count() == 0 assert states.count() == 0
assert state_attributes.count() == 0 assert state_attributes.count() == 0
assert "test.recorder2" not in instance.states_manager._last_committed_id assert "test.recorder2" not in recorder_mock.states_manager._last_committed_id
# Add some more states # Add some more states
await _add_test_states(hass) await _add_test_states(hass)
@ -187,27 +184,22 @@ async def test_purge_old_states(
events = session.query(Events).filter(Events.event_type == "state_changed") events = session.query(Events).filter(Events.event_type == "state_changed")
assert events.count() == 0 assert events.count() == 0
assert "test.recorder2" in instance.states_manager._last_committed_id assert "test.recorder2" in recorder_mock.states_manager._last_committed_id
state_attributes = session.query(StateAttributes) state_attributes = session.query(StateAttributes)
assert state_attributes.count() == 3 assert state_attributes.count() == 3
@pytest.mark.skip_on_db_engine(["mysql", "postgresql"]) @pytest.mark.skip_on_db_engine(["mysql", "postgresql"])
@pytest.mark.usefixtures("skip_by_db_engine") @pytest.mark.usefixtures("recorder_mock", "skip_by_db_engine")
async def test_purge_old_states_encouters_database_corruption( async def test_purge_old_states_encouters_database_corruption(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
recorder_db_url: str,
) -> None: ) -> None:
"""Test database image image is malformed while deleting old states. """Test database image image is malformed while deleting old states.
This test is specific for SQLite, wiping the database on error only happens This test is specific for SQLite, wiping the database on error only happens
with SQLite. with SQLite.
""" """
await async_setup_recorder_instance(hass)
await _add_test_states(hass) await _add_test_states(hass)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
@ -223,7 +215,7 @@ async def test_purge_old_states_encouters_database_corruption(
side_effect=sqlite3_exception, side_effect=sqlite3_exception,
), ),
): ):
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, {"keep_days": 0}) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, {"keep_days": 0})
await hass.async_block_till_done() await hass.async_block_till_done()
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
@ -236,13 +228,11 @@ async def test_purge_old_states_encouters_database_corruption(
async def test_purge_old_states_encounters_temporary_mysql_error( async def test_purge_old_states_encounters_temporary_mysql_error(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
recorder_mock: Recorder,
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,
) -> None: ) -> None:
"""Test retry on specific mysql operational errors.""" """Test retry on specific mysql operational errors."""
instance = await async_setup_recorder_instance(hass)
await _add_test_states(hass) await _add_test_states(hass)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
@ -255,9 +245,9 @@ async def test_purge_old_states_encounters_temporary_mysql_error(
"homeassistant.components.recorder.purge._purge_old_recorder_runs", "homeassistant.components.recorder.purge._purge_old_recorder_runs",
side_effect=[mysql_exception, None], side_effect=[mysql_exception, None],
), ),
patch.object(instance.engine.dialect, "name", "mysql"), patch.object(recorder_mock.engine.dialect, "name", "mysql"),
): ):
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, {"keep_days": 0}) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, {"keep_days": 0})
await hass.async_block_till_done() await hass.async_block_till_done()
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
@ -266,14 +256,12 @@ async def test_purge_old_states_encounters_temporary_mysql_error(
assert sleep_mock.called assert sleep_mock.called
@pytest.mark.usefixtures("recorder_mock")
async def test_purge_old_states_encounters_operational_error( async def test_purge_old_states_encounters_operational_error(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,
) -> None: ) -> None:
"""Test error on operational errors that are not mysql does not retry.""" """Test error on operational errors that are not mysql does not retry."""
await async_setup_recorder_instance(hass)
await _add_test_states(hass) await _add_test_states(hass)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
@ -283,7 +271,7 @@ async def test_purge_old_states_encounters_operational_error(
"homeassistant.components.recorder.purge._purge_old_recorder_runs", "homeassistant.components.recorder.purge._purge_old_recorder_runs",
side_effect=exception, side_effect=exception,
): ):
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, {"keep_days": 0}) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, {"keep_days": 0})
await hass.async_block_till_done() await hass.async_block_till_done()
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
@ -292,12 +280,8 @@ async def test_purge_old_states_encounters_operational_error(
assert "Error executing purge" in caplog.text assert "Error executing purge" in caplog.text
async def test_purge_old_events( async def test_purge_old_events(hass: HomeAssistant, recorder_mock: Recorder) -> None:
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant
) -> None:
"""Test deleting old events.""" """Test deleting old events."""
instance = await async_setup_recorder_instance(hass)
await _add_test_events(hass) await _add_test_events(hass)
with session_scope(hass=hass) as session: with session_scope(hass=hass) as session:
@ -310,7 +294,7 @@ async def test_purge_old_events(
# run purge_old_data() # run purge_old_data()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=1, events_batch_size=1,
@ -322,7 +306,7 @@ async def test_purge_old_events(
# we should only have 2 events left # we should only have 2 events left
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=1, events_batch_size=1,
@ -333,11 +317,9 @@ async def test_purge_old_events(
async def test_purge_old_recorder_runs( async def test_purge_old_recorder_runs(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant hass: HomeAssistant, recorder_mock: Recorder
) -> None: ) -> None:
"""Test deleting old recorder runs keeps current run.""" """Test deleting old recorder runs keeps current run."""
instance = await async_setup_recorder_instance(hass)
await _add_test_recorder_runs(hass) await _add_test_recorder_runs(hass)
# make sure we start with 7 recorder runs # make sure we start with 7 recorder runs
@ -349,7 +331,7 @@ async def test_purge_old_recorder_runs(
# run purge_old_data() # run purge_old_data()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=1, events_batch_size=1,
@ -358,7 +340,7 @@ async def test_purge_old_recorder_runs(
assert not finished assert not finished
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=1, events_batch_size=1,
@ -369,11 +351,9 @@ async def test_purge_old_recorder_runs(
async def test_purge_old_statistics_runs( async def test_purge_old_statistics_runs(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant hass: HomeAssistant, recorder_mock: Recorder
) -> None: ) -> None:
"""Test deleting old statistics runs keeps the latest run.""" """Test deleting old statistics runs keeps the latest run."""
instance = await async_setup_recorder_instance(hass)
await _add_test_statistics_runs(hass) await _add_test_statistics_runs(hass)
# make sure we start with 7 statistics runs # make sure we start with 7 statistics runs
@ -384,17 +364,17 @@ async def test_purge_old_statistics_runs(
purge_before = dt_util.utcnow() purge_before = dt_util.utcnow()
# run purge_old_data() # run purge_old_data()
finished = purge_old_data(instance, purge_before, repack=False) finished = purge_old_data(recorder_mock, purge_before, repack=False)
assert not finished assert not finished
finished = purge_old_data(instance, purge_before, repack=False) finished = purge_old_data(recorder_mock, purge_before, repack=False)
assert finished assert finished
assert statistics_runs.count() == 1 assert statistics_runs.count() == 1
@pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True)
@pytest.mark.usefixtures("recorder_mock")
async def test_purge_method( async def test_purge_method(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,
use_sqlite: bool, use_sqlite: bool,
@ -412,8 +392,6 @@ async def test_purge_method(
assert run1.run_id == run2.run_id assert run1.run_id == run2.run_id
assert run1.start == run2.start assert run1.start == run2.start
await async_setup_recorder_instance(hass)
service_data = {"keep_days": 4} service_data = {"keep_days": 4}
await _add_test_events(hass) await _add_test_events(hass)
await _add_test_states(hass) await _add_test_states(hass)
@ -519,8 +497,8 @@ async def test_purge_method(
@pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True)
async def test_purge_edge_case( async def test_purge_edge_case(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
recorder_mock: Recorder,
use_sqlite: bool, use_sqlite: bool,
) -> None: ) -> None:
"""Test states and events are purged even if they occurred shortly before purge_before.""" """Test states and events are purged even if they occurred shortly before purge_before."""
@ -554,11 +532,9 @@ async def test_purge_edge_case(
attributes_id=1002, attributes_id=1002,
) )
) )
instance = recorder.get_instance(hass) convert_pending_events_to_event_types(recorder_mock, session)
convert_pending_events_to_event_types(instance, session) convert_pending_states_to_meta(recorder_mock, session)
convert_pending_states_to_meta(instance, session)
await async_setup_recorder_instance(hass, None)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
service_data = {"keep_days": 2} service_data = {"keep_days": 2}
@ -577,7 +553,7 @@ async def test_purge_edge_case(
) )
assert events.count() == 1 assert events.count() == 1
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await hass.async_block_till_done() await hass.async_block_till_done()
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -592,10 +568,7 @@ async def test_purge_edge_case(
assert events.count() == 0 assert events.count() == 0
async def test_purge_cutoff_date( async def test_purge_cutoff_date(hass: HomeAssistant, recorder_mock: Recorder) -> None:
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant,
) -> None:
"""Test states and events are purged only if they occurred before "now() - keep_days".""" """Test states and events are purged only if they occurred before "now() - keep_days"."""
async def _add_db_entries(hass: HomeAssistant, cutoff: datetime, rows: int) -> None: async def _add_db_entries(hass: HomeAssistant, cutoff: datetime, rows: int) -> None:
@ -658,10 +631,9 @@ async def test_purge_cutoff_date(
attributes_id=1000 + row, attributes_id=1000 + row,
) )
) )
convert_pending_events_to_event_types(instance, session) convert_pending_events_to_event_types(recorder_mock, session)
convert_pending_states_to_meta(instance, session) convert_pending_states_to_meta(recorder_mock, session)
instance = await async_setup_recorder_instance(hass, None)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
service_data = {"keep_days": 2} service_data = {"keep_days": 2}
@ -697,7 +669,7 @@ async def test_purge_cutoff_date(
== 1 == 1
) )
instance.queue_task(PurgeTask(cutoff, repack=False, apply_filter=False)) recorder_mock.queue_task(PurgeTask(cutoff, repack=False, apply_filter=False))
await hass.async_block_till_done() await hass.async_block_till_done()
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -738,7 +710,9 @@ async def test_purge_cutoff_date(
) )
# Make sure we can purge everything # Make sure we can purge everything
instance.queue_task(PurgeTask(dt_util.utcnow(), repack=False, apply_filter=False)) recorder_mock.queue_task(
PurgeTask(dt_util.utcnow(), repack=False, apply_filter=False)
)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -749,7 +723,9 @@ async def test_purge_cutoff_date(
assert state_attributes.count() == 0 assert state_attributes.count() == 0
# Make sure we can purge everything when the db is already empty # Make sure we can purge everything when the db is already empty
instance.queue_task(PurgeTask(dt_util.utcnow(), repack=False, apply_filter=False)) recorder_mock.queue_task(
PurgeTask(dt_util.utcnow(), repack=False, apply_filter=False)
)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -761,15 +737,16 @@ async def test_purge_cutoff_date(
@pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True)
@pytest.mark.parametrize(
"recorder_config", [{"exclude": {"entities": ["sensor.excluded"]}}]
)
async def test_purge_filtered_states( async def test_purge_filtered_states(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
recorder_mock: Recorder,
use_sqlite: bool, use_sqlite: bool,
) -> None: ) -> None:
"""Test filtered states are purged.""" """Test filtered states are purged."""
config: ConfigType = {"exclude": {"entities": ["sensor.excluded"]}} assert recorder_mock.entity_filter("sensor.excluded") is False
instance = await async_setup_recorder_instance(hass, config)
assert instance.entity_filter("sensor.excluded") is False
def _add_db_entries(hass: HomeAssistant) -> None: def _add_db_entries(hass: HomeAssistant) -> None:
with session_scope(hass=hass) as session: with session_scope(hass=hass) as session:
@ -852,8 +829,8 @@ async def test_purge_filtered_states(
time_fired_ts=dt_util.utc_to_timestamp(timestamp), time_fired_ts=dt_util.utc_to_timestamp(timestamp),
) )
) )
convert_pending_states_to_meta(instance, session) convert_pending_states_to_meta(recorder_mock, session)
convert_pending_events_to_event_types(instance, session) convert_pending_events_to_event_types(recorder_mock, session)
service_data = {"keep_days": 10} service_data = {"keep_days": 10}
_add_db_entries(hass) _add_db_entries(hass)
@ -867,7 +844,7 @@ async def test_purge_filtered_states(
assert events_keep.count() == 1 assert events_keep.count() == 1
# Normal purge doesn't remove excluded entities # Normal purge doesn't remove excluded entities
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await hass.async_block_till_done() await hass.async_block_till_done()
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -883,7 +860,7 @@ async def test_purge_filtered_states(
# Test with 'apply_filter' = True # Test with 'apply_filter' = True
service_data["apply_filter"] = True service_data["apply_filter"] = True
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await hass.async_block_till_done() await hass.async_block_till_done()
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -931,7 +908,7 @@ async def test_purge_filtered_states(
assert session.query(StateAttributes).count() == 11 assert session.query(StateAttributes).count() == 11
# Do it again to make sure nothing changes # Do it again to make sure nothing changes
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -943,7 +920,7 @@ async def test_purge_filtered_states(
assert session.query(StateAttributes).count() == 11 assert session.query(StateAttributes).count() == 11
service_data = {"keep_days": 0} service_data = {"keep_days": 0}
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -956,15 +933,16 @@ async def test_purge_filtered_states(
@pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True)
@pytest.mark.parametrize(
"recorder_config", [{"exclude": {"entities": ["sensor.excluded"]}}]
)
async def test_purge_filtered_states_to_empty( async def test_purge_filtered_states_to_empty(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
recorder_mock: Recorder,
use_sqlite: bool, use_sqlite: bool,
) -> None: ) -> None:
"""Test filtered states are purged all the way to an empty db.""" """Test filtered states are purged all the way to an empty db."""
config: ConfigType = {"exclude": {"entities": ["sensor.excluded"]}} assert recorder_mock.entity_filter("sensor.excluded") is False
instance = await async_setup_recorder_instance(hass, config)
assert instance.entity_filter("sensor.excluded") is False
def _add_db_entries(hass: HomeAssistant) -> None: def _add_db_entries(hass: HomeAssistant) -> None:
with session_scope(hass=hass) as session: with session_scope(hass=hass) as session:
@ -979,7 +957,7 @@ async def test_purge_filtered_states_to_empty(
timestamp, timestamp,
event_id * days, event_id * days,
) )
convert_pending_states_to_meta(instance, session) convert_pending_states_to_meta(recorder_mock, session)
service_data = {"keep_days": 10} service_data = {"keep_days": 10}
_add_db_entries(hass) _add_db_entries(hass)
@ -992,7 +970,7 @@ async def test_purge_filtered_states_to_empty(
# Test with 'apply_filter' = True # Test with 'apply_filter' = True
service_data["apply_filter"] = True service_data["apply_filter"] = True
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -1004,21 +982,22 @@ async def test_purge_filtered_states_to_empty(
# Do it again to make sure nothing changes # Do it again to make sure nothing changes
# Why do we do this? Should we check the end result? # Why do we do this? Should we check the end result?
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True)
@pytest.mark.parametrize(
"recorder_config", [{"exclude": {"entities": ["sensor.old_format"]}}]
)
async def test_purge_without_state_attributes_filtered_states_to_empty( async def test_purge_without_state_attributes_filtered_states_to_empty(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
recorder_mock: Recorder,
use_sqlite: bool, use_sqlite: bool,
) -> None: ) -> None:
"""Test filtered legacy states without state attributes are purged all the way to an empty db.""" """Test filtered legacy states without state attributes are purged all the way to an empty db."""
config: ConfigType = {"exclude": {"entities": ["sensor.old_format"]}} assert recorder_mock.entity_filter("sensor.old_format") is False
instance = await async_setup_recorder_instance(hass, config)
assert instance.entity_filter("sensor.old_format") is False
def _add_db_entries(hass: HomeAssistant) -> None: def _add_db_entries(hass: HomeAssistant) -> None:
with session_scope(hass=hass) as session: with session_scope(hass=hass) as session:
@ -1055,8 +1034,8 @@ async def test_purge_without_state_attributes_filtered_states_to_empty(
time_fired_ts=dt_util.utc_to_timestamp(timestamp), time_fired_ts=dt_util.utc_to_timestamp(timestamp),
) )
) )
convert_pending_states_to_meta(instance, session) convert_pending_states_to_meta(recorder_mock, session)
convert_pending_events_to_event_types(instance, session) convert_pending_events_to_event_types(recorder_mock, session)
service_data = {"keep_days": 10} service_data = {"keep_days": 10}
_add_db_entries(hass) _add_db_entries(hass)
@ -1069,7 +1048,7 @@ async def test_purge_without_state_attributes_filtered_states_to_empty(
# Test with 'apply_filter' = True # Test with 'apply_filter' = True
service_data["apply_filter"] = True service_data["apply_filter"] = True
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -1081,18 +1060,18 @@ async def test_purge_without_state_attributes_filtered_states_to_empty(
# Do it again to make sure nothing changes # Do it again to make sure nothing changes
# Why do we do this? Should we check the end result? # Why do we do this? Should we check the end result?
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@pytest.mark.parametrize(
"recorder_config", [{"exclude": {"event_types": ["EVENT_PURGE"]}}]
)
async def test_purge_filtered_events( async def test_purge_filtered_events(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, recorder_mock: Recorder
hass: HomeAssistant,
) -> None: ) -> None:
"""Test filtered events are purged.""" """Test filtered events are purged."""
config: ConfigType = {"exclude": {"event_types": ["EVENT_PURGE"]}}
instance = await async_setup_recorder_instance(hass, config)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
def _add_db_entries(hass: HomeAssistant) -> None: def _add_db_entries(hass: HomeAssistant) -> None:
@ -1121,11 +1100,11 @@ async def test_purge_filtered_events(
timestamp, timestamp,
event_id, event_id,
) )
convert_pending_events_to_event_types(instance, session) convert_pending_events_to_event_types(recorder_mock, session)
convert_pending_states_to_meta(instance, session) convert_pending_states_to_meta(recorder_mock, session)
service_data = {"keep_days": 10} service_data = {"keep_days": 10}
await instance.async_add_executor_job(_add_db_entries, hass) await recorder_mock.async_add_executor_job(_add_db_entries, hass)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
with session_scope(hass=hass, read_only=True) as session: with session_scope(hass=hass, read_only=True) as session:
@ -1137,7 +1116,7 @@ async def test_purge_filtered_events(
assert states.count() == 10 assert states.count() == 10
# Normal purge doesn't remove excluded events # Normal purge doesn't remove excluded events
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await hass.async_block_till_done() await hass.async_block_till_done()
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -1153,7 +1132,7 @@ async def test_purge_filtered_events(
# Test with 'apply_filter' = True # Test with 'apply_filter' = True
service_data["apply_filter"] = True service_data["apply_filter"] = True
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await hass.async_block_till_done() await hass.async_block_till_done()
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -1171,23 +1150,26 @@ async def test_purge_filtered_events(
assert states.count() == 10 assert states.count() == 10
@pytest.mark.parametrize(
"recorder_config",
[
{
"exclude": {
"event_types": ["excluded_event"],
"entities": ["sensor.excluded", "sensor.old_format"],
}
}
],
)
async def test_purge_filtered_events_state_changed( async def test_purge_filtered_events_state_changed(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, recorder_mock: Recorder
hass: HomeAssistant,
) -> None: ) -> None:
"""Test filtered state_changed events are purged. This should also remove all states.""" """Test filtered state_changed events are purged. This should also remove all states."""
config: ConfigType = {
"exclude": {
"event_types": ["excluded_event"],
"entities": ["sensor.excluded", "sensor.old_format"],
}
}
instance = await async_setup_recorder_instance(hass, config)
# Assert entity_id is NOT excluded # Assert entity_id is NOT excluded
assert instance.entity_filter("sensor.excluded") is False assert recorder_mock.entity_filter("sensor.excluded") is False
assert instance.entity_filter("sensor.old_format") is False assert recorder_mock.entity_filter("sensor.old_format") is False
assert instance.entity_filter("sensor.keep") is True assert recorder_mock.entity_filter("sensor.keep") is True
assert "excluded_event" in instance.exclude_event_types assert "excluded_event" in recorder_mock.exclude_event_types
def _add_db_entries(hass: HomeAssistant) -> None: def _add_db_entries(hass: HomeAssistant) -> None:
with session_scope(hass=hass) as session: with session_scope(hass=hass) as session:
@ -1260,8 +1242,8 @@ async def test_purge_filtered_events_state_changed(
last_updated_ts=dt_util.utc_to_timestamp(timestamp), last_updated_ts=dt_util.utc_to_timestamp(timestamp),
) )
) )
convert_pending_events_to_event_types(instance, session) convert_pending_events_to_event_types(recorder_mock, session)
convert_pending_states_to_meta(instance, session) convert_pending_states_to_meta(recorder_mock, session)
service_data = {"keep_days": 10, "apply_filter": True} service_data = {"keep_days": 10, "apply_filter": True}
_add_db_entries(hass) _add_db_entries(hass)
@ -1279,7 +1261,7 @@ async def test_purge_filtered_events_state_changed(
assert events_purge.count() == 1 assert events_purge.count() == 1
assert states.count() == 64 assert states.count() == 64
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await hass.async_block_till_done() await hass.async_block_till_done()
for _ in range(4): for _ in range(4):
@ -1313,11 +1295,8 @@ async def test_purge_filtered_events_state_changed(
) # should have been kept ) # should have been kept
async def test_purge_entities( async def test_purge_entities(hass: HomeAssistant, recorder_mock: Recorder) -> None:
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant
) -> None:
"""Test purging of specific entities.""" """Test purging of specific entities."""
instance = await async_setup_recorder_instance(hass)
async def _purge_entities(hass, entity_ids, domains, entity_globs): async def _purge_entities(hass, entity_ids, domains, entity_globs):
service_data = { service_data = {
@ -1327,7 +1306,7 @@ async def test_purge_entities(
} }
await hass.services.async_call( await hass.services.async_call(
recorder.DOMAIN, SERVICE_PURGE_ENTITIES, service_data RECORDER_DOMAIN, SERVICE_PURGE_ENTITIES, service_data
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1365,8 +1344,8 @@ async def test_purge_entities(
timestamp, timestamp,
event_id * days, event_id * days,
) )
convert_pending_states_to_meta(instance, session) convert_pending_states_to_meta(recorder_mock, session)
convert_pending_events_to_event_types(instance, session) convert_pending_events_to_event_types(recorder_mock, session)
def _add_keep_records(hass: HomeAssistant) -> None: def _add_keep_records(hass: HomeAssistant) -> None:
with session_scope(hass=hass) as session: with session_scope(hass=hass) as session:
@ -1380,8 +1359,8 @@ async def test_purge_entities(
timestamp, timestamp,
event_id, event_id,
) )
convert_pending_states_to_meta(instance, session) convert_pending_states_to_meta(recorder_mock, session)
convert_pending_events_to_event_types(instance, session) convert_pending_events_to_event_types(recorder_mock, session)
_add_purge_records(hass) _add_purge_records(hass)
_add_keep_records(hass) _add_keep_records(hass)
@ -1659,15 +1638,14 @@ def _add_state_with_state_attributes(
@pytest.mark.timeout(30) @pytest.mark.timeout(30)
async def test_purge_many_old_events( async def test_purge_many_old_events(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant hass: HomeAssistant, recorder_mock: Recorder
) -> None: ) -> None:
"""Test deleting old events.""" """Test deleting old events."""
old_events_count = 5 old_events_count = 5
instance = await async_setup_recorder_instance(hass)
with ( with (
patch.object(instance, "max_bind_vars", old_events_count), patch.object(recorder_mock, "max_bind_vars", old_events_count),
patch.object(instance.database_engine, "max_bind_vars", old_events_count), patch.object(recorder_mock.database_engine, "max_bind_vars", old_events_count),
): ):
await _add_test_events(hass, old_events_count) await _add_test_events(hass, old_events_count)
@ -1681,7 +1659,7 @@ async def test_purge_many_old_events(
# run purge_old_data() # run purge_old_data()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
states_batch_size=3, states_batch_size=3,
@ -1692,7 +1670,7 @@ async def test_purge_many_old_events(
# we should only have 2 groups of events left # we should only have 2 groups of events left
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
states_batch_size=3, states_batch_size=3,
@ -1703,7 +1681,7 @@ async def test_purge_many_old_events(
# we should now purge everything # we should now purge everything
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
dt_util.utcnow(), dt_util.utcnow(),
repack=False, repack=False,
states_batch_size=20, states_batch_size=20,
@ -1714,11 +1692,10 @@ async def test_purge_many_old_events(
async def test_purge_old_events_purges_the_event_type_ids( async def test_purge_old_events_purges_the_event_type_ids(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant hass: HomeAssistant, recorder_mock: Recorder
) -> None: ) -> None:
"""Test deleting old events purges event type ids.""" """Test deleting old events purges event type ids."""
instance = await async_setup_recorder_instance(hass) assert recorder_mock.event_type_manager.active is True
assert instance.event_type_manager.active is True
utcnow = dt_util.utcnow() utcnow = dt_util.utcnow()
five_days_ago = utcnow - timedelta(days=5) five_days_ago = utcnow - timedelta(days=5)
@ -1762,7 +1739,7 @@ async def test_purge_old_events_purges_the_event_type_ids(
time_fired_ts=dt_util.utc_to_timestamp(timestamp), time_fired_ts=dt_util.utc_to_timestamp(timestamp),
) )
) )
return instance.event_type_manager.get_many( return recorder_mock.event_type_manager.get_many(
[ [
"EVENT_TEST_AUTOPURGE", "EVENT_TEST_AUTOPURGE",
"EVENT_TEST_PURGE", "EVENT_TEST_PURGE",
@ -1772,7 +1749,7 @@ async def test_purge_old_events_purges_the_event_type_ids(
session, session,
) )
event_type_to_id = await instance.async_add_executor_job(_insert_events) event_type_to_id = await recorder_mock.async_add_executor_job(_insert_events)
test_event_type_ids = event_type_to_id.values() test_event_type_ids = event_type_to_id.values()
with session_scope(hass=hass) as session: with session_scope(hass=hass) as session:
events = session.query(Events).where( events = session.query(Events).where(
@ -1787,7 +1764,7 @@ async def test_purge_old_events_purges_the_event_type_ids(
# run purge_old_data() # run purge_old_data()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
far_past, far_past,
repack=False, repack=False,
) )
@ -1796,12 +1773,12 @@ async def test_purge_old_events_purges_the_event_type_ids(
# We should remove the unused event type # We should remove the unused event type
assert event_types.count() == 3 assert event_types.count() == 3
assert "EVENT_TEST_UNUSED" not in instance.event_type_manager._id_map assert "EVENT_TEST_UNUSED" not in recorder_mock.event_type_manager._id_map
# we should only have 10 events left since # we should only have 10 events left since
# only one event type was recorded now # only one event type was recorded now
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
utcnow, utcnow,
repack=False, repack=False,
) )
@ -1811,7 +1788,7 @@ async def test_purge_old_events_purges_the_event_type_ids(
# Purge everything # Purge everything
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
utcnow + timedelta(seconds=1), utcnow + timedelta(seconds=1),
repack=False, repack=False,
) )
@ -1821,11 +1798,10 @@ async def test_purge_old_events_purges_the_event_type_ids(
async def test_purge_old_states_purges_the_state_metadata_ids( async def test_purge_old_states_purges_the_state_metadata_ids(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant hass: HomeAssistant, recorder_mock: Recorder
) -> None: ) -> None:
"""Test deleting old states purges state metadata_ids.""" """Test deleting old states purges state metadata_ids."""
instance = await async_setup_recorder_instance(hass) assert recorder_mock.states_meta_manager.active is True
assert instance.states_meta_manager.active is True
utcnow = dt_util.utcnow() utcnow = dt_util.utcnow()
five_days_ago = utcnow - timedelta(days=5) five_days_ago = utcnow - timedelta(days=5)
@ -1869,13 +1845,15 @@ async def test_purge_old_states_purges_the_state_metadata_ids(
last_updated_ts=dt_util.utc_to_timestamp(timestamp), last_updated_ts=dt_util.utc_to_timestamp(timestamp),
) )
) )
return instance.states_meta_manager.get_many( return recorder_mock.states_meta_manager.get_many(
["sensor.one", "sensor.two", "sensor.three", "sensor.unused"], ["sensor.one", "sensor.two", "sensor.three", "sensor.unused"],
session, session,
True, True,
) )
entity_id_to_metadata_id = await instance.async_add_executor_job(_insert_states) entity_id_to_metadata_id = await recorder_mock.async_add_executor_job(
_insert_states
)
test_metadata_ids = entity_id_to_metadata_id.values() test_metadata_ids = entity_id_to_metadata_id.values()
with session_scope(hass=hass) as session: with session_scope(hass=hass) as session:
states = session.query(States).where(States.metadata_id.in_(test_metadata_ids)) states = session.query(States).where(States.metadata_id.in_(test_metadata_ids))
@ -1888,7 +1866,7 @@ async def test_purge_old_states_purges_the_state_metadata_ids(
# run purge_old_data() # run purge_old_data()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
far_past, far_past,
repack=False, repack=False,
) )
@ -1897,12 +1875,12 @@ async def test_purge_old_states_purges_the_state_metadata_ids(
# We should remove the unused entity_id # We should remove the unused entity_id
assert states_meta.count() == 3 assert states_meta.count() == 3
assert "sensor.unused" not in instance.event_type_manager._id_map assert "sensor.unused" not in recorder_mock.event_type_manager._id_map
# we should only have 10 states left since # we should only have 10 states left since
# only one event type was recorded now # only one event type was recorded now
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
utcnow, utcnow,
repack=False, repack=False,
) )
@ -1912,7 +1890,7 @@ async def test_purge_old_states_purges_the_state_metadata_ids(
# Purge everything # Purge everything
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
utcnow + timedelta(seconds=1), utcnow + timedelta(seconds=1),
repack=False, repack=False,
) )
@ -1922,11 +1900,9 @@ async def test_purge_old_states_purges_the_state_metadata_ids(
async def test_purge_entities_keep_days( async def test_purge_entities_keep_days(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, recorder_mock: Recorder
hass: HomeAssistant,
) -> None: ) -> None:
"""Test purging states with an entity filter and keep_days.""" """Test purging states with an entity filter and keep_days."""
instance = await async_setup_recorder_instance(hass, {})
await hass.async_block_till_done() await hass.async_block_till_done()
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
start = dt_util.utcnow() start = dt_util.utcnow()
@ -1948,7 +1924,7 @@ async def test_purge_entities_keep_days(
hass.states.async_set("sensor.keep", "now") hass.states.async_set("sensor.keep", "now")
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
states = await instance.async_add_executor_job( states = await recorder_mock.async_add_executor_job(
get_significant_states, get_significant_states,
hass, hass,
one_month_ago, one_month_ago,
@ -1959,7 +1935,7 @@ async def test_purge_entities_keep_days(
assert len(states["sensor.purge"]) == 3 assert len(states["sensor.purge"]) == 3
await hass.services.async_call( await hass.services.async_call(
recorder.DOMAIN, RECORDER_DOMAIN,
SERVICE_PURGE_ENTITIES, SERVICE_PURGE_ENTITIES,
{ {
"entity_id": "sensor.purge", "entity_id": "sensor.purge",
@ -1969,7 +1945,7 @@ async def test_purge_entities_keep_days(
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
states = await instance.async_add_executor_job( states = await recorder_mock.async_add_executor_job(
get_significant_states, get_significant_states,
hass, hass,
one_month_ago, one_month_ago,
@ -1980,7 +1956,7 @@ async def test_purge_entities_keep_days(
assert len(states["sensor.purge"]) == 1 assert len(states["sensor.purge"]) == 1
await hass.services.async_call( await hass.services.async_call(
recorder.DOMAIN, RECORDER_DOMAIN,
SERVICE_PURGE_ENTITIES, SERVICE_PURGE_ENTITIES,
{ {
"entity_id": "sensor.purge", "entity_id": "sensor.purge",
@ -1989,7 +1965,7 @@ async def test_purge_entities_keep_days(
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
states = await instance.async_add_executor_job( states = await recorder_mock.async_add_executor_job(
get_significant_states, get_significant_states,
hass, hass,
one_month_ago, one_month_ago,

View file

@ -12,8 +12,11 @@ from sqlalchemy import text, update
from sqlalchemy.exc import DatabaseError, OperationalError from sqlalchemy.exc import DatabaseError, OperationalError
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
from homeassistant.components import recorder from homeassistant.components.recorder import (
from homeassistant.components.recorder import migration DOMAIN as RECORDER_DOMAIN,
Recorder,
migration,
)
from homeassistant.components.recorder.const import SupportedDialect from homeassistant.components.recorder.const import SupportedDialect
from homeassistant.components.recorder.history import get_significant_states from homeassistant.components.recorder.history import get_significant_states
from homeassistant.components.recorder.purge import purge_old_data from homeassistant.components.recorder.purge import purge_old_data
@ -47,6 +50,13 @@ from .db_schema_32 import (
from tests.typing import RecorderInstanceGenerator from tests.typing import RecorderInstanceGenerator
@pytest.fixture
async def mock_recorder_before_hass(
async_test_recorder: RecorderInstanceGenerator,
) -> None:
"""Set up recorder."""
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def db_schema_32(): def db_schema_32():
"""Fixture to initialize the db with the old schema 32.""" """Fixture to initialize the db with the old schema 32."""
@ -66,11 +76,8 @@ def mock_use_sqlite(request: pytest.FixtureRequest) -> Generator[None]:
yield yield
async def test_purge_old_states( async def test_purge_old_states(hass: HomeAssistant, recorder_mock: Recorder) -> None:
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant
) -> None:
"""Test deleting old states.""" """Test deleting old states."""
instance = await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await _add_test_states(hass) await _add_test_states(hass)
@ -87,13 +94,13 @@ async def test_purge_old_states(
events = session.query(Events).filter(Events.event_type == "state_changed") events = session.query(Events).filter(Events.event_type == "state_changed")
assert events.count() == 0 assert events.count() == 0
assert "test.recorder2" in instance.states_manager._last_committed_id assert "test.recorder2" in recorder_mock.states_manager._last_committed_id
purge_before = dt_util.utcnow() - timedelta(days=4) purge_before = dt_util.utcnow() - timedelta(days=4)
# run purge_old_data() # run purge_old_data()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
states_batch_size=1, states_batch_size=1,
events_batch_size=1, events_batch_size=1,
@ -103,7 +110,7 @@ async def test_purge_old_states(
assert states.count() == 2 assert states.count() == 2
assert state_attributes.count() == 1 assert state_attributes.count() == 1
assert "test.recorder2" in instance.states_manager._last_committed_id assert "test.recorder2" in recorder_mock.states_manager._last_committed_id
states_after_purge = list(session.query(States)) states_after_purge = list(session.query(States))
# Since these states are deleted in batches, we can't guarantee the order # Since these states are deleted in batches, we can't guarantee the order
@ -115,17 +122,17 @@ async def test_purge_old_states(
assert dontpurgeme_5.old_state_id == dontpurgeme_4.state_id assert dontpurgeme_5.old_state_id == dontpurgeme_4.state_id
assert dontpurgeme_4.old_state_id is None assert dontpurgeme_4.old_state_id is None
finished = purge_old_data(instance, purge_before, repack=False) finished = purge_old_data(recorder_mock, purge_before, repack=False)
assert finished assert finished
assert states.count() == 2 assert states.count() == 2
assert state_attributes.count() == 1 assert state_attributes.count() == 1
assert "test.recorder2" in instance.states_manager._last_committed_id assert "test.recorder2" in recorder_mock.states_manager._last_committed_id
# run purge_old_data again # run purge_old_data again
purge_before = dt_util.utcnow() purge_before = dt_util.utcnow()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
states_batch_size=1, states_batch_size=1,
events_batch_size=1, events_batch_size=1,
@ -135,7 +142,7 @@ async def test_purge_old_states(
assert states.count() == 0 assert states.count() == 0
assert state_attributes.count() == 0 assert state_attributes.count() == 0
assert "test.recorder2" not in instance.states_manager._last_committed_id assert "test.recorder2" not in recorder_mock.states_manager._last_committed_id
# Add some more states # Add some more states
await _add_test_states(hass) await _add_test_states(hass)
@ -149,26 +156,22 @@ async def test_purge_old_states(
events = session.query(Events).filter(Events.event_type == "state_changed") events = session.query(Events).filter(Events.event_type == "state_changed")
assert events.count() == 0 assert events.count() == 0
assert "test.recorder2" in instance.states_manager._last_committed_id assert "test.recorder2" in recorder_mock.states_manager._last_committed_id
state_attributes = session.query(StateAttributes) state_attributes = session.query(StateAttributes)
assert state_attributes.count() == 3 assert state_attributes.count() == 3
@pytest.mark.skip_on_db_engine(["mysql", "postgresql"]) @pytest.mark.skip_on_db_engine(["mysql", "postgresql"])
@pytest.mark.usefixtures("skip_by_db_engine") @pytest.mark.usefixtures("recorder_mock", "skip_by_db_engine")
async def test_purge_old_states_encouters_database_corruption( async def test_purge_old_states_encouters_database_corruption(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
recorder_db_url: str,
) -> None: ) -> None:
"""Test database image image is malformed while deleting old states. """Test database image image is malformed while deleting old states.
This test is specific for SQLite, wiping the database on error only happens This test is specific for SQLite, wiping the database on error only happens
with SQLite. with SQLite.
""" """
await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await _add_test_states(hass) await _add_test_states(hass)
@ -186,7 +189,7 @@ async def test_purge_old_states_encouters_database_corruption(
side_effect=sqlite3_exception, side_effect=sqlite3_exception,
), ),
): ):
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, {"keep_days": 0}) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, {"keep_days": 0})
await hass.async_block_till_done() await hass.async_block_till_done()
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
@ -199,12 +202,11 @@ async def test_purge_old_states_encouters_database_corruption(
async def test_purge_old_states_encounters_temporary_mysql_error( async def test_purge_old_states_encounters_temporary_mysql_error(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
recorder_mock: Recorder,
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,
) -> None: ) -> None:
"""Test retry on specific mysql operational errors.""" """Test retry on specific mysql operational errors."""
instance = await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await _add_test_states(hass) await _add_test_states(hass)
@ -219,9 +221,9 @@ async def test_purge_old_states_encounters_temporary_mysql_error(
"homeassistant.components.recorder.purge._purge_old_recorder_runs", "homeassistant.components.recorder.purge._purge_old_recorder_runs",
side_effect=[mysql_exception, None], side_effect=[mysql_exception, None],
), ),
patch.object(instance.engine.dialect, "name", "mysql"), patch.object(recorder_mock.engine.dialect, "name", "mysql"),
): ):
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, {"keep_days": 0}) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, {"keep_days": 0})
await hass.async_block_till_done() await hass.async_block_till_done()
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
@ -230,13 +232,12 @@ async def test_purge_old_states_encounters_temporary_mysql_error(
assert sleep_mock.called assert sleep_mock.called
@pytest.mark.usefixtures("recorder_mock")
async def test_purge_old_states_encounters_operational_error( async def test_purge_old_states_encounters_operational_error(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,
) -> None: ) -> None:
"""Test error on operational errors that are not mysql does not retry.""" """Test error on operational errors that are not mysql does not retry."""
await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await _add_test_states(hass) await _add_test_states(hass)
@ -248,7 +249,7 @@ async def test_purge_old_states_encounters_operational_error(
"homeassistant.components.recorder.purge._purge_old_recorder_runs", "homeassistant.components.recorder.purge._purge_old_recorder_runs",
side_effect=exception, side_effect=exception,
): ):
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, {"keep_days": 0}) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, {"keep_days": 0})
await hass.async_block_till_done() await hass.async_block_till_done()
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
@ -257,11 +258,8 @@ async def test_purge_old_states_encounters_operational_error(
assert "Error executing purge" in caplog.text assert "Error executing purge" in caplog.text
async def test_purge_old_events( async def test_purge_old_events(hass: HomeAssistant, recorder_mock: Recorder) -> None:
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant
) -> None:
"""Test deleting old events.""" """Test deleting old events."""
instance = await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await _add_test_events(hass) await _add_test_events(hass)
@ -274,7 +272,7 @@ async def test_purge_old_events(
# run purge_old_data() # run purge_old_data()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=1, events_batch_size=1,
@ -285,7 +283,7 @@ async def test_purge_old_events(
# we should only have 2 events left # we should only have 2 events left
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=1, events_batch_size=1,
@ -296,10 +294,9 @@ async def test_purge_old_events(
async def test_purge_old_recorder_runs( async def test_purge_old_recorder_runs(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant hass: HomeAssistant, recorder_mock: Recorder
) -> None: ) -> None:
"""Test deleting old recorder runs keeps current run.""" """Test deleting old recorder runs keeps current run."""
instance = await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await _add_test_recorder_runs(hass) await _add_test_recorder_runs(hass)
@ -313,7 +310,7 @@ async def test_purge_old_recorder_runs(
# run purge_old_data() # run purge_old_data()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=1, events_batch_size=1,
@ -322,7 +319,7 @@ async def test_purge_old_recorder_runs(
assert not finished assert not finished
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=1, events_batch_size=1,
@ -333,10 +330,9 @@ async def test_purge_old_recorder_runs(
async def test_purge_old_statistics_runs( async def test_purge_old_statistics_runs(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant hass: HomeAssistant, recorder_mock: Recorder
) -> None: ) -> None:
"""Test deleting old statistics runs keeps the latest run.""" """Test deleting old statistics runs keeps the latest run."""
instance = await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await _add_test_statistics_runs(hass) await _add_test_statistics_runs(hass)
@ -349,17 +345,17 @@ async def test_purge_old_statistics_runs(
purge_before = dt_util.utcnow() purge_before = dt_util.utcnow()
# run purge_old_data() # run purge_old_data()
finished = purge_old_data(instance, purge_before, repack=False) finished = purge_old_data(recorder_mock, purge_before, repack=False)
assert not finished assert not finished
finished = purge_old_data(instance, purge_before, repack=False) finished = purge_old_data(recorder_mock, purge_before, repack=False)
assert finished assert finished
assert statistics_runs.count() == 1 assert statistics_runs.count() == 1
@pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True)
@pytest.mark.usefixtures("recorder_mock")
async def test_purge_method( async def test_purge_method(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,
use_sqlite: bool, use_sqlite: bool,
@ -377,7 +373,6 @@ async def test_purge_method(
assert run1.run_id == run2.run_id assert run1.run_id == run2.run_id
assert run1.start == run2.start assert run1.start == run2.start
await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
service_data = {"keep_days": 4} service_data = {"keep_days": 4}
@ -478,11 +473,8 @@ async def test_purge_method(
@pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True)
async def test_purge_edge_case( @pytest.mark.usefixtures("recorder_mock")
async_setup_recorder_instance: RecorderInstanceGenerator, async def test_purge_edge_case(hass: HomeAssistant, use_sqlite: bool) -> None:
hass: HomeAssistant,
use_sqlite: bool,
) -> None:
"""Test states and events are purged even if they occurred shortly before purge_before.""" """Test states and events are purged even if they occurred shortly before purge_before."""
async def _add_db_entries(hass: HomeAssistant, timestamp: datetime) -> None: async def _add_db_entries(hass: HomeAssistant, timestamp: datetime) -> None:
@ -515,7 +507,6 @@ async def test_purge_edge_case(
) )
) )
await async_setup_recorder_instance(hass, None)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -534,7 +525,7 @@ async def test_purge_edge_case(
events = session.query(Events).filter(Events.event_type == "EVENT_TEST_PURGE") events = session.query(Events).filter(Events.event_type == "EVENT_TEST_PURGE")
assert events.count() == 1 assert events.count() == 1
await hass.services.async_call(recorder.DOMAIN, SERVICE_PURGE, service_data) await hass.services.async_call(RECORDER_DOMAIN, SERVICE_PURGE, service_data)
await hass.async_block_till_done() await hass.async_block_till_done()
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
@ -547,10 +538,7 @@ async def test_purge_edge_case(
assert events.count() == 0 assert events.count() == 0
async def test_purge_cutoff_date( async def test_purge_cutoff_date(hass: HomeAssistant, recorder_mock: Recorder) -> None:
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant,
) -> None:
"""Test states and events are purged only if they occurred before "now() - keep_days".""" """Test states and events are purged only if they occurred before "now() - keep_days"."""
async def _add_db_entries(hass: HomeAssistant, cutoff: datetime, rows: int) -> None: async def _add_db_entries(hass: HomeAssistant, cutoff: datetime, rows: int) -> None:
@ -614,7 +602,6 @@ async def test_purge_cutoff_date(
) )
) )
instance = await async_setup_recorder_instance(hass, None)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -643,7 +630,7 @@ async def test_purge_cutoff_date(
assert events.filter(Events.event_type == "PURGE").count() == rows - 1 assert events.filter(Events.event_type == "PURGE").count() == rows - 1
assert events.filter(Events.event_type == "KEEP").count() == 1 assert events.filter(Events.event_type == "KEEP").count() == 1
instance.queue_task(PurgeTask(cutoff, repack=False, apply_filter=False)) recorder_mock.queue_task(PurgeTask(cutoff, repack=False, apply_filter=False))
await hass.async_block_till_done() await hass.async_block_till_done()
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -674,7 +661,9 @@ async def test_purge_cutoff_date(
assert events.filter(Events.event_type == "KEEP").count() == 1 assert events.filter(Events.event_type == "KEEP").count() == 1
# Make sure we can purge everything # Make sure we can purge everything
instance.queue_task(PurgeTask(dt_util.utcnow(), repack=False, apply_filter=False)) recorder_mock.queue_task(
PurgeTask(dt_util.utcnow(), repack=False, apply_filter=False)
)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -685,7 +674,9 @@ async def test_purge_cutoff_date(
assert state_attributes.count() == 0 assert state_attributes.count() == 0
# Make sure we can purge everything when the db is already empty # Make sure we can purge everything when the db is already empty
instance.queue_task(PurgeTask(dt_util.utcnow(), repack=False, apply_filter=False)) recorder_mock.queue_task(
PurgeTask(dt_util.utcnow(), repack=False, apply_filter=False)
)
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
@ -938,16 +929,15 @@ def _add_state_and_state_changed_event(
async def test_purge_many_old_events( async def test_purge_many_old_events(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant hass: HomeAssistant, recorder_mock: Recorder
) -> None: ) -> None:
"""Test deleting old events.""" """Test deleting old events."""
instance = await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
old_events_count = 5 old_events_count = 5
with ( with (
patch.object(instance, "max_bind_vars", old_events_count), patch.object(recorder_mock, "max_bind_vars", old_events_count),
patch.object(instance.database_engine, "max_bind_vars", old_events_count), patch.object(recorder_mock.database_engine, "max_bind_vars", old_events_count),
): ):
await _add_test_events(hass, old_events_count) await _add_test_events(hass, old_events_count)
@ -959,7 +949,7 @@ async def test_purge_many_old_events(
# run purge_old_data() # run purge_old_data()
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
states_batch_size=3, states_batch_size=3,
@ -970,7 +960,7 @@ async def test_purge_many_old_events(
# we should only have 2 groups of events left # we should only have 2 groups of events left
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
states_batch_size=3, states_batch_size=3,
@ -981,7 +971,7 @@ async def test_purge_many_old_events(
# we should now purge everything # we should now purge everything
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
dt_util.utcnow(), dt_util.utcnow(),
repack=False, repack=False,
states_batch_size=20, states_batch_size=20,
@ -992,23 +982,24 @@ async def test_purge_many_old_events(
async def test_purge_can_mix_legacy_and_new_format( async def test_purge_can_mix_legacy_and_new_format(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant hass: HomeAssistant, recorder_mock: Recorder
) -> None: ) -> None:
"""Test purging with legacy and new events.""" """Test purging with legacy and new events."""
instance = await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
# New databases are no longer created with the legacy events index # New databases are no longer created with the legacy events index
assert instance.use_legacy_events_index is False assert recorder_mock.use_legacy_events_index is False
def _recreate_legacy_events_index(): def _recreate_legacy_events_index():
"""Recreate the legacy events index since its no longer created on new instances.""" """Recreate the legacy events index since its no longer created on new instances."""
migration._create_index(instance.get_session, "states", "ix_states_event_id") migration._create_index(
instance.use_legacy_events_index = True recorder_mock.get_session, "states", "ix_states_event_id"
)
recorder_mock.use_legacy_events_index = True
await instance.async_add_executor_job(_recreate_legacy_events_index) await recorder_mock.async_add_executor_job(_recreate_legacy_events_index)
assert instance.use_legacy_events_index is True assert recorder_mock.use_legacy_events_index is True
utcnow = dt_util.utcnow() utcnow = dt_util.utcnow()
eleven_days_ago = utcnow - timedelta(days=11) eleven_days_ago = utcnow - timedelta(days=11)
@ -1049,7 +1040,7 @@ async def test_purge_can_mix_legacy_and_new_format(
purge_before = dt_util.utcnow() - timedelta(days=4) purge_before = dt_util.utcnow() - timedelta(days=4)
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
) )
@ -1060,7 +1051,7 @@ async def test_purge_can_mix_legacy_and_new_format(
# and we switch methods # and we switch methods
purge_before = dt_util.utcnow() - timedelta(days=4) purge_before = dt_util.utcnow() - timedelta(days=4)
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=1, events_batch_size=1,
@ -1073,7 +1064,7 @@ async def test_purge_can_mix_legacy_and_new_format(
assert states_with_event_id.count() == 0 assert states_with_event_id.count() == 0
assert states_without_event_id.count() == 1 assert states_without_event_id.count() == 1
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=100, events_batch_size=100,
@ -1088,7 +1079,7 @@ async def test_purge_can_mix_legacy_and_new_format(
assert states_with_event_id.count() == 0 assert states_with_event_id.count() == 0
assert states_without_event_id.count() == 2 assert states_without_event_id.count() == 2
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
) )
@ -1102,29 +1093,29 @@ async def test_purge_can_mix_legacy_and_new_format(
@pytest.mark.skip_on_db_engine(["mysql", "postgresql"]) @pytest.mark.skip_on_db_engine(["mysql", "postgresql"])
@pytest.mark.usefixtures("skip_by_db_engine") @pytest.mark.usefixtures("skip_by_db_engine")
async def test_purge_can_mix_legacy_and_new_format_with_detached_state( async def test_purge_can_mix_legacy_and_new_format_with_detached_state(
async_setup_recorder_instance: RecorderInstanceGenerator,
hass: HomeAssistant, hass: HomeAssistant,
recorder_mock: Recorder,
recorder_db_url: str, recorder_db_url: str,
) -> None: ) -> None:
"""Test purging with legacy and new events with a detached state. """Test purging with legacy and new events with a detached state.
This tests disables foreign key checks on SQLite. This tests disables foreign key checks on SQLite.
""" """
instance = await async_setup_recorder_instance(hass)
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
# New databases are no longer created with the legacy events index # New databases are no longer created with the legacy events index
assert instance.use_legacy_events_index is False assert recorder_mock.use_legacy_events_index is False
def _recreate_legacy_events_index(): def _recreate_legacy_events_index():
"""Recreate the legacy events index since its no longer created on new instances.""" """Recreate the legacy events index since its no longer created on new instances."""
migration._create_index(instance.get_session, "states", "ix_states_event_id") migration._create_index(
instance.use_legacy_events_index = True recorder_mock.get_session, "states", "ix_states_event_id"
)
recorder_mock.use_legacy_events_index = True
await instance.async_add_executor_job(_recreate_legacy_events_index) await recorder_mock.async_add_executor_job(_recreate_legacy_events_index)
assert instance.use_legacy_events_index is True assert recorder_mock.use_legacy_events_index is True
with session_scope(hass=hass) as session: with session_scope(hass=hass) as session:
session.execute(text("PRAGMA foreign_keys = OFF")) session.execute(text("PRAGMA foreign_keys = OFF"))
@ -1196,7 +1187,7 @@ async def test_purge_can_mix_legacy_and_new_format_with_detached_state(
purge_before = dt_util.utcnow() - timedelta(days=4) purge_before = dt_util.utcnow() - timedelta(days=4)
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
) )
@ -1207,7 +1198,7 @@ async def test_purge_can_mix_legacy_and_new_format_with_detached_state(
# and we switch methods # and we switch methods
purge_before = dt_util.utcnow() - timedelta(days=4) purge_before = dt_util.utcnow() - timedelta(days=4)
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=1, events_batch_size=1,
@ -1220,7 +1211,7 @@ async def test_purge_can_mix_legacy_and_new_format_with_detached_state(
assert states_with_event_id.count() == 0 assert states_with_event_id.count() == 0
assert states_without_event_id.count() == 1 assert states_without_event_id.count() == 1
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
events_batch_size=100, events_batch_size=100,
@ -1235,7 +1226,7 @@ async def test_purge_can_mix_legacy_and_new_format_with_detached_state(
assert states_with_event_id.count() == 0 assert states_with_event_id.count() == 0
assert states_without_event_id.count() == 2 assert states_without_event_id.count() == 2
finished = purge_old_data( finished = purge_old_data(
instance, recorder_mock,
purge_before, purge_before,
repack=False, repack=False,
) )
@ -1247,11 +1238,9 @@ async def test_purge_can_mix_legacy_and_new_format_with_detached_state(
async def test_purge_entities_keep_days( async def test_purge_entities_keep_days(
async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, recorder_mock: Recorder
hass: HomeAssistant,
) -> None: ) -> None:
"""Test purging states with an entity filter and keep_days.""" """Test purging states with an entity filter and keep_days."""
instance = await async_setup_recorder_instance(hass, {})
await async_attach_db_engine(hass) await async_attach_db_engine(hass)
await hass.async_block_till_done() await hass.async_block_till_done()
@ -1275,7 +1264,7 @@ async def test_purge_entities_keep_days(
hass.states.async_set("sensor.keep", "now") hass.states.async_set("sensor.keep", "now")
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
states = await instance.async_add_executor_job( states = await recorder_mock.async_add_executor_job(
get_significant_states, get_significant_states,
hass, hass,
one_month_ago, one_month_ago,
@ -1286,7 +1275,7 @@ async def test_purge_entities_keep_days(
assert len(states["sensor.purge"]) == 3 assert len(states["sensor.purge"]) == 3
await hass.services.async_call( await hass.services.async_call(
recorder.DOMAIN, RECORDER_DOMAIN,
SERVICE_PURGE_ENTITIES, SERVICE_PURGE_ENTITIES,
{ {
"entity_id": "sensor.purge", "entity_id": "sensor.purge",
@ -1296,7 +1285,7 @@ async def test_purge_entities_keep_days(
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
states = await instance.async_add_executor_job( states = await recorder_mock.async_add_executor_job(
get_significant_states, get_significant_states,
hass, hass,
one_month_ago, one_month_ago,
@ -1307,7 +1296,7 @@ async def test_purge_entities_keep_days(
assert len(states["sensor.purge"]) == 1 assert len(states["sensor.purge"]) == 1
await hass.services.async_call( await hass.services.async_call(
recorder.DOMAIN, RECORDER_DOMAIN,
SERVICE_PURGE_ENTITIES, SERVICE_PURGE_ENTITIES,
{ {
"entity_id": "sensor.purge", "entity_id": "sensor.purge",
@ -1316,7 +1305,7 @@ async def test_purge_entities_keep_days(
await async_recorder_block_till_done(hass) await async_recorder_block_till_done(hass)
await async_wait_purge_done(hass) await async_wait_purge_done(hass)
states = await instance.async_add_executor_job( states = await recorder_mock.async_add_executor_job(
get_significant_states, get_significant_states,
hass, hass,
one_month_ago, one_month_ago,