Refactor tradfri cover tests (#87710)

* Refactor tradfri cover tests

* Complete typing
This commit is contained in:
Martin Hjelmare 2023-02-08 18:31:04 +01:00 committed by GitHub
parent 37a2040d7b
commit 630028106a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 100 additions and 126 deletions

View File

@ -0,0 +1,19 @@
{
"3": {
"0": "IKEA of Sweden",
"1": "FYRTUR block-out roller blind",
"2": "",
"3": "2.2.007",
"6": 3,
"9": 77
},
"5750": 7,
"9001": "Test",
"9002": 1566141494,
"9003": 65601,
"9019": 1,
"9020": 1566402653,
"9054": 0,
"9084": " 9d 58 b0 2 4 6a df be 77 e5 c1 e0 a2 26 2e 57",
"15015": [{ "5536": 40.0, "9003": 0 }]
}

View File

@ -1,154 +1,109 @@
"""Tradfri cover (recognised as blinds in the IKEA ecosystem) platform tests."""
from __future__ import annotations
from unittest.mock import MagicMock, Mock, PropertyMock, patch
import json
from typing import Any
from unittest.mock import MagicMock, Mock
import pytest
from pytradfri.const import ATTR_REACHABLE_STATE
from pytradfri.device import Device
from pytradfri.device.blind import Blind
from pytradfri.device.blind_control import BlindControl
from .common import setup_integration
from homeassistant.components.cover import ATTR_CURRENT_POSITION, DOMAIN as COVER_DOMAIN
from homeassistant.components.tradfri.const import DOMAIN
from homeassistant.const import STATE_CLOSED, STATE_OPEN, STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from .common import setup_integration, trigger_observe_callback
from tests.common import load_fixture
@pytest.fixture(autouse=True, scope="module")
def setup(request):
"""Set up patches for pytradfri methods."""
with patch(
"pytradfri.device.BlindControl.raw",
new_callable=PropertyMock,
return_value=[{"mock": "mock"}],
), patch(
"pytradfri.device.BlindControl.blinds",
):
yield
@pytest.fixture(scope="module")
def blind_response() -> dict[str, Any]:
"""Return a blind response."""
return json.loads(load_fixture("blind.json", DOMAIN))
def mock_cover(test_features=None, test_state=None, device_number=0):
"""Mock a tradfri cover/blind."""
if test_features is None:
test_features = {}
if test_state is None:
test_state = {}
mock_cover_data = Mock(**test_state)
dev_info_mock = MagicMock()
dev_info_mock.manufacturer = "manufacturer"
dev_info_mock.model_number = "model"
dev_info_mock.firmware_version = "1.2.3"
_mock_cover = Mock(
id=f"mock-cover-id-{device_number}",
reachable=True,
observe=Mock(),
device_info=dev_info_mock,
has_light_control=False,
has_socket_control=False,
has_blind_control=True,
has_signal_repeater_control=False,
has_air_purifier_control=False,
)
_mock_cover.name = f"tradfri_cover_{device_number}"
# Set supported features for the covers.
blind_control = BlindControl(_mock_cover)
# Store the initial state.
setattr(blind_control, "blinds", [mock_cover_data])
_mock_cover.blind_control = blind_control
return _mock_cover
@pytest.fixture
def blind(blind_response: dict[str, Any]) -> Blind:
"""Return blind."""
device = Device(blind_response)
blind_control = device.blind_control
assert blind_control
return blind_control.blinds[0]
async def test_cover(hass, mock_gateway, mock_api_factory):
"""Test that covers are correctly added."""
state = {
"current_cover_position": 40,
}
mock_gateway.mock_devices.append(mock_cover(test_state=state))
await setup_integration(hass)
cover_1 = hass.states.get("cover.tradfri_cover_0")
assert cover_1 is not None
assert cover_1.state == "open"
assert cover_1.attributes["current_position"] == 60
async def test_cover_observed(hass, mock_gateway, mock_api_factory):
"""Test that covers are correctly observed."""
state = {
"current_cover_position": 1,
}
cover = mock_cover(test_state=state)
mock_gateway.mock_devices.append(cover)
await setup_integration(hass)
assert len(cover.observe.mock_calls) > 0
async def test_cover_available(hass, mock_gateway, mock_api_factory):
async def test_cover_available(
hass: HomeAssistant,
mock_gateway: Mock,
mock_api_factory: MagicMock,
blind: Blind,
) -> None:
"""Test cover available property."""
cover = mock_cover(test_state={"current_cover_position": 1}, device_number=1)
cover.reachable = True
cover2 = mock_cover(test_state={"current_cover_position": 1}, device_number=2)
cover2.reachable = False
mock_gateway.mock_devices.append(cover)
mock_gateway.mock_devices.append(cover2)
entity_id = "cover.test"
device = blind.device
mock_gateway.mock_devices.append(device)
await setup_integration(hass)
assert hass.states.get("cover.tradfri_cover_1").state == "open"
assert hass.states.get("cover.tradfri_cover_2").state == "unavailable"
state = hass.states.get(entity_id)
assert state
assert state.state == STATE_OPEN
assert state.attributes[ATTR_CURRENT_POSITION] == 60
assert state.attributes["model"] == "FYRTUR block-out roller blind"
await trigger_observe_callback(
hass, mock_gateway, device, {ATTR_REACHABLE_STATE: 0}
)
state = hass.states.get(entity_id)
assert state
assert state.state == STATE_UNAVAILABLE
@pytest.mark.parametrize(
"test_data, expected_result",
[({"position": 100}, "open"), ({"position": 0}, "closed")],
"service, service_data, expected_state, expected_position",
[
("set_cover_position", {"position": 100}, STATE_OPEN, 100),
("set_cover_position", {"position": 0}, STATE_CLOSED, 0),
("open_cover", {}, STATE_OPEN, 100),
("close_cover", {}, STATE_CLOSED, 0),
("stop_cover", {}, STATE_OPEN, 60),
],
)
async def test_set_cover_position(
hass,
mock_gateway,
mock_api_factory,
test_data,
expected_result,
):
"""Test setting position of a cover."""
# Note pytradfri style, not hass. Values not really important.
initial_state = {
"current_cover_position": 0,
}
# Setup the gateway with a mock cover.
cover = mock_cover(test_state=initial_state, device_number=0)
mock_gateway.mock_devices.append(cover)
async def test_cover_services(
hass: HomeAssistant,
mock_gateway: Mock,
mock_api_factory: MagicMock,
blind: Blind,
service: str,
service_data: dict[str, Any],
expected_state: str,
expected_position: int,
) -> None:
"""Test cover services."""
entity_id = "cover.test"
device = blind.device
mock_gateway.mock_devices.append(device)
await setup_integration(hass)
# Use the turn_on service call to change the cover state.
state = hass.states.get(entity_id)
assert state
assert state.state == STATE_OPEN
assert state.attributes[ATTR_CURRENT_POSITION] == 60
await hass.services.async_call(
"cover",
"set_cover_position",
{"entity_id": "cover.tradfri_cover_0", **test_data},
COVER_DOMAIN,
service,
{"entity_id": entity_id, **service_data},
blocking=True,
)
await hass.async_block_till_done()
# Check that the cover is observed.
mock_func = cover.observe
assert len(mock_func.mock_calls) > 0
_, callkwargs = mock_func.call_args
assert "callback" in callkwargs
# Callback function to refresh cover state.
callback = callkwargs["callback"]
await trigger_observe_callback(hass, mock_gateway, device)
responses = mock_gateway.mock_responses
# Use the callback function to update the cover state.
dev = Device(responses[0])
cover_data = Blind(dev, 0)
cover.blind_control.blinds[0] = cover_data
callback(cover)
await hass.async_block_till_done()
# Check that the state is correct.
state = hass.states.get("cover.tradfri_cover_0")
assert state.state == expected_result
state = hass.states.get(entity_id)
assert state
assert state.state == expected_state
assert state.attributes[ATTR_CURRENT_POSITION] == expected_position