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:
parent
719a601880
commit
5116d02747
@ -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:
|
||||||
|
@ -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()
|
|
||||||
|
245
tests/components/deconz/test_services.py
Normal file
245
tests/components/deconz/test_services.py
Normal 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",
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user