mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 20:27:08 +00:00
Add switchbot cover unit tests (#140265)
* add cover unit tests * Add unit test for SwitchBot cover * fix: use mock_restore_cache to mock the last state * modify unit tests * modify scripts as suggest * improve readability * adjust patch target per review comments * adjust patch target per review comments --------- Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
04f5315ab2
commit
d0b61af7ec
@ -154,7 +154,7 @@ class SwitchBotBlindTiltEntity(SwitchbotEntity, CoverEntity, RestoreEntity):
|
||||
ATTR_CURRENT_TILT_POSITION
|
||||
)
|
||||
self._last_run_success = last_state.attributes.get("last_run_success")
|
||||
if (_tilt := self._attr_current_cover_position) is not None:
|
||||
if (_tilt := self._attr_current_cover_tilt_position) is not None:
|
||||
self._attr_is_closed = (_tilt < self.CLOSED_DOWN_THRESHOLD) or (
|
||||
_tilt > self.CLOSED_UP_THRESHOLD
|
||||
)
|
||||
|
@ -319,3 +319,70 @@ WOHUB2_SERVICE_INFO = BluetoothServiceInfoBleak(
|
||||
connectable=True,
|
||||
tx_power=-127,
|
||||
)
|
||||
|
||||
|
||||
WOCURTAIN3_SERVICE_INFO = BluetoothServiceInfoBleak(
|
||||
name="WoCurtain3",
|
||||
address="AA:BB:CC:DD:EE:FF",
|
||||
manufacturer_data={2409: b"\xcf;Zwu\x0c\x19\x0b\x00\x11D\x006"},
|
||||
service_data={"00000d00-0000-1000-8000-00805f9b34fb": b"{\xc06\x00\x11D"},
|
||||
service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
|
||||
rssi=-60,
|
||||
source="local",
|
||||
advertisement=generate_advertisement_data(
|
||||
local_name="WoCurtain3",
|
||||
manufacturer_data={2409: b"\xcf;Zwu\x0c\x19\x0b\x00\x11D\x006"},
|
||||
service_data={"00000d00-0000-1000-8000-00805f9b34fb": b"{\xc06\x00\x11D"},
|
||||
service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
|
||||
),
|
||||
device=generate_ble_device("AA:BB:CC:DD:EE:FF", "WoCurtain3"),
|
||||
time=0,
|
||||
connectable=True,
|
||||
tx_power=-127,
|
||||
)
|
||||
|
||||
|
||||
WOBLINDTILT_SERVICE_INFO = BluetoothServiceInfoBleak(
|
||||
name="WoBlindTilt",
|
||||
address="AA:BB:CC:DD:EE:FF",
|
||||
manufacturer_data={2409: b"\xfbgA`\x98\xe8\x1d%2\x11\x84"},
|
||||
service_data={"00000d00-0000-1000-8000-00805f9b34fb": b"x\x00*"},
|
||||
service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
|
||||
rssi=-60,
|
||||
source="local",
|
||||
advertisement=generate_advertisement_data(
|
||||
local_name="WoBlindTilt",
|
||||
manufacturer_data={2409: b"\xfbgA`\x98\xe8\x1d%2\x11\x84"},
|
||||
service_data={"00000d00-0000-1000-8000-00805f9b34fb": b"x\x00*"},
|
||||
service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
|
||||
),
|
||||
device=generate_ble_device("AA:BB:CC:DD:EE:FF", "WoBlindTilt"),
|
||||
time=0,
|
||||
connectable=True,
|
||||
tx_power=-127,
|
||||
)
|
||||
|
||||
|
||||
def make_advertisement(
|
||||
address: str, manufacturer_data: bytes, service_data: bytes
|
||||
) -> BluetoothServiceInfoBleak:
|
||||
"""Make a dummy advertisement."""
|
||||
return BluetoothServiceInfoBleak(
|
||||
name="Test Device",
|
||||
address=address,
|
||||
manufacturer_data={2409: manufacturer_data},
|
||||
service_data={"00000d00-0000-1000-8000-00805f9b34fb": service_data},
|
||||
service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
|
||||
rssi=-60,
|
||||
source="local",
|
||||
advertisement=generate_advertisement_data(
|
||||
local_name="Test Device",
|
||||
manufacturer_data={2409: manufacturer_data},
|
||||
service_data={"00000d00-0000-1000-8000-00805f9b34fb": service_data},
|
||||
service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
|
||||
),
|
||||
device=generate_ble_device(address, "Test Device"),
|
||||
time=0,
|
||||
connectable=True,
|
||||
tx_power=-127,
|
||||
)
|
||||
|
@ -2,7 +2,26 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.switchbot.const import DOMAIN
|
||||
from homeassistant.const import CONF_ADDRESS, CONF_NAME, CONF_SENSOR_TYPE
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_bluetooth(enable_bluetooth: None) -> None:
|
||||
"""Auto mock bluetooth."""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_entry_factory():
|
||||
"""Fixture to create a MockConfigEntry with a customizable sensor type."""
|
||||
return lambda sensor_type="curtain": MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
CONF_ADDRESS: "aa:bb:cc:dd:ee:ff",
|
||||
CONF_NAME: "test-name",
|
||||
CONF_SENSOR_TYPE: sensor_type,
|
||||
},
|
||||
unique_id="aabbccddeeff",
|
||||
)
|
||||
|
327
tests/components/switchbot/test_cover.py
Normal file
327
tests/components/switchbot/test_cover.py
Normal file
@ -0,0 +1,327 @@
|
||||
"""Test the switchbot covers."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
ATTR_CURRENT_POSITION,
|
||||
ATTR_CURRENT_TILT_POSITION,
|
||||
ATTR_POSITION,
|
||||
ATTR_TILT_POSITION,
|
||||
DOMAIN as COVER_DOMAIN,
|
||||
CoverState,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
SERVICE_CLOSE_COVER,
|
||||
SERVICE_CLOSE_COVER_TILT,
|
||||
SERVICE_OPEN_COVER,
|
||||
SERVICE_OPEN_COVER_TILT,
|
||||
SERVICE_SET_COVER_POSITION,
|
||||
SERVICE_SET_COVER_TILT_POSITION,
|
||||
SERVICE_STOP_COVER,
|
||||
SERVICE_STOP_COVER_TILT,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, State
|
||||
|
||||
from . import WOBLINDTILT_SERVICE_INFO, WOCURTAIN3_SERVICE_INFO, make_advertisement
|
||||
|
||||
from tests.common import MockConfigEntry, mock_restore_cache
|
||||
from tests.components.bluetooth import inject_bluetooth_service_info
|
||||
|
||||
|
||||
async def test_curtain3_setup(
|
||||
hass: HomeAssistant, mock_entry_factory: Callable[[str], MockConfigEntry]
|
||||
) -> None:
|
||||
"""Test setting up the Curtain3."""
|
||||
inject_bluetooth_service_info(hass, WOCURTAIN3_SERVICE_INFO)
|
||||
|
||||
entry = mock_entry_factory(sensor_type="curtain")
|
||||
|
||||
entity_id = "cover.test_name"
|
||||
mock_restore_cache(
|
||||
hass,
|
||||
[
|
||||
State(
|
||||
entity_id,
|
||||
CoverState.OPEN,
|
||||
{ATTR_CURRENT_POSITION: 50},
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == CoverState.OPEN
|
||||
assert state.attributes[ATTR_CURRENT_POSITION] == 50
|
||||
|
||||
|
||||
async def test_curtain3_controlling(
|
||||
hass: HomeAssistant, mock_entry_factory: Callable[[str], MockConfigEntry]
|
||||
) -> None:
|
||||
"""Test Curtain3 controlling."""
|
||||
inject_bluetooth_service_info(hass, WOCURTAIN3_SERVICE_INFO)
|
||||
|
||||
entry = mock_entry_factory(sensor_type="curtain")
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotCurtain.open",
|
||||
new=AsyncMock(return_value=True),
|
||||
) as mock_open,
|
||||
patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotCurtain.close",
|
||||
new=AsyncMock(return_value=True),
|
||||
) as mock_close,
|
||||
patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotCurtain.stop",
|
||||
new=AsyncMock(return_value=True),
|
||||
) as mock_stop,
|
||||
patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotCurtain.set_position",
|
||||
new=AsyncMock(return_value=True),
|
||||
) as mock_set_position,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "cover.test_name"
|
||||
address = "AA:BB:CC:DD:EE:FF"
|
||||
service_data = b"{\xc06\x00\x11D"
|
||||
|
||||
# Test open
|
||||
manufacturer_data = b"\xcf;Zwu\x0c\x19\x0b\x05\x11D\x006"
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
inject_bluetooth_service_info(
|
||||
hass, make_advertisement(address, manufacturer_data, service_data)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_open.assert_awaited_once()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == CoverState.OPEN
|
||||
assert state.attributes[ATTR_CURRENT_POSITION] == 95
|
||||
|
||||
# Test close
|
||||
manufacturer_data = b"\xcf;Zwu\x0c\x19\x0b\x58\x11D\x006"
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_CLOSE_COVER,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
inject_bluetooth_service_info(
|
||||
hass, make_advertisement(address, manufacturer_data, service_data)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_close.assert_awaited_once()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == CoverState.CLOSED
|
||||
assert state.attributes[ATTR_CURRENT_POSITION] == 12
|
||||
|
||||
# Test stop
|
||||
manufacturer_data = b"\xcf;Zwu\x0c\x19\x0b\x3c\x11D\x006"
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN, SERVICE_STOP_COVER, {ATTR_ENTITY_ID: entity_id}, blocking=True
|
||||
)
|
||||
inject_bluetooth_service_info(
|
||||
hass, make_advertisement(address, manufacturer_data, service_data)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_stop.assert_awaited_once()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == CoverState.OPEN
|
||||
assert state.attributes[ATTR_CURRENT_POSITION] == 40
|
||||
|
||||
# Test set position
|
||||
manufacturer_data = b"\xcf;Zwu\x0c\x19\x0b(\x11D\x006"
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_SET_COVER_POSITION,
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_POSITION: 50},
|
||||
blocking=True,
|
||||
)
|
||||
inject_bluetooth_service_info(
|
||||
hass, make_advertisement(address, manufacturer_data, service_data)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_set_position.assert_awaited_once()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == CoverState.OPEN
|
||||
assert state.attributes[ATTR_CURRENT_POSITION] == 60
|
||||
|
||||
|
||||
async def test_blindtilt_setup(
|
||||
hass: HomeAssistant, mock_entry_factory: Callable[[str], MockConfigEntry]
|
||||
) -> None:
|
||||
"""Test setting up the blindtilt."""
|
||||
inject_bluetooth_service_info(hass, WOBLINDTILT_SERVICE_INFO)
|
||||
|
||||
entry = mock_entry_factory(sensor_type="blind_tilt")
|
||||
entity_id = "cover.test_name"
|
||||
mock_restore_cache(
|
||||
hass,
|
||||
[
|
||||
State(
|
||||
entity_id,
|
||||
CoverState.OPEN,
|
||||
{ATTR_CURRENT_TILT_POSITION: 40},
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
entry.add_to_hass(hass)
|
||||
with patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotBlindTilt.update",
|
||||
new=AsyncMock(return_value=True),
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == CoverState.OPEN
|
||||
assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 40
|
||||
|
||||
|
||||
async def test_blindtilt_controlling(
|
||||
hass: HomeAssistant, mock_entry_factory: Callable[[str], MockConfigEntry]
|
||||
) -> None:
|
||||
"""Test blindtilt controlling."""
|
||||
inject_bluetooth_service_info(hass, WOBLINDTILT_SERVICE_INFO)
|
||||
|
||||
entry = mock_entry_factory(sensor_type="blind_tilt")
|
||||
entry.add_to_hass(hass)
|
||||
info = {
|
||||
"motionDirection": {
|
||||
"opening": False,
|
||||
"closing": False,
|
||||
"up": False,
|
||||
"down": False,
|
||||
},
|
||||
}
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotBlindTilt.get_basic_info",
|
||||
new=AsyncMock(return_value=info),
|
||||
),
|
||||
patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotBlindTilt.open",
|
||||
new=AsyncMock(return_value=True),
|
||||
) as mock_open,
|
||||
patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotBlindTilt.close",
|
||||
new=AsyncMock(return_value=True),
|
||||
) as mock_close,
|
||||
patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotBlindTilt.stop",
|
||||
new=AsyncMock(return_value=True),
|
||||
) as mock_stop,
|
||||
patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotBlindTilt.set_position",
|
||||
new=AsyncMock(return_value=True),
|
||||
) as mock_set_position,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "cover.test_name"
|
||||
address = "AA:BB:CC:DD:EE:FF"
|
||||
service_data = b"x\x00*"
|
||||
|
||||
# Test open
|
||||
manufacturer_data = b"\xfbgA`\x98\xe8\x1d%F\x12\x85"
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_OPEN_COVER_TILT,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
with patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotBlindTilt.get_basic_info",
|
||||
return_value=info,
|
||||
):
|
||||
inject_bluetooth_service_info(
|
||||
hass, make_advertisement(address, manufacturer_data, service_data)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_open.assert_awaited_once()
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == CoverState.OPEN
|
||||
assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 70
|
||||
|
||||
# Test close
|
||||
manufacturer_data = b"\xfbgA`\x98\xe8\x1d%\x0f\x12\x85"
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_CLOSE_COVER_TILT,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
with patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotBlindTilt.get_basic_info",
|
||||
return_value=info,
|
||||
):
|
||||
inject_bluetooth_service_info(
|
||||
hass, make_advertisement(address, manufacturer_data, service_data)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_close.assert_awaited_once()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == CoverState.CLOSED
|
||||
assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 15
|
||||
|
||||
# Test stop
|
||||
manufacturer_data = b"\xfbgA`\x98\xe8\x1d%\n\x12\x85"
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_STOP_COVER_TILT,
|
||||
{ATTR_ENTITY_ID: entity_id},
|
||||
blocking=True,
|
||||
)
|
||||
with patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotBlindTilt.get_basic_info",
|
||||
return_value=info,
|
||||
):
|
||||
inject_bluetooth_service_info(
|
||||
hass, make_advertisement(address, manufacturer_data, service_data)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_stop.assert_awaited_once()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == CoverState.CLOSED
|
||||
assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 10
|
||||
|
||||
# Test set position
|
||||
manufacturer_data = b"\xfbgA`\x98\xe8\x1d%2\x12\x85"
|
||||
await hass.services.async_call(
|
||||
COVER_DOMAIN,
|
||||
SERVICE_SET_COVER_TILT_POSITION,
|
||||
{ATTR_ENTITY_ID: entity_id, ATTR_TILT_POSITION: 50},
|
||||
blocking=True,
|
||||
)
|
||||
with patch(
|
||||
"homeassistant.components.switchbot.cover.switchbot.SwitchbotBlindTilt.get_basic_info",
|
||||
return_value=info,
|
||||
):
|
||||
inject_bluetooth_service_info(
|
||||
hass, make_advertisement(address, manufacturer_data, service_data)
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
mock_set_position.assert_awaited_once()
|
||||
state = hass.states.get(entity_id)
|
||||
assert state.state == CoverState.OPEN
|
||||
assert state.attributes[ATTR_CURRENT_TILT_POSITION] == 50
|
Loading…
x
Reference in New Issue
Block a user