Add tests for Zimi entitites (#144292)

This commit is contained in:
markhannon
2025-08-05 04:41:05 +10:00
committed by GitHub
parent 94f2118b19
commit a9621ac811
10 changed files with 528 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
"""Common items for testing the zimi component."""
from unittest.mock import MagicMock, create_autospec, patch
from zcc.device import ControlPointDevice
from homeassistant.components.zimi.const import DOMAIN
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
DEVICE_INFO = {
"id": "test-device-id",
"name": "unknown",
"manufacturer": "Zimi",
"model": "Controller XYZ",
"hwVersion": "2.2.2",
"fwVersion": "3.3.3",
}
ENTITY_INFO = {
"id": "test-entity-id",
"name": "Test Entity Name",
"room": "Test Entity Room",
"type": "unknown",
}
INPUT_HOST = "192.168.1.100"
INPUT_PORT = 5003
def mock_api_device(
device_name: str | None = None,
entity_type: str | None = None,
) -> MagicMock:
"""Mock a Zimi ControlPointDevice which is used in the zcc API with defaults."""
mock_api_device = create_autospec(ControlPointDevice)
mock_api_device.identifier = ENTITY_INFO["id"]
mock_api_device.room = ENTITY_INFO["room"]
mock_api_device.name = ENTITY_INFO["name"]
mock_api_device.type = entity_type or ENTITY_INFO["type"]
mock_manfacture_info = MagicMock()
mock_manfacture_info.identifier = DEVICE_INFO["id"]
mock_manfacture_info.manufacturer = DEVICE_INFO["manufacturer"]
mock_manfacture_info.model = DEVICE_INFO["model"]
mock_manfacture_info.name = device_name or DEVICE_INFO["name"]
mock_manfacture_info.hwVersion = DEVICE_INFO["hwVersion"]
mock_manfacture_info.firmwareVersion = DEVICE_INFO["fwVersion"]
mock_api_device.manufacture_info = mock_manfacture_info
mock_api_device.brightness = 0
mock_api_device.percentage = 0
return mock_api_device
async def setup_platform(
hass: HomeAssistant,
platform: str,
) -> MockConfigEntry:
"""Set up the specified Zimi platform."""
if not platform:
raise ValueError("Platform must be specified")
mock_config = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: INPUT_HOST, CONF_PORT: INPUT_PORT}
)
mock_config.add_to_hass(hass)
with patch("homeassistant.components.zimi.PLATFORMS", [platform]):
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
return mock_config

View File

@@ -0,0 +1,28 @@
"""Test fixtures for Zimi component."""
from unittest.mock import patch
import pytest
INPUT_MAC = "aa:bb:cc:dd:ee:ff"
API_INFO = {
"brand": "Zimi",
"network_name": "Test Network",
"firmware_version": "1.1.1",
}
@pytest.fixture
def mock_api():
"""Mock the API with defaults."""
with patch("homeassistant.components.zimi.async_connect_to_controller") as mock:
mock_api = mock.return_value
mock_api.connect.return_value = True
mock_api.mac = INPUT_MAC
mock_api.brand = API_INFO["brand"]
mock_api.network_name = API_INFO["network_name"]
mock_api.firmware_version = API_INFO["firmware_version"]
yield mock_api

View File

@@ -0,0 +1,17 @@
# serializer version: 1
# name: test_cover_entity
StateSnapshot({
'attributes': ReadOnlyDict({
'current_position': 0,
'device_class': 'garage',
'friendly_name': 'Cover Controller Test Entity Name',
'supported_features': <CoverEntityFeature: 15>,
}),
'context': <ANY>,
'entity_id': 'cover.cover_controller_test_entity_name',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'opening',
})
# ---

View File

@@ -0,0 +1,19 @@
# serializer version: 1
# name: test_fan_entity
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Fan Controller Test Entity Name',
'percentage': 1,
'percentage_step': 12.5,
'preset_mode': None,
'preset_modes': None,
'supported_features': <FanEntityFeature: 49>,
}),
'context': <ANY>,
'entity_id': 'fan.fan_controller_test_entity_name',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---

View File

