Skip to content

Commit d44e995

Browse files
authored
Add size in bytes to backups (#5473)
1 parent 5a22599 commit d44e995

File tree

5 files changed

+53
-6
lines changed

5 files changed

+53
-6
lines changed

supervisor/api/backups.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
ATTR_ADDITIONAL_LOCATIONS,
5555
ATTR_BACKGROUND,
5656
ATTR_LOCATIONS,
57+
ATTR_SIZE_BYTES,
5758
CONTENT_TYPE_TAR,
5859
)
5960
from .utils import api_process, api_validate
@@ -145,6 +146,7 @@ def _list_backups(self):
145146
ATTR_DATE: backup.date,
146147
ATTR_TYPE: backup.sys_type,
147148
ATTR_SIZE: backup.size,
149+
ATTR_SIZE_BYTES: backup.size_bytes,
148150
ATTR_LOCATION: backup.location,
149151
ATTR_LOCATIONS: backup.locations,
150152
ATTR_PROTECTED: backup.protected,
@@ -216,6 +218,7 @@ async def backup_info(self, request):
216218
ATTR_NAME: backup.name,
217219
ATTR_DATE: backup.date,
218220
ATTR_SIZE: backup.size,
221+
ATTR_SIZE_BYTES: backup.size_bytes,
219222
ATTR_COMPRESSED: backup.compressed,
220223
ATTR_PROTECTED: backup.protected,
221224
ATTR_SUPERVISOR_VERSION: backup.supervisor_version,

supervisor/api/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
ATTR_SAFE_MODE = "safe_mode"
6060
ATTR_SEAT = "seat"
6161
ATTR_SIGNED = "signed"
62+
ATTR_SIZE_BYTES = "size_bytes"
6263
ATTR_STARTUP_TIME = "startup_time"
6364
ATTR_STATUS = "status"
6465
ATTR_SUBSYSTEM = "subsystem"

supervisor/backups/backup.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from collections.abc import Awaitable
77
from copy import deepcopy
88
from datetime import timedelta
9+
from functools import cached_property
910
import io
1011
import json
1112
import logging
@@ -213,12 +214,17 @@ def locations(self) -> list[str | None]:
213214
key=location_sort_key,
214215
)
215216

216-
@property
217+
@cached_property
217218
def size(self) -> float:
218219
"""Return backup size."""
220+
return round(self.size_bytes / 1048576, 2) # calc mbyte
221+
222+
@cached_property
223+
def size_bytes(self) -> int:
224+
"""Return backup size in bytes."""
219225
if not self.tarfile.is_file():
220226
return 0
221-
return round(self.tarfile.stat().st_size / 1048576, 2) # calc mbyte
227+
return self.tarfile.stat().st_size
222228

223229
@property
224230
def is_new(self) -> bool:

tests/api/test_backups.py

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

2727

28-
async def test_info(api_client, coresys: CoreSys, mock_full_backup: Backup):
28+
async def test_info(
29+
api_client, coresys: CoreSys, mock_full_backup: Backup, tmp_path: Path
30+
):
2931
"""Test info endpoint."""
32+
copy(get_fixture_path("backup_example.tar"), tmp_path / "test_backup.tar")
33+
3034
resp = await api_client.get("/backups/info")
3135
result = await resp.json()
3236
assert result["data"]["days_until_stale"] == 30
@@ -35,17 +39,47 @@ async def test_info(api_client, coresys: CoreSys, mock_full_backup: Backup):
3539
assert result["data"]["backups"][0]["content"]["homeassistant"] is True
3640
assert len(result["data"]["backups"][0]["content"]["addons"]) == 1
3741
assert result["data"]["backups"][0]["content"]["addons"][0] == "local_ssh"
42+
assert result["data"]["backups"][0]["size"] == 0.01
43+
assert result["data"]["backups"][0]["size_bytes"] == 10240
44+
3845

46+
async def test_backup_more_info(
47+
api_client, coresys: CoreSys, mock_full_backup: Backup, tmp_path: Path
48+
):
49+
"""Test info endpoint."""
50+
copy(get_fixture_path("backup_example.tar"), tmp_path / "test_backup.tar")
3951

