1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-02 08:26:41 +01:00
Files
core/tests/components/unifi_access/test_image.py
2026-03-24 18:49:18 +01:00

160 lines
5.1 KiB
Python

"""Tests for the UniFi Access image platform."""
from __future__ import annotations
from collections.abc import Awaitable, Callable, Generator
from http import HTTPStatus
from unittest.mock import MagicMock, patch
import pytest
from syrupy.assertion import SnapshotAssertion
from unifi_access_api.models.websocket import (
LocationUpdateData,
LocationUpdateV2,
ThumbnailInfo,
WebsocketMessage,
)
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import setup_integration
from tests.common import MockConfigEntry, snapshot_platform
from tests.typing import ClientSessionGenerator
FRONT_DOOR_IMAGE = "image.front_door_thumbnail"
BACK_DOOR_IMAGE = "image.back_door_thumbnail"
def _get_ws_handlers(
mock_client: MagicMock,
) -> dict[str, Callable[[WebsocketMessage], Awaitable[None]]]:
"""Extract WebSocket handlers from mock client."""
return mock_client.start_websocket.call_args[0][0]
@pytest.fixture(autouse=True)
def mock_getrandbits() -> Generator[None]:
"""Mock image access token which normally is randomized."""
with patch(
"homeassistant.components.image.SystemRandom.getrandbits",
return_value=1,
):
yield
async def test_image_entities(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_client: MagicMock,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test image entities are created with expected state."""
with patch("homeassistant.components.unifi_access.PLATFORMS", [Platform.IMAGE]):
await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
async def test_async_image_with_thumbnail(
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_client: MagicMock,
hass_client: ClientSessionGenerator,
) -> None:
"""Test async_image returns bytes when a thumbnail exists from initial load."""
mock_client.get_thumbnail.return_value = b"fake-image-bytes"
client = await hass_client()
resp = await client.get(f"/api/image_proxy/{FRONT_DOOR_IMAGE}")
assert resp.status == HTTPStatus.OK
assert await resp.read() == b"fake-image-bytes"
mock_client.get_thumbnail.assert_awaited_once_with("/preview/front_door.png")
async def test_async_image_without_thumbnail(
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_client: MagicMock,
hass_client: ClientSessionGenerator,
) -> None:
"""Test async_image returns empty response when no thumbnail exists."""
client = await hass_client()
resp = await client.get(f"/api/image_proxy/{BACK_DOOR_IMAGE}")
assert resp.status == HTTPStatus.INTERNAL_SERVER_ERROR
async def test_initial_thumbnail_sets_image_last_updated(
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test initial thumbnail from API sets image_last_updated immediately."""
state = hass.states.get(FRONT_DOOR_IMAGE)
assert state is not None
assert state.state != "unknown"
# Back door has no thumbnail, so it should be unknown
state_back = hass.states.get(BACK_DOOR_IMAGE)
assert state_back is not None
assert state_back.state == "unknown"
async def test_handle_coordinator_update_sets_image_last_updated(
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test WS thumbnail update sets image_last_updated from thumbnail."""
# Back door starts without thumbnail
state_before = hass.states.get(BACK_DOOR_IMAGE)
assert state_before is not None
assert state_before.state == "unknown"
handlers = _get_ws_handlers(mock_client)
await handlers["access.data.device.location_update_v2"](
LocationUpdateV2(
event="access.data.device.location_update_v2",
data=LocationUpdateData(
id="door-002",
location_type="DOOR",
state=None,
thumbnail=ThumbnailInfo(
url="/thumb/door-002.jpg",
door_thumbnail_last_update=1700000000,
),
),
)
)
await hass.async_block_till_done()
state_after = hass.states.get(BACK_DOOR_IMAGE)
assert state_after is not None
assert state_after.state != "unknown"
# Second update with a newer timestamp should change image_last_updated
await handlers["access.data.device.location_update_v2"](
LocationUpdateV2(
event="access.data.device.location_update_v2",
data=LocationUpdateData(
id="door-002",
location_type="DOOR",
state=None,
thumbnail=ThumbnailInfo(
url="/thumb/door-002-v2.jpg",
door_thumbnail_last_update=1700001000,
),
),
)
)
await hass.async_block_till_done()
state_updated = hass.states.get(BACK_DOOR_IMAGE)
assert state_updated is not None
assert state_updated.state != state_after.state