Skip to content

Commit 90590ae

Browse files
authored
Add all addons flag to partial backups (#5490)
1 parent 5e6bef7 commit 90590ae

File tree

2 files changed

+49
-41
lines changed

2 files changed

+49
-41
lines changed

supervisor/api/backups.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161

6262
_LOGGER: logging.Logger = logging.getLogger(__name__)
6363

64+
ALL_ADDONS_FLAG = "ALL"
65+
6466
RE_SLUGIFY_NAME = re.compile(r"[^A-Za-z0-9]+")
6567
RE_BACKUP_FILENAME = re.compile(r"^[^\\\/]+\.tar$")
6668

@@ -108,7 +110,9 @@ def _ensure_list(item: Any) -> list:
108110

109111
SCHEMA_BACKUP_PARTIAL = SCHEMA_BACKUP_FULL.extend(
110112
{
111-
vol.Optional(ATTR_ADDONS): vol.All([str], vol.Unique()),
113+
vol.Optional(ATTR_ADDONS): vol.Or(
114+
ALL_ADDONS_FLAG, vol.All([str], vol.Unique())
115+
),
112116
vol.Optional(ATTR_FOLDERS): vol.All([vol.In(_ALL_FOLDERS)], vol.Unique()),
113117
vol.Optional(ATTR_HOMEASSISTANT): vol.Boolean(),
114118
}
@@ -352,6 +356,9 @@ async def backup_partial(self, request: web.Request):
352356
if locations:
353357
body[ATTR_ADDITIONAL_LOCATIONS] = locations
354358

359+
if body.get(ATTR_ADDONS) == ALL_ADDONS_FLAG:
360+
body[ATTR_ADDONS] = list(self.sys_addons.local)
361+
355362
background = body.pop(ATTR_BACKGROUND)
356363
backup_task, job_id = await self._background_backup_task(
357364
self.sys_backups.do_backup_partial, **body

tests/api/test_backups.py

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@
2525
from tests.const import TEST_ADDON_SLUG
2626

2727

28-
async def test_info(
29-
api_client, coresys: CoreSys, mock_full_backup: Backup, tmp_path: Path
30-
):
28+
@pytest.mark.usefixtures("mock_full_backup")
29+
async def test_info(api_client: TestClient, coresys: CoreSys, tmp_path: Path):
3130
"""Test info endpoint."""
3231
copy(get_fixture_path("backup_example.tar"), tmp_path / "test_backup.tar")
3332

@@ -43,8 +42,9 @@ async def test_info(
4342
assert result["data"]["backups"][0]["size_bytes"] == 10240
4443

4544

45+
@pytest.mark.usefixtures("mock_full_backup")
4646
async def test_backup_more_info(
47-
api_client, coresys: CoreSys, mock_full_backup: Backup, tmp_path: Path
47+
api_client: TestClient, coresys: CoreSys, tmp_path: Path
4848
):
4949
"""Test info endpoint."""
5050
copy(get_fixture_path("backup_example.tar"), tmp_path / "test_backup.tar")
@@ -65,9 +65,8 @@ async def test_backup_more_info(
6565
assert result["data"]["homeassistant_exclude_database"] is False
6666

6767

68-
async def test_list(
69-
api_client, coresys: CoreSys, mock_full_backup: Backup, tmp_path: Path
70-
):
68+
@pytest.mark.usefixtures("mock_full_backup")
69+
async def test_list(api_client: TestClient, coresys: CoreSys, tmp_path: Path):
7170
"""Test list endpoint."""
7271
copy(get_fixture_path("backup_example.tar"), tmp_path / "test_backup.tar")
7372

@@ -82,7 +81,7 @@ async def test_list(
8281
assert result["data"]["backups"][0]["size_bytes"] == 10240
8382

8483

85-
async def test_options(api_client, coresys: CoreSys):
84+
async def test_options(api_client: TestClient, coresys: CoreSys):
8685
"""Test options endpoint."""
8786
assert coresys.backups.days_until_stale == 30
8887

@@ -102,15 +101,13 @@ async def test_options(api_client, coresys: CoreSys):
102101
"location,backup_dir",
103102
[("backup_test", PurePath("mounts", "backup_test")), (None, PurePath("backup"))],
104103
)
104+
@pytest.mark.usefixtures("path_extern", "mount_propagation", "mock_is_mount")
105105
async def test_backup_to_location(
106106
api_client: TestClient,
107107
coresys: CoreSys,
108108
location: str | None,
109109
backup_dir: PurePath,
110110
tmp_supervisor_data: Path,
111-
path_extern,
112-
mount_propagation,
113-
mock_is_mount,
114111
):
115112
"""Test making a backup to a specific location with default mount."""
116113
await coresys.mounts.load()
@@ -149,14 +146,10 @@ async def test_backup_to_location(
149146
assert result["data"]["location"] == location
150147

151148

152-
async def test_backup_to_default(
153-
api_client: TestClient,
154-
coresys: CoreSys,
155-
tmp_supervisor_data,
156-
path_extern,
157-
mount_propagation,
158-
mock_is_mount,
159-
):
149+
@pytest.mark.usefixtures(
150+
"tmp_supervisor_data", "path_extern", "mount_propagation", "mock_is_mount"
151+
)
152+
async def test_backup_to_default(api_client: TestClient, coresys: CoreSys):
160153
"""Test making backup to default mount."""
161154
await coresys.mounts.load()
162155
(mount_dir := coresys.config.path_mounts / "backup_test").mkdir()
@@ -186,12 +179,9 @@ async def test_backup_to_default(
186179
assert (mount_dir / f"{slug}.tar").exists()
187180

188181

182+
@pytest.mark.usefixtures("tmp_supervisor_data", "path_extern")
189183
async def test_api_freeze_thaw(
190-
api_client: TestClient,
191-
coresys: CoreSys,
192-
ha_ws_client: AsyncMock,
193-
tmp_supervisor_data,
194-
path_extern,
184+
api_client: TestClient, coresys: CoreSys, ha_ws_client: AsyncMock
195185
):
196186
"""Test manual freeze and thaw for external backup via API."""
197187
coresys.core.state = CoreState.RUNNING
@@ -220,13 +210,12 @@ async def test_api_freeze_thaw(
220210
"partial_backup,exclude_db_setting",
221211
[(False, True), (True, True), (False, False), (True, False)],
222212
)
213+
@pytest.mark.usefixtures("tmp_supervisor_data", "path_extern")
223214
async def test_api_backup_exclude_database(
224215
api_client: TestClient,
225216
coresys: CoreSys,
226217
partial_backup: bool,
227218
exclude_db_setting: bool,
228-
tmp_supervisor_data,
229-
path_extern,
230219
):
231220
"""Test backups exclude the database when specified."""
232221
coresys.core.state = CoreState.RUNNING
@@ -268,13 +257,13 @@ async def _get_job_info(api_client: TestClient, job_id: str) -> dict[str, Any]:
268257
),
269258
],
270259
)
260+
@pytest.mark.usefixtures("path_extern")
271261
async def test_api_backup_restore_background(
272262
api_client: TestClient,
273263
coresys: CoreSys,
274264
backup_type: str,
275265
options: dict[str, Any],
276266
tmp_supervisor_data: Path,
277-
path_extern,
278267
):
279268
"""Test background option on backup/restore APIs."""
280269
coresys.core.state = CoreState.RUNNING
@@ -354,14 +343,13 @@ async def test_api_backup_restore_background(
354343
),
355344
],
356345
)
346+
@pytest.mark.usefixtures("install_addon_ssh", "path_extern")
357347
async def test_api_backup_errors(
358348
api_client: TestClient,
359349
coresys: CoreSys,
360350
backup_type: str,
361351
options: dict[str, Any],
362352
tmp_supervisor_data: Path,
363-
install_addon_ssh,
364-
path_extern,
365353
):
366354
"""Test error reporting in backup job."""
367355
coresys.core.state = CoreState.RUNNING
@@ -604,14 +592,13 @@ async def test_upload_download(
604592
assert backup == out_backup
605593

606594

607-
@pytest.mark.usefixtures("path_extern")
595+
@pytest.mark.usefixtures("path_extern", "tmp_supervisor_data")
608596
@pytest.mark.parametrize(
609597
("backup_type", "inputs"), [("full", {}), ("partial", {"folders": ["ssl"]})]
610598
)
611599
async def test_backup_to_multiple_locations(
612600
api_client: TestClient,
613601
coresys: CoreSys,
614-
tmp_supervisor_data: Path,
615602
backup_type: str,
616603
inputs: dict[str, Any],
617604
):
@@ -643,10 +630,10 @@ async def test_backup_to_multiple_locations(
643630
@pytest.mark.parametrize(
644631
("backup_type", "inputs"), [("full", {}), ("partial", {"folders": ["ssl"]})]
645632
)
633+
@pytest.mark.usefixtures("tmp_supervisor_data")
646634
async def test_backup_with_extras(
647635
api_client: TestClient,
648636
coresys: CoreSys,
649-
tmp_supervisor_data: Path,
650637
backup_type: str,
651638
inputs: dict[str, Any],
652639
):
@@ -671,11 +658,8 @@ async def test_backup_with_extras(
671658
slug = result["data"]["extra"] == {"user": "test", "scheduled": True}
672659

673660

674-
async def test_upload_to_multiple_locations(
675-
api_client: TestClient,
676-
coresys: CoreSys,
677-
tmp_supervisor_data: Path,
678-
):
661+
@pytest.mark.usefixtures("tmp_supervisor_data")
662+
async def test_upload_to_multiple_locations(api_client: TestClient, coresys: CoreSys):
679663
"""Test uploading a backup to multiple locations."""
680664
backup_file = get_fixture_path("backup_example.tar")
681665

@@ -700,10 +684,9 @@ async def test_upload_to_multiple_locations(
700684
assert coresys.backups.get("7fed74c8").location is None
701685

702686

687+
@pytest.mark.usefixtures("tmp_supervisor_data")
703688
async def test_upload_duplicate_backup_new_location(
704-
api_client: TestClient,
705-
coresys: CoreSys,
706-
tmp_supervisor_data: Path,
689+
api_client: TestClient, coresys: CoreSys
707690
):
708691
"""Test uploading a backup that already exists to a new location."""
709692
backup_file = get_fixture_path("backup_example.tar")
@@ -809,3 +792,21 @@ async def test_download_backup_from_invalid_location(api_client: TestClient):
809792
assert resp.status == 400
810793
body = await resp.json()
811794
assert body["message"] == "Backup test is not in location .cloud_backup"
795+
796+
797+
@pytest.mark.usefixtures("tmp_supervisor_data")
798+
async def test_partial_backup_all_addons(
799+
api_client: TestClient,
800+
coresys: CoreSys,
801+
install_addon_ssh: Addon,
802+
):
803+
"""Test backup including extra metdata."""
804+
coresys.core.state = CoreState.RUNNING
805+
coresys.hardware.disk.get_disk_free_space = lambda x: 5000
806+
807+
with patch.object(Backup, "store_addons") as store_addons:
808+
resp = await api_client.post(
809+
"/backups/new/partial", json={"name": "All addons test", "addons": "ALL"}
810+
)
811+
assert resp.status == 200
812+
store_addons.assert_called_once_with([install_addon_ssh])

0 commit comments

Comments
 (0)