Improve backup upload location determination (#5848)

* Improve backup upload location determination

For local backup upload locations, check if the location is on the same
file system an thuse allows to move the backup file after upload. This
allows custom backup mounts. Currently there is no documented,
persistent way to create such mounts in with Home Assistant OS
installations, but since we might add local mounts in the future this
seems a worthwhile addition.

Fixes: #5837

* Fix pytests
This commit is contained in:
Stefan Agner
2025-04-29 16:14:20 +02:00
committed by GitHub
parent 8e714072c2
commit c1b45406d6
3 changed files with 83 additions and 6 deletions

View File

@@ -5,6 +5,7 @@ import errno
from functools import partial
from pathlib import Path
from shutil import copy, rmtree
from types import SimpleNamespace
from unittest.mock import ANY, AsyncMock, MagicMock, Mock, PropertyMock, patch
from awesomeversion import AwesomeVersion
@@ -2122,3 +2123,63 @@ async def test_backup_multiple_locations_oserror(
assert (
UnhealthyReason.OSERROR_BAD_MESSAGE in coresys.resolution.unhealthy
) is unhealthy
@pytest.mark.parametrize("same_mount", [True, False])
async def test_get_upload_path_for_backup_location(
coresys: CoreSys,
same_mount,
):
"""Test get_upload_path_for_location with local backup location."""
manager = BackupManager(coresys)
target_path = coresys.config.path_backup
tmp_path = coresys.config.path_tmp
def make_stat_mock(target_path: Path, tmp_path: Path, same_mount: bool):
def _mock_stat(self):
if self == target_path:
return SimpleNamespace(st_dev=1)
if self == tmp_path:
return SimpleNamespace(st_dev=1 if same_mount else 2)
raise ValueError(f"Unexpected path: {self}")
return _mock_stat
with patch(
"pathlib.Path.stat", new=make_stat_mock(target_path, tmp_path, same_mount)
):
result = await manager.get_upload_path_for_location(None)
if same_mount:
assert result == tmp_path
else:
assert result == target_path
async def test_get_upload_path_for_mount_location(
coresys: CoreSys,
tmp_supervisor_data,
path_extern,
mount_propagation,
mock_is_mount,
):
"""Test get_upload_path_for_location with a Mount location."""
manager = BackupManager(coresys)
await coresys.mounts.load()
mount = Mount.from_dict(
coresys,
{
"name": "test_mount",
"usage": "backup",
"type": "cifs",
"server": "server.local",
"share": "test",
},
)
await coresys.mounts.create_mount(mount)
result = await manager.get_upload_path_for_location(mount)
assert result == mount.local_where