mirror of
https://github.com/home-assistant/core.git
synced 2026-02-04 22:35:58 +01:00
251 lines
8.2 KiB
Python
251 lines
8.2 KiB
Python
"""Test the switchbot services."""
|
|
|
|
from collections.abc import Callable
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
import pytest
|
|
|
|
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
|
|
from homeassistant.components.switchbot.const import DOMAIN
|
|
from homeassistant.components.switchbot.services import (
|
|
SERVICE_ADD_PASSWORD,
|
|
async_setup_services,
|
|
)
|
|
from homeassistant.const import ATTR_DEVICE_ID
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import ServiceValidationError
|
|
from homeassistant.helpers import device_registry as dr
|
|
|
|
from . import (
|
|
KEYPAD_VISION_INFO,
|
|
KEYPAD_VISION_PRO_INFO,
|
|
SMART_THERMOSTAT_RADIATOR_SERVICE_INFO,
|
|
)
|
|
|
|
from tests.common import MockConfigEntry
|
|
from tests.components.bluetooth import inject_bluetooth_service_info
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("ble_service_info", "sensor_type"),
|
|
[
|
|
(KEYPAD_VISION_INFO, "keypad_vision"),
|
|
(KEYPAD_VISION_PRO_INFO, "keypad_vision_pro"),
|
|
],
|
|
)
|
|
async def test_add_password_service(
|
|
hass: HomeAssistant,
|
|
mock_entry_encrypted_factory: Callable[[str], MockConfigEntry],
|
|
ble_service_info: BluetoothServiceInfoBleak,
|
|
sensor_type: str,
|
|
device_registry: dr.DeviceRegistry,
|
|
) -> None:
|
|
"""Test the add_password service."""
|
|
inject_bluetooth_service_info(hass, ble_service_info)
|
|
|
|
entry = mock_entry_encrypted_factory(sensor_type=sensor_type)
|
|
entry.add_to_hass(hass)
|
|
|
|
mocked_instance = AsyncMock(return_value=True)
|
|
with patch.multiple(
|
|
"homeassistant.components.switchbot.switchbot.SwitchbotKeypadVision",
|
|
update=AsyncMock(return_value=None),
|
|
add_password=mocked_instance,
|
|
):
|
|
await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
device_entry = dr.async_entries_for_config_entry(
|
|
device_registry, entry.entry_id
|
|
)[0]
|
|
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_ADD_PASSWORD,
|
|
{
|
|
ATTR_DEVICE_ID: device_entry.id,
|
|
"password": "123456",
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
mocked_instance.assert_called_once_with("123456")
|
|
|
|
|
|
async def test_device_not_found(
|
|
hass: HomeAssistant,
|
|
mock_entry_encrypted_factory: Callable[[str], MockConfigEntry],
|
|
) -> None:
|
|
"""Test the add_password service with non-existent device."""
|
|
inject_bluetooth_service_info(hass, KEYPAD_VISION_INFO)
|
|
|
|
entry = mock_entry_encrypted_factory(sensor_type="keypad_vision")
|
|
entry.add_to_hass(hass)
|
|
|
|
with patch.multiple(
|
|
"homeassistant.components.switchbot.switchbot.SwitchbotKeypadVision",
|
|
update=AsyncMock(return_value=None),
|
|
):
|
|
await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
with pytest.raises(ServiceValidationError) as err:
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_ADD_PASSWORD,
|
|
{
|
|
ATTR_DEVICE_ID: "nonexistent_device",
|
|
"password": "123456",
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
assert err.value.translation_domain == DOMAIN
|
|
assert err.value.translation_key == "invalid_device_id"
|
|
assert err.value.translation_placeholders == {"device_id": "nonexistent_device"}
|
|
|
|
|
|
async def test_device_not_belonging(
|
|
hass: HomeAssistant,
|
|
mock_entry_encrypted_factory: Callable[[str], MockConfigEntry],
|
|
device_registry: dr.DeviceRegistry,
|
|
) -> None:
|
|
"""Test service errors when device belongs to a different integration."""
|
|
inject_bluetooth_service_info(hass, KEYPAD_VISION_INFO)
|
|
|
|
entry = mock_entry_encrypted_factory(sensor_type="keypad_vision")
|
|
entry.add_to_hass(hass)
|
|
|
|
with patch.multiple(
|
|
"homeassistant.components.switchbot.switchbot.SwitchbotKeypadVision",
|
|
update=AsyncMock(return_value=None),
|
|
):
|
|
await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
other_entry = MockConfigEntry(domain="not_switchbot", data={}, title="Other")
|
|
other_entry.add_to_hass(hass)
|
|
|
|
device_entry = device_registry.async_get_or_create(
|
|
config_entry_id=other_entry.entry_id,
|
|
identifiers={("not_switchbot", "other_unique_id")},
|
|
name="Other device",
|
|
)
|
|
|
|
with pytest.raises(ServiceValidationError) as err:
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_ADD_PASSWORD,
|
|
{
|
|
ATTR_DEVICE_ID: device_entry.id,
|
|
"password": "123456",
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
assert err.value.translation_domain == DOMAIN
|
|
assert err.value.translation_key == "device_not_belonging"
|
|
assert err.value.translation_placeholders == {"device_id": device_entry.id}
|
|
|
|
|
|
async def test_device_entry_not_loaded(
|
|
hass: HomeAssistant,
|
|
mock_entry_encrypted_factory: Callable[[str], MockConfigEntry],
|
|
device_registry: dr.DeviceRegistry,
|
|
) -> None:
|
|
"""Test service errors when the config entry is not loaded."""
|
|
inject_bluetooth_service_info(hass, KEYPAD_VISION_INFO)
|
|
|
|
entry = mock_entry_encrypted_factory(sensor_type="keypad_vision")
|
|
entry.add_to_hass(hass)
|
|
|
|
with patch.multiple(
|
|
"homeassistant.components.switchbot.switchbot.SwitchbotKeypadVision",
|
|
update=AsyncMock(return_value=None),
|
|
):
|
|
await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
second_entry = mock_entry_encrypted_factory(sensor_type="keypad_vision")
|
|
second_entry.add_to_hass(hass)
|
|
|
|
device_entry = device_registry.async_get_or_create(
|
|
config_entry_id=second_entry.entry_id,
|
|
identifiers={(DOMAIN, "not_loaded_unique_id")},
|
|
name="Not loaded device",
|
|
)
|
|
|
|
with pytest.raises(ServiceValidationError) as err:
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_ADD_PASSWORD,
|
|
{
|
|
ATTR_DEVICE_ID: device_entry.id,
|
|
"password": "123456",
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
assert err.value.translation_domain == DOMAIN
|
|
assert err.value.translation_key == "device_entry_not_loaded"
|
|
assert err.value.translation_placeholders == {"device_id": device_entry.id}
|
|
|
|
|
|
async def test_service_unsupported_device(
|
|
hass: HomeAssistant,
|
|
mock_entry_encrypted_factory: Callable[[str], MockConfigEntry],
|
|
device_registry: dr.DeviceRegistry,
|
|
) -> None:
|
|
"""Test service errors when the device does not support the service."""
|
|
inject_bluetooth_service_info(hass, SMART_THERMOSTAT_RADIATOR_SERVICE_INFO)
|
|
|
|
entry = mock_entry_encrypted_factory(sensor_type="smart_thermostat_radiator")
|
|
entry.add_to_hass(hass)
|
|
|
|
with patch.multiple(
|
|
"homeassistant.components.switchbot.switchbot.SwitchbotSmartThermostatRadiator",
|
|
update=AsyncMock(return_value=None),
|
|
):
|
|
await hass.config_entries.async_setup(entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
device_entry = dr.async_entries_for_config_entry(device_registry, entry.entry_id)[0]
|
|
|
|
with pytest.raises(ServiceValidationError) as err:
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_ADD_PASSWORD,
|
|
{
|
|
ATTR_DEVICE_ID: device_entry.id,
|
|
"password": "123456",
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
assert err.value.translation_domain == DOMAIN
|
|
assert err.value.translation_key == "not_keypad_vision_device"
|
|
|
|
|
|
async def test_device_without_config_entry_id(
|
|
hass: HomeAssistant,
|
|
device_registry: dr.DeviceRegistry,
|
|
) -> None:
|
|
"""Test service errors when device has no config entry id."""
|
|
async_setup_services(hass)
|
|
|
|
entry = MockConfigEntry(domain=DOMAIN, data={}, title="No entry device")
|
|
entry.add_to_hass(hass)
|
|
|
|
with pytest.raises(ServiceValidationError) as err:
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_ADD_PASSWORD,
|
|
{
|
|
ATTR_DEVICE_ID: "abc",
|
|
"password": "123456",
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
assert err.value.translation_domain == DOMAIN
|
|
assert err.value.translation_key == "invalid_device_id"
|
|
assert err.value.translation_placeholders == {"device_id": "abc"}
|