diff --git a/homeassistant/components/backup/config.py b/homeassistant/components/backup/config.py index da6a2b85ccb..bcfa95463d1 100644 --- a/homeassistant/components/backup/config.py +++ b/homeassistant/components/backup/config.py @@ -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, ), ) diff --git a/homeassistant/components/backup/store.py b/homeassistant/components/backup/store.py index b8241bb771d..0e1c49426c5 100644 --- a/homeassistant/components/backup/store.py +++ b/homeassistant/components/backup/store.py @@ -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 diff --git a/tests/components/backup/snapshots/test_store.ambr b/tests/components/backup/snapshots/test_store.ambr index a66bbe43b85..45af91645ad 100644 --- a/tests/components/backup/snapshots/test_store.ambr +++ b/tests/components/backup/snapshots/test_store.ambr @@ -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, + }) +# --- diff --git a/tests/components/backup/test_store.py b/tests/components/backup/test_store.py index d240e21531d..cc84b66340c 100644 --- a/tests/components/backup/test_store.py +++ b/tests/components/backup/test_store.py @@ -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