Rewrite dyson vacuum test (#45265)

This commit is contained in:
Xiaonan Shen 2021-01-18 22:56:54 +08:00 committed by GitHub
parent c621c0fa5d
commit 5ee4479151
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 180 additions and 176 deletions

View File

@ -1,22 +1,27 @@
"""Common utils for Dyson tests.""" """Common utils for Dyson tests."""
from typing import Optional, Type
from unittest import mock from unittest import mock
from unittest.mock import MagicMock
from libpurecool.dyson_device import DysonDevice
from libpurecool.dyson_pure_cool import FanSpeed from libpurecool.dyson_pure_cool import FanSpeed
from homeassistant.core import HomeAssistant
def load_mock_device(device): SERIAL = "XX-XXXXX-XX"
NAME = "Temp Name"
ENTITY_NAME = "temp_name"
BASE_PATH = "homeassistant.components.dyson"
def load_mock_device(device: DysonDevice) -> None:
"""Load the mock with default values so it doesn't throw errors.""" """Load the mock with default values so it doesn't throw errors."""
device.serial = "XX-XXXXX-XX" device.serial = SERIAL
device.name = "Temp Name" device.name = NAME
device.connect = mock.Mock(return_value=True) device.connect = mock.Mock(return_value=True)
device.auto_connect = mock.Mock(return_value=True) device.auto_connect = mock.Mock(return_value=True)
device.environmental_state.particulate_matter_25 = "0000"
device.environmental_state.particulate_matter_10 = "0000"
device.environmental_state.nitrogen_dioxide = "0000"
device.environmental_state.volatil_organic_compounds = "0000"
device.environmental_state.volatile_organic_compounds = "0000"
device.environmental_state.temperature = 250
device.state.hepa_filter_state = 0 device.state.hepa_filter_state = 0
device.state.carbon_filter_state = 0 device.state.carbon_filter_state = 0
device.state.speed = FanSpeed.FAN_SPEED_1.value device.state.speed = FanSpeed.FAN_SPEED_1.value
@ -24,3 +29,27 @@ def load_mock_device(device):
device.state.oscillation_angle_high = "000" device.state.oscillation_angle_high = "000"
device.state.filter_life = "000" device.state.filter_life = "000"
device.state.heat_target = 200 device.state.heat_target = 200
if hasattr(device, "environmental_state"):
device.environmental_state.particulate_matter_25 = "0000"
device.environmental_state.particulate_matter_10 = "0000"
device.environmental_state.nitrogen_dioxide = "0000"
device.environmental_state.volatil_organic_compounds = "0000"
device.environmental_state.volatile_organic_compounds = "0000"
device.environmental_state.temperature = 250
def get_basic_device(spec: Type[DysonDevice]) -> DysonDevice:
"""Return a basic device with common fields filled out."""
device = MagicMock(spec=spec)
load_mock_device(device)
return device
async def async_update_device(
hass: HomeAssistant, device: DysonDevice, state_type: Optional[Type] = None
) -> None:
"""Update the device using callback function."""
callback = device.add_message_listener.call_args[0][0]
message = MagicMock(spec=state_type)
await hass.async_add_executor_job(callback, message)
await hass.async_block_till_done()

View File

@ -0,0 +1,46 @@
"""Configure pytest for Dyson tests."""
from unittest.mock import patch
from libpurecool.dyson_device import DysonDevice
import pytest
from homeassistant.components.dyson import CONF_LANGUAGE, DOMAIN
from homeassistant.const import CONF_DEVICES, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from .common import SERIAL
from tests.common import async_setup_component
BASE_PATH = "homeassistant.components.dyson"
@pytest.fixture
async def device(hass: HomeAssistant, request) -> DysonDevice:
"""Fixture to provide Dyson 360 Eye device."""
device = request.module.get_device()
platform = request.module.PLATFORM_DOMAIN
with patch(f"{BASE_PATH}.DysonAccount.login", return_value=True), patch(
f"{BASE_PATH}.DysonAccount.devices", return_value=[device]
), patch(f"{BASE_PATH}.DYSON_PLATFORMS", [platform]):
# DYSON_PLATFORMS is patched so that only the platform being tested is set up
await async_setup_component(
hass,
DOMAIN,
{
DOMAIN: {
CONF_USERNAME: "user@example.com",
CONF_PASSWORD: "password",
CONF_LANGUAGE: "US",
CONF_DEVICES: [
{
"device_id": SERIAL,
"device_ip": "0.0.0.0",
}
],
}
},
)
await hass.async_block_till_done()
return device

View File

@ -1,29 +1,43 @@
"""Test the Dyson 360 eye robot vacuum component.""" """Test the Dyson 360 eye robot vacuum component."""
import unittest from unittest.mock import MagicMock
from unittest import mock
from libpurecool.const import Dyson360EyeMode, PowerMode from libpurecool.const import Dyson360EyeMode, PowerMode
from libpurecool.dyson_360_eye import Dyson360Eye from libpurecool.dyson_360_eye import Dyson360Eye
import pytest
from homeassistant.components.dyson import vacuum as dyson from homeassistant.components.dyson.vacuum import ATTR_POSITION, SUPPORT_DYSON
from homeassistant.components.dyson.vacuum import Dyson360EyeDevice from homeassistant.components.vacuum import (
ATTR_FAN_SPEED,
ATTR_FAN_SPEED_LIST,
ATTR_STATUS,
DOMAIN as PLATFORM_DOMAIN,
SERVICE_RETURN_TO_BASE,
SERVICE_SET_FAN_SPEED,
SERVICE_START_PAUSE,
SERVICE_STOP,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
)
from homeassistant.const import (
ATTR_BATTERY_LEVEL,
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
STATE_OFF,
STATE_ON,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry
from tests.common import get_test_home_assistant from .common import ENTITY_NAME, NAME, SERIAL, async_update_device, get_basic_device
ENTITY_ID = f"{PLATFORM_DOMAIN}.{ENTITY_NAME}"
def _get_non_vacuum_device(): @callback
"""Return a non vacuum device.""" def get_device() -> Dyson360Eye:
device = mock.Mock() """Return a Dyson 360 Eye device."""
device.name = "Device_Fan" device = get_basic_device(Dyson360Eye)
device.state = None device.state = MagicMock()
return device
def _get_vacuum_device_cleaning():
"""Return a vacuum device running."""
device = mock.Mock(spec=Dyson360Eye)
device.name = "Device_Vacuum"
device.state = mock.MagicMock()
device.state.state = Dyson360EyeMode.FULL_CLEAN_RUNNING device.state.state = Dyson360EyeMode.FULL_CLEAN_RUNNING
device.state.battery_level = 85 device.state.battery_level = 85
device.state.power_mode = PowerMode.QUIET device.state.power_mode = PowerMode.QUIET
@ -31,159 +45,74 @@ def _get_vacuum_device_cleaning():
return device return device
def _get_vacuum_device_charging(): async def test_state(hass: HomeAssistant, device: Dyson360Eye) -> None:
"""Return a vacuum device charging.""" """Test the state of the vacuum."""
device = mock.Mock(spec=Dyson360Eye) er = await entity_registry.async_get_registry(hass)
device.name = "Device_Vacuum" assert er.async_get(ENTITY_ID).unique_id == SERIAL
device.state = mock.MagicMock()
state = hass.states.get(ENTITY_ID)
assert state.name == NAME
assert state.state == STATE_ON
attributes = state.attributes
assert attributes[ATTR_STATUS] == "Cleaning"
assert attributes[ATTR_SUPPORTED_FEATURES] == SUPPORT_DYSON
assert attributes[ATTR_BATTERY_LEVEL] == 85
assert attributes[ATTR_POSITION] == "(0, 0)"
assert attributes[ATTR_FAN_SPEED] == "Quiet"
assert attributes[ATTR_FAN_SPEED_LIST] == ["Quiet", "Max"]
device.state.state = Dyson360EyeMode.INACTIVE_CHARGING device.state.state = Dyson360EyeMode.INACTIVE_CHARGING
device.state.battery_level = 40 device.state.power_mode = PowerMode.MAX
device.state.power_mode = PowerMode.QUIET await async_update_device(hass, device)
device.state.position = (0, 0) state = hass.states.get(ENTITY_ID)
return device assert state.state == STATE_OFF
assert state.attributes[ATTR_STATUS] == "Stopped - Charging"
assert state.attributes[ATTR_FAN_SPEED] == "Max"
def _get_vacuum_device_pause():
"""Return a vacuum device in pause."""
device = mock.MagicMock(spec=Dyson360Eye)
device.name = "Device_Vacuum"
device.state = mock.MagicMock()
device.state.state = Dyson360EyeMode.FULL_CLEAN_PAUSED device.state.state = Dyson360EyeMode.FULL_CLEAN_PAUSED
device.state.battery_level = 40 await async_update_device(hass, device)
device.state.power_mode = PowerMode.QUIET state = hass.states.get(ENTITY_ID)
device.state.position = (0, 0) assert state.state == STATE_OFF
return device assert state.attributes[ATTR_STATUS] == "Paused"
def _get_vacuum_device_unknown_state(): @pytest.mark.parametrize(
"""Return a vacuum device with unknown state.""" "service,command,state",
device = mock.Mock(spec=Dyson360Eye) [
device.name = "Device_Vacuum" (SERVICE_TURN_ON, "start", Dyson360EyeMode.INACTIVE_CHARGED),
device.state = mock.MagicMock() (SERVICE_TURN_ON, "resume", Dyson360EyeMode.FULL_CLEAN_PAUSED),
device.state.state = "Unknown" (SERVICE_TURN_OFF, "pause", Dyson360EyeMode.FULL_CLEAN_RUNNING),
return device (SERVICE_STOP, "pause", Dyson360EyeMode.FULL_CLEAN_RUNNING),
(SERVICE_START_PAUSE, "pause", Dyson360EyeMode.FULL_CLEAN_RUNNING),
(SERVICE_START_PAUSE, "pause", Dyson360EyeMode.FULL_CLEAN_RUNNING),
(SERVICE_START_PAUSE, "start", Dyson360EyeMode.INACTIVE_CHARGED),
(SERVICE_START_PAUSE, "resume", Dyson360EyeMode.FULL_CLEAN_PAUSED),
(SERVICE_RETURN_TO_BASE, "abort", Dyson360EyeMode.FULL_CLEAN_PAUSED),
],
)
async def test_commands(
hass: HomeAssistant, device: Dyson360Eye, service: str, command: str, state: str
) -> None:
"""Test sending commands to the vacuum."""
device.state.state = state
await async_update_device(hass, device)
await hass.services.async_call(
PLATFORM_DOMAIN, service, {ATTR_ENTITY_ID: ENTITY_ID}, blocking=True
)
getattr(device, command).assert_called_once_with()
class DysonTest(unittest.TestCase): async def test_set_fan_speed(hass: HomeAssistant, device: Dyson360Eye):
"""Dyson 360 eye robot vacuum component test class.""" """Test setting fan speed of the vacuum."""
fan_speed_map = {
def setUp(self): # pylint: disable=invalid-name "Max": PowerMode.MAX,
"""Set up things to be run when tests are started.""" "Quiet": PowerMode.QUIET,
self.hass = get_test_home_assistant() }
self.addCleanup(self.tear_down_cleanup) for service_speed, command_speed in fan_speed_map.items():
await hass.services.async_call(
def tear_down_cleanup(self): PLATFORM_DOMAIN,
"""Stop everything that was started.""" SERVICE_SET_FAN_SPEED,
self.hass.stop() {ATTR_ENTITY_ID: ENTITY_ID, ATTR_FAN_SPEED: service_speed},
blocking=True,
def test_setup_component_with_no_devices(self): )
"""Test setup component with no devices.""" device.set_power_mode.assert_called_with(command_speed)
self.hass.data[dyson.DYSON_DEVICES] = []
add_entities = mock.MagicMock()
dyson.setup_platform(self.hass, {}, add_entities)
add_entities.assert_called_with([])
def test_setup_component(self):
"""Test setup component with devices."""
def _add_device(devices):
assert len(devices) == 1
assert devices[0].name == "Device_Vacuum"
device_vacuum = _get_vacuum_device_cleaning()
device_non_vacuum = _get_non_vacuum_device()
self.hass.data[dyson.DYSON_DEVICES] = [device_vacuum, device_non_vacuum]
dyson.setup_platform(self.hass, {}, _add_device)
def test_on_message(self):
"""Test when message is received."""
device = _get_vacuum_device_cleaning()
component = Dyson360EyeDevice(device)
component.entity_id = "entity_id"
component.schedule_update_ha_state = mock.Mock()
component.on_message(mock.Mock())
assert component.schedule_update_ha_state.called
def test_should_poll(self):
"""Test polling is disable."""
device = _get_vacuum_device_cleaning()
component = Dyson360EyeDevice(device)
assert not component.should_poll
def test_properties(self):
"""Test component properties."""
device1 = _get_vacuum_device_cleaning()
device2 = _get_vacuum_device_unknown_state()
device3 = _get_vacuum_device_charging()
component = Dyson360EyeDevice(device1)
component2 = Dyson360EyeDevice(device2)
component3 = Dyson360EyeDevice(device3)
assert component.name == "Device_Vacuum"
assert component.is_on
assert component.status == "Cleaning"
assert component2.status == "Unknown"
assert component.battery_level == 85
assert component.fan_speed == "Quiet"
assert component.fan_speed_list == ["Quiet", "Max"]
assert component.device_state_attributes["position"] == "(0, 0)"
assert component.available
assert component.supported_features == 255
assert component.battery_icon == "mdi:battery-80"
assert component3.battery_icon == "mdi:battery-charging-40"
def test_turn_on(self):
"""Test turn on vacuum."""
device1 = _get_vacuum_device_charging()
component1 = Dyson360EyeDevice(device1)
component1.turn_on()
assert device1.start.called
device2 = _get_vacuum_device_pause()
component2 = Dyson360EyeDevice(device2)
component2.turn_on()
assert device2.resume.called
def test_turn_off(self):
"""Test turn off vacuum."""
device1 = _get_vacuum_device_cleaning()
component1 = Dyson360EyeDevice(device1)
component1.turn_off()
assert device1.pause.called
def test_stop(self):
"""Test stop vacuum."""
device1 = _get_vacuum_device_cleaning()
component1 = Dyson360EyeDevice(device1)
component1.stop()
assert device1.pause.called
def test_set_fan_speed(self):
"""Test set fan speed vacuum."""
device1 = _get_vacuum_device_cleaning()
component1 = Dyson360EyeDevice(device1)
component1.set_fan_speed("Max")
device1.set_power_mode.assert_called_with(PowerMode.MAX)
def test_start_pause(self):
"""Test start/pause."""
device1 = _get_vacuum_device_charging()
component1 = Dyson360EyeDevice(device1)
component1.start_pause()
assert device1.start.called
device2 = _get_vacuum_device_pause()
component2 = Dyson360EyeDevice(device2)
component2.start_pause()
assert device2.resume.called
device3 = _get_vacuum_device_cleaning()
component3 = Dyson360EyeDevice(device3)
component3.start_pause()
assert device3.pause.called
def test_return_to_base(self):
"""Test return to base."""
device = _get_vacuum_device_pause()
component = Dyson360EyeDevice(device)
component.return_to_base()
assert device.abort.called