Add tests for LitterRobot sensors (#78638)

This commit is contained in:
Robert Hillis 2022-09-19 00:12:38 -04:00 committed by GitHub
parent 9655f30146
commit aa0cbf0afe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 191 additions and 9 deletions

View file

@ -1,6 +1,4 @@
"""Common utils for Litter-Robot tests."""
from datetime import datetime
from homeassistant.components.litterrobot import DOMAIN
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
@ -11,7 +9,7 @@ ROBOT_NAME = "Test"
ROBOT_SERIAL = "LR3C012345"
ROBOT_DATA = {
"powerStatus": "AC",
"lastSeen": datetime.now().isoformat(),
"lastSeen": "2022-09-17T13:06:37.884Z",
"cleanCycleWaitTimeMinutes": "7",
"unitStatus": "RDY",
"litterRobotNickname": ROBOT_NAME,
@ -24,5 +22,123 @@ ROBOT_DATA = {
"nightLightActive": "1",
"sleepModeActive": "112:50:19",
}
ROBOT_4_DATA = {
"name": ROBOT_NAME,
"serial": "LR4C010001",
"userId": "1234567",
"espFirmware": "1.1.50",
"picFirmwareVersion": "10512.2560.2.53",
"laserBoardFirmwareVersion": "4.0.65.4",
"wifiRssi": -53.0,
"unitPowerType": "AC",
"catWeight": 12.0,
"unitTimezone": "America/New_York",
"unitTime": None,
"cleanCycleWaitTime": 15,
"isKeypadLockout": False,
"nightLightMode": "OFF",
"nightLightBrightness": 85,
"isPanelSleepMode": False,
"panelSleepTime": 0,
"panelWakeTime": 0,
"weekdaySleepModeEnabled": {
"Sunday": {"sleepTime": 0, "wakeTime": 0, "isEnabled": False},
"Monday": {"sleepTime": 0, "wakeTime": 180, "isEnabled": True},
"Tuesday": {"sleepTime": 0, "wakeTime": 180, "isEnabled": True},
"Wednesday": {"sleepTime": 0, "wakeTime": 180, "isEnabled": True},
"Thursday": {"sleepTime": 0, "wakeTime": 180, "isEnabled": True},
"Friday": {"sleepTime": 0, "wakeTime": 180, "isEnabled": True},
"Saturday": {"sleepTime": 0, "wakeTime": 0, "isEnabled": False},
},
"unitPowerStatus": "ON",
"sleepStatus": "WAKE",
"robotStatus": "ROBOT_IDLE",
"globeMotorFaultStatus": "FAULT_CLEAR",
"pinchStatus": "CLEAR",
"catDetect": "CAT_DETECT_CLEAR",
"isBonnetRemoved": False,
"isNightLightLEDOn": False,
"odometerPowerCycles": 8,
"odometerCleanCycles": 158,
"odometerEmptyCycles": 1,
"odometerFilterCycles": 0,
"isDFIResetPending": False,
"DFINumberOfCycles": 104,
"DFILevelPercent": 76,
"isDFIFull": True,
"DFIFullCounter": 3,
"DFITriggerCount": 42,
"litterLevel": 460,
"DFILevelMM": 115,
"isCatDetectPending": False,
"globeMotorRetractFaultStatus": "FAULT_CLEAR",
"robotCycleStatus": "CYCLE_IDLE",
"robotCycleState": "CYCLE_STATE_WAIT_ON",
"weightSensor": -3.0,
"isOnline": True,
"isOnboarded": True,
"isProvisioned": True,
"isDebugModeActive": False,
"lastSeen": "2022-09-17T12:06:37.884Z",
"sessionId": "abcdef12-e358-4b6c-9022-012345678912",
"setupDateTime": "2022-08-28T17:01:12.644Z",
"isFirmwareUpdateTriggered": False,
"firmwareUpdateStatus": "NONE",
"wifiModeStatus": "ROUTER_CONNECTED",
"isUSBPowerOn": True,
"USBFaultStatus": "CLEAR",
"isDFIPartialFull": True,
}
FEEDER_ROBOT_DATA = {
"id": 1,
"name": ROBOT_NAME,
"serial": "RF1C000001",
"timezone": "America/Denver",
"isEighthCupEnabled": False,
"created_at": "2021-12-15T06:45:00.000000+00:00",
"household_id": 1,
"state": {
"id": 1,
"info": {
"level": 2,
"power": True,
"online": True,
"acPower": True,
"dcPower": False,
"gravity": False,
"chuteFull": False,
"fwVersion": "1.0.0",
"onBoarded": True,
"unitMeals": 0,
"motorJammed": False,
"chuteFullExt": False,
"panelLockout": False,
"unitPortions": 0,
"autoNightMode": True,
"mealInsertSize": 1,
},
"updated_at": "2022-09-08T15:07:00.000000+00:00",
},
"feeding_snack": [
{"timestamp": "2022-09-04T03:03:00.000000+00:00", "amount": 0.125},
{"timestamp": "2022-08-30T16:34:00.000000+00:00", "amount": 0.25},
],
"feeding_meal": [
{
"timestamp": "2022-09-08T18:00:00.000000+00:00",
"amount": 0.125,
"meal_name": "Lunch",
"meal_number": 2,
"meal_total_portions": 2,
},
{
"timestamp": "2022-09-08T12:00:00.000000+00:00",
"amount": 0.125,
"meal_name": "Breakfast",
"meal_number": 1,
"meal_total_portions": 1,
},
],
}
VACUUM_ENTITY_ID = "vacuum.test_litter_box"

View file

@ -4,26 +4,35 @@ from __future__ import annotations
from typing import Any
from unittest.mock import AsyncMock, MagicMock, patch
from pylitterbot import Account, LitterRobot3, Robot
from pylitterbot import Account, FeederRobot, LitterRobot3, LitterRobot4, Robot
from pylitterbot.exceptions import InvalidCommandException
import pytest
from homeassistant.components import litterrobot
from homeassistant.core import HomeAssistant
from .common import CONFIG, ROBOT_DATA
from .common import CONFIG, FEEDER_ROBOT_DATA, ROBOT_4_DATA, ROBOT_DATA
from tests.common import MockConfigEntry
def create_mock_robot(
robot_data: dict | None, account: Account, side_effect: Any | None = None
robot_data: dict | None,
account: Account,
v4: bool,
feeder: bool,
side_effect: Any | None = None,
) -> Robot:
"""Create a mock Litter-Robot device."""
if not robot_data:
robot_data = {}
robot = LitterRobot3(data={**ROBOT_DATA, **robot_data}, account=account)
if v4:
robot = LitterRobot4(data={**ROBOT_4_DATA, **robot_data}, account=account)
elif feeder:
robot = FeederRobot(data={**FEEDER_ROBOT_DATA, **robot_data}, account=account)
else:
robot = LitterRobot3(data={**ROBOT_DATA, **robot_data}, account=account)
robot.start_cleaning = AsyncMock(side_effect=side_effect)
robot.set_power_status = AsyncMock(side_effect=side_effect)
robot.reset_waste_drawer = AsyncMock(side_effect=side_effect)
@ -39,13 +48,17 @@ def create_mock_account(
robot_data: dict | None = None,
side_effect: Any | None = None,
skip_robots: bool = False,
v4: bool = False,
feeder: bool = False,
) -> MagicMock:
"""Create a mock Litter-Robot account."""
account = MagicMock(spec=Account)
account.connect = AsyncMock()
account.refresh_robots = AsyncMock()
account.robots = (
[] if skip_robots else [create_mock_robot(robot_data, account, side_effect)]
[]
if skip_robots
else [create_mock_robot(robot_data, account, v4, feeder, side_effect)]
)
return account
@ -56,6 +69,18 @@ def mock_account() -> MagicMock:
return create_mock_account()
@pytest.fixture
def mock_account_with_litterrobot_4() -> MagicMock:
"""Mock account with Litter-Robot 4."""
return create_mock_account(v4=True)
@pytest.fixture
def mock_account_with_feederrobot() -> MagicMock:
"""Mock account with Feeder-Robot."""
return create_mock_account(feeder=True)
@pytest.fixture
def mock_account_with_no_robots() -> MagicMock:
"""Mock a Litter-Robot account."""

View file

@ -2,12 +2,13 @@
from unittest.mock import MagicMock
from homeassistant.components.sensor import DOMAIN as PLATFORM_DOMAIN, SensorDeviceClass
from homeassistant.const import PERCENTAGE, STATE_UNKNOWN
from homeassistant.const import MASS_POUNDS, PERCENTAGE, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from .conftest import setup_integration
WASTE_DRAWER_ENTITY_ID = "sensor.test_waste_drawer"
SLEEP_END_TIME_ENTITY_ID = "sensor.test_sleep_mode_end_time"
SLEEP_START_TIME_ENTITY_ID = "sensor.test_sleep_mode_start_time"
@ -36,6 +37,10 @@ async def test_sleep_time_sensor_with_sleep_disabled(
assert sensor.state == STATE_UNKNOWN
assert sensor.attributes["device_class"] == SensorDeviceClass.TIMESTAMP
sensor = hass.states.get(SLEEP_END_TIME_ENTITY_ID)
assert sensor.state == STATE_UNKNOWN
assert sensor.attributes["device_class"] == SensorDeviceClass.TIMESTAMP
async def test_gauge_icon() -> None:
"""Test icon generator for gauge sensor."""
@ -59,3 +64,39 @@ async def test_gauge_icon() -> None:
assert icon_for_gauge_level(40, 10) == GAUGE_LOW
assert icon_for_gauge_level(80, 10) == GAUGE
assert icon_for_gauge_level(100, 10) == GAUGE_FULL
async def test_litter_robot_sensor(
hass: HomeAssistant, mock_account_with_litterrobot_4: MagicMock
) -> None:
"""Tests Litter-Robot sensors."""
await setup_integration(hass, mock_account_with_litterrobot_4, PLATFORM_DOMAIN)
sensor = hass.states.get(SLEEP_START_TIME_ENTITY_ID)
assert sensor.state == "2022-09-19T04:00:00+00:00"
assert sensor.attributes["device_class"] == SensorDeviceClass.TIMESTAMP
sensor = hass.states.get(SLEEP_END_TIME_ENTITY_ID)
assert sensor.state == "2022-09-16T07:00:00+00:00"
assert sensor.attributes["device_class"] == SensorDeviceClass.TIMESTAMP
sensor = hass.states.get("sensor.test_last_seen")
assert sensor.state == "2022-09-17T12:06:37+00:00"
assert sensor.attributes["device_class"] == SensorDeviceClass.TIMESTAMP
sensor = hass.states.get("sensor.test_status_code")
assert sensor.state == "dfs"
assert sensor.attributes["device_class"] == "litterrobot__status_code"
sensor = hass.states.get("sensor.test_litter_level")
assert sensor.state == "70.0"
assert sensor.attributes["unit_of_measurement"] == PERCENTAGE
sensor = hass.states.get("sensor.test_pet_weight")
assert sensor.state == "12.0"
assert sensor.attributes["unit_of_measurement"] == MASS_POUNDS
async def test_feeder_robot_sensor(
hass: HomeAssistant, mock_account_with_feederrobot: MagicMock
) -> None:
"""Tests Feeder-Robot sensors."""
await setup_integration(hass, mock_account_with_feederrobot, PLATFORM_DOMAIN)
sensor = hass.states.get("sensor.test_food_level")
assert sensor.state == "20"
assert sensor.attributes["unit_of_measurement"] == PERCENTAGE