Skip to content

Commit cdc2192

Browse files
joostlekCopilot
andauthored
Clean up Homelink tests (home-assistant#158685)
Co-authored-by: Copilot <[email protected]>
1 parent 74b1c1f commit cdc2192

File tree

10 files changed

+388
-265
lines changed

10 files changed

+388
-265
lines changed

homeassistant/components/gentex_homelink/__init__.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from . import oauth2
1212
from .const import DOMAIN
13-
from .coordinator import HomeLinkConfigEntry, HomeLinkCoordinator, HomeLinkData
13+
from .coordinator import HomeLinkConfigEntry, HomeLinkCoordinator
1414

1515
PLATFORMS: list[Platform] = [Platform.EVENT]
1616

@@ -44,15 +44,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: HomeLinkConfigEntry) ->
4444
)
4545

4646
await coordinator.async_config_entry_first_refresh()
47-
entry.runtime_data = HomeLinkData(
48-
provider=provider, coordinator=coordinator, last_update_id=None
49-
)
47+
entry.runtime_data = coordinator
5048
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
5149

5250
return True
5351

5452

5553
async def async_unload_entry(hass: HomeAssistant, entry: HomeLinkConfigEntry) -> bool:
5654
"""Unload a config entry."""
57-
await entry.runtime_data.coordinator.async_on_unload(None)
55+
await entry.runtime_data.async_on_unload(None)
5856
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

homeassistant/components/gentex_homelink/coordinator.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from __future__ import annotations
44

55
from collections.abc import Callable
6-
from dataclasses import dataclass
76
from functools import partial
87
import logging
98
from typing import TypedDict
@@ -17,19 +16,10 @@
1716

1817
_LOGGER = logging.getLogger(__name__)
1918

20-
type HomeLinkConfigEntry = ConfigEntry[HomeLinkData]
19+
type HomeLinkConfigEntry = ConfigEntry[HomeLinkCoordinator]
2120
type EventCallback = Callable[[HomeLinkEventData], None]
2221

2322

24-
@dataclass
25-
class HomeLinkData:
26-
"""Class for HomeLink integration runtime data."""
27-
28-
provider: MQTTProvider
29-
coordinator: HomeLinkCoordinator
30-
last_update_id: str | None
31-
32-
3323
class HomeLinkEventData(TypedDict):
3424
"""Data for a single event."""
3525

