core/tests/components/shelly/test_text.py

228 lines
7.0 KiB
Python

"""Tests for Shelly text platform."""
from copy import deepcopy
from unittest.mock import Mock
from aioshelly.exceptions import DeviceConnectionError, InvalidAuthError, RpcCallError
import pytest
from homeassistant.components.shelly.const import DOMAIN
from homeassistant.components.text import (
ATTR_VALUE,
DOMAIN as TEXT_PLATFORM,
SERVICE_SET_VALUE,
)
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import DeviceRegistry
from homeassistant.helpers.entity_registry import EntityRegistry
from . import init_integration, register_device, register_entity
@pytest.mark.parametrize(
("name", "entity_id"),
[
("Virtual text", "text.test_name_virtual_text"),
(None, "text.test_name_text_203"),
],
)
async def test_rpc_device_virtual_text(
hass: HomeAssistant,
entity_registry: EntityRegistry,
mock_rpc_device: Mock,
monkeypatch: pytest.MonkeyPatch,
name: str | None,
entity_id: str,
) -> None:
"""Test a virtual text for RPC device."""
config = deepcopy(mock_rpc_device.config)
config["text:203"] = {
"name": name,
"meta": {"ui": {"view": "field"}},
}
monkeypatch.setattr(mock_rpc_device, "config", config)
status = deepcopy(mock_rpc_device.status)
status["text:203"] = {"value": "lorem ipsum"}
monkeypatch.setattr(mock_rpc_device, "status", status)
await init_integration(hass, 3)
assert (state := hass.states.get(entity_id))
assert state.state == "lorem ipsum"
assert (entry := entity_registry.async_get(entity_id))
assert entry.unique_id == "123456789ABC-text:203-text"
monkeypatch.setitem(mock_rpc_device.status["text:203"], "value", "dolor sit amet")
mock_rpc_device.mock_update()
assert (state := hass.states.get(entity_id))
assert state.state == "dolor sit amet"
monkeypatch.setitem(mock_rpc_device.status["text:203"], "value", "sed do eiusmod")
await hass.services.async_call(
TEXT_PLATFORM,
SERVICE_SET_VALUE,
{ATTR_ENTITY_ID: entity_id, ATTR_VALUE: "sed do eiusmod"},
blocking=True,
)
mock_rpc_device.mock_update()
mock_rpc_device.text_set.assert_called_once_with(203, "sed do eiusmod")
assert (state := hass.states.get(entity_id))
assert state.state == "sed do eiusmod"
async def test_rpc_remove_virtual_text_when_mode_label(
hass: HomeAssistant,
entity_registry: EntityRegistry,
device_registry: DeviceRegistry,
mock_rpc_device: Mock,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Test if the virtual text will be removed if the mode has been changed to a label."""
config = deepcopy(mock_rpc_device.config)
config["text:200"] = {"name": None, "meta": {"ui": {"view": "label"}}}
monkeypatch.setattr(mock_rpc_device, "config", config)
status = deepcopy(mock_rpc_device.status)
status["text:200"] = {"value": "lorem ipsum"}
monkeypatch.setattr(mock_rpc_device, "status", status)
config_entry = await init_integration(hass, 3, skip_setup=True)
device_entry = register_device(device_registry, config_entry)
entity_id = register_entity(
hass,
TEXT_PLATFORM,
"test_name_text_200",
"text:200-text",
config_entry,
device_id=device_entry.id,
)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert entity_registry.async_get(entity_id) is None
async def test_rpc_remove_virtual_text_when_orphaned(
hass: HomeAssistant,
entity_registry: EntityRegistry,
device_registry: DeviceRegistry,
mock_rpc_device: Mock,
) -> None:
"""Check whether the virtual text will be removed if it has been removed from the device configuration."""
config_entry = await init_integration(hass, 3, skip_setup=True)
device_entry = register_device(device_registry, config_entry)
entity_id = register_entity(
hass,
TEXT_PLATFORM,
"test_name_text_200",
"text:200-text",
config_entry,
device_id=device_entry.id,
)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert entity_registry.async_get(entity_id) is None
@pytest.mark.parametrize(
("exception", "error"),
[
(
DeviceConnectionError,
"Device communication error occurred while calling action for text.test_name_text_203 of Test name",
),
(
RpcCallError(999),
"RPC call error occurred while calling action for text.test_name_text_203 of Test name",
),
],
)
async def test_text_set_exc(
hass: HomeAssistant,
mock_rpc_device: Mock,
monkeypatch: pytest.MonkeyPatch,
exception: Exception,
error: str,
) -> None:
"""Test text setting with exception."""
config = deepcopy(mock_rpc_device.config)
config["text:203"] = {
"name": None,
"meta": {"ui": {"view": "field"}},
}
monkeypatch.setattr(mock_rpc_device, "config", config)
status = deepcopy(mock_rpc_device.status)
status["text:203"] = {"value": "lorem ipsum"}
monkeypatch.setattr(mock_rpc_device, "status", status)
await init_integration(hass, 3)
mock_rpc_device.text_set.side_effect = exception
with pytest.raises(HomeAssistantError, match=error):
await hass.services.async_call(
TEXT_PLATFORM,
SERVICE_SET_VALUE,
{
ATTR_ENTITY_ID: f"{TEXT_PLATFORM}.test_name_text_203",
ATTR_VALUE: "new value",
},
blocking=True,
)
async def test_text_set_reauth_error(
hass: HomeAssistant,
mock_rpc_device: Mock,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Test text setting with authentication error."""
config = deepcopy(mock_rpc_device.config)
config["text:203"] = {
"name": None,
"meta": {"ui": {"view": "field"}},
}
monkeypatch.setattr(mock_rpc_device, "config", config)
status = deepcopy(mock_rpc_device.status)
status["text:203"] = {"value": "lorem ipsum"}
monkeypatch.setattr(mock_rpc_device, "status", status)
entry = await init_integration(hass, 3)
mock_rpc_device.text_set.side_effect = InvalidAuthError
await hass.services.async_call(
TEXT_PLATFORM,
SERVICE_SET_VALUE,
{
ATTR_ENTITY_ID: f"{TEXT_PLATFORM}.test_name_text_203",
ATTR_VALUE: "new value",
},
blocking=True,
)
assert entry.state is ConfigEntryState.LOADED
flows = hass.config_entries.flow.async_progress()
assert len(flows) == 1
flow = flows[0]
assert flow.get("step_id") == "reauth_confirm"
assert flow.get("handler") == DOMAIN
assert "context" in flow
assert flow["context"].get("source") == SOURCE_REAUTH
assert flow["context"].get("entry_id") == entry.entry_id