core/tests/components/switchbot/test_fan.py

230 lines
6.6 KiB
Python

"""Test the switchbot fan."""
from collections.abc import Callable
from unittest.mock import AsyncMock, patch
import pytest
from switchbot.devices.device import SwitchbotOperationError
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
from homeassistant.components.fan import (
ATTR_OSCILLATING,
ATTR_PERCENTAGE,
ATTR_PRESET_MODE,
DOMAIN as FAN_DOMAIN,
SERVICE_OSCILLATE,
SERVICE_SET_PERCENTAGE,
SERVICE_SET_PRESET_MODE,
)
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from . import (
AIR_PURIFIER_PM25_SERVICE_INFO,
AIR_PURIFIER_TABLE_VOC_SERVICE_INFO,
AIR_PURIFIER_TBALE_PM25_SERVICE_INFO,
AIR_PURIFIER_VOC_SERVICE_INFO,
CIRCULATOR_FAN_SERVICE_INFO,
)
from tests.common import MockConfigEntry
from tests.components.bluetooth import inject_bluetooth_service_info
@pytest.mark.parametrize(
(
"service",
"service_data",
"mock_method",
),
[
(
SERVICE_SET_PRESET_MODE,
{ATTR_PRESET_MODE: "baby"},
"set_preset_mode",
),
(
SERVICE_SET_PERCENTAGE,
{ATTR_PERCENTAGE: 27},
"set_percentage",
),
(
SERVICE_OSCILLATE,
{ATTR_OSCILLATING: True},
"set_oscillation",
),
(
SERVICE_TURN_OFF,
{},
"turn_off",
),
(
SERVICE_TURN_ON,
{},
"turn_on",
),
],
)
async def test_circulator_fan_controlling(
hass: HomeAssistant,
mock_entry_factory: Callable[[str], MockConfigEntry],
service: str,
service_data: dict,
mock_method: str,
) -> None:
"""Test controlling the circulator fan with different services."""
inject_bluetooth_service_info(hass, CIRCULATOR_FAN_SERVICE_INFO)
entry = mock_entry_factory(sensor_type="circulator_fan")
entity_id = "fan.test_name"
entry.add_to_hass(hass)
mocked_instance = AsyncMock(return_value=True)
mcoked_none_instance = AsyncMock(return_value=None)
with patch.multiple(
"homeassistant.components.switchbot.fan.switchbot.SwitchbotFan",
get_basic_info=mcoked_none_instance,
**{mock_method: mocked_instance},
):
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
await hass.services.async_call(
FAN_DOMAIN,
service,
{**service_data, ATTR_ENTITY_ID: entity_id},
blocking=True,
)
mocked_instance.assert_awaited_once()
@pytest.mark.parametrize(
("service_info", "sensor_type"),
[
(AIR_PURIFIER_VOC_SERVICE_INFO, "air_purifier"),
(AIR_PURIFIER_TABLE_VOC_SERVICE_INFO, "air_purifier_table"),
(AIR_PURIFIER_PM25_SERVICE_INFO, "air_purifier"),
(AIR_PURIFIER_TBALE_PM25_SERVICE_INFO, "air_purifier_table"),
],
)
@pytest.mark.parametrize(
("service", "service_data", "mock_method"),
[
(
SERVICE_SET_PRESET_MODE,
{ATTR_PRESET_MODE: "sleep"},
"set_preset_mode",
),
(
SERVICE_TURN_OFF,
{},
"turn_off",
),
(
SERVICE_TURN_ON,
{},
"turn_on",
),
],
)
async def test_air_purifier_controlling(
hass: HomeAssistant,
mock_entry_encrypted_factory: Callable[[str], MockConfigEntry],
service_info: BluetoothServiceInfoBleak,
sensor_type: str,
service: str,
service_data: dict,
mock_method: str,
) -> None:
"""Test controlling the air purifier with different services."""
inject_bluetooth_service_info(hass, service_info)
entry = mock_entry_encrypted_factory(sensor_type)
entity_id = "fan.test_name"
entry.add_to_hass(hass)
mocked_instance = AsyncMock(return_value=True)
mcoked_none_instance = AsyncMock(return_value=None)
with patch.multiple(
"homeassistant.components.switchbot.fan.switchbot.SwitchbotAirPurifier",
get_basic_info=mcoked_none_instance,
update=mcoked_none_instance,
**{mock_method: mocked_instance},
):
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
await hass.services.async_call(
FAN_DOMAIN,
service,
{**service_data, ATTR_ENTITY_ID: entity_id},
blocking=True,
)
mocked_instance.assert_awaited_once()
@pytest.mark.parametrize(
("service_info", "sensor_type"),
[
(AIR_PURIFIER_VOC_SERVICE_INFO, "air_purifier"),
(AIR_PURIFIER_TABLE_VOC_SERVICE_INFO, "air_purifier_table"),
(AIR_PURIFIER_PM25_SERVICE_INFO, "air_purifier"),
(AIR_PURIFIER_TBALE_PM25_SERVICE_INFO, "air_purifier_table"),
],
)
@pytest.mark.parametrize(
("service", "service_data", "mock_method"),
[
(SERVICE_SET_PRESET_MODE, {ATTR_PRESET_MODE: "sleep"}, "set_preset_mode"),
(SERVICE_TURN_OFF, {}, "turn_off"),
(SERVICE_TURN_ON, {}, "turn_on"),
],
)
@pytest.mark.parametrize(
("exception", "error_message"),
[
(
SwitchbotOperationError("Operation failed"),
"An error occurred while performing the action: Operation failed",
),
],
)
async def test_exception_handling_air_purifier_service(
hass: HomeAssistant,
mock_entry_encrypted_factory: Callable[[str], MockConfigEntry],
service_info: BluetoothServiceInfoBleak,
sensor_type: str,
service: str,
service_data: dict,
mock_method: str,
exception: Exception,
error_message: str,
) -> None:
"""Test exception handling for air purifier service with exception."""
inject_bluetooth_service_info(hass, service_info)
entry = mock_entry_encrypted_factory(sensor_type)
entry.add_to_hass(hass)
entity_id = "fan.test_name"
mcoked_none_instance = AsyncMock(return_value=None)
with patch.multiple(
"homeassistant.components.switchbot.fan.switchbot.SwitchbotAirPurifier",
get_basic_info=mcoked_none_instance,
update=mcoked_none_instance,
**{mock_method: AsyncMock(side_effect=exception)},
):
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
with pytest.raises(HomeAssistantError, match=error_message):
await hass.services.async_call(
FAN_DOMAIN,
service,
{**service_data, ATTR_ENTITY_ID: entity_id},
blocking=True,
)