From 44640ef9e8c2cae98be54bdfb83ba7e6b767966d Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Mon, 1 Jul 2024 12:33:51 +0200 Subject: [PATCH] First step towards fixtures in deCONZ tests (#120863) * config entry fixture * Mock web request * Make siren tests use new fixtures * Replace old constants * Add mock put request * Change comment --- tests/components/deconz/conftest.py | 179 ++++++++++++++++++++++++ tests/components/deconz/test_gateway.py | 7 +- tests/components/deconz/test_siren.py | 40 +++--- 3 files changed, 201 insertions(+), 25 deletions(-) diff --git a/tests/components/deconz/conftest.py b/tests/components/deconz/conftest.py index d0f0f11c99b..ec254ea1c1e 100644 --- a/tests/components/deconz/conftest.py +++ b/tests/components/deconz/conftest.py @@ -2,12 +2,191 @@ from __future__ import annotations +from collections.abc import Callable +from types import MappingProxyType +from typing import Any from unittest.mock import patch from pydeconz.websocket import Signal import pytest +from homeassistant.components.deconz.const import DOMAIN as DECONZ_DOMAIN +from homeassistant.config_entries import ConfigEntry +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 + +# Config entry fixtures + +API_KEY = "1234567890ABCDEF" +BRIDGEID = "01234E56789A" +HOST = "1.2.3.4" +PORT = 80 + + +@pytest.fixture(name="config_entry") +def fixture_config_entry( + hass: HomeAssistant, + config_entry_data: MappingProxyType[str, Any], + config_entry_options: MappingProxyType[str, Any], +) -> ConfigEntry: + """Define a config entry fixture.""" + config_entry = MockConfigEntry( + domain=DECONZ_DOMAIN, + entry_id="1", + unique_id=BRIDGEID, + data=config_entry_data, + options=config_entry_options, + ) + config_entry.add_to_hass(hass) + return config_entry + + +@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 {} + + +# 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], + 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] + + def __mock_requests(host: str = "") -> None: + url = f"http://{host or _host}:{_port}/api/{_api_key}" + aioclient_mock.get( + url, json=deconz_payload, headers={"content-type": CONTENT_TYPE_JSON} + ) + + return __mock_requests + + +# Request payload fixtures + + +@pytest.fixture(name="deconz_payload") +def fixture_data( + alarm_system_payload: dict[str, Any], + config_payload: dict[str, Any], + group_payload: dict[str, Any], + light_payload: dict[str, Any], + sensor_payload: dict[str, Any], +) -> dict[str, Any]: + """DeCONZ data.""" + return { + "alarmsystems": alarm_system_payload, + "config": config_payload, + "groups": group_payload, + "lights": light_payload, + "sensors": sensor_payload, + } + + +@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": BRIDGEID, + "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.""" + return {} + + +@pytest.fixture(name="sensor_payload") +def fixture_sensor_data() -> dict[str, Any]: + """Sensor data.""" + return {} + + +@pytest.fixture(name="config_entry_factory") +async def fixture_config_entry_factory( + hass: HomeAssistant, + config_entry: ConfigEntry, + mock_requests: Callable[[str, str], None], +) -> Callable[[], ConfigEntry]: + """Fixture factory that can set up UniFi network integration.""" + + async def __mock_setup_config_entry() -> ConfigEntry: + mock_requests(config_entry.data[CONF_HOST]) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + return config_entry + + return __mock_setup_config_entry + + +@pytest.fixture(name="config_entry_setup") +async def fixture_config_entry_setup( + hass: HomeAssistant, config_entry_factory: Callable[[], ConfigEntry] +) -> ConfigEntry: + """Fixture providing a set up instance of deCONZ integration.""" + return await config_entry_factory() + + +# Websocket fixtures @pytest.fixture(autouse=True) diff --git a/tests/components/deconz/test_gateway.py b/tests/components/deconz/test_gateway.py index b00a5cc1f05..71001312dec 100644 --- a/tests/components/deconz/test_gateway.py +++ b/tests/components/deconz/test_gateway.py @@ -47,14 +47,11 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr from homeassistant.helpers.typing import UNDEFINED, UndefinedType +from .conftest import API_KEY, BRIDGEID, HOST, PORT + from tests.common import MockConfigEntry from tests.test_util.aiohttp import AiohttpClientMocker -API_KEY = "1234567890ABCDEF" -BRIDGEID = "01234E56789A" -HOST = "1.2.3.4" -PORT = 80 - DEFAULT_URL = f"http://{HOST}:{PORT}/api/{API_KEY}" ENTRY_CONFIG = {CONF_API_KEY: API_KEY, CONF_HOST: HOST, CONF_PORT: PORT} diff --git a/tests/components/deconz/test_siren.py b/tests/components/deconz/test_siren.py index 62ed1b732b8..3db345a6ad2 100644 --- a/tests/components/deconz/test_siren.py +++ b/tests/components/deconz/test_siren.py @@ -1,8 +1,11 @@ """deCONZ switch platform tests.""" -from unittest.mock import patch +from collections.abc import Callable + +import pytest from homeassistant.components.siren import ATTR_DURATION, DOMAIN as SIREN_DOMAIN +from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_ENTITY_ID, SERVICE_TURN_OFF, @@ -13,21 +16,13 @@ from homeassistant.const import ( ) from homeassistant.core import HomeAssistant -from .test_gateway import ( - DECONZ_WEB_REQUEST, - mock_deconz_put_request, - setup_deconz_integration, -) - from tests.test_util.aiohttp import AiohttpClientMocker -async def test_sirens( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, mock_deconz_websocket -) -> None: - """Test that siren entities are created.""" - data = { - "lights": { +@pytest.mark.parametrize( + "light_payload", + [ + { "1": { "name": "Warning device", "type": "Warning device", @@ -41,10 +36,15 @@ async def test_sirens( "uniqueid": "00:00:00:00:00:00:00:01-00", }, } - } - with patch.dict(DECONZ_WEB_REQUEST, data): - config_entry = await setup_deconz_integration(hass, aioclient_mock) - + ], +) +async def test_sirens( + hass: HomeAssistant, + config_entry_setup: ConfigEntry, + mock_deconz_websocket, + mock_put_request: Callable[[str, str], AiohttpClientMocker], +) -> None: + """Test that siren entities are created.""" assert len(hass.states.async_all()) == 2 assert hass.states.get("siren.warning_device").state == STATE_ON assert not hass.states.get("siren.unsupported_siren") @@ -63,7 +63,7 @@ async def test_sirens( # Verify service calls - mock_deconz_put_request(aioclient_mock, config_entry.data, "/lights/1/state") + aioclient_mock = mock_put_request("/lights/1/state") # Service turn on siren @@ -95,13 +95,13 @@ async def test_sirens( ) assert aioclient_mock.mock_calls[3][2] == {"alert": "lselect", "ontime": 100} - await hass.config_entries.async_unload(config_entry.entry_id) + await hass.config_entries.async_unload(config_entry_setup.entry_id) states = hass.states.async_all() assert len(states) == 2 for state in states: assert state.state == STATE_UNAVAILABLE - await hass.config_entries.async_remove(config_entry.entry_id) + await hass.config_entries.async_remove(config_entry_setup.entry_id) await hass.async_block_till_done() assert len(hass.states.async_all()) == 0