diff --git a/homeassistant/components/backup/agent.py b/homeassistant/components/backup/agent.py index cb03327e941..fe9eb9ea699 100644 --- a/homeassistant/components/backup/agent.py +++ b/homeassistant/components/backup/agent.py @@ -30,11 +30,12 @@ class BackupAgent(abc.ABC): domain: str name: str + unique_id: str @cached_property def agent_id(self) -> str: """Return the agent_id.""" - return f"{self.domain}.{self.name}" + return f"{self.domain}.{self.unique_id}" @abc.abstractmethod async def async_download_backup( diff --git a/homeassistant/components/backup/backup.py b/homeassistant/components/backup/backup.py index ef4924161c2..3f60bd0b88e 100644 --- a/homeassistant/components/backup/backup.py +++ b/homeassistant/components/backup/backup.py @@ -32,6 +32,7 @@ class CoreLocalBackupAgent(LocalBackupAgent): domain = DOMAIN name = "local" + unique_id = "local" def __init__(self, hass: HomeAssistant) -> None: """Initialize the backup agent.""" diff --git a/homeassistant/components/backup/websocket.py b/homeassistant/components/backup/websocket.py index 70fc568c05c..74f56102670 100644 --- a/homeassistant/components/backup/websocket.py +++ b/homeassistant/components/backup/websocket.py @@ -306,7 +306,10 @@ async def backup_agents_info( connection.send_result( msg["id"], { - "agents": [{"agent_id": agent_id} for agent_id in manager.backup_agents], + "agents": [ + {"agent_id": agent.agent_id, "name": agent.name} + for agent in manager.backup_agents.values() + ], }, ) diff --git a/homeassistant/components/cloud/backup.py b/homeassistant/components/cloud/backup.py index 153d0741770..d42e846259c 100644 --- a/homeassistant/components/cloud/backup.py +++ b/homeassistant/components/cloud/backup.py @@ -82,8 +82,7 @@ def async_register_backup_agents_listener( class CloudBackupAgent(BackupAgent): """Cloud backup agent.""" - domain = DOMAIN - name = DOMAIN + domain = name = unique_id = DOMAIN def __init__(self, hass: HomeAssistant, cloud: Cloud[CloudClient]) -> None: """Initialize the cloud backup sync agent.""" diff --git a/homeassistant/components/hassio/backup.py b/homeassistant/components/hassio/backup.py index d49fafb886f..98ad2ad20e3 100644 --- a/homeassistant/components/hassio/backup.py +++ b/homeassistant/components/hassio/backup.py @@ -133,7 +133,7 @@ class SupervisorBackupAgent(BackupAgent): self._hass = hass self._backup_dir = Path("/backups") self._client = get_supervisor_client(hass) - self.name = name + self.name = self.unique_id = name self.location = location async def async_download_backup( diff --git a/homeassistant/components/kitchen_sink/backup.py b/homeassistant/components/kitchen_sink/backup.py index c4a045aeefc..44ac0456105 100644 --- a/homeassistant/components/kitchen_sink/backup.py +++ b/homeassistant/components/kitchen_sink/backup.py @@ -51,7 +51,7 @@ class KitchenSinkBackupAgent(BackupAgent): def __init__(self, name: str) -> None: """Initialize the kitchen sink backup sync agent.""" super().__init__() - self.name = name + self.name = self.unique_id = name self._uploads = [ AgentBackup( addons=[AddonInfo(name="Test", slug="test", version="1.0.0")], diff --git a/homeassistant/components/synology_dsm/backup.py b/homeassistant/components/synology_dsm/backup.py index eed6af758ba..62a1b97b717 100644 --- a/homeassistant/components/synology_dsm/backup.py +++ b/homeassistant/components/synology_dsm/backup.py @@ -39,7 +39,7 @@ async def async_get_backup_agents( return [] syno_datas: dict[str, SynologyDSMData] = hass.data[DOMAIN] return [ - SynologyDSMBackupAgent(hass, entry) + SynologyDSMBackupAgent(hass, entry, entry.unique_id) for entry in entries if entry.unique_id is not None and (syno_data := syno_datas.get(entry.unique_id)) @@ -76,11 +76,12 @@ class SynologyDSMBackupAgent(BackupAgent): domain = DOMAIN - def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None: + def __init__(self, hass: HomeAssistant, entry: ConfigEntry, unique_id: str) -> None: """Initialize the Synology DSM backup agent.""" super().__init__() LOGGER.debug("Initializing Synology DSM backup agent for %s", entry.unique_id) self.name = entry.title + self.unique_id = unique_id self.path = ( f"{entry.options[CONF_BACKUP_SHARE]}/{entry.options[CONF_BACKUP_PATH]}" ) diff --git a/tests/components/backup/common.py b/tests/components/backup/common.py index 4f456cc6d72..97236ee995d 100644 --- a/tests/components/backup/common.py +++ b/tests/components/backup/common.py @@ -64,6 +64,7 @@ class BackupAgentTest(BackupAgent): def __init__(self, name: str, backups: list[AgentBackup] | None = None) -> None: """Initialize the backup agent.""" self.name = name + self.unique_id = name if backups is None: backups = [ AgentBackup( diff --git a/tests/components/backup/snapshots/test_backup.ambr b/tests/components/backup/snapshots/test_backup.ambr index f91473e3b70..1a6774e7a95 100644 --- a/tests/components/backup/snapshots/test_backup.ambr +++ b/tests/components/backup/snapshots/test_backup.ambr @@ -39,6 +39,7 @@ 'agents': list([ dict({ 'agent_id': 'backup.local', + 'name': 'local', }), ]), }), @@ -97,6 +98,7 @@ 'agents': list([ dict({ 'agent_id': 'backup.local', + 'name': 'local', }), ]), }), @@ -128,6 +130,7 @@ 'agents': list([ dict({ 'agent_id': 'backup.local', + 'name': 'local', }), ]), }), @@ -159,6 +162,7 @@ 'agents': list([ dict({ 'agent_id': 'backup.local', + 'name': 'local', }), ]), }), @@ -190,6 +194,7 @@ 'agents': list([ dict({ 'agent_id': 'backup.local', + 'name': 'local', }), ]), }), diff --git a/tests/components/backup/snapshots/test_websocket.ambr b/tests/components/backup/snapshots/test_websocket.ambr index 43b4c1260dd..2a6bc14fb74 100644 --- a/tests/components/backup/snapshots/test_websocket.ambr +++ b/tests/components/backup/snapshots/test_websocket.ambr @@ -17,9 +17,11 @@ 'agents': list([ dict({ 'agent_id': 'backup.local', + 'name': 'local', }), dict({ - 'agent_id': 'domain.test', + 'agent_id': 'test.test', + 'name': 'test', }), ]), }), diff --git a/tests/components/backup/test_manager.py b/tests/components/backup/test_manager.py index 48e6db4ae9a..8a99f90d234 100644 --- a/tests/components/backup/test_manager.py +++ b/tests/components/backup/test_manager.py @@ -1203,8 +1203,8 @@ async def test_loading_platform_with_listener( await ws_client.send_json_auto_id({"type": "backup/agents/info"}) resp = await ws_client.receive_json() assert resp["result"]["agents"] == [ - {"agent_id": "backup.local"}, - {"agent_id": "test.remote1"}, + {"agent_id": "backup.local", "name": "local"}, + {"agent_id": "test.remote1", "name": "remote1"}, ] assert len(manager.local_backup_agents) == num_local_agents @@ -1220,8 +1220,8 @@ async def test_loading_platform_with_listener( await ws_client.send_json_auto_id({"type": "backup/agents/info"}) resp = await ws_client.receive_json() assert resp["result"]["agents"] == [ - {"agent_id": "backup.local"}, - {"agent_id": "test.remote2"}, + {"agent_id": "backup.local", "name": "local"}, + {"agent_id": "test.remote2", "name": "remote2"}, ] assert len(manager.local_backup_agents) == num_local_agents diff --git a/tests/components/cloud/test_backup.py b/tests/components/cloud/test_backup.py index db742525a48..373bd164c0c 100644 --- a/tests/components/cloud/test_backup.py +++ b/tests/components/cloud/test_backup.py @@ -146,7 +146,10 @@ async def test_agents_info( assert response["success"] assert response["result"] == { - "agents": [{"agent_id": "backup.local"}, {"agent_id": "cloud.cloud"}], + "agents": [ + {"agent_id": "backup.local", "name": "local"}, + {"agent_id": "cloud.cloud", "name": "cloud"}, + ], } diff --git a/tests/components/hassio/test_backup.py b/tests/components/hassio/test_backup.py index 40ab253b7e6..9483b513718 100644 --- a/tests/components/hassio/test_backup.py +++ b/tests/components/hassio/test_backup.py @@ -34,6 +34,7 @@ from homeassistant.components.backup import ( BackupAgentPlatformProtocol, Folder, ) +from homeassistant.components.hassio import DOMAIN from homeassistant.components.hassio.backup import LOCATION_CLOUD_BACKUP from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component @@ -252,11 +253,11 @@ async def setup_integration( class BackupAgentTest(BackupAgent): """Test backup agent.""" - domain = "test" - - def __init__(self, name: str) -> None: + def __init__(self, name: str, domain: str = "test") -> None: """Initialize the backup agent.""" + self.domain = domain self.name = name + self.unique_id = name async def async_download_backup( self, backup_id: str, **kwargs: Any @@ -304,7 +305,10 @@ async def _setup_backup_platform( @pytest.mark.parametrize( ("mounts", "expected_agents"), [ - (MountsInfo(default_backup_mount=None, mounts=[]), ["hassio.local"]), + ( + MountsInfo(default_backup_mount=None, mounts=[]), + [BackupAgentTest("local", DOMAIN)], + ), ( MountsInfo( default_backup_mount=None, @@ -321,7 +325,7 @@ async def _setup_backup_platform( ) ], ), - ["hassio.local", "hassio.test"], + [BackupAgentTest("local", DOMAIN), BackupAgentTest("test", DOMAIN)], ), ( MountsInfo( @@ -339,7 +343,7 @@ async def _setup_backup_platform( ) ], ), - ["hassio.local"], + [BackupAgentTest("local", DOMAIN)], ), ], ) @@ -348,7 +352,7 @@ async def test_agent_info( hass_ws_client: WebSocketGenerator, supervisor_client: AsyncMock, mounts: MountsInfo, - expected_agents: list[str], + expected_agents: list[BackupAgent], ) -> None: """Test backup agent info.""" client = await hass_ws_client(hass) @@ -361,7 +365,10 @@ async def test_agent_info( assert response["success"] assert response["result"] == { - "agents": [{"agent_id": agent_id} for agent_id in expected_agents], + "agents": [ + {"agent_id": agent.agent_id, "name": agent.name} + for agent in expected_agents + ], } diff --git a/tests/components/kitchen_sink/test_backup.py b/tests/components/kitchen_sink/test_backup.py index 9e46845e1cb..827bde39d7d 100644 --- a/tests/components/kitchen_sink/test_backup.py +++ b/tests/components/kitchen_sink/test_backup.py @@ -55,7 +55,10 @@ async def test_agents_info( assert response["success"] assert response["result"] == { - "agents": [{"agent_id": "backup.local"}, {"agent_id": "kitchen_sink.syncer"}], + "agents": [ + {"agent_id": "backup.local", "name": "local"}, + {"agent_id": "kitchen_sink.syncer", "name": "syncer"}, + ], } config_entry = hass.config_entries.async_entries(DOMAIN)[0] @@ -66,7 +69,9 @@ async def test_agents_info( response = await client.receive_json() assert response["success"] - assert response["result"] == {"agents": [{"agent_id": "backup.local"}]} + assert response["result"] == { + "agents": [{"agent_id": "backup.local", "name": "local"}] + } await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -76,7 +81,10 @@ async def test_agents_info( assert response["success"] assert response["result"] == { - "agents": [{"agent_id": "backup.local"}, {"agent_id": "kitchen_sink.syncer"}], + "agents": [ + {"agent_id": "backup.local", "name": "local"}, + {"agent_id": "kitchen_sink.syncer", "name": "syncer"}, + ], } diff --git a/tests/components/synology_dsm/test_backup.py b/tests/components/synology_dsm/test_backup.py index 0cd119cf015..436e3666176 100644 --- a/tests/components/synology_dsm/test_backup.py +++ b/tests/components/synology_dsm/test_backup.py @@ -208,8 +208,8 @@ async def test_agents_info( assert response["success"] assert response["result"] == { "agents": [ - {"agent_id": "synology_dsm.Mock Title"}, - {"agent_id": "backup.local"}, + {"agent_id": "synology_dsm.mocked_syno_dsm_entry", "name": "Mock Title"}, + {"agent_id": "backup.local", "name": "local"}, ], } @@ -231,7 +231,7 @@ async def test_agents_not_loaded( assert response["success"] assert response["result"] == { "agents": [ - {"agent_id": "backup.local"}, + {"agent_id": "backup.local", "name": "local"}, ], } @@ -251,8 +251,8 @@ async def test_agents_on_unload( assert response["success"] assert response["result"] == { "agents": [ - {"agent_id": "synology_dsm.Mock Title"}, - {"agent_id": "backup.local"}, + {"agent_id": "synology_dsm.mocked_syno_dsm_entry", "name": "Mock Title"}, + {"agent_id": "backup.local", "name": "local"}, ], } @@ -269,7 +269,7 @@ async def test_agents_on_unload( assert response["success"] assert response["result"] == { "agents": [ - {"agent_id": "backup.local"}, + {"agent_id": "backup.local", "name": "local"}, ], } @@ -299,7 +299,7 @@ async def test_agents_list_backups( "name": "Automatic backup 2025.2.0.dev0", "protected": True, "size": 13916160, - "agent_ids": ["synology_dsm.Mock Title"], + "agent_ids": ["synology_dsm.mocked_syno_dsm_entry"], "failed_agent_ids": [], "with_automatic_settings": None, } @@ -323,7 +323,9 @@ async def test_agents_list_backups_error( assert response["success"] assert response["result"] == { - "agent_errors": {"synology_dsm.Mock Title": "Failed to list backups"}, + "agent_errors": { + "synology_dsm.mocked_syno_dsm_entry": "Failed to list backups" + }, "backups": [], "last_attempted_automatic_backup": None, "last_completed_automatic_backup": None, @@ -362,7 +364,7 @@ async def test_agents_list_backups_disabled_filestation( "name": "Automatic backup 2025.2.0.dev0", "protected": True, "size": 13916160, - "agent_ids": ["synology_dsm.Mock Title"], + "agent_ids": ["synology_dsm.mocked_syno_dsm_entry"], "failed_agent_ids": [], "with_automatic_settings": None, }, @@ -429,7 +431,9 @@ async def test_agents_get_backup_error( assert response["success"] assert response["result"] == { - "agent_errors": {"synology_dsm.Mock Title": "Failed to list backups"}, + "agent_errors": { + "synology_dsm.mocked_syno_dsm_entry": "Failed to list backups" + }, "backup": None, } @@ -462,7 +466,7 @@ async def test_agents_download( backup_id = "abcd12ef" resp = await client.get( - f"/api/backup/download/{backup_id}?agent_id=synology_dsm.Mock Title" + f"/api/backup/download/{backup_id}?agent_id=synology_dsm.mocked_syno_dsm_entry" ) assert resp.status == 200 assert await resp.content.read() == b"backup data" @@ -482,7 +486,7 @@ async def test_agents_download_not_existing( ) resp = await client.get( - f"/api/backup/download/{backup_id}?agent_id=synology_dsm.Mock Title" + f"/api/backup/download/{backup_id}?agent_id=synology_dsm.mocked_syno_dsm_entry" ) assert resp.reason == "Internal Server Error" assert resp.status == 500 @@ -524,7 +528,7 @@ async def test_agents_upload( mocked_open.return_value.read = Mock(side_effect=[b"test", b""]) fetch_backup.return_value = test_backup resp = await client.post( - "/api/backup/upload?agent_id=synology_dsm.Mock Title", + "/api/backup/upload?agent_id=synology_dsm.mocked_syno_dsm_entry", data={"file": StringIO("test")}, ) @@ -578,7 +582,7 @@ async def test_agents_upload_error( SynologyDSMAPIErrorException("api", "500", "error") ) resp = await client.post( - "/api/backup/upload?agent_id=synology_dsm.Mock Title", + "/api/backup/upload?agent_id=synology_dsm.mocked_syno_dsm_entry", data={"file": StringIO("test")}, ) @@ -609,7 +613,7 @@ async def test_agents_upload_error( ] resp = await client.post( - "/api/backup/upload?agent_id=synology_dsm.Mock Title", + "/api/backup/upload?agent_id=synology_dsm.mocked_syno_dsm_entry", data={"file": StringIO("test")}, ) @@ -674,7 +678,9 @@ async def test_agents_delete_not_existing( assert response["success"] assert response["result"] == { - "agent_errors": {"synology_dsm.Mock Title": "Failed to delete the backup"} + "agent_errors": { + "synology_dsm.mocked_syno_dsm_entry": "Failed to delete the backup" + } } @@ -701,7 +707,9 @@ async def test_agents_delete_error( assert response["success"] assert response["result"] == { - "agent_errors": {"synology_dsm.Mock Title": "Failed to delete the backup"} + "agent_errors": { + "synology_dsm.mocked_syno_dsm_entry": "Failed to delete the backup" + } } mock: AsyncMock = setup_dsm_with_filestation.file.delete_file assert len(mock.mock_calls) == 1