From 1bf545eb25f20fc27fe161691a94531cba7e005c Mon Sep 17 00:00:00 2001 From: Erik <erik@montnemery.com> Date: Fri, 28 Feb 2025 10:28:49 +0100 Subject: [PATCH] Don't allow creating backups if hass is not running --- homeassistant/components/backup/manager.py | 8 ++-- tests/components/backup/test_manager.py | 47 +++++++++++++++++++++- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/backup/manager.py b/homeassistant/components/backup/manager.py index 317de85b823..df5d2aa606d 100644 --- a/homeassistant/components/backup/manager.py +++ b/homeassistant/components/backup/manager.py @@ -27,7 +27,7 @@ from homeassistant.backup_restore import ( password_to_key, ) from homeassistant.const import __version__ as HAVERSION -from homeassistant.core import HomeAssistant, callback +from homeassistant.core import CoreState, HomeAssistant, callback from homeassistant.helpers import ( instance_id, integration_platform, @@ -976,6 +976,8 @@ class BackupManager: with_automatic_settings: bool = False, ) -> NewBackup: """Initiate generating a backup.""" + if self.hass.state is not CoreState.running: + raise BackupManagerError("Home Assistant is not running") if self.state is not BackupManagerState.IDLE: raise BackupManagerError(f"Backup manager busy: {self.state}") @@ -991,7 +993,7 @@ class BackupManager: ) ) try: - return await self._async_create_backup( + return await self._async_initiate_backup( agent_ids=agent_ids, extra_metadata=extra_metadata, include_addons=include_addons, @@ -1018,7 +1020,7 @@ class BackupManager: self._update_issue_backup_failed() raise - async def _async_create_backup( + async def _async_initiate_backup( self, *, agent_ids: list[str], diff --git a/tests/components/backup/test_manager.py b/tests/components/backup/test_manager.py index 6e626e63748..28aca6f8a69 100644 --- a/tests/components/backup/test_manager.py +++ b/tests/components/backup/test_manager.py @@ -4,6 +4,7 @@ from __future__ import annotations import asyncio from collections.abc import Callable, Generator +from contextlib import AbstractContextManager, nullcontext as does_not_raise from dataclasses import replace from io import StringIO import json @@ -34,6 +35,7 @@ from homeassistant.components.backup import ( from homeassistant.components.backup.agent import BackupAgentError from homeassistant.components.backup.const import DATA_MANAGER from homeassistant.components.backup.manager import ( + BackupManager, BackupManagerError, BackupManagerState, CreateBackupStage, @@ -45,7 +47,7 @@ from homeassistant.components.backup.manager import ( WrittenBackup, ) from homeassistant.components.backup.util import password_to_key -from homeassistant.core import HomeAssistant +from homeassistant.core import CoreState, HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import issue_registry as ir @@ -659,6 +661,49 @@ async def test_initiate_backup( assert tar_file_path == f"{backup_directory}/{expected_filename}" +RAISES_HASS_NOT_RUNNING = pytest.raises( + HomeAssistantError, match="Home Assistant is not running" +) + + +@pytest.mark.parametrize( + ("core_state", "expected_result", "initiate_backup_calls"), + [ + (CoreState.final_write, RAISES_HASS_NOT_RUNNING, 0), + (CoreState.not_running, RAISES_HASS_NOT_RUNNING, 0), + (CoreState.running, does_not_raise(), 1), + (CoreState.starting, RAISES_HASS_NOT_RUNNING, 0), + (CoreState.stopped, RAISES_HASS_NOT_RUNNING, 0), + (CoreState.stopping, RAISES_HASS_NOT_RUNNING, 0), + ], +) +async def test_async_pre_backup_core_state( + hass: HomeAssistant, + core_state: CoreState, + expected_result: AbstractContextManager, + initiate_backup_calls: int, +) -> None: + """Test pre backup in different core states.""" + await setup_backup_integration(hass) + manager = hass.data[DATA_MANAGER] + hass.set_state(core_state) + with ( # pylint: disable=confusing-with-statement + patch.object(BackupManager, "_async_initiate_backup") as initiate_backup_mock, + expected_result, + ): + await manager.async_initiate_backup( + agent_ids=["backup.local"], + include_addons=[], + include_all_addons=False, + include_database=False, + include_folders=[], + include_homeassistant=True, + name=None, + password=None, + ) + assert len(initiate_backup_mock.mock_calls) == initiate_backup_calls + + @pytest.mark.usefixtures("mock_backup_generation") @pytest.mark.parametrize("exception", [BackupAgentError("Boom!"), Exception("Boom!")]) async def test_initiate_backup_with_agent_error( -- GitLab