"""Test backups API.""" import asyncio from pathlib import Path, PurePath from unittest.mock import AsyncMock, patch from aiohttp.test_utils import TestClient from awesomeversion import AwesomeVersion import pytest from supervisor.backups.backup import Backup from supervisor.const import CoreState from supervisor.coresys import CoreSys from supervisor.mounts.mount import Mount async def test_info(api_client, coresys: CoreSys, mock_full_backup: Backup): """Test info endpoint.""" resp = await api_client.get("/backups/info") result = await resp.json() assert result["data"]["days_until_stale"] == 30 assert len(result["data"]["backups"]) == 1 assert result["data"]["backups"][0]["slug"] == "test" assert result["data"]["backups"][0]["content"]["homeassistant"] is True assert len(result["data"]["backups"][0]["content"]["addons"]) == 1 assert result["data"]["backups"][0]["content"]["addons"][0] == "local_ssh" async def test_list(api_client, coresys: CoreSys, mock_full_backup: Backup): """Test list endpoint.""" resp = await api_client.get("/backups") result = await resp.json() assert len(result["data"]["backups"]) == 1 assert result["data"]["backups"][0]["slug"] == "test" assert result["data"]["backups"][0]["content"]["homeassistant"] is True assert len(result["data"]["backups"][0]["content"]["addons"]) == 1 assert result["data"]["backups"][0]["content"]["addons"][0] == "local_ssh" async def test_options(api_client, coresys: CoreSys): """Test options endpoint.""" assert coresys.backups.days_until_stale == 30 with patch.object(type(coresys.backups), "save_data") as save_data: await api_client.post( "/backups/options", json={ "days_until_stale": 10, }, ) save_data.assert_called_once() assert coresys.backups.days_until_stale == 10 @pytest.mark.parametrize( "location,backup_dir", [("backup_test", PurePath("mounts", "backup_test")), (None, PurePath("backup"))], ) async def test_backup_to_location( api_client: TestClient, coresys: CoreSys, location: str | None, backup_dir: PurePath, tmp_supervisor_data: Path, path_extern, mount_propagation, ): """Test making a backup to a specific location with default mount.""" await coresys.mounts.load() (coresys.config.path_mounts / "backup_test").mkdir() mount = Mount.from_dict( coresys, { "name": "backup_test", "type": "cifs", "usage": "backup", "server": "backup.local", "share": "backups", }, ) await coresys.mounts.create_mount(mount) coresys.mounts.default_backup_mount = mount coresys.core.state = CoreState.RUNNING coresys.hardware.disk.get_disk_free_space = lambda x: 5000 resp = await api_client.post( "/backups/new/full", json={ "name": "Mount test", "location": location, }, ) result = await resp.json() assert result["result"] == "ok" slug = result["data"]["slug"] assert (tmp_supervisor_data / backup_dir / f"{slug}.tar").exists() resp = await api_client.get(f"/backups/{slug}/info") result = await resp.json() assert result["result"] == "ok" assert result["data"]["location"] == location async def test_backup_to_default( api_client: TestClient, coresys: CoreSys, tmp_supervisor_data, path_extern, mount_propagation, ): """Test making backup to default mount.""" await coresys.mounts.load() (mount_dir := coresys.config.path_mounts / "backup_test").mkdir() mount = Mount.from_dict( coresys, { "name": "backup_test", "type": "cifs", "usage": "backup", "server": "backup.local", "share": "backups", }, ) await coresys.mounts.create_mount(mount) coresys.mounts.default_backup_mount = mount coresys.core.state = CoreState.RUNNING coresys.hardware.disk.get_disk_free_space = lambda x: 5000 resp = await api_client.post( "/backups/new/full", json={"name": "Mount test"}, ) result = await resp.json() assert result["result"] == "ok" slug = result["data"]["slug"] assert (mount_dir / f"{slug}.tar").exists() async def test_api_freeze_thaw( api_client: TestClient, coresys: CoreSys, ha_ws_client: AsyncMock, tmp_supervisor_data, path_extern, ): """Test manual freeze and thaw for external backup via API.""" coresys.core.state = CoreState.RUNNING coresys.hardware.disk.get_disk_free_space = lambda x: 5000 ha_ws_client.ha_version = AwesomeVersion("2022.1.0") await api_client.post("/backups/freeze") assert coresys.core.state == CoreState.FREEZE await asyncio.sleep(0) assert any( call.args[0] == {"type": "backup/start"} for call in ha_ws_client.async_send_command.call_args_list ) ha_ws_client.async_send_command.reset_mock() await api_client.post("/backups/thaw") assert coresys.core.state == CoreState.RUNNING await asyncio.sleep(0) assert any( call.args[0] == {"type": "backup/end"} for call in ha_ws_client.async_send_command.call_args_list )