diff --git a/homeassistant/components/backup/manager.py b/homeassistant/components/backup/manager.py index 8c8cd805565..f4ea27ca5f1 100644 --- a/homeassistant/components/backup/manager.py +++ b/homeassistant/components/backup/manager.py @@ -672,6 +672,7 @@ class BackupManager: self, *, agent_ids: list[str], + extra_metadata: dict[str, bool | str] | None = None, include_addons: list[str] | None, include_all_addons: bool, include_database: bool, @@ -684,6 +685,7 @@ class BackupManager: """Create a backup.""" new_backup = await self.async_initiate_backup( agent_ids=agent_ids, + extra_metadata=extra_metadata, include_addons=include_addons, include_all_addons=include_all_addons, include_database=include_database, @@ -717,6 +719,7 @@ class BackupManager: self, *, agent_ids: list[str], + extra_metadata: dict[str, bool | str] | None = None, include_addons: list[str] | None, include_all_addons: bool, include_database: bool, @@ -741,6 +744,7 @@ class BackupManager: try: return await self._async_create_backup( agent_ids=agent_ids, + extra_metadata=extra_metadata, include_addons=include_addons, include_all_addons=include_all_addons, include_database=include_database, @@ -764,6 +768,7 @@ class BackupManager: self, *, agent_ids: list[str], + extra_metadata: dict[str, bool | str] | None, include_addons: list[str] | None, include_all_addons: bool, include_database: bool, @@ -790,6 +795,7 @@ class BackupManager: name or f"{'Automatic' if with_automatic_settings else 'Custom'} backup {HAVERSION}" ) + extra_metadata = extra_metadata or {} try: ( @@ -798,7 +804,8 @@ class BackupManager: ) = await self._reader_writer.async_create_backup( agent_ids=agent_ids, backup_name=backup_name, - extra_metadata={ + extra_metadata=extra_metadata + | { "instance_id": await instance_id.async_get(self.hass), "with_automatic_settings": with_automatic_settings, }, diff --git a/homeassistant/components/hassio/backup.py b/homeassistant/components/hassio/backup.py index 98ad2ad20e3..4a9bfaded15 100644 --- a/homeassistant/components/hassio/backup.py +++ b/homeassistant/components/hassio/backup.py @@ -509,6 +509,7 @@ async def backup_addon_before_update( try: await backup_manager.async_create_backup( agent_ids=[await _default_agent(client)], + extra_metadata={"supervisor.addon_update": addon}, include_addons=[addon], include_all_addons=False, include_database=False, diff --git a/tests/components/backup/test_manager.py b/tests/components/backup/test_manager.py index 8a99f90d234..c6eeff79d45 100644 --- a/tests/components/backup/test_manager.py +++ b/tests/components/backup/test_manager.py @@ -90,13 +90,13 @@ def generate_backup_id_fixture() -> Generator[MagicMock]: @pytest.mark.usefixtures("mock_backup_generation") -async def test_async_create_backup( +async def test_create_backup_service( hass: HomeAssistant, caplog: pytest.LogCaptureFixture, mocked_json_bytes: Mock, mocked_tarfile: Mock, ) -> None: - """Test create backup.""" + """Test create backup service.""" assert await async_setup_component(hass, DOMAIN, {}) await hass.async_block_till_done() @@ -137,6 +137,128 @@ async def test_async_create_backup( ) +@pytest.mark.usefixtures("mock_backup_generation") +@pytest.mark.parametrize( + ("manager_kwargs", "expected_writer_kwargs"), + [ + ( + { + "agent_ids": ["backup.local"], + "include_addons": None, + "include_all_addons": False, + "include_database": True, + "include_folders": None, + "include_homeassistant": True, + "name": None, + "password": None, + }, + { + "agent_ids": ["backup.local"], + "backup_name": "Custom backup 2025.1.0", + "extra_metadata": { + "instance_id": ANY, + "with_automatic_settings": False, + }, + "include_addons": None, + "include_all_addons": False, + "include_database": True, + "include_folders": None, + "include_homeassistant": True, + "on_progress": ANY, + "password": None, + }, + ), + ( + { + "agent_ids": ["backup.local"], + "include_addons": None, + "include_all_addons": False, + "include_database": True, + "include_folders": None, + "include_homeassistant": True, + "name": None, + "password": None, + "with_automatic_settings": True, + }, + { + "agent_ids": ["backup.local"], + "backup_name": "Automatic backup 2025.1.0", + "extra_metadata": { + "instance_id": ANY, + "with_automatic_settings": True, + }, + "include_addons": None, + "include_all_addons": False, + "include_database": True, + "include_folders": None, + "include_homeassistant": True, + "on_progress": ANY, + "password": None, + }, + ), + ( + { + "agent_ids": ["backup.local"], + "extra_metadata": {"custom": "data"}, + "include_addons": None, + "include_all_addons": False, + "include_database": True, + "include_folders": None, + "include_homeassistant": True, + "name": None, + "password": None, + }, + { + "agent_ids": ["backup.local"], + "backup_name": "Custom backup 2025.1.0", + "extra_metadata": { + "custom": "data", + "instance_id": ANY, + "with_automatic_settings": False, + }, + "include_addons": None, + "include_all_addons": False, + "include_database": True, + "include_folders": None, + "include_homeassistant": True, + "on_progress": ANY, + "password": None, + }, + ), + ], +) +async def test_async_create_backup( + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, + mocked_json_bytes: Mock, + mocked_tarfile: Mock, + manager_kwargs: dict[str, Any], + expected_writer_kwargs: dict[str, Any], +) -> None: + """Test create backup.""" + assert await async_setup_component(hass, DOMAIN, {}) + await hass.async_block_till_done() + manager = hass.data[DATA_MANAGER] + + new_backup = NewBackup(backup_job_id="time-123") + backup_task = AsyncMock( + return_value=WrittenBackup( + backup=TEST_BACKUP_ABC123, + open_stream=AsyncMock(), + release_stream=AsyncMock(), + ), + )() # call it so that it can be awaited + + with patch( + "homeassistant.components.backup.manager.CoreBackupReaderWriter.async_create_backup", + return_value=(new_backup, backup_task), + ) as create_backup: + await manager.async_create_backup(**manager_kwargs) + + assert create_backup.called + assert create_backup.call_args == call(**expected_writer_kwargs) + + @pytest.mark.usefixtures("mock_backup_generation") async def test_create_backup_when_busy( hass: HomeAssistant, diff --git a/tests/components/hassio/test_update.py b/tests/components/hassio/test_update.py index 88d7076824f..732b2655107 100644 --- a/tests/components/hassio/test_update.py +++ b/tests/components/hassio/test_update.py @@ -240,6 +240,7 @@ async def test_update_addon(hass: HomeAssistant, update_addon: AsyncMock) -> Non None, { "agent_ids": ["hassio.local"], + "extra_metadata": {"supervisor.addon_update": "test"}, "include_addons": ["test"], "include_all_addons": False, "include_database": False, @@ -254,6 +255,7 @@ async def test_update_addon(hass: HomeAssistant, update_addon: AsyncMock) -> Non "my_nas", { "agent_ids": ["hassio.my_nas"], + "extra_metadata": {"supervisor.addon_update": "test"}, "include_addons": ["test"], "include_all_addons": False, "include_database": False, @@ -281,6 +283,7 @@ async def test_update_addon(hass: HomeAssistant, update_addon: AsyncMock) -> Non None, { "agent_ids": ["hassio.local"], + "extra_metadata": {"supervisor.addon_update": "test"}, "include_addons": ["test"], "include_all_addons": False, "include_database": False, diff --git a/tests/components/hassio/test_websocket_api.py b/tests/components/hassio/test_websocket_api.py index 1fefe54ad75..ab8dc1475e2 100644 --- a/tests/components/hassio/test_websocket_api.py +++ b/tests/components/hassio/test_websocket_api.py @@ -360,6 +360,7 @@ async def test_update_addon( None, { "agent_ids": ["hassio.local"], + "extra_metadata": {"supervisor.addon_update": "test"}, "include_addons": ["test"], "include_all_addons": False, "include_database": False, @@ -374,6 +375,7 @@ async def test_update_addon( "my_nas", { "agent_ids": ["hassio.my_nas"], + "extra_metadata": {"supervisor.addon_update": "test"}, "include_addons": ["test"], "include_all_addons": False, "include_database": False, @@ -401,6 +403,7 @@ async def test_update_addon( None, { "agent_ids": ["hassio.local"], + "extra_metadata": {"supervisor.addon_update": "test"}, "include_addons": ["test"], "include_all_addons": False, "include_database": False,