From 8dd5f25da988dc933a95ee176703b887def3047c Mon Sep 17 00:00:00 2001 From: Guido Schmitz <Shutgun@users.noreply.github.com> Date: Wed, 29 Jun 2022 15:46:32 +0200 Subject: [PATCH] Add cover tests for devolo_home_control (#72428) --- .coveragerc | 1 - tests/components/devolo_home_control/mocks.py | 26 ++++- .../devolo_home_control/test_cover.py | 103 ++++++++++++++++++ 3 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 tests/components/devolo_home_control/test_cover.py diff --git a/.coveragerc b/.coveragerc index 02c643ae757..eae8060449a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -210,7 +210,6 @@ omit = homeassistant/components/denonavr/media_player.py homeassistant/components/denonavr/receiver.py homeassistant/components/deutsche_bahn/sensor.py - homeassistant/components/devolo_home_control/cover.py homeassistant/components/devolo_home_control/light.py homeassistant/components/devolo_home_control/sensor.py homeassistant/components/devolo_home_control/switch.py diff --git a/tests/components/devolo_home_control/mocks.py b/tests/components/devolo_home_control/mocks.py index b43cb77ad71..e9dae0b70b1 100644 --- a/tests/components/devolo_home_control/mocks.py +++ b/tests/components/devolo_home_control/mocks.py @@ -51,7 +51,6 @@ class MultiLevelSwitchPropertyMock(MultiLevelSwitchProperty): self.element_uid = "Test" self.min = 4 self.max = 24 - self.switch_type = "temperature" self._value = 20 self._logger = MagicMock() @@ -120,9 +119,21 @@ class ClimateMock(DeviceMock): super().__init__() self.device_model_uid = "devolo.model.Room:Thermostat" self.multi_level_switch_property = {"Test": MultiLevelSwitchPropertyMock()} + self.multi_level_switch_property["Test"].switch_type = "temperature" self.multi_level_sensor_property = {"Test": MultiLevelSensorPropertyMock()} +class CoverMock(DeviceMock): + """devolo Home Control cover device mock.""" + + def __init__(self) -> None: + """Initialize the mock.""" + super().__init__() + self.multi_level_switch_property = { + "devolo.Blinds": MultiLevelSwitchPropertyMock() + } + + class RemoteControlMock(DeviceMock): """devolo Home Control remote control device mock.""" @@ -195,6 +206,19 @@ class HomeControlMockClimate(HomeControlMock): self.publisher.unregister = MagicMock() +class HomeControlMockCover(HomeControlMock): + """devolo Home Control gateway mock with cover devices.""" + + def __init__(self, **kwargs: Any) -> None: + """Initialize the mock.""" + super().__init__() + self.devices = { + "Test": CoverMock(), + } + self.publisher = Publisher(self.devices.keys()) + self.publisher.unregister = MagicMock() + + class HomeControlMockRemoteControl(HomeControlMock): """devolo Home Control gateway mock with remote control device.""" diff --git a/tests/components/devolo_home_control/test_cover.py b/tests/components/devolo_home_control/test_cover.py new file mode 100644 index 00000000000..1c05c00370b --- /dev/null +++ b/tests/components/devolo_home_control/test_cover.py @@ -0,0 +1,103 @@ +"""Tests for the devolo Home Control cover platform.""" +from unittest.mock import patch + +from homeassistant.components.cover import ATTR_CURRENT_POSITION, ATTR_POSITION, DOMAIN +from homeassistant.const import ( + ATTR_ENTITY_ID, + SERVICE_CLOSE_COVER, + SERVICE_OPEN_COVER, + SERVICE_SET_COVER_POSITION, + STATE_CLOSED, + STATE_OPEN, + STATE_UNAVAILABLE, +) +from homeassistant.core import HomeAssistant + +from . import configure_integration +from .mocks import HomeControlMock, HomeControlMockCover + + +async def test_cover(hass: HomeAssistant): + """Test setup and state change of a cover device.""" + entry = configure_integration(hass) + test_gateway = HomeControlMockCover() + test_gateway.devices["Test"].multi_level_switch_property["devolo.Blinds"].value = 20 + with patch( + "homeassistant.components.devolo_home_control.HomeControl", + side_effect=[test_gateway, HomeControlMock()], + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + state = hass.states.get(f"{DOMAIN}.test") + assert state is not None + assert state.state == STATE_OPEN + assert ( + state.attributes[ATTR_CURRENT_POSITION] + == test_gateway.devices["Test"] + .multi_level_switch_property["devolo.Blinds"] + .value + ) + + # Emulate websocket message: position changed + test_gateway.publisher.dispatch("Test", ("devolo.Blinds", 0.0)) + await hass.async_block_till_done() + state = hass.states.get(f"{DOMAIN}.test") + assert state.state == STATE_CLOSED + assert state.attributes[ATTR_CURRENT_POSITION] == 0.0 + + # Test setting position + with patch( + "devolo_home_control_api.properties.multi_level_switch_property.MultiLevelSwitchProperty.set" + ) as set_value: + await hass.services.async_call( + DOMAIN, + SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: f"{DOMAIN}.test"}, + blocking=True, + ) # In reality, this leads to a websocket message like already tested above + set_value.assert_called_once_with(100) + + set_value.reset_mock() + await hass.services.async_call( + DOMAIN, + SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: f"{DOMAIN}.test"}, + blocking=True, + ) # In reality, this leads to a websocket message like already tested above + set_value.assert_called_once_with(0) + + set_value.reset_mock() + await hass.services.async_call( + DOMAIN, + SERVICE_SET_COVER_POSITION, + {ATTR_ENTITY_ID: f"{DOMAIN}.test", ATTR_POSITION: 50}, + blocking=True, + ) # In reality, this leads to a websocket message like already tested above + set_value.assert_called_once_with(50) + + # Emulate websocket message: device went offline + test_gateway.devices["Test"].status = 1 + test_gateway.publisher.dispatch("Test", ("Status", False, "status")) + await hass.async_block_till_done() + assert hass.states.get(f"{DOMAIN}.test").state == STATE_UNAVAILABLE + + +async def test_remove_from_hass(hass: HomeAssistant): + """Test removing entity.""" + entry = configure_integration(hass) + test_gateway = HomeControlMockCover() + with patch( + "homeassistant.components.devolo_home_control.HomeControl", + side_effect=[test_gateway, HomeControlMock()], + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + state = hass.states.get(f"{DOMAIN}.test") + assert state is not None + await hass.config_entries.async_remove(entry.entry_id) + await hass.async_block_till_done() + + assert len(hass.states.async_all()) == 0 + assert test_gateway.publisher.unregister.call_count == 1 -- GitLab