core/tests/components/ring/device_mocks.py

209 lines
7.0 KiB
Python

"""Module for ring device mocks.
Creates a MagicMock for all device families, i.e. chimes, doorbells, stickup_cams and other.
Each device entry in the devices.json will have a MagicMock instead of the RingObject.
Mocks the api calls on the devices such as history() and health().
"""
from datetime import datetime
from functools import partial
from unittest.mock import AsyncMock, MagicMock
from ring_doorbell import (
RingCapability,
RingChime,
RingDoorBell,
RingOther,
RingStickUpCam,
)
from ring_doorbell.const import DOORBELL_EXISTING_TYPE
from homeassistant.components.ring.const import DOMAIN
from homeassistant.util import dt as dt_util
from tests.common import load_json_value_fixture
DEVICES_FIXTURE = load_json_value_fixture("devices.json", DOMAIN)
DOORBOT_HISTORY = load_json_value_fixture("doorbot_history.json", DOMAIN)
INTERCOM_HISTORY = load_json_value_fixture("intercom_history.json", DOMAIN)
DOORBOT_HEALTH = load_json_value_fixture("doorbot_health_attrs.json", DOMAIN)
CHIME_HEALTH = load_json_value_fixture("chime_health_attrs.json", DOMAIN)
FRONT_DOOR_DEVICE_ID = 987654
INGRESS_DEVICE_ID = 185036587
FRONT_DEVICE_ID = 765432
INTERNAL_DEVICE_ID = 345678
DOWNSTAIRS_DEVICE_ID = 123456
def get_mock_devices():
"""Return list of mock devices keyed by device_type."""
devices = {}
for device_family, device_class in DEVICE_TYPES.items():
devices[device_family] = [
_mocked_ring_device(
device, device_family, device_class, DEVICE_CAPABILITIES[device_class]
)
for device in DEVICES_FIXTURE[device_family]
]
return devices
def get_devices_data():
"""Return devices raw json used by the diagnostics module."""
return {
device_type: {obj["id"]: obj for obj in devices}
for device_type, devices in DEVICES_FIXTURE.items()
}
DEVICE_TYPES = {
"doorbots": RingDoorBell,
"authorized_doorbots": RingDoorBell,
"stickup_cams": RingStickUpCam,
"chimes": RingChime,
"other": RingOther,
}
DEVICE_CAPABILITIES = {
RingDoorBell: [
RingCapability.BATTERY,
RingCapability.VOLUME,
RingCapability.MOTION_DETECTION,
RingCapability.VIDEO,
RingCapability.DING,
RingCapability.HISTORY,
],
RingStickUpCam: [
RingCapability.BATTERY,
RingCapability.VOLUME,
RingCapability.MOTION_DETECTION,
RingCapability.VIDEO,
RingCapability.HISTORY,
RingCapability.SIREN,
RingCapability.LIGHT,
],
RingChime: [RingCapability.VOLUME],
RingOther: [RingCapability.OPEN, RingCapability.HISTORY, RingCapability.DING],
}
def _mocked_ring_device(device_dict, device_family, device_class, capabilities):
"""Return a mocked device."""
mock_device = MagicMock(spec=device_class, name=f"Mocked {device_family!s}")
def has_capability(capability):
return (
capability in capabilities
if isinstance(capability, RingCapability)
else RingCapability.from_name(capability) in capabilities
)
def update_health_data(fixture):
mock_device.configure_mock(
wifi_signal_category=fixture["device_health"].get("latest_signal_category"),
wifi_signal_strength=fixture["device_health"].get("latest_signal_strength"),
)
def update_history_data(fixture):
for entry in fixture: # Mimic the api date parsing
if isinstance(entry["created_at"], str):
dt_at = datetime.strptime(entry["created_at"], "%Y-%m-%dT%H:%M:%S.%f%z")
entry["created_at"] = dt_util.as_utc(dt_at)
mock_device.configure_mock(last_history=fixture) # Set last_history
return fixture
# Configure the device attributes
mock_device.configure_mock(**device_dict)
# Configure the Properties on the device
mock_device.configure_mock(
model=device_family,
device_api_id=device_dict["id"],
name=device_dict["description"],
wifi_signal_category=None,
wifi_signal_strength=None,
family=device_family,
)
# Configure common methods
mock_device.has_capability.side_effect = has_capability
mock_device.async_update_health_data.side_effect = lambda: update_health_data(
DOORBOT_HEALTH if device_family != "chimes" else CHIME_HEALTH
)
# Configure methods based on capability
if has_capability(RingCapability.HISTORY):
mock_device.configure_mock(last_history=[])
mock_device.async_history.side_effect = lambda *_, **__: update_history_data(
DOORBOT_HISTORY if device_family != "other" else INTERCOM_HISTORY
)
if has_capability(RingCapability.VIDEO):
mock_device.async_recording_url = AsyncMock(return_value="http://dummy.url")
if has_capability(RingCapability.MOTION_DETECTION):
mock_device.configure_mock(
motion_detection=device_dict["settings"].get("motion_detection_enabled"),
)
mock_device.async_set_motion_detection.side_effect = (
lambda i: mock_device.configure_mock(motion_detection=i)
)
if has_capability(RingCapability.LIGHT):
mock_device.configure_mock(lights=device_dict.get("led_status"))
if has_capability(RingCapability.VOLUME):
mock_device.configure_mock(
volume=device_dict["settings"].get(
"doorbell_volume", device_dict["settings"].get("volume")
)
)
mock_device.async_set_volume.side_effect = lambda i: mock_device.configure_mock(
volume=i
)
if has_capability(RingCapability.SIREN):
mock_device.configure_mock(
siren=device_dict["siren_status"].get("seconds_remaining")
)
mock_device.async_set_siren.side_effect = lambda i: mock_device.configure_mock(
siren=i
)
if has_capability(RingCapability.BATTERY):
mock_device.configure_mock(
battery_life=min(
100, device_dict.get("battery_life", device_dict.get("battery_life2"))
)
)
if device_family == "doorbots":
mock_device.configure_mock(
existing_doorbell_type=DOORBELL_EXISTING_TYPE[
device_dict["settings"]["chime_settings"].get("type", 2)
]
)
mock_device.configure_mock(
existing_doorbell_type_enabled=device_dict["settings"][
"chime_settings"
].get("enable", False)
)
mock_device.async_set_existing_doorbell_type_enabled.side_effect = (
lambda i: mock_device.configure_mock(existing_doorbell_type_enabled=i)
)
if device_family == "other":
for prop in ("doorbell_volume", "mic_volume", "voice_volume"):
mock_device.configure_mock(
**{
prop: device_dict["settings"].get(prop),
f"async_set_{prop}.side_effect": partial(
setattr, mock_device, prop
),
}
)
return mock_device