mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
UniFi Protect test refactoring (#63486)
* UniFi Protect test refactoring * More pylint fixes * Use load_fixture helper * yield to return where able
This commit is contained in:
parent
8864492e35
commit
d0d5222bf4
@ -1,81 +1,37 @@
|
|||||||
"""Fixtures and test data for UniFi Protect methods."""
|
"""Fixtures and test data for UniFi Protect methods."""
|
||||||
|
# pylint: disable=protected-access
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from ipaddress import IPv4Address
|
from ipaddress import IPv4Address
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any, Callable
|
from typing import Any, Callable
|
||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import AsyncMock, Mock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pyunifiprotect.data import Camera, Light, Version, WSSubscriptionMessage
|
from pyunifiprotect.data import Camera, Light, WSSubscriptionMessage
|
||||||
from pyunifiprotect.data.base import ProtectAdoptableDeviceModel
|
from pyunifiprotect.data.base import ProtectAdoptableDeviceModel
|
||||||
from pyunifiprotect.data.devices import Viewer
|
from pyunifiprotect.data.devices import Sensor, Viewer
|
||||||
from pyunifiprotect.data.nvr import DoorbellMessage, Liveview
|
from pyunifiprotect.data.nvr import NVR, Liveview
|
||||||
from pyunifiprotect.data.types import DoorbellMessageType, ModelType
|
|
||||||
|
|
||||||
from homeassistant.components.unifiprotect.const import DOMAIN, MIN_REQUIRED_PROTECT_V
|
from homeassistant.components.unifiprotect.const import DOMAIN
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant, split_entity_id
|
from homeassistant.core import HomeAssistant, split_entity_id
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.helpers.entity import EntityDescription
|
from homeassistant.helpers.entity import EntityDescription
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture
|
||||||
|
|
||||||
MAC_ADDR = "aa:bb:cc:dd:ee:ff"
|
MAC_ADDR = "aa:bb:cc:dd:ee:ff"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MockPortData:
|
|
||||||
"""Mock Port information."""
|
|
||||||
|
|
||||||
rtsp: int = 7441
|
|
||||||
rtsps: int = 7447
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MockDoorbellSettings:
|
|
||||||
"""Mock Port information."""
|
|
||||||
|
|
||||||
default_message_text = "Welcome"
|
|
||||||
all_messages = [
|
|
||||||
DoorbellMessage(
|
|
||||||
type=DoorbellMessageType.LEAVE_PACKAGE_AT_DOOR,
|
|
||||||
text=DoorbellMessageType.LEAVE_PACKAGE_AT_DOOR.value.replace("_", " "),
|
|
||||||
),
|
|
||||||
DoorbellMessage(
|
|
||||||
type=DoorbellMessageType.DO_NOT_DISTURB,
|
|
||||||
text=DoorbellMessageType.DO_NOT_DISTURB.value.replace("_", " "),
|
|
||||||
),
|
|
||||||
DoorbellMessage(
|
|
||||||
type=DoorbellMessageType.CUSTOM_MESSAGE,
|
|
||||||
text="Test",
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MockNvrData:
|
|
||||||
"""Mock for NVR."""
|
|
||||||
|
|
||||||
version: Version
|
|
||||||
mac: str
|
|
||||||
name: str
|
|
||||||
id: str
|
|
||||||
ports: MockPortData = MockPortData()
|
|
||||||
doorbell_settings = MockDoorbellSettings()
|
|
||||||
update_all_messages = Mock()
|
|
||||||
model: ModelType = ModelType.NVR
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MockBootstrap:
|
class MockBootstrap:
|
||||||
"""Mock for Bootstrap."""
|
"""Mock for Bootstrap."""
|
||||||
|
|
||||||
nvr: MockNvrData
|
nvr: NVR
|
||||||
cameras: dict[str, Any]
|
cameras: dict[str, Any]
|
||||||
lights: dict[str, Any]
|
lights: dict[str, Any]
|
||||||
sensors: dict[str, Any]
|
sensors: dict[str, Any]
|
||||||
@ -99,28 +55,51 @@ class MockEntityFixture:
|
|||||||
api: Mock
|
api: Mock
|
||||||
|
|
||||||
|
|
||||||
MOCK_NVR_DATA = MockNvrData(
|
@pytest.fixture(name="mock_nvr")
|
||||||
version=MIN_REQUIRED_PROTECT_V, mac=MAC_ADDR, name="UnifiProtect", id="test_id"
|
def mock_nvr_fixture():
|
||||||
)
|
"""Mock UniFi Protect Camera device."""
|
||||||
MOCK_OLD_NVR_DATA = MockNvrData(
|
|
||||||
version=Version("1.19.0"), mac=MAC_ADDR, name="UnifiProtect", id="test_id"
|
|
||||||
)
|
|
||||||
|
|
||||||
MOCK_BOOTSTRAP = MockBootstrap(
|
data = json.loads(load_fixture("sample_nvr.json", integration=DOMAIN))
|
||||||
nvr=MOCK_NVR_DATA, cameras={}, lights={}, sensors={}, viewers={}, liveviews={}
|
nvr = NVR.from_unifi_dict(**data)
|
||||||
|
|
||||||
|
# disable pydantic validation so mocking can happen
|
||||||
|
NVR.__config__.validate_assignment = False
|
||||||
|
|
||||||
|
yield nvr
|
||||||
|
|
||||||
|
NVR.__config__.validate_assignment = True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="mock_old_nvr")
|
||||||
|
def mock_old_nvr_fixture():
|
||||||
|
"""Mock UniFi Protect Camera device."""
|
||||||
|
|
||||||
|
data = json.loads(load_fixture("sample_nvr.json", integration=DOMAIN))
|
||||||
|
data["version"] = "1.19.0"
|
||||||
|
return NVR.from_unifi_dict(**data)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="mock_bootstrap")
|
||||||
|
def mock_bootstrap_fixture(mock_nvr: NVR):
|
||||||
|
"""Mock Bootstrap fixture."""
|
||||||
|
return MockBootstrap(
|
||||||
|
nvr=mock_nvr, cameras={}, lights={}, sensors={}, viewers={}, liveviews={}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_client():
|
def mock_client(mock_bootstrap: MockBootstrap):
|
||||||
"""Mock ProtectApiClient for testing."""
|
"""Mock ProtectApiClient for testing."""
|
||||||
client = Mock()
|
client = Mock()
|
||||||
client.bootstrap = MOCK_BOOTSTRAP
|
client.bootstrap = mock_bootstrap
|
||||||
|
|
||||||
|
nvr = mock_bootstrap.nvr
|
||||||
|
nvr._api = client
|
||||||
|
|
||||||
client.base_url = "https://127.0.0.1"
|
client.base_url = "https://127.0.0.1"
|
||||||
client.connection_host = IPv4Address("127.0.0.1")
|
client.connection_host = IPv4Address("127.0.0.1")
|
||||||
client.get_nvr = AsyncMock(return_value=MOCK_NVR_DATA)
|
client.get_nvr = AsyncMock(return_value=nvr)
|
||||||
client.update = AsyncMock(return_value=MOCK_BOOTSTRAP)
|
client.update = AsyncMock(return_value=mock_bootstrap)
|
||||||
client.async_disconnect_ws = AsyncMock()
|
client.async_disconnect_ws = AsyncMock()
|
||||||
|
|
||||||
def subscribe(ws_callback: Callable[[WSSubscriptionMessage], None]) -> Any:
|
def subscribe(ws_callback: Callable[[WSSubscriptionMessage], None]) -> Any:
|
||||||
@ -162,44 +141,40 @@ def mock_entry(
|
|||||||
def mock_liveview():
|
def mock_liveview():
|
||||||
"""Mock UniFi Protect Camera device."""
|
"""Mock UniFi Protect Camera device."""
|
||||||
|
|
||||||
path = Path(__file__).parent / "sample_data" / "sample_liveview.json"
|
data = json.loads(load_fixture("sample_liveview.json", integration=DOMAIN))
|
||||||
with open(path, encoding="utf-8") as json_file:
|
return Liveview.from_unifi_dict(**data)
|
||||||
data = json.load(json_file)
|
|
||||||
|
|
||||||
yield Liveview.from_unifi_dict(**data)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_camera():
|
def mock_camera():
|
||||||
"""Mock UniFi Protect Camera device."""
|
"""Mock UniFi Protect Camera device."""
|
||||||
|
|
||||||
path = Path(__file__).parent / "sample_data" / "sample_camera.json"
|
data = json.loads(load_fixture("sample_camera.json", integration=DOMAIN))
|
||||||
with open(path, encoding="utf-8") as json_file:
|
return Camera.from_unifi_dict(**data)
|
||||||
data = json.load(json_file)
|
|
||||||
|
|
||||||
yield Camera.from_unifi_dict(**data)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_light():
|
def mock_light():
|
||||||
"""Mock UniFi Protect Camera device."""
|
"""Mock UniFi Protect Camera device."""
|
||||||
|
|
||||||
path = Path(__file__).parent / "sample_data" / "sample_light.json"
|
data = json.loads(load_fixture("sample_light.json", integration=DOMAIN))
|
||||||
with open(path, encoding="utf-8") as json_file:
|
return Light.from_unifi_dict(**data)
|
||||||
data = json.load(json_file)
|
|
||||||
|
|
||||||
yield Light.from_unifi_dict(**data)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_viewer():
|
def mock_viewer():
|
||||||
"""Mock UniFi Protect Viewport device."""
|
"""Mock UniFi Protect Viewport device."""
|
||||||
|
|
||||||
path = Path(__file__).parent / "sample_data" / "sample_viewport.json"
|
data = json.loads(load_fixture("sample_viewport.json", integration=DOMAIN))
|
||||||
with open(path, encoding="utf-8") as json_file:
|
return Viewer.from_unifi_dict(**data)
|
||||||
data = json.load(json_file)
|
|
||||||
|
|
||||||
yield Viewer.from_unifi_dict(**data)
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_sensor():
|
||||||
|
"""Mock UniFi Protect Sensor device."""
|
||||||
|
|
||||||
|
data = json.loads(load_fixture("sample_sensor.json", integration=DOMAIN))
|
||||||
|
return Sensor.from_unifi_dict(**data)
|
||||||
|
|
||||||
|
|
||||||
async def time_changed(hass: HomeAssistant, seconds: int) -> None:
|
async def time_changed(hass: HomeAssistant, seconds: int) -> None:
|
||||||
|
236
tests/components/unifiprotect/fixtures/sample_nvr.json
Normal file
236
tests/components/unifiprotect/fixtures/sample_nvr.json
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
{
|
||||||
|
"mac": "A1E00C826924",
|
||||||
|
"host": "192.168.216.198",
|
||||||
|
"name": "UnifiProtect",
|
||||||
|
"canAutoUpdate": true,
|
||||||
|
"isStatsGatheringEnabled": true,
|
||||||
|
"timezone": "America/New_York",
|
||||||
|
"version": "1.21.0-beta.2",
|
||||||
|
"ucoreVersion": "2.3.26",
|
||||||
|
"firmwareVersion": "2.3.10",
|
||||||
|
"uiVersion": null,
|
||||||
|
"hardwarePlatform": "al324",
|
||||||
|
"ports": {
|
||||||
|
"ump": 7449,
|
||||||
|
"http": 7080,
|
||||||
|
"https": 7443,
|
||||||
|
"rtsp": 7447,
|
||||||
|
"rtsps": 7441,
|
||||||
|
"rtmp": 1935,
|
||||||
|
"devicesWss": 7442,
|
||||||
|
"cameraHttps": 7444,
|
||||||
|
"cameraTcp": 7877,
|
||||||
|
"liveWs": 7445,
|
||||||
|
"liveWss": 7446,
|
||||||
|
"tcpStreams": 7448,
|
||||||
|
"playback": 7450,
|
||||||
|
"emsCLI": 7440,
|
||||||
|
"emsLiveFLV": 7550,
|
||||||
|
"cameraEvents": 7551,
|
||||||
|
"tcpBridge": 7888,
|
||||||
|
"ucore": 11081,
|
||||||
|
"discoveryClient": 0
|
||||||
|
},
|
||||||
|
"uptime": 1191516000,
|
||||||
|
"lastSeen": 1641269019283,
|
||||||
|
"isUpdating": false,
|
||||||
|
"lastUpdateAt": null,
|
||||||
|
"isStation": false,
|
||||||
|
"enableAutomaticBackups": true,
|
||||||
|
"enableStatsReporting": false,
|
||||||
|
"isSshEnabled": false,
|
||||||
|
"errorCode": null,
|
||||||
|
"releaseChannel": "beta",
|
||||||
|
"ssoChannel": null,
|
||||||
|
"hosts": [
|
||||||
|
"192.168.216.198"
|
||||||
|
],
|
||||||
|
"enableBridgeAutoAdoption": true,
|
||||||
|
"hardwareId": "baf4878d-df21-4427-9fbe-c2ef15301412",
|
||||||
|
"hardwareRevision": "113-03137-22",
|
||||||
|
"hostType": 59936,
|
||||||
|
"hostShortname": "UNVRPRO",
|
||||||
|
"isHardware": true,
|
||||||
|
"isWirelessUplinkEnabled": false,
|
||||||
|
"timeFormat": "24h",
|
||||||
|
"temperatureUnit": "C",
|
||||||
|
"recordingRetentionDurationMs": null,
|
||||||
|
"enableCrashReporting": true,
|
||||||
|
"disableAudio": false,
|
||||||
|
"analyticsData": "anonymous",
|
||||||
|
"anonymousDeviceId": "65257f7d-874c-498a-8f1b-00b2dd0a7ae1",
|
||||||
|
"cameraUtilization": 30,
|
||||||
|
"isRecycling": false,
|
||||||
|
"avgMotions": [
|
||||||
|
21.29,
|
||||||
|
14,
|
||||||
|
5.43,
|
||||||
|
2.29,
|
||||||
|
6.43,
|
||||||
|
7.43,
|
||||||
|
16.86,
|
||||||
|
17,
|
||||||
|
24.71,
|
||||||
|
36.86,
|
||||||
|
46.43,
|
||||||
|
47.57,
|
||||||
|
51.57,
|
||||||
|
52.71,
|
||||||
|
63.86,
|
||||||
|
80.86,
|
||||||
|
86.71,
|
||||||
|
91.71,
|
||||||
|
96.57,
|
||||||
|
71.14,
|
||||||
|
57,
|
||||||
|
53.71,
|
||||||
|
39.57,
|
||||||
|
21.29
|
||||||
|
],
|
||||||
|
"disableAutoLink": false,
|
||||||
|
"skipFirmwareUpdate": false,
|
||||||
|
"wifiSettings": {
|
||||||
|
"useThirdPartyWifi": false,
|
||||||
|
"ssid": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"locationSettings": {
|
||||||
|
"isAway": true,
|
||||||
|
"isGeofencingEnabled": false,
|
||||||
|
"latitude": 41.4519,
|
||||||
|
"longitude": -81.921,
|
||||||
|
"radius": 200
|
||||||
|
},
|
||||||
|
"featureFlags": {
|
||||||
|
"beta": false,
|
||||||
|
"dev": false,
|
||||||
|
"notificationsV2": true
|
||||||
|
},
|
||||||
|
"systemInfo": {
|
||||||
|
"cpu": {
|
||||||
|
"averageLoad": 5,
|
||||||
|
"temperature": 70
|
||||||
|
},
|
||||||
|
"memory": {
|
||||||
|
"available": 6481504,
|
||||||
|
"free": 87080,
|
||||||
|
"total": 8163024
|
||||||
|
},
|
||||||
|
"storage": {
|
||||||
|
"available": 21796939214848,
|
||||||
|
"isRecycling": false,
|
||||||
|
"size": 31855989432320,
|
||||||
|
"type": "raid",
|
||||||
|
"used": 8459815895040,
|
||||||
|
"devices": [
|
||||||
|
{
|
||||||
|
"model": "ST16000VE000-2L2103",
|
||||||
|
"size": 16000900661248,
|
||||||
|
"healthy": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "ST16000VE000-2L2103",
|
||||||
|
"size": 16000900661248,
|
||||||
|
"healthy": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "ST16000VE000-2L2103",
|
||||||
|
"size": 16000900661248,
|
||||||
|
"healthy": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tmpfs": {
|
||||||
|
"available": 934204,
|
||||||
|
"total": 1048576,
|
||||||
|
"used": 114372,
|
||||||
|
"path": "/var/opt/unifi-protect/tmp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"doorbellSettings": {
|
||||||
|
"defaultMessageText": "Welcome",
|
||||||
|
"defaultMessageResetTimeoutMs": 60000,
|
||||||
|
"customMessages": [
|
||||||
|
"Come In!",
|
||||||
|
"Use Other Door"
|
||||||
|
],
|
||||||
|
"allMessages": [
|
||||||
|
{
|
||||||
|
"type": "LEAVE_PACKAGE_AT_DOOR",
|
||||||
|
"text": "LEAVE PACKAGE AT DOOR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "DO_NOT_DISTURB",
|
||||||
|
"text": "DO NOT DISTURB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CUSTOM_MESSAGE",
|
||||||
|
"text": "Test"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"smartDetectAgreement": {
|
||||||
|
"status": "agreed",
|
||||||
|
"lastUpdateAt": 1606964227734
|
||||||
|
},
|
||||||
|
"storageStats": {
|
||||||
|
"utilization": 26.61384533704469,
|
||||||
|
"capacity": 5706909122,
|
||||||
|
"remainingCapacity": 4188081155,
|
||||||
|
"recordingSpace": {
|
||||||
|
"total": 31787269955584,
|
||||||
|
"used": 8459814862848,
|
||||||
|
"available": 23327455092736
|
||||||
|
},
|
||||||
|
"storageDistribution": {
|
||||||
|
"recordingTypeDistributions": [
|
||||||
|
{
|
||||||
|
"recordingType": "rotating",
|
||||||
|
"size": 7736989099040,
|
||||||
|
"percentage": 91.47686438351941
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recordingType": "timelapse",
|
||||||
|
"size": 21474836480,
|
||||||
|
"percentage": 0.2539037704709915
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recordingType": "detections",
|
||||||
|
"size": 699400412128,
|
||||||
|
"percentage": 8.269231846009593
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"resolutionDistributions": [
|
||||||
|
{
|
||||||
|
"resolution": "HD",
|
||||||
|
"size": 2896955441152,
|
||||||
|
"percentage": 9.113571077981481
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resolution": "4K",
|
||||||
|
"size": 5560908906496,
|
||||||
|
"percentage": 17.494138107066746
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resolution": "free",
|
||||||
|
"size": 23329405607936,
|
||||||
|
"percentage": 73.39229081495176
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": "test_id",
|
||||||
|
"isAway": true,
|
||||||
|
"isSetup": true,
|
||||||
|
"network": "Ethernet",
|
||||||
|
"type": "UNVR-PRO",
|
||||||
|
"upSince": 1640077503063,
|
||||||
|
"isRecordingDisabled": false,
|
||||||
|
"isRecordingMotionOnly": false,
|
||||||
|
"maxCameraCapacity": {
|
||||||
|
"4K": 20,
|
||||||
|
"2K": 30,
|
||||||
|
"HD": 60
|
||||||
|
},
|
||||||
|
"modelKey": "nvr"
|
||||||
|
}
|
92
tests/components/unifiprotect/fixtures/sample_sensor.json
Normal file
92
tests/components/unifiprotect/fixtures/sample_sensor.json
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"mac": "26DBAFF133A4",
|
||||||
|
"connectionHost": "192.168.216.198",
|
||||||
|
"type": "UFP-SENSE",
|
||||||
|
"name": "Egdczv Urg",
|
||||||
|
"upSince": 1641256963255,
|
||||||
|
"uptime": null,
|
||||||
|
"lastSeen": 1641259127934,
|
||||||
|
"connectedSince": 1641259139255,
|
||||||
|
"state": "CONNECTED",
|
||||||
|
"hardwareRevision": 6,
|
||||||
|
"firmwareVersion": "1.0.2",
|
||||||
|
"latestFirmwareVersion": "1.0.2",
|
||||||
|
"firmwareBuild": null,
|
||||||
|
"isUpdating": false,
|
||||||
|
"isAdopting": false,
|
||||||
|
"isAdopted": true,
|
||||||
|
"isAdoptedByOther": false,
|
||||||
|
"isProvisioned": false,
|
||||||
|
"isRebooting": false,
|
||||||
|
"isSshEnabled": false,
|
||||||
|
"canAdopt": false,
|
||||||
|
"isAttemptingToConnect": false,
|
||||||
|
"isMotionDetected": false,
|
||||||
|
"mountType": "door",
|
||||||
|
"leakDetectedAt": null,
|
||||||
|
"tamperingDetectedAt": null,
|
||||||
|
"isOpened": true,
|
||||||
|
"openStatusChangedAt": 1641269036582,
|
||||||
|
"alarmTriggeredAt": null,
|
||||||
|
"motionDetectedAt": 1641269044824,
|
||||||
|
"wiredConnectionState": {
|
||||||
|
"phyRate": null
|
||||||
|
},
|
||||||
|
"stats": {
|
||||||
|
"light": {
|
||||||
|
"value": 0,
|
||||||
|
"status": "neutral"
|
||||||
|
},
|
||||||
|
"humidity": {
|
||||||
|
"value": 35,
|
||||||
|
"status": "neutral"
|
||||||
|
},
|
||||||
|
"temperature": {
|
||||||
|
"value": 17.23,
|
||||||
|
"status": "neutral"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bluetoothConnectionState": {
|
||||||
|
"signalQuality": 15,
|
||||||
|
"signalStrength": -84
|
||||||
|
},
|
||||||
|
"batteryStatus": {
|
||||||
|
"percentage": 100,
|
||||||
|
"isLow": false
|
||||||
|
},
|
||||||
|
"alarmSettings": {
|
||||||
|
"isEnabled": false
|
||||||
|
},
|
||||||
|
"lightSettings": {
|
||||||
|
"isEnabled": true,
|
||||||
|
"lowThreshold": null,
|
||||||
|
"highThreshold": null,
|
||||||
|
"margin": 10
|
||||||
|
},
|
||||||
|
"motionSettings": {
|
||||||
|
"isEnabled": true,
|
||||||
|
"sensitivity": 100
|
||||||
|
},
|
||||||
|
"temperatureSettings": {
|
||||||
|
"isEnabled": true,
|
||||||
|
"lowThreshold": null,
|
||||||
|
"highThreshold": null,
|
||||||
|
"margin": 0.1
|
||||||
|
},
|
||||||
|
"humiditySettings": {
|
||||||
|
"isEnabled": true,
|
||||||
|
"lowThreshold": null,
|
||||||
|
"highThreshold": null,
|
||||||
|
"margin": 1
|
||||||
|
},
|
||||||
|
"ledSettings": {
|
||||||
|
"isEnabled": true
|
||||||
|
},
|
||||||
|
"bridge": "61b3f5c90050a703e700042a",
|
||||||
|
"camera": "2f9beb2e6f79af3c32c22d49",
|
||||||
|
"bridgeCandidates": [],
|
||||||
|
"id": "f6ecbe829f81cc79ad6e0c9a",
|
||||||
|
"isConnected": true,
|
||||||
|
"marketName": "UP Sense",
|
||||||
|
"modelKey": "sensor"
|
||||||
|
}
|
@ -37,7 +37,7 @@ async def camera_fixture(
|
|||||||
|
|
||||||
assert_entity_counts(hass, Platform.BUTTON, 1, 0)
|
assert_entity_counts(hass, Platform.BUTTON, 1, 0)
|
||||||
|
|
||||||
yield (camera_obj, "button.test_camera_reboot_device")
|
return (camera_obj, "button.test_camera_reboot_device")
|
||||||
|
|
||||||
|
|
||||||
async def test_button(
|
async def test_button(
|
||||||
|
@ -70,7 +70,7 @@ async def camera_fixture(
|
|||||||
|
|
||||||
assert_entity_counts(hass, Platform.CAMERA, 2, 1)
|
assert_entity_counts(hass, Platform.CAMERA, 2, 1)
|
||||||
|
|
||||||
yield (camera_obj, "camera.test_camera_high")
|
return (camera_obj, "camera.test_camera_high")
|
||||||
|
|
||||||
|
|
||||||
def validate_default_camera_entity(
|
def validate_default_camera_entity(
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from pyunifiprotect import NotAuthorized, NvrError
|
from pyunifiprotect import NotAuthorized, NvrError
|
||||||
|
from pyunifiprotect.data.nvr import NVR
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.unifiprotect.const import (
|
from homeassistant.components.unifiprotect.const import (
|
||||||
@ -20,12 +21,12 @@ from homeassistant.data_entry_flow import (
|
|||||||
)
|
)
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
|
||||||
from .conftest import MAC_ADDR, MOCK_NVR_DATA, MOCK_OLD_NVR_DATA
|
from .conftest import MAC_ADDR
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def test_form(hass: HomeAssistant) -> None:
|
async def test_form(hass: HomeAssistant, mock_nvr: NVR) -> None:
|
||||||
"""Test we get the form."""
|
"""Test we get the form."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
@ -35,7 +36,7 @@ async def test_form(hass: HomeAssistant) -> None:
|
|||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.unifiprotect.config_flow.ProtectApiClient.get_nvr",
|
"homeassistant.components.unifiprotect.config_flow.ProtectApiClient.get_nvr",
|
||||||
return_value=MOCK_NVR_DATA,
|
return_value=mock_nvr,
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.unifiprotect.async_setup_entry",
|
"homeassistant.components.unifiprotect.async_setup_entry",
|
||||||
return_value=True,
|
return_value=True,
|
||||||
@ -63,7 +64,7 @@ async def test_form(hass: HomeAssistant) -> None:
|
|||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_form_version_too_old(hass: HomeAssistant) -> None:
|
async def test_form_version_too_old(hass: HomeAssistant, mock_old_nvr: NVR) -> None:
|
||||||
"""Test we handle the version being too old."""
|
"""Test we handle the version being too old."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
@ -71,7 +72,7 @@ async def test_form_version_too_old(hass: HomeAssistant) -> None:
|
|||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.unifiprotect.config_flow.ProtectApiClient.get_nvr",
|
"homeassistant.components.unifiprotect.config_flow.ProtectApiClient.get_nvr",
|
||||||
return_value=MOCK_OLD_NVR_DATA,
|
return_value=mock_old_nvr,
|
||||||
):
|
):
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
@ -132,7 +133,7 @@ async def test_form_cannot_connect(hass: HomeAssistant) -> None:
|
|||||||
assert result2["errors"] == {"base": "cannot_connect"}
|
assert result2["errors"] == {"base": "cannot_connect"}
|
||||||
|
|
||||||
|
|
||||||
async def test_form_reauth_auth(hass: HomeAssistant) -> None:
|
async def test_form_reauth_auth(hass: HomeAssistant, mock_nvr: NVR) -> None:
|
||||||
"""Test we handle reauth auth."""
|
"""Test we handle reauth auth."""
|
||||||
mock_config = MockConfigEntry(
|
mock_config = MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
@ -176,7 +177,7 @@ async def test_form_reauth_auth(hass: HomeAssistant) -> None:
|
|||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.unifiprotect.config_flow.ProtectApiClient.get_nvr",
|
"homeassistant.components.unifiprotect.config_flow.ProtectApiClient.get_nvr",
|
||||||
return_value=MOCK_NVR_DATA,
|
return_value=mock_nvr,
|
||||||
):
|
):
|
||||||
result3 = await hass.config_entries.flow.async_configure(
|
result3 = await hass.config_entries.flow.async_configure(
|
||||||
result2["flow_id"],
|
result2["flow_id"],
|
||||||
|
@ -4,12 +4,13 @@ from __future__ import annotations
|
|||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from pyunifiprotect import NotAuthorized, NvrError
|
from pyunifiprotect import NotAuthorized, NvrError
|
||||||
|
from pyunifiprotect.data import NVR
|
||||||
|
|
||||||
from homeassistant.components.unifiprotect.const import CONF_DISABLE_RTSP
|
from homeassistant.components.unifiprotect.const import CONF_DISABLE_RTSP
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .conftest import MOCK_OLD_NVR_DATA, MockEntityFixture
|
from .conftest import MockEntityFixture
|
||||||
|
|
||||||
|
|
||||||
async def test_setup(hass: HomeAssistant, mock_entry: MockEntityFixture):
|
async def test_setup(hass: HomeAssistant, mock_entry: MockEntityFixture):
|
||||||
@ -51,10 +52,12 @@ async def test_unload(hass: HomeAssistant, mock_entry: MockEntityFixture):
|
|||||||
assert mock_entry.api.async_disconnect_ws.called
|
assert mock_entry.api.async_disconnect_ws.called
|
||||||
|
|
||||||
|
|
||||||
async def test_setup_too_old(hass: HomeAssistant, mock_entry: MockEntityFixture):
|
async def test_setup_too_old(
|
||||||
|
hass: HomeAssistant, mock_entry: MockEntityFixture, mock_old_nvr: NVR
|
||||||
|
):
|
||||||
"""Test setup of unifiprotect entry with too old of version of UniFi Protect."""
|
"""Test setup of unifiprotect entry with too old of version of UniFi Protect."""
|
||||||
|
|
||||||
mock_entry.api.get_nvr.return_value = MOCK_OLD_NVR_DATA
|
mock_entry.api.get_nvr.return_value = mock_old_nvr
|
||||||
|
|
||||||
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
await hass.config_entries.async_setup(mock_entry.entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@ -200,10 +200,10 @@ async def test_number_setup_camera_missing_attr(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("description", LIGHT_NUMBERS)
|
@pytest.mark.parametrize("description", LIGHT_NUMBERS)
|
||||||
async def test_switch_light_simple(
|
async def test_number_light_simple(
|
||||||
hass: HomeAssistant, light: Light, description: ProtectNumberEntityDescription
|
hass: HomeAssistant, light: Light, description: ProtectNumberEntityDescription
|
||||||
):
|
):
|
||||||
"""Tests all simple switches for lights."""
|
"""Tests all simple numbers for lights."""
|
||||||
|
|
||||||
assert description.ufp_set_function is not None
|
assert description.ufp_set_function is not None
|
||||||
|
|
||||||
@ -224,10 +224,10 @@ async def test_switch_light_simple(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("description", CAMERA_NUMBERS)
|
@pytest.mark.parametrize("description", CAMERA_NUMBERS)
|
||||||
async def test_switch_camera_simple(
|
async def test_number_camera_simple(
|
||||||
hass: HomeAssistant, camera: Camera, description: ProtectNumberEntityDescription
|
hass: HomeAssistant, camera: Camera, description: ProtectNumberEntityDescription
|
||||||
):
|
):
|
||||||
"""Tests all simple switches for cameras."""
|
"""Tests all simple numbers for cameras."""
|
||||||
|
|
||||||
assert description.ufp_set_function is not None
|
assert description.ufp_set_function is not None
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
"""Test the UniFi Protect number platform."""
|
"""Test the UniFi Protect select platform."""
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ async def viewer_fixture(
|
|||||||
mock_viewer: Viewer,
|
mock_viewer: Viewer,
|
||||||
mock_liveview: Liveview,
|
mock_liveview: Liveview,
|
||||||
):
|
):
|
||||||
"""Fixture for a single viewport for testing the number platform."""
|
"""Fixture for a single viewport for testing the select platform."""
|
||||||
|
|
||||||
# disable pydantic validation so mocking can happen
|
# disable pydantic validation so mocking can happen
|
||||||
Viewer.__config__.validate_assignment = False
|
Viewer.__config__.validate_assignment = False
|
||||||
@ -81,7 +81,7 @@ async def viewer_fixture(
|
|||||||
async def camera_fixture(
|
async def camera_fixture(
|
||||||
hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera
|
hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera
|
||||||
):
|
):
|
||||||
"""Fixture for a single camera for testing the switch platform."""
|
"""Fixture for a single camera for testing the select platform."""
|
||||||
|
|
||||||
# disable pydantic validation so mocking can happen
|
# disable pydantic validation so mocking can happen
|
||||||
Camera.__config__.validate_assignment = False
|
Camera.__config__.validate_assignment = False
|
||||||
@ -119,7 +119,7 @@ async def light_fixture(
|
|||||||
mock_light: Light,
|
mock_light: Light,
|
||||||
camera: Camera,
|
camera: Camera,
|
||||||
):
|
):
|
||||||
"""Fixture for a single light for testing the number platform."""
|
"""Fixture for a single light for testing the select platform."""
|
||||||
|
|
||||||
# disable pydantic validation so mocking can happen
|
# disable pydantic validation so mocking can happen
|
||||||
Light.__config__.validate_assignment = False
|
Light.__config__.validate_assignment = False
|
||||||
@ -151,7 +151,7 @@ async def light_fixture(
|
|||||||
async def camera_none_fixture(
|
async def camera_none_fixture(
|
||||||
hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera
|
hass: HomeAssistant, mock_entry: MockEntityFixture, mock_camera: Camera
|
||||||
):
|
):
|
||||||
"""Fixture for a single camera for testing the switch platform."""
|
"""Fixture for a single camera for testing the select platform."""
|
||||||
|
|
||||||
# disable pydantic validation so mocking can happen
|
# disable pydantic validation so mocking can happen
|
||||||
Camera.__config__.validate_assignment = False
|
Camera.__config__.validate_assignment = False
|
||||||
@ -228,11 +228,11 @@ async def test_select_setup_viewer(
|
|||||||
assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION
|
assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION
|
||||||
|
|
||||||
|
|
||||||
async def test_number_setup_camera_all(
|
async def test_select_setup_camera_all(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
camera: Camera,
|
camera: Camera,
|
||||||
):
|
):
|
||||||
"""Test number entity setup for camera devices (all features)."""
|
"""Test select entity setup for camera devices (all features)."""
|
||||||
|
|
||||||
entity_registry = er.async_get(hass)
|
entity_registry = er.async_get(hass)
|
||||||
expected_values = ("Always", "Auto", "Default Message (Welcome)")
|
expected_values = ("Always", "Auto", "Default Message (Welcome)")
|
||||||
@ -252,11 +252,11 @@ async def test_number_setup_camera_all(
|
|||||||
assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION
|
assert state.attributes[ATTR_ATTRIBUTION] == DEFAULT_ATTRIBUTION
|
||||||
|
|
||||||
|
|
||||||
async def test_number_setup_camera_none(
|
async def test_select_setup_camera_none(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
camera_none: Camera,
|
camera_none: Camera,
|
||||||
):
|
):
|
||||||
"""Test number entity setup for camera devices (no features)."""
|
"""Test select entity setup for camera devices (no features)."""
|
||||||
|
|
||||||
entity_registry = er.async_get(hass)
|
entity_registry = er.async_get(hass)
|
||||||
expected_values = ("Always", "Auto", "Default Message (Welcome)")
|
expected_values = ("Always", "Auto", "Default Message (Welcome)")
|
||||||
@ -332,6 +332,9 @@ async def test_select_update_doorbell_settings(
|
|||||||
|
|
||||||
expected_length += 1
|
expected_length += 1
|
||||||
new_nvr = copy(mock_entry.api.bootstrap.nvr)
|
new_nvr = copy(mock_entry.api.bootstrap.nvr)
|
||||||
|
new_nvr.__fields__["update_all_messages"] = Mock()
|
||||||
|
new_nvr.update_all_messages = Mock()
|
||||||
|
|
||||||
new_nvr.doorbell_settings.all_messages = [
|
new_nvr.doorbell_settings.all_messages = [
|
||||||
*new_nvr.doorbell_settings.all_messages,
|
*new_nvr.doorbell_settings.all_messages,
|
||||||
DoorbellMessage(
|
DoorbellMessage(
|
||||||
@ -615,7 +618,7 @@ async def test_select_service_doorbell_invalid(
|
|||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
camera.set_lcd_text.assert_not_called
|
assert not camera.set_lcd_text.called
|
||||||
|
|
||||||
|
|
||||||
async def test_select_service_doorbell_success(
|
async def test_select_service_doorbell_success(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user