Axis improve coverage binary tests (#111758)

* Parametrize binary sensor tests

* Add test coverage to the different *guard apps

* Add object analytics tests
pull/111800/head
Robert Svensson 2024-02-29 05:14:50 +01:00 committed by GitHub
parent 224f6dbdbb
commit 458391ee2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 171 additions and 45 deletions

View File

@ -21,6 +21,8 @@ from homeassistant.const import (
from .const import (
API_DISCOVERY_RESPONSE,
APP_AOA_RESPONSE,
APP_VMD4_RESPONSE,
APPLICATIONS_LIST_RESPONSE,
BASIC_DEVICE_INFO_RESPONSE,
BRAND_RESPONSE,
@ -36,7 +38,6 @@ from .const import (
PTZ_RESPONSE,
STREAM_PROFILES_RESPONSE,
VIEW_AREAS_RESPONSE,
VMD4_RESPONSE,
)
from tests.common import MockConfigEntry
@ -105,88 +106,90 @@ def default_request_fixture(
"""Mock default Vapix requests responses."""
def __mock_default_requests(host):
path = f"http://{host}:80"
respx_mock(base_url=f"http://{host}:80")
if host != DEFAULT_HOST:
respx.post(f"{path}/axis-cgi/apidiscovery.cgi").respond(
respx.post("/axis-cgi/apidiscovery.cgi").respond(
json=API_DISCOVERY_RESPONSE,
)
respx.post(f"{path}/axis-cgi/basicdeviceinfo.cgi").respond(
respx.post("/axis-cgi/basicdeviceinfo.cgi").respond(
json=BASIC_DEVICE_INFO_RESPONSE,
)
respx.post(f"{path}/axis-cgi/io/portmanagement.cgi").respond(
respx.post("/axis-cgi/io/portmanagement.cgi").respond(
json=port_management_payload,
)
respx.post(f"{path}/axis-cgi/mqtt/client.cgi").respond(
respx.post("/axis-cgi/mqtt/client.cgi").respond(
json=MQTT_CLIENT_RESPONSE,
)
respx.post(f"{path}/axis-cgi/streamprofile.cgi").respond(
respx.post("/axis-cgi/streamprofile.cgi").respond(
json=STREAM_PROFILES_RESPONSE,
)
respx.post(f"{path}/axis-cgi/viewarea/info.cgi").respond(
json=VIEW_AREAS_RESPONSE
)
respx.post("/axis-cgi/viewarea/info.cgi").respond(json=VIEW_AREAS_RESPONSE)
respx.post(
f"{path}/axis-cgi/param.cgi",
"/axis-cgi/param.cgi",
data={"action": "list", "group": "root.Brand"},
).respond(
text=BRAND_RESPONSE,
headers={"Content-Type": "text/plain"},
)
respx.post(
f"{path}/axis-cgi/param.cgi",
"/axis-cgi/param.cgi",
data={"action": "list", "group": "root.Image"},
).respond(
text=IMAGE_RESPONSE,
headers={"Content-Type": "text/plain"},
)
respx.post(
f"{path}/axis-cgi/param.cgi",
"/axis-cgi/param.cgi",
data={"action": "list", "group": "root.Input"},
).respond(
text=PORTS_RESPONSE,
headers={"Content-Type": "text/plain"},
)
respx.post(
f"{path}/axis-cgi/param.cgi",
"/axis-cgi/param.cgi",
data={"action": "list", "group": "root.IOPort"},
).respond(
text=param_ports_payload,
headers={"Content-Type": "text/plain"},
)
respx.post(
f"{path}/axis-cgi/param.cgi",
"/axis-cgi/param.cgi",
data={"action": "list", "group": "root.Output"},
).respond(
text=PORTS_RESPONSE,
headers={"Content-Type": "text/plain"},
)
respx.post(
f"{path}/axis-cgi/param.cgi",
"/axis-cgi/param.cgi",
data={"action": "list", "group": "root.Properties"},
).respond(
text=param_properties_payload,
headers={"Content-Type": "text/plain"},
)
respx.post(
f"{path}/axis-cgi/param.cgi",
"/axis-cgi/param.cgi",
data={"action": "list", "group": "root.PTZ"},
).respond(
text=PTZ_RESPONSE,
headers={"Content-Type": "text/plain"},
)
respx.post(
f"{path}/axis-cgi/param.cgi",
"/axis-cgi/param.cgi",
data={"action": "list", "group": "root.StreamProfile"},
).respond(
text=STREAM_PROFILES_RESPONSE,
headers={"Content-Type": "text/plain"},
)
respx.post(f"{path}/axis-cgi/applications/list.cgi").respond(
respx.post("/axis-cgi/applications/list.cgi").respond(
text=APPLICATIONS_LIST_RESPONSE,
headers={"Content-Type": "text/xml"},
)
respx.post(f"{path}/local/vmd/control.cgi").respond(json=VMD4_RESPONSE)
respx.post("/local/fenceguard/control.cgi").respond(json=APP_VMD4_RESPONSE)
respx.post("/local/loiteringguard/control.cgi").respond(json=APP_VMD4_RESPONSE)
respx.post("/local/motionguard/control.cgi").respond(json=APP_VMD4_RESPONSE)
respx.post("/local/vmd/control.cgi").respond(json=APP_VMD4_RESPONSE)
respx.post("/local/objectanalytics/control.cgi").respond(json=APP_AOA_RESPONSE)
return __mock_default_requests

View File

@ -35,7 +35,11 @@ API_DISCOVERY_PORT_MANAGEMENT = {
}
APPLICATIONS_LIST_RESPONSE = """<reply result="ok">
<application Name="fenceguard" NiceName="AXIS Fence Guard" Vendor="Axis Communications" Version="2.2-6" ApplicationID="47775" License="None" Status="Running" ConfigurationPage="local/fenceguard/config.html" VendorHomePage="http://www.axis.com" LicenseName="Proprietary" />
<application Name="loiteringguard" NiceName="AXIS Loitering Guard" Vendor="Axis Communications" Version="2.2-6" ApplicationID="46775" License="None" Status="Running" ConfigurationPage="local/loiteringguard/config.html" VendorHomePage="http://www.axis.com" LicenseName="Proprietary" />
<application Name="motionguard" NiceName="AXIS Motion Guard" Vendor="Axis Communications" Version="2.2-6" ApplicationID="48170" License="None" Status="Running" ConfigurationPage="local/motionguard/config.html" VendorHomePage="http://www.axis.com" LicenseName="Proprietary" />
<application Name="vmd" NiceName="AXIS Video Motion Detection" Vendor="Axis Communications" Version="4.2-0" ApplicationID="143440" License="None" Status="Running" ConfigurationPage="local/vmd/config.html" VendorHomePage="http://www.axis.com" />
<application Name="objectanalytics" NiceName="AXIS Object Analytics" Vendor="Axis Communications" Version="1.0-0" ApplicationID="143440" License="None" Status="Running" ConfigurationPage="local/vmd/config.html" VendorHomePage="http://www.axis.com" />
</reply>"""
BASIC_DEVICE_INFO_RESPONSE = {
@ -95,7 +99,7 @@ PORT_MANAGEMENT_RESPONSE = {
},
}
VMD4_RESPONSE = {
APP_VMD4_RESPONSE = {
"apiVersion": "1.4",
"method": "getConfiguration",
"context": CONTEXT,
@ -108,6 +112,46 @@ VMD4_RESPONSE = {
},
}
APP_AOA_RESPONSE = {
"apiVersion": "1.0",
"context": "Axis library",
"data": {
"devices": [{"id": 1, "rotation": 180, "type": "camera"}],
"metadataOverlay": [],
"perspectives": [],
"scenarios": [
{
"devices": [{"id": 1}],
"filters": [
{"distance": 5, "type": "distanceSwayingObject"},
{"time": 1, "type": "timeShortLivedLimit"},
{"height": 3, "type": "sizePercentage", "width": 3},
],
"id": 1,
"name": "Scenario 1",
"objectClassifications": [],
"perspectives": [],
"presets": [],
"triggers": [
{
"type": "includeArea",
"vertices": [
[-0.97, -0.97],
[-0.97, 0.97],
[0.97, 0.97],
[0.97, -0.97],
],
}
],
"type": "motion",
},
],
"status": {},
},
"method": "getConfiguration",
}
BRAND_RESPONSE = """root.Brand.Brand=AXIS
root.Brand.ProdFullName=AXIS M1065-LW Network Camera
root.Brand.ProdNbr=M1065-LW

View File

@ -1,4 +1,6 @@
"""Axis binary sensor platform tests."""
import pytest
from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN
from homeassistant.components.binary_sensor import (
DOMAIN as BINARY_SENSOR_DOMAIN,
@ -30,23 +32,10 @@ async def test_no_binary_sensors(hass: HomeAssistant, setup_config_entry) -> Non
assert not hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)
async def test_binary_sensors(
async def test_unsupported_binary_sensors(
hass: HomeAssistant, setup_config_entry, mock_rtsp_event
) -> None:
"""Test that sensors are loaded properly."""
mock_rtsp_event(
topic="tns1:Device/tnsaxis:Sensor/PIR",
data_type="state",
data_value="0",
source_name="sensor",
source_idx="0",
)
mock_rtsp_event(
topic="tnsaxis:CameraApplicationPlatform/VMD/Camera1Profile1",
data_type="active",
data_value="1",
)
# Unsupported event
"""Test that unsupported sensors are not loaded."""
mock_rtsp_event(
topic="tns1:PTZController/tnsaxis:PTZPresets/Channel_1",
data_type="on_preset",
@ -56,14 +45,104 @@ async def test_binary_sensors(
)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 2
assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 0
pir = hass.states.get(f"{BINARY_SENSOR_DOMAIN}.{NAME}_pir_0")
assert pir.state == STATE_OFF
assert pir.name == f"{NAME} PIR 0"
assert pir.attributes["device_class"] == BinarySensorDeviceClass.MOTION
vmd4 = hass.states.get(f"{BINARY_SENSOR_DOMAIN}.{NAME}_vmd4_profile_1")
assert vmd4.state == STATE_ON
assert vmd4.name == f"{NAME} VMD4 Profile 1"
assert vmd4.attributes["device_class"] == BinarySensorDeviceClass.MOTION
@pytest.mark.parametrize(
("event", "entity"),
[
(
{
"topic": "tns1:Device/tnsaxis:Sensor/PIR",
"data_type": "state",
"data_value": "0",
"source_name": "sensor",
"source_idx": "0",
},
{
"id": f"{BINARY_SENSOR_DOMAIN}.{NAME}_pir_0",
"state": STATE_OFF,
"name": f"{NAME} PIR 0",
"device_class": BinarySensorDeviceClass.MOTION,
},
),
(
{
"topic": "tnsaxis:CameraApplicationPlatform/FenceGuard/Camera1Profile1",
"data_type": "active",
"data_value": "1",
},
{
"id": f"{BINARY_SENSOR_DOMAIN}.{NAME}_fence_guard_profile_1",
"state": STATE_ON,
"name": f"{NAME} Fence Guard Profile 1",
"device_class": BinarySensorDeviceClass.MOTION,
},
),
(
{
"topic": "tnsaxis:CameraApplicationPlatform/MotionGuard/Camera1Profile1",
"data_type": "active",
"data_value": "1",
},
{
"id": f"{BINARY_SENSOR_DOMAIN}.{NAME}_motion_guard_profile_1",
"state": STATE_ON,
"name": f"{NAME} Motion Guard Profile 1",
"device_class": BinarySensorDeviceClass.MOTION,
},
),
(
{
"topic": "tnsaxis:CameraApplicationPlatform/LoiteringGuard/Camera1Profile1",
"data_type": "active",
"data_value": "1",
},
{
"id": f"{BINARY_SENSOR_DOMAIN}.{NAME}_loitering_guard_profile_1",
"state": STATE_ON,
"name": f"{NAME} Loitering Guard Profile 1",
"device_class": BinarySensorDeviceClass.MOTION,
},
),
(
{
"topic": "tnsaxis:CameraApplicationPlatform/VMD/Camera1Profile1",
"data_type": "active",
"data_value": "1",
},
{
"id": f"{BINARY_SENSOR_DOMAIN}.{NAME}_vmd4_profile_1",
"state": STATE_ON,
"name": f"{NAME} VMD4 Profile 1",
"device_class": BinarySensorDeviceClass.MOTION,
},
),
(
{
"topic": "tnsaxis:CameraApplicationPlatform/ObjectAnalytics/Device1Scenario1",
"data_type": "active",
"data_value": "1",
},
{
"id": f"{BINARY_SENSOR_DOMAIN}.{NAME}_object_analytics_scenario_1",
"state": STATE_ON,
"name": f"{NAME} Object Analytics Scenario 1",
"device_class": BinarySensorDeviceClass.MOTION,
},
),
],
)
async def test_binary_sensors(
hass: HomeAssistant, setup_config_entry, mock_rtsp_event, event, entity
) -> None:
"""Test that sensors are loaded properly."""
mock_rtsp_event(**event)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 1
state = hass.states.get(entity["id"])
assert state.state == entity["state"]
assert state.name == entity["name"]
assert state.attributes["device_class"] == entity["device_class"]