core/tests/components/backup/test_manager.py

270 lines
7.8 KiB
Python
Raw Normal View History

"""Tests for the Backup integration."""
2022-03-15 21:46:02 +00:00
from __future__ import annotations
from pathlib import Path
2022-03-15 21:46:02 +00:00
from unittest.mock import AsyncMock, MagicMock, Mock, patch
import pytest
from homeassistant.components.backup import BackupManager
2022-03-15 21:46:02 +00:00
from homeassistant.components.backup.manager import BackupPlatformProtocol
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
2022-03-15 21:46:02 +00:00
from homeassistant.setup import async_setup_component
from .common import TEST_BACKUP
2022-03-15 21:46:02 +00:00
from tests.common import MockPlatform, mock_platform
async def _mock_backup_generation(manager: BackupManager):
"""Mock backup generator."""
def _mock_iterdir(path: Path) -> list[Path]:
if not path.name.endswith("testing_config"):
return []
return [
Path("test.txt"),
Path(".DS_Store"),
Path(".storage"),
]
with patch("tarfile.open", MagicMock()) as mocked_tarfile, patch(
"pathlib.Path.iterdir", _mock_iterdir
), patch("pathlib.Path.stat", MagicMock(st_size=123)), patch(
"pathlib.Path.is_file", lambda x: x.name != ".storage"
), patch(
"pathlib.Path.is_dir",
lambda x: x.name == ".storage",
), patch(
"pathlib.Path.exists",
lambda x: x != manager.backup_dir,
), patch(
"pathlib.Path.is_symlink",
lambda _: False,
), patch(
"pathlib.Path.mkdir",
MagicMock(),
), patch(
"homeassistant.components.backup.manager.json_util.save_json"
) as mocked_json_util, patch(
"homeassistant.components.backup.manager.HAVERSION",
"2025.1.0",
):
await manager.generate_backup()
assert mocked_json_util.call_count == 1
assert mocked_json_util.call_args[0][1]["homeassistant"] == {
"version": "2025.1.0"
}
assert (
manager.backup_dir.as_posix()
in mocked_tarfile.call_args_list[0].kwargs["name"]
)
async def _setup_mock_domain(
hass: HomeAssistant,
platform: BackupPlatformProtocol | None = None,
) -> None:
"""Set up a mock domain."""
mock_platform(hass, "some_domain.backup", platform or MockPlatform())
assert await async_setup_component(hass, "some_domain", {})
async def test_constructor(hass: HomeAssistant) -> None:
"""Test BackupManager constructor."""
manager = BackupManager(hass)
assert manager.backup_dir.as_posix() == hass.config.path("backups")
async def test_load_backups(hass: HomeAssistant) -> None:
"""Test loading backups."""
manager = BackupManager(hass)
with patch("pathlib.Path.glob", return_value=[TEST_BACKUP.path]), patch(
"tarfile.open", return_value=MagicMock()
), patch(
"json.loads",
return_value={
"slug": TEST_BACKUP.slug,
"name": TEST_BACKUP.name,
"date": TEST_BACKUP.date,
},
), patch(
"pathlib.Path.stat", return_value=MagicMock(st_size=TEST_BACKUP.size)
):
await manager.load_backups()
backups = await manager.get_backups()
assert backups == {TEST_BACKUP.slug: TEST_BACKUP}
async def test_load_backups_with_exception(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test loading backups with exception."""
manager = BackupManager(hass)
with patch("pathlib.Path.glob", return_value=[TEST_BACKUP.path]), patch(
"tarfile.open", side_effect=OSError("Test ecxeption")
):
await manager.load_backups()
backups = await manager.get_backups()
assert f"Unable to read backup {TEST_BACKUP.path}: Test ecxeption" in caplog.text
assert backups == {}
async def test_removing_backup(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test removing backup."""
manager = BackupManager(hass)
manager.backups = {TEST_BACKUP.slug: TEST_BACKUP}
2022-03-15 21:46:02 +00:00
manager.loaded_backups = True
with patch("pathlib.Path.exists", return_value=True):
await manager.remove_backup(TEST_BACKUP.slug)
assert "Removed backup located at" in caplog.text
async def test_removing_non_existing_backup(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test removing not existing backup."""
manager = BackupManager(hass)
await manager.remove_backup("non_existing")
assert "Removed backup located at" not in caplog.text
async def test_getting_backup_that_does_not_exist(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
):
"""Test getting backup that does not exist."""
manager = BackupManager(hass)
manager.backups = {TEST_BACKUP.slug: TEST_BACKUP}
2022-03-15 21:46:02 +00:00
manager.loaded_backups = True
with patch("pathlib.Path.exists", return_value=False):
backup = await manager.get_backup(TEST_BACKUP.slug)
assert backup is None
assert (
f"Removing tracked backup ({TEST_BACKUP.slug}) that "
f"does not exists on the expected path {TEST_BACKUP.path}" in caplog.text
)
async def test_generate_backup_when_backing_up(hass: HomeAssistant) -> None:
"""Test generate backup."""
manager = BackupManager(hass)
manager.backing_up = True
with pytest.raises(HomeAssistantError, match="Backup already in progress"):
await manager.generate_backup()
async def test_generate_backup(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test generate backup."""
manager = BackupManager(hass)
2022-03-15 21:46:02 +00:00
manager.loaded_backups = True
2022-03-15 21:46:02 +00:00
await _mock_backup_generation(manager)
2022-03-15 21:46:02 +00:00
assert "Generated new backup with slug " in caplog.text
assert "Creating backup directory" in caplog.text
assert "Loaded 0 platforms" in caplog.text
2022-03-15 21:46:02 +00:00
async def test_loading_platforms(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test loading backup platforms."""
manager = BackupManager(hass)
2022-03-15 21:46:02 +00:00
assert not manager.loaded_platforms
assert not manager.platforms
await _setup_mock_domain(
hass,
Mock(
async_pre_backup=AsyncMock(),
async_post_backup=AsyncMock(),
),
)
await manager.load_platforms()
assert manager.loaded_platforms
assert len(manager.platforms) == 1
assert "Loaded 1 platforms" in caplog.text
async def test_not_loading_bad_platforms(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test loading backup platforms."""
manager = BackupManager(hass)
assert not manager.loaded_platforms
assert not manager.platforms
await _setup_mock_domain(hass)
await manager.load_platforms()
assert manager.loaded_platforms
assert len(manager.platforms) == 0
assert "Loaded 0 platforms" in caplog.text
assert (
"some_domain does not implement required functions for the backup platform"
in caplog.text
)
async def test_exception_plaform_pre(hass: HomeAssistant) -> None:
"""Test exception in pre step."""
manager = BackupManager(hass)
manager.loaded_backups = True
async def _mock_step(hass: HomeAssistant) -> None:
raise HomeAssistantError("Test exception")
await _setup_mock_domain(
hass,
Mock(
async_pre_backup=_mock_step,
async_post_backup=AsyncMock(),
),
)
with pytest.raises(HomeAssistantError):
await _mock_backup_generation(manager)
async def test_exception_plaform_post(hass: HomeAssistant) -> None:
"""Test exception in post step."""
manager = BackupManager(hass)
manager.loaded_backups = True
async def _mock_step(hass: HomeAssistant) -> None:
raise HomeAssistantError("Test exception")
await _setup_mock_domain(
hass,
Mock(
async_pre_backup=AsyncMock(),
async_post_backup=_mock_step,
),
)
with pytest.raises(HomeAssistantError):
await _mock_backup_generation(manager)