1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-02 08:26:41 +01:00
Files
core/tests/components/zoneminder/test_services.py
nic bc324a1a6e Add ZoneMinder integration test suite (#163115)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Joostlek <joostlek@outlook.com>
2026-02-24 23:27:13 +01:00

125 lines
3.8 KiB
Python

"""Tests for ZoneMinder service calls."""
from __future__ import annotations
from unittest.mock import MagicMock, patch
import pytest
import voluptuous as vol
from homeassistant.components.zoneminder.const import DOMAIN
from homeassistant.const import ATTR_ID, ATTR_NAME
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from .conftest import MOCK_HOST, MOCK_HOST_2, create_mock_zm_client
async def test_set_run_state_service_registered(
hass: HomeAssistant,
mock_zoneminder_client: MagicMock,
single_server_config: dict,
) -> None:
"""Test set_run_state service is registered after setup."""
assert await async_setup_component(hass, DOMAIN, single_server_config)
await hass.async_block_till_done()
assert hass.services.has_service(DOMAIN, "set_run_state")
async def test_set_run_state_valid_call(
hass: HomeAssistant,
mock_zoneminder_client: MagicMock,
single_server_config: dict,
) -> None:
"""Test valid set_run_state call sets state on correct ZM client."""
assert await async_setup_component(hass, DOMAIN, single_server_config)
await hass.async_block_till_done()
await hass.services.async_call(
DOMAIN,
"set_run_state",
{ATTR_ID: MOCK_HOST, ATTR_NAME: "Away"},
blocking=True,
)
await hass.async_block_till_done()
mock_zoneminder_client.set_active_state.assert_called_once_with("Away")
async def test_set_run_state_multi_server_targets_correct_server(
hass: HomeAssistant, multi_server_config: dict
) -> None:
"""Test set_run_state targets specific server by id."""
clients: dict[str, MagicMock] = {}
def make_client(*args, **kwargs):
client = create_mock_zm_client()
# Extract hostname from the server_origin (first positional arg)
origin = args[0]
hostname = origin.split("://")[1]
clients[hostname] = client
return client
with patch(
"homeassistant.components.zoneminder.ZoneMinder",
side_effect=make_client,
):
assert await async_setup_component(hass, DOMAIN, multi_server_config)
await hass.async_block_till_done()
await hass.services.async_call(
DOMAIN,
"set_run_state",
{ATTR_ID: MOCK_HOST_2, ATTR_NAME: "Home"},
blocking=True,
)
await hass.async_block_till_done()
# Only the second server should have been called
clients[MOCK_HOST_2].set_active_state.assert_called_once_with("Home")
clients[MOCK_HOST].set_active_state.assert_not_called()
async def test_set_run_state_missing_fields_rejected(
hass: HomeAssistant,
mock_zoneminder_client: MagicMock,
single_server_config: dict,
) -> None:
"""Test service call with missing required fields is rejected."""
assert await async_setup_component(hass, DOMAIN, single_server_config)
await hass.async_block_till_done()
with pytest.raises(vol.MultipleInvalid):
await hass.services.async_call(
DOMAIN,
"set_run_state",
{ATTR_ID: MOCK_HOST}, # Missing ATTR_NAME
blocking=True,
)
async def test_set_run_state_invalid_host(
hass: HomeAssistant,
mock_zoneminder_client: MagicMock,
single_server_config: dict,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test service call with invalid host logs error.
Regression: services.py logs error but doesn't return early,
so it also raises KeyError when trying to access the invalid host.
"""
assert await async_setup_component(hass, DOMAIN, single_server_config)
await hass.async_block_till_done()
with pytest.raises(KeyError):
await hass.services.async_call(
DOMAIN,
"set_run_state",
{ATTR_ID: "invalid.host", ATTR_NAME: "Away"},
blocking=True,
)
assert "Invalid ZoneMinder host provided" in caplog.text