Add safety manager direct tests

This commit is contained in:
Jean-Marc Collin
2024-12-31 16:22:17 +00:00
parent 1c39ad670d
commit e9cc5691af
6 changed files with 119 additions and 17 deletions

View File

@@ -1,2 +1,2 @@
FROM mcr.microsoft.com/devcontainers/python:1-3.13 FROM mcr.microsoft.com/devcontainers/python:1-3.13
RUN apt update && apt install -y ffmpeg RUN apt update && apt install -y ffmpeg libturbojpeg0-dev

View File

@@ -371,11 +371,11 @@ STEP_CENTRAL_ADVANCED_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name
vol.Required(CONF_SAFETY_DELAY_MIN, default=60): cv.positive_int, vol.Required(CONF_SAFETY_DELAY_MIN, default=60): cv.positive_int,
vol.Required( vol.Required(
CONF_SAFETY_MIN_ON_PERCENT, CONF_SAFETY_MIN_ON_PERCENT,
default=DEFAULT_SECURITY_MIN_ON_PERCENT, default=DEFAULT_SAFETY_MIN_ON_PERCENT,
): vol.Coerce(float), ): vol.Coerce(float),
vol.Required( vol.Required(
CONF_SAFETY_DEFAULT_ON_PERCENT, CONF_SAFETY_DEFAULT_ON_PERCENT,
default=DEFAULT_SECURITY_DEFAULT_ON_PERCENT, default=DEFAULT_SAFETY_DEFAULT_ON_PERCENT,
): vol.Coerce(float), ): vol.Coerce(float),
} }
) )

View File

@@ -379,8 +379,8 @@ SERVICE_SET_WINDOW_BYPASS = "set_window_bypass"
SERVICE_SET_AUTO_REGULATION_MODE = "set_auto_regulation_mode" SERVICE_SET_AUTO_REGULATION_MODE = "set_auto_regulation_mode"
SERVICE_SET_AUTO_FAN_MODE = "set_auto_fan_mode" SERVICE_SET_AUTO_FAN_MODE = "set_auto_fan_mode"
DEFAULT_SECURITY_MIN_ON_PERCENT = 0.5 DEFAULT_SAFETY_MIN_ON_PERCENT = 0.5
DEFAULT_SECURITY_DEFAULT_ON_PERCENT = 0.1 DEFAULT_SAFETY_DEFAULT_ON_PERCENT = 0.1
ATTR_TOTAL_ENERGY = "total_energy" ATTR_TOTAL_ENERGY = "total_energy"
ATTR_MEAN_POWER_CYCLE = "mean_cycle_power" ATTR_MEAN_POWER_CYCLE = "mean_cycle_power"

View File

@@ -53,16 +53,21 @@ class FeatureSafetyManager(BaseFeatureManager):
self._safety_min_on_percent = ( self._safety_min_on_percent = (
entry_infos.get(CONF_SAFETY_MIN_ON_PERCENT) entry_infos.get(CONF_SAFETY_MIN_ON_PERCENT)
if entry_infos.get(CONF_SAFETY_MIN_ON_PERCENT) is not None if entry_infos.get(CONF_SAFETY_MIN_ON_PERCENT) is not None
else DEFAULT_SECURITY_MIN_ON_PERCENT else DEFAULT_SAFETY_MIN_ON_PERCENT
) )
self._safety_default_on_percent = ( self._safety_default_on_percent = (
entry_infos.get(CONF_SAFETY_DEFAULT_ON_PERCENT) entry_infos.get(CONF_SAFETY_DEFAULT_ON_PERCENT)
if entry_infos.get(CONF_SAFETY_DEFAULT_ON_PERCENT) is not None if entry_infos.get(CONF_SAFETY_DEFAULT_ON_PERCENT) is not None
else DEFAULT_SECURITY_DEFAULT_ON_PERCENT else DEFAULT_SAFETY_DEFAULT_ON_PERCENT
) )
self._safety_state = STATE_UNKNOWN if (
self._is_configured = True self._safety_delay_min is not None
and self._safety_default_on_percent is not None
and self._safety_default_on_percent is not None
):
self._safety_state = STATE_UNKNOWN
self._is_configured = True
@overrides @overrides
def start_listening(self): def start_listening(self):
@@ -253,16 +258,23 @@ class FeatureSafetyManager(BaseFeatureManager):
def add_custom_attributes(self, extra_state_attributes: dict[str, Any]): def add_custom_attributes(self, extra_state_attributes: dict[str, Any]):
"""Add some custom attributes""" """Add some custom attributes"""
extra_state_attributes.update( extra_state_attributes.update(
{ {
"safety_delay_min": self._safety_delay_min,
"safety_min_on_percent": self._safety_min_on_percent,
"safety_default_on_percent": self._safety_default_on_percent,
"safety_state": self._safety_state,
"is_safety_configured": self._is_configured, "is_safety_configured": self._is_configured,
"safety_state": self._safety_state,
} }
) )
if self._is_configured:
extra_state_attributes.update(
{
"safety_delay_min": self._safety_delay_min,
"safety_min_on_percent": self._safety_min_on_percent,
"safety_default_on_percent": self._safety_default_on_percent,
}
)
@overrides @overrides
@property @property
def is_configured(self) -> bool: def is_configured(self) -> bool:

