mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 16:27:08 +00:00
Add tests coverage for Shelly entity (#82432)
* Add tests coverage for Shelly entity * Make it generator expression
This commit is contained in:
parent
4bb69fee23
commit
32f3eb722e
@ -1111,7 +1111,6 @@ omit =
|
|||||||
homeassistant/components/seventeentrack/sensor.py
|
homeassistant/components/seventeentrack/sensor.py
|
||||||
homeassistant/components/shelly/climate.py
|
homeassistant/components/shelly/climate.py
|
||||||
homeassistant/components/shelly/coordinator.py
|
homeassistant/components/shelly/coordinator.py
|
||||||
homeassistant/components/shelly/entity.py
|
|
||||||
homeassistant/components/shelly/number.py
|
homeassistant/components/shelly/number.py
|
||||||
homeassistant/components/shelly/utils.py
|
homeassistant/components/shelly/utils.py
|
||||||
homeassistant/components/shiftr/*
|
homeassistant/components/shiftr/*
|
||||||
|
@ -21,12 +21,7 @@ from homeassistant.helpers.typing import StateType
|
|||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
from .const import CONF_SLEEP_PERIOD, LOGGER
|
from .const import CONF_SLEEP_PERIOD, LOGGER
|
||||||
from .coordinator import (
|
from .coordinator import ShellyBlockCoordinator, ShellyRpcCoordinator, get_entry_data
|
||||||
ShellyBlockCoordinator,
|
|
||||||
ShellyRpcCoordinator,
|
|
||||||
ShellyRpcPollingCoordinator,
|
|
||||||
get_entry_data,
|
|
||||||
)
|
|
||||||
from .utils import (
|
from .utils import (
|
||||||
async_remove_shelly_entity,
|
async_remove_shelly_entity,
|
||||||
get_block_entity_name,
|
get_block_entity_name,
|
||||||
@ -269,21 +264,10 @@ def async_setup_entry_rest(
|
|||||||
"""Set up entities for REST sensors."""
|
"""Set up entities for REST sensors."""
|
||||||
coordinator = get_entry_data(hass)[config_entry.entry_id].rest
|
coordinator = get_entry_data(hass)[config_entry.entry_id].rest
|
||||||
assert coordinator
|
assert coordinator
|
||||||
entities = []
|
|
||||||
for sensor_id in sensors:
|
|
||||||
description = sensors.get(sensor_id)
|
|
||||||
|
|
||||||
if not coordinator.device.settings.get("sleep_mode"):
|
|
||||||
entities.append((sensor_id, description))
|
|
||||||
|
|
||||||
if not entities:
|
|
||||||
return
|
|
||||||
|
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
[
|
sensor_class(coordinator, sensor_id, sensors[sensor_id])
|
||||||
sensor_class(coordinator, sensor_id, description)
|
for sensor_id in sensors
|
||||||
for sensor_id, description in entities
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -350,10 +334,6 @@ class ShellyBlockEntity(CoordinatorEntity[ShellyBlockCoordinator]):
|
|||||||
"""When entity is added to HASS."""
|
"""When entity is added to HASS."""
|
||||||
self.async_on_remove(self.coordinator.async_add_listener(self._update_callback))
|
self.async_on_remove(self.coordinator.async_add_listener(self._update_callback))
|
||||||
|
|
||||||
async def async_update(self) -> None:
|
|
||||||
"""Update entity with latest info."""
|
|
||||||
await self.coordinator.async_request_refresh()
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _update_callback(self) -> None:
|
def _update_callback(self) -> None:
|
||||||
"""Handle device update."""
|
"""Handle device update."""
|
||||||
@ -373,16 +353,12 @@ class ShellyBlockEntity(CoordinatorEntity[ShellyBlockCoordinator]):
|
|||||||
self.coordinator.entry.async_start_reauth(self.hass)
|
self.coordinator.entry.async_start_reauth(self.hass)
|
||||||
|
|
||||||
|
|
||||||
class ShellyRpcEntity(entity.Entity):
|
class ShellyRpcEntity(CoordinatorEntity[ShellyRpcCoordinator]):
|
||||||
"""Helper class to represent a rpc entity."""
|
"""Helper class to represent a rpc entity."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, coordinator: ShellyRpcCoordinator, key: str) -> None:
|
||||||
self,
|
|
||||||
coordinator: ShellyRpcCoordinator | ShellyRpcPollingCoordinator,
|
|
||||||
key: str,
|
|
||||||
) -> None:
|
|
||||||
"""Initialize Shelly entity."""
|
"""Initialize Shelly entity."""
|
||||||
self.coordinator = coordinator
|
super().__init__(coordinator)
|
||||||
self.key = key
|
self.key = key
|
||||||
self._attr_should_poll = False
|
self._attr_should_poll = False
|
||||||
self._attr_device_info = {
|
self._attr_device_info = {
|
||||||
@ -405,10 +381,6 @@ class ShellyRpcEntity(entity.Entity):
|
|||||||
"""When entity is added to HASS."""
|
"""When entity is added to HASS."""
|
||||||
self.async_on_remove(self.coordinator.async_add_listener(self._update_callback))
|
self.async_on_remove(self.coordinator.async_add_listener(self._update_callback))
|
||||||
|
|
||||||
async def async_update(self) -> None:
|
|
||||||
"""Update entity with latest info."""
|
|
||||||
await self.coordinator.async_request_refresh()
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _update_callback(self) -> None:
|
def _update_callback(self) -> None:
|
||||||
"""Handle device update."""
|
"""Handle device update."""
|
||||||
@ -525,16 +497,6 @@ class ShellyRestAttributeEntity(CoordinatorEntity[ShellyBlockCoordinator]):
|
|||||||
)
|
)
|
||||||
return self._last_value
|
return self._last_value
|
||||||
|
|
||||||
@property
|
|
||||||
def extra_state_attributes(self) -> dict[str, Any] | None:
|
|
||||||
"""Return the state attributes."""
|
|
||||||
if self.entity_description.extra_state_attributes is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return self.entity_description.extra_state_attributes(
|
|
||||||
self.block_coordinator.device.status
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ShellyRpcAttributeEntity(ShellyRpcEntity, entity.Entity):
|
class ShellyRpcAttributeEntity(ShellyRpcEntity, entity.Entity):
|
||||||
"""Helper class to represent a rpc attribute."""
|
"""Helper class to represent a rpc attribute."""
|
||||||
@ -586,19 +548,6 @@ class ShellyRpcAttributeEntity(ShellyRpcEntity, entity.Entity):
|
|||||||
self.coordinator.device.status[self.key][self.entity_description.sub_key]
|
self.coordinator.device.status[self.key][self.entity_description.sub_key]
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
|
||||||
def extra_state_attributes(self) -> dict[str, Any] | None:
|
|
||||||
"""Return the state attributes."""
|
|
||||||
if self.entity_description.extra_state_attributes is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
assert self.coordinator.device.shelly
|
|
||||||
|
|
||||||
return self.entity_description.extra_state_attributes(
|
|
||||||
self.coordinator.device.status[self.key][self.entity_description.sub_key],
|
|
||||||
self.coordinator.device.shelly,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ShellySleepingBlockAttributeEntity(ShellyBlockAttributeEntity, RestoreEntity):
|
class ShellySleepingBlockAttributeEntity(ShellyBlockAttributeEntity, RestoreEntity):
|
||||||
"""Represent a shelly sleeping block attribute entity."""
|
"""Represent a shelly sleeping block attribute entity."""
|
||||||
|
@ -12,6 +12,7 @@ from homeassistant.components.shelly.const import (
|
|||||||
CONF_SLEEP_PERIOD,
|
CONF_SLEEP_PERIOD,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
REST_SENSORS_UPDATE_INTERVAL,
|
REST_SENSORS_UPDATE_INTERVAL,
|
||||||
|
RPC_SENSORS_POLLING_INTERVAL,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_HOST
|
from homeassistant.const import CONF_HOST
|
||||||
@ -84,6 +85,14 @@ async def mock_rest_update(hass: HomeAssistant):
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
|
async def mock_polling_rpc_update(hass: HomeAssistant):
|
||||||
|
"""Move time to create polling RPC sensors update event."""
|
||||||
|
async_fire_time_changed(
|
||||||
|
hass, dt.utcnow() + timedelta(seconds=RPC_SENSORS_POLLING_INTERVAL)
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
def register_entity(
|
def register_entity(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
domain: str,
|
domain: str,
|
||||||
|
@ -29,6 +29,7 @@ MOCK_SETTINGS = {
|
|||||||
"fw": "20201124-092159/v1.9.0@57ac4ad8",
|
"fw": "20201124-092159/v1.9.0@57ac4ad8",
|
||||||
"relays": [{"btn_type": "momentary"}, {"btn_type": "toggle"}],
|
"relays": [{"btn_type": "momentary"}, {"btn_type": "toggle"}],
|
||||||
"rollers": [{"positioning": True}],
|
"rollers": [{"positioning": True}],
|
||||||
|
"external_power": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -97,12 +98,20 @@ MOCK_BLOCKS = [
|
|||||||
set_state=AsyncMock(side_effect=mock_light_set_state),
|
set_state=AsyncMock(side_effect=mock_light_set_state),
|
||||||
),
|
),
|
||||||
Mock(
|
Mock(
|
||||||
sensor_ids={"motion": 0, "temp": 22.1},
|
sensor_ids={"motion": 0, "temp": 22.1, "gas": "mild"},
|
||||||
motion=0,
|
motion=0,
|
||||||
temp=22.1,
|
temp=22.1,
|
||||||
|
gas="mild",
|
||||||
description="sensor_0",
|
description="sensor_0",
|
||||||
type="sensor",
|
type="sensor",
|
||||||
),
|
),
|
||||||
|
Mock(
|
||||||
|
sensor_ids={"battery": 98},
|
||||||
|
battery=98,
|
||||||
|
cfgChanged=0,
|
||||||
|
description="device_0",
|
||||||
|
type="device",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
MOCK_CONFIG = {
|
MOCK_CONFIG = {
|
||||||
@ -165,6 +174,8 @@ MOCK_STATUS_RPC = {
|
|||||||
"stable": {"version": "some_beta_version"},
|
"stable": {"version": "some_beta_version"},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"voltmeter": {"voltage": 4.3},
|
||||||
|
"wifi": {"rssi": -63},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
||||||
from homeassistant.const import STATE_OFF, STATE_ON
|
from homeassistant.const import STATE_OFF, STATE_ON
|
||||||
from homeassistant.core import State
|
from homeassistant.core import State
|
||||||
|
from homeassistant.helpers.entity_registry import async_get
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
init_integration,
|
init_integration,
|
||||||
@ -32,6 +33,25 @@ async def test_block_binary_sensor(hass, mock_block_device, monkeypatch):
|
|||||||
assert hass.states.get(entity_id).state == STATE_ON
|
assert hass.states.get(entity_id).state == STATE_ON
|
||||||
|
|
||||||
|
|
||||||
|
async def test_block_binary_sensor_extra_state_attr(
|
||||||
|
hass, mock_block_device, monkeypatch
|
||||||
|
):
|
||||||
|
"""Test block binary sensor extra state attributes."""
|
||||||
|
entity_id = f"{BINARY_SENSOR_DOMAIN}.test_name_gas"
|
||||||
|
await init_integration(hass, 1)
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
assert state.attributes.get("detected") == "mild"
|
||||||
|
|
||||||
|
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "gas", "none")
|
||||||
|
mock_block_device.mock_update()
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
assert state.attributes.get("detected") == "none"
|
||||||
|
|
||||||
|
|
||||||
async def test_block_rest_binary_sensor(hass, mock_block_device, monkeypatch):
|
async def test_block_rest_binary_sensor(hass, mock_block_device, monkeypatch):
|
||||||
"""Test block REST binary sensor."""
|
"""Test block REST binary sensor."""
|
||||||
entity_id = register_entity(hass, BINARY_SENSOR_DOMAIN, "test_name_cloud", "cloud")
|
entity_id = register_entity(hass, BINARY_SENSOR_DOMAIN, "test_name_cloud", "cloud")
|
||||||
@ -105,6 +125,21 @@ async def test_rpc_binary_sensor(hass, mock_rpc_device, monkeypatch) -> None:
|
|||||||
assert hass.states.get(entity_id).state == STATE_ON
|
assert hass.states.get(entity_id).state == STATE_ON
|
||||||
|
|
||||||
|
|
||||||
|
async def test_rpc_binary_sensor_removal(hass, mock_rpc_device, monkeypatch):
|
||||||
|
"""Test RPC binary sensor is removed due to removal_condition."""
|
||||||
|
entity_registry = async_get(hass)
|
||||||
|
entity_id = register_entity(
|
||||||
|
hass, BINARY_SENSOR_DOMAIN, "test_cover_0_input", "input:0-input"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert entity_registry.async_get(entity_id) is not None
|
||||||
|
|
||||||
|
monkeypatch.setattr(mock_rpc_device, "status", {"input:0": {"state": False}})
|
||||||
|
await init_integration(hass, 2)
|
||||||
|
|
||||||
|
assert entity_registry.async_get(entity_id) is None
|
||||||
|
|
||||||
|
|
||||||
async def test_rpc_sleeping_binary_sensor(
|
async def test_rpc_sleeping_binary_sensor(
|
||||||
hass, mock_rpc_device, device_reg, monkeypatch
|
hass, mock_rpc_device, device_reg, monkeypatch
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -70,6 +70,7 @@ async def test_rpc_config_entry_diagnostics(
|
|||||||
"beta": {"version": "some_beta_version"},
|
"beta": {"version": "some_beta_version"},
|
||||||
"stable": {"version": "some_beta_version"},
|
"stable": {"version": "some_beta_version"},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"wifi": {"rssi": -63},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
|
|
||||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||||
|
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
|
||||||
from homeassistant.core import State
|
from homeassistant.core import State
|
||||||
|
from homeassistant.helpers.entity_registry import async_get
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
init_integration,
|
init_integration,
|
||||||
|
mock_polling_rpc_update,
|
||||||
mock_rest_update,
|
mock_rest_update,
|
||||||
mutate_rpc_device_status,
|
mutate_rpc_device_status,
|
||||||
register_device,
|
register_device,
|
||||||
@ -16,6 +19,7 @@ from tests.common import mock_restore_cache
|
|||||||
|
|
||||||
RELAY_BLOCK_ID = 0
|
RELAY_BLOCK_ID = 0
|
||||||
SENSOR_BLOCK_ID = 3
|
SENSOR_BLOCK_ID = 3
|
||||||
|
DEVICE_BLOCK_ID = 4
|
||||||
|
|
||||||
|
|
||||||
async def test_block_sensor(hass, mock_block_device, monkeypatch):
|
async def test_block_sensor(hass, mock_block_device, monkeypatch):
|
||||||
@ -88,6 +92,79 @@ async def test_block_restored_sleeping_sensor(
|
|||||||
assert hass.states.get(entity_id).state == "22.1"
|
assert hass.states.get(entity_id).state == "22.1"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_block_sensor_error(hass, mock_block_device, monkeypatch):
|
||||||
|
"""Test block sensor unavailable on sensor error."""
|
||||||
|
entity_id = f"{SENSOR_DOMAIN}.test_name_battery"
|
||||||
|
await init_integration(hass, 1)
|
||||||
|
|
||||||
|
assert hass.states.get(entity_id).state == "98"
|
||||||
|
|
||||||
|
monkeypatch.setattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "battery", -1)
|
||||||
|
mock_block_device.mock_update()
|
||||||
|
|
||||||
|
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
async def test_block_sensor_removal(hass, mock_block_device, monkeypatch):
|
||||||
|
"""Test block sensor is removed due to removal_condition."""
|
||||||
|
entity_registry = async_get(hass)
|
||||||
|
entity_id = register_entity(
|
||||||
|
hass, SENSOR_DOMAIN, "test_name_battery", "device_0-battery"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert entity_registry.async_get(entity_id) is not None
|
||||||
|
|
||||||
|
monkeypatch.setitem(mock_block_device.settings, "external_power", 1)
|
||||||
|
await init_integration(hass, 1)
|
||||||
|
|
||||||
|
assert entity_registry.async_get(entity_id) is None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_block_not_matched_restored_sleeping_sensor(
|
||||||
|
hass, mock_block_device, device_reg, monkeypatch
|
||||||
|
):
|
||||||
|
"""Test block not matched to restored sleeping sensor."""
|
||||||
|
entry = await init_integration(hass, 1, sleep_period=1000, skip_setup=True)
|
||||||
|
register_device(device_reg, entry)
|
||||||
|
entity_id = register_entity(
|
||||||
|
hass, SENSOR_DOMAIN, "test_name_temperature", "sensor_0-temp", entry
|
||||||
|
)
|
||||||
|
mock_restore_cache(hass, [State(entity_id, "20.4")])
|
||||||
|
monkeypatch.setattr(mock_block_device, "initialized", False)
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get(entity_id).state == "20.4"
|
||||||
|
|
||||||
|
# Make device online
|
||||||
|
monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "type", "other_type")
|
||||||
|
monkeypatch.setattr(mock_block_device, "initialized", True)
|
||||||
|
mock_block_device.mock_update()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get(entity_id).state == "20.4"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_block_sensor_without_value(hass, mock_block_device, monkeypatch):
|
||||||
|
"""Test block sensor without value is not created."""
|
||||||
|
entity_id = f"{SENSOR_DOMAIN}.test_name_battery"
|
||||||
|
monkeypatch.setattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "battery", None)
|
||||||
|
await init_integration(hass, 1)
|
||||||
|
|
||||||
|
assert hass.states.get(entity_id) is None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_block_sensor_unknown_value(hass, mock_block_device, monkeypatch):
|
||||||
|
"""Test block sensor unknown value."""
|
||||||
|
entity_id = f"{SENSOR_DOMAIN}.test_name_battery"
|
||||||
|
await init_integration(hass, 1)
|
||||||
|
|
||||||
|
monkeypatch.setattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "battery", None)
|
||||||
|
mock_block_device.mock_update()
|
||||||
|
|
||||||
|
assert hass.states.get(entity_id).state == STATE_UNKNOWN
|
||||||
|
|
||||||
|
|
||||||
async def test_rpc_sensor(hass, mock_rpc_device, monkeypatch) -> None:
|
async def test_rpc_sensor(hass, mock_rpc_device, monkeypatch) -> None:
|
||||||
"""Test RPC sensor."""
|
"""Test RPC sensor."""
|
||||||
entity_id = f"{SENSOR_DOMAIN}.test_cover_0_power"
|
entity_id = f"{SENSOR_DOMAIN}.test_cover_0_power"
|
||||||
@ -101,6 +178,32 @@ async def test_rpc_sensor(hass, mock_rpc_device, monkeypatch) -> None:
|
|||||||
assert hass.states.get(entity_id).state == "88.2"
|
assert hass.states.get(entity_id).state == "88.2"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_rpc_sensor_error(hass, mock_rpc_device, monkeypatch):
|
||||||
|
"""Test RPC sensor unavailable on sensor error."""
|
||||||
|
entity_id = f"{SENSOR_DOMAIN}.test_name_voltmeter"
|
||||||
|
await init_integration(hass, 2)
|
||||||
|
|
||||||
|
assert hass.states.get(entity_id).state == "4.3"
|
||||||
|
|
||||||
|
mutate_rpc_device_status(monkeypatch, mock_rpc_device, "voltmeter", "voltage", None)
|
||||||
|
mock_rpc_device.mock_update()
|
||||||
|
|
||||||
|
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
|
||||||
|
async def test_rpc_polling_sensor(hass, mock_rpc_device, monkeypatch) -> None:
|
||||||
|
"""Test RPC polling sensor."""
|
||||||
|
entity_id = register_entity(hass, SENSOR_DOMAIN, "test_name_rssi", "wifi-rssi")
|
||||||
|
await init_integration(hass, 2)
|
||||||
|
|
||||||
|
assert hass.states.get(entity_id).state == "-63"
|
||||||
|
|
||||||
|
mutate_rpc_device_status(monkeypatch, mock_rpc_device, "wifi", "rssi", "-70")
|
||||||
|
await mock_polling_rpc_update(hass)
|
||||||
|
|
||||||
|
assert hass.states.get(entity_id).state == "-70"
|
||||||
|
|
||||||
|
|
||||||
async def test_rpc_sleeping_sensor(
|
async def test_rpc_sleeping_sensor(
|
||||||
hass, mock_rpc_device, device_reg, monkeypatch
|
hass, mock_rpc_device, device_reg, monkeypatch
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
"""Tests for Shelly switch platform."""
|
"""Tests for Shelly switch platform."""
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
|
from aioshelly.exceptions import DeviceConnectionError, InvalidAuthError, RpcCallError
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.shelly.const import DOMAIN
|
||||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||||
|
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
SERVICE_TURN_OFF,
|
SERVICE_TURN_OFF,
|
||||||
@ -7,6 +14,7 @@ from homeassistant.const import (
|
|||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
)
|
)
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
|
||||||
from . import init_integration
|
from . import init_integration
|
||||||
|
|
||||||
@ -34,6 +42,56 @@ async def test_block_device_services(hass, mock_block_device):
|
|||||||
assert hass.states.get("switch.test_name_channel_1").state == STATE_OFF
|
assert hass.states.get("switch.test_name_channel_1").state == STATE_OFF
|
||||||
|
|
||||||
|
|
||||||
|
async def test_block_set_state_connection_error(hass, mock_block_device, monkeypatch):
|
||||||
|
"""Test block device set state connection error."""
|
||||||
|
monkeypatch.setattr(
|
||||||
|
mock_block_device.blocks[RELAY_BLOCK_ID],
|
||||||
|
"set_state",
|
||||||
|
AsyncMock(side_effect=DeviceConnectionError),
|
||||||
|
)
|
||||||
|
await init_integration(hass, 1)
|
||||||
|
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
SWITCH_DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
{ATTR_ENTITY_ID: "switch.test_name_channel_1"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_block_set_state_auth_error(hass, mock_block_device, monkeypatch):
|
||||||
|
"""Test block device set state authentication error."""
|
||||||
|
monkeypatch.setattr(
|
||||||
|
mock_block_device.blocks[RELAY_BLOCK_ID],
|
||||||
|
"set_state",
|
||||||
|
AsyncMock(side_effect=InvalidAuthError),
|
||||||
|
)
|
||||||
|
entry = await init_integration(hass, 1)
|
||||||
|
|
||||||
|
assert entry.state == ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
SWITCH_DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
{ATTR_ENTITY_ID: "switch.test_name_channel_1"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert entry.state == 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
|
||||||
|
|
||||||
|
|
||||||
async def test_block_device_update(hass, mock_block_device, monkeypatch):
|
async def test_block_device_update(hass, mock_block_device, monkeypatch):
|
||||||
"""Test block device update."""
|
"""Test block device update."""
|
||||||
monkeypatch.setattr(mock_block_device.blocks[RELAY_BLOCK_ID], "output", False)
|
monkeypatch.setattr(mock_block_device.blocks[RELAY_BLOCK_ID], "output", False)
|
||||||
@ -98,3 +156,50 @@ async def test_rpc_device_switch_type_lights_mode(hass, mock_rpc_device, monkeyp
|
|||||||
)
|
)
|
||||||
await init_integration(hass, 2)
|
await init_integration(hass, 2)
|
||||||
assert hass.states.get("switch.test_switch_0") is None
|
assert hass.states.get("switch.test_switch_0") is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("exc", [DeviceConnectionError, RpcCallError(-1, "error")])
|
||||||
|
async def test_rpc_set_state_errors(hass, exc, mock_rpc_device, monkeypatch):
|
||||||
|
"""Test RPC device set state connection/call errors."""
|
||||||
|
monkeypatch.setattr(mock_rpc_device, "call_rpc", AsyncMock(side_effect=exc))
|
||||||
|
await init_integration(hass, 2)
|
||||||
|
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
SWITCH_DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
{ATTR_ENTITY_ID: "switch.test_switch_0"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_rpc_auth_error(hass, mock_rpc_device, monkeypatch):
|
||||||
|
"""Test RPC device set state authentication error."""
|
||||||
|
monkeypatch.setattr(
|
||||||
|
mock_rpc_device,
|
||||||
|
"call_rpc",
|
||||||
|
AsyncMock(side_effect=InvalidAuthError),
|
||||||
|
)
|
||||||
|
entry = await init_integration(hass, 2)
|
||||||
|
|
||||||
|
assert entry.state == ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
SWITCH_DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
{ATTR_ENTITY_ID: "switch.test_switch_0"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert entry.state == 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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user