Keep one backup per backup agent when executing retention policy (#138189)

* Keep one backup per backup agent when executing retention policy

* Add tests

* Use defaultdict instead of dict.setdefault

* Update hassio tests
This commit is contained in:
Erik Montnemery 2025-02-10 17:09:57 +01:00 committed by GitHub
parent 53d011f345
commit e1817d466e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 374 additions and 31 deletions

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import abc
import asyncio
from collections import defaultdict
from collections.abc import AsyncIterator, Callable, Coroutine
from dataclasses import dataclass, replace
from enum import StrEnum
@ -677,10 +678,13 @@ class BackupManager:
return None
return with_automatic_settings
async def async_delete_backup(self, backup_id: str) -> dict[str, Exception]:
async def async_delete_backup(
self, backup_id: str, *, agent_ids: list[str] | None = None
) -> dict[str, Exception]:
"""Delete a backup."""
agent_errors: dict[str, Exception] = {}
agent_ids = list(self.backup_agents)
if agent_ids is None:
agent_ids = list(self.backup_agents)
delete_backup_results = await asyncio.gather(
*(
@ -731,35 +735,71 @@ class BackupManager:
# Run the include filter first to ensure we only consider backups that
# should be included in the deletion process.
backups = include_filter(backups)
backups_by_agent: dict[str, dict[str, ManagerBackup]] = defaultdict(dict)
for backup_id, backup in backups.items():
for agent_id in backup.agents:
backups_by_agent[agent_id][backup_id] = backup
LOGGER.debug("Total automatic backups: %s", backups)
LOGGER.debug("Backups returned by include filter: %s", backups)
LOGGER.debug(
"Backups returned by include filter by agent: %s",
{agent_id: list(backups) for agent_id, backups in backups_by_agent.items()},
)
backups_to_delete = delete_filter(backups)
LOGGER.debug("Backups returned by delete filter: %s", backups_to_delete)
if not backups_to_delete:
return
# always delete oldest backup first
backups_to_delete = dict(
sorted(
backups_to_delete.items(),
key=lambda backup_item: backup_item[1].date,
)
backups_to_delete_by_agent: dict[str, dict[str, ManagerBackup]] = defaultdict(
dict
)
for backup_id, backup in sorted(
backups_to_delete.items(),
key=lambda backup_item: backup_item[1].date,
):
for agent_id in backup.agents:
backups_to_delete_by_agent[agent_id][backup_id] = backup
LOGGER.debug(
"Backups returned by delete filter by agent: %s",
{
agent_id: list(backups)
for agent_id, backups in backups_to_delete_by_agent.items()
},
)
for agent_id, to_delete_from_agent in backups_to_delete_by_agent.items():
if len(to_delete_from_agent) >= len(backups_by_agent[agent_id]):
# Never delete the last backup.
last_backup = to_delete_from_agent.popitem()
LOGGER.debug(
"Keeping the last backup %s for agent %s", last_backup, agent_id
)
LOGGER.debug(
"Backups to delete by agent: %s",
{
agent_id: list(backups)
for agent_id, backups in backups_to_delete_by_agent.items()
},
)
if len(backups_to_delete) >= len(backups):
# Never delete the last backup.
last_backup = backups_to_delete.popitem()
LOGGER.debug("Keeping the last backup: %s", last_backup)
backup_ids_to_delete: dict[str, set[str]] = defaultdict(set)
for agent_id, to_delete in backups_to_delete_by_agent.items():
for backup_id in to_delete:
backup_ids_to_delete[backup_id].add(agent_id)
LOGGER.debug("Backups to delete: %s", backups_to_delete)
if not backups_to_delete:
if not backup_ids_to_delete:
return
backup_ids = list(backups_to_delete)
backup_ids = list(backup_ids_to_delete)
delete_results = await asyncio.gather(
*(self.async_delete_backup(backup_id) for backup_id in backups_to_delete)
*(
self.async_delete_backup(backup_id, agent_ids=list(agent_ids))
for backup_id, agent_ids in backup_ids_to_delete.items()
)
)
agent_errors = {
backup_id: error

View File

@ -6,6 +6,7 @@ from unittest.mock import ANY, AsyncMock, MagicMock, Mock, call, patch
from freezegun.api import FrozenDateTimeFactory
import pytest
from pytest_unordered import unordered
from syrupy import SnapshotAssertion
from homeassistant.components.backup import (
@ -20,6 +21,7 @@ from homeassistant.components.backup import (
from homeassistant.components.backup.agent import BackupAgentUnreachableError
from homeassistant.components.backup.const import DATA_MANAGER, DOMAIN
from homeassistant.components.backup.manager import (
AgentBackupStatus,
CreateBackupEvent,
CreateBackupState,
ManagerBackup,
@ -1800,21 +1802,25 @@ async def test_config_schedule_logic(
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -1839,21 +1845,25 @@ async def test_config_schedule_logic(
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -1878,11 +1888,13 @@ async def test_config_schedule_logic(
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
@ -1907,26 +1919,46 @@ async def test_config_schedule_logic(
},
{
"backup-1": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-09T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-5": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -1940,7 +1972,80 @@ async def test_config_schedule_logic(
1,
1,
1,
[call("backup-1")],
[
call(
"backup-1",
agent_ids=unordered(["test.test-agent", "test.test-agent2"]),
)
],
),
(
{
"type": "backup/config/update",
"create_backup": {"agent_ids": ["test.test-agent"]},
"retention": {"copies": 3, "days": None},
"schedule": {"recurrence": "daily"},
},
{
"backup-1": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-09T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-5": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
),
},
{},
{},
"2024-11-11T04:45:00+01:00",
"2024-11-12T04:45:00+01:00",
"2024-11-12T04:45:00+01:00",
1,
1,
1,
[
call(
"backup-1",
agent_ids=unordered(["test.test-agent", "test.test-agent2"]),
)
],
),
(
{
@ -1951,26 +2056,31 @@ async def test_config_schedule_logic(
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-09T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-5": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -1984,7 +2094,10 @@ async def test_config_schedule_logic(
1,
1,
2,
[call("backup-1"), call("backup-2")],
[
call("backup-1", agent_ids=["test.test-agent"]),
call("backup-2", agent_ids=["test.test-agent"]),
],
),
(
{
@ -1995,21 +2108,25 @@ async def test_config_schedule_logic(
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2023,7 +2140,7 @@ async def test_config_schedule_logic(
1,
1,
1,
[call("backup-1")],
[call("backup-1", agent_ids=["test.test-agent"])],
),
(
{
@ -2034,21 +2151,25 @@ async def test_config_schedule_logic(
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2062,7 +2183,7 @@ async def test_config_schedule_logic(
1,
1,
1,
[call("backup-1")],
[call("backup-1", agent_ids=["test.test-agent"])],
),
(
{
@ -2073,26 +2194,46 @@ async def test_config_schedule_logic(
},
{
"backup-1": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-09T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-5": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2106,7 +2247,20 @@ async def test_config_schedule_logic(
1,
1,
3,
[call("backup-1"), call("backup-2"), call("backup-3")],
[
call(
"backup-1",
agent_ids=unordered(["test.test-agent", "test.test-agent2"]),
),
call(
"backup-2",
agent_ids=unordered(["test.test-agent", "test.test-agent2"]),
),
call(
"backup-3",
agent_ids=unordered(["test.test-agent", "test.test-agent2"]),
),
],
),
(
{
@ -2117,11 +2271,86 @@ async def test_config_schedule_logic(
},
{
"backup-1": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-09T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-5": MagicMock(
agents={
"test.test-agent": MagicMock(spec=AgentBackupStatus),
"test.test-agent2": MagicMock(spec=AgentBackupStatus),
},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
),
},
{},
{},
"2024-11-11T04:45:00+01:00",
"2024-11-12T04:45:00+01:00",
"2024-11-12T04:45:00+01:00",
1,
1,
3,
[
call(
"backup-1",
agent_ids=unordered(["test.test-agent", "test.test-agent2"]),
),
call(
"backup-2",
agent_ids=unordered(["test.test-agent", "test.test-agent2"]),
),
call("backup-3", agent_ids=["test.test-agent"]),
],
),
(
{
"type": "backup/config/update",
"create_backup": {"agent_ids": ["test.test-agent"]},
"retention": {"copies": 0, "days": None},
"schedule": {"recurrence": "daily"},
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2261,21 +2490,25 @@ async def test_config_retention_copies_logic(
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2297,21 +2530,25 @@ async def test_config_retention_copies_logic(
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2333,26 +2570,31 @@ async def test_config_retention_copies_logic(
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-09T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-5": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2363,7 +2605,7 @@ async def test_config_retention_copies_logic(
1,
1,
1,
[call("backup-1")],
[call("backup-1", agent_ids=["test.test-agent"])],
),
(
{
@ -2374,26 +2616,31 @@ async def test_config_retention_copies_logic(
},
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-09T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-5": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2404,7 +2651,10 @@ async def test_config_retention_copies_logic(
1,
1,
2,
[call("backup-1"), call("backup-2")],
[
call("backup-1", agent_ids=["test.test-agent"]),
call("backup-2", agent_ids=["test.test-agent"]),
],
),
],
)
@ -2519,16 +2769,19 @@ async def test_config_retention_copies_logic_manual_backup(
[],
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2541,7 +2794,7 @@ async def test_config_retention_copies_logic_manual_backup(
"2024-11-12T12:00:00+01:00",
1,
1,
[call("backup-1")],
[call("backup-1", agent_ids=["test.test-agent"])],
),
# No config update - No cleanup
(
@ -2549,16 +2802,19 @@ async def test_config_retention_copies_logic_manual_backup(
[],
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2586,16 +2842,19 @@ async def test_config_retention_copies_logic_manual_backup(
],
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2608,7 +2867,7 @@ async def test_config_retention_copies_logic_manual_backup(
"2024-11-12T12:00:00+01:00",
1,
1,
[call("backup-1")],
[call("backup-1", agent_ids=["test.test-agent"])],
),
(
None,
@ -2622,16 +2881,19 @@ async def test_config_retention_copies_logic_manual_backup(
],
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2644,7 +2906,7 @@ async def test_config_retention_copies_logic_manual_backup(
"2024-11-12T12:00:00+01:00",
1,
1,
[call("backup-1")],
[call("backup-1", agent_ids=["test.test-agent"])],
),
(
None,
@ -2658,16 +2920,19 @@ async def test_config_retention_copies_logic_manual_backup(
],
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2694,21 +2959,25 @@ async def test_config_retention_copies_logic_manual_backup(
],
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-09T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2721,7 +2990,10 @@ async def test_config_retention_copies_logic_manual_backup(
"2024-11-12T12:00:00+01:00",
1,
2,
[call("backup-1"), call("backup-2")],
[
call("backup-1", agent_ids=["test.test-agent"]),
call("backup-2", agent_ids=["test.test-agent"]),
],
),
(
None,
@ -2735,16 +3007,19 @@ async def test_config_retention_copies_logic_manual_backup(
],
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2757,7 +3032,7 @@ async def test_config_retention_copies_logic_manual_backup(
"2024-11-12T12:00:00+01:00",
1,
1,
[call("backup-1")],
[call("backup-1", agent_ids=["test.test-agent"])],
),
(
None,
@ -2771,16 +3046,19 @@ async def test_config_retention_copies_logic_manual_backup(
],
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2793,7 +3071,7 @@ async def test_config_retention_copies_logic_manual_backup(
"2024-11-12T12:00:00+01:00",
1,
1,
[call("backup-1")],
[call("backup-1", agent_ids=["test.test-agent"])],
),
(
None,
@ -2807,21 +3085,25 @@ async def test_config_retention_copies_logic_manual_backup(
],
{
"backup-1": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-09T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"test.test-agent": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
@ -2834,7 +3116,10 @@ async def test_config_retention_copies_logic_manual_backup(
"2024-11-12T12:00:00+01:00",
1,
2,
[call("backup-1"), call("backup-2")],
[
call("backup-1", agent_ids=["test.test-agent"]),
call("backup-2", agent_ids=["test.test-agent"]),
],
),
],
)

View File

@ -10,6 +10,9 @@ from aiohasupervisor.models import HomeAssistantUpdateOptions, StoreAddonUpdate
import pytest
from homeassistant.components.backup import BackupManagerError, ManagerBackup
# pylint: disable-next=hass-component-root-import
from homeassistant.components.backup.manager import AgentBackupStatus
from homeassistant.components.hassio import DOMAIN
from homeassistant.components.hassio.const import REQUEST_REFRESH_DELAY
from homeassistant.const import __version__ as HAVERSION
@ -348,34 +351,40 @@ async def test_update_addon_with_backup(
(
{
"backup-1": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
extra_metadata={"supervisor.addon_update": "other"},
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
extra_metadata={"supervisor.addon_update": "other"},
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-5": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
extra_metadata={"supervisor.addon_update": "test"},
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-6": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
extra_metadata={"supervisor.addon_update": "test"},
with_automatic_settings=True,

View File

@ -9,6 +9,9 @@ from aiohasupervisor.models import HomeAssistantUpdateOptions, StoreAddonUpdate
import pytest
from homeassistant.components.backup import BackupManagerError, ManagerBackup
# pylint: disable-next=hass-component-root-import
from homeassistant.components.backup.manager import AgentBackupStatus
from homeassistant.components.hassio import DOMAIN
from homeassistant.components.hassio.const import (
ATTR_DATA,
@ -467,34 +470,40 @@ async def test_update_addon_with_backup(
(
{
"backup-1": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-10T04:45:00+01:00",
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-2": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
with_automatic_settings=False,
spec=ManagerBackup,
),
"backup-3": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
extra_metadata={"supervisor.addon_update": "other"},
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-4": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
extra_metadata={"supervisor.addon_update": "other"},
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-5": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-11T04:45:00+01:00",
extra_metadata={"supervisor.addon_update": "test"},
with_automatic_settings=True,
spec=ManagerBackup,
),
"backup-6": MagicMock(
agents={"hassio.local": MagicMock(spec=AgentBackupStatus)},
date="2024-11-12T04:45:00+01:00",
extra_metadata={"supervisor.addon_update": "test"},
with_automatic_settings=True,