From 76a59338eb850752eec5288de72540e4edf74212 Mon Sep 17 00:00:00 2001 From: David Bonnes Date: Sat, 5 Oct 2024 22:32:12 +0100 Subject: [PATCH] Add tests for evohome climate entities (#127612) * initial commit * rename symbol (zon -> zone) * move get_entity* helper function to test * update snapshot --- .../evohome/snapshots/test_climate.ambr | 190 ++++++++++++++++ tests/components/evohome/test_climate.py | 203 ++++++++++++++++++ 2 files changed, 393 insertions(+) create mode 100644 tests/components/evohome/snapshots/test_climate.ambr create mode 100644 tests/components/evohome/test_climate.py diff --git a/tests/components/evohome/snapshots/test_climate.ambr b/tests/components/evohome/snapshots/test_climate.ambr new file mode 100644 index 00000000000..1a77cf0e80d --- /dev/null +++ b/tests/components/evohome/snapshots/test_climate.ambr @@ -0,0 +1,190 @@ +# serializer version: 1 +# name: test_zone_set_hvac_mode[default] + list([ + tuple( + dict({ + 'HeatSetpointValue': 5.0, + 'setpointMode': , + }), + ), + ]) +# --- +# name: test_zone_set_hvac_mode[h032585] + list([ + tuple( + dict({ + 'HeatSetpointValue': 4.5, + 'setpointMode': , + }), + ), + ]) +# --- +# name: test_zone_set_hvac_mode[h099625] + list([ + tuple( + dict({ + 'HeatSetpointValue': 5.0, + 'setpointMode': , + }), + ), + ]) +# --- +# name: test_zone_set_hvac_mode[minimal] + list([ + tuple( + dict({ + 'HeatSetpointValue': 5.0, + 'setpointMode': , + }), + ), + ]) +# --- +# name: test_zone_set_hvac_mode[sys_004] + list([ + tuple( + dict({ + 'HeatSetpointValue': 5.0, + 'setpointMode': , + }), + ), + ]) +# --- +# name: test_zone_set_preset_mode[default] + list([ + tuple( + dict({ + 'HeatSetpointValue': 17.0, + 'setpointMode': , + }), + ), + tuple( + dict({ + 'HeatSetpointValue': 17.0, + 'setpointMode': , + 'timeUntil': '2024-07-10T21:10:00Z', + }), + ), + ]) +# --- +# name: test_zone_set_preset_mode[h032585] + list([ + tuple( + dict({ + 'HeatSetpointValue': 21.5, + 'setpointMode': , + }), + ), + tuple( + dict({ + 'HeatSetpointValue': 21.5, + 'setpointMode': , + 'timeUntil': '2024-07-10T21:10:00Z', + }), + ), + ]) +# --- +# name: test_zone_set_preset_mode[h099625] + list([ + tuple( + dict({ + 'HeatSetpointValue': 21.5, + 'setpointMode': , + }), + ), + tuple( + dict({ + 'HeatSetpointValue': 21.5, + 'setpointMode': , + 'timeUntil': '2024-07-10T19:10:00Z', + }), + ), + ]) +# --- +# name: test_zone_set_preset_mode[minimal] + list([ + tuple( + dict({ + 'HeatSetpointValue': 17.0, + 'setpointMode': , + }), + ), + tuple( + dict({ + 'HeatSetpointValue': 17.0, + 'setpointMode': , + 'timeUntil': '2024-07-10T21:10:00Z', + }), + ), + ]) +# --- +# name: test_zone_set_preset_mode[sys_004] + list([ + tuple( + dict({ + 'HeatSetpointValue': 15.0, + 'setpointMode': , + }), + ), + tuple( + dict({ + 'HeatSetpointValue': 15.0, + 'setpointMode': , + 'timeUntil': '2024-07-10T20:10:00Z', + }), + ), + ]) +# --- +# name: test_zone_set_temperature[default] + list([ + tuple( + dict({ + 'HeatSetpointValue': 19.1, + 'setpointMode': , + 'timeUntil': '2024-07-10T21:10:00Z', + }), + ), + ]) +# --- +# name: test_zone_set_temperature[h032585] + list([ + tuple( + dict({ + 'HeatSetpointValue': 19.1, + 'setpointMode': , + 'timeUntil': '2024-07-10T21:10:00Z', + }), + ), + ]) +# --- +# name: test_zone_set_temperature[h099625] + list([ + tuple( + dict({ + 'HeatSetpointValue': 19.1, + 'setpointMode': , + 'timeUntil': '2024-07-10T19:10:00Z', + }), + ), + ]) +# --- +# name: test_zone_set_temperature[minimal] + list([ + tuple( + dict({ + 'HeatSetpointValue': 19.1, + 'setpointMode': , + 'timeUntil': '2024-07-10T21:10:00Z', + }), + ), + ]) +# --- +# name: test_zone_set_temperature[sys_004] + list([ + tuple( + dict({ + 'HeatSetpointValue': 19.1, + 'setpointMode': , + }), + ), + ]) +# --- diff --git a/tests/components/evohome/test_climate.py b/tests/components/evohome/test_climate.py new file mode 100644 index 00000000000..602a2ac561a --- /dev/null +++ b/tests/components/evohome/test_climate.py @@ -0,0 +1,203 @@ +"""The tests for climate entities of evohome. + +All evohome systems have controllers and at least one zone. +""" + +from __future__ import annotations + +from unittest.mock import patch + +from freezegun.api import FrozenDateTimeFactory +import pytest +from syrupy import SnapshotAssertion + +from homeassistant.components.climate import HVACMode +from homeassistant.components.evohome import DOMAIN +from homeassistant.components.evohome.climate import EvoZone +from homeassistant.components.evohome.coordinator import EvoBroker +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er +from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.util import dt as dt_util + +from .conftest import setup_evohome +from .const import TEST_INSTALLS + + +def get_zone_entity(hass: HomeAssistant) -> EvoZone: + """Return the entity of the first zone of the evohome system.""" + + broker: EvoBroker = hass.data[DOMAIN]["broker"] + + unique_id = broker.tcs._zones[0]._id + if unique_id == broker.tcs._id: + unique_id += "z" # special case of merged controller/zone + + entity_registry = er.async_get(hass) + entity_id = entity_registry.async_get_entity_id(Platform.CLIMATE, DOMAIN, unique_id) + + component: EntityComponent = hass.data.get(Platform.CLIMATE) # type: ignore[assignment] + return next(e for e in component.entities if e.entity_id == entity_id) # type: ignore[return-value] + + +@pytest.mark.parametrize("install", TEST_INSTALLS) +async def test_zone_set_hvac_mode( + hass: HomeAssistant, + config: dict[str, str], + install: str, + snapshot: SnapshotAssertion, +) -> None: + """Test climate methods of a evohome-compatible zone.""" + + results = [] + + async for _ in setup_evohome(hass, config, install=install): + zone = get_zone_entity(hass) + + assert zone.hvac_modes == [HVACMode.OFF, HVACMode.HEAT] + + # set_hvac_mode(HVACMode.HEAT): FollowSchedule + with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn: + await zone.async_set_hvac_mode(HVACMode.HEAT) + + assert mock_fcn.await_count == 1 + assert install != "default" or mock_fcn.await_args.args == ( + { + "setpointMode": "FollowSchedule", + }, + ) + assert mock_fcn.await_args.kwargs == {} + + # set_hvac_mode(HVACMode.OFF): PermanentOverride, minHeatSetpoint + with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn: + await zone.async_set_hvac_mode(HVACMode.OFF) + + assert mock_fcn.await_count == 1 + assert install != "default" or mock_fcn.await_args.args == ( + { + "setpointMode": "PermanentOverride", + "HeatSetpointValue": 5.0, # varies by install + }, + ) + assert mock_fcn.await_args.kwargs == {} + + results.append(mock_fcn.await_args.args) + + assert results == snapshot + + +@pytest.mark.parametrize("install", TEST_INSTALLS) +async def test_zone_set_preset_mode( + hass: HomeAssistant, + config: dict[str, str], + install: str, + freezer: FrozenDateTimeFactory, + snapshot: SnapshotAssertion, +) -> None: + """Test climate methods of a evohome-compatible zone.""" + + freezer.move_to("2024-07-10T12:00:00Z") + results = [] + + async for _ in setup_evohome(hass, config, install=install): + zone = get_zone_entity(hass) + + assert zone.preset_modes == ["none", "temporary", "permanent"] + + # set_preset_mode(none): FollowSchedule + with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn: + await zone.async_set_preset_mode("none") + + assert mock_fcn.await_count == 1 + assert mock_fcn.await_args.args == ( + { + "setpointMode": "FollowSchedule", + }, + ) + assert mock_fcn.await_args.kwargs == {} + + # set_preset_mode(permanent): PermanentOverride + with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn: + await zone.async_set_preset_mode("permanent") + + assert mock_fcn.await_count == 1 + assert install != "default" or mock_fcn.await_args.args == ( + { + "setpointMode": "PermanentOverride", + "HeatSetpointValue": 17.0, # varies by install + }, + ) + assert mock_fcn.await_args.kwargs == {} + + results.append(mock_fcn.await_args.args) + + # set_preset_mode(permanent): TemporaryOverride + with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn: + await zone.async_set_preset_mode("temporary") + + assert mock_fcn.await_count == 1 + assert install != "default" or mock_fcn.await_args.args == ( + { + "setpointMode": "TemporaryOverride", + "HeatSetpointValue": 17.0, # varies by install + "timeUntil": "2024-07-10T21:10:00Z", # varies by install + }, + ) + assert mock_fcn.await_args.kwargs == {} + + results.append(mock_fcn.await_args.args) + + assert results == snapshot + + +@pytest.mark.parametrize("install", TEST_INSTALLS) +async def test_zone_set_temperature( + hass: HomeAssistant, + config: dict[str, str], + install: str, + freezer: FrozenDateTimeFactory, + snapshot: SnapshotAssertion, +) -> None: + """Test climate methods of a evohome-compatible zone.""" + + freezer.move_to("2024-07-10T12:00:00Z") + results = [] + + async for _ in setup_evohome(hass, config, install=install): + zone = get_zone_entity(hass) + + # set_temperature(temp): TemporaryOverride, advanced + with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn: + await zone.async_set_temperature(temperature=19.1) + + assert mock_fcn.await_count == 1 + assert install != "default" or mock_fcn.await_args.args == ( + { + "setpointMode": "TemporaryOverride", + "HeatSetpointValue": 19.1, + "timeUntil": "2024-07-10T21:10:00Z", # varies by install + }, + ) + assert mock_fcn.await_args.kwargs == {} + + results.append(mock_fcn.await_args.args) + + # set_temperature(temp, until): TemporaryOverride, until + with patch("evohomeasync2.zone.Zone._set_mode") as mock_fcn: + await zone.async_set_temperature( + temperature=19.2, + until=dt_util.parse_datetime("2024-07-10T13:30:00Z"), + ) + + assert mock_fcn.await_count == 1 + assert mock_fcn.await_args.args == ( + { + "setpointMode": "TemporaryOverride", + "HeatSetpointValue": 19.2, + "timeUntil": "2024-07-10T13:30:00Z", + }, + ) + assert mock_fcn.await_args.kwargs == {} + + assert results == snapshot