Skip to content

Commit a061e47

Browse files
authored
Improve eurotronic_cometblue tests (#168046)
1 parent e5c49b6 commit a061e47

6 files changed

Lines changed: 568 additions & 44 deletions

File tree

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,67 @@
11
"""Tests for the Eurotronic Comet Blue integration."""
2+
3+
from eurotronic_cometblue_ha import const as cometblue_const
4+
5+
from homeassistant.const import CONF_PIN
6+
7+
FIXTURE_DEVICE_NAME = "Comet Blue"
8+
FIXTURE_MAC = "aa:bb:cc:dd:ee:ff"
9+
FIXTURE_RSSI = -60
10+
FIXTURE_SERVICE_UUID = "47e9ee00-47e9-11e4-8939-164230d1df67"
11+
12+
WRITEABLE_CHARACTERISTICS = [
13+
cometblue_const.CHARACTERISTIC_DATETIME,
14+
cometblue_const.CHARACTERISTIC_MONDAY,
15+
cometblue_const.CHARACTERISTIC_TUESDAY,
16+
cometblue_const.CHARACTERISTIC_WEDNESDAY,
17+
cometblue_const.CHARACTERISTIC_THURSDAY,
18+
cometblue_const.CHARACTERISTIC_FRIDAY,
19+
cometblue_const.CHARACTERISTIC_SATURDAY,
20+
cometblue_const.CHARACTERISTIC_SUNDAY,
21+
cometblue_const.CHARACTERISTIC_HOLIDAY_1,
22+
cometblue_const.CHARACTERISTIC_SETTINGS,
23+
cometblue_const.CHARACTERISTIC_TEMPERATURE,
24+
cometblue_const.CHARACTERISTIC_PIN,
25+
]
26+
WRITEABLE_CHARACTERISTICS_ALLOW_UNCHANGED = [
27+
cometblue_const.CHARACTERISTIC_SETTINGS,
28+
cometblue_const.CHARACTERISTIC_TEMPERATURE,
29+
]
30+
31+
FIXTURE_DEFAULT_CHARACTERISTICS = {
32+
cometblue_const.CHARACTERISTIC_MODEL: b"Comet Blue",
33+
cometblue_const.CHARACTERISTIC_VERSION: b"0.0.10",
34+
cometblue_const.CHARACTERISTIC_MANUFACTURER: b"Eurotronic GmbH",
35+
cometblue_const.CHARACTERISTIC_HOLIDAY_1: [
36+
128,
37+
27,
38+
11,
39+
22,
40+
128,
41+
27,
42+
11,
43+
22,
44+
34,
45+
],
46+
cometblue_const.CHARACTERISTIC_TEMPERATURE: [
47+
41,
48+
40,
49+
34,
50+
42,
51+
0,
52+
4,
53+
10,
54+
],
55+
cometblue_const.CHARACTERISTIC_BATTERY: b"48",
56+
cometblue_const.CHARACTERISTIC_MONDAY: [37, 137, 0, 0, 0, 0, 0, 0],
57+
cometblue_const.CHARACTERISTIC_TUESDAY: [37, 137, 0, 0, 0, 0, 0, 0],
58+
cometblue_const.CHARACTERISTIC_WEDNESDAY: [37, 137, 0, 0, 0, 0, 0, 0],
59+
cometblue_const.CHARACTERISTIC_THURSDAY: [37, 137, 0, 0, 0, 0, 0, 0],
60+
cometblue_const.CHARACTERISTIC_FRIDAY: [0, 1, 10, 20, 21, 130, 140, 143],
61+
cometblue_const.CHARACTERISTIC_SATURDAY: [37, 137, 0, 0, 0, 0, 0, 0],
62+
cometblue_const.CHARACTERISTIC_SUNDAY: [37, 137, 0, 0, 0, 0, 0, 0],
63+
}
64+
65+
FIXTURE_USER_INPUT = {
66+
CONF_PIN: "000000",
67+
}

tests/components/eurotronic_cometblue/conftest.py

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Session fixtures."""
22

3-
from collections.abc import Generator
3+
from collections.abc import Buffer, Generator
44
from typing import Any
55
from unittest.mock import AsyncMock, patch
66
import uuid
@@ -12,17 +12,21 @@
1212
import pytest
1313

1414
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
15+
from homeassistant.components.eurotronic_cometblue import PLATFORMS
1516
from homeassistant.components.eurotronic_cometblue.const import DOMAIN
16-
from homeassistant.const import CONF_ADDRESS
17+
from homeassistant.const import CONF_ADDRESS, Platform
18+
from homeassistant.core import HomeAssistant
1719
from homeassistant.helpers.device_registry import format_mac
1820

19-
from .const import (
21+
from . import (
22+
FIXTURE_DEFAULT_CHARACTERISTICS,
2023
FIXTURE_DEVICE_NAME,
21-
FIXTURE_GATT_CHARACTERISTICS,
2224
FIXTURE_MAC,
2325
FIXTURE_RSSI,
2426
FIXTURE_SERVICE_UUID,
2527
FIXTURE_USER_INPUT,
28+
WRITEABLE_CHARACTERISTICS,
29+
WRITEABLE_CHARACTERISTICS_ALLOW_UNCHANGED,
2630
)
2731

2832
from tests.common import MockConfigEntry
@@ -58,9 +62,24 @@
5862
)
5963

6064

65+
def _normalize_characteristic(
66+
char_specifier: BleakGATTCharacteristic | int | str | uuid.UUID,
67+
) -> uuid.UUID:
68+
"""Normalize a characteristic specifier to UUID."""
69+
if not isinstance(char_specifier, (BleakGATTCharacteristic, str, uuid.UUID)):
70+
raise BleakCharacteristicNotFoundError(char_specifier)
71+
if isinstance(char_specifier, BleakGATTCharacteristic):
72+
char_specifier = char_specifier.uuid
73+
if not isinstance(char_specifier, uuid.UUID):
74+
char_specifier = uuid.UUID(char_specifier)
75+
return char_specifier
76+
77+
6178
class MockCometBlueBleakClient(CometBlueBleakClient):
6279
"""Mock BleakClient."""
6380

81+
characteristics: dict[uuid.UUID, bytearray] = {}
82+
6483
def __init__(self, *args: Any, **kwargs: Any) -> None:
6584
"""Mock init."""
6685
super().__init__(*args, **kwargs)
@@ -94,17 +113,40 @@ async def read_gatt_char(
94113
**kwargs: Any,
95114
) -> bytearray:
96115
"""Mock read_gatt_char."""
97-
if not isinstance(char_specifier, (BleakGATTCharacteristic, str, uuid.UUID)):
98-
raise BleakCharacteristicNotFoundError(char_specifier)
99-
if isinstance(char_specifier, BleakGATTCharacteristic):
100-
char_specifier = char_specifier.uuid
101-
if not isinstance(char_specifier, uuid.UUID):
102-
char_specifier = uuid.UUID(char_specifier)
116+
char_specifier = _normalize_characteristic(char_specifier)
103117
try:
104-
return FIXTURE_GATT_CHARACTERISTICS[char_specifier]
118+
return bytearray(self.characteristics[char_specifier])
105119
except KeyError:
106120
raise BleakCharacteristicNotFoundError(char_specifier)
107121

122+
async def write_gatt_char(
123+
self,
124+
char_specifier: BleakGATTCharacteristic | int | str | uuid.UUID,
125+
data: Buffer,
126+
response: bool | None = None,
127+
) -> None:
128+
"""Mock write_gatt_char."""
129+
char_specifier = _normalize_characteristic(char_specifier)
130+
if char_specifier not in WRITEABLE_CHARACTERISTICS:
131+
raise BleakCharacteristicNotFoundError(char_specifier)
132+
data = bytearray(data)
133+
# when writing temperature it is possible that 128 will be sent, meaning "no change"
134+
# we have to restore the original value in this case to keep tests working
135+
if char_specifier in WRITEABLE_CHARACTERISTICS_ALLOW_UNCHANGED:
136+
for i, byte in enumerate(data):
137+
if byte == 128:
138+
data[i] = self.characteristics[char_specifier][i]
139+
self.characteristics[char_specifier] = data
140+
141+
142+
@pytest.fixture
143+
def mock_gatt_characteristics() -> dict[uuid.UUID, bytearray]:
144+
"""Provide a mutable per-test GATT characteristic store."""
145+
return {
146+
characteristic: bytearray(value)
147+
for characteristic, value in FIXTURE_DEFAULT_CHARACTERISTICS.items()
148+
}
149+
108150

109151
@pytest.fixture
110152
def mock_service_info() -> Generator[None]:
@@ -133,13 +175,26 @@ def mock_ble_device() -> Generator[None]:
133175

134176

135177
@pytest.fixture(autouse=True)
136-
def mock_bluetooth(enable_bluetooth: None) -> Generator[None]:
178+
def mock_bluetooth(
179+
enable_bluetooth: None,
180+
mock_gatt_characteristics: dict[uuid.UUID, bytearray],
181+
) -> Generator[None]:
137182
"""Auto mock bluetooth."""
138183

139-
with patch(
140-
"eurotronic_cometblue_ha.CometBlueBleakClient", MockCometBlueBleakClient
184+
MockCometBlueBleakClient.characteristics = mock_gatt_characteristics
185+
with (
186+
patch(
187+
"homeassistant.components.eurotronic_cometblue.entity.bluetooth.async_address_present",
188+
return_value=True,
189+
),
190+
patch(
191+
"homeassistant.components.eurotronic_cometblue.coordinator.COMMAND_RETRY_INTERVAL",
192+
0,
193+
),
194+
patch("eurotronic_cometblue_ha.CometBlueBleakClient", MockCometBlueBleakClient),
141195
):
142196
yield
197+
MockCometBlueBleakClient.characteristics = {}
143198

144199

145200
# Home Assistant related fixtures
@@ -164,3 +219,16 @@ def mock_setup_entry() -> Generator[AsyncMock]:
164219
return_value=True,
165220
) as mock_setup:
166221
yield mock_setup
222+
223+
224+
async def setup_with_selected_platforms(
225+
hass: HomeAssistant, entry: MockConfigEntry, platforms: list[Platform] | None = None
226+
) -> None:
227+
"""Set up the Eurotronic Comet Blue integration with the selected platforms."""
228+
entry.add_to_hass(hass)
229+
with patch(
230+
"homeassistant.components.eurotronic_cometblue.PLATFORMS",
231+
platforms or PLATFORMS,
232+
):
233+
assert await hass.config_entries.async_setup(entry.entry_id)
234+
await hass.async_block_till_done()

tests/components/eurotronic_cometblue/const.py

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# serializer version: 1
2+
# name: test_climate_state[climate.comet_blue_aa_bb_cc_dd_ee_ff-entry]
3+
EntityRegistryEntrySnapshot({
4+
'aliases': list([
5+
None,
6+
]),
7+
'area_id': None,
8+
'capabilities': dict({
9+
'hvac_modes': list([
10+
<HVACMode.AUTO: 'auto'>,
11+
<HVACMode.HEAT: 'heat'>,
12+
<HVACMode.OFF: 'off'>,
13+
]),
14+
'max_temp': 28.5,
15+
'min_temp': 7.5,
16+
'preset_modes': list([
17+
'comfort',
18+
'eco',
19+
'boost',
20+
'away',
21+
'none',
22+
]),
23+
'target_temp_step': 0.5,
24+
}),
25+
'config_entry_id': <ANY>,
26+
'config_subentry_id': <ANY>,
27+
'device_class': None,
28+
'device_id': <ANY>,
29+
'disabled_by': None,
30+
'domain': 'climate',
31+
'entity_category': None,
32+
'entity_id': 'climate.comet_blue_aa_bb_cc_dd_ee_ff',
33+
'has_entity_name': True,
34+
'hidden_by': None,
35+
'icon': None,
36+
'id': <ANY>,
37+
'labels': set({
38+
}),
39+
'name': None,
40+
'object_id_base': None,
41+
'options': dict({
42+
}),
43+
'original_device_class': None,
44+
'original_icon': None,
45+
'original_name': None,
46+
'platform': 'eurotronic_cometblue',
47+
'previous_unique_id': None,
48+
'suggested_object_id': None,
49+
'supported_features': <ClimateEntityFeature: 403>,
50+
'translation_key': None,
51+
'unique_id': 'aa:bb:cc:dd:ee:ff',
52+
'unit_of_measurement': None,
53+
})
54+
# ---
55+
# name: test_climate_state[climate.comet_blue_aa_bb_cc_dd_ee_ff-state]
56+
StateSnapshot({
57+
'attributes': ReadOnlyDict({
58+
'current_temperature': 20.5,
59+
'friendly_name': 'Comet Blue aa:bb:cc:dd:ee:ff',
60+
'hvac_modes': list([
61+
<HVACMode.AUTO: 'auto'>,
62+
<HVACMode.HEAT: 'heat'>,
63+
<HVACMode.OFF: 'off'>,
64+
]),
65+
'max_temp': 28.5,
66+
'min_temp': 7.5,
67+
'preset_mode': 'none',
68+
'preset_modes': list([
69+
'comfort',
70+
'eco',
71+
'boost',
72+
'away',
73+
'none',
74+
]),
75+
'supported_features': <ClimateEntityFeature: 403>,
76+
'target_temp_high': 21.0,
77+
'target_temp_low': 17.0,
78+
'target_temp_step': 0.5,
79+
'temperature': 20.0,
80+
}),
81+
'context': <ANY>,
82+
'entity_id': 'climate.comet_blue_aa_bb_cc_dd_ee_ff',
83+
'last_changed': <ANY>,
84+
'last_reported': <ANY>,
85+
'last_updated': <ANY>,
86+
'state': 'auto',
87+
})
88+
# ---

0 commit comments

Comments
 (0)