core/tests/components/deconz/conftest.py

306 lines
8.9 KiB
Python
Raw Normal View History

2020-10-23 14:28:21 +00:00
"""deconz conftest."""
2021-03-18 14:13:22 +00:00
from __future__ import annotations
2024-07-19 11:10:38 +00:00
from collections.abc import Callable, Coroutine, Generator
from types import MappingProxyType
2024-07-19 11:10:38 +00:00
from typing import Any, Protocol
from unittest.mock import patch
from pydeconz.websocket import Signal
import pytest
from homeassistant.components.deconz.const import DOMAIN as DECONZ_DOMAIN
2024-07-19 11:10:38 +00:00
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT, CONTENT_TYPE_JSON
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
from tests.components.light.conftest import mock_light_profiles # noqa: F401
from tests.test_util.aiohttp import AiohttpClientMocker
2024-07-19 11:10:38 +00:00
type ConfigEntryFactoryType = Callable[
[MockConfigEntry], Coroutine[Any, Any, MockConfigEntry]
]
type WebsocketDataType = Callable[[dict[str, Any]], Coroutine[Any, Any, None]]
type WebsocketStateType = Callable[[str], Coroutine[Any, Any, None]]
class _WebsocketMock(Protocol):
async def __call__(
self, data: dict[str, Any] | None = None, state: str = ""
) -> None: ...
# Config entry fixtures
API_KEY = "1234567890ABCDEF"
BRIDGE_ID = "01234E56789A"
HOST = "1.2.3.4"
PORT = 80
@pytest.fixture(name="config_entry")
def fixture_config_entry(
config_entry_data: MappingProxyType[str, Any],
config_entry_options: MappingProxyType[str, Any],
config_entry_source: str,
2024-07-19 11:10:38 +00:00
) -> MockConfigEntry:
"""Define a config entry fixture."""
return MockConfigEntry(
domain=DECONZ_DOMAIN,
entry_id="1",
unique_id=BRIDGE_ID,
data=config_entry_data,
options=config_entry_options,
source=config_entry_source,
)
@pytest.fixture(name="config_entry_data")
def fixture_config_entry_data() -> MappingProxyType[str, Any]:
"""Define a config entry data fixture."""
return {
CONF_API_KEY: API_KEY,
CONF_HOST: HOST,
CONF_PORT: PORT,
}
@pytest.fixture(name="config_entry_options")
def fixture_config_entry_options() -> MappingProxyType[str, Any]:
"""Define a config entry options fixture."""
return {}
@pytest.fixture(name="config_entry_source")
def fixture_config_entry_source() -> str:
"""Define a config entry source fixture."""
return SOURCE_USER
# Request mocks
@pytest.fixture(name="mock_put_request")
def fixture_put_request(
aioclient_mock: AiohttpClientMocker, config_entry_data: MappingProxyType[str, Any]
) -> Callable[[str, str], AiohttpClientMocker]:
"""Mock a deCONZ put request."""
_host = config_entry_data[CONF_HOST]
_port = config_entry_data[CONF_PORT]
_api_key = config_entry_data[CONF_API_KEY]
def __mock_requests(path: str, host: str = "") -> AiohttpClientMocker:
url = f"http://{host or _host}:{_port}/api/{_api_key}{path}"
aioclient_mock.put(url, json={}, headers={"content-type": CONTENT_TYPE_JSON})
return aioclient_mock
return __mock_requests
@pytest.fixture(name="mock_requests")
def fixture_get_request(
aioclient_mock: AiohttpClientMocker,
config_entry_data: MappingProxyType[str, Any],
config_payload: dict[str, Any],
alarm_system_payload: dict[str, Any],
group_payload: dict[str, Any],
light_payload: dict[str, Any],
sensor_payload: dict[str, Any],
deconz_payload: dict[str, Any],
) -> Callable[[str], None]:
"""Mock default deCONZ requests responses."""
_host = config_entry_data[CONF_HOST]
_port = config_entry_data[CONF_PORT]
_api_key = config_entry_data[CONF_API_KEY]
data = deconz_payload
data.setdefault("alarmsystems", alarm_system_payload)
data.setdefault("config", config_payload)
data.setdefault("groups", group_payload)
if "state" in light_payload:
light_payload = {"0": light_payload}
data.setdefault("lights", light_payload)
if "state" in sensor_payload or "config" in sensor_payload:
sensor_payload = {"0": sensor_payload}
data.setdefault("sensors", sensor_payload)
def __mock_requests(host: str = "") -> None:
url = f"http://{host or _host}:{_port}/api/{_api_key}"
aioclient_mock.get(
url,
json=deconz_payload | {"config": config_payload},
headers={
"content-type": CONTENT_TYPE_JSON,
},
)
return __mock_requests
# Request payload fixtures
@pytest.fixture(name="deconz_payload")
def fixture_data() -> dict[str, Any]:
"""Combine multiple payloads with one fixture."""
return {}
@pytest.fixture(name="alarm_system_payload")
def fixture_alarm_system_data() -> dict[str, Any]:
"""Alarm system data."""
return {}
@pytest.fixture(name="config_payload")
def fixture_config_data() -> dict[str, Any]:
"""Config data."""
return {
"bridgeid": BRIDGE_ID,
"ipaddress": HOST,
"mac": "00:11:22:33:44:55",
"modelid": "deCONZ",
"name": "deCONZ mock gateway",
"sw_version": "2.05.69",
"uuid": "1234",
"websocketport": 1234,
}
@pytest.fixture(name="group_payload")
def fixture_group_data() -> dict[str, Any]:
"""Group data."""
return {}
@pytest.fixture(name="light_payload")
def fixture_light_data() -> dict[str, Any]:
"""Light data.
Should be
- one light data payload {"state": ...}
- multiple lights {"1": ..., "2": ...}
"""
return {}
@pytest.fixture(name="sensor_payload")
def fixture_sensor_data() -> dict[str, Any]:
"""Sensor data.
Should be
- one sensor data payload {"config": ..., "state": ...} ("0")
- multiple sensors {"1": ..., "2": ...}
"""
return {}
@pytest.fixture(name="config_entry_factory")
async def fixture_config_entry_factory(
hass: HomeAssistant,
2024-07-19 11:10:38 +00:00
config_entry: MockConfigEntry,
mock_requests: Callable[[str], None],
) -> ConfigEntryFactoryType:
"""Fixture factory that can set up UniFi network integration."""
2024-07-19 11:10:38 +00:00
async def __mock_setup_config_entry(
entry: MockConfigEntry = config_entry,
) -> MockConfigEntry:
entry.add_to_hass(hass)
mock_requests(entry.data[CONF_HOST])
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
return entry
return __mock_setup_config_entry
@pytest.fixture(name="config_entry_setup")
async def fixture_config_entry_setup(
config_entry_factory: ConfigEntryFactoryType,
2024-07-19 11:10:38 +00:00
) -> MockConfigEntry:
"""Fixture providing a set up instance of deCONZ integration."""
return await config_entry_factory()
# Websocket fixtures
@pytest.fixture(autouse=True, name="_mock_websocket")
2024-07-19 11:10:38 +00:00
def fixture_websocket() -> Generator[_WebsocketMock]:
"""No real websocket allowed."""
with patch("pydeconz.gateway.WSClient") as mock:
async def make_websocket_call(
data: dict[str, Any] | None = None, state: str = ""
) -> None:
"""Generate a websocket call."""
pydeconz_gateway_session_handler = mock.call_args[0][3]
signal: Signal
if data:
mock.return_value.data = data
signal = Signal.DATA
elif state:
mock.return_value.state = state
signal = Signal.CONNECTION_STATE
await pydeconz_gateway_session_handler(signal)
yield make_websocket_call
@pytest.fixture(name="mock_websocket_data")
def fixture_websocket_data(_mock_websocket: _WebsocketMock) -> WebsocketDataType:
"""Fixture to send websocket data."""
async def change_websocket_data(data: dict[str, Any]) -> None:
"""Provide new data on the websocket."""
if "t" not in data:
data["t"] = "event"
if "e" not in data:
data["e"] = "changed"
if "id" not in data:
data["id"] = "0"
await _mock_websocket(data=data)
return change_websocket_data
@pytest.fixture(name="light_ws_data")
def fixture_light_websocket_data(
mock_websocket_data: WebsocketDataType,
) -> WebsocketDataType:
"""Fixture to send light data over websocket."""
async def send_light_data(data: dict[str, Any]) -> None:
"""Send light data on the websocket."""
await mock_websocket_data({"r": "lights"} | data)
return send_light_data
@pytest.fixture(name="sensor_ws_data")
def fixture_sensor_websocket_data(
mock_websocket_data: WebsocketDataType,
) -> WebsocketDataType:
"""Fixture to send sensor data over websocket."""
async def send_sensor_data(data: dict[str, Any]) -> None:
"""Send sensor data on the websocket."""
await mock_websocket_data({"r": "sensors"} | data)
return send_sensor_data
@pytest.fixture(name="mock_websocket_state")
def fixture_websocket_state(_mock_websocket: _WebsocketMock) -> WebsocketStateType:
"""Fixture to set websocket state."""
async def change_websocket_state(state: str) -> None:
"""Simulate a change to the websocket connection state."""
await _mock_websocket(state=state)
return change_websocket_state