1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-19 15:00:27 +01:00
Files

242 lines
8.1 KiB
Python

"""Tests for the UniFi Access select platform."""
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