mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Remove support for live schema migration of old recorder databases (#122399)
* Remove support for live schema migration of old recorder databases * Update test
This commit is contained in:
parent
9514a38320
commit
ea75c8864f
@ -119,7 +119,10 @@ from .util import (
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from . import Recorder
|
from . import Recorder
|
||||||
|
|
||||||
LIVE_MIGRATION_MIN_SCHEMA_VERSION = 0
|
# Live schema migration supported starting from schema version 42 or newer
|
||||||
|
# Schema version 41 was introduced in HA Core 2023.4
|
||||||
|
# Schema version 42 was introduced in HA Core 2023.11
|
||||||
|
LIVE_MIGRATION_MIN_SCHEMA_VERSION = 42
|
||||||
|
|
||||||
MIGRATION_NOTE_OFFLINE = (
|
MIGRATION_NOTE_OFFLINE = (
|
||||||
"Note: this may take several hours on large databases and slow machines. "
|
"Note: this may take several hours on large databases and slow machines. "
|
||||||
|
@ -87,10 +87,23 @@ async def test_schema_update_calls(
|
|||||||
call(instance, hass, engine, session_maker, version + 1, 0)
|
call(instance, hass, engine, session_maker, version + 1, 0)
|
||||||
for version in range(db_schema.SCHEMA_VERSION)
|
for version in range(db_schema.SCHEMA_VERSION)
|
||||||
]
|
]
|
||||||
status = migration.SchemaValidationStatus(0, True, set(), 0)
|
|
||||||
assert migrate_schema.mock_calls == [
|
assert migrate_schema.mock_calls == [
|
||||||
call(instance, hass, engine, session_maker, status, 0),
|
call(
|
||||||
call(instance, hass, engine, session_maker, status, db_schema.SCHEMA_VERSION),
|
instance,
|
||||||
|
hass,
|
||||||
|
engine,
|
||||||
|
session_maker,
|
||||||
|
migration.SchemaValidationStatus(0, True, set(), 0),
|
||||||
|
42,
|
||||||
|
),
|
||||||
|
call(
|
||||||
|
instance,
|
||||||
|
hass,
|
||||||
|
engine,
|
||||||
|
session_maker,
|
||||||
|
migration.SchemaValidationStatus(42, True, set(), 0),
|
||||||
|
db_schema.SCHEMA_VERSION,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -117,7 +130,9 @@ async def test_migration_in_progress(
|
|||||||
new=create_engine_test,
|
new=create_engine_test,
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
await async_setup_recorder_instance(hass, wait_recorder=False)
|
await async_setup_recorder_instance(
|
||||||
|
hass, wait_recorder=False, wait_recorder_setup=False
|
||||||
|
)
|
||||||
await hass.async_add_executor_job(instrument_migration.migration_started.wait)
|
await hass.async_add_executor_job(instrument_migration.migration_started.wait)
|
||||||
assert recorder.util.async_migration_in_progress(hass) is True
|
assert recorder.util.async_migration_in_progress(hass) is True
|
||||||
|
|
||||||
@ -129,8 +144,25 @@ async def test_migration_in_progress(
|
|||||||
assert recorder.get_instance(hass).schema_version == SCHEMA_VERSION
|
assert recorder.get_instance(hass).schema_version == SCHEMA_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
(
|
||||||
|
"func_to_patch",
|
||||||
|
"expected_setup_result",
|
||||||
|
"expected_pn_create",
|
||||||
|
"expected_pn_dismiss",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
("migrate_schema_non_live", False, 1, 0),
|
||||||
|
("migrate_schema_live", True, 2, 1),
|
||||||
|
],
|
||||||
|
)
|
||||||
async def test_database_migration_failed(
|
async def test_database_migration_failed(
|
||||||
hass: HomeAssistant, async_setup_recorder_instance: RecorderInstanceGenerator
|
hass: HomeAssistant,
|
||||||
|
async_setup_recorder_instance: RecorderInstanceGenerator,
|
||||||
|
func_to_patch: str,
|
||||||
|
expected_setup_result: bool,
|
||||||
|
expected_pn_create: int,
|
||||||
|
expected_pn_dismiss: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test we notify if the migration fails."""
|
"""Test we notify if the migration fails."""
|
||||||
assert recorder.util.async_migration_in_progress(hass) is False
|
assert recorder.util.async_migration_in_progress(hass) is False
|
||||||
@ -141,7 +173,7 @@ async def test_database_migration_failed(
|
|||||||
new=create_engine_test,
|
new=create_engine_test,
|
||||||
),
|
),
|
||||||
patch(
|
patch(
|
||||||
"homeassistant.components.recorder.migration._apply_update",
|
f"homeassistant.components.recorder.migration.{func_to_patch}",
|
||||||
side_effect=ValueError,
|
side_effect=ValueError,
|
||||||
),
|
),
|
||||||
patch(
|
patch(
|
||||||
@ -153,7 +185,9 @@ async def test_database_migration_failed(
|
|||||||
side_effect=pn.dismiss,
|
side_effect=pn.dismiss,
|
||||||
) as mock_dismiss,
|
) as mock_dismiss,
|
||||||
):
|
):
|
||||||
await async_setup_recorder_instance(hass, wait_recorder=False)
|
await async_setup_recorder_instance(
|
||||||
|
hass, wait_recorder=False, expected_setup_result=expected_setup_result
|
||||||
|
)
|
||||||
hass.states.async_set("my.entity", "on", {})
|
hass.states.async_set("my.entity", "on", {})
|
||||||
hass.states.async_set("my.entity", "off", {})
|
hass.states.async_set("my.entity", "off", {})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -161,8 +195,8 @@ async def test_database_migration_failed(
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert recorder.util.async_migration_in_progress(hass) is False
|
assert recorder.util.async_migration_in_progress(hass) is False
|
||||||
assert len(mock_create.mock_calls) == 2
|
assert len(mock_create.mock_calls) == expected_pn_create
|
||||||
assert len(mock_dismiss.mock_calls) == 1
|
assert len(mock_dismiss.mock_calls) == expected_pn_dismiss
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skip_on_db_engine(["mysql", "postgresql"])
|
@pytest.mark.skip_on_db_engine(["mysql", "postgresql"])
|
||||||
@ -346,7 +380,7 @@ async def test_events_during_migration_are_queued(
|
|||||||
),
|
),
|
||||||
):
|
):
|
||||||
await async_setup_recorder_instance(
|
await async_setup_recorder_instance(
|
||||||
hass, {"commit_interval": 0}, wait_recorder=False
|
hass, {"commit_interval": 0}, wait_recorder=False, wait_recorder_setup=False
|
||||||
)
|
)
|
||||||
await hass.async_add_executor_job(instrument_migration.migration_started.wait)
|
await hass.async_add_executor_job(instrument_migration.migration_started.wait)
|
||||||
assert recorder.util.async_migration_in_progress(hass) is True
|
assert recorder.util.async_migration_in_progress(hass) is True
|
||||||
@ -389,7 +423,7 @@ async def test_events_during_migration_queue_exhausted(
|
|||||||
),
|
),
|
||||||
):
|
):
|
||||||
await async_setup_recorder_instance(
|
await async_setup_recorder_instance(
|
||||||
hass, {"commit_interval": 0}, wait_recorder=False
|
hass, {"commit_interval": 0}, wait_recorder=False, wait_recorder_setup=False
|
||||||
)
|
)
|
||||||
await hass.async_add_executor_job(instrument_migration.migration_started.wait)
|
await hass.async_add_executor_job(instrument_migration.migration_started.wait)
|
||||||
assert recorder.util.async_migration_in_progress(hass) is True
|
assert recorder.util.async_migration_in_progress(hass) is True
|
||||||
@ -421,7 +455,15 @@ async def test_events_during_migration_queue_exhausted(
|
|||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("start_version", "live"),
|
("start_version", "live"),
|
||||||
[(0, True), (9, True), (16, True), (18, True), (22, True), (25, True), (43, True)],
|
[
|
||||||
|
(0, False),
|
||||||
|
(9, False),
|
||||||
|
(16, False),
|
||||||
|
(18, False),
|
||||||
|
(22, False),
|
||||||
|
(25, False),
|
||||||
|
(43, True),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
async def test_schema_migrate(
|
async def test_schema_migrate(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -500,7 +542,9 @@ async def test_schema_migrate(
|
|||||||
"homeassistant.components.recorder.Recorder._pre_process_startup_events",
|
"homeassistant.components.recorder.Recorder._pre_process_startup_events",
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
await async_setup_recorder_instance(hass, wait_recorder=False)
|
await async_setup_recorder_instance(
|
||||||
|
hass, wait_recorder=False, wait_recorder_setup=live
|
||||||
|
)
|
||||||
await hass.async_add_executor_job(instrument_migration.migration_started.wait)
|
await hass.async_add_executor_job(instrument_migration.migration_started.wait)
|
||||||
assert recorder.util.async_migration_in_progress(hass) is True
|
assert recorder.util.async_migration_in_progress(hass) is True
|
||||||
await recorder_helper.async_wait_recorder(hass)
|
await recorder_helper.async_wait_recorder(hass)
|
||||||
|
@ -2555,7 +2555,9 @@ async def test_recorder_info_migration_queue_exhausted(
|
|||||||
recorder.core, "MIN_AVAILABLE_MEMORY_FOR_QUEUE_BACKLOG", sys.maxsize
|
recorder.core, "MIN_AVAILABLE_MEMORY_FOR_QUEUE_BACKLOG", sys.maxsize
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
async with async_test_recorder(hass, wait_recorder=False):
|
async with async_test_recorder(
|
||||||
|
hass, wait_recorder=False, wait_recorder_setup=False
|
||||||
|
):
|
||||||
await hass.async_add_executor_job(
|
await hass.async_add_executor_job(
|
||||||
instrument_migration.migration_started.wait
|
instrument_migration.migration_started.wait
|
||||||
)
|
)
|
||||||
|
@ -1399,6 +1399,7 @@ async def _async_init_recorder_component(
|
|||||||
db_url: str | None = None,
|
db_url: str | None = None,
|
||||||
*,
|
*,
|
||||||
expected_setup_result: bool,
|
expected_setup_result: bool,
|
||||||
|
wait_setup: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the recorder asynchronously."""
|
"""Initialize the recorder asynchronously."""
|
||||||
# pylint: disable-next=import-outside-toplevel
|
# pylint: disable-next=import-outside-toplevel
|
||||||
@ -1416,10 +1417,14 @@ async def _async_init_recorder_component(
|
|||||||
setup_task = asyncio.ensure_future(
|
setup_task = asyncio.ensure_future(
|
||||||
async_setup_component(hass, recorder.DOMAIN, {recorder.DOMAIN: config})
|
async_setup_component(hass, recorder.DOMAIN, {recorder.DOMAIN: config})
|
||||||
)
|
)
|
||||||
# Wait for recorder integration to setup
|
if wait_setup:
|
||||||
setup_result = await setup_task
|
# Wait for recorder integration to setup
|
||||||
assert setup_result == expected_setup_result
|
setup_result = await setup_task
|
||||||
assert (recorder.DOMAIN in hass.config.components) == expected_setup_result
|
assert setup_result == expected_setup_result
|
||||||
|
assert (recorder.DOMAIN in hass.config.components) == expected_setup_result
|
||||||
|
else:
|
||||||
|
# Wait for recorder to connect to the database
|
||||||
|
await recorder_helper.async_wait_recorder(hass)
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"Test recorder successfully started, database location: %s",
|
"Test recorder successfully started, database location: %s",
|
||||||
config[recorder.CONF_DB_URL],
|
config[recorder.CONF_DB_URL],
|
||||||
@ -1585,6 +1590,7 @@ async def async_test_recorder(
|
|||||||
*,
|
*,
|
||||||
expected_setup_result: bool = True,
|
expected_setup_result: bool = True,
|
||||||
wait_recorder: bool = True,
|
wait_recorder: bool = True,
|
||||||
|
wait_recorder_setup: bool = True,
|
||||||
) -> AsyncGenerator[recorder.Recorder]:
|
) -> AsyncGenerator[recorder.Recorder]:
|
||||||
"""Setup and return recorder instance.""" # noqa: D401
|
"""Setup and return recorder instance.""" # noqa: D401
|
||||||
await _async_init_recorder_component(
|
await _async_init_recorder_component(
|
||||||
@ -1592,6 +1598,7 @@ async def async_test_recorder(
|
|||||||
config,
|
config,
|
||||||
recorder_db_url,
|
recorder_db_url,
|
||||||
expected_setup_result=expected_setup_result,
|
expected_setup_result=expected_setup_result,
|
||||||
|
wait_setup=wait_recorder_setup,
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
instance = hass.data[recorder.DATA_INSTANCE]
|
instance = hass.data[recorder.DATA_INSTANCE]
|
||||||
@ -1621,6 +1628,7 @@ async def async_setup_recorder_instance(
|
|||||||
*,
|
*,
|
||||||
expected_setup_result: bool = True,
|
expected_setup_result: bool = True,
|
||||||
wait_recorder: bool = True,
|
wait_recorder: bool = True,
|
||||||
|
wait_recorder_setup: bool = True,
|
||||||
) -> AsyncGenerator[recorder.Recorder]:
|
) -> AsyncGenerator[recorder.Recorder]:
|
||||||
"""Set up and return recorder instance."""
|
"""Set up and return recorder instance."""
|
||||||
|
|
||||||
@ -1630,6 +1638,7 @@ async def async_setup_recorder_instance(
|
|||||||
config,
|
config,
|
||||||
expected_setup_result=expected_setup_result,
|
expected_setup_result=expected_setup_result,
|
||||||
wait_recorder=wait_recorder,
|
wait_recorder=wait_recorder,
|
||||||
|
wait_recorder_setup=wait_recorder_setup,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user