mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 09:47:13 +00:00
Remaining addon management to aiohasupervisor (#128484)
* Move set addon options to aiohasupervisor * addon stats to aiohasupervisor and test fixes * addon changelogs to aiohasupervisor * Raise correct error for library in tests * Cache client in instance property * Use singleton method rather then HassIO instance method * Mock supervisor client in more tests
This commit is contained in:
parent
9b3ac49298
commit
ad55c9cc19
@ -105,10 +105,8 @@ from .handler import ( # noqa: F401
|
|||||||
async_get_green_settings,
|
async_get_green_settings,
|
||||||
async_get_yellow_settings,
|
async_get_yellow_settings,
|
||||||
async_reboot_host,
|
async_reboot_host,
|
||||||
async_set_addon_options,
|
|
||||||
async_set_green_settings,
|
async_set_green_settings,
|
||||||
async_set_yellow_settings,
|
async_set_yellow_settings,
|
||||||
async_update_addon,
|
|
||||||
async_update_core,
|
async_update_core,
|
||||||
async_update_diagnostics,
|
async_update_diagnostics,
|
||||||
async_update_os,
|
async_update_os,
|
||||||
@ -432,6 +430,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
|
|||||||
|
|
||||||
async def update_info_data(_: datetime | None = None) -> None:
|
async def update_info_data(_: datetime | None = None) -> None:
|
||||||
"""Update last available supervisor information."""
|
"""Update last available supervisor information."""
|
||||||
|
supervisor_client = get_supervisor_client(hass)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
(
|
(
|
||||||
@ -445,7 +444,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
|
|||||||
) = await asyncio.gather(
|
) = await asyncio.gather(
|
||||||
create_eager_task(hassio.get_info()),
|
create_eager_task(hassio.get_info()),
|
||||||
create_eager_task(hassio.get_host_info()),
|
create_eager_task(hassio.get_host_info()),
|
||||||
create_eager_task(hassio.client.store.info()),
|
create_eager_task(supervisor_client.store.info()),
|
||||||
create_eager_task(hassio.get_core_info()),
|
create_eager_task(hassio.get_core_info()),
|
||||||
create_eager_task(hassio.get_supervisor_info()),
|
create_eager_task(hassio.get_supervisor_info()),
|
||||||
create_eager_task(hassio.get_os_info()),
|
create_eager_task(hassio.get_os_info()),
|
||||||
|
@ -10,10 +10,12 @@ from functools import partial, wraps
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any, Concatenate
|
from typing import Any, Concatenate
|
||||||
|
|
||||||
from aiohasupervisor import SupervisorClient, SupervisorError
|
from aiohasupervisor import SupervisorError
|
||||||
from aiohasupervisor.models import (
|
from aiohasupervisor.models import (
|
||||||
|
AddonsOptions,
|
||||||
AddonState as SupervisorAddonState,
|
AddonState as SupervisorAddonState,
|
||||||
InstalledAddonComplete,
|
InstalledAddonComplete,
|
||||||
|
StoreAddonUpdate,
|
||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
@ -23,8 +25,6 @@ from .handler import (
|
|||||||
HassioAPIError,
|
HassioAPIError,
|
||||||
async_create_backup,
|
async_create_backup,
|
||||||
async_get_addon_discovery_info,
|
async_get_addon_discovery_info,
|
||||||
async_set_addon_options,
|
|
||||||
async_update_addon,
|
|
||||||
get_supervisor_client,
|
get_supervisor_client,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,10 +36,13 @@ type _ReturnFuncType[_T, **_P, _R] = Callable[
|
|||||||
|
|
||||||
def api_error[_AddonManagerT: AddonManager, **_P, _R](
|
def api_error[_AddonManagerT: AddonManager, **_P, _R](
|
||||||
error_message: str,
|
error_message: str,
|
||||||
|
*,
|
||||||
|
expected_error_type: type[HassioAPIError | SupervisorError] | None = None,
|
||||||
) -> Callable[
|
) -> Callable[
|
||||||
[_FuncType[_AddonManagerT, _P, _R]], _ReturnFuncType[_AddonManagerT, _P, _R]
|
[_FuncType[_AddonManagerT, _P, _R]], _ReturnFuncType[_AddonManagerT, _P, _R]
|
||||||
]:
|
]:
|
||||||
"""Handle HassioAPIError and raise a specific AddonError."""
|
"""Handle HassioAPIError and raise a specific AddonError."""
|
||||||
|
error_type = expected_error_type or (HassioAPIError, SupervisorError)
|
||||||
|
|
||||||
def handle_hassio_api_error(
|
def handle_hassio_api_error(
|
||||||
func: _FuncType[_AddonManagerT, _P, _R],
|
func: _FuncType[_AddonManagerT, _P, _R],
|
||||||
@ -53,7 +56,7 @@ def api_error[_AddonManagerT: AddonManager, **_P, _R](
|
|||||||
"""Wrap an add-on manager method."""
|
"""Wrap an add-on manager method."""
|
||||||
try:
|
try:
|
||||||
return_value = await func(self, *args, **kwargs)
|
return_value = await func(self, *args, **kwargs)
|
||||||
except (HassioAPIError, SupervisorError) as err:
|
except error_type as err:
|
||||||
raise AddonError(
|
raise AddonError(
|
||||||
f"{error_message.format(addon_name=self.addon_name)}: {err}"
|
f"{error_message.format(addon_name=self.addon_name)}: {err}"
|
||||||
) from err
|
) from err
|
||||||
@ -111,14 +114,7 @@ class AddonManager:
|
|||||||
self._restart_task: asyncio.Task | None = None
|
self._restart_task: asyncio.Task | None = None
|
||||||
self._start_task: asyncio.Task | None = None
|
self._start_task: asyncio.Task | None = None
|
||||||
self._update_task: asyncio.Task | None = None
|
self._update_task: asyncio.Task | None = None
|
||||||
self._client: SupervisorClient | None = None
|
self._supervisor_client = get_supervisor_client(hass)
|
||||||
|
|
||||||
@property
|
|
||||||
def _supervisor_client(self) -> SupervisorClient:
|
|
||||||
"""Get supervisor client."""
|
|
||||||
if not self._client:
|
|
||||||
self._client = get_supervisor_client(self._hass)
|
|
||||||
return self._client
|
|
||||||
|
|
||||||
def task_in_progress(self) -> bool:
|
def task_in_progress(self) -> bool:
|
||||||
"""Return True if any of the add-on tasks are in progress."""
|
"""Return True if any of the add-on tasks are in progress."""
|
||||||
@ -145,7 +141,10 @@ class AddonManager:
|
|||||||
discovery_info_config: dict = discovery_info["config"]
|
discovery_info_config: dict = discovery_info["config"]
|
||||||
return discovery_info_config
|
return discovery_info_config
|
||||||
|
|
||||||
@api_error("Failed to get the {addon_name} add-on info")
|
@api_error(
|
||||||
|
"Failed to get the {addon_name} add-on info",
|
||||||
|
expected_error_type=SupervisorError,
|
||||||
|
)
|
||||||
async def async_get_addon_info(self) -> AddonInfo:
|
async def async_get_addon_info(self) -> AddonInfo:
|
||||||
"""Return and cache manager add-on info."""
|
"""Return and cache manager add-on info."""
|
||||||
addon_store_info = await self._supervisor_client.store.addon_info(
|
addon_store_info = await self._supervisor_client.store.addon_info(
|
||||||
@ -187,19 +186,24 @@ class AddonManager:
|
|||||||
|
|
||||||
return addon_state
|
return addon_state
|
||||||
|
|
||||||
@api_error("Failed to set the {addon_name} add-on options")
|
@api_error(
|
||||||
|
"Failed to set the {addon_name} add-on options",
|
||||||
|
expected_error_type=SupervisorError,
|
||||||
|
)
|
||||||
async def async_set_addon_options(self, config: dict) -> None:
|
async def async_set_addon_options(self, config: dict) -> None:
|
||||||
"""Set manager add-on options."""
|
"""Set manager add-on options."""
|
||||||
options = {"options": config}
|
await self._supervisor_client.addons.addon_options(
|
||||||
await async_set_addon_options(self._hass, self.addon_slug, options)
|
self.addon_slug, AddonsOptions(config=config)
|
||||||
|
)
|
||||||
|
|
||||||
def _check_addon_available(self, addon_info: AddonInfo) -> None:
|
def _check_addon_available(self, addon_info: AddonInfo) -> None:
|
||||||
"""Check if the managed add-on is available."""
|
"""Check if the managed add-on is available."""
|
||||||
|
|
||||||
if not addon_info.available:
|
if not addon_info.available:
|
||||||
raise AddonError(f"{self.addon_name} add-on is not available")
|
raise AddonError(f"{self.addon_name} add-on is not available")
|
||||||
|
|
||||||
@api_error("Failed to install the {addon_name} add-on")
|
@api_error(
|
||||||
|
"Failed to install the {addon_name} add-on", expected_error_type=SupervisorError
|
||||||
|
)
|
||||||
async def async_install_addon(self) -> None:
|
async def async_install_addon(self) -> None:
|
||||||
"""Install the managed add-on."""
|
"""Install the managed add-on."""
|
||||||
addon_info = await self.async_get_addon_info()
|
addon_info = await self.async_get_addon_info()
|
||||||
@ -208,7 +212,10 @@ class AddonManager:
|
|||||||
|
|
||||||
await self._supervisor_client.store.install_addon(self.addon_slug)
|
await self._supervisor_client.store.install_addon(self.addon_slug)
|
||||||
|
|
||||||
@api_error("Failed to uninstall the {addon_name} add-on")
|
@api_error(
|
||||||
|
"Failed to uninstall the {addon_name} add-on",
|
||||||
|
expected_error_type=SupervisorError,
|
||||||
|
)
|
||||||
async def async_uninstall_addon(self) -> None:
|
async def async_uninstall_addon(self) -> None:
|
||||||
"""Uninstall the managed add-on."""
|
"""Uninstall the managed add-on."""
|
||||||
await self._supervisor_client.addons.uninstall_addon(self.addon_slug)
|
await self._supervisor_client.addons.uninstall_addon(self.addon_slug)
|
||||||
@ -227,19 +234,27 @@ class AddonManager:
|
|||||||
return
|
return
|
||||||
|
|
||||||
await self.async_create_backup()
|
await self.async_create_backup()
|
||||||
await async_update_addon(self._hass, self.addon_slug)
|
await self._supervisor_client.store.update_addon(
|
||||||
|
self.addon_slug, StoreAddonUpdate(backup=False)
|
||||||
|
)
|
||||||
|
|
||||||
@api_error("Failed to start the {addon_name} add-on")
|
@api_error(
|
||||||
|
"Failed to start the {addon_name} add-on", expected_error_type=SupervisorError
|
||||||
|
)
|
||||||
async def async_start_addon(self) -> None:
|
async def async_start_addon(self) -> None:
|
||||||
"""Start the managed add-on."""
|
"""Start the managed add-on."""
|
||||||
await self._supervisor_client.addons.start_addon(self.addon_slug)
|
await self._supervisor_client.addons.start_addon(self.addon_slug)
|
||||||
|
|
||||||
@api_error("Failed to restart the {addon_name} add-on")
|
@api_error(
|
||||||
|
"Failed to restart the {addon_name} add-on", expected_error_type=SupervisorError
|
||||||
|
)
|
||||||
async def async_restart_addon(self) -> None:
|
async def async_restart_addon(self) -> None:
|
||||||
"""Restart the managed add-on."""
|
"""Restart the managed add-on."""
|
||||||
await self._supervisor_client.addons.restart_addon(self.addon_slug)
|
await self._supervisor_client.addons.restart_addon(self.addon_slug)
|
||||||
|
|
||||||
@api_error("Failed to stop the {addon_name} add-on")
|
@api_error(
|
||||||
|
"Failed to stop the {addon_name} add-on", expected_error_type=SupervisorError
|
||||||
|
)
|
||||||
async def async_stop_addon(self) -> None:
|
async def async_stop_addon(self) -> None:
|
||||||
"""Stop the managed add-on."""
|
"""Stop the managed add-on."""
|
||||||
await self._supervisor_client.addons.stop_addon(self.addon_slug)
|
await self._supervisor_client.addons.stop_addon(self.addon_slug)
|
||||||
|
@ -56,7 +56,7 @@ from .const import (
|
|||||||
SUPERVISOR_CONTAINER,
|
SUPERVISOR_CONTAINER,
|
||||||
SupervisorEntityModel,
|
SupervisorEntityModel,
|
||||||
)
|
)
|
||||||
from .handler import HassIO, HassioAPIError
|
from .handler import HassIO, HassioAPIError, get_supervisor_client
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .issues import SupervisorIssues
|
from .issues import SupervisorIssues
|
||||||
@ -318,6 +318,7 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
self._container_updates: defaultdict[str, dict[str, set[str]]] = defaultdict(
|
self._container_updates: defaultdict[str, dict[str, set[str]]] = defaultdict(
|
||||||
lambda: defaultdict(set)
|
lambda: defaultdict(set)
|
||||||
)
|
)
|
||||||
|
self._supervisor_client = get_supervisor_client(hass)
|
||||||
|
|
||||||
async def _async_update_data(self) -> dict[str, Any]:
|
async def _async_update_data(self) -> dict[str, Any]:
|
||||||
"""Update data via library."""
|
"""Update data via library."""
|
||||||
@ -502,17 +503,17 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
async def _update_addon_stats(self, slug: str) -> tuple[str, dict[str, Any] | None]:
|
async def _update_addon_stats(self, slug: str) -> tuple[str, dict[str, Any] | None]:
|
||||||
"""Update single addon stats."""
|
"""Update single addon stats."""
|
||||||
try:
|
try:
|
||||||
stats = await self.hassio.get_addon_stats(slug)
|
stats = await self._supervisor_client.addons.addon_stats(slug)
|
||||||
except HassioAPIError as err:
|
except SupervisorError as err:
|
||||||
_LOGGER.warning("Could not fetch stats for %s: %s", slug, err)
|
_LOGGER.warning("Could not fetch stats for %s: %s", slug, err)
|
||||||
return (slug, None)
|
return (slug, None)
|
||||||
return (slug, stats)
|
return (slug, stats.to_dict())
|
||||||
|
|
||||||
async def _update_addon_changelog(self, slug: str) -> tuple[str, str | None]:
|
async def _update_addon_changelog(self, slug: str) -> tuple[str, str | None]:
|
||||||
"""Return the changelog for an add-on."""
|
"""Return the changelog for an add-on."""
|
||||||
try:
|
try:
|
||||||
changelog = await self.hassio.get_addon_changelog(slug)
|
changelog = await self._supervisor_client.store.addon_changelog(slug)
|
||||||
except HassioAPIError as err:
|
except SupervisorError as err:
|
||||||
_LOGGER.warning("Could not fetch changelog for %s: %s", slug, err)
|
_LOGGER.warning("Could not fetch changelog for %s: %s", slug, err)
|
||||||
return (slug, None)
|
return (slug, None)
|
||||||
return (slug, changelog)
|
return (slug, changelog)
|
||||||
@ -520,7 +521,7 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
async def _update_addon_info(self, slug: str) -> tuple[str, dict[str, Any] | None]:
|
async def _update_addon_info(self, slug: str) -> tuple[str, dict[str, Any] | None]:
|
||||||
"""Return the info for an add-on."""
|
"""Return the info for an add-on."""
|
||||||
try:
|
try:
|
||||||
info = await self.hassio.client.addons.addon_info(slug)
|
info = await self._supervisor_client.addons.addon_info(slug)
|
||||||
except SupervisorError as err:
|
except SupervisorError as err:
|
||||||
_LOGGER.warning("Could not fetch info for %s: %s", slug, err)
|
_LOGGER.warning("Could not fetch info for %s: %s", slug, err)
|
||||||
return (slug, None)
|
return (slug, None)
|
||||||
|
@ -7,6 +7,7 @@ from dataclasses import dataclass
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from aiohasupervisor import SupervisorError
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp.web_exceptions import HTTPServiceUnavailable
|
from aiohttp.web_exceptions import HTTPServiceUnavailable
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ from homeassistant.helpers import discovery_flow
|
|||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
from .const import ATTR_ADDON, ATTR_CONFIG, ATTR_DISCOVERY, ATTR_UUID, DOMAIN
|
from .const import ATTR_ADDON, ATTR_CONFIG, ATTR_DISCOVERY, ATTR_UUID, DOMAIN
|
||||||
from .handler import HassIO, HassioAPIError
|
from .handler import HassIO, HassioAPIError, get_supervisor_client
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -88,6 +89,7 @@ class HassIODiscovery(HomeAssistantView):
|
|||||||
"""Initialize WebView."""
|
"""Initialize WebView."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.hassio = hassio
|
self.hassio = hassio
|
||||||
|
self._supervisor_client = get_supervisor_client(hass)
|
||||||
|
|
||||||
async def post(self, request: web.Request, uuid: str) -> web.Response:
|
async def post(self, request: web.Request, uuid: str) -> web.Response:
|
||||||
"""Handle new discovery requests."""
|
"""Handle new discovery requests."""
|
||||||
@ -126,8 +128,8 @@ class HassIODiscovery(HomeAssistantView):
|
|||||||
|
|
||||||
# Read additional Add-on info
|
# Read additional Add-on info
|
||||||
try:
|
try:
|
||||||
addon_info = await self.hassio.client.addons.addon_info(slug)
|
addon_info = await self._supervisor_client.addons.addon_info(slug)
|
||||||
except HassioAPIError as err:
|
except SupervisorError as err:
|
||||||
_LOGGER.error("Can't read add-on info: %s", err)
|
_LOGGER.error("Can't read add-on info: %s", err)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -21,12 +21,15 @@ from homeassistant.components.http import (
|
|||||||
)
|
)
|
||||||
from homeassistant.const import SERVER_PORT
|
from homeassistant.const import SERVER_PORT
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.singleton import singleton
|
||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
|
|
||||||
from .const import ATTR_DISCOVERY, ATTR_MESSAGE, ATTR_RESULT, DOMAIN, X_HASS_SOURCE
|
from .const import ATTR_DISCOVERY, ATTR_MESSAGE, ATTR_RESULT, DOMAIN, X_HASS_SOURCE
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
KEY_SUPERVISOR_CLIENT = "supervisor_client"
|
||||||
|
|
||||||
|
|
||||||
class HassioAPIError(RuntimeError):
|
class HassioAPIError(RuntimeError):
|
||||||
"""Return if a API trow a error."""
|
"""Return if a API trow a error."""
|
||||||
@ -73,40 +76,6 @@ async def async_update_diagnostics(hass: HomeAssistant, diagnostics: bool) -> bo
|
|||||||
return await hassio.update_diagnostics(diagnostics)
|
return await hassio.update_diagnostics(diagnostics)
|
||||||
|
|
||||||
|
|
||||||
@bind_hass
|
|
||||||
@api_data
|
|
||||||
async def async_update_addon(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
slug: str,
|
|
||||||
backup: bool = False,
|
|
||||||
) -> dict:
|
|
||||||
"""Update add-on.
|
|
||||||
|
|
||||||
The caller of the function should handle HassioAPIError.
|
|
||||||
"""
|
|
||||||
hassio: HassIO = hass.data[DOMAIN]
|
|
||||||
command = f"/addons/{slug}/update"
|
|
||||||
return await hassio.send_command(
|
|
||||||
command,
|
|
||||||
payload={"backup": backup},
|
|
||||||
timeout=None,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@bind_hass
|
|
||||||
@api_data
|
|
||||||
async def async_set_addon_options(
|
|
||||||
hass: HomeAssistant, slug: str, options: dict
|
|
||||||
) -> dict:
|
|
||||||
"""Set add-on options.
|
|
||||||
|
|
||||||
The caller of the function should handle HassioAPIError.
|
|
||||||
"""
|
|
||||||
hassio: HassIO = hass.data[DOMAIN]
|
|
||||||
command = f"/addons/{slug}/options"
|
|
||||||
return await hassio.send_command(command, payload=options)
|
|
||||||
|
|
||||||
|
|
||||||
@bind_hass
|
@bind_hass
|
||||||
async def async_get_addon_discovery_info(hass: HomeAssistant, slug: str) -> dict | None:
|
async def async_get_addon_discovery_info(hass: HomeAssistant, slug: str) -> dict | None:
|
||||||
"""Return discovery data for an add-on."""
|
"""Return discovery data for an add-on."""
|
||||||
@ -253,14 +222,11 @@ class HassIO:
|
|||||||
self._ip = ip
|
self._ip = ip
|
||||||
base_url = f"http://{ip}"
|
base_url = f"http://{ip}"
|
||||||
self._base_url = URL(base_url)
|
self._base_url = URL(base_url)
|
||||||
self._client = SupervisorClient(
|
|
||||||
base_url, os.environ.get("SUPERVISOR_TOKEN", ""), session=websession
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def client(self) -> SupervisorClient:
|
def base_url(self) -> URL:
|
||||||
"""Return aiohasupervisor client."""
|
"""Return base url for Supervisor."""
|
||||||
return self._client
|
return self._base_url
|
||||||
|
|
||||||
@_api_bool
|
@_api_bool
|
||||||
def is_connected(self) -> Coroutine:
|
def is_connected(self) -> Coroutine:
|
||||||
@ -326,14 +292,6 @@ class HassIO:
|
|||||||
"""
|
"""
|
||||||
return self.send_command("/core/stats", method="get")
|
return self.send_command("/core/stats", method="get")
|
||||||
|
|
||||||
@api_data
|
|
||||||
def get_addon_stats(self, addon: str) -> Coroutine:
|
|
||||||
"""Return stats for an Add-on.
|
|
||||||
|
|
||||||
This method returns a coroutine.
|
|
||||||
"""
|
|
||||||
return self.send_command(f"/addons/{addon}/stats", method="get")
|
|
||||||
|
|
||||||
@api_data
|
@api_data
|
||||||
def get_supervisor_stats(self) -> Coroutine:
|
def get_supervisor_stats(self) -> Coroutine:
|
||||||
"""Return stats for the supervisor.
|
"""Return stats for the supervisor.
|
||||||
@ -342,15 +300,6 @@ class HassIO:
|
|||||||
"""
|
"""
|
||||||
return self.send_command("/supervisor/stats", method="get")
|
return self.send_command("/supervisor/stats", method="get")
|
||||||
|
|
||||||
def get_addon_changelog(self, addon: str) -> Coroutine:
|
|
||||||
"""Return changelog for an Add-on.
|
|
||||||
|
|
||||||
This method returns a coroutine.
|
|
||||||
"""
|
|
||||||
return self.send_command(
|
|
||||||
f"/addons/{addon}/changelog", method="get", return_text=True
|
|
||||||
)
|
|
||||||
|
|
||||||
@api_data
|
@api_data
|
||||||
def get_ingress_panels(self) -> Coroutine:
|
def get_ingress_panels(self) -> Coroutine:
|
||||||
"""Return data for Add-on ingress panels.
|
"""Return data for Add-on ingress panels.
|
||||||
@ -531,7 +480,12 @@ class HassIO:
|
|||||||
raise HassioAPIError
|
raise HassioAPIError
|
||||||
|
|
||||||
|
|
||||||
|
@singleton(KEY_SUPERVISOR_CLIENT)
|
||||||
def get_supervisor_client(hass: HomeAssistant) -> SupervisorClient:
|
def get_supervisor_client(hass: HomeAssistant) -> SupervisorClient:
|
||||||
"""Return supervisor client."""
|
"""Return supervisor client."""
|
||||||
hassio: HassIO = hass.data[DOMAIN]
|
hassio: HassIO = hass.data[DOMAIN]
|
||||||
return hassio.client
|
return SupervisorClient(
|
||||||
|
hassio.base_url,
|
||||||
|
os.environ.get("SUPERVISOR_TOKEN", ""),
|
||||||
|
session=hassio.websession,
|
||||||
|
)
|
||||||
|
@ -4,6 +4,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from aiohasupervisor import SupervisorError
|
||||||
|
from aiohasupervisor.models import StoreAddonUpdate
|
||||||
from awesomeversion import AwesomeVersion, AwesomeVersionStrategy
|
from awesomeversion import AwesomeVersion, AwesomeVersionStrategy
|
||||||
|
|
||||||
from homeassistant.components.update import (
|
from homeassistant.components.update import (
|
||||||
@ -15,6 +17,7 @@ from homeassistant.config_entries import ConfigEntry
|
|||||||
from homeassistant.const import ATTR_ICON, ATTR_NAME
|
from homeassistant.const import ATTR_ICON, ATTR_NAME
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers.entity import EntityDescription
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -28,6 +31,7 @@ from .const import (
|
|||||||
DATA_KEY_OS,
|
DATA_KEY_OS,
|
||||||
DATA_KEY_SUPERVISOR,
|
DATA_KEY_SUPERVISOR,
|
||||||
)
|
)
|
||||||
|
from .coordinator import HassioDataUpdateCoordinator
|
||||||
from .entity import (
|
from .entity import (
|
||||||
HassioAddonEntity,
|
HassioAddonEntity,
|
||||||
HassioCoreEntity,
|
HassioCoreEntity,
|
||||||
@ -36,10 +40,10 @@ from .entity import (
|
|||||||
)
|
)
|
||||||
from .handler import (
|
from .handler import (
|
||||||
HassioAPIError,
|
HassioAPIError,
|
||||||
async_update_addon,
|
|
||||||
async_update_core,
|
async_update_core,
|
||||||
async_update_os,
|
async_update_os,
|
||||||
async_update_supervisor,
|
async_update_supervisor,
|
||||||
|
get_supervisor_client,
|
||||||
)
|
)
|
||||||
|
|
||||||
ENTITY_DESCRIPTION = UpdateEntityDescription(
|
ENTITY_DESCRIPTION = UpdateEntityDescription(
|
||||||
@ -96,6 +100,16 @@ class SupervisorAddonUpdateEntity(HassioAddonEntity, UpdateEntity):
|
|||||||
| UpdateEntityFeature.RELEASE_NOTES
|
| UpdateEntityFeature.RELEASE_NOTES
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: HassioDataUpdateCoordinator,
|
||||||
|
entity_description: EntityDescription,
|
||||||
|
addon: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
"""Initialize object."""
|
||||||
|
super().__init__(coordinator, entity_description, addon)
|
||||||
|
self._supervisor_client = get_supervisor_client(self.hass)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _addon_data(self) -> dict:
|
def _addon_data(self) -> dict:
|
||||||
"""Return the add-on data."""
|
"""Return the add-on data."""
|
||||||
@ -165,8 +179,10 @@ class SupervisorAddonUpdateEntity(HassioAddonEntity, UpdateEntity):
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Install an update."""
|
"""Install an update."""
|
||||||
try:
|
try:
|
||||||
await async_update_addon(self.hass, slug=self._addon_slug, backup=backup)
|
await self._supervisor_client.store.update_addon(
|
||||||
except HassioAPIError as err:
|
self._addon_slug, StoreAddonUpdate(backup=backup)
|
||||||
|
)
|
||||||
|
except SupervisorError as err:
|
||||||
raise HomeAssistantError(f"Error updating {self.title}: {err}") from err
|
raise HomeAssistantError(f"Error updating {self.title}: {err}") from err
|
||||||
|
|
||||||
await self.coordinator.force_info_update_supervisor()
|
await self.coordinator.force_info_update_supervisor()
|
||||||
|
@ -6,7 +6,7 @@ from collections.abc import Callable, Generator
|
|||||||
from importlib.util import find_spec
|
from importlib.util import find_spec
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any
|
||||||
from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
from aiohasupervisor.models import Repository, StoreAddon, StoreInfo
|
from aiohasupervisor.models import Repository, StoreAddon, StoreInfo
|
||||||
import pytest
|
import pytest
|
||||||
@ -194,7 +194,9 @@ def mock_legacy_device_tracker_setup() -> Callable[[HomeAssistant, MockScanner],
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="addon_manager")
|
@pytest.fixture(name="addon_manager")
|
||||||
def addon_manager_fixture(hass: HomeAssistant) -> AddonManager:
|
def addon_manager_fixture(
|
||||||
|
hass: HomeAssistant, supervisor_client: AsyncMock
|
||||||
|
) -> AddonManager:
|
||||||
"""Return an AddonManager instance."""
|
"""Return an AddonManager instance."""
|
||||||
# pylint: disable-next=import-outside-toplevel
|
# pylint: disable-next=import-outside-toplevel
|
||||||
from .hassio.common import mock_addon_manager
|
from .hassio.common import mock_addon_manager
|
||||||
@ -363,10 +365,7 @@ def stop_addon_fixture(supervisor_client: AsyncMock) -> AsyncMock:
|
|||||||
@pytest.fixture(name="addon_options")
|
@pytest.fixture(name="addon_options")
|
||||||
def addon_options_fixture(addon_info: AsyncMock) -> dict[str, Any]:
|
def addon_options_fixture(addon_info: AsyncMock) -> dict[str, Any]:
|
||||||
"""Mock add-on options."""
|
"""Mock add-on options."""
|
||||||
# pylint: disable-next=import-outside-toplevel
|
return addon_info.return_value.options
|
||||||
from .hassio.common import mock_addon_options
|
|
||||||
|
|
||||||
return mock_addon_options(addon_info)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="set_addon_options_side_effect")
|
@pytest.fixture(name="set_addon_options_side_effect")
|
||||||
@ -382,13 +381,12 @@ def set_addon_options_side_effect_fixture(
|
|||||||
|
|
||||||
@pytest.fixture(name="set_addon_options")
|
@pytest.fixture(name="set_addon_options")
|
||||||
def set_addon_options_fixture(
|
def set_addon_options_fixture(
|
||||||
|
supervisor_client: AsyncMock,
|
||||||
set_addon_options_side_effect: Any | None,
|
set_addon_options_side_effect: Any | None,
|
||||||
) -> Generator[AsyncMock]:
|
) -> AsyncMock:
|
||||||
"""Mock set add-on options."""
|
"""Mock set add-on options."""
|
||||||
# pylint: disable-next=import-outside-toplevel
|
supervisor_client.addons.addon_options.side_effect = set_addon_options_side_effect
|
||||||
from .hassio.common import mock_set_addon_options
|
return supervisor_client.addons.addon_options
|
||||||
|
|
||||||
yield from mock_set_addon_options(set_addon_options_side_effect)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="uninstall_addon")
|
@pytest.fixture(name="uninstall_addon")
|
||||||
@ -407,12 +405,9 @@ def create_backup_fixture() -> Generator[AsyncMock]:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="update_addon")
|
@pytest.fixture(name="update_addon")
|
||||||
def update_addon_fixture() -> Generator[AsyncMock]:
|
def update_addon_fixture(supervisor_client: AsyncMock) -> AsyncMock:
|
||||||
"""Mock update add-on."""
|
"""Mock update add-on."""
|
||||||
# pylint: disable-next=import-outside-toplevel
|
return supervisor_client.store.update_addon
|
||||||
from .hassio.common import mock_update_addon
|
|
||||||
|
|
||||||
yield from mock_update_addon()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="store_addons")
|
@pytest.fixture(name="store_addons")
|
||||||
@ -440,6 +435,22 @@ def store_info_fixture(
|
|||||||
return supervisor_client.store.info
|
return supervisor_client.store.info
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="addon_stats")
|
||||||
|
def addon_stats_fixture(supervisor_client: AsyncMock) -> AsyncMock:
|
||||||
|
"""Mock addon stats info."""
|
||||||
|
# pylint: disable-next=import-outside-toplevel
|
||||||
|
from .hassio.common import mock_addon_stats
|
||||||
|
|
||||||
|
return mock_addon_stats(supervisor_client)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="addon_changelog")
|
||||||
|
def addon_changelog_fixture(supervisor_client: AsyncMock) -> AsyncMock:
|
||||||
|
"""Mock addon changelog."""
|
||||||
|
supervisor_client.store.addon_changelog.return_value = ""
|
||||||
|
return supervisor_client.store.addon_changelog
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="supervisor_client")
|
@pytest.fixture(name="supervisor_client")
|
||||||
def supervisor_client() -> Generator[AsyncMock]:
|
def supervisor_client() -> Generator[AsyncMock]:
|
||||||
"""Mock the supervisor client."""
|
"""Mock the supervisor client."""
|
||||||
@ -459,8 +470,20 @@ def supervisor_client() -> Generator[AsyncMock]:
|
|||||||
return_value=supervisor_client,
|
return_value=supervisor_client,
|
||||||
),
|
),
|
||||||
patch(
|
patch(
|
||||||
"homeassistant.components.hassio.handler.HassIO.client",
|
"homeassistant.components.hassio.discovery.get_supervisor_client",
|
||||||
new=PropertyMock(return_value=supervisor_client),
|
return_value=supervisor_client,
|
||||||
|
),
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.hassio.coordinator.get_supervisor_client",
|
||||||
|
return_value=supervisor_client,
|
||||||
|
),
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.hassio.update.get_supervisor_client",
|
||||||
|
return_value=supervisor_client,
|
||||||
|
),
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.hassio.get_supervisor_client",
|
||||||
|
return_value=supervisor_client,
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
yield supervisor_client
|
yield supervisor_client
|
||||||
|
@ -10,6 +10,8 @@ from typing import Any
|
|||||||
from unittest.mock import DEFAULT, AsyncMock, Mock, patch
|
from unittest.mock import DEFAULT, AsyncMock, Mock, patch
|
||||||
|
|
||||||
from aiohasupervisor.models import (
|
from aiohasupervisor.models import (
|
||||||
|
AddonsOptions,
|
||||||
|
AddonsStats,
|
||||||
AddonStage,
|
AddonStage,
|
||||||
InstalledAddonComplete,
|
InstalledAddonComplete,
|
||||||
Repository,
|
Repository,
|
||||||
@ -23,6 +25,7 @@ from homeassistant.core import HomeAssistant
|
|||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
INSTALLED_ADDON_FIELDS = [field.name for field in fields(InstalledAddonComplete)]
|
INSTALLED_ADDON_FIELDS = [field.name for field in fields(InstalledAddonComplete)]
|
||||||
STORE_ADDON_FIELDS = [field.name for field in fields(StoreAddonComplete)]
|
STORE_ADDON_FIELDS = [field.name for field in fields(StoreAddonComplete)]
|
||||||
|
ADDONS_STATS_FIELDS = [field.name for field in fields(AddonsStats)]
|
||||||
|
|
||||||
MOCK_STORE_ADDONS = [
|
MOCK_STORE_ADDONS = [
|
||||||
StoreAddon(
|
StoreAddon(
|
||||||
@ -202,32 +205,16 @@ def mock_start_addon_side_effect(
|
|||||||
return start_addon
|
return start_addon
|
||||||
|
|
||||||
|
|
||||||
def mock_addon_options(addon_info: AsyncMock) -> dict[str, Any]:
|
|
||||||
"""Mock add-on options."""
|
|
||||||
return addon_info.return_value.options
|
|
||||||
|
|
||||||
|
|
||||||
def mock_set_addon_options_side_effect(addon_options: dict[str, Any]) -> Any | None:
|
def mock_set_addon_options_side_effect(addon_options: dict[str, Any]) -> Any | None:
|
||||||
"""Return the set add-on options side effect."""
|
"""Return the set add-on options side effect."""
|
||||||
|
|
||||||
async def set_addon_options(hass: HomeAssistant, slug: str, options: dict) -> None:
|
async def set_addon_options(slug: str, options: AddonsOptions) -> None:
|
||||||
"""Mock set add-on options."""
|
"""Mock set add-on options."""
|
||||||
addon_options.update(options["options"])
|
addon_options.update(options.config)
|
||||||
|
|
||||||
return set_addon_options
|
return set_addon_options
|
||||||
|
|
||||||
|
|
||||||
def mock_set_addon_options(
|
|
||||||
set_addon_options_side_effect: Any | None,
|
|
||||||
) -> Generator[AsyncMock]:
|
|
||||||
"""Mock set add-on options."""
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.hassio.addon_manager.async_set_addon_options",
|
|
||||||
side_effect=set_addon_options_side_effect,
|
|
||||||
) as set_options:
|
|
||||||
yield set_options
|
|
||||||
|
|
||||||
|
|
||||||
def mock_create_backup() -> Generator[AsyncMock]:
|
def mock_create_backup() -> Generator[AsyncMock]:
|
||||||
"""Mock create backup."""
|
"""Mock create backup."""
|
||||||
with patch(
|
with patch(
|
||||||
@ -236,9 +223,21 @@ def mock_create_backup() -> Generator[AsyncMock]:
|
|||||||
yield create_backup
|
yield create_backup
|
||||||
|
|
||||||
|
|
||||||
def mock_update_addon() -> Generator[AsyncMock]:
|
def mock_addon_stats(supervisor_client: AsyncMock) -> AsyncMock:
|
||||||
"""Mock update add-on."""
|
"""Mock addon stats."""
|
||||||
with patch(
|
supervisor_client.addons.addon_stats.return_value = addon_stats = Mock(
|
||||||
"homeassistant.components.hassio.addon_manager.async_update_addon"
|
spec=AddonsStats,
|
||||||
) as update_addon:
|
cpu_percent=0.99,
|
||||||
yield update_addon
|
memory_usage=182611968,
|
||||||
|
memory_limit=3977146368,
|
||||||
|
memory_percent=4.59,
|
||||||
|
network_rx=362570232,
|
||||||
|
network_tx=82374138,
|
||||||
|
blk_read=46010945536,
|
||||||
|
blk_write=15051526144,
|
||||||
|
)
|
||||||
|
addon_stats.to_dict = MethodType(
|
||||||
|
lambda self: mock_to_dict(self, ADDONS_STATS_FIELDS),
|
||||||
|
addon_stats,
|
||||||
|
)
|
||||||
|
return supervisor_client.addons.addon_stats
|
||||||
|
@ -5,7 +5,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import AsyncMock, Mock, patch
|
||||||
|
|
||||||
from aiohasupervisor.models import AddonState
|
from aiohasupervisor.models import AddonsStats, AddonState
|
||||||
from aiohttp.test_utils import TestClient
|
from aiohttp.test_utils import TestClient
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -55,6 +55,7 @@ def hassio_stubs(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
hass_client: ClientSessionGenerator,
|
hass_client: ClientSessionGenerator,
|
||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
supervisor_client: AsyncMock,
|
||||||
) -> RefreshToken:
|
) -> RefreshToken:
|
||||||
"""Create mock hassio http client."""
|
"""Create mock hassio http client."""
|
||||||
with (
|
with (
|
||||||
@ -133,7 +134,9 @@ def all_setup_requests(
|
|||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
request: pytest.FixtureRequest,
|
request: pytest.FixtureRequest,
|
||||||
addon_installed: AsyncMock,
|
addon_installed: AsyncMock,
|
||||||
store_info,
|
store_info: AsyncMock,
|
||||||
|
addon_changelog: AsyncMock,
|
||||||
|
addon_stats: AsyncMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Mock all setup requests."""
|
"""Mock all setup requests."""
|
||||||
include_addons = hasattr(request, "param") and request.param.get(
|
include_addons = hasattr(request, "param") and request.param.get(
|
||||||
@ -249,8 +252,6 @@ def all_setup_requests(
|
|||||||
|
|
||||||
addon_installed.side_effect = mock_addon_info
|
addon_installed.side_effect = mock_addon_info
|
||||||
|
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test/changelog", text="")
|
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test2/changelog", text="")
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
"http://127.0.0.1/core/stats",
|
"http://127.0.0.1/core/stats",
|
||||||
json={
|
json={
|
||||||
@ -283,38 +284,32 @@ def all_setup_requests(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test/stats",
|
async def mock_addon_stats(addon: str) -> AddonsStats:
|
||||||
json={
|
"""Mock addon stats for test and test2."""
|
||||||
"result": "ok",
|
if addon == "test2":
|
||||||
"data": {
|
return AddonsStats(
|
||||||
"cpu_percent": 0.99,
|
cpu_percent=0.8,
|
||||||
"memory_usage": 182611968,
|
memory_usage=51941376,
|
||||||
"memory_limit": 3977146368,
|
memory_limit=3977146368,
|
||||||
"memory_percent": 4.59,
|
memory_percent=1.31,
|
||||||
"network_rx": 362570232,
|
network_rx=31338284,
|
||||||
"network_tx": 82374138,
|
network_tx=15692900,
|
||||||
"blk_read": 46010945536,
|
blk_read=740077568,
|
||||||
"blk_write": 15051526144,
|
blk_write=6004736,
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
aioclient_mock.get(
|
return AddonsStats(
|
||||||
"http://127.0.0.1/addons/test2/stats",
|
cpu_percent=0.99,
|
||||||
json={
|
memory_usage=182611968,
|
||||||
"result": "ok",
|
memory_limit=3977146368,
|
||||||
"data": {
|
memory_percent=4.59,
|
||||||
"cpu_percent": 0.8,
|
network_rx=362570232,
|
||||||
"memory_usage": 51941376,
|
network_tx=82374138,
|
||||||
"memory_limit": 3977146368,
|
blk_read=46010945536,
|
||||||
"memory_percent": 1.31,
|
blk_write=15051526144,
|
||||||
"network_rx": 31338284,
|
|
||||||
"network_tx": 15692900,
|
|
||||||
"blk_read": 740077568,
|
|
||||||
"blk_write": 6004736,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
addon_stats.side_effect = mock_addon_stats
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
"http://127.0.0.1/network/info",
|
"http://127.0.0.1/network/info",
|
||||||
json={
|
json={
|
||||||
|
@ -7,6 +7,7 @@ from typing import Any
|
|||||||
from unittest.mock import AsyncMock, call
|
from unittest.mock import AsyncMock, call
|
||||||
|
|
||||||
from aiohasupervisor import SupervisorError
|
from aiohasupervisor import SupervisorError
|
||||||
|
from aiohasupervisor.models import AddonsOptions
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.hassio.addon_manager import (
|
from homeassistant.components.hassio.addon_manager import (
|
||||||
@ -137,7 +138,7 @@ async def test_get_addon_info(
|
|||||||
"addon_store_info_error",
|
"addon_store_info_error",
|
||||||
"addon_store_info_calls",
|
"addon_store_info_calls",
|
||||||
),
|
),
|
||||||
[(SupervisorError("Boom"), 1, None, 1), (None, 0, HassioAPIError("Boom"), 1)],
|
[(SupervisorError("Boom"), 1, None, 1), (None, 0, SupervisorError("Boom"), 1)],
|
||||||
)
|
)
|
||||||
async def test_get_addon_info_error(
|
async def test_get_addon_info_error(
|
||||||
addon_manager: AddonManager,
|
addon_manager: AddonManager,
|
||||||
@ -170,7 +171,7 @@ async def test_set_addon_options(
|
|||||||
|
|
||||||
assert set_addon_options.call_count == 1
|
assert set_addon_options.call_count == 1
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass, "test_addon", {"options": {"test_key": "test"}}
|
"test_addon", AddonsOptions(config={"test_key": "test"})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -178,7 +179,7 @@ async def test_set_addon_options_error(
|
|||||||
hass: HomeAssistant, addon_manager: AddonManager, set_addon_options: AsyncMock
|
hass: HomeAssistant, addon_manager: AddonManager, set_addon_options: AsyncMock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test set addon options raises error."""
|
"""Test set addon options raises error."""
|
||||||
set_addon_options.side_effect = HassioAPIError("Boom")
|
set_addon_options.side_effect = SupervisorError("Boom")
|
||||||
|
|
||||||
with pytest.raises(AddonError) as err:
|
with pytest.raises(AddonError) as err:
|
||||||
await addon_manager.async_set_addon_options({"test_key": "test"})
|
await addon_manager.async_set_addon_options({"test_key": "test"})
|
||||||
@ -187,7 +188,7 @@ async def test_set_addon_options_error(
|
|||||||
|
|
||||||
assert set_addon_options.call_count == 1
|
assert set_addon_options.call_count == 1
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass, "test_addon", {"options": {"test_key": "test"}}
|
"test_addon", AddonsOptions(config={"test_key": "test"})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -215,7 +216,7 @@ async def test_install_addon_error(
|
|||||||
"""Test install addon raises error."""
|
"""Test install addon raises error."""
|
||||||
addon_store_info.return_value.available = True
|
addon_store_info.return_value.available = True
|
||||||
addon_info.return_value.available = True
|
addon_info.return_value.available = True
|
||||||
install_addon.side_effect = HassioAPIError("Boom")
|
install_addon.side_effect = SupervisorError("Boom")
|
||||||
|
|
||||||
with pytest.raises(AddonError) as err:
|
with pytest.raises(AddonError) as err:
|
||||||
await addon_manager.async_install_addon()
|
await addon_manager.async_install_addon()
|
||||||
@ -266,7 +267,7 @@ async def test_schedule_install_addon_error(
|
|||||||
install_addon: AsyncMock,
|
install_addon: AsyncMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test schedule install addon raises error."""
|
"""Test schedule install addon raises error."""
|
||||||
install_addon.side_effect = HassioAPIError("Boom")
|
install_addon.side_effect = SupervisorError("Boom")
|
||||||
|
|
||||||
with pytest.raises(AddonError) as err:
|
with pytest.raises(AddonError) as err:
|
||||||
await addon_manager.async_schedule_install_addon()
|
await addon_manager.async_schedule_install_addon()
|
||||||
@ -283,7 +284,7 @@ async def test_schedule_install_addon_logs_error(
|
|||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test schedule install addon logs error."""
|
"""Test schedule install addon logs error."""
|
||||||
install_addon.side_effect = HassioAPIError("Boom")
|
install_addon.side_effect = SupervisorError("Boom")
|
||||||
|
|
||||||
await addon_manager.async_schedule_install_addon(catch_error=True)
|
await addon_manager.async_schedule_install_addon(catch_error=True)
|
||||||
|
|
||||||
@ -541,7 +542,7 @@ async def test_update_addon_error(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test update addon raises error."""
|
"""Test update addon raises error."""
|
||||||
addon_info.return_value.update_available = True
|
addon_info.return_value.update_available = True
|
||||||
update_addon.side_effect = HassioAPIError("Boom")
|
update_addon.side_effect = SupervisorError("Boom")
|
||||||
|
|
||||||
with pytest.raises(AddonError) as err:
|
with pytest.raises(AddonError) as err:
|
||||||
await addon_manager.async_update_addon()
|
await addon_manager.async_update_addon()
|
||||||
@ -620,7 +621,7 @@ async def test_schedule_update_addon(
|
|||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
HassioAPIError("Boom"),
|
SupervisorError("Boom"),
|
||||||
1,
|
1,
|
||||||
"Failed to update the Test add-on: Boom",
|
"Failed to update the Test add-on: Boom",
|
||||||
),
|
),
|
||||||
@ -670,7 +671,7 @@ async def test_schedule_update_addon_error(
|
|||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
HassioAPIError("Boom"),
|
SupervisorError("Boom"),
|
||||||
1,
|
1,
|
||||||
"Failed to update the Test add-on: Boom",
|
"Failed to update the Test add-on: Boom",
|
||||||
),
|
),
|
||||||
@ -790,7 +791,7 @@ async def test_schedule_install_setup_addon(
|
|||||||
),
|
),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
HassioAPIError("Boom"),
|
SupervisorError("Boom"),
|
||||||
1,
|
1,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@ -801,7 +802,7 @@ async def test_schedule_install_setup_addon(
|
|||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
HassioAPIError("Boom"),
|
SupervisorError("Boom"),
|
||||||
1,
|
1,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@ -859,7 +860,7 @@ async def test_schedule_install_setup_addon_error(
|
|||||||
),
|
),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
HassioAPIError("Boom"),
|
SupervisorError("Boom"),
|
||||||
1,
|
1,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@ -870,7 +871,7 @@ async def test_schedule_install_setup_addon_error(
|
|||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
HassioAPIError("Boom"),
|
SupervisorError("Boom"),
|
||||||
1,
|
1,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@ -956,7 +957,7 @@ async def test_schedule_setup_addon(
|
|||||||
),
|
),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
HassioAPIError("Boom"),
|
SupervisorError("Boom"),
|
||||||
1,
|
1,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
@ -1005,7 +1006,7 @@ async def test_schedule_setup_addon_error(
|
|||||||
),
|
),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
HassioAPIError("Boom"),
|
SupervisorError("Boom"),
|
||||||
1,
|
1,
|
||||||
None,
|
None,
|
||||||
0,
|
0,
|
||||||
|
@ -19,7 +19,13 @@ MOCK_ENVIRON = {"SUPERVISOR": "127.0.0.1", "SUPERVISOR_TOKEN": "abcdefgh"}
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def mock_all(aioclient_mock: AiohttpClientMocker, addon_installed, store_info) -> None:
|
def mock_all(
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
addon_installed: AsyncMock,
|
||||||
|
store_info: AsyncMock,
|
||||||
|
addon_changelog: AsyncMock,
|
||||||
|
addon_stats: AsyncMock,
|
||||||
|
) -> None:
|
||||||
"""Mock all setup requests."""
|
"""Mock all setup requests."""
|
||||||
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
|
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
|
||||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={"result": "ok"})
|
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={"result": "ok"})
|
||||||
@ -100,22 +106,6 @@ def mock_all(aioclient_mock: AiohttpClientMocker, addon_installed, store_info) -
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test/stats",
|
|
||||||
json={
|
|
||||||
"result": "ok",
|
|
||||||
"data": {
|
|
||||||
"cpu_percent": 0.99,
|
|
||||||
"memory_usage": 182611968,
|
|
||||||
"memory_limit": 3977146368,
|
|
||||||
"memory_percent": 4.59,
|
|
||||||
"network_rx": 362570232,
|
|
||||||
"network_tx": 82374138,
|
|
||||||
"blk_read": 46010945536,
|
|
||||||
"blk_write": 15051526144,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
"http://127.0.0.1/core/stats",
|
"http://127.0.0.1/core/stats",
|
||||||
json={
|
json={
|
||||||
@ -148,8 +138,6 @@ def mock_all(aioclient_mock: AiohttpClientMocker, addon_installed, store_info) -
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test/changelog", text="")
|
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test2/changelog", text="")
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Test Supervisor diagnostics."""
|
"""Test Supervisor diagnostics."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from unittest.mock import patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -18,7 +18,13 @@ MOCK_ENVIRON = {"SUPERVISOR": "127.0.0.1", "SUPERVISOR_TOKEN": "abcdefgh"}
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def mock_all(aioclient_mock: AiohttpClientMocker, addon_installed, store_info) -> None:
|
def mock_all(
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
addon_installed: AsyncMock,
|
||||||
|
store_info: AsyncMock,
|
||||||
|
addon_stats: AsyncMock,
|
||||||
|
addon_changelog: AsyncMock,
|
||||||
|
) -> None:
|
||||||
"""Mock all setup requests."""
|
"""Mock all setup requests."""
|
||||||
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
|
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
|
||||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={"result": "ok"})
|
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={"result": "ok"})
|
||||||
@ -103,22 +109,6 @@ def mock_all(aioclient_mock: AiohttpClientMocker, addon_installed, store_info) -
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test/stats",
|
|
||||||
json={
|
|
||||||
"result": "ok",
|
|
||||||
"data": {
|
|
||||||
"cpu_percent": 0.99,
|
|
||||||
"memory_usage": 182611968,
|
|
||||||
"memory_limit": 3977146368,
|
|
||||||
"memory_percent": 4.59,
|
|
||||||
"network_rx": 362570232,
|
|
||||||
"network_tx": 82374138,
|
|
||||||
"blk_read": 46010945536,
|
|
||||||
"blk_write": 15051526144,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
"http://127.0.0.1/core/stats",
|
"http://127.0.0.1/core/stats",
|
||||||
json={
|
json={
|
||||||
@ -151,8 +141,6 @@ def mock_all(aioclient_mock: AiohttpClientMocker, addon_installed, store_info) -
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test/changelog", text="")
|
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test2/changelog", text="")
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
||||||
)
|
)
|
||||||
|
@ -201,20 +201,6 @@ async def test_api_homeassistant_restart(
|
|||||||
assert aioclient_mock.call_count == 1
|
assert aioclient_mock.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_api_addon_stats(
|
|
||||||
hassio_handler: HassIO, aioclient_mock: AiohttpClientMocker
|
|
||||||
) -> None:
|
|
||||||
"""Test setup with API Add-on stats."""
|
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test/stats",
|
|
||||||
json={"result": "ok", "data": {"memory_percent": 0.01}},
|
|
||||||
)
|
|
||||||
|
|
||||||
data = await hassio_handler.get_addon_stats("test")
|
|
||||||
assert data["memory_percent"] == 0.01
|
|
||||||
assert aioclient_mock.call_count == 1
|
|
||||||
|
|
||||||
|
|
||||||
async def test_api_core_stats(
|
async def test_api_core_stats(
|
||||||
hassio_handler: HassIO, aioclient_mock: AiohttpClientMocker
|
hassio_handler: HassIO, aioclient_mock: AiohttpClientMocker
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -5,6 +5,7 @@ import os
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
|
from aiohasupervisor.models import AddonsStats
|
||||||
import pytest
|
import pytest
|
||||||
from voluptuous import Invalid
|
from voluptuous import Invalid
|
||||||
|
|
||||||
@ -52,7 +53,12 @@ def os_info(extra_os_info):
|
|||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def mock_all(
|
def mock_all(
|
||||||
aioclient_mock: AiohttpClientMocker, os_info, store_info, addon_info
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
os_info: AsyncMock,
|
||||||
|
store_info: AsyncMock,
|
||||||
|
addon_info: AsyncMock,
|
||||||
|
addon_stats: AsyncMock,
|
||||||
|
addon_changelog: AsyncMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Mock all setup requests."""
|
"""Mock all setup requests."""
|
||||||
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
|
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
|
||||||
@ -156,64 +162,38 @@ def mock_all(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test/stats",
|
async def mock_addon_stats(addon: str) -> AddonsStats:
|
||||||
json={
|
"""Mock addon stats for test and test2."""
|
||||||
"result": "ok",
|
if addon in {"test2", "test3"}:
|
||||||
"data": {
|
return AddonsStats(
|
||||||
"cpu_percent": 0.99,
|
cpu_percent=0.8,
|
||||||
"memory_usage": 182611968,
|
memory_usage=51941376,
|
||||||
"memory_limit": 3977146368,
|
memory_limit=3977146368,
|
||||||
"memory_percent": 4.59,
|
memory_percent=1.31,
|
||||||
"network_rx": 362570232,
|
network_rx=31338284,
|
||||||
"network_tx": 82374138,
|
network_tx=15692900,
|
||||||
"blk_read": 46010945536,
|
blk_read=740077568,
|
||||||
"blk_write": 15051526144,
|
blk_write=6004736,
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
aioclient_mock.get(
|
return AddonsStats(
|
||||||
"http://127.0.0.1/addons/test2/stats",
|
cpu_percent=0.99,
|
||||||
json={
|
memory_usage=182611968,
|
||||||
"result": "ok",
|
memory_limit=3977146368,
|
||||||
"data": {
|
memory_percent=4.59,
|
||||||
"cpu_percent": 0.8,
|
network_rx=362570232,
|
||||||
"memory_usage": 51941376,
|
network_tx=82374138,
|
||||||
"memory_limit": 3977146368,
|
blk_read=46010945536,
|
||||||
"memory_percent": 1.31,
|
blk_write=15051526144,
|
||||||
"network_rx": 31338284,
|
|
||||||
"network_tx": 15692900,
|
|
||||||
"blk_read": 740077568,
|
|
||||||
"blk_write": 6004736,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test3/stats",
|
|
||||||
json={
|
|
||||||
"result": "ok",
|
|
||||||
"data": {
|
|
||||||
"cpu_percent": 0.8,
|
|
||||||
"memory_usage": 51941376,
|
|
||||||
"memory_limit": 3977146368,
|
|
||||||
"memory_percent": 1.31,
|
|
||||||
"network_rx": 31338284,
|
|
||||||
"network_tx": 15692900,
|
|
||||||
"blk_read": 740077568,
|
|
||||||
"blk_write": 6004736,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test/changelog", text="")
|
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test/info",
|
|
||||||
json={"result": "ok", "data": {"auto_update": True}},
|
|
||||||
)
|
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test2/changelog", text="")
|
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test2/info",
|
|
||||||
json={"result": "ok", "data": {"auto_update": False}},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
addon_stats.side_effect = mock_addon_stats
|
||||||
|
|
||||||
|
def mock_addon_info(slug: str):
|
||||||
|
addon_info.return_value.auto_update = slug == "test"
|
||||||
|
return addon_info.return_value
|
||||||
|
|
||||||
|
addon_info.side_effect = mock_addon_info
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
||||||
)
|
)
|
||||||
|
@ -4,15 +4,12 @@ from datetime import timedelta
|
|||||||
import os
|
import os
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
|
from aiohasupervisor import SupervisorError
|
||||||
from freezegun.api import FrozenDateTimeFactory
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.hassio import (
|
from homeassistant.components.hassio import DOMAIN, HASSIO_UPDATE_INTERVAL
|
||||||
DOMAIN,
|
|
||||||
HASSIO_UPDATE_INTERVAL,
|
|
||||||
HassioAPIError,
|
|
||||||
)
|
|
||||||
from homeassistant.components.hassio.const import REQUEST_REFRESH_DELAY
|
from homeassistant.components.hassio.const import REQUEST_REFRESH_DELAY
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.const import STATE_UNAVAILABLE
|
from homeassistant.const import STATE_UNAVAILABLE
|
||||||
@ -34,38 +31,11 @@ def mock_all(
|
|||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
addon_installed: AsyncMock,
|
addon_installed: AsyncMock,
|
||||||
store_info: AsyncMock,
|
store_info: AsyncMock,
|
||||||
|
addon_stats: AsyncMock,
|
||||||
|
addon_changelog: AsyncMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Mock all setup requests."""
|
"""Mock all setup requests."""
|
||||||
_install_default_mocks(aioclient_mock)
|
_install_default_mocks(aioclient_mock)
|
||||||
_install_test_addon_stats_mock(aioclient_mock)
|
|
||||||
|
|
||||||
|
|
||||||
def _install_test_addon_stats_mock(aioclient_mock: AiohttpClientMocker):
|
|
||||||
"""Install mock to provide valid stats for the test addon."""
|
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test/stats",
|
|
||||||
json={
|
|
||||||
"result": "ok",
|
|
||||||
"data": {
|
|
||||||
"cpu_percent": 0.99,
|
|
||||||
"memory_usage": 182611968,
|
|
||||||
"memory_limit": 3977146368,
|
|
||||||
"memory_percent": 4.59,
|
|
||||||
"network_rx": 362570232,
|
|
||||||
"network_tx": 82374138,
|
|
||||||
"blk_read": 46010945536,
|
|
||||||
"blk_write": 15051526144,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _install_test_addon_stats_failure_mock(aioclient_mock: AiohttpClientMocker):
|
|
||||||
"""Install mocks to raise an exception when fetching stats for the test addon."""
|
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test/stats",
|
|
||||||
exc=HassioAPIError,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _install_default_mocks(aioclient_mock: AiohttpClientMocker):
|
def _install_default_mocks(aioclient_mock: AiohttpClientMocker):
|
||||||
@ -174,8 +144,6 @@ def _install_default_mocks(aioclient_mock: AiohttpClientMocker):
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test/changelog", text="")
|
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test2/changelog", text="")
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
||||||
)
|
)
|
||||||
@ -285,6 +253,7 @@ async def test_stats_addon_sensor(
|
|||||||
entity_registry: er.EntityRegistry,
|
entity_registry: er.EntityRegistry,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
freezer: FrozenDateTimeFactory,
|
freezer: FrozenDateTimeFactory,
|
||||||
|
addon_stats: AsyncMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test stats addons sensor."""
|
"""Test stats addons sensor."""
|
||||||
config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=DOMAIN)
|
config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=DOMAIN)
|
||||||
@ -302,7 +271,7 @@ async def test_stats_addon_sensor(
|
|||||||
|
|
||||||
aioclient_mock.clear_requests()
|
aioclient_mock.clear_requests()
|
||||||
_install_default_mocks(aioclient_mock)
|
_install_default_mocks(aioclient_mock)
|
||||||
_install_test_addon_stats_failure_mock(aioclient_mock)
|
addon_stats.side_effect = SupervisorError
|
||||||
|
|
||||||
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
|
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
|
||||||
async_fire_time_changed(hass)
|
async_fire_time_changed(hass)
|
||||||
@ -312,7 +281,7 @@ async def test_stats_addon_sensor(
|
|||||||
|
|
||||||
aioclient_mock.clear_requests()
|
aioclient_mock.clear_requests()
|
||||||
_install_default_mocks(aioclient_mock)
|
_install_default_mocks(aioclient_mock)
|
||||||
_install_test_addon_stats_mock(aioclient_mock)
|
addon_stats.side_effect = None
|
||||||
|
|
||||||
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
|
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
|
||||||
async_fire_time_changed(hass)
|
async_fire_time_changed(hass)
|
||||||
@ -345,7 +314,7 @@ async def test_stats_addon_sensor(
|
|||||||
|
|
||||||
aioclient_mock.clear_requests()
|
aioclient_mock.clear_requests()
|
||||||
_install_default_mocks(aioclient_mock)
|
_install_default_mocks(aioclient_mock)
|
||||||
_install_test_addon_stats_failure_mock(aioclient_mock)
|
addon_stats.side_effect = SupervisorError
|
||||||
|
|
||||||
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
|
freezer.tick(HASSIO_UPDATE_INTERVAL + timedelta(seconds=1))
|
||||||
async_fire_time_changed(hass)
|
async_fire_time_changed(hass)
|
||||||
|
@ -4,7 +4,8 @@ from datetime import timedelta
|
|||||||
import os
|
import os
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
from aiohasupervisor import SupervisorBadRequestError
|
from aiohasupervisor import SupervisorBadRequestError, SupervisorError
|
||||||
|
from aiohasupervisor.models import StoreAddonUpdate
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.hassio import DOMAIN, HassioAPIError
|
from homeassistant.components.hassio import DOMAIN, HassioAPIError
|
||||||
@ -22,7 +23,13 @@ MOCK_ENVIRON = {"SUPERVISOR": "127.0.0.1", "SUPERVISOR_TOKEN": "abcdefgh"}
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def mock_all(aioclient_mock: AiohttpClientMocker, addon_installed, store_info) -> None:
|
def mock_all(
|
||||||
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
addon_installed: AsyncMock,
|
||||||
|
store_info: AsyncMock,
|
||||||
|
addon_stats: AsyncMock,
|
||||||
|
addon_changelog: AsyncMock,
|
||||||
|
) -> None:
|
||||||
"""Mock all setup requests."""
|
"""Mock all setup requests."""
|
||||||
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
|
aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"})
|
||||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={"result": "ok"})
|
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={"result": "ok"})
|
||||||
@ -108,22 +115,6 @@ def mock_all(aioclient_mock: AiohttpClientMocker, addon_installed, store_info) -
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
aioclient_mock.get(
|
|
||||||
"http://127.0.0.1/addons/test/stats",
|
|
||||||
json={
|
|
||||||
"result": "ok",
|
|
||||||
"data": {
|
|
||||||
"cpu_percent": 0.99,
|
|
||||||
"memory_usage": 182611968,
|
|
||||||
"memory_limit": 3977146368,
|
|
||||||
"memory_percent": 4.59,
|
|
||||||
"network_rx": 362570232,
|
|
||||||
"network_tx": 82374138,
|
|
||||||
"blk_read": 46010945536,
|
|
||||||
"blk_write": 15051526144,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
"http://127.0.0.1/core/stats",
|
"http://127.0.0.1/core/stats",
|
||||||
json={
|
json={
|
||||||
@ -156,8 +147,6 @@ def mock_all(aioclient_mock: AiohttpClientMocker, addon_installed, store_info) -
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test/changelog", text="")
|
|
||||||
aioclient_mock.get("http://127.0.0.1/addons/test2/changelog", text="")
|
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
|
||||||
)
|
)
|
||||||
@ -227,9 +216,7 @@ async def test_update_entities(
|
|||||||
assert state.attributes["auto_update"] is auto_update
|
assert state.attributes["auto_update"] is auto_update
|
||||||
|
|
||||||
|
|
||||||
async def test_update_addon(
|
async def test_update_addon(hass: HomeAssistant, update_addon: AsyncMock) -> None:
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
|
||||||
) -> None:
|
|
||||||
"""Test updating addon update entity."""
|
"""Test updating addon update entity."""
|
||||||
config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=DOMAIN)
|
config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=DOMAIN)
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -243,17 +230,13 @@ async def test_update_addon(
|
|||||||
assert result
|
assert result
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/addons/test/update",
|
|
||||||
json={"result": "ok", "data": {}},
|
|
||||||
)
|
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"update",
|
"update",
|
||||||
"install",
|
"install",
|
||||||
{"entity_id": "update.test_update"},
|
{"entity_id": "update.test_update"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
update_addon.assert_called_once_with("test", StoreAddonUpdate(backup=False))
|
||||||
|
|
||||||
|
|
||||||
async def test_update_os(
|
async def test_update_os(
|
||||||
@ -344,7 +327,8 @@ async def test_update_supervisor(
|
|||||||
|
|
||||||
|
|
||||||
async def test_update_addon_with_error(
|
async def test_update_addon_with_error(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
hass: HomeAssistant,
|
||||||
|
update_addon: AsyncMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test updating addon update entity with error."""
|
"""Test updating addon update entity with error."""
|
||||||
config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=DOMAIN)
|
config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=DOMAIN)
|
||||||
@ -358,11 +342,7 @@ async def test_update_addon_with_error(
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
aioclient_mock.post(
|
update_addon.side_effect = SupervisorError
|
||||||
"http://127.0.0.1/addons/test/update",
|
|
||||||
exc=HassioAPIError,
|
|
||||||
)
|
|
||||||
|
|
||||||
with pytest.raises(HomeAssistantError, match=r"^Error updating test:"):
|
with pytest.raises(HomeAssistantError, match=r"^Error updating test:"):
|
||||||
assert not await hass.services.async_call(
|
assert not await hass.services.async_call(
|
||||||
"update",
|
"update",
|
||||||
@ -610,19 +590,15 @@ async def test_setting_up_core_update_when_addon_fails(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
addon_installed: AsyncMock,
|
addon_installed: AsyncMock,
|
||||||
|
addon_stats: AsyncMock,
|
||||||
|
addon_changelog: AsyncMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test setting up core update when single addon fails."""
|
"""Test setting up core update when single addon fails."""
|
||||||
addon_installed.side_effect = SupervisorBadRequestError("Addon Test does not exist")
|
addon_installed.side_effect = SupervisorBadRequestError("Addon Test does not exist")
|
||||||
|
addon_stats.side_effect = SupervisorBadRequestError("add-on is not running")
|
||||||
|
addon_changelog.side_effect = SupervisorBadRequestError("add-on is not running")
|
||||||
with (
|
with (
|
||||||
patch.dict(os.environ, MOCK_ENVIRON),
|
patch.dict(os.environ, MOCK_ENVIRON),
|
||||||
patch(
|
|
||||||
"homeassistant.components.hassio.HassIO.get_addon_stats",
|
|
||||||
side_effect=HassioAPIError("add-on is not running"),
|
|
||||||
),
|
|
||||||
patch(
|
|
||||||
"homeassistant.components.hassio.HassIO.get_addon_changelog",
|
|
||||||
side_effect=HassioAPIError("add-on is not running"),
|
|
||||||
),
|
|
||||||
):
|
):
|
||||||
result = await async_setup_component(
|
result = await async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
|
@ -7,15 +7,10 @@ from typing import Any
|
|||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import AsyncMock, Mock, patch
|
||||||
|
|
||||||
from aiohasupervisor import SupervisorError
|
from aiohasupervisor import SupervisorError
|
||||||
|
from aiohasupervisor.models import AddonsOptions
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.hassio import (
|
from homeassistant.components.hassio import AddonError, AddonInfo, AddonState, HassIO
|
||||||
AddonError,
|
|
||||||
AddonInfo,
|
|
||||||
AddonState,
|
|
||||||
HassIO,
|
|
||||||
HassioAPIError,
|
|
||||||
)
|
|
||||||
from homeassistant.components.homeassistant_hardware import silabs_multiprotocol_addon
|
from homeassistant.components.homeassistant_hardware import silabs_multiprotocol_addon
|
||||||
from homeassistant.components.zha import DOMAIN as ZHA_DOMAIN
|
from homeassistant.components.zha import DOMAIN as ZHA_DOMAIN
|
||||||
from homeassistant.config_entries import ConfigEntry, ConfigFlow
|
from homeassistant.config_entries import ConfigEntry, ConfigFlow
|
||||||
@ -38,6 +33,11 @@ TEST_DOMAIN = "test"
|
|||||||
TEST_DOMAIN_2 = "test_2"
|
TEST_DOMAIN_2 = "test_2"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def mock_supervisor_client(supervisor_client: AsyncMock) -> None:
|
||||||
|
"""Mock supervisor client."""
|
||||||
|
|
||||||
|
|
||||||
class FakeConfigFlow(ConfigFlow):
|
class FakeConfigFlow(ConfigFlow):
|
||||||
"""Handle a config flow for the silabs multiprotocol add-on."""
|
"""Handle a config flow for the silabs multiprotocol add-on."""
|
||||||
|
|
||||||
@ -253,16 +253,15 @@ async def test_option_flow_install_multi_pan_addon(
|
|||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
assert result["step_id"] == "start_addon"
|
assert result["step_id"] == "start_addon"
|
||||||
set_addon_options.assert_called_once_with(
|
set_addon_options.assert_called_once_with(
|
||||||
hass,
|
|
||||||
"core_silabs_multiprotocol",
|
"core_silabs_multiprotocol",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"autoflash_firmware": True,
|
"autoflash_firmware": True,
|
||||||
"device": "/dev/ttyTEST123",
|
"device": "/dev/ttyTEST123",
|
||||||
"baudrate": "115200",
|
"baudrate": "115200",
|
||||||
"flow_control": True,
|
"flow_control": True,
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -336,16 +335,15 @@ async def test_option_flow_install_multi_pan_addon_zha(
|
|||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
assert result["step_id"] == "start_addon"
|
assert result["step_id"] == "start_addon"
|
||||||
set_addon_options.assert_called_once_with(
|
set_addon_options.assert_called_once_with(
|
||||||
hass,
|
|
||||||
"core_silabs_multiprotocol",
|
"core_silabs_multiprotocol",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"autoflash_firmware": True,
|
"autoflash_firmware": True,
|
||||||
"device": "/dev/ttyTEST123",
|
"device": "/dev/ttyTEST123",
|
||||||
"baudrate": "115200",
|
"baudrate": "115200",
|
||||||
"flow_control": True,
|
"flow_control": True,
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
# Check the channel is initialized from ZHA
|
# Check the channel is initialized from ZHA
|
||||||
assert multipan_manager._channel == 11
|
assert multipan_manager._channel == 11
|
||||||
@ -424,16 +422,15 @@ async def test_option_flow_install_multi_pan_addon_zha_other_radio(
|
|||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
assert result["step_id"] == "start_addon"
|
assert result["step_id"] == "start_addon"
|
||||||
set_addon_options.assert_called_once_with(
|
set_addon_options.assert_called_once_with(
|
||||||
hass,
|
|
||||||
"core_silabs_multiprotocol",
|
"core_silabs_multiprotocol",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"autoflash_firmware": True,
|
"autoflash_firmware": True,
|
||||||
"device": "/dev/ttyTEST123",
|
"device": "/dev/ttyTEST123",
|
||||||
"baudrate": "115200",
|
"baudrate": "115200",
|
||||||
"flow_control": True,
|
"flow_control": True,
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -1204,7 +1201,7 @@ async def test_option_flow_install_multi_pan_addon_install_fails(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test installing the multi pan addon."""
|
"""Test installing the multi pan addon."""
|
||||||
|
|
||||||
install_addon.side_effect = HassioAPIError("Boom")
|
install_addon.side_effect = SupervisorError("Boom")
|
||||||
|
|
||||||
# Setup the config entry
|
# Setup the config entry
|
||||||
config_entry = MockConfigEntry(
|
config_entry = MockConfigEntry(
|
||||||
@ -1283,16 +1280,15 @@ async def test_option_flow_install_multi_pan_addon_start_fails(
|
|||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
assert result["step_id"] == "start_addon"
|
assert result["step_id"] == "start_addon"
|
||||||
set_addon_options.assert_called_once_with(
|
set_addon_options.assert_called_once_with(
|
||||||
hass,
|
|
||||||
"core_silabs_multiprotocol",
|
"core_silabs_multiprotocol",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"autoflash_firmware": True,
|
"autoflash_firmware": True,
|
||||||
"device": "/dev/ttyTEST123",
|
"device": "/dev/ttyTEST123",
|
||||||
"baudrate": "115200",
|
"baudrate": "115200",
|
||||||
"flow_control": True,
|
"flow_control": True,
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -1317,7 +1313,7 @@ async def test_option_flow_install_multi_pan_addon_set_options_fails(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test installing the multi pan addon."""
|
"""Test installing the multi pan addon."""
|
||||||
|
|
||||||
set_addon_options.side_effect = HassioAPIError("Boom")
|
set_addon_options.side_effect = SupervisorError("Boom")
|
||||||
|
|
||||||
# Setup the config entry
|
# Setup the config entry
|
||||||
config_entry = MockConfigEntry(
|
config_entry = MockConfigEntry(
|
||||||
@ -1361,7 +1357,7 @@ async def test_option_flow_addon_info_fails(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test installing the multi pan addon."""
|
"""Test installing the multi pan addon."""
|
||||||
|
|
||||||
addon_store_info.side_effect = HassioAPIError("Boom")
|
addon_store_info.side_effect = SupervisorError("Boom")
|
||||||
|
|
||||||
# Setup the config entry
|
# Setup the config entry
|
||||||
config_entry = MockConfigEntry(
|
config_entry = MockConfigEntry(
|
||||||
@ -1494,16 +1490,15 @@ async def test_option_flow_install_multi_pan_addon_zha_migration_fails_step_2(
|
|||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
assert result["step_id"] == "start_addon"
|
assert result["step_id"] == "start_addon"
|
||||||
set_addon_options.assert_called_once_with(
|
set_addon_options.assert_called_once_with(
|
||||||
hass,
|
|
||||||
"core_silabs_multiprotocol",
|
"core_silabs_multiprotocol",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"autoflash_firmware": True,
|
"autoflash_firmware": True,
|
||||||
"device": "/dev/ttyTEST123",
|
"device": "/dev/ttyTEST123",
|
||||||
"baudrate": "115200",
|
"baudrate": "115200",
|
||||||
"flow_control": True,
|
"flow_control": True,
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -1668,7 +1663,7 @@ async def test_check_multi_pan_addon_info_error(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test `check_multi_pan_addon` where the addon info cannot be read."""
|
"""Test `check_multi_pan_addon` where the addon info cannot be read."""
|
||||||
|
|
||||||
addon_store_info.side_effect = HassioAPIError("Boom")
|
addon_store_info.side_effect = SupervisorError("Boom")
|
||||||
|
|
||||||
with pytest.raises(HomeAssistantError):
|
with pytest.raises(HomeAssistantError):
|
||||||
await silabs_multiprotocol_addon.check_multi_pan_addon(hass)
|
await silabs_multiprotocol_addon.check_multi_pan_addon(hass)
|
||||||
|
@ -1318,7 +1318,7 @@ async def test_addon_not_installed_failures(
|
|||||||
install_addon: AsyncMock,
|
install_addon: AsyncMock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test add-on install failure."""
|
"""Test add-on install failure."""
|
||||||
install_addon.side_effect = HassioAPIError()
|
install_addon.side_effect = SupervisorError()
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
@ -1355,7 +1355,7 @@ async def test_addon_not_installed_failures_zeroconf(
|
|||||||
zeroconf_info: ZeroconfServiceInfo,
|
zeroconf_info: ZeroconfServiceInfo,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test add-on install failure."""
|
"""Test add-on install failure."""
|
||||||
install_addon.side_effect = HassioAPIError()
|
install_addon.side_effect = SupervisorError()
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_ZEROCONF}, data=zeroconf_info
|
DOMAIN, context={"source": config_entries.SOURCE_ZEROCONF}, data=zeroconf_info
|
||||||
|
@ -389,7 +389,7 @@ async def test_addon_info_failure(
|
|||||||
True,
|
True,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
HassioAPIError("Boom"),
|
SupervisorError("Boom"),
|
||||||
None,
|
None,
|
||||||
ServerVersionTooOld("Invalid version"),
|
ServerVersionTooOld("Invalid version"),
|
||||||
),
|
),
|
||||||
|
@ -14,11 +14,7 @@ import voluptuous as vol
|
|||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components import mqtt
|
from homeassistant.components import mqtt
|
||||||
from homeassistant.components.hassio import (
|
from homeassistant.components.hassio import AddonError, HassioServiceInfo
|
||||||
AddonError,
|
|
||||||
HassioAPIError,
|
|
||||||
HassioServiceInfo,
|
|
||||||
)
|
|
||||||
from homeassistant.components.mqtt.config_flow import PWD_NOT_CHANGED
|
from homeassistant.components.mqtt.config_flow import PWD_NOT_CHANGED
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_CLIENT_ID,
|
CONF_CLIENT_ID,
|
||||||
@ -253,7 +249,7 @@ async def test_user_connection_works(
|
|||||||
assert len(mock_finish_setup.mock_calls) == 1
|
assert len(mock_finish_setup.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("mqtt_client_mock", "supervisor")
|
@pytest.mark.usefixtures("mqtt_client_mock", "supervisor", "supervisor_client")
|
||||||
async def test_user_connection_works_with_supervisor(
|
async def test_user_connection_works_with_supervisor(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_try_connection: MagicMock,
|
mock_try_connection: MagicMock,
|
||||||
@ -856,7 +852,7 @@ async def test_addon_not_installed_failures(
|
|||||||
|
|
||||||
Case: The Mosquitto add-on install fails.
|
Case: The Mosquitto add-on install fails.
|
||||||
"""
|
"""
|
||||||
install_addon.side_effect = HassioAPIError()
|
install_addon.side_effect = SupervisorError()
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
"mqtt", context={"source": config_entries.SOURCE_USER}
|
"mqtt", context={"source": config_entries.SOURCE_USER}
|
||||||
|
@ -47,6 +47,7 @@ def enable_mocks_fixture(
|
|||||||
"""Enable API mocks."""
|
"""Enable API mocks."""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("supervisor_client")
|
||||||
async def test_import_dataset(
|
async def test_import_dataset(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_async_zeroconf: MagicMock,
|
mock_async_zeroconf: MagicMock,
|
||||||
@ -201,6 +202,7 @@ async def test_import_share_radio_no_channel_collision(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("supervisor_client")
|
||||||
@pytest.mark.parametrize("enable_compute_pskc", [True])
|
@pytest.mark.parametrize("enable_compute_pskc", [True])
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"dataset", [DATASET_INSECURE_NW_KEY, DATASET_INSECURE_PASSPHRASE]
|
"dataset", [DATASET_INSECURE_NW_KEY, DATASET_INSECURE_PASSPHRASE]
|
||||||
@ -310,6 +312,7 @@ async def test_config_entry_update(hass: HomeAssistant) -> None:
|
|||||||
mock_otrb_api.assert_called_once_with(new_config_entry_data["url"], ANY, ANY)
|
mock_otrb_api.assert_called_once_with(new_config_entry_data["url"], ANY, ANY)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("supervisor_client")
|
||||||
async def test_remove_entry(
|
async def test_remove_entry(
|
||||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, otbr_config_entry_multipan
|
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, otbr_config_entry_multipan
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Test OTBR Silicon Labs Multiprotocol support."""
|
"""Test OTBR Silicon Labs Multiprotocol support."""
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from python_otbr_api import ActiveDataSet, tlv_parser
|
from python_otbr_api import ActiveDataSet, tlv_parser
|
||||||
@ -31,6 +31,11 @@ DATASET_CH16_PENDING = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def mock_supervisor_client(supervisor_client: AsyncMock) -> None:
|
||||||
|
"""Mock supervisor client."""
|
||||||
|
|
||||||
|
|
||||||
async def test_async_change_channel(
|
async def test_async_change_channel(
|
||||||
hass: HomeAssistant, otbr_config_entry_multipan
|
hass: HomeAssistant, otbr_config_entry_multipan
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -13,6 +13,11 @@ OTBR_MULTIPAN_URL = "http://core-silabs-multiprotocol:8081"
|
|||||||
OTBR_NON_MULTIPAN_URL = "/dev/ttyAMA1"
|
OTBR_NON_MULTIPAN_URL = "/dev/ttyAMA1"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def mock_supervisor_client(supervisor_client: AsyncMock) -> None:
|
||||||
|
"""Mock supervisor client."""
|
||||||
|
|
||||||
|
|
||||||
async def test_get_allowed_channel(
|
async def test_get_allowed_channel(
|
||||||
hass: HomeAssistant, multiprotocol_addon_manager_mock
|
hass: HomeAssistant, multiprotocol_addon_manager_mock
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Test OTBR Websocket API."""
|
"""Test OTBR Websocket API."""
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import python_otbr_api
|
import python_otbr_api
|
||||||
@ -29,6 +29,11 @@ async def websocket_client(
|
|||||||
return await hass_ws_client(hass)
|
return await hass_ws_client(hass)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def mock_supervisor_client(supervisor_client: AsyncMock) -> None:
|
||||||
|
"""Mock supervisor client."""
|
||||||
|
|
||||||
|
|
||||||
async def test_get_info(
|
async def test_get_info(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
aioclient_mock: AiohttpClientMocker,
|
aioclient_mock: AiohttpClientMocker,
|
||||||
|
@ -121,6 +121,11 @@ def backup(make_backup):
|
|||||||
return make_backup()
|
return make_backup()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def mock_supervisor_client(supervisor_client: AsyncMock) -> None:
|
||||||
|
"""Mock supervisor client."""
|
||||||
|
|
||||||
|
|
||||||
def mock_detect_radio_type(
|
def mock_detect_radio_type(
|
||||||
radio_type: RadioType = RadioType.ezsp,
|
radio_type: RadioType = RadioType.ezsp,
|
||||||
ret: ProbeResult = ProbeResult.RADIO_TYPE_DETECTED,
|
ret: ProbeResult = ProbeResult.RADIO_TYPE_DETECTED,
|
||||||
@ -772,6 +777,7 @@ async def test_user_flow_show_form(hass: HomeAssistant) -> None:
|
|||||||
assert result["step_id"] == "choose_serial_port"
|
assert result["step_id"] == "choose_serial_port"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("addon_not_installed")
|
||||||
@patch("serial.tools.list_ports.comports", MagicMock(return_value=[]))
|
@patch("serial.tools.list_ports.comports", MagicMock(return_value=[]))
|
||||||
async def test_user_flow_show_manual(hass: HomeAssistant) -> None:
|
async def test_user_flow_show_manual(hass: HomeAssistant) -> None:
|
||||||
"""Test user flow manual entry when no comport detected."""
|
"""Test user flow manual entry when no comport detected."""
|
||||||
|
@ -7,6 +7,8 @@ from ipaddress import ip_address
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import AsyncMock, MagicMock, call, patch
|
from unittest.mock import AsyncMock, MagicMock, call, patch
|
||||||
|
|
||||||
|
from aiohasupervisor import SupervisorError
|
||||||
|
from aiohasupervisor.models import AddonsOptions
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import pytest
|
import pytest
|
||||||
from serial.tools.list_ports_common import ListPortInfo
|
from serial.tools.list_ports_common import ListPortInfo
|
||||||
@ -601,10 +603,9 @@ async def test_usb_discovery(
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"device": USB_DISCOVERY_INFO.device,
|
"device": USB_DISCOVERY_INFO.device,
|
||||||
"s0_legacy_key": "new123",
|
"s0_legacy_key": "new123",
|
||||||
"s2_access_control_key": "new456",
|
"s2_access_control_key": "new456",
|
||||||
@ -613,7 +614,7 @@ async def test_usb_discovery(
|
|||||||
"lr_s2_access_control_key": "new654",
|
"lr_s2_access_control_key": "new654",
|
||||||
"lr_s2_authenticated_key": "new321",
|
"lr_s2_authenticated_key": "new321",
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -702,10 +703,9 @@ async def test_usb_discovery_addon_not_running(
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"device": USB_DISCOVERY_INFO.device,
|
"device": USB_DISCOVERY_INFO.device,
|
||||||
"s0_legacy_key": "new123",
|
"s0_legacy_key": "new123",
|
||||||
"s2_access_control_key": "new456",
|
"s2_access_control_key": "new456",
|
||||||
@ -714,7 +714,7 @@ async def test_usb_discovery_addon_not_running(
|
|||||||
"lr_s2_access_control_key": "new654",
|
"lr_s2_access_control_key": "new654",
|
||||||
"lr_s2_authenticated_key": "new321",
|
"lr_s2_authenticated_key": "new321",
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -797,10 +797,9 @@ async def test_discovery_addon_not_running(
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"device": "/test",
|
"device": "/test",
|
||||||
"s0_legacy_key": "new123",
|
"s0_legacy_key": "new123",
|
||||||
"s2_access_control_key": "new456",
|
"s2_access_control_key": "new456",
|
||||||
@ -809,7 +808,7 @@ async def test_discovery_addon_not_running(
|
|||||||
"lr_s2_access_control_key": "new654",
|
"lr_s2_access_control_key": "new654",
|
||||||
"lr_s2_authenticated_key": "new321",
|
"lr_s2_authenticated_key": "new321",
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -900,10 +899,9 @@ async def test_discovery_addon_not_installed(
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"device": "/test",
|
"device": "/test",
|
||||||
"s0_legacy_key": "new123",
|
"s0_legacy_key": "new123",
|
||||||
"s2_access_control_key": "new456",
|
"s2_access_control_key": "new456",
|
||||||
@ -912,7 +910,7 @@ async def test_discovery_addon_not_installed(
|
|||||||
"lr_s2_access_control_key": "new654",
|
"lr_s2_access_control_key": "new654",
|
||||||
"lr_s2_authenticated_key": "new321",
|
"lr_s2_authenticated_key": "new321",
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -1182,7 +1180,7 @@ async def test_addon_running(
|
|||||||
{"config": ADDON_DISCOVERY_INFO},
|
{"config": ADDON_DISCOVERY_INFO},
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
HassioAPIError(),
|
SupervisorError(),
|
||||||
"addon_info_failed",
|
"addon_info_failed",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -1313,10 +1311,9 @@ async def test_addon_installed(
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"device": "/test",
|
"device": "/test",
|
||||||
"s0_legacy_key": "new123",
|
"s0_legacy_key": "new123",
|
||||||
"s2_access_control_key": "new456",
|
"s2_access_control_key": "new456",
|
||||||
@ -1325,7 +1322,7 @@ async def test_addon_installed(
|
|||||||
"lr_s2_access_control_key": "new654",
|
"lr_s2_access_control_key": "new654",
|
||||||
"lr_s2_authenticated_key": "new321",
|
"lr_s2_authenticated_key": "new321",
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -1366,7 +1363,7 @@ async def test_addon_installed(
|
|||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("discovery_info", "start_addon_side_effect"),
|
("discovery_info", "start_addon_side_effect"),
|
||||||
[({"config": ADDON_DISCOVERY_INFO}, HassioAPIError())],
|
[({"config": ADDON_DISCOVERY_INFO}, SupervisorError())],
|
||||||
)
|
)
|
||||||
async def test_addon_installed_start_failure(
|
async def test_addon_installed_start_failure(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -1407,10 +1404,9 @@ async def test_addon_installed_start_failure(
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"device": "/test",
|
"device": "/test",
|
||||||
"s0_legacy_key": "new123",
|
"s0_legacy_key": "new123",
|
||||||
"s2_access_control_key": "new456",
|
"s2_access_control_key": "new456",
|
||||||
@ -1419,7 +1415,7 @@ async def test_addon_installed_start_failure(
|
|||||||
"lr_s2_access_control_key": "new654",
|
"lr_s2_access_control_key": "new654",
|
||||||
"lr_s2_authenticated_key": "new321",
|
"lr_s2_authenticated_key": "new321",
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -1486,10 +1482,9 @@ async def test_addon_installed_failures(
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"device": "/test",
|
"device": "/test",
|
||||||
"s0_legacy_key": "new123",
|
"s0_legacy_key": "new123",
|
||||||
"s2_access_control_key": "new456",
|
"s2_access_control_key": "new456",
|
||||||
@ -1498,7 +1493,7 @@ async def test_addon_installed_failures(
|
|||||||
"lr_s2_access_control_key": "new654",
|
"lr_s2_access_control_key": "new654",
|
||||||
"lr_s2_authenticated_key": "new321",
|
"lr_s2_authenticated_key": "new321",
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -1515,7 +1510,7 @@ async def test_addon_installed_failures(
|
|||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("set_addon_options_side_effect", "discovery_info"),
|
("set_addon_options_side_effect", "discovery_info"),
|
||||||
[(HassioAPIError(), {"config": ADDON_DISCOVERY_INFO})],
|
[(SupervisorError(), {"config": ADDON_DISCOVERY_INFO})],
|
||||||
)
|
)
|
||||||
async def test_addon_installed_set_options_failure(
|
async def test_addon_installed_set_options_failure(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -1556,10 +1551,9 @@ async def test_addon_installed_set_options_failure(
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"device": "/test",
|
"device": "/test",
|
||||||
"s0_legacy_key": "new123",
|
"s0_legacy_key": "new123",
|
||||||
"s2_access_control_key": "new456",
|
"s2_access_control_key": "new456",
|
||||||
@ -1568,7 +1562,7 @@ async def test_addon_installed_set_options_failure(
|
|||||||
"lr_s2_access_control_key": "new654",
|
"lr_s2_access_control_key": "new654",
|
||||||
"lr_s2_authenticated_key": "new321",
|
"lr_s2_authenticated_key": "new321",
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.ABORT
|
assert result["type"] is FlowResultType.ABORT
|
||||||
@ -1634,10 +1628,9 @@ async def test_addon_installed_already_configured(
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"device": "/new",
|
"device": "/new",
|
||||||
"s0_legacy_key": "new123",
|
"s0_legacy_key": "new123",
|
||||||
"s2_access_control_key": "new456",
|
"s2_access_control_key": "new456",
|
||||||
@ -1646,7 +1639,7 @@ async def test_addon_installed_already_configured(
|
|||||||
"lr_s2_access_control_key": "new654",
|
"lr_s2_access_control_key": "new654",
|
||||||
"lr_s2_authenticated_key": "new321",
|
"lr_s2_authenticated_key": "new321",
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -1719,10 +1712,9 @@ async def test_addon_not_installed(
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{
|
AddonsOptions(
|
||||||
"options": {
|
config={
|
||||||
"device": "/test",
|
"device": "/test",
|
||||||
"s0_legacy_key": "new123",
|
"s0_legacy_key": "new123",
|
||||||
"s2_access_control_key": "new456",
|
"s2_access_control_key": "new456",
|
||||||
@ -1731,7 +1723,7 @@ async def test_addon_not_installed(
|
|||||||
"lr_s2_access_control_key": "new654",
|
"lr_s2_access_control_key": "new654",
|
||||||
"lr_s2_authenticated_key": "new321",
|
"lr_s2_authenticated_key": "new321",
|
||||||
}
|
}
|
||||||
},
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -1774,7 +1766,7 @@ async def test_install_addon_failure(
|
|||||||
hass: HomeAssistant, supervisor, addon_not_installed, install_addon
|
hass: HomeAssistant, supervisor, addon_not_installed, install_addon
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test add-on install failure."""
|
"""Test add-on install failure."""
|
||||||
install_addon.side_effect = HassioAPIError()
|
install_addon.side_effect = SupervisorError()
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
@ -1994,9 +1986,8 @@ async def test_options_addon_running(
|
|||||||
|
|
||||||
new_addon_options["device"] = new_addon_options.pop("usb_path")
|
new_addon_options["device"] = new_addon_options.pop("usb_path")
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
|
||||||
"core_zwave_js",
|
"core_zwave_js",
|
||||||
{"options": new_addon_options},
|
AddonsOptions(config=new_addon_options),
|
||||||
)
|
)
|
||||||
assert client.disconnect.call_count == disconnect_calls
|
assert client.disconnect.call_count == disconnect_calls
|
||||||
|
|
||||||
@ -2275,9 +2266,7 @@ async def test_options_different_device(
|
|||||||
assert set_addon_options.call_count == 1
|
assert set_addon_options.call_count == 1
|
||||||
new_addon_options["device"] = new_addon_options.pop("usb_path")
|
new_addon_options["device"] = new_addon_options.pop("usb_path")
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
"core_zwave_js", AddonsOptions(config=new_addon_options)
|
||||||
"core_zwave_js",
|
|
||||||
{"options": new_addon_options},
|
|
||||||
)
|
)
|
||||||
assert client.disconnect.call_count == disconnect_calls
|
assert client.disconnect.call_count == disconnect_calls
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -2298,9 +2287,7 @@ async def test_options_different_device(
|
|||||||
|
|
||||||
assert set_addon_options.call_count == 2
|
assert set_addon_options.call_count == 2
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
"core_zwave_js", AddonsOptions(config=addon_options)
|
||||||
"core_zwave_js",
|
|
||||||
{"options": addon_options},
|
|
||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
assert result["step_id"] == "start_addon"
|
assert result["step_id"] == "start_addon"
|
||||||
@ -2357,7 +2344,7 @@ async def test_options_different_device(
|
|||||||
"emulate_hardware": False,
|
"emulate_hardware": False,
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
[HassioAPIError(), None],
|
[SupervisorError(), None],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{"config": ADDON_DISCOVERY_INFO},
|
{"config": ADDON_DISCOVERY_INFO},
|
||||||
@ -2387,8 +2374,8 @@ async def test_options_different_device(
|
|||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
[
|
[
|
||||||
HassioAPIError(),
|
SupervisorError(),
|
||||||
HassioAPIError(),
|
SupervisorError(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -2441,9 +2428,7 @@ async def test_options_addon_restart_failed(
|
|||||||
assert set_addon_options.call_count == 1
|
assert set_addon_options.call_count == 1
|
||||||
new_addon_options["device"] = new_addon_options.pop("usb_path")
|
new_addon_options["device"] = new_addon_options.pop("usb_path")
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
"core_zwave_js", AddonsOptions(config=new_addon_options)
|
||||||
"core_zwave_js",
|
|
||||||
{"options": new_addon_options},
|
|
||||||
)
|
)
|
||||||
assert client.disconnect.call_count == disconnect_calls
|
assert client.disconnect.call_count == disconnect_calls
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
@ -2461,9 +2446,7 @@ async def test_options_addon_restart_failed(
|
|||||||
old_addon_options.pop("network_key")
|
old_addon_options.pop("network_key")
|
||||||
assert set_addon_options.call_count == 2
|
assert set_addon_options.call_count == 2
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
"core_zwave_js", AddonsOptions(config=old_addon_options)
|
||||||
"core_zwave_js",
|
|
||||||
{"options": old_addon_options},
|
|
||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
assert result["type"] is FlowResultType.SHOW_PROGRESS
|
||||||
assert result["step_id"] == "start_addon"
|
assert result["step_id"] == "start_addon"
|
||||||
@ -2697,9 +2680,7 @@ async def test_options_addon_not_installed(
|
|||||||
|
|
||||||
new_addon_options["device"] = new_addon_options.pop("usb_path")
|
new_addon_options["device"] = new_addon_options.pop("usb_path")
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass,
|
"core_zwave_js", AddonsOptions(config=new_addon_options)
|
||||||
"core_zwave_js",
|
|
||||||
{"options": new_addon_options},
|
|
||||||
)
|
)
|
||||||
assert client.disconnect.call_count == disconnect_calls
|
assert client.disconnect.call_count == disconnect_calls
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import logging
|
|||||||
from unittest.mock import AsyncMock, call, patch
|
from unittest.mock import AsyncMock, call, patch
|
||||||
|
|
||||||
from aiohasupervisor import SupervisorError
|
from aiohasupervisor import SupervisorError
|
||||||
|
from aiohasupervisor.models import AddonsOptions
|
||||||
import pytest
|
import pytest
|
||||||
from zwave_js_server.client import Client
|
from zwave_js_server.client import Client
|
||||||
from zwave_js_server.event import Event
|
from zwave_js_server.event import Event
|
||||||
@ -554,7 +555,7 @@ async def test_start_addon(
|
|||||||
assert install_addon.call_count == 0
|
assert install_addon.call_count == 0
|
||||||
assert set_addon_options.call_count == 1
|
assert set_addon_options.call_count == 1
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass, "core_zwave_js", {"options": addon_options}
|
"core_zwave_js", AddonsOptions(config=addon_options)
|
||||||
)
|
)
|
||||||
assert start_addon.call_count == 1
|
assert start_addon.call_count == 1
|
||||||
assert start_addon.call_args == call("core_zwave_js")
|
assert start_addon.call_args == call("core_zwave_js")
|
||||||
@ -603,13 +604,13 @@ async def test_install_addon(
|
|||||||
assert install_addon.call_args == call("core_zwave_js")
|
assert install_addon.call_args == call("core_zwave_js")
|
||||||
assert set_addon_options.call_count == 1
|
assert set_addon_options.call_count == 1
|
||||||
assert set_addon_options.call_args == call(
|
assert set_addon_options.call_args == call(
|
||||||
hass, "core_zwave_js", {"options": addon_options}
|
"core_zwave_js", AddonsOptions(config=addon_options)
|
||||||
)
|
)
|
||||||
assert start_addon.call_count == 1
|
assert start_addon.call_count == 1
|
||||||
assert start_addon.call_args == call("core_zwave_js")
|
assert start_addon.call_args == call("core_zwave_js")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("addon_info_side_effect", [HassioAPIError("Boom")])
|
@pytest.mark.parametrize("addon_info_side_effect", [SupervisorError("Boom")])
|
||||||
async def test_addon_info_failure(
|
async def test_addon_info_failure(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
addon_installed,
|
addon_installed,
|
||||||
@ -747,7 +748,7 @@ async def test_addon_options_changed(
|
|||||||
[
|
[
|
||||||
("1.0.0", True, 1, 1, None, None),
|
("1.0.0", True, 1, 1, None, None),
|
||||||
("1.0.0", False, 0, 0, None, None),
|
("1.0.0", False, 0, 0, None, None),
|
||||||
("1.0.0", True, 1, 1, HassioAPIError("Boom"), 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, HassioAPIError("Boom")),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user