Improve axis tests (#114035)

* Combine binary sensor tests into more logical groups

* Improve light tests

* Clean up switch tests

* Improve typing in conftest

* Add typing to camera

* Improve binary sensor

* Improve light

* Improve switch
This commit is contained in:
Robert Svensson 2024-03-23 00:44:06 +01:00 committed by GitHub
parent 26b6bd83fc
commit bf8d880e5f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 142 additions and 159 deletions

View File

@ -2,8 +2,10 @@
from __future__ import annotations from __future__ import annotations
from collections.abc import Generator from collections.abc import Callable, Generator
from copy import deepcopy from copy import deepcopy
from types import MappingProxyType
from typing import Any
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from axis.rtsp import Signal, State from axis.rtsp import Signal, State
@ -11,6 +13,7 @@ import pytest
import respx import respx
from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
CONF_HOST, CONF_HOST,
CONF_MODEL, CONF_MODEL,
@ -19,6 +22,7 @@ from homeassistant.const import (
CONF_PORT, CONF_PORT,
CONF_USERNAME, CONF_USERNAME,
) )
from homeassistant.core import HomeAssistant
from .const import ( from .const import (
API_DISCOVERY_RESPONSE, API_DISCOVERY_RESPONSE,
@ -42,7 +46,6 @@ from .const import (
) )
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
from tests.components.light.conftest import mock_light_profiles # noqa: F401
@pytest.fixture @pytest.fixture
@ -58,28 +61,33 @@ def mock_setup_entry() -> Generator[AsyncMock, None, None]:
@pytest.fixture(name="config_entry") @pytest.fixture(name="config_entry")
def config_entry_fixture(hass, config, options, config_entry_version): def config_entry_fixture(
hass: HomeAssistant,
config_entry_data: MappingProxyType[str, Any],
config_entry_options: MappingProxyType[str, Any],
config_entry_version: int,
) -> ConfigEntry:
"""Define a config entry fixture.""" """Define a config entry fixture."""
entry = MockConfigEntry( config_entry = MockConfigEntry(
domain=AXIS_DOMAIN, domain=AXIS_DOMAIN,
entry_id="676abe5b73621446e6550a2e86ffe3dd", entry_id="676abe5b73621446e6550a2e86ffe3dd",
unique_id=FORMATTED_MAC, unique_id=FORMATTED_MAC,
data=config, data=config_entry_data,
options=options, options=config_entry_options,
version=config_entry_version, version=config_entry_version,
) )
entry.add_to_hass(hass) config_entry.add_to_hass(hass)
return entry return config_entry
@pytest.fixture(name="config_entry_version") @pytest.fixture(name="config_entry_version")
def config_entry_version_fixture(request): def config_entry_version_fixture() -> int:
"""Define a config entry version fixture.""" """Define a config entry version fixture."""
return 3 return 3
@pytest.fixture(name="config") @pytest.fixture(name="config_entry_data")
def config_fixture(): def config_entry_data_fixture() -> MappingProxyType[str, Any]:
"""Define a config entry data fixture.""" """Define a config entry data fixture."""
return { return {
CONF_HOST: DEFAULT_HOST, CONF_HOST: DEFAULT_HOST,
@ -91,8 +99,8 @@ def config_fixture():
} }
@pytest.fixture(name="options") @pytest.fixture(name="config_entry_options")
def options_fixture(request): def config_entry_options_fixture() -> MappingProxyType[str, Any]:
"""Define a config entry options fixture.""" """Define a config entry options fixture."""
return {} return {}
@ -102,11 +110,14 @@ def options_fixture(request):
@pytest.fixture(name="mock_vapix_requests") @pytest.fixture(name="mock_vapix_requests")
def default_request_fixture( def default_request_fixture(
respx_mock, port_management_payload, param_properties_payload, param_ports_payload respx_mock: respx,
): port_management_payload: dict[str, Any],
param_properties_payload: dict[str, Any],
param_ports_payload: dict[str, Any],
) -> Callable[[str], None]:
"""Mock default Vapix requests responses.""" """Mock default Vapix requests responses."""
def __mock_default_requests(host): def __mock_default_requests(host: str) -> None:
respx_mock(base_url=f"http://{host}:80") respx_mock(base_url=f"http://{host}:80")
if host != DEFAULT_HOST: if host != DEFAULT_HOST:
@ -196,13 +207,13 @@ def default_request_fixture(
@pytest.fixture @pytest.fixture
def api_discovery_items(): def api_discovery_items() -> dict[str, Any]:
"""Additional Apidiscovery items.""" """Additional Apidiscovery items."""
return {} return {}
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def api_discovery_fixture(api_discovery_items): def api_discovery_fixture(api_discovery_items: dict[str, Any]) -> None:
"""Apidiscovery mock response.""" """Apidiscovery mock response."""
data = deepcopy(API_DISCOVERY_RESPONSE) data = deepcopy(API_DISCOVERY_RESPONSE)
if api_discovery_items: if api_discovery_items:
@ -211,34 +222,36 @@ def api_discovery_fixture(api_discovery_items):
@pytest.fixture(name="port_management_payload") @pytest.fixture(name="port_management_payload")
def io_port_management_data_fixture(): def io_port_management_data_fixture() -> dict[str, Any]:
"""Property parameter data.""" """Property parameter data."""
return PORT_MANAGEMENT_RESPONSE return PORT_MANAGEMENT_RESPONSE
@pytest.fixture(name="param_properties_payload") @pytest.fixture(name="param_properties_payload")
def param_properties_data_fixture(): def param_properties_data_fixture() -> dict[str, Any]:
"""Property parameter data.""" """Property parameter data."""
return PROPERTIES_RESPONSE return PROPERTIES_RESPONSE
@pytest.fixture(name="param_ports_payload") @pytest.fixture(name="param_ports_payload")
def param_ports_data_fixture(): def param_ports_data_fixture() -> dict[str, Any]:
"""Property parameter data.""" """Property parameter data."""
return PORTS_RESPONSE return PORTS_RESPONSE
@pytest.fixture(name="setup_default_vapix_requests") @pytest.fixture(name="setup_default_vapix_requests")
def default_vapix_requests_fixture(mock_vapix_requests): def default_vapix_requests_fixture(mock_vapix_requests: Callable[[str], None]) -> None:
"""Mock default Vapix requests responses.""" """Mock default Vapix requests responses."""
mock_vapix_requests(DEFAULT_HOST) mock_vapix_requests(DEFAULT_HOST)
@pytest.fixture(name="prepare_config_entry") @pytest.fixture(name="prepare_config_entry")
async def prep_config_entry_fixture(hass, config_entry, setup_default_vapix_requests): async def prep_config_entry_fixture(
hass: HomeAssistant, config_entry: ConfigEntry, setup_default_vapix_requests: None
) -> Callable[[], ConfigEntry]:
"""Fixture factory to set up Axis network device.""" """Fixture factory to set up Axis network device."""
async def __mock_setup_config_entry(): async def __mock_setup_config_entry() -> ConfigEntry:
assert await hass.config_entries.async_setup(config_entry.entry_id) assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
return config_entry return config_entry
@ -247,7 +260,9 @@ async def prep_config_entry_fixture(hass, config_entry, setup_default_vapix_requ
@pytest.fixture(name="setup_config_entry") @pytest.fixture(name="setup_config_entry")
async def setup_config_entry_fixture(hass, config_entry, setup_default_vapix_requests): async def setup_config_entry_fixture(
hass: HomeAssistant, config_entry: ConfigEntry, setup_default_vapix_requests: None
) -> ConfigEntry:
"""Define a fixture to set up Axis network device.""" """Define a fixture to set up Axis network device."""
assert await hass.config_entries.async_setup(config_entry.entry_id) assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()
@ -258,24 +273,24 @@ async def setup_config_entry_fixture(hass, config_entry, setup_default_vapix_req
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def mock_axis_rtspclient(): def mock_axis_rtspclient() -> Generator[Callable[[dict | None, str], None], None, None]:
"""No real RTSP communication allowed.""" """No real RTSP communication allowed."""
with patch("axis.stream_manager.RTSPClient") as rtsp_client_mock: with patch("axis.stream_manager.RTSPClient") as rtsp_client_mock:
rtsp_client_mock.return_value.session.state = State.STOPPED rtsp_client_mock.return_value.session.state = State.STOPPED
async def start_stream(): async def start_stream() -> None:
"""Set state to playing when calling RTSPClient.start.""" """Set state to playing when calling RTSPClient.start."""
rtsp_client_mock.return_value.session.state = State.PLAYING rtsp_client_mock.return_value.session.state = State.PLAYING
rtsp_client_mock.return_value.start = start_stream rtsp_client_mock.return_value.start = start_stream
def stop_stream(): def stop_stream() -> None:
"""Set state to stopped when calling RTSPClient.stop.""" """Set state to stopped when calling RTSPClient.stop."""
rtsp_client_mock.return_value.session.state = State.STOPPED rtsp_client_mock.return_value.session.state = State.STOPPED
rtsp_client_mock.return_value.stop = stop_stream rtsp_client_mock.return_value.stop = stop_stream
def make_rtsp_call(data: dict | None = None, state: str = ""): def make_rtsp_call(data: dict | None = None, state: str = "") -> None:
"""Generate a RTSP call.""" """Generate a RTSP call."""
axis_streammanager_session_callback = rtsp_client_mock.call_args[0][4] axis_streammanager_session_callback = rtsp_client_mock.call_args[0][4]
@ -291,7 +306,9 @@ def mock_axis_rtspclient():
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def mock_rtsp_event(mock_axis_rtspclient): def mock_rtsp_event(
mock_axis_rtspclient: Callable[[dict | None, str], None],
) -> Callable[[str, str, str, str, str, str], None]:
"""Fixture to allow mocking received RTSP events.""" """Fixture to allow mocking received RTSP events."""
def send_event( def send_event(
@ -342,7 +359,9 @@ def mock_rtsp_event(mock_axis_rtspclient):
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def mock_rtsp_signal_state(mock_axis_rtspclient): def mock_rtsp_signal_state(
mock_axis_rtspclient: Callable[[dict | None, str], None],
) -> Callable[[bool], None]:
"""Fixture to allow mocking RTSP state signalling.""" """Fixture to allow mocking RTSP state signalling."""
def send_signal(connected: bool) -> None: def send_signal(connected: bool) -> None:

View File

@ -1,54 +1,20 @@
"""Axis binary sensor platform tests.""" """Axis binary sensor platform tests."""
from collections.abc import Callable
import pytest import pytest
from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
DOMAIN as BINARY_SENSOR_DOMAIN, DOMAIN as BINARY_SENSOR_DOMAIN,
BinarySensorDeviceClass, BinarySensorDeviceClass,
) )
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.const import STATE_OFF, STATE_ON
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from .const import NAME from .const import NAME
async def test_platform_manually_configured(hass: HomeAssistant) -> None:
"""Test that nothing happens when platform is manually configured."""
assert (
await async_setup_component(
hass,
BINARY_SENSOR_DOMAIN,
{BINARY_SENSOR_DOMAIN: {"platform": AXIS_DOMAIN}},
)
is True
)
assert AXIS_DOMAIN not in hass.data
async def test_no_binary_sensors(hass: HomeAssistant, setup_config_entry) -> None:
"""Test that no sensors in Axis results in no sensor entities."""
assert not hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)
async def test_unsupported_binary_sensors(
hass: HomeAssistant, setup_config_entry, mock_rtsp_event
) -> None:
"""Test that unsupported sensors are not loaded."""
mock_rtsp_event(
topic="tns1:PTZController/tnsaxis:PTZPresets/Channel_1",
data_type="on_preset",
data_value="1",
source_name="PresetToken",
source_idx="0",
)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 0
@pytest.mark.parametrize( @pytest.mark.parametrize(
("event", "entity"), ("event", "entity"),
[ [
@ -178,10 +144,41 @@ async def test_unsupported_binary_sensors(
"device_class": BinarySensorDeviceClass.MOTION, "device_class": BinarySensorDeviceClass.MOTION,
}, },
), ),
# Events with names generated from event ID and topic
(
{
"topic": "tnsaxis:CameraApplicationPlatform/VMD/Camera1Profile9",
"data_type": "active",
"data_value": "1",
},
{
"id": f"{BINARY_SENSOR_DOMAIN}.{NAME}_vmd4_camera1profile9",
"state": STATE_ON,
"name": f"{NAME} VMD4 Camera1Profile9",
"device_class": BinarySensorDeviceClass.MOTION,
},
),
(
{
"topic": "tnsaxis:CameraApplicationPlatform/ObjectAnalytics/Device1Scenario8",
"data_type": "active",
"data_value": "1",
},
{
"id": f"{BINARY_SENSOR_DOMAIN}.{NAME}_object_analytics_device1scenario8",
"state": STATE_ON,
"name": f"{NAME} Object Analytics Device1Scenario8",
"device_class": BinarySensorDeviceClass.MOTION,
},
),
], ],
) )
async def test_binary_sensors( async def test_binary_sensors(
hass: HomeAssistant, setup_config_entry, mock_rtsp_event, event, entity hass: HomeAssistant,
setup_config_entry: ConfigEntry,
mock_rtsp_event: Callable[[str, str, str, str, str, str], None],
event: dict[str, str],
entity: dict[str, str],
) -> None: ) -> None:
"""Test that sensors are loaded properly.""" """Test that sensors are loaded properly."""
mock_rtsp_event(**event) mock_rtsp_event(**event)
@ -198,6 +195,15 @@ async def test_binary_sensors(
@pytest.mark.parametrize( @pytest.mark.parametrize(
("event"), ("event"),
[ [
# Event with unsupported topic
{
"topic": "tns1:PTZController/tnsaxis:PTZPresets/Channel_1",
"data_type": "on_preset",
"data_value": "1",
"source_name": "PresetToken",
"source_idx": "0",
},
# Event with unsupported source_idx
{ {
"topic": "tns1:Device/tnsaxis:IO/Port", "topic": "tns1:Device/tnsaxis:IO/Port",
"data_type": "state", "data_type": "state",
@ -206,6 +212,7 @@ async def test_binary_sensors(
"source_name": "port", "source_name": "port",
"source_idx": "-1", "source_idx": "-1",
}, },
# Event with unsupported ID in topic 'ANY'
{ {
"topic": "tnsaxis:CameraApplicationPlatform/VMD/Camera1ProfileANY", "topic": "tnsaxis:CameraApplicationPlatform/VMD/Camera1ProfileANY",
"data_type": "active", "data_type": "active",
@ -219,40 +226,12 @@ async def test_binary_sensors(
], ],
) )
async def test_unsupported_events( async def test_unsupported_events(
hass: HomeAssistant, setup_config_entry, mock_rtsp_event, event hass: HomeAssistant,
setup_config_entry: ConfigEntry,
mock_rtsp_event: Callable[[str, str, str, str, str, str], None],
event: dict[str, str],
) -> None: ) -> None:
"""Validate nothing breaks with unsupported events.""" """Validate nothing breaks with unsupported events."""
mock_rtsp_event(**event) mock_rtsp_event(**event)
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 0 assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 0
@pytest.mark.parametrize(
("event", "entity_id"),
[
(
{
"topic": "tnsaxis:CameraApplicationPlatform/VMD/Camera1Profile9",
"data_type": "active",
"data_value": "1",
},
"binary_sensor.name_vmd4_camera1profile9",
),
(
{
"topic": "tnsaxis:CameraApplicationPlatform/ObjectAnalytics/Device1Scenario8",
"data_type": "active",
"data_value": "1",
},
"binary_sensor.name_object_analytics_device1scenario8",
),
],
)
async def test_no_primary_name_for_event(
hass: HomeAssistant, setup_config_entry, mock_rtsp_event, event, entity_id
) -> None:
"""Validate fallback method for getting name works."""
mock_rtsp_event(**event)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids(BINARY_SENSOR_DOMAIN)) == 1
assert hass.states.get(entity_id)

View File

@ -1,5 +1,7 @@
"""Axis camera platform tests.""" """Axis camera platform tests."""
from collections.abc import Callable
import pytest import pytest
from homeassistant.components import camera from homeassistant.components import camera
@ -8,6 +10,7 @@ from homeassistant.components.axis.const import (
DOMAIN as AXIS_DOMAIN, DOMAIN as AXIS_DOMAIN,
) )
from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_IDLE from homeassistant.const import STATE_IDLE
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
@ -27,7 +30,7 @@ async def test_platform_manually_configured(hass: HomeAssistant) -> None:
assert AXIS_DOMAIN not in hass.data assert AXIS_DOMAIN not in hass.data
async def test_camera(hass: HomeAssistant, setup_config_entry) -> None: async def test_camera(hass: HomeAssistant, setup_config_entry: ConfigEntry) -> None:
"""Test that Axis camera platform is loaded properly.""" """Test that Axis camera platform is loaded properly."""
assert len(hass.states.async_entity_ids(CAMERA_DOMAIN)) == 1 assert len(hass.states.async_entity_ids(CAMERA_DOMAIN)) == 1
@ -46,9 +49,9 @@ async def test_camera(hass: HomeAssistant, setup_config_entry) -> None:
) )
@pytest.mark.parametrize("options", [{CONF_STREAM_PROFILE: "profile_1"}]) @pytest.mark.parametrize("config_entry_options", [{CONF_STREAM_PROFILE: "profile_1"}])
async def test_camera_with_stream_profile( async def test_camera_with_stream_profile(
hass: HomeAssistant, setup_config_entry hass: HomeAssistant, setup_config_entry: ConfigEntry
) -> None: ) -> None:
"""Test that Axis camera entity is using the correct path with stream profike.""" """Test that Axis camera entity is using the correct path with stream profike."""
assert len(hass.states.async_entity_ids(CAMERA_DOMAIN)) == 1 assert len(hass.states.async_entity_ids(CAMERA_DOMAIN)) == 1
@ -83,7 +86,9 @@ root.Properties.System.SerialNumber={MAC}
@pytest.mark.parametrize("param_properties_payload", [property_data]) @pytest.mark.parametrize("param_properties_payload", [property_data])
async def test_camera_disabled(hass: HomeAssistant, prepare_config_entry) -> None: async def test_camera_disabled(
hass: HomeAssistant, prepare_config_entry: Callable[[], ConfigEntry]
) -> None:
"""Test that Axis camera platform is loaded properly but does not create camera entity.""" """Test that Axis camera platform is loaded properly but does not create camera entity."""
await prepare_config_entry() await prepare_config_entry()
assert len(hass.states.async_entity_ids(CAMERA_DOMAIN)) == 0 assert len(hass.states.async_entity_ids(CAMERA_DOMAIN)) == 0

View File

@ -45,7 +45,7 @@ def hass_mock_forward_entry_setup(hass):
async def test_device_setup( async def test_device_setup(
hass: HomeAssistant, hass: HomeAssistant,
forward_entry_setup, forward_entry_setup,
config, config_entry_data,
setup_config_entry, setup_config_entry,
device_registry: dr.DeviceRegistry, device_registry: dr.DeviceRegistry,
) -> None: ) -> None:
@ -63,9 +63,9 @@ async def test_device_setup(
assert forward_entry_setup.mock_calls[2][1][1] == "light" assert forward_entry_setup.mock_calls[2][1][1] == "light"
assert forward_entry_setup.mock_calls[3][1][1] == "switch" assert forward_entry_setup.mock_calls[3][1][1] == "switch"
assert hub.config.host == config[CONF_HOST] assert hub.config.host == config_entry_data[CONF_HOST]
assert hub.config.model == config[CONF_MODEL] assert hub.config.model == config_entry_data[CONF_MODEL]
assert hub.config.name == config[CONF_NAME] assert hub.config.name == config_entry_data[CONF_NAME]
assert hub.unique_id == FORMATTED_MAC assert hub.unique_id == FORMATTED_MAC
device_entry = device_registry.async_get_device( device_entry = device_registry.async_get_device(
@ -206,11 +206,11 @@ async def test_device_unknown_error(
assert hass.data[AXIS_DOMAIN] == {} assert hass.data[AXIS_DOMAIN] == {}
async def test_shutdown(config) -> None: async def test_shutdown(config_entry_data) -> None:
"""Successful shutdown.""" """Successful shutdown."""
hass = Mock() hass = Mock()
entry = Mock() entry = Mock()
entry.data = config entry.data = config_entry_data
mock_api = Mock() mock_api = Mock()
mock_api.vapix.serial_number = FORMATTED_MAC mock_api.vapix.serial_number = FORMATTED_MAC
@ -221,25 +221,27 @@ async def test_shutdown(config) -> None:
assert len(axis_device.api.stream.stop.mock_calls) == 1 assert len(axis_device.api.stream.stop.mock_calls) == 1
async def test_get_device_fails(hass: HomeAssistant, config) -> None: async def test_get_device_fails(hass: HomeAssistant, config_entry_data) -> None:
"""Device unauthorized yields authentication required error.""" """Device unauthorized yields authentication required error."""
with patch( with patch(
"axis.vapix.vapix.Vapix.initialize", side_effect=axislib.Unauthorized "axis.vapix.vapix.Vapix.initialize", side_effect=axislib.Unauthorized
), pytest.raises(axis.errors.AuthenticationRequired): ), pytest.raises(axis.errors.AuthenticationRequired):
await axis.hub.get_axis_api(hass, config) await axis.hub.get_axis_api(hass, config_entry_data)
async def test_get_device_device_unavailable(hass: HomeAssistant, config) -> None: async def test_get_device_device_unavailable(
hass: HomeAssistant, config_entry_data
) -> None:
"""Device unavailable yields cannot connect error.""" """Device unavailable yields cannot connect error."""
with patch( with patch(
"axis.vapix.vapix.Vapix.request", side_effect=axislib.RequestError "axis.vapix.vapix.Vapix.request", side_effect=axislib.RequestError
), pytest.raises(axis.errors.CannotConnect): ), pytest.raises(axis.errors.CannotConnect):
await axis.hub.get_axis_api(hass, config) await axis.hub.get_axis_api(hass, config_entry_data)
async def test_get_device_unknown_error(hass: HomeAssistant, config) -> None: async def test_get_device_unknown_error(hass: HomeAssistant, config_entry_data) -> None:
"""Device yield unknown error.""" """Device yield unknown error."""
with patch( with patch(
"axis.vapix.vapix.Vapix.request", side_effect=axislib.AxisException "axis.vapix.vapix.Vapix.request", side_effect=axislib.AxisException
), pytest.raises(axis.errors.AuthenticationRequired): ), pytest.raises(axis.errors.AuthenticationRequired):
await axis.hub.get_axis_api(hass, config) await axis.hub.get_axis_api(hass, config_entry_data)

View File

@ -1,13 +1,15 @@
"""Axis light platform tests.""" """Axis light platform tests."""
from collections.abc import Callable
from typing import Any
from unittest.mock import patch from unittest.mock import patch
from axis.vapix.models.api import CONTEXT from axis.vapix.models.api import CONTEXT
import pytest import pytest
import respx import respx
from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN
from homeassistant.components.light import ATTR_BRIGHTNESS, DOMAIN as LIGHT_DOMAIN from homeassistant.components.light import ATTR_BRIGHTNESS, DOMAIN as LIGHT_DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
@ -16,7 +18,6 @@ from homeassistant.const import (
STATE_ON, STATE_ON,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from .const import DEFAULT_HOST, NAME from .const import DEFAULT_HOST, NAME
@ -28,7 +29,7 @@ API_DISCOVERY_LIGHT_CONTROL = {
@pytest.fixture @pytest.fixture
def light_control_items(): def light_control_items() -> list[dict[str, Any]]:
"""Available lights.""" """Available lights."""
return [ return [
{ {
@ -47,7 +48,7 @@ def light_control_items():
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def light_control_fixture(light_control_items): def light_control_fixture(light_control_items: list[dict[str, Any]]) -> None:
"""Light control mock response.""" """Light control mock response."""
data = { data = {
"apiVersion": "1.1", "apiVersion": "1.1",
@ -67,24 +68,12 @@ def light_control_fixture(light_control_items):
) )
async def test_platform_manually_configured(hass: HomeAssistant) -> None:
"""Test that nothing happens when platform is manually configured."""
assert await async_setup_component(
hass, LIGHT_DOMAIN, {LIGHT_DOMAIN: {"platform": AXIS_DOMAIN}}
)
assert AXIS_DOMAIN not in hass.data
async def test_no_lights(hass: HomeAssistant, setup_config_entry) -> None:
"""Test that no light events in Axis results in no light entities."""
assert not hass.states.async_entity_ids(LIGHT_DOMAIN)
@pytest.mark.parametrize("api_discovery_items", [API_DISCOVERY_LIGHT_CONTROL]) @pytest.mark.parametrize("api_discovery_items", [API_DISCOVERY_LIGHT_CONTROL])
@pytest.mark.parametrize("light_control_items", [[]]) @pytest.mark.parametrize("light_control_items", [[]])
async def test_no_light_entity_without_light_control_representation( async def test_no_light_entity_without_light_control_representation(
hass: HomeAssistant, setup_config_entry, mock_rtsp_event hass: HomeAssistant,
setup_config_entry: ConfigEntry,
mock_rtsp_event: Callable[[str, str, str, str, str, str], None],
) -> None: ) -> None:
"""Verify no lights entities get created without light control representation.""" """Verify no lights entities get created without light control representation."""
mock_rtsp_event( mock_rtsp_event(
@ -102,10 +91,10 @@ async def test_no_light_entity_without_light_control_representation(
@pytest.mark.parametrize("api_discovery_items", [API_DISCOVERY_LIGHT_CONTROL]) @pytest.mark.parametrize("api_discovery_items", [API_DISCOVERY_LIGHT_CONTROL])
async def test_lights( async def test_lights(
hass: HomeAssistant, hass: HomeAssistant,
respx_mock, respx_mock: respx,
setup_config_entry, setup_config_entry: ConfigEntry,
mock_rtsp_event, mock_rtsp_event: Callable[[str, str, str, str, str, str], None],
api_discovery_items, api_discovery_items: dict[str, Any],
) -> None: ) -> None:
"""Test that lights are loaded properly.""" """Test that lights are loaded properly."""
# Add light # Add light

View File

@ -1,12 +1,13 @@
"""Axis switch platform tests.""" """Axis switch platform tests."""
from collections.abc import Callable
from unittest.mock import patch from unittest.mock import patch
from axis.vapix.models.api import CONTEXT from axis.vapix.models.api import CONTEXT
import pytest import pytest
from homeassistant.components.axis.const import DOMAIN as AXIS_DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
@ -15,25 +16,9 @@ from homeassistant.const import (
STATE_ON, STATE_ON,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from .const import API_DISCOVERY_PORT_MANAGEMENT, NAME from .const import API_DISCOVERY_PORT_MANAGEMENT, NAME
async def test_platform_manually_configured(hass: HomeAssistant) -> None:
"""Test that nothing happens when platform is manually configured."""
assert await async_setup_component(
hass, SWITCH_DOMAIN, {SWITCH_DOMAIN: {"platform": AXIS_DOMAIN}}
)
assert AXIS_DOMAIN not in hass.data
async def test_no_switches(hass: HomeAssistant, setup_config_entry) -> None:
"""Test that no output events in Axis results in no switch entities."""
assert not hass.states.async_entity_ids(SWITCH_DOMAIN)
PORT_DATA = """root.IOPort.I0.Configurable=yes PORT_DATA = """root.IOPort.I0.Configurable=yes
root.IOPort.I0.Direction=output root.IOPort.I0.Direction=output
root.IOPort.I0.Output.Name=Doorbell root.IOPort.I0.Output.Name=Doorbell
@ -47,7 +32,9 @@ root.IOPort.I1.Output.Active=open
@pytest.mark.parametrize("param_ports_payload", [PORT_DATA]) @pytest.mark.parametrize("param_ports_payload", [PORT_DATA])
async def test_switches_with_port_cgi( async def test_switches_with_port_cgi(
hass: HomeAssistant, setup_config_entry, mock_rtsp_event hass: HomeAssistant,
setup_config_entry: ConfigEntry,
mock_rtsp_event: Callable[[str, str, str, str, str, str], None],
) -> None: ) -> None:
"""Test that switches are loaded properly using port.cgi.""" """Test that switches are loaded properly using port.cgi."""
mock_rtsp_event( mock_rtsp_event(
@ -130,7 +117,9 @@ PORT_MANAGEMENT_RESPONSE = {
@pytest.mark.parametrize("api_discovery_items", [API_DISCOVERY_PORT_MANAGEMENT]) @pytest.mark.parametrize("api_discovery_items", [API_DISCOVERY_PORT_MANAGEMENT])
@pytest.mark.parametrize("port_management_payload", [PORT_MANAGEMENT_RESPONSE]) @pytest.mark.parametrize("port_management_payload", [PORT_MANAGEMENT_RESPONSE])
async def test_switches_with_port_management( async def test_switches_with_port_management(
hass: HomeAssistant, setup_config_entry, mock_rtsp_event hass: HomeAssistant,
setup_config_entry: ConfigEntry,
mock_rtsp_event: Callable[[str, str, str, str, str, str], None],
) -> None: ) -> None:
"""Test that switches are loaded properly using port management.""" """Test that switches are loaded properly using port management."""
mock_rtsp_event( mock_rtsp_event(