mirror of
https://github.com/home-assistant/core.git
synced 2026-08-21 13:50:31 +01:00
194 lines
6.0 KiB
Python
194 lines
6.0 KiB
Python
"""Tests for Shelly camera platform."""
|
|
|
|
from collections.abc import Generator
|
|
from copy import deepcopy
|
|
from unittest.mock import Mock, patch
|
|
|
|
from aioshelly.const import MODEL_CAMERA
|
|
import pytest
|
|
from syrupy.assertion import SnapshotAssertion
|
|
|
|
from homeassistant.components.camera import (
|
|
DATA_COMPONENT,
|
|
CameraState,
|
|
get_camera_from_entity_id,
|
|
)
|
|
from homeassistant.components.shelly.const import CONF_SLEEP_PERIOD
|
|
from homeassistant.const import (
|
|
CONF_HOST,
|
|
CONF_MODEL,
|
|
CONF_PASSWORD,
|
|
CONF_USERNAME,
|
|
Platform,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity_registry import EntityRegistry
|
|
|
|
from . import MOCK_MAC, init_integration, patch_platforms
|
|
|
|
from tests.common import snapshot_platform
|
|
|
|
CAMERA_ENTITY_ID = "camera.test_name_stream_0"
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def fixture_platforms() -> Generator[None]:
|
|
"""Limit platforms under test."""
|
|
with patch_platforms([Platform.CAMERA]):
|
|
yield
|
|
|
|
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_camera_entity_setup(
|
|
hass: HomeAssistant,
|
|
mock_camera_rpc_device: Mock,
|
|
entity_registry: EntityRegistry,
|
|
snapshot: SnapshotAssertion,
|
|
) -> None:
|
|
"""Test camera entity is created with correct unique_id and initial state."""
|
|
with patch("random.SystemRandom.getrandbits", return_value=123123123123):
|
|
entry = await init_integration(hass, 3, model=MODEL_CAMERA)
|
|
|
|
assert hass.states.get(CAMERA_ENTITY_ID)
|
|
await snapshot_platform(hass, entity_registry, snapshot, entry.entry_id)
|
|
|
|
assert (er_entry := entity_registry.async_get(CAMERA_ENTITY_ID))
|
|
assert er_entry.unique_id == f"{MOCK_MAC}-camera:0-stream_0"
|
|
|
|
|
|
async def test_camera_state_streaming(
|
|
hass: HomeAssistant,
|
|
mock_camera_rpc_device: Mock,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""Test camera state is streaming when streams > 0."""
|
|
await init_integration(hass, 3, model=MODEL_CAMERA)
|
|
|
|
new_status = deepcopy(mock_camera_rpc_device.status)
|
|
new_status["camera:0"]["streams"] = 1
|
|
monkeypatch.setattr(mock_camera_rpc_device, "status", new_status)
|
|
mock_camera_rpc_device.mock_update()
|
|
await hass.async_block_till_done()
|
|
|
|
assert (state := hass.states.get(CAMERA_ENTITY_ID))
|
|
assert state.state == CameraState.STREAMING
|
|
|
|
|
|
async def test_camera_state_recording(
|
|
hass: HomeAssistant,
|
|
mock_camera_rpc_device: Mock,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""Test camera state is recording when recordings is set."""
|
|
await init_integration(hass, 3, model=MODEL_CAMERA)
|
|
|
|
new_status = deepcopy(mock_camera_rpc_device.status)
|
|
new_status["camera:0"]["recordings"] = {"id": 1}
|
|
monkeypatch.setattr(mock_camera_rpc_device, "status", new_status)
|
|
mock_camera_rpc_device.mock_update()
|
|
await hass.async_block_till_done()
|
|
|
|
assert (state := hass.states.get(CAMERA_ENTITY_ID))
|
|
assert state.state == CameraState.RECORDING
|
|
|
|
|
|
async def test_camera_use_stream_for_stills(
|
|
hass: HomeAssistant,
|
|
mock_camera_rpc_device: Mock,
|
|
) -> None:
|
|
"""Test use_stream_for_stills returns True (still images from the RTSP stream)."""
|
|
await init_integration(hass, 3, model=MODEL_CAMERA)
|
|
|
|
camera = get_camera_from_entity_id(hass, CAMERA_ENTITY_ID)
|
|
assert camera.use_stream_for_stills is True
|
|
|
|
|
|
async def test_camera_stream_source(
|
|
hass: HomeAssistant,
|
|
mock_camera_rpc_device: Mock,
|
|
) -> None:
|
|
"""Test stream_source returns the RTSP URL for go2rtc."""
|
|
await init_integration(hass, 3, model=MODEL_CAMERA)
|
|
|
|
camera = get_camera_from_entity_id(hass, CAMERA_ENTITY_ID)
|
|
result = await camera.stream_source()
|
|
assert result == "rtsp://192.168.1.37/stream/0"
|
|
|
|
|
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
|
async def test_camera_stream_source_stream_1(
|
|
hass: HomeAssistant,
|
|
mock_camera_rpc_device: Mock,
|
|
) -> None:
|
|
"""Test stream_source returns correct RTSP URL for stream 1."""
|
|
await init_integration(hass, 3, model=MODEL_CAMERA)
|
|
|
|
camera = get_camera_from_entity_id(hass, "camera.test_name_stream_1")
|
|
result = await camera.stream_source()
|
|
assert result == "rtsp://192.168.1.37/stream/1"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("password", "expected_password"),
|
|
[
|
|
("password", "password"),
|
|
("pass:word@1", "pass%3Aword%401"),
|
|
],
|
|
)
|
|
async def test_camera_stream_source_with_credentials(
|
|
hass: HomeAssistant,
|
|
mock_camera_rpc_device: Mock,
|
|
password: str,
|
|
expected_password: str,
|
|
) -> None:
|
|
"""Test stream_source returns the RTSP URL with credentials for go2rtc."""
|
|
await init_integration(
|
|
hass,
|
|
3,
|
|
model=MODEL_CAMERA,
|
|
data={
|
|
CONF_HOST: "192.168.1.37",
|
|
CONF_MODEL: MODEL_CAMERA,
|
|
CONF_PASSWORD: password,
|
|
CONF_SLEEP_PERIOD: 0,
|
|
CONF_USERNAME: "admin",
|
|
},
|
|
)
|
|
|
|
camera = get_camera_from_entity_id(hass, CAMERA_ENTITY_ID)
|
|
result = await camera.stream_source()
|
|
assert result == f"rtsp://admin:{expected_password}@192.168.1.37/stream/0"
|
|
|
|
|
|
async def test_camera_off_when_streamer_stopped(
|
|
hass: HomeAssistant,
|
|
mock_camera_rpc_device: Mock,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""Test camera is off when the streamer is not running."""
|
|
status = deepcopy(mock_camera_rpc_device.status)
|
|
status["camera:0"]["streamer"] = "stopped"
|
|
monkeypatch.setattr(mock_camera_rpc_device, "status", status)
|
|
|
|
await init_integration(hass, 3, model=MODEL_CAMERA)
|
|
|
|
camera = hass.data[DATA_COMPONENT].get_entity(CAMERA_ENTITY_ID)
|
|
assert camera is not None
|
|
assert camera.is_on is False
|
|
|
|
|
|
async def test_camera_properties_when_device_not_initialized(
|
|
hass: HomeAssistant,
|
|
mock_camera_rpc_device: Mock,
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""Test camera properties return safe values when the device is not initialized."""
|
|
await init_integration(hass, 3, model=MODEL_CAMERA)
|
|
|
|
camera = get_camera_from_entity_id(hass, CAMERA_ENTITY_ID)
|
|
|
|
monkeypatch.setattr(mock_camera_rpc_device, "initialized", False)
|
|
|
|
assert camera.is_on is False
|
|
assert camera.available is False
|