"""Tests for the ONVIF integration.""" from unittest.mock import AsyncMock, MagicMock, patch from onvif.exceptions import ONVIFError from zeep.exceptions import Fault from homeassistant import config_entries from homeassistant.components.onvif import config_flow from homeassistant.components.onvif.const import CONF_SNAPSHOT_AUTH from homeassistant.components.onvif.models import ( Capabilities, DeviceInfo, Profile, PullPointManagerState, Resolution, Video, WebHookManagerState, ) from homeassistant.const import HTTP_DIGEST_AUTHENTICATION from tests.common import MockConfigEntry URN = "urn:uuid:123456789" NAME = "TestCamera" HOST = "1.2.3.4" PORT = 80 USERNAME = "admin" PASSWORD = "12345" MAC = "aa:bb:cc:dd:ee" SERIAL_NUMBER = "ABCDEFGHIJK" MANUFACTURER = "TestManufacturer" MODEL = "TestModel" FIRMWARE_VERSION = "TestFirmwareVersion" def setup_mock_onvif_camera( mock_onvif_camera, with_h264=True, two_profiles=False, with_interfaces=True, with_interfaces_not_implemented=False, with_serial=True, profiles_transient_failure=False, auth_fail=False, update_xaddrs_fail=False, no_profiles=False, auth_failure=False, wrong_port=False, ): """Prepare mock onvif.ONVIFCamera.""" devicemgmt = MagicMock() device_info = MagicMock() device_info.SerialNumber = SERIAL_NUMBER if with_serial else None devicemgmt.GetDeviceInformation = AsyncMock(return_value=device_info) interface = MagicMock() interface.Enabled = True interface.Info.HwAddress = MAC if with_interfaces_not_implemented: devicemgmt.GetNetworkInterfaces = AsyncMock( side_effect=Fault("not implemented") ) else: devicemgmt.GetNetworkInterfaces = AsyncMock( return_value=[interface] if with_interfaces else [] ) media_service = MagicMock() profile1 = MagicMock() profile1.VideoEncoderConfiguration.Encoding = "H264" if with_h264 else "MJPEG" profile2 = MagicMock() profile2.VideoEncoderConfiguration.Encoding = "H264" if two_profiles else "MJPEG" if auth_fail: media_service.GetProfiles = AsyncMock(side_effect=Fault("Authority failure")) elif profiles_transient_failure: media_service.GetProfiles = AsyncMock(side_effect=Fault("camera not ready")) elif no_profiles: media_service.GetProfiles = AsyncMock(return_value=[]) else: media_service.GetProfiles = AsyncMock(return_value=[profile1, profile2]) if wrong_port: mock_onvif_camera.update_xaddrs = AsyncMock(side_effect=AttributeError) elif auth_failure: mock_onvif_camera.update_xaddrs = AsyncMock( side_effect=Fault( "not authorized", subcodes=[MagicMock(text="NotAuthorized")] ) ) elif update_xaddrs_fail: mock_onvif_camera.update_xaddrs = AsyncMock( side_effect=ONVIFError("camera not ready") ) else: mock_onvif_camera.update_xaddrs = AsyncMock(return_value=True) mock_onvif_camera.create_devicemgmt_service = AsyncMock(return_value=devicemgmt) mock_onvif_camera.create_media_service = AsyncMock(return_value=media_service) mock_onvif_camera.close = AsyncMock(return_value=None) mock_onvif_camera.xaddrs = {} mock_onvif_camera.services = {} def mock_constructor( host, port, user, passwd, wsdl_dir, encrypt=True, no_cache=False, adjust_time=False, transport=None, ): """Fake the controller constructor.""" return mock_onvif_camera mock_onvif_camera.side_effect = mock_constructor def setup_mock_device(mock_device, capabilities=None): """Prepare mock ONVIFDevice.""" mock_device.async_setup = AsyncMock(return_value=True) mock_device.available = True mock_device.name = NAME mock_device.info = DeviceInfo( MANUFACTURER, MODEL, FIRMWARE_VERSION, SERIAL_NUMBER, MAC, ) mock_device.capabilities = capabilities or Capabilities(imaging=True, ptz=True) profile1 = Profile( index=0, token="dummy", name="profile1", video=Video("any", Resolution(640, 480)), ptz=None, video_source_token=None, ) mock_device.profiles = [profile1] mock_device.events = MagicMock( webhook_manager=MagicMock(state=WebHookManagerState.STARTED), pullpoint_manager=MagicMock(state=PullPointManagerState.PAUSED), ) def mock_constructor(hass, config): """Fake the controller constructor.""" return mock_device mock_device.side_effect = mock_constructor async def setup_onvif_integration( hass, config=None, options=None, unique_id=MAC, entry_id="1", source=config_entries.SOURCE_USER, capabilities=None, ) -> tuple[MockConfigEntry, MagicMock, MagicMock]: """Create an ONVIF config entry.""" if not config: config = { config_flow.CONF_NAME: NAME, config_flow.CONF_HOST: HOST, config_flow.CONF_PORT: PORT, config_flow.CONF_USERNAME: USERNAME, config_flow.CONF_PASSWORD: PASSWORD, CONF_SNAPSHOT_AUTH: HTTP_DIGEST_AUTHENTICATION, } config_entry = MockConfigEntry( domain=config_flow.DOMAIN, source=source, data={**config}, options=options or {}, entry_id=entry_id, unique_id=unique_id, ) config_entry.add_to_hass(hass) with patch( "homeassistant.components.onvif.config_flow.get_device" ) as mock_onvif_camera, patch( "homeassistant.components.onvif.config_flow.wsdiscovery" ) as mock_discovery, patch( "homeassistant.components.onvif.ONVIFDevice" ) as mock_device: setup_mock_onvif_camera(mock_onvif_camera, two_profiles=True) # no discovery mock_discovery.return_value = [] setup_mock_device(mock_device, capabilities=capabilities) mock_device.device = mock_onvif_camera await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() return config_entry, mock_onvif_camera, mock_device