40-
async def test_list(api_client, coresys: CoreSys, mock_full_backup: Backup):
52+
resp = await api_client.get("/backups/test/info")
53+
result = await resp.json()
54+
assert result["data"]["slug"] == "test"
55+
assert result["data"]["homeassistant"] == "2022.8.0"
56+
assert len(result["data"]["addons"]) == 1
57+
assert result["data"]["addons"][0] == {
58+
"name": "SSH",
59+
"size": 0,
60+
"slug": "local_ssh",
61+
"version": "1.0.0",
62+
}
63+
assert result["data"]["size"] == 0.01
64+
assert result["data"]["size_bytes"] == 10240
65+
assert result["data"]["homeassistant_exclude_database"] is False
66+
67+
68+
async def test_list(
69+
api_client, coresys: CoreSys, mock_full_backup: Backup, tmp_path: Path
70+
):
4171
"""Test list endpoint."""
72+
copy(get_fixture_path("backup_example.tar"), tmp_path / "test_backup.tar")
73+
4274
resp = await api_client.get("/backups")
4375
result = await resp.json()
4476
assert len(result["data"]["backups"]) == 1
4577
assert result["data"]["backups"][0]["slug"] == "test"
4678
assert result["data"]["backups"][0]["content"]["homeassistant"] is True
4779
assert len(result["data"]["backups"][0]["content"]["addons"]) == 1
4880
assert result["data"]["backups"][0]["content"]["addons"][0] == "local_ssh"
81+
assert result["data"]["backups"][0]["size"] == 0.01
82+
assert result["data"]["backups"][0]["size_bytes"] == 10240
4983

5084

5185
async def test_options(api_client, coresys: CoreSys):

tests/conftest.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
ATTR_ADDONS,
3131
ATTR_ADDONS_CUSTOM_LIST,
3232
ATTR_DATE,
33+
ATTR_EXCLUDE_DATABASE,
3334
ATTR_FOLDERS,
3435
ATTR_HOMEASSISTANT,
3536
ATTR_NAME,
@@ -580,7 +581,7 @@ def install_addon_example(coresys: CoreSys, repository):
580581
@pytest.fixture
581582
async def mock_full_backup(coresys: CoreSys, tmp_path) -> Backup:
582583
"""Mock a full backup."""
583-
mock_backup = Backup(coresys, Path(tmp_path, "test_backup"), "test", None)
584+
mock_backup = Backup(coresys, Path(tmp_path, "test_backup.tar"), "test", None)
584585
mock_backup.new("Test", utcnow().isoformat(), BackupType.FULL)
585586
mock_backup.repositories = ["https://github.com/awesome-developer/awesome-repo"]
586587
mock_backup.docker = {}
@@ -596,6 +597,7 @@ async def mock_full_backup(coresys: CoreSys, tmp_path) -> Backup:
596597
mock_backup._data[ATTR_HOMEASSISTANT] = {
597598
ATTR_VERSION: AwesomeVersion("2022.8.0"),
598599
ATTR_SIZE: 0,
600+
ATTR_EXCLUDE_DATABASE: False,
599601
}
600602
coresys.backups._backups = {"test": mock_backup}
601603
yield mock_backup
@@ -604,7 +606,7 @@ async def mock_full_backup(coresys: CoreSys, tmp_path) -> Backup:
604606
@pytest.fixture
605607
async def mock_partial_backup(coresys: CoreSys, tmp_path) -> Backup:
606608
"""Mock a partial backup."""
607-
mock_backup = Backup(coresys, Path(tmp_path, "test_backup"), "test", None)
609+
mock_backup = Backup(coresys, Path(tmp_path, "test_backup.tar"), "test", None)
608610
mock_backup.new("Test", utcnow().isoformat(), BackupType.PARTIAL)
609611
mock_backup.repositories = ["https://github.com/awesome-developer/awesome-repo"]
610612
mock_backup.docker = {}
@@ -620,6 +622,7 @@ async def mock_partial_backup(coresys: CoreSys, tmp_path) -> Backup:
620622
mock_backup._data[ATTR_HOMEASSISTANT] = {
621623
ATTR_VERSION: AwesomeVersion("2022.8.0"),
622624
ATTR_SIZE: 0,
625+
ATTR_EXCLUDE_DATABASE: False,
623626
}
624627
coresys.backups._backups = {"test": mock_backup}
625628
yield mock_backup

0 commit comments

Comments
 (0)