Increase test coverage of deCONZ device triggers (#48126)

* Increase test coverage of deCONZ device triggers

* Revert removed new line

* Found a way to explicitly assert that exceptions are raised

* Remove unnecessary block till done

* Fix unnecessary elif

* Fix review comments

* Remove helper tests
This commit is contained in:
Robert Svensson 2021-03-23 13:49:44 +01:00 committed by GitHub
parent e0e3495849
commit 1095d93892
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 299 additions and 46 deletions

View File

@ -16,7 +16,6 @@ from homeassistant.const import (
)
from . import DOMAIN
from .const import LOGGER
from .deconz_event import CONF_DECONZ_EVENT, CONF_GESTURE
CONF_SUBTYPE = "subtype"
@ -414,16 +413,13 @@ async def async_validate_trigger_config(hass, config):
trigger = (config[CONF_TYPE], config[CONF_SUBTYPE])
if (
not device
or device.model not in REMOTES
or trigger not in REMOTES[device.model]
):
if not device:
raise InvalidDeviceAutomationConfig(
f"deCONZ trigger {trigger} device with id "
f"{config[CONF_DEVICE_ID]} not found"
)
if not device:
raise InvalidDeviceAutomationConfig(
f"deCONZ trigger {trigger} device with ID "
f"{config[CONF_DEVICE_ID]} not found"
)
if device.model not in REMOTES or trigger not in REMOTES[device.model]:
raise InvalidDeviceAutomationConfig(
f"deCONZ trigger {trigger} is not valid for device "
f"{device} ({config[CONF_DEVICE_ID]})"
@ -443,8 +439,9 @@ async def async_attach_trigger(hass, config, action, automation_info):
deconz_event = _get_deconz_event_from_device_id(hass, device.id)
if deconz_event is None:
LOGGER.error("No deconz_event tied to device %s found", device.name)
raise InvalidDeviceAutomationConfig
raise InvalidDeviceAutomationConfig(
f'No deconz_event tied to device "{device.name}" found'
)
event_id = deconz_event.serial

View File

@ -1,7 +1,10 @@
"""deCONZ device automation tests."""
from unittest.mock import patch
from unittest.mock import Mock, patch
import pytest
from homeassistant.components.automation import DOMAIN as AUTOMATION_DOMAIN
from homeassistant.components.deconz import device_trigger
from homeassistant.components.deconz.const import DOMAIN as DECONZ_DOMAIN
from homeassistant.components.deconz.device_trigger import CONF_SUBTYPE
@ -14,33 +17,23 @@ from homeassistant.const import (
CONF_PLATFORM,
CONF_TYPE,
)
from homeassistant.helpers.trigger import async_initialize_triggers
from homeassistant.setup import async_setup_component
from .test_gateway import DECONZ_WEB_REQUEST, setup_deconz_integration
from tests.common import assert_lists_same, async_get_device_automations
from tests.common import (
assert_lists_same,
async_get_device_automations,
async_mock_service,
)
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa: F401
SENSORS = {
"1": {
"config": {
"alert": "none",
"battery": 60,
"group": "10",
"on": True,
"reachable": True,
},
"ep": 1,
"etag": "1b355c0b6d2af28febd7ca9165881952",
"manufacturername": "IKEA of Sweden",
"mode": 1,
"modelid": "TRADFRI on/off switch",
"name": "TRÅDFRI on/off switch ",
"state": {"buttonevent": 2002, "lastupdated": "2019-09-07T07:39:39"},
"swversion": "1.4.018",
"type": "ZHASwitch",
"uniqueid": "d0:cf:5e:ff:fe:71:a4:3a-01-1000",
}
}
@pytest.fixture
def automation_calls(hass):
"""Track automation calls to a mock service."""
return async_mock_service(hass, "test", "automation")
async def test_get_triggers(hass, aioclient_mock):
@ -76,8 +69,6 @@ async def test_get_triggers(hass, aioclient_mock):
identifiers={(DECONZ_DOMAIN, "d0:cf:5e:ff:fe:71:a4:3a")}
)
assert device_trigger._get_deconz_event_from_device_id(hass, device.id)
triggers = await async_get_device_automations(hass, "trigger", device.id)
expected_triggers = [
@ -135,14 +126,279 @@ async def test_get_triggers(hass, aioclient_mock):
assert_lists_same(triggers, expected_triggers)
async def test_helper_no_match(hass, aioclient_mock):
"""Verify trigger helper returns None when no event could be matched."""
async def test_get_triggers_manage_unsupported_remotes(hass, aioclient_mock):
"""Verify no triggers for an unsupported remote."""
data = {
"sensors": {
"1": {
"config": {
"alert": "none",
"group": "10",
"on": True,
"reachable": True,
},
"ep": 1,
"etag": "1b355c0b6d2af28febd7ca9165881952",
"manufacturername": "IKEA of Sweden",
"mode": 1,
"modelid": "Unsupported model",
"name": "TRÅDFRI on/off switch ",
"state": {"buttonevent": 2002, "lastupdated": "2019-09-07T07:39:39"},
"swversion": "1.4.018",
"type": "ZHASwitch",
"uniqueid": "d0:cf:5e:ff:fe:71:a4:3a-01-1000",
}
}
}
with patch.dict(DECONZ_WEB_REQUEST, data):
await setup_deconz_integration(hass, aioclient_mock)
device_registry = await hass.helpers.device_registry.async_get_registry()
device = device_registry.async_get_device(
identifiers={(DECONZ_DOMAIN, "d0:cf:5e:ff:fe:71:a4:3a")}
)
triggers = await async_get_device_automations(hass, "trigger", device.id)
expected_triggers = []
assert_lists_same(triggers, expected_triggers)
async def test_functional_device_trigger(
hass, aioclient_mock, mock_deconz_websocket, automation_calls
):
"""Test proper matching and attachment of device trigger automation."""
await async_setup_component(hass, "persistent_notification", {})
data = {
"sensors": {
"1": {
"config": {
"alert": "none",
"battery": 60,
"group": "10",
"on": True,
"reachable": True,
},
"ep": 1,
"etag": "1b355c0b6d2af28febd7ca9165881952",
"manufacturername": "IKEA of Sweden",
"mode": 1,
"modelid": "TRADFRI on/off switch",
"name": "TRÅDFRI on/off switch ",
"state": {"buttonevent": 2002, "lastupdated": "2019-09-07T07:39:39"},
"swversion": "1.4.018",
"type": "ZHASwitch",
"uniqueid": "d0:cf:5e:ff:fe:71:a4:3a-01-1000",
}
}
}
with patch.dict(DECONZ_WEB_REQUEST, data):
await setup_deconz_integration(hass, aioclient_mock)
device_registry = await hass.helpers.device_registry.async_get_registry()
device = device_registry.async_get_device(
identifiers={(DECONZ_DOMAIN, "d0:cf:5e:ff:fe:71:a4:3a")}
)
assert await async_setup_component(
hass,
AUTOMATION_DOMAIN,
{
AUTOMATION_DOMAIN: [
{
"trigger": {
CONF_PLATFORM: "device",
CONF_DOMAIN: DECONZ_DOMAIN,
CONF_DEVICE_ID: device.id,
CONF_TYPE: device_trigger.CONF_SHORT_PRESS,
CONF_SUBTYPE: device_trigger.CONF_TURN_ON,
},
"action": {
"service": "test.automation",
"data_template": {"some": "test_trigger_button_press"},
},
},
]
},
)
assert len(hass.states.async_entity_ids(AUTOMATION_DOMAIN)) == 1
event_changed_sensor = {
"t": "event",
"e": "changed",
"r": "sensors",
"id": "1",
"state": {"buttonevent": 1002},
}
await mock_deconz_websocket(data=event_changed_sensor)
await hass.async_block_till_done()
assert len(automation_calls) == 1
assert automation_calls[0].data["some"] == "test_trigger_button_press"
async def test_validate_trigger_unknown_device(
hass, aioclient_mock, mock_deconz_websocket
):
"""Test unknown device does not return a trigger config."""
await setup_deconz_integration(hass, aioclient_mock)
deconz_event = device_trigger._get_deconz_event_from_device_id(hass, "mock-id")
assert not deconz_event
assert await async_setup_component(
hass,
AUTOMATION_DOMAIN,
{
AUTOMATION_DOMAIN: [
{
"trigger": {
CONF_PLATFORM: "device",
CONF_DOMAIN: DECONZ_DOMAIN,
CONF_DEVICE_ID: "unknown device",
CONF_TYPE: device_trigger.CONF_SHORT_PRESS,
CONF_SUBTYPE: device_trigger.CONF_TURN_ON,
},
"action": {
"service": "test.automation",
"data_template": {"some": "test_trigger_button_press"},
},
},
]
},
)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(AUTOMATION_DOMAIN)) == 0
async def test_helper_no_gateway_exist(hass):
"""Verify trigger helper returns None when no gateway exist."""
deconz_event = device_trigger._get_deconz_event_from_device_id(hass, "mock-id")
assert not deconz_event
async def test_validate_trigger_unsupported_device(
hass, aioclient_mock, mock_deconz_websocket
):
"""Test unsupported device doesn't return a trigger config."""
config_entry = await setup_deconz_integration(hass, aioclient_mock)
device_registry = await hass.helpers.device_registry.async_get_registry()
device = device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
identifiers={(DECONZ_DOMAIN, "d0:cf:5e:ff:fe:71:a4:3a")},
model="unsupported",
)
assert await async_setup_component(
hass,
AUTOMATION_DOMAIN,
{
AUTOMATION_DOMAIN: [
{
"trigger": {
CONF_PLATFORM: "device",
CONF_DOMAIN: DECONZ_DOMAIN,
CONF_DEVICE_ID: device.id,
CONF_TYPE: device_trigger.CONF_SHORT_PRESS,
CONF_SUBTYPE: device_trigger.CONF_TURN_ON,
},
"action": {
"service": "test.automation",
"data_template": {"some": "test_trigger_button_press"},
},
},
]
},
)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(AUTOMATION_DOMAIN)) == 0
async def test_validate_trigger_unsupported_trigger(
hass, aioclient_mock, mock_deconz_websocket
):
"""Test unsupported trigger does not return a trigger config."""
config_entry = await setup_deconz_integration(hass, aioclient_mock)
device_registry = await hass.helpers.device_registry.async_get_registry()
device = device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
identifiers={(DECONZ_DOMAIN, "d0:cf:5e:ff:fe:71:a4:3a")},
model="TRADFRI on/off switch",
)
trigger_config = {
CONF_PLATFORM: "device",
CONF_DOMAIN: DECONZ_DOMAIN,
CONF_DEVICE_ID: device.id,
CONF_TYPE: "unsupported",
CONF_SUBTYPE: device_trigger.CONF_TURN_ON,
}
assert await async_setup_component(
hass,
AUTOMATION_DOMAIN,
{
AUTOMATION_DOMAIN: [
{
"trigger": trigger_config,
"action": {
"service": "test.automation",
"data_template": {"some": "test_trigger_button_press"},
},
},
]
},
)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(AUTOMATION_DOMAIN)) == 0
async def test_attach_trigger_no_matching_event(
hass, aioclient_mock, mock_deconz_websocket
):
"""Test no matching event for device doesn't return a trigger config."""
config_entry = await setup_deconz_integration(hass, aioclient_mock)
device_registry = await hass.helpers.device_registry.async_get_registry()
device = device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
identifiers={(DECONZ_DOMAIN, "d0:cf:5e:ff:fe:71:a4:3a")},
name="Tradfri switch",
model="TRADFRI on/off switch",
)
trigger_config = {
CONF_PLATFORM: "device",
CONF_DOMAIN: DECONZ_DOMAIN,
CONF_DEVICE_ID: device.id,
CONF_TYPE: device_trigger.CONF_SHORT_PRESS,
CONF_SUBTYPE: device_trigger.CONF_TURN_ON,
}
assert await async_setup_component(
hass,
AUTOMATION_DOMAIN,
{
AUTOMATION_DOMAIN: [
{
"trigger": trigger_config,
"action": {
"service": "test.automation",
"data_template": {"some": "test_trigger_button_press"},
},
},
]
},
)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(AUTOMATION_DOMAIN)) == 1
# Assert that deCONZ async_attach_trigger raises InvalidDeviceAutomationConfig
assert not await async_initialize_triggers(
hass,
[trigger_config],
action=Mock(),
domain=AUTOMATION_DOMAIN,
name="mock-name",
log_cb=Mock(),
)