View File

@@ -1,8 +1,7 @@
# pylint: disable=unused-argument, line-too-long, protected-access, too-many-lines # pylint: disable=unused-argument, line-too-long, protected-access, too-many-lines
""" Test the Window management """ """ Test the Window management """
import logging import logging
from datetime import datetime, timedelta from unittest.mock import PropertyMock, MagicMock
from unittest.mock import patch, call, PropertyMock, AsyncMock, MagicMock
from custom_components.versatile_thermostat.base_thermostat import BaseThermostat from custom_components.versatile_thermostat.base_thermostat import BaseThermostat

View File

@@ -1,7 +1,7 @@
# pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long # pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long
""" Test the Security featrure """ """ Test the Security featrure """
from unittest.mock import patch, call from unittest.mock import patch, call, PropertyMock, MagicMock
from datetime import timedelta, datetime from datetime import timedelta, datetime
import logging import logging
@@ -11,12 +11,103 @@ from custom_components.versatile_thermostat.thermostat_climate import (
from custom_components.versatile_thermostat.thermostat_switch import ( from custom_components.versatile_thermostat.thermostat_switch import (
ThermostatOverSwitch, ThermostatOverSwitch,
) )
from custom_components.versatile_thermostat.feature_safety_manager import (
FeatureSafetyManager,
)
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG)
async def test_safety_feature_manager_create(
hass: HomeAssistant,
):
"""Test the FeatureMotionManager class direclty"""
fake_vtherm = MagicMock(spec=BaseThermostat)
type(fake_vtherm).name = PropertyMock(return_value="the name")
# 1. creation
safety_manager = FeatureSafetyManager(fake_vtherm, hass)
assert safety_manager is not None
assert safety_manager.is_configured is False
assert safety_manager.is_safety_detected is False
assert safety_manager.safety_state is STATE_UNAVAILABLE
assert safety_manager.name == "the name"
assert len(safety_manager._active_listener) == 0
custom_attributes = {}
safety_manager.add_custom_attributes(custom_attributes)
assert custom_attributes["is_safety_configured"] is False
assert custom_attributes["safety_state"] is STATE_UNAVAILABLE
assert custom_attributes.get("safety_delay_min", None) is None
assert custom_attributes.get("safety_min_on_percent", None) is None
assert custom_attributes.get("safety_default_on_percent", None) is None
@pytest.mark.parametrize(
"safety_delay_min, safety_min_on_percent, safety_default_on_percent, is_configured, state",
[
# fmt: off
( 10, 11, 12, True, STATE_UNKNOWN),
( None, 11, 12, False, STATE_UNAVAILABLE),
( 10, None, 12, True, STATE_UNKNOWN),
( 10, 11, None, True, STATE_UNKNOWN),
( 10, None, None, True, STATE_UNKNOWN),
( None, None, None, False, STATE_UNAVAILABLE),
# fmt: on
],
)
async def test_safety_feature_manager_post_init(
hass: HomeAssistant,
safety_delay_min,
safety_min_on_percent,
safety_default_on_percent,
is_configured,
state,
):
"""Test the FeatureSafetyManager class direclty"""
fake_vtherm = MagicMock(spec=BaseThermostat)
type(fake_vtherm).name = PropertyMock(return_value="the name")
# 1. creation
safety_manager = FeatureSafetyManager(fake_vtherm, hass)
assert safety_manager is not None
# 2. post_init
safety_manager.post_init(
{
CONF_SAFETY_DELAY_MIN: safety_delay_min,
CONF_SAFETY_MIN_ON_PERCENT: safety_min_on_percent,
CONF_SAFETY_DEFAULT_ON_PERCENT: safety_default_on_percent,
}
)
assert safety_manager.is_configured is is_configured
assert safety_manager.safety_state is state
custom_attributes = {}
safety_manager.add_custom_attributes(custom_attributes)
assert custom_attributes["is_safety_configured"] is is_configured
assert custom_attributes["safety_state"] is state
if safety_manager.is_configured:
assert custom_attributes.get("safety_delay_min", None) == safety_delay_min
assert (
custom_attributes.get("safety_min_on_percent", None)
== safety_min_on_percent
or DEFAULT_SAFETY_MIN_ON_PERCENT
)
assert (
custom_attributes.get("safety_default_on_percent", None)
== safety_default_on_percent
or DEFAULT_SAFETY_DEFAULT_ON_PERCENT
)
@pytest.mark.parametrize("expected_lingering_tasks", [True]) @pytest.mark.parametrize("expected_lingering_tasks", [True])
@pytest.mark.parametrize("expected_lingering_timers", [True]) @pytest.mark.parametrize("expected_lingering_timers", [True])
async def test_security_feature(hass: HomeAssistant, skip_hass_states_is_state): async def test_security_feature(hass: HomeAssistant, skip_hass_states_is_state):