Refactor homekit_controller tests to reduce duplication. (#64198)

This commit is contained in:
Jc2k 2022-01-16 18:43:44 +00:00 committed by GitHub
parent 187b4fad84
commit 99481e2258
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 435 additions and 290 deletions

View file

@ -1,6 +1,10 @@
"""Code to support homekit_controller tests."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
import json
import logging
import os
from unittest import mock
@ -15,12 +19,45 @@ from homeassistant.components.homekit_controller.const import (
CONTROLLER,
DOMAIN,
HOMEKIT_ACCESSORY_DISPATCH,
IDENTIFIER_ACCESSORY_ID,
IDENTIFIER_SERIAL_NUMBER,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture
logger = logging.getLogger(__name__)
@dataclass
class EntityTestInfo:
"""Describes how we expected an entity to be created by homekit_controller."""
entity_id: str
unique_id: str
friendly_name: str
state: str
supported_features: int = 0
@dataclass
class DeviceTestInfo:
"""Describes how we exepced a device to be created by homekit_controlller."""
unique_id: str
name: str
manufacturer: str
model: str
sw_version: str
hw_version: str
serial_number: str
devices: list[DeviceTestInfo]
entities: list[EntityTestInfo]
class Helper:
"""Helper methods for interacting with HomeKit fakes."""
@ -171,3 +208,73 @@ async def setup_test_component(hass, setup_accessory, capitalize=False, suffix=N
config_entry, pairing = await setup_test_accessories(hass, [accessory])
entity = "testdevice" if suffix is None else f"testdevice_{suffix}"
return Helper(hass, ".".join((domain, entity)), pairing, accessory, config_entry)
def assert_devices_and_entities_created(hass: HomeAssistant, expected: DeviceTestInfo):
"""Check that all expected devices and entities are loaded and enumerated as expected."""
entity_registry = er.async_get(hass)
device_registry = dr.async_get(hass)
def _do_assertions(expected: DeviceTestInfo) -> dr.DeviceEntry:
# Note: homekit_controller currently uses a 3-tuple for device identifiers
# The current standard is a 2-tuple (hkc was not migrated when this change was brought in)
# There are currently really 3 cases here:
# - We can match exactly one device by serial number. This won't work for devices like the Ryse.
# These have nlank or broken serial numbers.
# - The device unique id is "00:00:00:00:00:00" - this is the pairing id. This is only set for
# the root (bridge) device.
# - The device unique id is "00:00:00:00:00:00-X", where X is a HAP aid. This is only set when
# we have detected broken serial numbers (and serial number is not used as an identifier).
device = device_registry.async_get_device(
{
(DOMAIN, IDENTIFIER_SERIAL_NUMBER, expected.serial_number),
(DOMAIN, IDENTIFIER_ACCESSORY_ID, expected.unique_id),
}
)
logger.debug("Comparing device %r to %r", device, expected)
assert device
assert device.name == expected.name
assert device.model == expected.model
assert device.manufacturer == expected.manufacturer
assert device.hw_version == expected.hw_version
assert device.sw_version == expected.sw_version
# We might have matched the device by one identifier only
# Lets check that the other one is correct. Otherwise the test might silently be wrong.
for _, key, value in device.identifiers:
if key == IDENTIFIER_SERIAL_NUMBER:
assert value == expected.serial_number
elif key == IDENTIFIER_ACCESSORY_ID:
assert value == expected.unique_id
for entity_info in expected.entities:
entity = entity_registry.async_get(entity_info.entity_id)
logger.debug("Comparing entity %r to %r", entity, entity_info)
assert entity
assert entity.device_id == device.id
assert entity.unique_id == entity_info.unique_id
assert entity.supported_features == entity_info.supported_features
state = hass.states.get(entity_info.entity_id)
logger.debug("Comparing state %r to %r", state, entity_info)
assert state is not None
assert state.state == entity_info.state
assert state.attributes["friendly_name"] == entity_info.friendly_name
for child in expected.devices:
child_device = _do_assertions(child)
assert child_device.via_device_id == device.id
assert child_device.id != device.id
return device
root_device = _do_assertions(expected)
# Root device must not have a via, otherwise its not the device
assert root_device.via_device_id is None