225 lines
7.6 KiB
Python
225 lines
7.6 KiB
Python
"""Test deCONZ gateway."""
|
|
|
|
from collections.abc import Callable
|
|
from unittest.mock import patch
|
|
|
|
import pydeconz
|
|
from pydeconz.websocket import State
|
|
import pytest
|
|
|
|
from homeassistant.components import ssdp
|
|
from homeassistant.components.alarm_control_panel import (
|
|
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
|
|
)
|
|
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
|
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
|
|
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN
|
|
from homeassistant.components.cover import DOMAIN as COVER_DOMAIN
|
|
from homeassistant.components.deconz.config_flow import DECONZ_MANUFACTURERURL
|
|
from homeassistant.components.deconz.const import DOMAIN as DECONZ_DOMAIN
|
|
from homeassistant.components.deconz.errors import AuthenticationRequired, CannotConnect
|
|
from homeassistant.components.deconz.hub import DeconzHub, get_deconz_api
|
|
from homeassistant.components.fan import DOMAIN as FAN_DOMAIN
|
|
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
|
from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN
|
|
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
|
|
from homeassistant.components.scene import DOMAIN as SCENE_DOMAIN
|
|
from homeassistant.components.select import DOMAIN as SELECT_DOMAIN
|
|
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
|
from homeassistant.components.siren import DOMAIN as SIREN_DOMAIN
|
|
from homeassistant.components.ssdp import (
|
|
ATTR_UPNP_MANUFACTURER_URL,
|
|
ATTR_UPNP_SERIAL,
|
|
ATTR_UPNP_UDN,
|
|
)
|
|
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
|
from homeassistant.config_entries import SOURCE_HASSIO, SOURCE_SSDP, ConfigEntry
|
|
from homeassistant.const import STATE_OFF, STATE_UNAVAILABLE
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers import device_registry as dr
|
|
|
|
from .conftest import BRIDGEID, HOST, PORT
|
|
|
|
|
|
async def test_gateway_setup(
|
|
hass: HomeAssistant,
|
|
device_registry: dr.DeviceRegistry,
|
|
config_entry_factory: Callable[[], ConfigEntry],
|
|
) -> None:
|
|
"""Successful setup."""
|
|
# Patching async_forward_entry_setup* is not advisable, and should be refactored
|
|
# in the future.
|
|
with patch(
|
|
"homeassistant.config_entries.ConfigEntries.async_forward_entry_setups",
|
|
return_value=True,
|
|
) as forward_entry_setup:
|
|
config_entry = await config_entry_factory()
|
|
gateway = DeconzHub.get_hub(hass, config_entry)
|
|
assert gateway.bridgeid == BRIDGEID
|
|
assert gateway.master is True
|
|
assert gateway.config.allow_clip_sensor is False
|
|
assert gateway.config.allow_deconz_groups is True
|
|
assert gateway.config.allow_new_devices is True
|
|
|
|
assert len(gateway.deconz_ids) == 0
|
|
assert len(hass.states.async_all()) == 0
|
|
|
|
assert forward_entry_setup.mock_calls[0][1] == (
|
|
config_entry,
|
|
[
|
|
ALARM_CONTROL_PANEL_DOMAIN,
|
|
BINARY_SENSOR_DOMAIN,
|
|
BUTTON_DOMAIN,
|
|
CLIMATE_DOMAIN,
|
|
COVER_DOMAIN,
|
|
FAN_DOMAIN,
|
|
LIGHT_DOMAIN,
|
|
LOCK_DOMAIN,
|
|
NUMBER_DOMAIN,
|
|
SCENE_DOMAIN,
|
|
SELECT_DOMAIN,
|
|
SENSOR_DOMAIN,
|
|
SIREN_DOMAIN,
|
|
SWITCH_DOMAIN,
|
|
],
|
|
)
|
|
|
|
gateway_entry = device_registry.async_get_device(
|
|
identifiers={(DECONZ_DOMAIN, gateway.bridgeid)}
|
|
)
|
|
|
|
assert gateway_entry.configuration_url == f"http://{HOST}:{PORT}"
|
|
assert gateway_entry.entry_type is dr.DeviceEntryType.SERVICE
|
|
|
|
|
|
@pytest.mark.parametrize("config_entry_source", [SOURCE_HASSIO])
|
|
async def test_gateway_device_configuration_url_when_addon(
|
|
hass: HomeAssistant,
|
|
device_registry: dr.DeviceRegistry,
|
|
config_entry_factory: Callable[[], ConfigEntry],
|
|
) -> None:
|
|
"""Successful setup."""
|
|
# Patching async_forward_entry_setup* is not advisable, and should be refactored
|
|
# in the future.
|
|
with patch(
|
|
"homeassistant.config_entries.ConfigEntries.async_forward_entry_setups",
|
|
return_value=True,
|
|
):
|
|
config_entry = await config_entry_factory()
|
|
gateway = DeconzHub.get_hub(hass, config_entry)
|
|
|
|
gateway_entry = device_registry.async_get_device(
|
|
identifiers={(DECONZ_DOMAIN, gateway.bridgeid)}
|
|
)
|
|
|
|
assert (
|
|
gateway_entry.configuration_url == "homeassistant://hassio/ingress/core_deconz"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"sensor_payload",
|
|
[
|
|
{
|
|
"1": {
|
|
"name": "presence",
|
|
"type": "ZHAPresence",
|
|
"state": {"presence": False},
|
|
"config": {"on": True, "reachable": True},
|
|
"uniqueid": "00:00:00:00:00:00:00:00-00",
|
|
}
|
|
}
|
|
],
|
|
)
|
|
@pytest.mark.usefixtures("config_entry_setup")
|
|
async def test_connection_status_signalling(
|
|
hass: HomeAssistant, mock_websocket_state
|
|
) -> None:
|
|
"""Make sure that connection status triggers a dispatcher send."""
|
|
assert hass.states.get("binary_sensor.presence").state == STATE_OFF
|
|
|
|
await mock_websocket_state(State.RETRYING)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.states.get("binary_sensor.presence").state == STATE_UNAVAILABLE
|
|
|
|
await mock_websocket_state(State.RUNNING)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.states.get("binary_sensor.presence").state == STATE_OFF
|
|
|
|
|
|
async def test_update_address(
|
|
hass: HomeAssistant, config_entry_setup: ConfigEntry
|
|
) -> None:
|
|
"""Make sure that connection status triggers a dispatcher send."""
|
|
gateway = DeconzHub.get_hub(hass, config_entry_setup)
|
|
assert gateway.api.host == "1.2.3.4"
|
|
|
|
with patch(
|
|
"homeassistant.components.deconz.async_setup_entry",
|
|
return_value=True,
|
|
) as mock_setup_entry:
|
|
await hass.config_entries.flow.async_init(
|
|
DECONZ_DOMAIN,
|
|
data=ssdp.SsdpServiceInfo(
|
|
ssdp_st="mock_st",
|
|
ssdp_usn="mock_usn",
|
|
ssdp_location="http://2.3.4.5:80/",
|
|
upnp={
|
|
ATTR_UPNP_MANUFACTURER_URL: DECONZ_MANUFACTURERURL,
|
|
ATTR_UPNP_SERIAL: BRIDGEID,
|
|
ATTR_UPNP_UDN: "uuid:456DEF",
|
|
},
|
|
),
|
|
context={"source": SOURCE_SSDP},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert gateway.api.host == "2.3.4.5"
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
|
|
async def test_reset_after_successful_setup(
|
|
hass: HomeAssistant, config_entry_setup: ConfigEntry
|
|
) -> None:
|
|
"""Make sure that connection status triggers a dispatcher send."""
|
|
gateway = DeconzHub.get_hub(hass, config_entry_setup)
|
|
|
|
result = await gateway.async_reset()
|
|
await hass.async_block_till_done()
|
|
|
|
assert result is True
|
|
|
|
|
|
async def test_get_deconz_api(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
|
"""Successful call."""
|
|
with patch("pydeconz.DeconzSession.refresh_state", return_value=True):
|
|
assert await get_deconz_api(hass, config_entry)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("side_effect", "raised_exception"),
|
|
[
|
|
(TimeoutError, CannotConnect),
|
|
(pydeconz.RequestError, CannotConnect),
|
|
(pydeconz.ResponseError, CannotConnect),
|
|
(pydeconz.Unauthorized, AuthenticationRequired),
|
|
],
|
|
)
|
|
async def test_get_deconz_api_fails(
|
|
hass: HomeAssistant,
|
|
config_entry: ConfigEntry,
|
|
side_effect: Exception,
|
|
raised_exception: Exception,
|
|
) -> None:
|
|
"""Failed call."""
|
|
with (
|
|
patch(
|
|
"pydeconz.DeconzSession.refresh_state",
|
|
side_effect=side_effect,
|
|
),
|
|
pytest.raises(raised_exception),
|
|
):
|
|
assert await get_deconz_api(hass, config_entry)
|