Prepare backup store to read version 2 (#136149)

This commit is contained in:
Erik Montnemery 2025-01-21 14:37:44 +01:00 committed by GitHub
parent 5b49ba563e
commit a2cbaef264
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 234 additions and 35 deletions

View File

@ -102,7 +102,7 @@ class BackupConfigData:
schedule=BackupSchedule(
days=days,
recurrence=ScheduleRecurrence(data["schedule"]["recurrence"]),
state=ScheduleState(data["schedule"]["state"]),
state=ScheduleState(data["schedule"].get("state", ScheduleState.NEVER)),
time=time,
),
)

View File

@ -57,7 +57,9 @@ class _BackupStore(Store[StoredBackupData]):
data["config"]["schedule"]["days"] = [state]
data["config"]["schedule"]["recurrence"] = "custom_days"
if old_major_version > 1:
# Note: We allow reading data with major version 2.
# Reject if major version is higher than 2.
if old_major_version > 2:
raise NotImplementedError
return data

View File

@ -1,5 +1,5 @@
# serializer version: 1
# name: test_store_migration
# name: test_store_migration[store_data0]
dict({
'data': dict({
'backups': list([
@ -41,3 +41,131 @@
'version': 1,
})
# ---
# name: test_store_migration[store_data0].1
dict({
'data': dict({
'backups': list([
dict({
'backup_id': 'abc123',
'failed_agent_ids': list([
'test.remote',
]),
}),
]),
'config': dict({
'create_backup': dict({
'agent_ids': list([
'test-agent',
]),
'include_addons': None,
'include_all_addons': False,
'include_database': True,
'include_folders': None,
'name': None,
'password': None,
}),
'last_attempted_automatic_backup': None,
'last_completed_automatic_backup': None,
'retention': dict({
'copies': None,
'days': None,
}),
'schedule': dict({
'days': list([
]),
'recurrence': 'never',
'state': 'never',
'time': None,
}),
}),
}),
'key': 'backup',
'minor_version': 2,
'version': 1,
})
# ---
# name: test_store_migration[store_data1]
dict({
'data': dict({
'backups': list([
dict({
'backup_id': 'abc123',
'failed_agent_ids': list([
'test.remote',
]),
}),
]),
'config': dict({
'create_backup': dict({
'agent_ids': list([
]),
'include_addons': None,
'include_all_addons': False,
'include_database': True,
'include_folders': None,
'name': None,
'password': None,
}),
'last_attempted_automatic_backup': None,
'last_completed_automatic_backup': None,
'retention': dict({
'copies': None,
'days': None,
}),
'schedule': dict({
'days': list([
]),
'recurrence': 'never',
'time': None,
}),
'something_from_the_future': 'value',
}),
}),
'key': 'backup',
'minor_version': 2,
'version': 1,
})
# ---
# name: test_store_migration[store_data1].1
dict({
'data': dict({
'backups': list([
dict({
'backup_id': 'abc123',
'failed_agent_ids': list([
'test.remote',
]),
}),
]),
'config': dict({
'create_backup': dict({
'agent_ids': list([
'test-agent',
]),
'include_addons': None,
'include_all_addons': False,
'include_database': True,
'include_folders': None,
'name': None,
'password': None,
}),
'last_attempted_automatic_backup': None,
'last_completed_automatic_backup': None,
'retention': dict({
'copies': None,
'days': None,
}),
'schedule': dict({
'days': list([
]),
'recurrence': 'never',
'state': 'never',
'time': None,
}),
}),
}),
'key': 'backup',
'minor_version': 2,
'version': 1,
})
# ---

View File

@ -1,7 +1,10 @@
"""Tests for the Backup integration."""
from collections.abc import Generator
from typing import Any
from unittest.mock import patch
import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.backup.const import DOMAIN
@ -9,46 +12,112 @@ from homeassistant.core import HomeAssistant
from .common import setup_backup_integration
from tests.typing import WebSocketGenerator
@pytest.fixture(autouse=True)
def mock_delay_save() -> Generator[None]:
"""Mock the delay save constant."""
with patch("homeassistant.components.backup.store.STORE_DELAY_SAVE", 0):
yield
@pytest.mark.parametrize(
"store_data",
[
{
"data": {
"backups": [
{
"backup_id": "abc123",
"failed_agent_ids": ["test.remote"],
}
],
"config": {
"create_backup": {
"agent_ids": [],
"include_addons": None,
"include_all_addons": False,
"include_database": True,
"include_folders": None,
"name": None,
"password": None,
},
"last_attempted_automatic_backup": None,
"last_completed_automatic_backup": None,
"retention": {
"copies": None,
"days": None,
},
"schedule": {
"state": "never",
},
},
},
"key": DOMAIN,
"version": 1,
},
{
"data": {
"backups": [
{
"backup_id": "abc123",
"failed_agent_ids": ["test.remote"],
}
],
"config": {
"create_backup": {
"agent_ids": [],
"include_addons": None,
"include_all_addons": False,
"include_database": True,
"include_folders": None,
"name": None,
"password": None,
},
"last_attempted_automatic_backup": None,
"last_completed_automatic_backup": None,
"retention": {
"copies": None,
"days": None,
},
"schedule": {
"days": [],
"recurrence": "never",
"time": None,
},
"something_from_the_future": "value",
},
},
"key": DOMAIN,
"version": 2,
},
],
)
async def test_store_migration(
hass: HomeAssistant,
hass_storage: dict[str, Any],
hass_ws_client: WebSocketGenerator,
snapshot: SnapshotAssertion,
store_data: dict[str, Any],
) -> None:
"""Test migrating the backup store."""
hass_storage[DOMAIN] = {
"data": {
"backups": [
{
"backup_id": "abc123",
"failed_agent_ids": ["test.remote"],
}
],
"config": {
"create_backup": {
"agent_ids": [],
"include_addons": None,
"include_all_addons": False,
"include_database": True,
"include_folders": None,
"name": None,
"password": None,
},
"last_attempted_automatic_backup": None,
"last_completed_automatic_backup": None,
"retention": {
"copies": None,
"days": None,
},
"schedule": {
"state": "never",
},
},
},
"key": DOMAIN,
"version": 1,
}
hass_storage[DOMAIN] = store_data
await setup_backup_integration(hass)
await hass.async_block_till_done()
# Check migrated data
assert hass_storage[DOMAIN] == snapshot
# Update settings, then check saved data
client = await hass_ws_client(hass)
await client.send_json_auto_id(
{
"type": "backup/config/update",
"create_backup": {"agent_ids": ["test-agent"]},
}
)
result = await client.receive_json()
assert result["success"]
await hass.async_block_till_done()
assert hass_storage[DOMAIN] == snapshot