"""Common test utils for working with recorder.""" from datetime import timedelta from sqlalchemy import create_engine from homeassistant import core as ha from homeassistant.components import recorder from homeassistant.core import HomeAssistant from homeassistant.util import dt as dt_util from tests.common import async_fire_time_changed, fire_time_changed from tests.components.recorder import models_schema_0 DEFAULT_PURGE_TASKS = 3 def wait_recording_done(hass: HomeAssistant) -> None: """Block till recording is done.""" hass.block_till_done() trigger_db_commit(hass) hass.block_till_done() hass.data[recorder.DATA_INSTANCE].block_till_done() hass.block_till_done() async def async_wait_recording_done_without_instance(hass: HomeAssistant) -> None: """Block till recording is done.""" await hass.loop.run_in_executor(None, wait_recording_done, hass) def trigger_db_commit(hass: HomeAssistant) -> None: """Force the recorder to commit.""" for _ in range(recorder.DEFAULT_COMMIT_INTERVAL): # We only commit on time change fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=1)) async def async_wait_recording_done( hass: HomeAssistant, instance: recorder.Recorder, ) -> None: """Async wait until recording is done.""" await hass.async_block_till_done() async_trigger_db_commit(hass) await hass.async_block_till_done() await async_recorder_block_till_done(hass, instance) await hass.async_block_till_done() async def async_wait_purge_done( hass: HomeAssistant, instance: recorder.Recorder, max: int = None ) -> None: """Wait for max number of purge events. Because a purge may insert another PurgeTask into the queue after the WaitTask finishes, we need up to a maximum number of WaitTasks that we will put into the queue. """ if not max: max = DEFAULT_PURGE_TASKS for _ in range(max + 1): await async_wait_recording_done(hass, instance) @ha.callback def async_trigger_db_commit(hass: HomeAssistant) -> None: """Fore the recorder to commit. Async friendly.""" for _ in range(recorder.DEFAULT_COMMIT_INTERVAL): async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=1)) async def async_recorder_block_till_done( hass: HomeAssistant, instance: recorder.Recorder, ) -> None: """Non blocking version of recorder.block_till_done().""" await hass.async_add_executor_job(instance.block_till_done) def corrupt_db_file(test_db_file): """Corrupt an sqlite3 database file.""" with open(test_db_file, "w+") as fhandle: fhandle.seek(200) fhandle.write("I am a corrupt db" * 100) def create_engine_test(*args, **kwargs): """Test version of create_engine that initializes with old schema. This simulates an existing db with the old schema. """ engine = create_engine(*args, **kwargs) models_schema_0.Base.metadata.create_all(engine) return engine