mirror of
https://github.com/home-assistant/core.git
synced 2026-05-08 17:49:37 +01:00
96891228c9
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: RaHehl <rahehl@users.noreply.github.com>
244 lines
8.2 KiB
Python
244 lines
8.2 KiB
Python
"""Tests for the UniFi Access select platform."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Generator
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
import pytest
|
|
from syrupy.assertion import SnapshotAssertion
|
|
from unifi_access_api import (
|
|
ApiConnectionError,
|
|
ApiNotFoundError,
|
|
DoorLockRule,
|
|
DoorLockRuleStatus,
|
|
DoorLockRuleType,
|
|
UnifiAccessError,
|
|
)
|
|
|
|
from homeassistant.components.unifi_access.const import DOMAIN
|
|
from homeassistant.const import STATE_UNKNOWN, Platform
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import HomeAssistantError
|
|
from homeassistant.helpers import entity_registry as er
|
|
|
|
from . import setup_integration
|
|
|
|
from tests.common import MockConfigEntry, snapshot_platform
|
|
|
|
FRONT_DOOR_LOCK_RULE_SELECT_ENTITY = "select.front_door_lock_rule"
|
|
BACK_DOOR_LOCK_RULE_SELECT_ENTITY = "select.back_door_lock_rule"
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def only_select_platform() -> Generator[None]:
|
|
"""Limit setup to the select platform for select tests."""
|
|
with patch("homeassistant.components.unifi_access.PLATFORMS", [Platform.SELECT]):
|
|
yield
|
|
|
|
|
|
async def test_select_entities(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
entity_registry: er.EntityRegistry,
|
|
snapshot: SnapshotAssertion,
|
|
) -> None:
|
|
"""Test select entities are created with expected state."""
|
|
mock_client.get_door_lock_rule = AsyncMock(
|
|
return_value=DoorLockRuleStatus(
|
|
type=DoorLockRuleType.KEEP_LOCK, ended_time=1700000000
|
|
)
|
|
)
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
|
|
|
|
|
async def test_select_current_option_no_rule(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
) -> None:
|
|
"""Test select reflects unknown state when no lock rule is active."""
|
|
mock_client.get_door_lock_rule = AsyncMock(return_value=DoorLockRuleStatus())
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
state = hass.states.get(FRONT_DOOR_LOCK_RULE_SELECT_ENTITY)
|
|
assert state is not None
|
|
assert state.state == STATE_UNKNOWN
|
|
|
|
|
|
async def test_select_current_option_active_rule(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
) -> None:
|
|
"""Test select reflects the current lock rule type."""
|
|
mock_client.get_door_lock_rule = AsyncMock(
|
|
return_value=DoorLockRuleStatus(type=DoorLockRuleType.KEEP_LOCK)
|
|
)
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
state = hass.states.get(FRONT_DOOR_LOCK_RULE_SELECT_ENTITY)
|
|
assert state is not None
|
|
assert state.state == "keep_lock"
|
|
|
|
|
|
async def test_select_option_calls_api(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
) -> None:
|
|
"""Test selecting an option calls set_door_lock_rule on the client."""
|
|
mock_client.get_door_lock_rule = AsyncMock(return_value=DoorLockRuleStatus())
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await hass.services.async_call(
|
|
Platform.SELECT,
|
|
"select_option",
|
|
{"entity_id": FRONT_DOOR_LOCK_RULE_SELECT_ENTITY, "option": "keep_lock"},
|
|
blocking=True,
|
|
)
|
|
|
|
mock_client.set_door_lock_rule.assert_awaited_once_with(
|
|
"door-001", DoorLockRule(type=DoorLockRuleType.KEEP_LOCK, interval=10)
|
|
)
|
|
|
|
|
|
async def test_select_schedule_option_does_not_call_api(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
) -> None:
|
|
"""Test selecting schedule does not call the API."""
|
|
mock_client.get_door_lock_rule = AsyncMock(
|
|
return_value=DoorLockRuleStatus(type=DoorLockRuleType.SCHEDULE)
|
|
)
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
await hass.services.async_call(
|
|
Platform.SELECT,
|
|
"select_option",
|
|
{"entity_id": FRONT_DOOR_LOCK_RULE_SELECT_ENTITY, "option": "schedule"},
|
|
blocking=True,
|
|
)
|
|
|
|
mock_client.set_door_lock_rule.assert_not_awaited()
|
|
|
|
|
|
async def test_select_not_created_when_lock_rules_unsupported(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
) -> None:
|
|
"""Test that select entities are not created when lock rules are unsupported."""
|
|
mock_client.get_door_lock_rule = AsyncMock(side_effect=ApiNotFoundError())
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
assert hass.states.get(FRONT_DOOR_LOCK_RULE_SELECT_ENTITY) is None
|
|
|
|
|
|
async def test_select_lock_early_option_shown_for_schedule_rule(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
) -> None:
|
|
"""Test lock_early appears in options when a schedule rule is active."""
|
|
mock_client.get_door_lock_rule = AsyncMock(
|
|
return_value=DoorLockRuleStatus(type=DoorLockRuleType.SCHEDULE)
|
|
)
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
state = hass.states.get(FRONT_DOOR_LOCK_RULE_SELECT_ENTITY)
|
|
assert state is not None
|
|
assert state.state == "schedule"
|
|
assert "schedule" in state.attributes["options"]
|
|
assert "lock_early" in state.attributes["options"]
|
|
|
|
|
|
async def test_select_lock_early_option_hidden_for_non_schedule_rule(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
) -> None:
|
|
"""Test lock_early is absent from options when no schedule rule is active."""
|
|
mock_client.get_door_lock_rule = AsyncMock(
|
|
return_value=DoorLockRuleStatus(type=DoorLockRuleType.KEEP_LOCK)
|
|
)
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
state = hass.states.get(FRONT_DOOR_LOCK_RULE_SELECT_ENTITY)
|
|
assert state is not None
|
|
assert "lock_early" not in state.attributes["options"]
|
|
|
|
|
|
async def test_select_created_for_supported_doors_only(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
) -> None:
|
|
"""Test select entities are created only for doors that support lock rules."""
|
|
|
|
async def mock_get_door_lock_rule(door_id: str) -> DoorLockRuleStatus:
|
|
if door_id == "door-001":
|
|
return DoorLockRuleStatus(
|
|
type=DoorLockRuleType.KEEP_LOCK, ended_time=1700000000
|
|
)
|
|
raise ApiNotFoundError
|
|
|
|
mock_client.get_door_lock_rule = AsyncMock(side_effect=mock_get_door_lock_rule)
|
|
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
assert hass.states.get(FRONT_DOOR_LOCK_RULE_SELECT_ENTITY) is not None
|
|
assert hass.states.get(BACK_DOOR_LOCK_RULE_SELECT_ENTITY) is None
|
|
|
|
|
|
async def test_select_placeholder_created_for_transient_error_doors(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
) -> None:
|
|
"""Test select placeholders are created for doors with transient fetch errors."""
|
|
|
|
async def mock_get_door_lock_rule(door_id: str) -> DoorLockRuleStatus:
|
|
if door_id == "door-001":
|
|
raise ApiConnectionError("Connection failed")
|
|
raise ApiNotFoundError
|
|
|
|
mock_client.get_door_lock_rule = AsyncMock(side_effect=mock_get_door_lock_rule)
|
|
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
assert hass.states.get(FRONT_DOOR_LOCK_RULE_SELECT_ENTITY) is not None
|
|
assert hass.states.get(FRONT_DOOR_LOCK_RULE_SELECT_ENTITY).state == STATE_UNKNOWN
|
|
assert hass.states.get(BACK_DOOR_LOCK_RULE_SELECT_ENTITY) is None
|
|
|
|
|
|
async def test_select_option_raises_on_api_error(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_client: MagicMock,
|
|
) -> None:
|
|
"""Test HomeAssistantError is raised when set_door_lock_rule fails."""
|
|
mock_client.get_door_lock_rule = AsyncMock(return_value=DoorLockRuleStatus())
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
mock_client.set_door_lock_rule = AsyncMock(
|
|
side_effect=UnifiAccessError("API error")
|
|
)
|
|
|
|
with pytest.raises(HomeAssistantError) as exc_info:
|
|
await hass.services.async_call(
|
|
Platform.SELECT,
|
|
"select_option",
|
|
{
|
|
"entity_id": FRONT_DOOR_LOCK_RULE_SELECT_ENTITY,
|
|
"option": "keep_lock",
|
|
},
|
|
blocking=True,
|
|
)
|
|
assert exc_info.value.translation_key == "lock_rule_failed"
|
|
assert exc_info.value.translation_domain == DOMAIN
|