From 6df15ad8fc57086834be1a8275b95c79e3e29cc1 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Thu, 4 Jul 2024 17:39:24 +0200 Subject: [PATCH] Drop use of async_setup_recorder_instance fixture in recorder purge tests (#121193) --- tests/components/recorder/test_purge.py | 312 ++++++++---------- .../recorder/test_purge_v32_schema.py | 181 +++++----- 2 files changed, 229 insertions(+), 264 deletions(-) diff --git a/tests/components/recorder/test_purge.py b/tests/components/recorder/test_purge.py index b21bbd36d28..5e6a413d64e 100644 --- a/tests/components/recorder/test_purge.py +++ b/tests/components/recorder/test_purge.py @@ -12,7 +12,7 @@ from sqlalchemy.exc import DatabaseError, OperationalError from sqlalchemy.orm.session import Session 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.db_schema import ( Events, @@ -35,7 +35,6 @@ from homeassistant.components.recorder.tasks import PurgeTask from homeassistant.components.recorder.util import session_scope from homeassistant.const import EVENT_STATE_CHANGED, EVENT_THEMES_UPDATED, STATE_ON from homeassistant.core import HomeAssistant -from homeassistant.helpers.typing import ConfigType from homeassistant.util import dt as dt_util 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") def mock_use_sqlite(request: pytest.FixtureRequest) -> Generator[None]: """Pytest fixture to switch purge method.""" @@ -70,20 +76,15 @@ def mock_use_sqlite(request: pytest.FixtureRequest) -> Generator[None]: yield -async def test_purge_big_database( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant -) -> None: +async def test_purge_big_database(hass: HomeAssistant, recorder_mock: Recorder) -> None: """Test deleting 2/3 old states from a big database.""" - - instance = await async_setup_recorder_instance(hass) - for _ in range(12): await _add_test_states(hass, wait_recording_done=False) await async_wait_recording_done(hass) with ( - patch.object(instance, "max_bind_vars", 72), - patch.object(instance.database_engine, "max_bind_vars", 72), + patch.object(recorder_mock, "max_bind_vars", 72), + patch.object(recorder_mock.database_engine, "max_bind_vars", 72), session_scope(hass=hass) as session, ): states = session.query(States) @@ -94,7 +95,7 @@ async def test_purge_big_database( purge_before = dt_util.utcnow() - timedelta(days=4) finished = purge_old_data( - instance, + recorder_mock, purge_before, states_batch_size=1, events_batch_size=1, @@ -105,12 +106,8 @@ async def test_purge_big_database( assert state_attributes.count() == 1 -async def test_purge_old_states( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant -) -> None: +async def test_purge_old_states(hass: HomeAssistant, recorder_mock: Recorder) -> None: """Test deleting old states.""" - instance = await async_setup_recorder_instance(hass) - await _add_test_states(hass) # 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") 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) # run purge_old_data() finished = purge_old_data( - instance, + recorder_mock, purge_before, states_batch_size=1, events_batch_size=1, @@ -141,7 +138,7 @@ async def test_purge_old_states( assert states.count() == 2 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)) # 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_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 states.count() == 2 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 purge_before = dt_util.utcnow() finished = purge_old_data( - instance, + recorder_mock, purge_before, states_batch_size=1, events_batch_size=1, @@ -173,7 +170,7 @@ async def test_purge_old_states( assert states.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 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") 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) assert state_attributes.count() == 3 @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_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, - recorder_db_url: str, ) -> None: """Test database image image is malformed while deleting old states. This test is specific for SQLite, wiping the database on error only happens with SQLite. """ - - await async_setup_recorder_instance(hass) - await _add_test_states(hass) await async_wait_recording_done(hass) @@ -223,7 +215,7 @@ async def test_purge_old_states_encouters_database_corruption( 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 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_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, + recorder_mock: Recorder, caplog: pytest.LogCaptureFixture, ) -> None: """Test retry on specific mysql operational errors.""" - instance = await async_setup_recorder_instance(hass) - await _add_test_states(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", 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 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 +@pytest.mark.usefixtures("recorder_mock") async def test_purge_old_states_encounters_operational_error( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, caplog: pytest.LogCaptureFixture, ) -> None: """Test error on operational errors that are not mysql does not retry.""" - await async_setup_recorder_instance(hass) - await _add_test_states(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", 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 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 -async def test_purge_old_events( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant -) -> None: +async def test_purge_old_events(hass: HomeAssistant, recorder_mock: Recorder) -> None: """Test deleting old events.""" - instance = await async_setup_recorder_instance(hass) - await _add_test_events(hass) with session_scope(hass=hass) as session: @@ -310,7 +294,7 @@ async def test_purge_old_events( # run purge_old_data() finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, events_batch_size=1, @@ -322,7 +306,7 @@ async def test_purge_old_events( # we should only have 2 events left finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, events_batch_size=1, @@ -333,11 +317,9 @@ async def test_purge_old_events( async def test_purge_old_recorder_runs( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test deleting old recorder runs keeps current run.""" - instance = await async_setup_recorder_instance(hass) - await _add_test_recorder_runs(hass) # make sure we start with 7 recorder runs @@ -349,7 +331,7 @@ async def test_purge_old_recorder_runs( # run purge_old_data() finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, events_batch_size=1, @@ -358,7 +340,7 @@ async def test_purge_old_recorder_runs( assert not finished finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, events_batch_size=1, @@ -369,11 +351,9 @@ async def test_purge_old_recorder_runs( async def test_purge_old_statistics_runs( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test deleting old statistics runs keeps the latest run.""" - instance = await async_setup_recorder_instance(hass) - await _add_test_statistics_runs(hass) # make sure we start with 7 statistics runs @@ -384,17 +364,17 @@ async def test_purge_old_statistics_runs( purge_before = dt_util.utcnow() # 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 - finished = purge_old_data(instance, purge_before, repack=False) + finished = purge_old_data(recorder_mock, purge_before, repack=False) assert finished assert statistics_runs.count() == 1 @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) +@pytest.mark.usefixtures("recorder_mock") async def test_purge_method( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, caplog: pytest.LogCaptureFixture, use_sqlite: bool, @@ -412,8 +392,6 @@ async def test_purge_method( assert run1.run_id == run2.run_id assert run1.start == run2.start - await async_setup_recorder_instance(hass) - service_data = {"keep_days": 4} await _add_test_events(hass) await _add_test_states(hass) @@ -519,8 +497,8 @@ async def test_purge_method( @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) async def test_purge_edge_case( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, + recorder_mock: Recorder, use_sqlite: bool, ) -> None: """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, ) ) - instance = recorder.get_instance(hass) - convert_pending_events_to_event_types(instance, session) - convert_pending_states_to_meta(instance, session) + convert_pending_events_to_event_types(recorder_mock, session) + convert_pending_states_to_meta(recorder_mock, session) - await async_setup_recorder_instance(hass, None) await async_wait_purge_done(hass) service_data = {"keep_days": 2} @@ -577,7 +553,7 @@ async def test_purge_edge_case( ) 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 async_recorder_block_till_done(hass) @@ -592,10 +568,7 @@ async def test_purge_edge_case( assert events.count() == 0 -async def test_purge_cutoff_date( - async_setup_recorder_instance: RecorderInstanceGenerator, - hass: HomeAssistant, -) -> None: +async def test_purge_cutoff_date(hass: HomeAssistant, recorder_mock: Recorder) -> None: """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: @@ -658,10 +631,9 @@ async def test_purge_cutoff_date( attributes_id=1000 + row, ) ) - convert_pending_events_to_event_types(instance, session) - convert_pending_states_to_meta(instance, session) + convert_pending_events_to_event_types(recorder_mock, session) + convert_pending_states_to_meta(recorder_mock, session) - instance = await async_setup_recorder_instance(hass, None) await async_wait_purge_done(hass) service_data = {"keep_days": 2} @@ -697,7 +669,7 @@ async def test_purge_cutoff_date( == 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 async_recorder_block_till_done(hass) await async_wait_purge_done(hass) @@ -738,7 +710,9 @@ async def test_purge_cutoff_date( ) # 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_wait_purge_done(hass) @@ -749,7 +723,9 @@ async def test_purge_cutoff_date( assert state_attributes.count() == 0 # 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_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( + "recorder_config", [{"exclude": {"entities": ["sensor.excluded"]}}] +) async def test_purge_filtered_states( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, + recorder_mock: Recorder, use_sqlite: bool, ) -> None: """Test filtered states are purged.""" - config: ConfigType = {"exclude": {"entities": ["sensor.excluded"]}} - instance = await async_setup_recorder_instance(hass, config) - assert instance.entity_filter("sensor.excluded") is False + assert recorder_mock.entity_filter("sensor.excluded") is False def _add_db_entries(hass: HomeAssistant) -> None: 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), ) ) - convert_pending_states_to_meta(instance, session) - convert_pending_events_to_event_types(instance, session) + convert_pending_states_to_meta(recorder_mock, session) + convert_pending_events_to_event_types(recorder_mock, session) service_data = {"keep_days": 10} _add_db_entries(hass) @@ -867,7 +844,7 @@ async def test_purge_filtered_states( assert events_keep.count() == 1 # 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 async_recorder_block_till_done(hass) @@ -883,7 +860,7 @@ async def test_purge_filtered_states( # Test with '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 async_recorder_block_till_done(hass) @@ -931,7 +908,7 @@ async def test_purge_filtered_states( assert session.query(StateAttributes).count() == 11 # 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_wait_purge_done(hass) @@ -943,7 +920,7 @@ async def test_purge_filtered_states( assert session.query(StateAttributes).count() == 11 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_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( + "recorder_config", [{"exclude": {"entities": ["sensor.excluded"]}}] +) async def test_purge_filtered_states_to_empty( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, + recorder_mock: Recorder, use_sqlite: bool, ) -> None: """Test filtered states are purged all the way to an empty db.""" - config: ConfigType = {"exclude": {"entities": ["sensor.excluded"]}} - instance = await async_setup_recorder_instance(hass, config) - assert instance.entity_filter("sensor.excluded") is False + assert recorder_mock.entity_filter("sensor.excluded") is False def _add_db_entries(hass: HomeAssistant) -> None: with session_scope(hass=hass) as session: @@ -979,7 +957,7 @@ async def test_purge_filtered_states_to_empty( timestamp, event_id * days, ) - convert_pending_states_to_meta(instance, session) + convert_pending_states_to_meta(recorder_mock, session) service_data = {"keep_days": 10} _add_db_entries(hass) @@ -992,7 +970,7 @@ async def test_purge_filtered_states_to_empty( # Test with '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_wait_purge_done(hass) @@ -1004,21 +982,22 @@ async def test_purge_filtered_states_to_empty( # Do it again to make sure nothing changes # 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_wait_purge_done(hass) @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_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, + recorder_mock: Recorder, use_sqlite: bool, ) -> None: """Test filtered legacy states without state attributes are purged all the way to an empty db.""" - config: ConfigType = {"exclude": {"entities": ["sensor.old_format"]}} - instance = await async_setup_recorder_instance(hass, config) - assert instance.entity_filter("sensor.old_format") is False + assert recorder_mock.entity_filter("sensor.old_format") is False def _add_db_entries(hass: HomeAssistant) -> None: 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), ) ) - convert_pending_states_to_meta(instance, session) - convert_pending_events_to_event_types(instance, session) + convert_pending_states_to_meta(recorder_mock, session) + convert_pending_events_to_event_types(recorder_mock, session) service_data = {"keep_days": 10} _add_db_entries(hass) @@ -1069,7 +1048,7 @@ async def test_purge_without_state_attributes_filtered_states_to_empty( # Test with '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_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 # 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_wait_purge_done(hass) +@pytest.mark.parametrize( + "recorder_config", [{"exclude": {"event_types": ["EVENT_PURGE"]}}] +) async def test_purge_filtered_events( - async_setup_recorder_instance: RecorderInstanceGenerator, - hass: HomeAssistant, + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """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) def _add_db_entries(hass: HomeAssistant) -> None: @@ -1121,11 +1100,11 @@ async def test_purge_filtered_events( timestamp, event_id, ) - convert_pending_events_to_event_types(instance, session) - convert_pending_states_to_meta(instance, session) + convert_pending_events_to_event_types(recorder_mock, session) + convert_pending_states_to_meta(recorder_mock, session) 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) with session_scope(hass=hass, read_only=True) as session: @@ -1137,7 +1116,7 @@ async def test_purge_filtered_events( assert states.count() == 10 # 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 async_recorder_block_till_done(hass) @@ -1153,7 +1132,7 @@ async def test_purge_filtered_events( # Test with '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 async_recorder_block_till_done(hass) @@ -1171,23 +1150,26 @@ async def test_purge_filtered_events( 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_setup_recorder_instance: RecorderInstanceGenerator, - hass: HomeAssistant, + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """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 instance.entity_filter("sensor.excluded") is False - assert instance.entity_filter("sensor.old_format") is False - assert instance.entity_filter("sensor.keep") is True - assert "excluded_event" in instance.exclude_event_types + assert recorder_mock.entity_filter("sensor.excluded") is False + assert recorder_mock.entity_filter("sensor.old_format") is False + assert recorder_mock.entity_filter("sensor.keep") is True + assert "excluded_event" in recorder_mock.exclude_event_types def _add_db_entries(hass: HomeAssistant) -> None: 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), ) ) - convert_pending_events_to_event_types(instance, session) - convert_pending_states_to_meta(instance, session) + convert_pending_events_to_event_types(recorder_mock, session) + convert_pending_states_to_meta(recorder_mock, session) service_data = {"keep_days": 10, "apply_filter": True} _add_db_entries(hass) @@ -1279,7 +1261,7 @@ async def test_purge_filtered_events_state_changed( assert events_purge.count() == 1 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() for _ in range(4): @@ -1313,11 +1295,8 @@ async def test_purge_filtered_events_state_changed( ) # should have been kept -async def test_purge_entities( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant -) -> None: +async def test_purge_entities(hass: HomeAssistant, recorder_mock: Recorder) -> None: """Test purging of specific entities.""" - instance = await async_setup_recorder_instance(hass) async def _purge_entities(hass, entity_ids, domains, entity_globs): service_data = { @@ -1327,7 +1306,7 @@ async def test_purge_entities( } 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() @@ -1365,8 +1344,8 @@ async def test_purge_entities( timestamp, event_id * days, ) - convert_pending_states_to_meta(instance, session) - convert_pending_events_to_event_types(instance, session) + convert_pending_states_to_meta(recorder_mock, session) + convert_pending_events_to_event_types(recorder_mock, session) def _add_keep_records(hass: HomeAssistant) -> None: with session_scope(hass=hass) as session: @@ -1380,8 +1359,8 @@ async def test_purge_entities( timestamp, event_id, ) - convert_pending_states_to_meta(instance, session) - convert_pending_events_to_event_types(instance, session) + convert_pending_states_to_meta(recorder_mock, session) + convert_pending_events_to_event_types(recorder_mock, session) _add_purge_records(hass) _add_keep_records(hass) @@ -1659,15 +1638,14 @@ def _add_state_with_state_attributes( @pytest.mark.timeout(30) async def test_purge_many_old_events( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test deleting old events.""" old_events_count = 5 - instance = await async_setup_recorder_instance(hass) with ( - patch.object(instance, "max_bind_vars", old_events_count), - patch.object(instance.database_engine, "max_bind_vars", old_events_count), + patch.object(recorder_mock, "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) @@ -1681,7 +1659,7 @@ async def test_purge_many_old_events( # run purge_old_data() finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, states_batch_size=3, @@ -1692,7 +1670,7 @@ async def test_purge_many_old_events( # we should only have 2 groups of events left finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, states_batch_size=3, @@ -1703,7 +1681,7 @@ async def test_purge_many_old_events( # we should now purge everything finished = purge_old_data( - instance, + recorder_mock, dt_util.utcnow(), repack=False, 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_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test deleting old events purges event type ids.""" - instance = await async_setup_recorder_instance(hass) - assert instance.event_type_manager.active is True + assert recorder_mock.event_type_manager.active is True utcnow = dt_util.utcnow() 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), ) ) - return instance.event_type_manager.get_many( + return recorder_mock.event_type_manager.get_many( [ "EVENT_TEST_AUTOPURGE", "EVENT_TEST_PURGE", @@ -1772,7 +1749,7 @@ async def test_purge_old_events_purges_the_event_type_ids( 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() with session_scope(hass=hass) as session: events = session.query(Events).where( @@ -1787,7 +1764,7 @@ async def test_purge_old_events_purges_the_event_type_ids( # run purge_old_data() finished = purge_old_data( - instance, + recorder_mock, far_past, repack=False, ) @@ -1796,12 +1773,12 @@ async def test_purge_old_events_purges_the_event_type_ids( # We should remove the unused event type 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 # only one event type was recorded now finished = purge_old_data( - instance, + recorder_mock, utcnow, repack=False, ) @@ -1811,7 +1788,7 @@ async def test_purge_old_events_purges_the_event_type_ids( # Purge everything finished = purge_old_data( - instance, + recorder_mock, utcnow + timedelta(seconds=1), 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_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test deleting old states purges state metadata_ids.""" - instance = await async_setup_recorder_instance(hass) - assert instance.states_meta_manager.active is True + assert recorder_mock.states_meta_manager.active is True utcnow = dt_util.utcnow() 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), ) ) - return instance.states_meta_manager.get_many( + return recorder_mock.states_meta_manager.get_many( ["sensor.one", "sensor.two", "sensor.three", "sensor.unused"], session, 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() with session_scope(hass=hass) as session: 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() finished = purge_old_data( - instance, + recorder_mock, far_past, repack=False, ) @@ -1897,12 +1875,12 @@ async def test_purge_old_states_purges_the_state_metadata_ids( # We should remove the unused entity_id 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 # only one event type was recorded now finished = purge_old_data( - instance, + recorder_mock, utcnow, repack=False, ) @@ -1912,7 +1890,7 @@ async def test_purge_old_states_purges_the_state_metadata_ids( # Purge everything finished = purge_old_data( - instance, + recorder_mock, utcnow + timedelta(seconds=1), 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_setup_recorder_instance: RecorderInstanceGenerator, - hass: HomeAssistant, + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test purging states with an entity filter and keep_days.""" - instance = await async_setup_recorder_instance(hass, {}) await hass.async_block_till_done() await async_wait_recording_done(hass) start = dt_util.utcnow() @@ -1948,7 +1924,7 @@ async def test_purge_entities_keep_days( hass.states.async_set("sensor.keep", "now") 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, hass, one_month_ago, @@ -1959,7 +1935,7 @@ async def test_purge_entities_keep_days( assert len(states["sensor.purge"]) == 3 await hass.services.async_call( - recorder.DOMAIN, + RECORDER_DOMAIN, SERVICE_PURGE_ENTITIES, { "entity_id": "sensor.purge", @@ -1969,7 +1945,7 @@ async def test_purge_entities_keep_days( await async_recorder_block_till_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, hass, one_month_ago, @@ -1980,7 +1956,7 @@ async def test_purge_entities_keep_days( assert len(states["sensor.purge"]) == 1 await hass.services.async_call( - recorder.DOMAIN, + RECORDER_DOMAIN, SERVICE_PURGE_ENTITIES, { "entity_id": "sensor.purge", @@ -1989,7 +1965,7 @@ async def test_purge_entities_keep_days( await async_recorder_block_till_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, hass, one_month_ago, diff --git a/tests/components/recorder/test_purge_v32_schema.py b/tests/components/recorder/test_purge_v32_schema.py index a3b91ce54a9..51424c31ea2 100644 --- a/tests/components/recorder/test_purge_v32_schema.py +++ b/tests/components/recorder/test_purge_v32_schema.py @@ -12,8 +12,11 @@ from sqlalchemy import text, update from sqlalchemy.exc import DatabaseError, OperationalError from sqlalchemy.orm.session import Session -from homeassistant.components import recorder -from homeassistant.components.recorder import migration +from homeassistant.components.recorder import ( + DOMAIN as RECORDER_DOMAIN, + Recorder, + migration, +) from homeassistant.components.recorder.const import SupportedDialect from homeassistant.components.recorder.history import get_significant_states from homeassistant.components.recorder.purge import purge_old_data @@ -47,6 +50,13 @@ from .db_schema_32 import ( 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) def db_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 -async def test_purge_old_states( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant -) -> None: +async def test_purge_old_states(hass: HomeAssistant, recorder_mock: Recorder) -> None: """Test deleting old states.""" - instance = await async_setup_recorder_instance(hass) await async_attach_db_engine(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") 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) # run purge_old_data() finished = purge_old_data( - instance, + recorder_mock, purge_before, states_batch_size=1, events_batch_size=1, @@ -103,7 +110,7 @@ async def test_purge_old_states( assert states.count() == 2 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)) # 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_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 states.count() == 2 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 purge_before = dt_util.utcnow() finished = purge_old_data( - instance, + recorder_mock, purge_before, states_batch_size=1, events_batch_size=1, @@ -135,7 +142,7 @@ async def test_purge_old_states( assert states.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 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") 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) assert state_attributes.count() == 3 @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_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, - recorder_db_url: str, ) -> None: """Test database image image is malformed while deleting old states. This test is specific for SQLite, wiping the database on error only happens with SQLite. """ - - await async_setup_recorder_instance(hass) await async_attach_db_engine(hass) await _add_test_states(hass) @@ -186,7 +189,7 @@ async def test_purge_old_states_encouters_database_corruption( 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 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_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, + recorder_mock: Recorder, caplog: pytest.LogCaptureFixture, ) -> None: """Test retry on specific mysql operational errors.""" - instance = await async_setup_recorder_instance(hass) await async_attach_db_engine(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", 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 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 +@pytest.mark.usefixtures("recorder_mock") async def test_purge_old_states_encounters_operational_error( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, caplog: pytest.LogCaptureFixture, ) -> None: """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 _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", 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 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 -async def test_purge_old_events( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant -) -> None: +async def test_purge_old_events(hass: HomeAssistant, recorder_mock: Recorder) -> None: """Test deleting old events.""" - instance = await async_setup_recorder_instance(hass) await async_attach_db_engine(hass) await _add_test_events(hass) @@ -274,7 +272,7 @@ async def test_purge_old_events( # run purge_old_data() finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, events_batch_size=1, @@ -285,7 +283,7 @@ async def test_purge_old_events( # we should only have 2 events left finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, events_batch_size=1, @@ -296,10 +294,9 @@ async def test_purge_old_events( async def test_purge_old_recorder_runs( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test deleting old recorder runs keeps current run.""" - instance = await async_setup_recorder_instance(hass) await async_attach_db_engine(hass) await _add_test_recorder_runs(hass) @@ -313,7 +310,7 @@ async def test_purge_old_recorder_runs( # run purge_old_data() finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, events_batch_size=1, @@ -322,7 +319,7 @@ async def test_purge_old_recorder_runs( assert not finished finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, events_batch_size=1, @@ -333,10 +330,9 @@ async def test_purge_old_recorder_runs( async def test_purge_old_statistics_runs( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test deleting old statistics runs keeps the latest run.""" - instance = await async_setup_recorder_instance(hass) await async_attach_db_engine(hass) await _add_test_statistics_runs(hass) @@ -349,17 +345,17 @@ async def test_purge_old_statistics_runs( purge_before = dt_util.utcnow() # 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 - finished = purge_old_data(instance, purge_before, repack=False) + finished = purge_old_data(recorder_mock, purge_before, repack=False) assert finished assert statistics_runs.count() == 1 @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) +@pytest.mark.usefixtures("recorder_mock") async def test_purge_method( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, caplog: pytest.LogCaptureFixture, use_sqlite: bool, @@ -377,7 +373,6 @@ async def test_purge_method( assert run1.run_id == run2.run_id assert run1.start == run2.start - await async_setup_recorder_instance(hass) await async_attach_db_engine(hass) service_data = {"keep_days": 4} @@ -478,11 +473,8 @@ async def test_purge_method( @pytest.mark.parametrize("use_sqlite", [True, False], indirect=True) -async def test_purge_edge_case( - async_setup_recorder_instance: RecorderInstanceGenerator, - hass: HomeAssistant, - use_sqlite: bool, -) -> None: +@pytest.mark.usefixtures("recorder_mock") +async def test_purge_edge_case(hass: HomeAssistant, use_sqlite: bool) -> None: """Test states and events are purged even if they occurred shortly before purge_before.""" 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_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") 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 async_recorder_block_till_done(hass) @@ -547,10 +538,7 @@ async def test_purge_edge_case( assert events.count() == 0 -async def test_purge_cutoff_date( - async_setup_recorder_instance: RecorderInstanceGenerator, - hass: HomeAssistant, -) -> None: +async def test_purge_cutoff_date(hass: HomeAssistant, recorder_mock: Recorder) -> None: """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: @@ -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_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 == "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 async_recorder_block_till_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 # 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_wait_purge_done(hass) @@ -685,7 +674,9 @@ async def test_purge_cutoff_date( assert state_attributes.count() == 0 # 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_wait_purge_done(hass) @@ -938,16 +929,15 @@ def _add_state_and_state_changed_event( async def test_purge_many_old_events( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test deleting old events.""" - instance = await async_setup_recorder_instance(hass) await async_attach_db_engine(hass) old_events_count = 5 with ( - patch.object(instance, "max_bind_vars", old_events_count), - patch.object(instance.database_engine, "max_bind_vars", old_events_count), + patch.object(recorder_mock, "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) @@ -959,7 +949,7 @@ async def test_purge_many_old_events( # run purge_old_data() finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, states_batch_size=3, @@ -970,7 +960,7 @@ async def test_purge_many_old_events( # we should only have 2 groups of events left finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, states_batch_size=3, @@ -981,7 +971,7 @@ async def test_purge_many_old_events( # we should now purge everything finished = purge_old_data( - instance, + recorder_mock, dt_util.utcnow(), repack=False, 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_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test purging with legacy and new events.""" - instance = await async_setup_recorder_instance(hass) await async_attach_db_engine(hass) await async_wait_recording_done(hass) # 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(): """Recreate the legacy events index since its no longer created on new instances.""" - migration._create_index(instance.get_session, "states", "ix_states_event_id") - instance.use_legacy_events_index = True + migration._create_index( + 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) - assert instance.use_legacy_events_index is True + await recorder_mock.async_add_executor_job(_recreate_legacy_events_index) + assert recorder_mock.use_legacy_events_index is True utcnow = dt_util.utcnow() 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) finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, ) @@ -1060,7 +1051,7 @@ async def test_purge_can_mix_legacy_and_new_format( # and we switch methods purge_before = dt_util.utcnow() - timedelta(days=4) finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, 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_without_event_id.count() == 1 finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, 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_without_event_id.count() == 2 finished = purge_old_data( - instance, + recorder_mock, purge_before, 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.usefixtures("skip_by_db_engine") async def test_purge_can_mix_legacy_and_new_format_with_detached_state( - async_setup_recorder_instance: RecorderInstanceGenerator, hass: HomeAssistant, + recorder_mock: Recorder, recorder_db_url: str, ) -> None: """Test purging with legacy and new events with a detached state. This tests disables foreign key checks on SQLite. """ - - instance = await async_setup_recorder_instance(hass) await async_attach_db_engine(hass) await async_wait_recording_done(hass) # 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(): """Recreate the legacy events index since its no longer created on new instances.""" - migration._create_index(instance.get_session, "states", "ix_states_event_id") - instance.use_legacy_events_index = True + migration._create_index( + 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) - assert instance.use_legacy_events_index is True + await recorder_mock.async_add_executor_job(_recreate_legacy_events_index) + assert recorder_mock.use_legacy_events_index is True with session_scope(hass=hass) as session: 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) finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, ) @@ -1207,7 +1198,7 @@ async def test_purge_can_mix_legacy_and_new_format_with_detached_state( # and we switch methods purge_before = dt_util.utcnow() - timedelta(days=4) finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, 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_without_event_id.count() == 1 finished = purge_old_data( - instance, + recorder_mock, purge_before, repack=False, 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_without_event_id.count() == 2 finished = purge_old_data( - instance, + recorder_mock, purge_before, 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_setup_recorder_instance: RecorderInstanceGenerator, - hass: HomeAssistant, + hass: HomeAssistant, recorder_mock: Recorder ) -> None: """Test purging states with an entity filter and keep_days.""" - instance = await async_setup_recorder_instance(hass, {}) await async_attach_db_engine(hass) await hass.async_block_till_done() @@ -1275,7 +1264,7 @@ async def test_purge_entities_keep_days( hass.states.async_set("sensor.keep", "now") 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, hass, one_month_ago, @@ -1286,7 +1275,7 @@ async def test_purge_entities_keep_days( assert len(states["sensor.purge"]) == 3 await hass.services.async_call( - recorder.DOMAIN, + RECORDER_DOMAIN, SERVICE_PURGE_ENTITIES, { "entity_id": "sensor.purge", @@ -1296,7 +1285,7 @@ async def test_purge_entities_keep_days( await async_recorder_block_till_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, hass, one_month_ago, @@ -1307,7 +1296,7 @@ async def test_purge_entities_keep_days( assert len(states["sensor.purge"]) == 1 await hass.services.async_call( - recorder.DOMAIN, + RECORDER_DOMAIN, SERVICE_PURGE_ENTITIES, { "entity_id": "sensor.purge", @@ -1316,7 +1305,7 @@ async def test_purge_entities_keep_days( await async_recorder_block_till_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, hass, one_month_ago,