@@ -0,0 +1,38 @@
# serializer version: 1
# name: test_dimmer_entity
StateSnapshot({
'attributes': ReadOnlyDict({
'brightness': 0,
'color_mode': <ColorMode.BRIGHTNESS: 'brightness'>,
'friendly_name': 'Light Controller Test Entity Name',
'supported_color_modes': list([
<ColorMode.BRIGHTNESS: 'brightness'>,
]),
'supported_features': <LightEntityFeature: 0>,
}),
'context': <ANY>,
'entity_id': 'light.light_controller_test_entity_name',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_light_entity
StateSnapshot({
'attributes': ReadOnlyDict({
'color_mode': <ColorMode.ONOFF: 'onoff'>,
'friendly_name': 'Light Controller Test Entity Name',
'supported_color_modes': list([
<ColorMode.ONOFF: 'onoff'>,
]),
'supported_features': <LightEntityFeature: 0>,
}),
'context': <ANY>,
'entity_id': 'light.light_controller_test_entity_name',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---

View File

@@ -0,0 +1,14 @@
# serializer version: 1
# name: test_switch_entity
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Switch Controller Test Entity Name',
}),
'context': <ANY>,
'entity_id': 'switch.switch_controller_test_entity_name',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---

View File

@@ -0,0 +1,77 @@
"""Test the Zimi cover entity."""
from unittest.mock import MagicMock
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.cover import CoverEntityFeature
from homeassistant.const import (
SERVICE_CLOSE_COVER,
SERVICE_OPEN_COVER,
SERVICE_SET_COVER_POSITION,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import ENTITY_INFO, mock_api_device, setup_platform
async def test_cover_entity(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_api: MagicMock,
snapshot: SnapshotAssertion,
) -> None:
"""Tests cover entity."""
device_name = "Cover Controller"
entity_key = "cover.cover_controller_test_entity_name"
entity_type = Platform.COVER
mock_api.doors = [mock_api_device(device_name=device_name, entity_type=entity_type)]
await setup_platform(hass, entity_type)
entity = entity_registry.entities[entity_key]
assert entity.unique_id == ENTITY_INFO["id"]
assert (
entity.supported_features
== CoverEntityFeature.OPEN
| CoverEntityFeature.CLOSE
| CoverEntityFeature.STOP
| CoverEntityFeature.SET_POSITION
)
state = hass.states.get(entity_key)
assert state == snapshot
services = hass.services.async_services()
assert SERVICE_CLOSE_COVER in services[entity_type]
await hass.services.async_call(
entity_type,
SERVICE_CLOSE_COVER,
{"entity_id": entity_key},
blocking=True,
)
assert mock_api.doors[0].close_door.called
assert SERVICE_OPEN_COVER in services[entity_type]
await hass.services.async_call(
entity_type,
SERVICE_OPEN_COVER,
{"entity_id": entity_key},
blocking=True,
)
assert mock_api.doors[0].open_door.called
assert SERVICE_SET_COVER_POSITION in services[entity_type]
await hass.services.async_call(
entity_type,
SERVICE_SET_COVER_POSITION,
{"entity_id": entity_key, "position": 50},
blocking=True,
)
assert mock_api.doors[0].open_to_percentage.called

View File

@@ -0,0 +1,75 @@
"""Test the Zimi fan entity."""
from unittest.mock import MagicMock
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.fan import FanEntityFeature
from homeassistant.const import SERVICE_TURN_OFF, SERVICE_TURN_ON, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import ENTITY_INFO, mock_api_device, setup_platform
async def test_fan_entity(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_api: MagicMock,
snapshot: SnapshotAssertion,
) -> None:
"""Tests fan entity."""
device_name = "Fan Controller"
entity_key = "fan.fan_controller_test_entity_name"
entity_type = Platform.FAN
mock_api.fans = [mock_api_device(device_name=device_name, entity_type=entity_type)]
await setup_platform(hass, entity_type)
entity = entity_registry.entities[entity_key]
assert entity.unique_id == ENTITY_INFO["id"]
assert (
entity.supported_features
== FanEntityFeature.SET_SPEED
| FanEntityFeature.TURN_OFF
| FanEntityFeature.TURN_ON
)
state = hass.states.get(entity_key)
assert state == snapshot
services = hass.services.async_services()
assert SERVICE_TURN_ON in services[entity_type]
await hass.services.async_call(
entity_type,
SERVICE_TURN_ON,
{"entity_id": entity_key},
blocking=True,
)
assert mock_api.fans[0].turn_on.called
assert SERVICE_TURN_OFF in services[entity_type]
await hass.services.async_call(
entity_type,
SERVICE_TURN_OFF,
{"entity_id": entity_key},
blocking=True,
)
assert mock_api.fans[0].turn_off.called
assert "set_percentage" in services[entity_type]
await hass.services.async_call(
entity_type,
"set_percentage",
{"entity_id": entity_key, "percentage": 50},
blocking=True,
)
assert mock_api.fans[0].set_fanspeed.called

View File

@@ -0,0 +1,119 @@
"""Test the Zimi light entity."""
from unittest.mock import MagicMock
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.light import ColorMode
from homeassistant.const import SERVICE_TURN_OFF, SERVICE_TURN_ON, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import ENTITY_INFO, mock_api_device, setup_platform
async def test_light_entity(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_api: MagicMock,
snapshot: SnapshotAssertion,
) -> None:
"""Tests lights entity."""
device_name = "Light Controller"
entity_key = "light.light_controller_test_entity_name"
entity_type = "light"
mock_api.lights = [
mock_api_device(device_name=device_name, entity_type=entity_type)
]
await setup_platform(hass, Platform.LIGHT)
entity = entity_registry.entities[entity_key]
assert entity.unique_id == ENTITY_INFO["id"]
assert entity.capabilities == {
"supported_color_modes": [ColorMode.ONOFF],
}
state = hass.states.get(entity_key)
assert state == snapshot
services = hass.services.async_services()
assert SERVICE_TURN_ON in services[entity_type]
await hass.services.async_call(
entity_type,
SERVICE_TURN_ON,
{"entity_id": entity_key},
blocking=True,
)
assert mock_api.lights[0].turn_on.called
assert SERVICE_TURN_OFF in services[entity_type]
await hass.services.async_call(
entity_type,
SERVICE_TURN_OFF,
{"entity_id": entity_key},
blocking=True,
)
assert mock_api.lights[0].turn_off.called
async def test_dimmer_entity(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_api: MagicMock,
snapshot: SnapshotAssertion,
) -> None:
"""Tests dimmer entity."""
device_name = "Light Controller"
entity_key = "light.light_controller_test_entity_name"
entity_type = "dimmer"
entity_type_override = "light"
mock_api.lights = [
mock_api_device(device_name=device_name, entity_type=entity_type)
]
await setup_platform(hass, Platform.LIGHT)
entity = entity_registry.entities[entity_key]
assert entity.unique_id == ENTITY_INFO["id"]
assert entity.capabilities == {
"supported_color_modes": [ColorMode.BRIGHTNESS],
}
state = hass.states.get(entity_key)
assert state == snapshot
services = hass.services.async_services()
assert SERVICE_TURN_ON in services[entity_type_override]
await hass.services.async_call(
entity_type_override,
SERVICE_TURN_ON,
{"entity_id": entity_key},
blocking=True,
)
assert mock_api.lights[0].set_brightness.called
assert SERVICE_TURN_OFF in services[entity_type_override]
await hass.services.async_call(
entity_type_override,
SERVICE_TURN_OFF,
{"entity_id": entity_key},
blocking=True,
)
assert mock_api.lights[0].set_brightness.called

View File

@@ -0,0 +1,60 @@
"""Test the Zimi switch entity."""
from unittest.mock import MagicMock
from syrupy.assertion import SnapshotAssertion
from homeassistant.const import SERVICE_TURN_OFF, SERVICE_TURN_ON, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import ENTITY_INFO, mock_api_device, setup_platform
async def test_switch_entity(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_api: MagicMock,
snapshot: SnapshotAssertion,
) -> None:
"""Tests switch entity."""
device_name = "Switch Controller"
entity_key = "switch.switch_controller_test_entity_name"
entity_type = "switch"
mock_api.outlets = [
mock_api_device(device_name=device_name, entity_type=entity_type)
]
await setup_platform(hass, Platform.SWITCH)
entity = entity_registry.entities[entity_key]
assert entity.unique_id == ENTITY_INFO["id"]
state = hass.states.get(entity_key)
assert state == snapshot
services = hass.services.async_services()
assert SERVICE_TURN_ON in services[entity_type]
await hass.services.async_call(
entity_type,
SERVICE_TURN_ON,
{"entity_id": entity_key},
blocking=True,
)
assert mock_api.outlets[0].turn_on.called
assert SERVICE_TURN_OFF in services[entity_type]
await hass.services.async_call(
entity_type,
SERVICE_TURN_OFF,
{"entity_id": entity_key},
blocking=True,
)
assert mock_api.outlets[0].turn_off.called