Skip to content

Commit c51bb19

Browse files
mdegat01Copilot
andcommitted
Fix partial backup/restore API to remap addons key to apps
The external API accepts `addons` as the request body key (since ATTR_APPS = "addons"), but do_backup_partial and do_restore_partial now take an `apps` parameter after the rename. The **body expansion in both endpoints would pass `addons=...` causing a TypeError. Remap the key before expansion in both backup_partial and restore_partial: if ATTR_APPS in body: body["apps"] = body.pop(ATTR_APPS) Also adds test_restore_partial_with_addons_key to verify the restore path correctly receives apps= when addons is passed in the request body. This path had no existing test coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ba5899e commit c51bb19

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

supervisor/api/backups.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,8 @@ async def backup_partial(self, request: web.Request):
335335
if body.get(ATTR_APPS) == ALL_ADDONS_FLAG:
336336
body[ATTR_APPS] = list(self.sys_apps.local)
337337

338+
if ATTR_APPS in body:
339+
body["apps"] = body.pop(ATTR_APPS)
338340
background = body.pop(ATTR_BACKGROUND)
339341
backup_task, job_id = await background_task(
340342
self, self.sys_backups.do_backup_partial, **body
@@ -380,6 +382,8 @@ async def restore_partial(self, request: web.Request):
380382
request, body.get(ATTR_LOCATION, backup.location)
381383
)
382384
background = body.pop(ATTR_BACKGROUND)
385+
if ATTR_APPS in body:
386+
body["apps"] = body.pop(ATTR_APPS)
383387
restore_task, job_id = await background_task(
384388
self, self.sys_backups.do_restore_partial, backup, **body
385389
)

tests/api/test_backups.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from supervisor.addons.addon import App
1616
from supervisor.backups.backup import Backup, BackupLocation
17+
from supervisor.backups.manager import BackupManager
1718
from supervisor.const import CoreState
1819
from supervisor.coresys import CoreSys
1920
from supervisor.docker.manager import DockerAPI
@@ -1535,3 +1536,28 @@ async def test_pre_post_backup_command_error(
15351536
"exit_code": 1,
15361537
"debug_logging_command": "ha supervisor options --logging debug",
15371538
}
1539+
1540+
1541+
async def test_restore_partial_with_addons_key(
1542+
api_client: TestClient,
1543+
coresys: CoreSys,
1544+
mock_partial_backup: Backup,
1545+
):
1546+
"""Test that partial restore accepts 'addons' key in request body and remaps it to 'apps'."""
1547+
await coresys.core.set_state(CoreState.RUNNING)
1548+
coresys.hardware.disk.get_disk_free_space = lambda x: 5000
1549+
1550+
with patch.object(
1551+
BackupManager, "do_restore_partial", return_value=True
1552+
) as mock_restore:
1553+
resp = await api_client.post(
1554+
f"/backups/{mock_partial_backup.slug}/restore/partial",
1555+
json={"addons": ["local_ssh"]},
1556+
)
1557+
1558+
assert resp.status == 200
1559+
mock_restore.assert_called_once()
1560+
_, call_kwargs = mock_restore.call_args
1561+
assert "apps" in call_kwargs
1562+
assert call_kwargs["apps"] == ["local_ssh"]
1563+
assert "addons" not in call_kwargs

0 commit comments

Comments
 (0)