@@ -68,7 +58,7 @@ def async_add_event_listener(
6858
self._listeners[target_event_id] = update_callback
6959
return partial(self.__async_remove_listener_internal, target_event_id)
7060

71-
def __async_remove_listener_internal(self, listener_id: str):
61+
def __async_remove_listener_internal(self, listener_id: str) -> None:
7262
del self._listeners[listener_id]
7363

7464
@callback
@@ -92,7 +82,7 @@ async def _async_setup(self) -> None:
9282
await self.discover_devices()
9383
self.provider.listen(self.on_message)
9484

95-
async def discover_devices(self):
85+
async def discover_devices(self) -> None:
9686
"""Discover devices and build the Entities."""
9787
self.device_data = await self.provider.discover()
9888

homeassistant/components/gentex_homelink/event.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,24 @@
33
from __future__ import annotations
44

55
from homeassistant.components.event import EventDeviceClass, EventEntity
6-
from homeassistant.config_entries import ConfigEntry
76
from homeassistant.core import HomeAssistant, callback
87
from homeassistant.helpers.device_registry import DeviceInfo
98
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
109

1110
from .const import DOMAIN, EVENT_PRESSED
12-
from .coordinator import HomeLinkCoordinator, HomeLinkEventData
11+
from .coordinator import HomeLinkConfigEntry, HomeLinkCoordinator, HomeLinkEventData
1312

1413

1514
async def async_setup_entry(
1615
hass: HomeAssistant,
17-
config_entry: ConfigEntry,
16+
config_entry: HomeLinkConfigEntry,
1817
async_add_entities: AddConfigEntryEntitiesCallback,
1918
) -> None:
20-
"""Add the entities for the binary sensor."""
21-
coordinator = config_entry.runtime_data.coordinator
19+
"""Add the entities for the event platform."""
20+
coordinator = config_entry.runtime_data
2221

2322
async_add_entities(
24-
HomeLinkEventEntity(button.id, button.name, device.id, device.name, coordinator)
23+
HomeLinkEventEntity(coordinator, button.id, button.name, device.id, device.name)
2524
for device in coordinator.device_data
2625
for button in device.buttons
2726
)
@@ -40,11 +39,11 @@ class HomeLinkEventEntity(EventEntity):
4039

4140
def __init__(
4241
self,
42+
coordinator: HomeLinkCoordinator,
4343
button_id: str,
4444
param_name: str,
4545
device_id: str,
4646
device_name: str,
47-
coordinator: HomeLinkCoordinator,
4847
) -> None:
4948
"""Initialize the event entity."""
5049

@@ -74,5 +73,4 @@ def _handle_event_data_update(self, update_data: HomeLinkEventData) -> None:
7473
if update_data["requestId"] != self.last_request_id:
7574
self._trigger_event(EVENT_PRESSED)
7675
self.last_request_id = update_data["requestId"]
77-
78-
self.async_write_ha_state()
76+
self.async_write_ha_state()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,32 @@
11
"""Tests for the homelink integration."""
2+
3+
from typing import Any
4+
from unittest.mock import AsyncMock
5+
6+
from homeassistant.core import HomeAssistant
7+
8+
from tests.common import MockConfigEntry
9+
10+
11+
async def setup_integration(hass: HomeAssistant, entry: MockConfigEntry) -> None:
12+
"""Set up the homelink integration for testing."""
13+
entry.add_to_hass(hass)
14+
await hass.config_entries.async_setup(entry.entry_id)
15+
await hass.async_block_till_done()
16+
17+
18+
async def update_callback(
19+
hass: HomeAssistant, mock: AsyncMock, update_type: str, data: dict[str, Any]
20+
) -> None:
21+
"""Invoke the MQTT provider's message callback with the specified update type and data."""
22+
for call in mock.listen.call_args_list:
23+
call[0][0](
24+
"topic",
25+
{
26+
"type": update_type,
27+
"data": data,
28+
},
29+
)
30+
31+
await hass.async_block_till_done()
32+
await hass.async_block_till_done()

tests/components/gentex_homelink/conftest.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@
33
from collections.abc import Generator
44
from unittest.mock import AsyncMock, patch
55

6+
from homelink.model.button import Button
7+
import homelink.model.device
68
import pytest
79

10+
from homeassistant.components.gentex_homelink import DOMAIN
11+
12+
from tests.common import MockConfigEntry
13+
814

915
@pytest.fixture
1016
def mock_srp_auth() -> Generator[AsyncMock]:
@@ -24,6 +30,50 @@ def mock_srp_auth() -> Generator[AsyncMock]:
2430
yield instance
2531

2632

33+
@pytest.fixture
34+
def mock_mqtt_provider(mock_device: AsyncMock) -> Generator[AsyncMock]:
35+
"""Mock MQTT provider."""
36+
with patch(
37+
"homeassistant.components.gentex_homelink.MQTTProvider", autospec=True
38+
) as mock_mqtt_provider:
39+
instance = mock_mqtt_provider.return_value
40+
instance.discover.return_value = [mock_device]
41+
yield instance
42+
43+
44+
@pytest.fixture
45+
def mock_device() -> AsyncMock:
46+
"""Mock Device instance."""
47+
device = AsyncMock(spec=homelink.model.device.Device, autospec=True)
48+
buttons = [
49+
Button(id="1", name="Button 1", device=device),
50+
Button(id="2", name="Button 2", device=device),
51+
Button(id="3", name="Button 3", device=device),
52+
]
53+
device.id = "TestDevice"
54+
device.name = "TestDevice"
55+
device.buttons = buttons
56+
return device
57+
58+
59+
@pytest.fixture
60+
def mock_config_entry() -> MockConfigEntry:
61+
"""Mock setup entry."""
62+
return MockConfigEntry(
63+
domain=DOMAIN,
64+
data={
65+
"auth_implementation": "gentex_homelink",
66+
"token": {
67+
"access_token": "access",
68+
"refresh_token": "refresh",
69+
"expires_in": 3600,
70+
"token_type": "bearer",
71+
"expires_at": 1234567890,
72+
},
73+
},
74+
)
75+
76+
2777
@pytest.fixture
2878
def mock_setup_entry() -> Generator[AsyncMock]:
2979
"""Mock setup entry."""
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# serializer version: 1
2+
# name: test_entities[event.testdevice_button_1-entry]
3+
EntityRegistryEntrySnapshot({
4+
'aliases': set({
5+
}),
6+
'area_id': None,
7+
'capabilities': dict({
8+
'event_types': list([
9+
'Pressed',
10+
]),
11+
}),
12+
'config_entry_id': <ANY>,
13+
'config_subentry_id': <ANY>,
14+
'device_class': None,
15+
'device_id': <ANY>,
16+
'disabled_by': None,
17+
'domain': 'event',
18+
'entity_category': None,
19+
'entity_id': 'event.testdevice_button_1',
20+
'has_entity_name': True,
21+
'hidden_by': None,
22+
'icon': None,
23+
'id': <ANY>,
24+
'labels': set({
25+
}),
26+
'name': None,
27+
'options': dict({
28+
}),
29+
'original_device_class': <EventDeviceClass.BUTTON: 'button'>,
30+
'original_icon': None,
31+
'original_name': 'Button 1',
32+
'platform': 'gentex_homelink',
33+
'previous_unique_id': None,
34+
'suggested_object_id': None,
35+
'supported_features': 0,
36+
'translation_key': None,
37+
'unique_id': '1',
38+
'unit_of_measurement': None,
39+
})
40+
# ---
41+
# name: test_entities[event.testdevice_button_1-state]
42+
StateSnapshot({
43+
'attributes': ReadOnlyDict({
44+
'device_class': 'button',
45+
'event_type': None,
46+
'event_types': list([
47+
'Pressed',
48+
]),
49+
'friendly_name': 'TestDevice Button 1',
50+
}),
51+
'context': <ANY>,
52+
'entity_id': 'event.testdevice_button_1',
53+
'last_changed': <ANY>,
54+
'last_reported': <ANY>,
55+
'last_updated': <ANY>,
56+
'state': 'unknown',
57+
})
58+
# ---
59+
# name: test_entities[event.testdevice_button_2-entry]
60+
EntityRegistryEntrySnapshot({
61+
'aliases': set({
62+
}),
63+
'area_id': None,
64+
'capabilities': dict({
65+
'event_types': list([
66+
'Pressed',
67+
]),
68+
}),
69+
'config_entry_id': <ANY>,
70+
'config_subentry_id': <ANY>,
71+
'device_class': None,
72+
'device_id': <ANY>,
73+
'disabled_by': None,
74+
'domain': 'event',
75+
'entity_category': None,
76+
'entity_id': 'event.testdevice_button_2',
77+
'has_entity_name': True,
78+
'hidden_by': None,
79+
'icon': None,
80+
'id': <ANY>,
81+
'labels': set({
82+
}),
83+
'name': None,
84+
'options': dict({
85+
}),
86+
'original_device_class': <EventDeviceClass.BUTTON: 'button'>,
87+
'original_icon': None,
88+
'original_name': 'Button 2',
89+
'platform': 'gentex_homelink',
90+
'previous_unique_id': None,
91+
'suggested_object_id': None,
92+
'supported_features': 0,
93+
'translation_key': None,
94+
'unique_id': '2',
95+
'unit_of_measurement': None,
96+
})
97+
# ---
98+
# name: test_entities[event.testdevice_button_2-state]
99+
StateSnapshot({
100+
'attributes': ReadOnlyDict({
101+
'device_class': 'button',
102+
'event_type': None,
103+
'event_types': list([
104+
'Pressed',
105+
]),
106+
'friendly_name': 'TestDevice Button 2',
107+
}),
108+
'context': <ANY>,
109+
'entity_id': 'event.testdevice_button_2',
110+
'last_changed': <ANY>,
111+
'last_reported': <ANY>,
112+
'last_updated': <ANY>,
113+
'state': 'unknown',
114+
})
115+
# ---
116+
# name: test_entities[event.testdevice_button_3-entry]
117+
EntityRegistryEntrySnapshot({
118+
'aliases': set({
119+
}),
120+
'area_id': None,
121+
'capabilities': dict({
122+
'event_types': list([
123+
'Pressed',
124+
]),
125+
}),
126+
'config_entry_id': <ANY>,
127+
'config_subentry_id': <ANY>,
128+
'device_class': None,
129+
'device_id': <ANY>,
130+
'disabled_by': None,
131+
'domain': 'event',
132+
'entity_category': None,
133+
'entity_id': 'event.testdevice_button_3',
134+
'has_entity_name': True,
135+
'hidden_by': None,
136+
'icon': None,
137+
'id': <ANY>,
138+
'labels': set({
139+
}),
140+
'name': None,
141+
'options': dict({
142+
}),
143+
'original_device_class': <EventDeviceClass.BUTTON: 'button'>,
144+
'original_icon': None,
145+
'original_name': 'Button 3',
146+
'platform': 'gentex_homelink',
147+
'previous_unique_id': None,
148+
'suggested_object_id': None,
149+
'supported_features': 0,
150+
'translation_key': None,
151+
'unique_id': '3',
152+
'unit_of_measurement': None,
153+
})
154+
# ---
155+
# name: test_entities[event.testdevice_button_3-state]
156+
StateSnapshot({
157+
'attributes': ReadOnlyDict({
158+
'device_class': 'button',
159+
'event_type': None,
160+
'event_types': list([
161+
'Pressed',
162+
]),
163+
'friendly_name': 'TestDevice Button 3',
164+
}),
165+
'context': <ANY>,
166+
'entity_id': 'event.testdevice_button_3',
167+
'last_changed': <ANY>,
168+
'last_reported': <ANY>,
169+
'last_updated': <ANY>,
170+
'state': 'unknown',
171+
})
172+
# ---

0 commit comments

Comments
 (0)