Tweak deCONZ init and hub tests (#122484)

* Improve typing of init tests

* Clean up gateway test

* Validate deconz device registry entry

* Rename gateway to hub

* Snake case BRIDGEID to BRIDGE_ID
pull/122493/head
Robert Svensson 2024-07-23 21:29:48 +02:00 committed by GitHub
parent 2730713b39
commit e6ef8a34a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 74 additions and 137 deletions

View File

@ -35,7 +35,7 @@ class _WebsocketMock(Protocol):
# Config entry fixtures
API_KEY = "1234567890ABCDEF"
BRIDGEID = "01234E56789A"
BRIDGE_ID = "01234E56789A"
HOST = "1.2.3.4"
PORT = 80
@ -50,7 +50,7 @@ def fixture_config_entry(
return MockConfigEntry(
domain=DECONZ_DOMAIN,
entry_id="1",
unique_id=BRIDGEID,
unique_id=BRIDGE_ID,
data=config_entry_data,
options=config_entry_options,
source=config_entry_source,
@ -158,7 +158,7 @@ def fixture_alarm_system_data() -> dict[str, Any]:
def fixture_config_data() -> dict[str, Any]:
"""Config data."""
return {
"bridgeid": BRIDGEID,
"bridgeid": BRIDGE_ID,
"ipaddress": HOST,
"mac": "00:11:22:33:44:55",
"modelid": "deCONZ",
@ -219,7 +219,6 @@ async def fixture_config_entry_factory(
@pytest.fixture(name="config_entry_setup")
async def fixture_config_entry_setup(
hass: HomeAssistant,
config_entry_factory: Callable[[], Coroutine[Any, Any, MockConfigEntry]],
) -> MockConfigEntry:
"""Fixture providing a set up instance of deCONZ integration."""

View File

@ -0,0 +1,33 @@
# serializer version: 1
# name: test_device_registry_entry
DeviceRegistryEntrySnapshot({
'area_id': None,
'config_entries': <ANY>,
'configuration_url': 'http://1.2.3.4:80',
'connections': set({
}),
'disabled_by': None,
'entry_type': <DeviceEntryType.SERVICE: 'service'>,
'hw_version': None,
'id': <ANY>,
'identifiers': set({
tuple(
'deconz',
'01234E56789A',
),
}),
'is_new': False,
'labels': set({
}),
'manufacturer': 'Dresden Elektronik',
'model': 'deCONZ',
'model_id': None,
'name': 'deCONZ mock gateway',
'name_by_user': None,
'primary_config_entry': <ANY>,
'serial_number': None,
'suggested_area': None,
'sw_version': None,
'via_device_id': None,
})
# ---

View File

@ -33,7 +33,7 @@ from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT, CONTENT_TYPE
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from .conftest import API_KEY, BRIDGEID
from .conftest import API_KEY, BRIDGE_ID
from tests.test_util.aiohttp import AiohttpClientMocker
@ -48,7 +48,7 @@ async def test_flow_discovered_bridges(
aioclient_mock.get(
pydeconz.utils.URL_DISCOVER,
json=[
{"id": BRIDGEID, "internalipaddress": "1.2.3.4", "internalport": 80},
{"id": BRIDGE_ID, "internalipaddress": "1.2.3.4", "internalport": 80},
{"id": "1234E567890A", "internalipaddress": "5.6.7.8", "internalport": 80},
],
headers={"content-type": CONTENT_TYPE_JSON},
@ -79,7 +79,7 @@ async def test_flow_discovered_bridges(
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == BRIDGEID
assert result["title"] == BRIDGE_ID
assert result["data"] == {
CONF_HOST: "1.2.3.4",
CONF_PORT: 80,
@ -93,7 +93,7 @@ async def test_flow_manual_configuration_decision(
"""Test that config flow for one discovered bridge works."""
aioclient_mock.get(
pydeconz.utils.URL_DISCOVER,
json=[{"id": BRIDGEID, "internalipaddress": "1.2.3.4", "internalport": 80}],
json=[{"id": BRIDGE_ID, "internalipaddress": "1.2.3.4", "internalport": 80}],
headers={"content-type": CONTENT_TYPE_JSON},
)
@ -124,7 +124,7 @@ async def test_flow_manual_configuration_decision(
aioclient_mock.get(
f"http://1.2.3.4:80/api/{API_KEY}/config",
json={"bridgeid": BRIDGEID},
json={"bridgeid": BRIDGE_ID},
headers={"content-type": CONTENT_TYPE_JSON},
)
@ -133,7 +133,7 @@ async def test_flow_manual_configuration_decision(
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == BRIDGEID
assert result["title"] == BRIDGE_ID
assert result["data"] == {
CONF_HOST: "1.2.3.4",
CONF_PORT: 80,
@ -175,7 +175,7 @@ async def test_flow_manual_configuration(
aioclient_mock.get(
f"http://1.2.3.4:80/api/{API_KEY}/config",
json={"bridgeid": BRIDGEID},
json={"bridgeid": BRIDGE_ID},
headers={"content-type": CONTENT_TYPE_JSON},
)
@ -184,7 +184,7 @@ async def test_flow_manual_configuration(
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == BRIDGEID
assert result["title"] == BRIDGE_ID
assert result["data"] == {
CONF_HOST: "1.2.3.4",
CONF_PORT: 80,
@ -257,7 +257,7 @@ async def test_manual_configuration_update_configuration(
aioclient_mock.get(
f"http://2.3.4.5:80/api/{API_KEY}/config",
json={"bridgeid": BRIDGEID},
json={"bridgeid": BRIDGE_ID},
headers={"content-type": CONTENT_TYPE_JSON},
)
@ -304,7 +304,7 @@ async def test_manual_configuration_dont_update_configuration(
aioclient_mock.get(
f"http://1.2.3.4:80/api/{API_KEY}/config",
json={"bridgeid": BRIDGEID},
json={"bridgeid": BRIDGE_ID},
headers={"content-type": CONTENT_TYPE_JSON},
)
@ -375,7 +375,7 @@ async def test_link_step_fails(
"""Test config flow should abort if no API key was possible to retrieve."""
aioclient_mock.get(
pydeconz.utils.URL_DISCOVER,
json=[{"id": BRIDGEID, "internalipaddress": "1.2.3.4", "internalport": 80}],
json=[{"id": BRIDGE_ID, "internalipaddress": "1.2.3.4", "internalport": 80}],
headers={"content-type": CONTENT_TYPE_JSON},
)
@ -426,7 +426,7 @@ async def test_reauth_flow_update_configuration(
aioclient_mock.get(
f"http://1.2.3.4:80/api/{new_api_key}/config",
json={"bridgeid": BRIDGEID},
json={"bridgeid": BRIDGE_ID},
headers={"content-type": CONTENT_TYPE_JSON},
)
@ -451,7 +451,7 @@ async def test_flow_ssdp_discovery(
ssdp_location="http://1.2.3.4:80/",
upnp={
ATTR_UPNP_MANUFACTURER_URL: DECONZ_MANUFACTURERURL,
ATTR_UPNP_SERIAL: BRIDGEID,
ATTR_UPNP_SERIAL: BRIDGE_ID,
},
),
context={"source": SOURCE_SSDP},
@ -475,7 +475,7 @@ async def test_flow_ssdp_discovery(
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == BRIDGEID
assert result["title"] == BRIDGE_ID
assert result["data"] == {
CONF_HOST: "1.2.3.4",
CONF_PORT: 80,
@ -499,7 +499,7 @@ async def test_ssdp_discovery_update_configuration(
ssdp_location="http://2.3.4.5:80/",
upnp={
ATTR_UPNP_MANUFACTURER_URL: DECONZ_MANUFACTURERURL,
ATTR_UPNP_SERIAL: BRIDGEID,
ATTR_UPNP_SERIAL: BRIDGE_ID,
},
),
context={"source": SOURCE_SSDP},
@ -525,7 +525,7 @@ async def test_ssdp_discovery_dont_update_configuration(
ssdp_location="http://1.2.3.4:80/",
upnp={
ATTR_UPNP_MANUFACTURER_URL: DECONZ_MANUFACTURERURL,
ATTR_UPNP_SERIAL: BRIDGEID,
ATTR_UPNP_SERIAL: BRIDGE_ID,
},
),
context={"source": SOURCE_SSDP},
@ -549,7 +549,7 @@ async def test_ssdp_discovery_dont_update_existing_hassio_configuration(
ssdp_location="http://1.2.3.4:80/",
upnp={
ATTR_UPNP_MANUFACTURER_URL: DECONZ_MANUFACTURERURL,
ATTR_UPNP_SERIAL: BRIDGEID,
ATTR_UPNP_SERIAL: BRIDGE_ID,
},
),
context={"source": SOURCE_SSDP},
@ -569,7 +569,7 @@ async def test_flow_hassio_discovery(hass: HomeAssistant) -> None:
"addon": "Mock Addon",
CONF_HOST: "mock-deconz",
CONF_PORT: 80,
CONF_SERIAL: BRIDGEID,
CONF_SERIAL: BRIDGE_ID,
CONF_API_KEY: API_KEY,
},
name="Mock Addon",
@ -622,7 +622,7 @@ async def test_hassio_discovery_update_configuration(
CONF_HOST: "2.3.4.5",
CONF_PORT: 8080,
CONF_API_KEY: "updated",
CONF_SERIAL: BRIDGEID,
CONF_SERIAL: BRIDGE_ID,
},
name="Mock Addon",
slug="deconz",
@ -650,7 +650,7 @@ async def test_hassio_discovery_dont_update_configuration(hass: HomeAssistant) -
CONF_HOST: "1.2.3.4",
CONF_PORT: 80,
CONF_API_KEY: API_KEY,
CONF_SERIAL: BRIDGEID,
CONF_SERIAL: BRIDGE_ID,
},
name="Mock Addon",
slug="deconz",

View File

@ -1,120 +1,40 @@
"""Test deCONZ gateway."""
from collections.abc import Callable
from unittest.mock import patch
import pydeconz
from pydeconz.websocket import State
import pytest
from syrupy import SnapshotAssertion
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.config_entries import 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
from .conftest import BRIDGE_ID
async def test_gateway_setup(
hass: HomeAssistant,
async def test_device_registry_entry(
config_entry_setup: ConfigEntry,
device_registry: dr.DeviceRegistry,
config_entry_factory: Callable[[], ConfigEntry],
snapshot: SnapshotAssertion,
) -> 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"
device_entry = device_registry.async_get_device(
identifiers={(DECONZ_DOMAIN, config_entry_setup.unique_id)}
)
assert device_entry == snapshot
@pytest.mark.parametrize(
@ -166,7 +86,7 @@ async def test_update_address(
ssdp_location="http://2.3.4.5:80/",
upnp={
ATTR_UPNP_MANUFACTURER_URL: DECONZ_MANUFACTURERURL,
ATTR_UPNP_SERIAL: BRIDGEID,
ATTR_UPNP_SERIAL: BRIDGE_ID,
ATTR_UPNP_UDN: "uuid:456DEF",
},
),

View File

@ -16,22 +16,9 @@ from homeassistant.core import HomeAssistant
from .conftest import ConfigEntryFactoryType
from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker
ENTRY1_HOST = "1.2.3.4"
ENTRY1_PORT = 80
ENTRY1_API_KEY = "1234567890ABCDEF"
ENTRY1_BRIDGEID = "12345ABC"
ENTRY1_UUID = "456DEF"
ENTRY2_HOST = "2.3.4.5"
ENTRY2_PORT = 80
ENTRY2_API_KEY = "1234567890ABCDEF"
ENTRY2_BRIDGEID = "23456DEF"
ENTRY2_UUID = "789ACE"
async def setup_entry(hass, entry):
async def setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Test that setup entry works."""
with (
patch.object(DeconzHub, "async_setup", return_value=True),
@ -109,9 +96,7 @@ async def test_unload_entry(
async def test_unload_entry_multiple_gateways(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
config_entry_factory,
hass: HomeAssistant, config_entry_factory: ConfigEntryFactoryType
) -> None:
"""Test being able to unload an entry and master gateway gets moved."""
config_entry = await config_entry_factory()
@ -133,7 +118,7 @@ async def test_unload_entry_multiple_gateways(
async def test_unload_entry_multiple_gateways_parallel(
hass: HomeAssistant, config_entry_factory
hass: HomeAssistant, config_entry_factory: ConfigEntryFactoryType
) -> None:
"""Test race condition when unloading multiple config entries in parallel."""
config_entry = await config_entry_factory()

View File

@ -25,7 +25,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from .test_gateway import BRIDGEID
from .test_hub import BRIDGE_ID
from tests.common import async_capture_events
from tests.test_util.aiohttp import AiohttpClientMocker
@ -39,7 +39,7 @@ async def test_configure_service_with_field(
"""Test that service invokes pydeconz with the correct path and data."""
data = {
SERVICE_FIELD: "/lights/2",
CONF_BRIDGE_ID: BRIDGEID,
CONF_BRIDGE_ID: BRIDGE_ID,
SERVICE_DATA: {"on": True, "attr1": 10, "attr2": 20},
}
@ -228,7 +228,7 @@ async def test_service_refresh_devices(
mock_requests()
await hass.services.async_call(
DECONZ_DOMAIN, SERVICE_DEVICE_REFRESH, service_data={CONF_BRIDGE_ID: BRIDGEID}
DECONZ_DOMAIN, SERVICE_DEVICE_REFRESH, service_data={CONF_BRIDGE_ID: BRIDGE_ID}
)
await hass.async_block_till_done()
@ -294,7 +294,7 @@ async def test_service_refresh_devices_trigger_no_state_update(
mock_requests()
await hass.services.async_call(
DECONZ_DOMAIN, SERVICE_DEVICE_REFRESH, service_data={CONF_BRIDGE_ID: BRIDGEID}
DECONZ_DOMAIN, SERVICE_DEVICE_REFRESH, service_data={CONF_BRIDGE_ID: BRIDGE_ID}
)
await hass.async_block_till_done()
@ -369,7 +369,7 @@ async def test_remove_orphaned_entries_service(
await hass.services.async_call(
DECONZ_DOMAIN,
SERVICE_REMOVE_ORPHANED_ENTRIES,
service_data={CONF_BRIDGE_ID: BRIDGEID},
service_data={CONF_BRIDGE_ID: BRIDGE_ID},
)
await hass.async_block_till_done()