Fix device name not set on all incomfort platforms (#118827)

* Prelimenary tests for incomfort integration

* Use snapshot_platform

* Use helper

* Ensure the device name is set in device info

* Move snapshot tests to platform test modules

* Move unused snapshot file

* Naming and docstr

* update snapshots

* cleanup snapshots

* Add water heater tests
This commit is contained in:
Jan Bouwhuis 2024-06-04 20:51:34 +02:00 committed by GitHub
parent 5fca2c09c5
commit 956623d964
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 559 additions and 16 deletions

View File

@ -591,11 +591,7 @@ omit =
homeassistant/components/iglo/light.py
homeassistant/components/ihc/*
homeassistant/components/incomfort/__init__.py
homeassistant/components/incomfort/binary_sensor.py
homeassistant/components/incomfort/climate.py
homeassistant/components/incomfort/errors.py
homeassistant/components/incomfort/models.py
homeassistant/components/incomfort/sensor.py
homeassistant/components/incomfort/water_heater.py
homeassistant/components/insteon/binary_sensor.py
homeassistant/components/insteon/climate.py

View File

@ -43,6 +43,8 @@ class IncomfortFailed(IncomfortEntity, BinarySensorEntity):
self._attr_unique_id = f"{heater.serial_no}_failed"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, heater.serial_no)},
manufacturer="Intergas",
name="Boiler",
)
@property

View File

@ -96,6 +96,8 @@ class IncomfortSensor(IncomfortEntity, SensorEntity):
self._attr_unique_id = f"{heater.serial_no}_{slugify(description.name)}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, heater.serial_no)},
manufacturer="Intergas",
name="Boiler",
)
@property

View File

@ -6,8 +6,18 @@ from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from homeassistant.components.incomfort import DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
MOCK_CONFIG = {
"host": "192.168.1.12",
"username": "admin",
"password": "verysecret",
}
@pytest.fixture
def mock_setup_entry() -> Generator[AsyncMock, None, None]:
@ -19,6 +29,22 @@ def mock_setup_entry() -> Generator[AsyncMock, None, None]:
yield mock_setup_entry
@pytest.fixture
def mock_entry_data() -> dict[str, Any]:
"""Mock config entry data for fixture."""
return MOCK_CONFIG
@pytest.fixture
def mock_config_entry(
hass: HomeAssistant, mock_entry_data: dict[str, Any]
) -> ConfigEntry:
"""Mock a config entry setup for incomfort integration."""
entry = MockConfigEntry(domain=DOMAIN, data=mock_entry_data)
entry.add_to_hass(hass)
return entry
@pytest.fixture
def mock_heater_status() -> dict[str, Any]:
"""Mock heater status."""
@ -33,7 +59,7 @@ def mock_heater_status() -> dict[str, Any]:
"heater_temp": 35.34,
"tap_temp": 30.21,
"pressure": 1.86,
"serial_no": "2404c08648",
"serial_no": "c0ffeec0ffee",
"nodenr": 249,
"rf_message_rssi": 30,
"rfstatus_cntr": 0,
@ -62,14 +88,25 @@ def mock_incomfort(
room_temp: float
setpoint: float
status: dict[str, Any]
set_override: MagicMock
def __init__(self) -> None:
"""Initialize mocked room."""
self.override = mock_room_status["override"]
self.room_no = 1
self.room_temp = mock_room_status["room_temp"]
self.setpoint = mock_room_status["setpoint"]
self.status = mock_room_status
self.set_override = MagicMock()
@property
def override(self) -> str:
return mock_room_status["override"]
@property
def room_temp(self) -> float:
return mock_room_status["room_temp"]
@property
def setpoint(self) -> float:
return mock_room_status["setpoint"]
class MockHeater:
"""Mocked InComfort heater class."""
@ -77,6 +114,20 @@ def mock_incomfort(
serial_no: str
status: dict[str, Any]
rooms: list[MockRoom]
is_failed: bool
is_pumping: bool
display_code: int
display_text: str | None
fault_code: int | None
is_burning: bool
is_tapping: bool
heater_temp: float
tap_temp: float
pressure: float
serial_no: str
nodenr: int
rf_message_rssi: int
rfstatus_cntr: int
def __init__(self) -> None:
"""Initialize mocked heater."""
@ -84,11 +135,15 @@ def mock_incomfort(
async def update(self) -> None:
self.status = mock_heater_status
self.rooms = [MockRoom]
for key, value in mock_heater_status.items():
setattr(self, key, value)
self.rooms = [MockRoom()]
with patch(
"homeassistant.components.incomfort.models.InComfortGateway", MagicMock()
) as patch_gateway:
patch_gateway().heaters = AsyncMock()
patch_gateway().heaters.return_value = [MockHeater()]
patch_gateway().mock_heater_status = mock_heater_status
patch_gateway().mock_room_status = mock_room_status
yield patch_gateway

View File

@ -0,0 +1,95 @@
# serializer version: 1
# name: test_setup_platform[binary_sensor.boiler_fault-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.boiler_fault',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Fault',
'platform': 'incomfort',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'c0ffeec0ffee_failed',
'unit_of_measurement': None,
})
# ---
# name: test_setup_platform[binary_sensor.boiler_fault-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'fault_code': None,
'friendly_name': 'Boiler Fault',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.boiler_fault',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_setup_platforms[binary_sensor.boiler_fault-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.boiler_fault',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Fault',
'platform': 'incomfort',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'c0ffeec0ffee_failed',
'unit_of_measurement': None,
})
# ---
# name: test_setup_platforms[binary_sensor.boiler_fault-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'fault_code': None,
'friendly_name': 'Boiler Fault',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.boiler_fault',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---

View File

@ -0,0 +1,66 @@
# serializer version: 1
# name: test_setup_platform[climate.thermostat_1-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'hvac_modes': list([
<HVACMode.HEAT: 'heat'>,
]),
'max_temp': 30.0,
'min_temp': 5.0,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'climate',
'entity_category': None,
'entity_id': 'climate.thermostat_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': None,
'platform': 'incomfort',
'previous_unique_id': None,
'supported_features': <ClimateEntityFeature: 1>,
'translation_key': None,
'unique_id': 'c0ffeec0ffee_1',
'unit_of_measurement': None,
})
# ---
# name: test_setup_platform[climate.thermostat_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_temperature': 21.4,
'friendly_name': 'Thermostat 1',
'hvac_modes': list([
<HVACMode.HEAT: 'heat'>,
]),
'max_temp': 30.0,
'min_temp': 5.0,
'status': dict({
'override': 18.0,
'room_temp': 21.42,
'setpoint': 18.0,
}),
'supported_features': <ClimateEntityFeature: 1>,
'temperature': 18.0,
}),
'context': <ANY>,
'entity_id': 'climate.thermostat_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'heat',
})
# ---

View File

@ -0,0 +1,147 @@
# serializer version: 1
# name: test_setup_platform[sensor.boiler_cv_pressure-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.boiler_cv_pressure',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.PRESSURE: 'pressure'>,
'original_icon': None,
'original_name': 'CV Pressure',
'platform': 'incomfort',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'c0ffeec0ffee_cv_pressure',
'unit_of_measurement': <UnitOfPressure.BAR: 'bar'>,
})
# ---
# name: test_setup_platform[sensor.boiler_cv_pressure-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'pressure',
'friendly_name': 'Boiler CV Pressure',
'unit_of_measurement': <UnitOfPressure.BAR: 'bar'>,
}),
'context': <ANY>,
'entity_id': 'sensor.boiler_cv_pressure',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1.86',
})
# ---
# name: test_setup_platform[sensor.boiler_cv_temp-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.boiler_cv_temp',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'CV Temp',
'platform': 'incomfort',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'c0ffeec0ffee_cv_temp',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_setup_platform[sensor.boiler_cv_temp-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Boiler CV Temp',
'is_pumping': False,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.boiler_cv_temp',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '35.34',
})
# ---
# name: test_setup_platform[sensor.boiler_tap_temp-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.boiler_tap_temp',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Tap Temp',
'platform': 'incomfort',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'c0ffeec0ffee_tap_temp',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_setup_platform[sensor.boiler_tap_temp-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Boiler Tap Temp',
'is_tapping': False,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.boiler_tap_temp',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '30.21',
})
# ---

View File

@ -0,0 +1,61 @@
# serializer version: 1
# name: test_setup_platform[water_heater.boiler-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'max_temp': 80.0,
'min_temp': 30.0,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'water_heater',
'entity_category': None,
'entity_id': 'water_heater.boiler',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:thermometer-lines',
'original_name': None,
'platform': 'incomfort',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'c0ffeec0ffee',
'unit_of_measurement': None,
})
# ---
# name: test_setup_platform[water_heater.boiler-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'current_temperature': 35.3,
'display_code': 126,
'display_text': 'standby',
'friendly_name': 'Boiler',
'icon': 'mdi:thermometer-lines',
'is_burning': False,
'max_temp': 80.0,
'min_temp': 30.0,
'supported_features': <WaterHeaterEntityFeature: 0>,
'target_temp_high': None,
'target_temp_low': None,
'temperature': None,
}),
'context': <ANY>,
'entity_id': 'water_heater.boiler',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'standby',
})
# ---

View File

@ -0,0 +1,25 @@
"""Binary sensor tests for Intergas InComfort integration."""
from unittest.mock import MagicMock, patch
from syrupy import SnapshotAssertion
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import snapshot_platform
@patch("homeassistant.components.incomfort.PLATFORMS", [Platform.BINARY_SENSOR])
async def test_setup_platform(
hass: HomeAssistant,
mock_incomfort: MagicMock,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
mock_config_entry: ConfigEntry,
) -> None:
"""Test the incomfort entities are set up correctly."""
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)

View File

@ -0,0 +1,25 @@
"""Climate sensor tests for Intergas InComfort integration."""
from unittest.mock import MagicMock, patch
from syrupy import SnapshotAssertion
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import snapshot_platform
@patch("homeassistant.components.incomfort.PLATFORMS", [Platform.CLIMATE])
async def test_setup_platform(
hass: HomeAssistant,
mock_incomfort: MagicMock,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
mock_config_entry: ConfigEntry,
) -> None:
"""Test the incomfort entities are set up correctly."""
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)

View File

@ -12,13 +12,9 @@ from homeassistant.const import CONF_HOST, CONF_PASSWORD
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
from .conftest import MOCK_CONFIG
MOCK_CONFIG = {
"host": "192.168.1.12",
"username": "admin",
"password": "verysecret",
}
from tests.common import MockConfigEntry
async def test_form(
@ -144,7 +140,7 @@ async def test_form_validation(
DOMAIN, context={"source": SOURCE_USER}
)
# Simulate issue and retry
# Simulate an issue
mock_incomfort().heaters.side_effect = exc
result = await hass.config_entries.flow.async_configure(
result["flow_id"], MOCK_CONFIG

View File

@ -0,0 +1,23 @@
"""Tests for Intergas InComfort integration."""
from unittest.mock import MagicMock, patch
from syrupy import SnapshotAssertion
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
@patch("homeassistant.components.incomfort.PLATFORMS", [Platform.SENSOR])
async def test_setup_platforms(
hass: HomeAssistant,
mock_incomfort: MagicMock,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
mock_config_entry: ConfigEntry,
) -> None:
"""Test the incomfort integration is set up correctly."""
await hass.config_entries.async_setup(mock_config_entry.entry_id)
assert mock_config_entry.state is ConfigEntryState.LOADED

View File

@ -0,0 +1,25 @@
"""Sensor tests for Intergas InComfort integration."""
from unittest.mock import MagicMock, patch
from syrupy import SnapshotAssertion
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import snapshot_platform
@patch("homeassistant.components.incomfort.PLATFORMS", [Platform.SENSOR])
async def test_setup_platform(
hass: HomeAssistant,
mock_incomfort: MagicMock,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
mock_config_entry: ConfigEntry,
) -> None:
"""Test the incomfort entities are set up correctly."""
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)

View File

@ -0,0 +1,25 @@
"""Water heater tests for Intergas InComfort integration."""
from unittest.mock import MagicMock, patch
from syrupy import SnapshotAssertion
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import snapshot_platform
@patch("homeassistant.components.incomfort.PLATFORMS", [Platform.WATER_HEATER])
async def test_setup_platform(
hass: HomeAssistant,
mock_incomfort: MagicMock,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
mock_config_entry: ConfigEntry,
) -> None:
"""Test the incomfort entities are set up correctly."""
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)