Support non-live database migration (#72433)
* Support non-live database migration * Tweak startup order, add test * Address review comments * Fix typo * Clarify comment about promoting dependencies * Tweak * Fix merge mistake * Fix some tests * Fix additional test * Fix additional test * Adjust tests * Improve test coverage
This commit is contained in:
parent
9d0a252ca7
commit
fd6ffef52f
20 changed files with 993 additions and 61 deletions
|
@ -27,6 +27,7 @@ from homeassistant.components.recorder.db_schema import (
|
|||
States,
|
||||
)
|
||||
from homeassistant.components.recorder.util import session_scope
|
||||
from homeassistant.helpers import recorder as recorder_helper
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .common import async_wait_recording_done, create_engine_test
|
||||
|
@ -53,6 +54,7 @@ async def test_schema_update_calls(hass):
|
|||
"homeassistant.components.recorder.migration._apply_update",
|
||||
wraps=migration._apply_update,
|
||||
) as update:
|
||||
recorder_helper.async_initialize_recorder(hass)
|
||||
await async_setup_component(
|
||||
hass, "recorder", {"recorder": {"db_url": "sqlite://"}}
|
||||
)
|
||||
|
@ -74,10 +76,11 @@ async def test_migration_in_progress(hass):
|
|||
"""Test that we can check for migration in progress."""
|
||||
assert recorder.util.async_migration_in_progress(hass) is False
|
||||
|
||||
with patch("homeassistant.components.recorder.ALLOW_IN_MEMORY_DB", True,), patch(
|
||||
with patch("homeassistant.components.recorder.ALLOW_IN_MEMORY_DB", True), patch(
|
||||
"homeassistant.components.recorder.core.create_engine",
|
||||
new=create_engine_test,
|
||||
):
|
||||
recorder_helper.async_initialize_recorder(hass)
|
||||
await async_setup_component(
|
||||
hass, "recorder", {"recorder": {"db_url": "sqlite://"}}
|
||||
)
|
||||
|
@ -105,6 +108,7 @@ async def test_database_migration_failed(hass):
|
|||
"homeassistant.components.persistent_notification.dismiss",
|
||||
side_effect=pn.dismiss,
|
||||
) as mock_dismiss:
|
||||
recorder_helper.async_initialize_recorder(hass)
|
||||
await async_setup_component(
|
||||
hass, "recorder", {"recorder": {"db_url": "sqlite://"}}
|
||||
)
|
||||
|
@ -136,6 +140,7 @@ async def test_database_migration_encounters_corruption(hass):
|
|||
), patch(
|
||||
"homeassistant.components.recorder.core.move_away_broken_database"
|
||||
) as move_away:
|
||||
recorder_helper.async_initialize_recorder(hass)
|
||||
await async_setup_component(
|
||||
hass, "recorder", {"recorder": {"db_url": "sqlite://"}}
|
||||
)
|
||||
|
@ -165,6 +170,7 @@ async def test_database_migration_encounters_corruption_not_sqlite(hass):
|
|||
"homeassistant.components.persistent_notification.dismiss",
|
||||
side_effect=pn.dismiss,
|
||||
) as mock_dismiss:
|
||||
recorder_helper.async_initialize_recorder(hass)
|
||||
await async_setup_component(
|
||||
hass, "recorder", {"recorder": {"db_url": "sqlite://"}}
|
||||
)
|
||||
|
@ -189,6 +195,7 @@ async def test_events_during_migration_are_queued(hass):
|
|||
"homeassistant.components.recorder.core.create_engine",
|
||||
new=create_engine_test,
|
||||
):
|
||||
recorder_helper.async_initialize_recorder(hass)
|
||||
await async_setup_component(
|
||||
hass,
|
||||
"recorder",
|
||||
|
@ -219,6 +226,7 @@ async def test_events_during_migration_queue_exhausted(hass):
|
|||
"homeassistant.components.recorder.core.create_engine",
|
||||
new=create_engine_test,
|
||||
), patch.object(recorder.core, "MAX_QUEUE_BACKLOG", 1):
|
||||
recorder_helper.async_initialize_recorder(hass)
|
||||
await async_setup_component(
|
||||
hass,
|
||||
"recorder",
|
||||
|
@ -247,8 +255,11 @@ async def test_events_during_migration_queue_exhausted(hass):
|
|||
assert len(db_states) == 2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("start_version", [0, 16, 18, 22])
|
||||
async def test_schema_migrate(hass, start_version):
|
||||
@pytest.mark.parametrize(
|
||||
"start_version,live",
|
||||
[(0, True), (16, True), (18, True), (22, True), (25, True)],
|
||||
)
|
||||
async def test_schema_migrate(hass, start_version, live):
|
||||
"""Test the full schema migration logic.
|
||||
|
||||
We're just testing that the logic can execute successfully here without
|
||||
|
@ -259,7 +270,8 @@ async def test_schema_migrate(hass, start_version):
|
|||
migration_done = threading.Event()
|
||||
migration_stall = threading.Event()
|
||||
migration_version = None
|
||||
real_migration = recorder.migration.migrate_schema
|
||||
real_migrate_schema = recorder.migration.migrate_schema
|
||||
real_apply_update = recorder.migration._apply_update
|
||||
|
||||
def _create_engine_test(*args, **kwargs):
|
||||
"""Test version of create_engine that initializes with old schema.
|
||||
|
@ -284,14 +296,12 @@ async def test_schema_migrate(hass, start_version):
|
|||
start=self.run_history.recording_start, created=dt_util.utcnow()
|
||||
)
|
||||
|
||||
def _instrument_migration(*args):
|
||||
def _instrument_migrate_schema(*args):
|
||||
"""Control migration progress and check results."""
|
||||
nonlocal migration_done
|
||||
nonlocal migration_version
|
||||
nonlocal migration_stall
|
||||
migration_stall.wait()
|
||||
try:
|
||||
real_migration(*args)
|
||||
real_migrate_schema(*args)
|
||||
except Exception:
|
||||
migration_done.set()
|
||||
raise
|
||||
|
@ -307,6 +317,12 @@ async def test_schema_migrate(hass, start_version):
|
|||
migration_version = res.schema_version
|
||||
migration_done.set()
|
||||
|
||||
def _instrument_apply_update(*args):
|
||||
"""Control migration progress."""
|
||||
nonlocal migration_stall
|
||||
migration_stall.wait()
|
||||
real_apply_update(*args)
|
||||
|
||||
with patch("homeassistant.components.recorder.ALLOW_IN_MEMORY_DB", True), patch(
|
||||
"homeassistant.components.recorder.core.create_engine",
|
||||
new=_create_engine_test,
|
||||
|
@ -316,12 +332,21 @@ async def test_schema_migrate(hass, start_version):
|
|||
autospec=True,
|
||||
) as setup_run, patch(
|
||||
"homeassistant.components.recorder.migration.migrate_schema",
|
||||
wraps=_instrument_migration,
|
||||
wraps=_instrument_migrate_schema,
|
||||
), patch(
|
||||
"homeassistant.components.recorder.migration._apply_update",
|
||||
wraps=_instrument_apply_update,
|
||||
):
|
||||
await async_setup_component(
|
||||
hass, "recorder", {"recorder": {"db_url": "sqlite://"}}
|
||||
recorder_helper.async_initialize_recorder(hass)
|
||||
hass.async_create_task(
|
||||
async_setup_component(
|
||||
hass, "recorder", {"recorder": {"db_url": "sqlite://"}}
|
||||
)
|
||||
)
|
||||
await recorder_helper.async_wait_recorder(hass)
|
||||
|
||||
assert recorder.util.async_migration_in_progress(hass) is True
|
||||
assert recorder.util.async_migration_is_live(hass) == live
|
||||
migration_stall.set()
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_add_executor_job(migration_done.wait)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue