From 4dd7c62a424d9b3eb2d69de032fd6db26af1de91 Mon Sep 17 00:00:00 2001 From: Jean-Marc Collin Date: Sat, 22 Apr 2023 09:24:57 +0200 Subject: [PATCH] Migration to 2023.4 and fix lingering tasks and timers tests errors --- .../versatile_thermostat/climate.py | 10 ++++---- .../versatile_thermostat/tests/commons.py | 1 + .../tests/test_binary_sensors.py | 13 ++++++++++ .../versatile_thermostat/tests/test_bugs.py | 8 +++++++ .../tests/test_config_flow.py | 13 ++++++++++ .../tests/test_movement.py | 6 +++++ .../tests/test_multiple_switch.py | 4 ++++ .../versatile_thermostat/tests/test_power.py | 8 +++++++ .../tests/test_security.py | 2 ++ .../tests/test_sensors.py | 6 +++++ .../versatile_thermostat/tests/test_start.py | 6 +++++ .../versatile_thermostat/tests/test_tpi.py | 2 ++ .../versatile_thermostat/tests/test_window.py | 24 +++++++++++++++++++ 13 files changed, 99 insertions(+), 4 deletions(-) diff --git a/custom_components/versatile_thermostat/climate.py b/custom_components/versatile_thermostat/climate.py index 0aed65e..764ddf1 100644 --- a/custom_components/versatile_thermostat/climate.py +++ b/custom_components/versatile_thermostat/climate.py @@ -601,7 +601,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): ) ) - self.async_on_remove(self.async_remove_thermostat) + self.async_on_remove(self.remove_thermostat) try: await self.async_startup() @@ -609,11 +609,11 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): # Ingore this error which is possible if underlying climate is not found temporary pass - def async_remove_thermostat(self): + async def remove_thermostat(self): """Called when the thermostat will be removed""" _LOGGER.info("%s - Removing thermostat", self) for under in self._underlyings: - under.remove_entity() + await under.remove_entity() async def async_startup(self): """Triggered on startup, used to get old state and set internal states accordingly""" @@ -1521,7 +1521,9 @@ class VersatileThermostat(ClimateEntity, RestoreEntity): ) # We do not change the preset which is kept to ACTIVITY but only the target_temperature # We take the presence into account - await self._async_internal_set_temperature(self.find_preset_temp(new_preset)) + await self._async_internal_set_temperature( + self.find_preset_temp(new_preset) + ) self.recalculate() await self._async_control_heating(force=True) diff --git a/custom_components/versatile_thermostat/tests/commons.py b/custom_components/versatile_thermostat/tests/commons.py index a0c7f55..80046ad 100644 --- a/custom_components/versatile_thermostat/tests/commons.py +++ b/custom_components/versatile_thermostat/tests/commons.py @@ -2,6 +2,7 @@ import asyncio import logging from unittest.mock import patch, MagicMock +import pytest from homeassistant.core import HomeAssistant, Event, EVENT_STATE_CHANGED, State from homeassistant.const import UnitOfTemperature, STATE_ON, STATE_OFF diff --git a/custom_components/versatile_thermostat/tests/test_binary_sensors.py b/custom_components/versatile_thermostat/tests/test_binary_sensors.py index bf434fc..e1ad6c6 100644 --- a/custom_components/versatile_thermostat/tests/test_binary_sensors.py +++ b/custom_components/versatile_thermostat/tests/test_binary_sensors.py @@ -9,6 +9,7 @@ from homeassistant.components.binary_sensor import BinarySensorDeviceClass from pytest_homeassistant_custom_component.common import MockConfigEntry +from .commons import * from ..climate import VersatileThermostat from ..binary_sensor import ( SecurityBinarySensor, @@ -21,6 +22,8 @@ from ..binary_sensor import ( from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_security_binary_sensors( hass: HomeAssistant, skip_hass_states_is_state, @@ -96,6 +99,8 @@ async def test_security_binary_sensors( assert security_binary_sensor.state == STATE_OFF +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_overpowering_binary_sensors( hass: HomeAssistant, skip_hass_states_is_state, @@ -178,6 +183,8 @@ async def test_overpowering_binary_sensors( assert overpowering_binary_sensor.state == STATE_OFF +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_window_binary_sensors( hass: HomeAssistant, skip_hass_states_is_state, @@ -264,6 +271,8 @@ async def test_window_binary_sensors( assert window_binary_sensor.state == STATE_OFF +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_motion_binary_sensors( hass: HomeAssistant, skip_hass_states_is_state, @@ -350,6 +359,8 @@ async def test_motion_binary_sensors( assert motion_binary_sensor.state == STATE_OFF +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_presence_binary_sensors( hass: HomeAssistant, skip_hass_states_is_state, @@ -432,6 +443,8 @@ async def test_presence_binary_sensors( assert presence_binary_sensor.state == STATE_OFF +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_binary_sensors_over_climate_minimal( hass: HomeAssistant, skip_hass_states_is_state, diff --git a/custom_components/versatile_thermostat/tests/test_bugs.py b/custom_components/versatile_thermostat/tests/test_bugs.py index f183b4e..060090b 100644 --- a/custom_components/versatile_thermostat/tests/test_bugs.py +++ b/custom_components/versatile_thermostat/tests/test_bugs.py @@ -8,6 +8,8 @@ import logging logging.getLogger().setLevel(logging.DEBUG) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_bug_56( hass: HomeAssistant, skip_hass_states_is_state, @@ -85,6 +87,8 @@ async def test_bug_56( entity.update_custom_attributes() +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_bug_63( hass: HomeAssistant, skip_hass_states_is_state, @@ -135,6 +139,8 @@ async def test_bug_63( # Waiting for answer in https://github.com/jmcollin78/versatile_thermostat/issues/64 # Repro case not evident +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_bug_64( hass: HomeAssistant, skip_hass_states_is_state, @@ -180,6 +186,8 @@ async def test_bug_64( assert entity +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_bug_66( hass: HomeAssistant, skip_hass_states_is_state, diff --git a/custom_components/versatile_thermostat/tests/test_config_flow.py b/custom_components/versatile_thermostat/tests/test_config_flow.py index be61a30..eba58e3 100644 --- a/custom_components/versatile_thermostat/tests/test_config_flow.py +++ b/custom_components/versatile_thermostat/tests/test_config_flow.py @@ -6,9 +6,12 @@ from homeassistant.config_entries import SOURCE_USER, ConfigEntry from custom_components.versatile_thermostat.const import DOMAIN +from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import from .const import * # pylint: disable=wildcard-import, unused-wildcard-import +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_show_form(hass: HomeAssistant) -> None: """Test that the form is served with no input""" # Init the API @@ -24,6 +27,8 @@ async def test_show_form(hass: HomeAssistant) -> None: assert result["step_id"] == SOURCE_USER +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_user_config_flow_over_switch(hass: HomeAssistant, skip_hass_states_get): """Test the config flow with all thermostat_over_switch features""" result = await hass.config_entries.flow.async_init( @@ -121,6 +126,8 @@ async def test_user_config_flow_over_switch(hass: HomeAssistant, skip_hass_state assert isinstance(result["result"], ConfigEntry) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_user_config_flow_over_climate(hass: HomeAssistant, skip_hass_states_get): """Test the config flow with all thermostat_over_climate features and no additional features""" result = await hass.config_entries.flow.async_init( @@ -206,6 +213,8 @@ async def test_user_config_flow_over_climate(hass: HomeAssistant, skip_hass_stat assert isinstance(result["result"], ConfigEntry) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_user_config_flow_window_auto_ok( hass: HomeAssistant, skip_hass_states_get, skip_control_heating ): @@ -301,6 +310,8 @@ async def test_user_config_flow_window_auto_ok( assert isinstance(result["result"], ConfigEntry) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_user_config_flow_window_auto_ko( hass: HomeAssistant, skip_hass_states_get ): @@ -371,6 +382,8 @@ async def test_user_config_flow_window_auto_ko( } +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_user_config_flow_over_4_switches( hass: HomeAssistant, skip_hass_states_get, skip_control_heating ): diff --git a/custom_components/versatile_thermostat/tests/test_movement.py b/custom_components/versatile_thermostat/tests/test_movement.py index e86483e..0e67553 100644 --- a/custom_components/versatile_thermostat/tests/test_movement.py +++ b/custom_components/versatile_thermostat/tests/test_movement.py @@ -9,6 +9,8 @@ import logging logging.getLogger().setLevel(logging.DEBUG) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_movement_management_time_not_enough( hass: HomeAssistant, skip_hass_states_is_state ): @@ -140,6 +142,8 @@ async def test_movement_management_time_not_enough( assert mock_send_event.call_count == 0 +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_movement_management_time_enough_and_presence( hass: HomeAssistant, skip_hass_states_is_state ): @@ -270,6 +274,8 @@ async def test_movement_management_time_enough_and_presence( assert mock_send_event.call_count == 0 +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_movement_management_time_enoughand_not_presence( hass: HomeAssistant, skip_hass_states_is_state ): diff --git a/custom_components/versatile_thermostat/tests/test_multiple_switch.py b/custom_components/versatile_thermostat/tests/test_multiple_switch.py index c5a650d..61940be 100644 --- a/custom_components/versatile_thermostat/tests/test_multiple_switch.py +++ b/custom_components/versatile_thermostat/tests/test_multiple_switch.py @@ -9,6 +9,8 @@ import logging logging.getLogger().setLevel(logging.DEBUG) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_one_switch_cycle( hass: HomeAssistant, skip_hass_states_is_state, @@ -206,6 +208,8 @@ async def test_one_switch_cycle( # assert entity.underlying_entity(0)._should_relaunch_control_heating is False +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_multiple_switchs( hass: HomeAssistant, skip_hass_states_is_state, diff --git a/custom_components/versatile_thermostat/tests/test_power.py b/custom_components/versatile_thermostat/tests/test_power.py index 165abfe..a59a612 100644 --- a/custom_components/versatile_thermostat/tests/test_power.py +++ b/custom_components/versatile_thermostat/tests/test_power.py @@ -10,6 +10,8 @@ import logging logging.getLogger().setLevel(logging.DEBUG) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_power_management_hvac_off( hass: HomeAssistant, skip_hass_states_is_state ): @@ -96,6 +98,8 @@ async def test_power_management_hvac_off( assert mock_heater_off.call_count == 0 +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_power_management_hvac_on(hass: HomeAssistant, skip_hass_states_is_state): """Test the Power management""" @@ -226,6 +230,8 @@ async def test_power_management_hvac_on(hass: HomeAssistant, skip_hass_states_is assert mock_heater_off.call_count == 0 +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_power_management_energy_over_switch( hass: HomeAssistant, skip_hass_states_is_state ): @@ -350,6 +356,8 @@ async def test_power_management_energy_over_switch( assert round(entity.total_energy, 2) == round((2.0 + 0.6) * 100 * 5 / 60.0, 2) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_power_management_energy_over_climate( hass: HomeAssistant, skip_hass_states_is_state ): diff --git a/custom_components/versatile_thermostat/tests/test_security.py b/custom_components/versatile_thermostat/tests/test_security.py index 55cc712..de46c96 100644 --- a/custom_components/versatile_thermostat/tests/test_security.py +++ b/custom_components/versatile_thermostat/tests/test_security.py @@ -9,6 +9,8 @@ import logging logging.getLogger().setLevel(logging.DEBUG) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_security_feature(hass: HomeAssistant, skip_hass_states_is_state): """Test the security feature and https://github.com/jmcollin78/versatile_thermostat/issues/49: 1. creates a thermostat and check that security is off diff --git a/custom_components/versatile_thermostat/tests/test_sensors.py b/custom_components/versatile_thermostat/tests/test_sensors.py index a17c23c..8755f91 100644 --- a/custom_components/versatile_thermostat/tests/test_sensors.py +++ b/custom_components/versatile_thermostat/tests/test_sensors.py @@ -26,6 +26,8 @@ from ..sensor import ( from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_sensors_over_switch( hass: HomeAssistant, skip_hass_states_is_state, @@ -182,6 +184,8 @@ async def test_sensors_over_switch( cancel_switchs_cycles(entity) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_sensors_over_climate( hass: HomeAssistant, skip_hass_states_is_state, @@ -316,6 +320,8 @@ async def test_sensors_over_climate( assert last_ext_temperature_sensor.device_class == SensorDeviceClass.TIMESTAMP +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_sensors_over_climate_minimal( hass: HomeAssistant, skip_hass_states_is_state, diff --git a/custom_components/versatile_thermostat/tests/test_start.py b/custom_components/versatile_thermostat/tests/test_start.py index 9900ba2..3c11564 100644 --- a/custom_components/versatile_thermostat/tests/test_start.py +++ b/custom_components/versatile_thermostat/tests/test_start.py @@ -15,6 +15,8 @@ from ..climate import VersatileThermostat from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_over_switch_full_start(hass: HomeAssistant, skip_hass_states_is_state): """Test the normal full start of a thermostat in thermostat_over_switch type""" @@ -76,6 +78,8 @@ async def test_over_switch_full_start(hass: HomeAssistant, skip_hass_states_is_s ) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_over_climate_full_start(hass: HomeAssistant, skip_hass_states_is_state): """Test the normal full start of a thermostat in thermostat_over_climate type""" @@ -143,6 +147,8 @@ async def test_over_climate_full_start(hass: HomeAssistant, skip_hass_states_is_ mock_find_climate.assert_has_calls([call.find_underlying_entity()]) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_over_4switch_full_start(hass: HomeAssistant, skip_hass_states_is_state): """Test the normal full start of a thermostat in thermostat_over_switch with 4 switches type""" diff --git a/custom_components/versatile_thermostat/tests/test_tpi.py b/custom_components/versatile_thermostat/tests/test_tpi.py index 54c9730..4225190 100644 --- a/custom_components/versatile_thermostat/tests/test_tpi.py +++ b/custom_components/versatile_thermostat/tests/test_tpi.py @@ -3,6 +3,8 @@ from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_tpi_calculation(hass: HomeAssistant, skip_hass_states_is_state): """Test the TPI calculation""" diff --git a/custom_components/versatile_thermostat/tests/test_window.py b/custom_components/versatile_thermostat/tests/test_window.py index cf60834..bff77ba 100644 --- a/custom_components/versatile_thermostat/tests/test_window.py +++ b/custom_components/versatile_thermostat/tests/test_window.py @@ -9,6 +9,8 @@ import logging logging.getLogger().setLevel(logging.DEBUG) +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_window_management_time_not_enough( hass: HomeAssistant, skip_hass_states_is_state ): @@ -92,7 +94,11 @@ async def test_window_management_time_not_enough( await try_window_condition(None) assert entity.window_state == STATE_OFF + await entity.remove_thermostat() + +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_window_management_time_enough( hass: HomeAssistant, skip_hass_states_is_state ): @@ -227,7 +233,12 @@ async def test_window_management_time_enough( ) assert entity.preset_mode is PRESET_BOOST + # Clean the entity + await entity.remove_thermostat() + +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_window_auto_fast(hass: HomeAssistant, skip_hass_states_is_state): """Test the Power management""" @@ -406,7 +417,12 @@ async def test_window_auto_fast(hass: HomeAssistant, skip_hass_states_is_state): assert entity.window_auto_state == STATE_OFF assert entity.hvac_mode is HVACMode.HEAT + # Clean the entity + await entity.remove_thermostat() + +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_window_auto_auto_stop(hass: HomeAssistant, skip_hass_states_is_state): """Test the Power management""" @@ -544,7 +560,12 @@ async def test_window_auto_auto_stop(hass: HomeAssistant, skip_hass_states_is_st assert entity.hvac_mode is HVACMode.HEAT assert entity.preset_mode is PRESET_BOOST + # Clean the entity + await entity.remove_thermostat() + +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize("expected_lingering_timers", [True]) async def test_window_auto_no_on_percent( hass: HomeAssistant, skip_hass_states_is_state ): @@ -647,3 +668,6 @@ async def test_window_auto_no_on_percent( assert entity._window_auto_algo.is_window_close_detected() is False assert entity.window_auto_state == STATE_OFF assert entity.hvac_mode is HVACMode.HEAT + + # Clean the entity + await entity.remove_thermostat()