Backup method to aiohasupervisor

This commit is contained in:
Mike Degatano 2024-11-07 20:36:11 +00:00
parent e388e9f396
commit 645cdf5692
8 changed files with 116 additions and 173 deletions

View File

@ -116,7 +116,6 @@ from .discovery import async_setup_discovery_view # noqa: F401
from .handler import ( # noqa: F401
HassIO,
HassioAPIError,
async_create_backup,
async_get_green_settings,
async_get_yellow_settings,
async_reboot_host,

View File

@ -15,13 +15,14 @@ from aiohasupervisor.models import (
AddonsOptions,
AddonState as SupervisorAddonState,
InstalledAddonComplete,
PartialBackupOptions,
StoreAddonUpdate,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from .handler import HassioAPIError, async_create_backup, get_supervisor_client
from .handler import get_supervisor_client
type _FuncType[_T, **_P, _R] = Callable[Concatenate[_T, _P], Awaitable[_R]]
type _ReturnFuncType[_T, **_P, _R] = Callable[
@ -31,18 +32,15 @@ type _ReturnFuncType[_T, **_P, _R] = Callable[
def api_error[_AddonManagerT: AddonManager, **_P, _R](
error_message: str,
*,
expected_error_type: type[HassioAPIError | SupervisorError] | None = None,
) -> Callable[
[_FuncType[_AddonManagerT, _P, _R]], _ReturnFuncType[_AddonManagerT, _P, _R]
]:
"""Handle HassioAPIError and raise a specific AddonError."""
error_type = expected_error_type or (HassioAPIError, SupervisorError)
"""Handle SupervisorError and raise a specific AddonError."""
def handle_hassio_api_error(
def handle_supervisor_api_error(
func: _FuncType[_AddonManagerT, _P, _R],
) -> _ReturnFuncType[_AddonManagerT, _P, _R]:
"""Handle a HassioAPIError."""
"""Handle a SupervisorError."""
@wraps(func)
async def wrapper(
@ -51,7 +49,7 @@ def api_error[_AddonManagerT: AddonManager, **_P, _R](
"""Wrap an add-on manager method."""
try:
return_value = await func(self, *args, **kwargs)
except error_type as err:
except SupervisorError as err:
raise AddonError(
f"{error_message.format(addon_name=self.addon_name)}: {err}"
) from err
@ -60,7 +58,7 @@ def api_error[_AddonManagerT: AddonManager, **_P, _R](
return wrapper
return handle_hassio_api_error
return handle_supervisor_api_error
@dataclass
@ -123,10 +121,7 @@ class AddonManager:
)
)
@api_error(
"Failed to get the {addon_name} add-on discovery info",
expected_error_type=SupervisorError,
)
@api_error("Failed to get the {addon_name} add-on discovery info")
async def async_get_addon_discovery_info(self) -> dict:
"""Return add-on discovery info."""
discovery_info = next(
@ -143,10 +138,7 @@ class AddonManager:
return discovery_info.config
@api_error(
"Failed to get the {addon_name} add-on info",
expected_error_type=SupervisorError,
)
@api_error("Failed to get the {addon_name} add-on info")
async def async_get_addon_info(self) -> AddonInfo:
"""Return and cache manager add-on info."""
addon_store_info = await self._supervisor_client.store.addon_info(
@ -188,10 +180,7 @@ class AddonManager:
return addon_state
@api_error(
"Failed to set the {addon_name} add-on options",
expected_error_type=SupervisorError,
)
@api_error("Failed to set the {addon_name} add-on options")
async def async_set_addon_options(self, config: dict) -> None:
"""Set manager add-on options."""
await self._supervisor_client.addons.set_addon_options(
@ -203,9 +192,7 @@ class AddonManager:
if not addon_info.available:
raise AddonError(f"{self.addon_name} add-on is not available")
@api_error(
"Failed to install the {addon_name} add-on", expected_error_type=SupervisorError
)
@api_error("Failed to install the {addon_name} add-on")
async def async_install_addon(self) -> None:
"""Install the managed add-on."""
addon_info = await self.async_get_addon_info()
@ -214,10 +201,7 @@ class AddonManager:
await self._supervisor_client.store.install_addon(self.addon_slug)
@api_error(
"Failed to uninstall the {addon_name} add-on",
expected_error_type=SupervisorError,
)
@api_error("Failed to uninstall the {addon_name} add-on")
async def async_uninstall_addon(self) -> None:
"""Uninstall the managed add-on."""
await self._supervisor_client.addons.uninstall_addon(self.addon_slug)
@ -240,23 +224,17 @@ class AddonManager:
self.addon_slug, StoreAddonUpdate(backup=False)
)
@api_error(
"Failed to start the {addon_name} add-on", expected_error_type=SupervisorError
)
@api_error("Failed to start the {addon_name} add-on")
async def async_start_addon(self) -> None:
"""Start the managed add-on."""
await self._supervisor_client.addons.start_addon(self.addon_slug)
@api_error(
"Failed to restart the {addon_name} add-on", expected_error_type=SupervisorError
)
@api_error("Failed to restart the {addon_name} add-on")
async def async_restart_addon(self) -> None:
"""Restart the managed add-on."""
await self._supervisor_client.addons.restart_addon(self.addon_slug)
@api_error(
"Failed to stop the {addon_name} add-on", expected_error_type=SupervisorError
)
@api_error("Failed to stop the {addon_name} add-on")
async def async_stop_addon(self) -> None:
"""Stop the managed add-on."""
await self._supervisor_client.addons.stop_addon(self.addon_slug)
@ -268,10 +246,8 @@ class AddonManager:
name = f"addon_{self.addon_slug}_{addon_info.version}"
self._logger.debug("Creating backup: %s", name)
await async_create_backup(
self._hass,
{"name": name, "addons": [self.addon_slug]},
partial=True,
await self._supervisor_client.backups.partial_backup(
PartialBackupOptions(name=name, addons={self.addon_slug})
)
async def async_configure_addon(

View File

@ -76,21 +76,6 @@ async def async_update_diagnostics(hass: HomeAssistant, diagnostics: bool) -> bo
return await hassio.update_diagnostics(diagnostics)
@bind_hass
@api_data
async def async_create_backup(
hass: HomeAssistant, payload: dict, partial: bool = False
) -> dict:
"""Create a full or partial backup.
The caller of the function should handle HassioAPIError.
"""
hassio: HassIO = hass.data[DOMAIN]
backup_type = "partial" if partial else "full"
command = f"/backups/new/{backup_type}"
return await hassio.send_command(command, payload=payload, timeout=None)
@api_data
async def async_get_green_settings(hass: HomeAssistant) -> dict[str, bool]:
"""Return settings specific to Home Assistant Green."""

View File

@ -11,6 +11,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
from aiohasupervisor.models import (
Discovery,
NewBackup,
Repository,
ResolutionInfo,
StoreAddon,
@ -417,13 +418,22 @@ def uninstall_addon_fixture(supervisor_client: AsyncMock) -> AsyncMock:
return supervisor_client.addons.uninstall_addon
@pytest.fixture(name="create_backup")
def create_backup_fixture() -> Generator[AsyncMock]:
"""Mock create backup."""
# pylint: disable-next=import-outside-toplevel
from .hassio.common import mock_create_backup
@pytest.fixture(name="create_partial_backup")
def create_partial_backup_fixture(supervisor_client: AsyncMock) -> AsyncMock:
"""Mock create partial backup."""
supervisor_client.backups.partial_backup.return_value = NewBackup(
"job123", "backup123"
)
return supervisor_client.backups.partial_backup
yield from mock_create_backup()
@pytest.fixture(name="create_full_backup")
def create_backup_fixture(supervisor_client: AsyncMock) -> AsyncMock:
"""Mock create full backup."""
supervisor_client.backups.full_backup.return_value = NewBackup(
"job123", "backup123"
)
return supervisor_client.backups.full_backup
@pytest.fixture(name="update_addon")
@ -505,6 +515,7 @@ def supervisor_client() -> Generator[AsyncMock]:
"""Mock the supervisor client."""
supervisor_client = AsyncMock()
supervisor_client.addons = AsyncMock()
supervisor_client.backups = AsyncMock()
supervisor_client.discovery = AsyncMock()
supervisor_client.homeassistant = AsyncMock()
supervisor_client.os = AsyncMock()

View File

@ -2,12 +2,11 @@
from __future__ import annotations
from collections.abc import Generator
from dataclasses import fields
import logging
from types import MethodType
from typing import Any
from unittest.mock import AsyncMock, Mock, patch
from unittest.mock import AsyncMock, Mock
from aiohasupervisor.models import (
AddonsOptions,
@ -198,14 +197,6 @@ def mock_set_addon_options_side_effect(addon_options: dict[str, Any]) -> Any | N
return set_addon_options
def mock_create_backup() -> Generator[AsyncMock]:
"""Mock create backup."""
with patch(
"homeassistant.components.hassio.addon_manager.async_create_backup"
) as create_backup:
yield create_backup
def mock_addon_stats(supervisor_client: AsyncMock) -> AsyncMock:
"""Mock addon stats."""
supervisor_client.addons.addon_stats.return_value = addon_stats = Mock(

View File

@ -8,7 +8,7 @@ from unittest.mock import AsyncMock, call
from uuid import uuid4
from aiohasupervisor import SupervisorError
from aiohasupervisor.models import AddonsOptions, Discovery
from aiohasupervisor.models import AddonsOptions, Discovery, PartialBackupOptions
import pytest
from homeassistant.components.hassio.addon_manager import (
@ -17,7 +17,6 @@ from homeassistant.components.hassio.addon_manager import (
AddonManager,
AddonState,
)
from homeassistant.components.hassio.handler import HassioAPIError
from homeassistant.core import HomeAssistant
@ -502,7 +501,7 @@ async def test_update_addon(
addon_manager: AddonManager,
addon_info: AsyncMock,
addon_installed: AsyncMock,
create_backup: AsyncMock,
create_partial_backup: AsyncMock,
update_addon: AsyncMock,
) -> None:
"""Test update addon."""
@ -511,9 +510,8 @@ async def test_update_addon(
await addon_manager.async_update_addon()
assert addon_info.call_count == 2
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass, {"name": "addon_test_addon_1.0.0", "addons": ["test_addon"]}, partial=True
create_partial_backup.assert_called_once_with(
PartialBackupOptions(name="addon_test_addon_1.0.0", addons={"test_addon"})
)
assert update_addon.call_count == 1
@ -522,7 +520,7 @@ async def test_update_addon_no_update(
addon_manager: AddonManager,
addon_info: AsyncMock,
addon_installed: AsyncMock,
create_backup: AsyncMock,
create_partial_backup: AsyncMock,
update_addon: AsyncMock,
) -> None:
"""Test update addon without update available."""
@ -531,7 +529,7 @@ async def test_update_addon_no_update(
await addon_manager.async_update_addon()
assert addon_info.call_count == 1
assert create_backup.call_count == 0
assert create_partial_backup.call_count == 0
assert update_addon.call_count == 0
@ -540,7 +538,7 @@ async def test_update_addon_error(
addon_manager: AddonManager,
addon_info: AsyncMock,
addon_installed: AsyncMock,
create_backup: AsyncMock,
create_partial_backup: AsyncMock,
update_addon: AsyncMock,
) -> None:
"""Test update addon raises error."""
@ -553,9 +551,8 @@ async def test_update_addon_error(
assert str(err.value) == "Failed to update the Test add-on: Boom"
assert addon_info.call_count == 2
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass, {"name": "addon_test_addon_1.0.0", "addons": ["test_addon"]}, partial=True
create_partial_backup.assert_called_once_with(
PartialBackupOptions(name="addon_test_addon_1.0.0", addons={"test_addon"})
)
assert update_addon.call_count == 1
@ -565,7 +562,7 @@ async def test_schedule_update_addon(
addon_manager: AddonManager,
addon_info: AsyncMock,
addon_installed: AsyncMock,
create_backup: AsyncMock,
create_partial_backup: AsyncMock,
update_addon: AsyncMock,
) -> None:
"""Test schedule update addon."""
@ -591,9 +588,8 @@ async def test_schedule_update_addon(
assert addon_manager.task_in_progress() is False
assert addon_info.call_count == 3
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass, {"name": "addon_test_addon_1.0.0", "addons": ["test_addon"]}, partial=True
create_partial_backup.assert_called_once_with(
PartialBackupOptions(name="addon_test_addon_1.0.0", addons={"test_addon"})
)
assert update_addon.call_count == 1
@ -607,15 +603,15 @@ async def test_schedule_update_addon(
@pytest.mark.parametrize(
(
"create_backup_error",
"create_backup_calls",
"create_partial_backup_error",
"create_partial_backup_calls",
"update_addon_error",
"update_addon_calls",
"error_message",
),
[
(
HassioAPIError("Boom"),
SupervisorError("Boom"),
1,
None,
0,
@ -633,17 +629,17 @@ async def test_schedule_update_addon(
async def test_schedule_update_addon_error(
addon_manager: AddonManager,
addon_installed: AsyncMock,
create_backup: AsyncMock,
create_partial_backup: AsyncMock,
update_addon: AsyncMock,
create_backup_error: Exception | None,
create_backup_calls: int,
create_partial_backup_error: Exception | None,
create_partial_backup_calls: int,
update_addon_error: Exception | None,
update_addon_calls: int,
error_message: str,
) -> None:
"""Test schedule update addon raises error."""
addon_installed.return_value.update_available = True
create_backup.side_effect = create_backup_error
create_partial_backup.side_effect = create_partial_backup_error
update_addon.side_effect = update_addon_error
with pytest.raises(AddonError) as err:
@ -651,21 +647,21 @@ async def test_schedule_update_addon_error(
assert str(err.value) == error_message
assert create_backup.call_count == create_backup_calls
assert create_partial_backup.call_count == create_partial_backup_calls
assert update_addon.call_count == update_addon_calls
@pytest.mark.parametrize(
(
"create_backup_error",
"create_backup_calls",
"create_partial_backup_error",
"create_partial_backup_calls",
"update_addon_error",
"update_addon_calls",
"error_log",
),
[
(
HassioAPIError("Boom"),
SupervisorError("Boom"),
1,
None,
0,
@ -683,10 +679,10 @@ async def test_schedule_update_addon_error(
async def test_schedule_update_addon_logs_error(
addon_manager: AddonManager,
addon_installed: AsyncMock,
create_backup: AsyncMock,
create_partial_backup: AsyncMock,
update_addon: AsyncMock,
create_backup_error: Exception | None,
create_backup_calls: int,
create_partial_backup_error: Exception | None,
create_partial_backup_calls: int,
update_addon_error: Exception | None,
update_addon_calls: int,
error_log: str,
@ -694,13 +690,13 @@ async def test_schedule_update_addon_logs_error(
) -> None:
"""Test schedule update addon logs error."""
addon_installed.return_value.update_available = True
create_backup.side_effect = create_backup_error
create_partial_backup.side_effect = create_partial_backup_error
update_addon.side_effect = update_addon_error
await addon_manager.async_schedule_update_addon(catch_error=True)
assert error_log in caplog.text
assert create_backup.call_count == create_backup_calls
assert create_partial_backup.call_count == create_partial_backup_calls
assert update_addon.call_count == update_addon_calls
@ -709,15 +705,14 @@ async def test_create_backup(
addon_manager: AddonManager,
addon_info: AsyncMock,
addon_installed: AsyncMock,
create_backup: AsyncMock,
create_partial_backup: AsyncMock,
) -> None:
"""Test creating a backup of the addon."""
await addon_manager.async_create_backup()
assert addon_info.call_count == 1
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass, {"name": "addon_test_addon_1.0.0", "addons": ["test_addon"]}, partial=True
create_partial_backup.assert_called_once_with(
PartialBackupOptions(name="addon_test_addon_1.0.0", addons={"test_addon"})
)
@ -726,10 +721,10 @@ async def test_create_backup_error(
addon_manager: AddonManager,
addon_info: AsyncMock,
addon_installed: AsyncMock,
create_backup: AsyncMock,
create_partial_backup: AsyncMock,
) -> None:
"""Test creating a backup of the addon raises error."""
create_backup.side_effect = HassioAPIError("Boom")
create_partial_backup.side_effect = SupervisorError("Boom")
with pytest.raises(AddonError) as err:
await addon_manager.async_create_backup()
@ -737,9 +732,8 @@ async def test_create_backup_error(
assert str(err.value) == "Failed to create a backup of the Test add-on: Boom"
assert addon_info.call_count == 1
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass, {"name": "addon_test_addon_1.0.0", "addons": ["test_addon"]}, partial=True
create_partial_backup.assert_called_once_with(
PartialBackupOptions(name="addon_test_addon_1.0.0", addons={"test_addon"})
)

View File

@ -7,6 +7,7 @@ from collections.abc import Generator
from unittest.mock import AsyncMock, MagicMock, call, patch
from aiohasupervisor import SupervisorError
from aiohasupervisor.models import PartialBackupOptions
from matter_server.client.exceptions import (
CannotConnect,
NotConnected,
@ -16,7 +17,6 @@ from matter_server.client.exceptions import (
from matter_server.common.errors import MatterError
import pytest
from homeassistant.components.hassio import HassioAPIError
from homeassistant.components.matter.const import DOMAIN
from homeassistant.config_entries import ConfigEntryDisabler, ConfigEntryState
from homeassistant.const import STATE_UNAVAILABLE
@ -377,7 +377,7 @@ async def test_addon_info_failure(
"update_calls",
"backup_calls",
"update_addon_side_effect",
"create_backup_side_effect",
"create_partial_backup_side_effect",
"connect_side_effect",
),
[
@ -399,7 +399,7 @@ async def test_addon_info_failure(
0,
1,
None,
HassioAPIError("Boom"),
SupervisorError("Boom"),
ServerVersionTooOld("Invalid version"),
),
],
@ -411,7 +411,7 @@ async def test_update_addon(
addon_info: AsyncMock,
install_addon: AsyncMock,
start_addon: AsyncMock,
create_backup: AsyncMock,
create_partial_backup: AsyncMock,
update_addon: AsyncMock,
matter_client: MagicMock,
addon_version: str,
@ -419,13 +419,13 @@ async def test_update_addon(
update_calls: int,
backup_calls: int,
update_addon_side_effect: Exception | None,
create_backup_side_effect: Exception | None,
create_partial_backup_side_effect: Exception | None,
connect_side_effect: Exception,
) -> None:
"""Test update the Matter add-on during entry setup."""
addon_info.return_value.version = addon_version
addon_info.return_value.update_available = update_available
create_backup.side_effect = create_backup_side_effect
create_partial_backup.side_effect = create_partial_backup_side_effect
update_addon.side_effect = update_addon_side_effect
matter_client.connect.side_effect = connect_side_effect
entry = MockConfigEntry(
@ -442,7 +442,7 @@ async def test_update_addon(
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.SETUP_RETRY
assert create_backup.call_count == backup_calls
assert create_partial_backup.call_count == backup_calls
assert update_addon.call_count == update_calls
@ -548,7 +548,7 @@ async def test_remove_entry(
hass: HomeAssistant,
addon_installed: AsyncMock,
stop_addon: AsyncMock,
create_backup: AsyncMock,
create_partial_backup: AsyncMock,
uninstall_addon: AsyncMock,
caplog: pytest.LogCaptureFixture,
) -> None:
@ -581,18 +581,17 @@ async def test_remove_entry(
assert stop_addon.call_count == 1
assert stop_addon.call_args == call("core_matter_server")
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass,
{"name": "addon_core_matter_server_1.0.0", "addons": ["core_matter_server"]},
partial=True,
create_partial_backup.assert_called_once_with(
PartialBackupOptions(
name="addon_core_matter_server_1.0.0", addons={"core_matter_server"}
)
)
assert uninstall_addon.call_count == 1
assert uninstall_addon.call_args == call("core_matter_server")
assert entry.state is ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
stop_addon.reset_mock()
create_backup.reset_mock()
create_partial_backup.reset_mock()
uninstall_addon.reset_mock()
# test add-on stop failure
@ -604,38 +603,37 @@ async def test_remove_entry(
assert stop_addon.call_count == 1
assert stop_addon.call_args == call("core_matter_server")
assert create_backup.call_count == 0
assert create_partial_backup.call_count == 0
assert uninstall_addon.call_count == 0
assert entry.state is ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
assert "Failed to stop the Matter Server add-on" in caplog.text
stop_addon.side_effect = None
stop_addon.reset_mock()
create_backup.reset_mock()
create_partial_backup.reset_mock()
uninstall_addon.reset_mock()
# test create backup failure
entry.add_to_hass(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
create_backup.side_effect = HassioAPIError()
create_partial_backup.side_effect = SupervisorError()
await hass.config_entries.async_remove(entry.entry_id)
assert stop_addon.call_count == 1
assert stop_addon.call_args == call("core_matter_server")
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass,
{"name": "addon_core_matter_server_1.0.0", "addons": ["core_matter_server"]},
partial=True,
create_partial_backup.assert_called_once_with(
PartialBackupOptions(
name="addon_core_matter_server_1.0.0", addons={"core_matter_server"}
)
)
assert uninstall_addon.call_count == 0
assert entry.state is ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
assert "Failed to create a backup of the Matter Server add-on" in caplog.text
create_backup.side_effect = None
create_partial_backup.side_effect = None
stop_addon.reset_mock()
create_backup.reset_mock()
create_partial_backup.reset_mock()
uninstall_addon.reset_mock()
# test add-on uninstall failure
@ -647,11 +645,10 @@ async def test_remove_entry(
assert stop_addon.call_count == 1
assert stop_addon.call_args == call("core_matter_server")
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass,
{"name": "addon_core_matter_server_1.0.0", "addons": ["core_matter_server"]},
partial=True,
create_partial_backup.assert_called_once_with(
PartialBackupOptions(
name="addon_core_matter_server_1.0.0", addons={"core_matter_server"}
)
)
assert uninstall_addon.call_count == 1
assert uninstall_addon.call_args == call("core_matter_server")

View File

@ -6,7 +6,7 @@ import logging
from unittest.mock import AsyncMock, call, patch
from aiohasupervisor import SupervisorError
from aiohasupervisor.models import AddonsOptions
from aiohasupervisor.models import AddonsOptions, PartialBackupOptions
import pytest
from zwave_js_server.client import Client
from zwave_js_server.event import Event
@ -14,7 +14,6 @@ from zwave_js_server.exceptions import BaseZwaveJSServerError, InvalidServerVers
from zwave_js_server.model.node import Node
from zwave_js_server.model.version import VersionInfo
from homeassistant.components.hassio import HassioAPIError
from homeassistant.components.logger import DOMAIN as LOGGER_DOMAIN, SERVICE_SET_LEVEL
from homeassistant.components.persistent_notification import async_dismiss
from homeassistant.components.zwave_js import DOMAIN
@ -743,13 +742,13 @@ async def test_addon_options_changed(
"update_calls",
"backup_calls",
"update_addon_side_effect",
"create_backup_side_effect",
"create_partial_backup_side_effect",
),
[
("1.0.0", True, 1, 1, None, None),
("1.0.0", False, 0, 0, None, None),
("1.0.0", True, 1, 1, SupervisorError("Boom"), None),
("1.0.0", True, 0, 1, None, HassioAPIError("Boom")),
("1.0.0", True, 0, 1, None, SupervisorError("Boom")),
],
)
async def test_update_addon(
@ -758,7 +757,7 @@ async def test_update_addon(
addon_info,
addon_installed,
addon_running,
create_backup,
create_partial_backup,
update_addon,
addon_options,
addon_version,
@ -766,7 +765,7 @@ async def test_update_addon(
update_calls,
backup_calls,
update_addon_side_effect,
create_backup_side_effect,
create_partial_backup_side_effect,
version_state,
) -> None:
"""Test update the Z-Wave JS add-on during entry setup."""
@ -776,7 +775,7 @@ async def test_update_addon(
addon_options["network_key"] = network_key
addon_info.return_value.version = addon_version
addon_info.return_value.update_available = update_available
create_backup.side_effect = create_backup_side_effect
create_partial_backup.side_effect = create_partial_backup_side_effect
update_addon.side_effect = update_addon_side_effect
client.connect.side_effect = InvalidServerVersion(
VersionInfo("a", "b", 1, 1, 1), 1, "Invalid version"
@ -797,7 +796,7 @@ async def test_update_addon(
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.SETUP_RETRY
assert create_backup.call_count == backup_calls
assert create_partial_backup.call_count == backup_calls
assert update_addon.call_count == update_calls
@ -897,7 +896,7 @@ async def test_remove_entry(
hass: HomeAssistant,
addon_installed,
stop_addon,
create_backup,
create_partial_backup,
uninstall_addon,
caplog: pytest.LogCaptureFixture,
) -> None:
@ -930,18 +929,15 @@ async def test_remove_entry(
assert stop_addon.call_count == 1
assert stop_addon.call_args == call("core_zwave_js")
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass,
{"name": "addon_core_zwave_js_1.0.0", "addons": ["core_zwave_js"]},
partial=True,
create_partial_backup.assert_called_once_with(
PartialBackupOptions(name="addon_core_zwave_js_1.0.0", addons={"core_zwave_js"})
)
assert uninstall_addon.call_count == 1
assert uninstall_addon.call_args == call("core_zwave_js")
assert entry.state is ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
stop_addon.reset_mock()
create_backup.reset_mock()
create_partial_backup.reset_mock()
uninstall_addon.reset_mock()
# test add-on stop failure
@ -953,38 +949,35 @@ async def test_remove_entry(
assert stop_addon.call_count == 1
assert stop_addon.call_args == call("core_zwave_js")
assert create_backup.call_count == 0
assert create_partial_backup.call_count == 0
assert uninstall_addon.call_count == 0
assert entry.state is ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
assert "Failed to stop the Z-Wave JS add-on" in caplog.text
stop_addon.side_effect = None
stop_addon.reset_mock()
create_backup.reset_mock()
create_partial_backup.reset_mock()
uninstall_addon.reset_mock()
# test create backup failure
entry.add_to_hass(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
create_backup.side_effect = HassioAPIError()
create_partial_backup.side_effect = SupervisorError()
await hass.config_entries.async_remove(entry.entry_id)
assert stop_addon.call_count == 1
assert stop_addon.call_args == call("core_zwave_js")
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass,
{"name": "addon_core_zwave_js_1.0.0", "addons": ["core_zwave_js"]},
partial=True,
create_partial_backup.assert_called_once_with(
PartialBackupOptions(name="addon_core_zwave_js_1.0.0", addons={"core_zwave_js"})
)
assert uninstall_addon.call_count == 0
assert entry.state is ConfigEntryState.NOT_LOADED
assert len(hass.config_entries.async_entries(DOMAIN)) == 0
assert "Failed to create a backup of the Z-Wave JS add-on" in caplog.text
create_backup.side_effect = None
create_partial_backup.side_effect = None
stop_addon.reset_mock()
create_backup.reset_mock()
create_partial_backup.reset_mock()
uninstall_addon.reset_mock()
# test add-on uninstall failure
@ -996,11 +989,8 @@ async def test_remove_entry(
assert stop_addon.call_count == 1
assert stop_addon.call_args == call("core_zwave_js")
assert create_backup.call_count == 1
assert create_backup.call_args == call(
hass,
{"name": "addon_core_zwave_js_1.0.0", "addons": ["core_zwave_js"]},
partial=True,
create_partial_backup.assert_called_once_with(
PartialBackupOptions(name="addon_core_zwave_js_1.0.0", addons={"core_zwave_js"})
)
assert uninstall_addon.call_count == 1
assert uninstall_addon.call_args == call("core_zwave_js")