core/tests/components/reolink/test_views.py

244 lines
7.4 KiB
Python

"""Tests for the Reolink views platform."""
from http import HTTPStatus
import logging
from typing import Any, cast
from unittest.mock import AsyncMock, MagicMock, Mock, patch
from aiohttp import ClientConnectionError, ClientResponse
import pytest
from reolink_aio.enums import VodRequestType
from reolink_aio.exceptions import ReolinkError
from homeassistant.components.reolink.views import async_generate_playback_proxy_url
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
from tests.typing import ClientSessionGenerator
TEST_YEAR = 2023
TEST_MONTH = 11
TEST_DAY = 14
TEST_DAY2 = 15
TEST_HOUR = 13
TEST_MINUTE = 12
TEST_FILE_NAME_MP4 = f"Mp4Record/{TEST_YEAR}-{TEST_MONTH}-{TEST_DAY}/RecS04_{TEST_YEAR}{TEST_MONTH}{TEST_DAY}{TEST_HOUR}{TEST_MINUTE}00_123456_AB123C.mp4"
TEST_STREAM = "sub"
TEST_CHANNEL = "0"
TEST_VOD_TYPE = VodRequestType.PLAYBACK.value
TEST_MIME_TYPE_MP4 = "video/mp4"
TEST_URL = "http://test_url&token=test"
TEST_ERROR = "TestError"
def get_mock_session(
response: list[Any] | None = None,
content_length: int = 8,
content_type: str = TEST_MIME_TYPE_MP4,
) -> Mock:
"""Get a mock session to mock the camera response."""
if response is None:
response = [b"test", b"test", StopAsyncIteration()]
content = Mock()
content.__anext__ = AsyncMock(side_effect=response)
content.__aiter__ = Mock(return_value=content)
mock_response = Mock()
mock_response.content_length = content_length
mock_response.content_type = content_type
mock_response.content.iter_chunked = Mock(return_value=content)
mock_session = Mock()
mock_session.get = AsyncMock(return_value=mock_response)
return mock_session
async def test_playback_proxy(
hass: HomeAssistant,
reolink_connect: MagicMock,
config_entry: MockConfigEntry,
hass_client: ClientSessionGenerator,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test successful playback proxy URL."""
reolink_connect.get_vod_source.return_value = (TEST_MIME_TYPE_MP4, TEST_URL)
mock_session = get_mock_session()
with patch(
"homeassistant.components.reolink.views.async_get_clientsession",
return_value=mock_session,
):
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
caplog.set_level(logging.DEBUG)
proxy_url = async_generate_playback_proxy_url(
config_entry.entry_id,
TEST_CHANNEL,
TEST_FILE_NAME_MP4,
TEST_STREAM,
TEST_VOD_TYPE,
)
http_client = await hass_client()
response = cast(ClientResponse, await http_client.get(proxy_url))
assert await response.content.read() == b"testtest"
assert response.status == 200
async def test_proxy_get_source_error(
hass: HomeAssistant,
reolink_connect: MagicMock,
config_entry: MockConfigEntry,
hass_client: ClientSessionGenerator,
) -> None:
"""Test error while getting source for playback proxy URL."""
reolink_connect.get_vod_source.side_effect = ReolinkError(TEST_ERROR)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
proxy_url = async_generate_playback_proxy_url(
config_entry.entry_id,
TEST_CHANNEL,
TEST_FILE_NAME_MP4,
TEST_STREAM,
TEST_VOD_TYPE,
)
http_client = await hass_client()
response = await http_client.get(proxy_url)
assert await response.content.read() == bytes(TEST_ERROR, "utf-8")
assert response.status == HTTPStatus.BAD_REQUEST
reolink_connect.get_vod_source.side_effect = None
async def test_proxy_invalid_config_entry_id(
hass: HomeAssistant,
reolink_connect: MagicMock,
config_entry: MockConfigEntry,
hass_client: ClientSessionGenerator,
) -> None:
"""Test config entry id not found for playback proxy URL."""
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
proxy_url = async_generate_playback_proxy_url(
"wrong_config_id",
TEST_CHANNEL,
TEST_FILE_NAME_MP4,
TEST_STREAM,
TEST_VOD_TYPE,
)
http_client = await hass_client()
response = await http_client.get(proxy_url)
assert await response.content.read() == bytes(
"Reolink playback proxy could not find config entry id: wrong_config_id",
"utf-8",
)
assert response.status == HTTPStatus.BAD_REQUEST
async def test_playback_proxy_timeout(
hass: HomeAssistant,
reolink_connect: MagicMock,
config_entry: MockConfigEntry,
hass_client: ClientSessionGenerator,
) -> None:
"""Test playback proxy URL with a timeout in the second chunk."""
reolink_connect.get_vod_source.return_value = (TEST_MIME_TYPE_MP4, TEST_URL)
mock_session = get_mock_session([b"test", TimeoutError()], 4)
with patch(
"homeassistant.components.reolink.views.async_get_clientsession",
return_value=mock_session,
):
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
proxy_url = async_generate_playback_proxy_url(
config_entry.entry_id,
TEST_CHANNEL,
TEST_FILE_NAME_MP4,
TEST_STREAM,
TEST_VOD_TYPE,
)
http_client = await hass_client()
response = cast(ClientResponse, await http_client.get(proxy_url))
assert await response.content.read() == b"test"
assert response.status == 200
async def test_playback_wrong_content(
hass: HomeAssistant,
reolink_connect: MagicMock,
config_entry: MockConfigEntry,
hass_client: ClientSessionGenerator,
) -> None:
"""Test playback proxy URL with a wrong content type in the response."""
reolink_connect.get_vod_source.return_value = (TEST_MIME_TYPE_MP4, TEST_URL)
mock_session = get_mock_session(content_type="video/x-flv")
with patch(
"homeassistant.components.reolink.views.async_get_clientsession",
return_value=mock_session,
):
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
proxy_url = async_generate_playback_proxy_url(
config_entry.entry_id,
TEST_CHANNEL,
TEST_FILE_NAME_MP4,
TEST_STREAM,
TEST_VOD_TYPE,
)
http_client = await hass_client()
response = cast(ClientResponse, await http_client.get(proxy_url))
assert response.status == HTTPStatus.BAD_REQUEST
async def test_playback_connect_error(
hass: HomeAssistant,
reolink_connect: MagicMock,
config_entry: MockConfigEntry,
hass_client: ClientSessionGenerator,
) -> None:
"""Test playback proxy URL with a connection error."""
reolink_connect.get_vod_source.return_value = (TEST_MIME_TYPE_MP4, TEST_URL)
mock_session = Mock()
mock_session.get = AsyncMock(side_effect=ClientConnectionError(TEST_ERROR))
with patch(
"homeassistant.components.reolink.views.async_get_clientsession",
return_value=mock_session,
):
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
proxy_url = async_generate_playback_proxy_url(
config_entry.entry_id,
TEST_CHANNEL,
TEST_FILE_NAME_MP4,
TEST_STREAM,
TEST_VOD_TYPE,
)
http_client = await hass_client()
response = cast(ClientResponse, await http_client.get(proxy_url))
assert response.status == HTTPStatus.BAD_REQUEST