Skip to content

Commit 62b27c8

Browse files
committed
Migrate discovery apis to aiohasupervisor
1 parent 0b4e3c3 commit 62b27c8

File tree

12 files changed

+715
-277
lines changed

12 files changed

+715
-277
lines changed

homeassistant/components/hassio/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@
101101
HassIO,
102102
HassioAPIError,
103103
async_create_backup,
104-
async_get_addon_discovery_info,
105104
async_get_green_settings,
106105
async_get_yellow_settings,
107106
async_reboot_host,

homeassistant/components/hassio/addon_manager.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@
2121
from homeassistant.core import HomeAssistant, callback
2222
from homeassistant.exceptions import HomeAssistantError
2323

24-
from .handler import (
25-
HassioAPIError,
26-
async_create_backup,
27-
async_get_addon_discovery_info,
28-
get_supervisor_client,
29-
)
24+
from .handler import HassioAPIError, async_create_backup, get_supervisor_client
3025

3126
type _FuncType[_T, **_P, _R] = Callable[Concatenate[_T, _P], Awaitable[_R]]
3227
type _ReturnFuncType[_T, **_P, _R] = Callable[
@@ -128,18 +123,25 @@ def task_in_progress(self) -> bool:
128123
)
129124
)
130125

131-
@api_error("Failed to get the {addon_name} add-on discovery info")
126+
@api_error(
127+
"Failed to get the {addon_name} add-on discovery info",
128+
expected_error_type=SupervisorError,
129+
)
132130
async def async_get_addon_discovery_info(self) -> dict:
133131
"""Return add-on discovery info."""
134-
discovery_info = await async_get_addon_discovery_info(
135-
self._hass, self.addon_slug
132+
discovery_info = next(
133+
(
134+
msg
135+
for msg in await self._supervisor_client.discovery.list()
136+
if msg.addon == self.addon_slug
137+
),
138+
None,
136139
)
137140

138141
if not discovery_info:
139142
raise AddonError(f"Failed to get {self.addon_name} add-on discovery info")
140143

141-
discovery_info_config: dict = discovery_info["config"]
142-
return discovery_info_config
144+
return discovery_info.config
143145

144146
@api_error(
145147
"Failed to get the {addon_name} add-on info",

homeassistant/components/hassio/discovery.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from typing import Any
99

1010
from aiohasupervisor import SupervisorError
11+
from aiohasupervisor.models import Discovery
1112
from aiohttp import web
1213
from aiohttp.web_exceptions import HTTPServiceUnavailable
1314

@@ -19,8 +20,8 @@
1920
from homeassistant.helpers import discovery_flow
2021
from homeassistant.helpers.dispatcher import async_dispatcher_connect
2122

22-
from .const import ATTR_ADDON, ATTR_CONFIG, ATTR_DISCOVERY, ATTR_UUID, DOMAIN
23-
from .handler import HassIO, HassioAPIError, get_supervisor_client
23+
from .const import ATTR_ADDON, ATTR_UUID, DOMAIN
24+
from .handler import HassIO, get_supervisor_client
2425

2526
_LOGGER = logging.getLogger(__name__)
2627

@@ -39,20 +40,21 @@ class HassioServiceInfo(BaseServiceInfo):
3940
def async_setup_discovery_view(hass: HomeAssistant, hassio: HassIO) -> None:
4041
"""Discovery setup."""
4142
hassio_discovery = HassIODiscovery(hass, hassio)
43+
supervisor_client = get_supervisor_client(hass)
4244
hass.http.register_view(hassio_discovery)
4345

4446
# Handle exists discovery messages
4547
async def _async_discovery_start_handler(event: Event) -> None:
4648
"""Process all exists discovery on startup."""
4749
try:
48-
data = await hassio.retrieve_discovery_messages()
49-
except HassioAPIError as err:
50+
data = await supervisor_client.discovery.list()
51+
except SupervisorError as err:
5052
_LOGGER.error("Can't read discover info: %s", err)
5153
return
5254

5355
jobs = [
5456
asyncio.create_task(hassio_discovery.async_process_new(discovery))
55-
for discovery in data[ATTR_DISCOVERY]
57+
for discovery in data
5658
]
5759
if jobs:
5860
await asyncio.wait(jobs)
@@ -95,8 +97,8 @@ async def post(self, request: web.Request, uuid: str) -> web.Response:
9597
"""Handle new discovery requests."""
9698
# Fetch discovery data and prevent injections
9799
try:
98-
data = await self.hassio.get_discovery_message(uuid)
99-
except HassioAPIError as err:
100+
data = await self._supervisor_client.discovery.get(uuid)
101+
except SupervisorError as err:
100102
_LOGGER.error("Can't read discovery data: %s", err)
101103
raise HTTPServiceUnavailable from None
102104

@@ -113,52 +115,50 @@ async def delete(self, request: web.Request, uuid: str) -> web.Response:
113115
async def async_rediscover(self, uuid: str) -> None:
114116
"""Rediscover add-on when config entry is removed."""
115117
try:
116-
data = await self.hassio.get_discovery_message(uuid)
117-
except HassioAPIError as err:
118+
data = await self._supervisor_client.discovery.get(uuid)
119+
except SupervisorError as err:
118120
_LOGGER.debug("Can't read discovery data: %s", err)
119121
else:
120122
await self.async_process_new(data)
121123

122-
async def async_process_new(self, data: dict[str, Any]) -> None:
124+
async def async_process_new(self, data: Discovery) -> None:
123125
"""Process add discovery entry."""
124-
service: str = data[ATTR_SERVICE]
125-
config_data: dict[str, Any] = data[ATTR_CONFIG]
126-
slug: str = data[ATTR_ADDON]
127-
uuid: str = data[ATTR_UUID]
128-
129126
# Read additional Add-on info
130127
try:
131-
addon_info = await self._supervisor_client.addons.addon_info(slug)
128+
addon_info = await self._supervisor_client.addons.addon_info(data.addon)
132129
except SupervisorError as err:
133130
_LOGGER.error("Can't read add-on info: %s", err)
134131
return
135132

136-
config_data[ATTR_ADDON] = addon_info.name
133+
data.config[ATTR_ADDON] = addon_info.name
137134

138135
# Use config flow
139136
discovery_flow.async_create_flow(
140137
self.hass,
141-
service,
138+
data.service,
142139
context={"source": config_entries.SOURCE_HASSIO},
143140
data=HassioServiceInfo(
144-
config=config_data, name=addon_info.name, slug=slug, uuid=uuid
141+
config=data.config,
142+
name=addon_info.name,
143+
slug=data.addon,
144+
uuid=data.uuid,
145145
),
146146
discovery_key=discovery_flow.DiscoveryKey(
147147
domain=DOMAIN,
148-
key=data[ATTR_UUID],
148+
key=data.uuid,
149149
version=1,
150150
),
151151
)
152152

153153
async def async_process_del(self, data: dict[str, Any]) -> None:
154154
"""Process remove discovery entry."""
155-
service = data[ATTR_SERVICE]
156-
uuid = data[ATTR_UUID]
155+
service: str = data[ATTR_SERVICE]
156+
uuid: str = data[ATTR_UUID]
157157

158158
# Check if really deletet / prevent injections
159159
try:
160-
data = await self.hassio.get_discovery_message(uuid)
161-
except HassioAPIError:
160+
data = await self._supervisor_client.discovery.get(uuid)
161+
except SupervisorError:
162162
pass
163163
else:
164164
_LOGGER.warning("Retrieve wrong unload for %s", service)

homeassistant/components/hassio/handler.py

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from homeassistant.helpers.singleton import singleton
2525
from homeassistant.loader import bind_hass
2626

27-
from .const import ATTR_DISCOVERY, ATTR_MESSAGE, ATTR_RESULT, DOMAIN, X_HASS_SOURCE
27+
from .const import ATTR_MESSAGE, ATTR_RESULT, DOMAIN, X_HASS_SOURCE
2828

2929
_LOGGER = logging.getLogger(__name__)
3030

@@ -76,15 +76,6 @@ async def async_update_diagnostics(hass: HomeAssistant, diagnostics: bool) -> bo
7676
return await hassio.update_diagnostics(diagnostics)
7777

7878

79-
@bind_hass
80-
async def async_get_addon_discovery_info(hass: HomeAssistant, slug: str) -> dict | None:
81-
"""Return discovery data for an add-on."""
82-
hassio: HassIO = hass.data[DOMAIN]
83-
data = await hassio.retrieve_discovery_messages()
84-
discovered_addons = data[ATTR_DISCOVERY]
85-
return next((addon for addon in discovered_addons if addon["addon"] == slug), None)
86-
87-
8879
@bind_hass
8980
@api_data
9081
async def async_create_backup(
@@ -332,22 +323,6 @@ def refresh_updates(self) -> Coroutine:
332323
"""
333324
return self.send_command("/refresh_updates", timeout=300)
334325

335-
@api_data
336-
def retrieve_discovery_messages(self) -> Coroutine:
337-
"""Return all discovery data from Hass.io API.
338-
339-
This method returns a coroutine.
340-
"""
341-
return self.send_command("/discovery", method="get", timeout=60)
342-
343-
@api_data
344-
def get_discovery_message(self, uuid: str) -> Coroutine:
345-
"""Return a single discovery data message.
346-
347-
This method returns a coroutine.
348-
"""
349-
return self.send_command(f"/discovery/{uuid}", method="get")
350-
351326
@api_data
352327
def get_resolution_info(self) -> Coroutine:
353328
"""Return data for Supervisor resolution center.

tests/components/conftest.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from typing import TYPE_CHECKING, Any
99
from unittest.mock import AsyncMock, MagicMock, patch
1010

11-
from aiohasupervisor.models import Repository, StoreAddon, StoreInfo
11+
from aiohasupervisor.models import Discovery, Repository, StoreAddon, StoreInfo
1212
import pytest
1313

1414
from homeassistant.config_entries import (
@@ -205,12 +205,9 @@ def addon_manager_fixture(
205205

206206

207207
@pytest.fixture(name="discovery_info")
208-
def discovery_info_fixture() -> Any:
208+
def discovery_info_fixture() -> list[Discovery]:
209209
"""Return the discovery info from the supervisor."""
210-
# pylint: disable-next=import-outside-toplevel
211-
from .hassio.common import mock_discovery_info
212-
213-
return mock_discovery_info()
210+
return []
214211

215212

216213
@pytest.fixture(name="discovery_info_side_effect")
@@ -221,13 +218,29 @@ def discovery_info_side_effect_fixture() -> Any | None:
221218

222219
@pytest.fixture(name="get_addon_discovery_info")
223220
def get_addon_discovery_info_fixture(
224-
discovery_info: dict[str, Any], discovery_info_side_effect: Any | None
225-
) -> Generator[AsyncMock]:
221+
supervisor_client: AsyncMock,
222+
discovery_info: list[Discovery],
223+
discovery_info_side_effect: Any | None,
224+
) -> AsyncMock:
226225
"""Mock get add-on discovery info."""
227-
# pylint: disable-next=import-outside-toplevel
228-
from .hassio.common import mock_get_addon_discovery_info
226+
supervisor_client.discovery.list.return_value = discovery_info
227+
supervisor_client.discovery.list.side_effect = discovery_info_side_effect
228+
return supervisor_client.discovery.list
229229

230-
yield from mock_get_addon_discovery_info(discovery_info, discovery_info_side_effect)
230+
231+
@pytest.fixture(name="get_discovery_message_side_effect")
232+
def get_discovery_message_side_effect_fixture() -> Any | None:
233+
"""Side effect for getting a discovery message by uuid."""
234+
return None
235+
236+
237+
@pytest.fixture(name="get_discovery_message")
238+
def get_discovery_message_fixture(
239+
supervisor_client: AsyncMock, get_discovery_message_side_effect: Any | None
240+
) -> AsyncMock:
241+
"""Mock getting a discovery message by uuid."""
242+
supervisor_client.discovery.get.side_effect = get_discovery_message_side_effect
243+
return supervisor_client.discovery.get
231244

232245

233246
@pytest.fixture(name="addon_store_info_side_effect")
@@ -456,6 +469,7 @@ def supervisor_client() -> Generator[AsyncMock]:
456469
"""Mock the supervisor client."""
457470
supervisor_client = AsyncMock()
458471
supervisor_client.addons = AsyncMock()
472+
supervisor_client.discovery = AsyncMock()
459473
with (
460474
patch(
461475
"homeassistant.components.hassio.get_supervisor_client",

tests/components/hassio/common.py

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import logging
88
from types import MethodType
99
from typing import Any
10-
from unittest.mock import DEFAULT, AsyncMock, Mock, patch
10+
from unittest.mock import AsyncMock, Mock, patch
1111

1212
from aiohasupervisor.models import (
1313
AddonsOptions,
@@ -75,23 +75,6 @@ def mock_addon_manager(hass: HomeAssistant) -> AddonManager:
7575
return AddonManager(hass, LOGGER, "Test", "test_addon")
7676

7777

78-
def mock_discovery_info() -> Any:
79-
"""Return the discovery info from the supervisor."""
80-
return DEFAULT
81-
82-
83-
def mock_get_addon_discovery_info(
84-
discovery_info: dict[str, Any], discovery_info_side_effect: Any | None
85-
) -> Generator[AsyncMock]:
86-
"""Mock get add-on discovery info."""
87-
with patch(
88-
"homeassistant.components.hassio.addon_manager.async_get_addon_discovery_info",
89-
side_effect=discovery_info_side_effect,
90-
return_value=discovery_info,
91-
) as get_addon_discovery_info:
92-
yield get_addon_discovery_info
93-
94-
9578
def mock_addon_store_info(
9679
supervisor_client: AsyncMock,
9780
addon_store_info_side_effect: Any | None,

tests/components/hassio/test_addon_manager.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
import asyncio
66
from typing import Any
77
from unittest.mock import AsyncMock, call
8+
from uuid import uuid4
89

910
from aiohasupervisor import SupervisorError
10-
from aiohasupervisor.models import AddonsOptions
11+
from aiohasupervisor.models import AddonsOptions, Discovery
1112
import pytest
1213

1314
from homeassistant.components.hassio.addon_manager import (
@@ -62,7 +63,11 @@ async def test_get_addon_discovery_info(
6263
addon_manager: AddonManager, get_addon_discovery_info: AsyncMock
6364
) -> None:
6465
"""Test get addon discovery info."""
65-
get_addon_discovery_info.return_value = {"config": {"test_key": "test"}}
66+
get_addon_discovery_info.return_value = [
67+
Discovery(
68+
addon="test_addon", service="", uuid=uuid4(), config={"test_key": "test"}
69+
)
70+
]
6671

6772
assert await addon_manager.async_get_addon_discovery_info() == {"test_key": "test"}
6873

@@ -73,8 +78,6 @@ async def test_missing_addon_discovery_info(
7378
addon_manager: AddonManager, get_addon_discovery_info: AsyncMock
7479
) -> None:
7580
"""Test missing addon discovery info."""
76-
get_addon_discovery_info.return_value = None
77-
7881
with pytest.raises(AddonError):
7982
await addon_manager.async_get_addon_discovery_info()
8083

@@ -85,7 +88,7 @@ async def test_get_addon_discovery_info_error(
8588
addon_manager: AddonManager, get_addon_discovery_info: AsyncMock
8689
) -> None:
8790
"""Test get addon discovery info raises error."""
88-
get_addon_discovery_info.side_effect = HassioAPIError("Boom")
91+
get_addon_discovery_info.side_effect = SupervisorError("Boom")
8992

9093
with pytest.raises(AddonError) as err:
9194
assert await addon_manager.async_get_addon_discovery_info()

0 commit comments

Comments
 (0)