"""Tests for ZoneMinder camera entities.""" from datetime import timedelta from unittest.mock import MagicMock, PropertyMock, patch from freezegun.api import FrozenDateTimeFactory from homeassistant.components.camera import CameraState from homeassistant.components.zoneminder.const import DOMAIN from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component from .conftest import create_mock_monitor, create_mock_zm_client from tests.common import async_fire_time_changed async def _setup_zm_with_cameras( hass: HomeAssistant, mock_zoneminder_client: MagicMock, config: dict, monitors: list, freezer: FrozenDateTimeFactory, verify_ssl: bool = True, ) -> None: """Set up ZM component with camera platform and given monitors.""" mock_zoneminder_client.get_monitors.return_value = monitors type(mock_zoneminder_client).verify_ssl = PropertyMock(return_value=verify_ssl) assert await async_setup_component(hass, DOMAIN, config) await hass.async_block_till_done(wait_background_tasks=True) # Camera uses setup_platform (sync), add camera platform explicitly assert await async_setup_component( hass, "camera", {"camera": [{"platform": DOMAIN}]}, ) await hass.async_block_till_done(wait_background_tasks=True) # Trigger first poll to update entity state freezer.tick(timedelta(seconds=60)) async_fire_time_changed(hass) await hass.async_block_till_done(wait_background_tasks=True) async def test_one_camera_per_monitor( hass: HomeAssistant, mock_zoneminder_client: MagicMock, single_server_config: dict, two_monitors: list, freezer: FrozenDateTimeFactory, ) -> None: """Test one camera entity is created per monitor.""" await _setup_zm_with_cameras( hass, mock_zoneminder_client, single_server_config, two_monitors, freezer ) states = hass.states.async_all("camera") assert len(states) == 2 async def test_camera_entity_name( hass: HomeAssistant, mock_zoneminder_client: MagicMock, single_server_config: dict, freezer: FrozenDateTimeFactory, ) -> None: """Test camera entity name matches monitor name.""" monitors = [create_mock_monitor(name="Front Door")] await _setup_zm_with_cameras( hass, mock_zoneminder_client, single_server_config, monitors, freezer ) state = hass.states.get("camera.front_door") assert state is not None assert state.name == "Front Door" async def test_camera_recording_state( hass: HomeAssistant, mock_zoneminder_client: MagicMock, single_server_config: dict, freezer: FrozenDateTimeFactory, ) -> None: """Test camera recording state reflects monitor is_recording.""" monitors = [ create_mock_monitor(name="Recording Cam", is_recording=True, is_available=True) ] await _setup_zm_with_cameras( hass, mock_zoneminder_client, single_server_config, monitors, freezer ) state = hass.states.get("camera.recording_cam") assert state is not None assert state.state == CameraState.RECORDING async def test_camera_idle_state( hass: HomeAssistant, mock_zoneminder_client: MagicMock, single_server_config: dict, freezer: FrozenDateTimeFactory, ) -> None: """Test camera idle state when not recording.""" monitors = [ create_mock_monitor(name="Idle Cam", is_recording=False, is_available=True) ] await _setup_zm_with_cameras( hass, mock_zoneminder_client, single_server_config, monitors, freezer ) state = hass.states.get("camera.idle_cam") assert state is not None assert state.state == CameraState.IDLE async def test_camera_unavailable_state( hass: HomeAssistant, mock_zoneminder_client: MagicMock, single_server_config: dict, freezer: FrozenDateTimeFactory, ) -> None: """Test camera unavailable state tracking.""" monitors = [create_mock_monitor(name="Offline Cam", is_available=False)] await _setup_zm_with_cameras( hass, mock_zoneminder_client, single_server_config, monitors, freezer ) state = hass.states.get("camera.offline_cam") assert state is not None assert state.state == "unavailable" async def test_no_monitors_raises_platform_not_ready( hass: HomeAssistant, mock_zoneminder_client: MagicMock, single_server_config: dict, ) -> None: """Test PlatformNotReady raised when no monitors returned.""" mock_zoneminder_client.get_monitors.return_value = [] assert await async_setup_component(hass, DOMAIN, single_server_config) await hass.async_block_till_done() await async_setup_component( hass, "camera", {"camera": [{"platform": DOMAIN}]}, ) await hass.async_block_till_done() # No camera entities should exist states = hass.states.async_all("camera") assert len(states) == 0 async def test_multi_server_camera_creation( hass: HomeAssistant, multi_server_config: dict, freezer: FrozenDateTimeFactory, ) -> None: """Test cameras created from multiple ZM servers.""" monitors1 = [create_mock_monitor(monitor_id=1, name="Front Door")] monitors2 = [create_mock_monitor(monitor_id=2, name="Back Yard")] clients = iter( [ create_mock_zm_client(monitors=monitors1), create_mock_zm_client(monitors=monitors2), ] ) with patch( "homeassistant.components.zoneminder.ZoneMinder", side_effect=lambda *args, **kwargs: next(clients), ): assert await async_setup_component(hass, DOMAIN, multi_server_config) await hass.async_block_till_done(wait_background_tasks=True) assert await async_setup_component( hass, "camera", {"camera": [{"platform": DOMAIN}]}, ) await hass.async_block_till_done(wait_background_tasks=True) freezer.tick(timedelta(seconds=60)) async_fire_time_changed(hass) await hass.async_block_till_done(wait_background_tasks=True) states = hass.states.async_all("camera") assert len(states) == 2 async def test_filter_urllib3_logging_called( hass: HomeAssistant, mock_zoneminder_client: MagicMock, single_server_config: dict, freezer: FrozenDateTimeFactory, ) -> None: """Test filter_urllib3_logging() is called in setup_platform.""" monitors = [create_mock_monitor(name="Front Door")] with patch( "homeassistant.components.zoneminder.camera.filter_urllib3_logging" ) as mock_filter: await _setup_zm_with_cameras( hass, mock_zoneminder_client, single_server_config, monitors, freezer ) mock_filter.assert_called_once()