1
mirror of https://github.com/home-assistant/core synced 2024-09-09 12:51:22 +02:00

deCONZ - Improve service tests (#26663)

* Improve configure service tests

* Add refresh device service test

* Add tests for setup and unload services

* Remove refresh device test from test_init

* Extra verification of deconz services existance in hass.data
This commit is contained in:
Robert Svensson 2019-09-16 10:08:13 +02:00 committed by Pascal Vizeli
parent 719a601880
commit 5116d02747
3 changed files with 248 additions and 98 deletions

View File

@ -89,13 +89,14 @@ async def async_configure_service(hass, data):
See Dresden Elektroniks REST API documentation for details: See Dresden Elektroniks REST API documentation for details:
http://dresden-elektronik.github.io/deconz-rest-doc/rest/ http://dresden-elektronik.github.io/deconz-rest-doc/rest/
""" """
bridgeid = data.get(CONF_BRIDGEID)
field = data.get(SERVICE_FIELD, "") field = data.get(SERVICE_FIELD, "")
entity_id = data.get(SERVICE_ENTITY) entity_id = data.get(SERVICE_ENTITY)
data = data[SERVICE_DATA] data = data[SERVICE_DATA]
gateway = get_master_gateway(hass) gateway = get_master_gateway(hass)
if CONF_BRIDGEID in data: if bridgeid:
gateway = hass.data[DOMAIN][data[CONF_BRIDGEID]] gateway = hass.data[DOMAIN][bridgeid]
if entity_id: if entity_id:
try: try:

View File

@ -3,7 +3,6 @@ from unittest.mock import Mock, patch
import asyncio import asyncio
import pytest import pytest
import voluptuous as vol
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.components import deconz from homeassistant.components import deconz
@ -168,98 +167,3 @@ async def test_unload_entry_multiple_gateways(hass):
assert ENTRY2_BRIDGEID in hass.data[deconz.DOMAIN] assert ENTRY2_BRIDGEID in hass.data[deconz.DOMAIN]
assert hass.data[deconz.DOMAIN][ENTRY2_BRIDGEID].master assert hass.data[deconz.DOMAIN][ENTRY2_BRIDGEID].master
async def test_service_configure(hass):
"""Test that service invokes pydeconz with the correct path and data."""
entry = MockConfigEntry(
domain=deconz.DOMAIN,
data={
deconz.config_flow.CONF_HOST: ENTRY1_HOST,
deconz.config_flow.CONF_PORT: ENTRY1_PORT,
deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY,
deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID,
},
)
entry.add_to_hass(hass)
await setup_entry(hass, entry)
hass.data[deconz.DOMAIN][ENTRY1_BRIDGEID].deconz_ids = {"light.test": "/light/1"}
data = {"on": True, "attr1": 10, "attr2": 20}
# only field
with patch("pydeconz.DeconzSession.async_put_state", return_value=mock_coro(True)):
await hass.services.async_call(
"deconz", "configure", service_data={"field": "/light/42", "data": data}
)
await hass.async_block_till_done()
# only entity
with patch("pydeconz.DeconzSession.async_put_state", return_value=mock_coro(True)):
await hass.services.async_call(
"deconz", "configure", service_data={"entity": "light.test", "data": data}
)
await hass.async_block_till_done()
# entity + field
with patch("pydeconz.DeconzSession.async_put_state", return_value=mock_coro(True)):
await hass.services.async_call(
"deconz",
"configure",
service_data={"entity": "light.test", "field": "/state", "data": data},
)
await hass.async_block_till_done()
# non-existing entity (or not from deCONZ)
with patch("pydeconz.DeconzSession.async_put_state", return_value=mock_coro(True)):
await hass.services.async_call(
"deconz",
"configure",
service_data={
"entity": "light.nonexisting",
"field": "/state",
"data": data,
},
)
await hass.async_block_till_done()
# field does not start with /
with pytest.raises(vol.Invalid):
with patch(
"pydeconz.DeconzSession.async_put_state", return_value=mock_coro(True)
):
await hass.services.async_call(
"deconz",
"configure",
service_data={"entity": "light.test", "field": "state", "data": data},
)
await hass.async_block_till_done()
async def test_service_refresh_devices(hass):
"""Test that service can refresh devices."""
entry = MockConfigEntry(
domain=deconz.DOMAIN,
data={
deconz.config_flow.CONF_HOST: ENTRY1_HOST,
deconz.config_flow.CONF_PORT: ENTRY1_PORT,
deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY,
deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID,
},
)
entry.add_to_hass(hass)
await setup_entry(hass, entry)
with patch(
"pydeconz.DeconzSession.async_load_parameters", return_value=mock_coro(True)
):
await hass.services.async_call("deconz", "device_refresh", service_data={})
await hass.async_block_till_done()
with patch(
"pydeconz.DeconzSession.async_load_parameters", return_value=mock_coro(False)
):
await hass.services.async_call("deconz", "device_refresh", service_data={})
await hass.async_block_till_done()

View File

@ -0,0 +1,245 @@
"""deCONZ service tests."""
from asynctest import Mock, patch
import pytest
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components import deconz
BRIDGEID = "0123456789"
ENTRY_CONFIG = {
deconz.config_flow.CONF_API_KEY: "ABCDEF",
deconz.config_flow.CONF_BRIDGEID: BRIDGEID,
deconz.config_flow.CONF_HOST: "1.2.3.4",
deconz.config_flow.CONF_PORT: 80,
}
DECONZ_CONFIG = {
"bridgeid": BRIDGEID,
"mac": "00:11:22:33:44:55",
"name": "deCONZ mock gateway",
"sw_version": "2.05.69",
"websocketport": 1234,
}
DECONZ_WEB_REQUEST = {"config": DECONZ_CONFIG}
GROUP = {
"1": {
"id": "Group 1 id",
"name": "Group 1 name",
"type": "LightGroup",
"state": {},
"action": {},
"scenes": [{"id": "1", "name": "Scene 1"}],
"lights": ["1"],
}
}
LIGHT = {
"1": {
"id": "Light 1 id",
"name": "Light 1 name",
"state": {"reachable": True},
"type": "Light",
"uniqueid": "00:00:00:00:00:00:00:01-00",
}
}
SENSOR = {
"1": {
"id": "Sensor 1 id",
"name": "Sensor 1 name",
"type": "ZHALightLevel",
"state": {"lightlevel": 30000, "dark": False},
"config": {"reachable": True},
"uniqueid": "00:00:00:00:00:00:00:02-00",
}
}
async def setup_deconz_integration(hass, options):
"""Create the deCONZ gateway."""
config_entry = config_entries.ConfigEntry(
version=1,
domain=deconz.DOMAIN,
title="Mock Title",
data=ENTRY_CONFIG,
source="test",
connection_class=config_entries.CONN_CLASS_LOCAL_PUSH,
system_options={},
options=options,
entry_id="1",
)
with patch(
"pydeconz.DeconzSession.async_get_state", return_value=DECONZ_WEB_REQUEST
):
await deconz.async_setup_entry(hass, config_entry)
await hass.async_block_till_done()
hass.config_entries._entries.append(config_entry)
return hass.data[deconz.DOMAIN][BRIDGEID]
async def test_service_setup(hass):
"""Verify service setup works."""
assert deconz.services.DECONZ_SERVICES not in hass.data
with patch(
"homeassistant.core.ServiceRegistry.async_register", return_value=Mock(True)
) as async_register:
await deconz.services.async_setup_services(hass)
assert hass.data[deconz.services.DECONZ_SERVICES] is True
assert async_register.call_count == 2
async def test_service_setup_already_registered(hass):
"""Make sure that services are only registered once."""
hass.data[deconz.services.DECONZ_SERVICES] = True
with patch(
"homeassistant.core.ServiceRegistry.async_register", return_value=Mock(True)
) as async_register:
await deconz.services.async_setup_services(hass)
async_register.assert_not_called()
async def test_service_unload(hass):
"""Verify service unload works."""
hass.data[deconz.services.DECONZ_SERVICES] = True
with patch(
"homeassistant.core.ServiceRegistry.async_remove", return_value=Mock(True)
) as async_remove:
await deconz.services.async_unload_services(hass)
assert hass.data[deconz.services.DECONZ_SERVICES] is False
assert async_remove.call_count == 2
async def test_service_unload_not_registered(hass):
"""Make sure that services can only be unloaded once."""
with patch(
"homeassistant.core.ServiceRegistry.async_remove", return_value=Mock(True)
) as async_remove:
await deconz.services.async_unload_services(hass)
assert deconz.services.DECONZ_SERVICES not in hass.data
async_remove.assert_not_called()
async def test_configure_service_with_field(hass):
"""Test that service invokes pydeconz with the correct path and data."""
await setup_deconz_integration(hass, options={})
data = {
deconz.services.SERVICE_FIELD: "/light/2",
deconz.CONF_BRIDGEID: BRIDGEID,
deconz.services.SERVICE_DATA: {"on": True, "attr1": 10, "attr2": 20},
}
with patch(
"pydeconz.DeconzSession.async_put_state", return_value=Mock(True)
) as put_state:
await hass.services.async_call(
deconz.DOMAIN, deconz.services.SERVICE_CONFIGURE_DEVICE, service_data=data
)
await hass.async_block_till_done()
put_state.assert_called_with("/light/2", {"on": True, "attr1": 10, "attr2": 20})
async def test_configure_service_with_entity(hass):
"""Test that service invokes pydeconz with the correct path and data."""
gateway = await setup_deconz_integration(hass, options={})
gateway.deconz_ids["light.test"] = "/light/1"
data = {
deconz.services.SERVICE_ENTITY: "light.test",
deconz.services.SERVICE_DATA: {"on": True, "attr1": 10, "attr2": 20},
}
with patch(
"pydeconz.DeconzSession.async_put_state", return_value=Mock(True)
) as put_state:
await hass.services.async_call(
deconz.DOMAIN, deconz.services.SERVICE_CONFIGURE_DEVICE, service_data=data
)
await hass.async_block_till_done()
put_state.assert_called_with("/light/1", {"on": True, "attr1": 10, "attr2": 20})
async def test_configure_service_with_entity_and_field(hass):
"""Test that service invokes pydeconz with the correct path and data."""
gateway = await setup_deconz_integration(hass, options={})
gateway.deconz_ids["light.test"] = "/light/1"
data = {
deconz.services.SERVICE_ENTITY: "light.test",
deconz.services.SERVICE_FIELD: "/state",
deconz.services.SERVICE_DATA: {"on": True, "attr1": 10, "attr2": 20},
}
with patch(
"pydeconz.DeconzSession.async_put_state", return_value=Mock(True)
) as put_state:
await hass.services.async_call(
deconz.DOMAIN, deconz.services.SERVICE_CONFIGURE_DEVICE, service_data=data
)
await hass.async_block_till_done()
put_state.assert_called_with(
"/light/1/state", {"on": True, "attr1": 10, "attr2": 20}
)
async def test_configure_service_with_faulty_field(hass):
"""Test that service invokes pydeconz with the correct path and data."""
await setup_deconz_integration(hass, options={})
data = {deconz.services.SERVICE_FIELD: "light/2", deconz.services.SERVICE_DATA: {}}
with pytest.raises(vol.Invalid):
await hass.services.async_call(
deconz.DOMAIN, deconz.services.SERVICE_CONFIGURE_DEVICE, service_data=data
)
await hass.async_block_till_done()
async def test_configure_service_with_faulty_entity(hass):
"""Test that service invokes pydeconz with the correct path and data."""
await setup_deconz_integration(hass, options={})
data = {
deconz.services.SERVICE_ENTITY: "light.nonexisting",
deconz.services.SERVICE_DATA: {},
}
with patch(
"pydeconz.DeconzSession.async_put_state", return_value=Mock(True)
) as put_state:
await hass.services.async_call(
deconz.DOMAIN, deconz.services.SERVICE_CONFIGURE_DEVICE, service_data=data
)
await hass.async_block_till_done()
put_state.assert_not_called()
async def test_service_refresh_devices(hass):
"""Test that service can refresh devices."""
gateway = await setup_deconz_integration(hass, options={})
data = {deconz.CONF_BRIDGEID: BRIDGEID}
with patch(
"pydeconz.DeconzSession.async_get_state",
return_value={"groups": GROUP, "lights": LIGHT, "sensors": SENSOR},
):
await hass.services.async_call(
deconz.DOMAIN, deconz.services.SERVICE_DEVICE_REFRESH, service_data=data
)
await hass.async_block_till_done()
assert gateway.deconz_ids == {
"light.group_1_name": "/groups/1",
"light.light_1_name": "/lights/1",
"scene.group_1_name_scene_1": "/groups/1/scenes/1",
"sensor.sensor_1_name": "/sensors/1",
}