core/tests/components/home_connect/test_light.py

349 lines
9.5 KiB
Python

"""Tests for home_connect light entities."""
from collections.abc import Awaitable, Callable, Generator
from unittest.mock import MagicMock, Mock
from homeconnect.api import HomeConnectAppliance, HomeConnectError
import pytest
from homeassistant.components.home_connect.const import (
BSH_AMBIENT_LIGHT_BRIGHTNESS,
BSH_AMBIENT_LIGHT_COLOR,
BSH_AMBIENT_LIGHT_CUSTOM_COLOR,
BSH_AMBIENT_LIGHT_ENABLED,
COOKING_LIGHTING,
COOKING_LIGHTING_BRIGHTNESS,
REFRIGERATION_EXTERNAL_LIGHT_BRIGHTNESS,
REFRIGERATION_EXTERNAL_LIGHT_POWER,
)
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import (
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_OFF,
STATE_ON,
STATE_UNKNOWN,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from .conftest import get_all_appliances
from tests.common import MockConfigEntry, load_json_object_fixture
TEST_HC_APP = "Hood"
SETTINGS_STATUS = {
setting.pop("key"): setting
for setting in load_json_object_fixture("home_connect/settings.json")
.get(TEST_HC_APP)
.get("data")
.get("settings")
}
@pytest.fixture
def platforms() -> list[str]:
"""Fixture to specify platforms to test."""
return [Platform.LIGHT]
async def test_light(
bypass_throttle: Generator[None],
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[], Awaitable[bool]],
setup_credentials: None,
get_appliances: Mock,
) -> None:
"""Test switch entities."""
get_appliances.side_effect = get_all_appliances
assert config_entry.state == ConfigEntryState.NOT_LOADED
assert await integration_setup()
assert config_entry.state == ConfigEntryState.LOADED
@pytest.mark.parametrize(
("entity_id", "status", "service", "service_data", "state", "appliance"),
[
(
"light.hood_functional_light",
{
COOKING_LIGHTING: {
"value": True,
},
},
SERVICE_TURN_ON,
{},
STATE_ON,
"Hood",
),
(
"light.hood_functional_light",
{
COOKING_LIGHTING: {
"value": True,
},
COOKING_LIGHTING_BRIGHTNESS: {"value": 70},
},
SERVICE_TURN_ON,
{"brightness": 200},
STATE_ON,
"Hood",
),
(
"light.hood_functional_light",
{
COOKING_LIGHTING: {"value": False},
COOKING_LIGHTING_BRIGHTNESS: {"value": 70},
},
SERVICE_TURN_OFF,
{},
STATE_OFF,
"Hood",
),
(
"light.hood_functional_light",
{
COOKING_LIGHTING: {
"value": None,
},
COOKING_LIGHTING_BRIGHTNESS: None,
},
SERVICE_TURN_ON,
{},
STATE_UNKNOWN,
"Hood",
),
(
"light.hood_ambient_light",
{
BSH_AMBIENT_LIGHT_ENABLED: {
"value": True,
},
BSH_AMBIENT_LIGHT_BRIGHTNESS: {"value": 70},
},
SERVICE_TURN_ON,
{"brightness": 200},
STATE_ON,
"Hood",
),
(
"light.hood_ambient_light",
{
BSH_AMBIENT_LIGHT_ENABLED: {"value": False},
BSH_AMBIENT_LIGHT_BRIGHTNESS: {"value": 70},
},
SERVICE_TURN_OFF,
{},
STATE_OFF,
"Hood",
),
(
"light.hood_ambient_light",
{
BSH_AMBIENT_LIGHT_ENABLED: {"value": True},
BSH_AMBIENT_LIGHT_CUSTOM_COLOR: {},
},
SERVICE_TURN_ON,
{},
STATE_ON,
"Hood",
),
(
"light.hood_ambient_light",
{
BSH_AMBIENT_LIGHT_ENABLED: {"value": True},
BSH_AMBIENT_LIGHT_COLOR: {
"value": "",
},
BSH_AMBIENT_LIGHT_CUSTOM_COLOR: {},
},
SERVICE_TURN_ON,
{
"rgb_color": [255, 255, 0],
},
STATE_ON,
"Hood",
),
(
"light.fridgefreezer_external_light",
{
REFRIGERATION_EXTERNAL_LIGHT_POWER: {
"value": True,
},
REFRIGERATION_EXTERNAL_LIGHT_BRIGHTNESS: {"value": 75},
},
SERVICE_TURN_ON,
{},
STATE_ON,
"FridgeFreezer",
),
],
indirect=["appliance"],
)
async def test_light_functionality(
entity_id: str,
status: dict,
service: str,
service_data: dict,
state: str,
appliance: Mock,
bypass_throttle: Generator[None],
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[], Awaitable[bool]],
setup_credentials: None,
get_appliances: MagicMock,
) -> None:
"""Test light functionality."""
appliance.status.update(
HomeConnectAppliance.json2dict(
load_json_object_fixture("home_connect/settings.json")
.get(appliance.name)
.get("data")
.get("settings")
)
)
get_appliances.return_value = [appliance]
assert config_entry.state == ConfigEntryState.NOT_LOADED
assert await integration_setup()
assert config_entry.state == ConfigEntryState.LOADED
appliance.status.update(status)
service_data["entity_id"] = entity_id
await hass.services.async_call(
LIGHT_DOMAIN,
service,
service_data,
blocking=True,
)
assert hass.states.is_state(entity_id, state)
@pytest.mark.parametrize(
(
"entity_id",
"status",
"service",
"service_data",
"mock_attr",
"attr_side_effect",
"problematic_appliance",
"exception_match",
),
[
(
"light.hood_functional_light",
{
COOKING_LIGHTING: {
"value": False,
},
},
SERVICE_TURN_ON,
{},
"set_setting",
[HomeConnectError, HomeConnectError],
"Hood",
r"Error.*turn.*on.*",
),
(
"light.hood_functional_light",
{
COOKING_LIGHTING: {
"value": True,
},
COOKING_LIGHTING_BRIGHTNESS: {"value": 70},
},
SERVICE_TURN_ON,
{"brightness": 200},
"set_setting",
[HomeConnectError, HomeConnectError],
"Hood",
r"Error.*turn.*on.*",
),
(
"light.hood_functional_light",
{
COOKING_LIGHTING: {"value": False},
},
SERVICE_TURN_OFF,
{},
"set_setting",
[HomeConnectError, HomeConnectError],
"Hood",
r"Error.*turn.*off.*",
),
(
"light.hood_ambient_light",
{
BSH_AMBIENT_LIGHT_ENABLED: {
"value": True,
},
BSH_AMBIENT_LIGHT_BRIGHTNESS: {"value": 70},
},
SERVICE_TURN_ON,
{},
"set_setting",
[HomeConnectError, HomeConnectError],
"Hood",
r"Error.*turn.*on.*",
),
(
"light.hood_ambient_light",
{
BSH_AMBIENT_LIGHT_ENABLED: {
"value": True,
},
BSH_AMBIENT_LIGHT_BRIGHTNESS: {"value": 70},
},
SERVICE_TURN_ON,
{"brightness": 200},
"set_setting",
[HomeConnectError, None, HomeConnectError],
"Hood",
r"Error.*set.*color.*",
),
],
indirect=["problematic_appliance"],
)
async def test_switch_exception_handling(
entity_id: str,
status: dict,
service: str,
service_data: dict,
mock_attr: str,
attr_side_effect: list,
problematic_appliance: Mock,
exception_match: str,
bypass_throttle: Generator[None],
hass: HomeAssistant,
integration_setup: Callable[[], Awaitable[bool]],
config_entry: MockConfigEntry,
setup_credentials: None,
get_appliances: MagicMock,
) -> None:
"""Test light exception handling."""
problematic_appliance.status.update(SETTINGS_STATUS)
problematic_appliance.set_setting.side_effect = attr_side_effect
get_appliances.return_value = [problematic_appliance]
assert config_entry.state == ConfigEntryState.NOT_LOADED
assert await integration_setup()
assert config_entry.state == ConfigEntryState.LOADED
# Assert that an exception is called.
with pytest.raises(HomeConnectError):
getattr(problematic_appliance, mock_attr)()
problematic_appliance.status.update(status)
service_data["entity_id"] = entity_id
with pytest.raises(ServiceValidationError, match=exception_match):
await hass.services.async_call(
LIGHT_DOMAIN, service, service_data, blocking=True
)
assert getattr(problematic_appliance, mock_attr).call_count == len(attr_side_effect)