From e49c2fde14abd6dccf69b2c259f2a71a4f89289f Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 19 Jun 2023 13:24:36 +0200 Subject: [PATCH] Add tests for kitchen_sink lock platform (#94723) --- homeassistant/components/kitchen_sink/lock.py | 14 ++- .../kitchen_sink/snapshots/test_lock.ambr | 49 ++++++++ tests/components/kitchen_sink/test_lock.py | 105 ++++++++++++++++++ 3 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 tests/components/kitchen_sink/snapshots/test_lock.ambr create mode 100644 tests/components/kitchen_sink/test_lock.py diff --git a/homeassistant/components/kitchen_sink/lock.py b/homeassistant/components/kitchen_sink/lock.py index 343190acb631..b25941cf1a3e 100644 --- a/homeassistant/components/kitchen_sink/lock.py +++ b/homeassistant/components/kitchen_sink/lock.py @@ -5,7 +5,7 @@ from typing import Any from homeassistant.components.lock import LockEntity, LockEntityFeature from homeassistant.config_entries import ConfigEntry -from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED, STATE_UNLOCKING +from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType @@ -17,7 +17,7 @@ async def async_setup_platform( async_add_entities: AddEntitiesCallback, discovery_info: DiscoveryInfoType | None = None, ) -> None: - """Set up the Demo sensors.""" + """Set up the Demo locks.""" async_add_entities( [ DemoLock( @@ -70,6 +70,8 @@ class DemoLock(LockEntity): self._attr_unique_id = unique_id self._attr_supported_features = features self._state = state + self._attr_is_locking = False + self._attr_is_unlocking = False @property def is_locked(self) -> bool: @@ -78,12 +80,18 @@ class DemoLock(LockEntity): async def async_lock(self, **kwargs: Any) -> None: """Lock the device.""" + self._attr_is_locking = True + self.async_write_ha_state() + self._attr_is_locking = False self._state = STATE_LOCKED self.async_write_ha_state() async def async_unlock(self, **kwargs: Any) -> None: """Unlock the device.""" - self._state = STATE_UNLOCKING + self._attr_is_unlocking = True + self.async_write_ha_state() + self._attr_is_unlocking = False + self._state = STATE_UNLOCKED self.async_write_ha_state() async def async_open(self, **kwargs: Any) -> None: diff --git a/tests/components/kitchen_sink/snapshots/test_lock.ambr b/tests/components/kitchen_sink/snapshots/test_lock.ambr new file mode 100644 index 000000000000..9303401bdd56 --- /dev/null +++ b/tests/components/kitchen_sink/snapshots/test_lock.ambr @@ -0,0 +1,49 @@ +# serializer version: 1 +# name: test_states + set({ + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Another basic lock', + 'supported_features': , + }), + 'context': , + 'entity_id': 'lock.another_basic_lock', + 'last_changed': , + 'last_updated': , + 'state': 'unlocked', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Another openable lock', + 'supported_features': , + }), + 'context': , + 'entity_id': 'lock.another_openable_lock', + 'last_changed': , + 'last_updated': , + 'state': 'unlocked', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Basic lock', + 'supported_features': , + }), + 'context': , + 'entity_id': 'lock.basic_lock', + 'last_changed': , + 'last_updated': , + 'state': 'locked', + }), + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Openable lock', + 'supported_features': , + }), + 'context': , + 'entity_id': 'lock.openable_lock', + 'last_changed': , + 'last_updated': , + 'state': 'locked', + }), + }) +# --- diff --git a/tests/components/kitchen_sink/test_lock.py b/tests/components/kitchen_sink/test_lock.py new file mode 100644 index 000000000000..a74c9a19a23f --- /dev/null +++ b/tests/components/kitchen_sink/test_lock.py @@ -0,0 +1,105 @@ +"""The tests for the kitchen_sink lock platform.""" +from unittest.mock import patch + +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.kitchen_sink import DOMAIN +from homeassistant.components.lock import ( + DOMAIN as LOCK_DOMAIN, + SERVICE_LOCK, + SERVICE_OPEN, + SERVICE_UNLOCK, + STATE_LOCKED, + STATE_LOCKING, + STATE_UNLOCKED, + STATE_UNLOCKING, +) +from homeassistant.const import ATTR_ENTITY_ID, EVENT_STATE_CHANGED, Platform +from homeassistant.core import HomeAssistant +from homeassistant.setup import async_setup_component + +from tests.common import async_capture_events, async_mock_service + +LOCKED_LOCK = "lock.basic_lock" +OPENABLE_LOCK = "lock.openable_lock" +UNLOCKED_LOCK = "lock.another_basic_lock" + + +@pytest.fixture +async def lock_only() -> None: + """Enable only the lock platform.""" + with patch( + "homeassistant.components.kitchen_sink.COMPONENTS_WITH_DEMO_PLATFORM", + [Platform.LOCK], + ): + yield + + +@pytest.fixture(autouse=True) +async def setup_comp(hass: HomeAssistant, lock_only): + """Set up demo component.""" + assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}}) + await hass.async_block_till_done() + + +async def test_states(hass: HomeAssistant, snapshot: SnapshotAssertion) -> None: + """Test the expected lock entities are added.""" + states = hass.states.async_all() + assert set(states) == snapshot + + +async def test_locking(hass: HomeAssistant) -> None: + """Test the locking of a lock.""" + state = hass.states.get(UNLOCKED_LOCK) + assert state.state == STATE_UNLOCKED + await hass.async_block_till_done() + + state_changes = async_capture_events(hass, EVENT_STATE_CHANGED) + await hass.services.async_call( + LOCK_DOMAIN, SERVICE_LOCK, {ATTR_ENTITY_ID: UNLOCKED_LOCK}, blocking=False + ) + await hass.async_block_till_done() + + assert state_changes[0].data["entity_id"] == UNLOCKED_LOCK + assert state_changes[0].data["new_state"].state == STATE_LOCKING + + assert state_changes[1].data["entity_id"] == UNLOCKED_LOCK + assert state_changes[1].data["new_state"].state == STATE_LOCKED + + +async def test_unlocking(hass: HomeAssistant) -> None: + """Test the unlocking of a lock.""" + state = hass.states.get(LOCKED_LOCK) + assert state.state == STATE_LOCKED + await hass.async_block_till_done() + + state_changes = async_capture_events(hass, EVENT_STATE_CHANGED) + await hass.services.async_call( + LOCK_DOMAIN, SERVICE_UNLOCK, {ATTR_ENTITY_ID: LOCKED_LOCK}, blocking=False + ) + await hass.async_block_till_done() + + assert state_changes[0].data["entity_id"] == LOCKED_LOCK + assert state_changes[0].data["new_state"].state == STATE_UNLOCKING + + assert state_changes[1].data["entity_id"] == LOCKED_LOCK + assert state_changes[1].data["new_state"].state == STATE_UNLOCKED + + +async def test_opening_mocked(hass: HomeAssistant) -> None: + """Test the opening of a lock.""" + calls = async_mock_service(hass, LOCK_DOMAIN, SERVICE_OPEN) + await hass.services.async_call( + LOCK_DOMAIN, SERVICE_OPEN, {ATTR_ENTITY_ID: OPENABLE_LOCK}, blocking=True + ) + assert len(calls) == 1 + + +async def test_opening(hass: HomeAssistant) -> None: + """Test the opening of a lock.""" + await hass.services.async_call( + LOCK_DOMAIN, SERVICE_OPEN, {ATTR_ENTITY_ID: OPENABLE_LOCK}, blocking=True + ) + state = hass.states.get(OPENABLE_LOCK) + assert state.state == STATE_UNLOCKED