2018-03-12 22:22:08 +00:00
|
|
|
"""Tests for Home Assistant View."""
|
2024-03-08 13:50:04 +00:00
|
|
|
|
2023-01-31 19:37:26 +00:00
|
|
|
from decimal import Decimal
|
2021-10-23 18:34:53 +00:00
|
|
|
from http import HTTPStatus
|
2022-06-22 19:59:51 +00:00
|
|
|
import json
|
2021-01-01 21:31:56 +00:00
|
|
|
from unittest.mock import AsyncMock, Mock
|
|
|
|
|
2018-11-30 20:28:35 +00:00
|
|
|
from aiohttp.web_exceptions import (
|
2019-07-31 19:25:30 +00:00
|
|
|
HTTPBadRequest,
|
2019-12-09 10:59:38 +00:00
|
|
|
HTTPInternalServerError,
|
2019-07-31 19:25:30 +00:00
|
|
|
HTTPUnauthorized,
|
|
|
|
)
|
2018-03-12 22:22:08 +00:00
|
|
|
import pytest
|
2018-11-30 20:28:35 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
2024-03-07 17:03:44 +00:00
|
|
|
from homeassistant.components.http import KEY_HASS
|
2018-11-30 20:28:35 +00:00
|
|
|
from homeassistant.components.http.view import (
|
2019-07-31 19:25:30 +00:00
|
|
|
HomeAssistantView,
|
|
|
|
request_handler_factory,
|
|
|
|
)
|
2018-11-30 20:28:35 +00:00
|
|
|
from homeassistant.exceptions import ServiceNotFound, Unauthorized
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
2023-05-21 18:36:03 +00:00
|
|
|
def mock_request() -> Mock:
|
2018-11-30 20:28:35 +00:00
|
|
|
"""Mock a request."""
|
2024-03-07 17:03:44 +00:00
|
|
|
return Mock(app={KEY_HASS: Mock(is_stopping=False)}, match_info={})
|
2020-06-02 18:54:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
2023-05-21 18:36:03 +00:00
|
|
|
def mock_request_with_stopping() -> Mock:
|
2020-06-02 18:54:11 +00:00
|
|
|
"""Mock a request."""
|
2024-03-07 17:03:44 +00:00
|
|
|
return Mock(app={KEY_HASS: Mock(is_stopping=True)}, match_info={})
|
2018-03-12 22:22:08 +00:00
|
|
|
|
|
|
|
|
2023-02-13 09:25:26 +00:00
|
|
|
async def test_invalid_json(caplog: pytest.LogCaptureFixture) -> None:
|
2018-03-12 22:22:08 +00:00
|
|
|
"""Test trying to return invalid JSON."""
|
|
|
|
with pytest.raises(HTTPInternalServerError):
|
2023-01-31 19:37:26 +00:00
|
|
|
HomeAssistantView.json({"hello": Decimal("2.0")})
|
2018-03-12 22:22:08 +00:00
|
|
|
|
2023-01-31 19:37:26 +00:00
|
|
|
assert (
|
|
|
|
"Unable to serialize to JSON. Bad data found at $.hello=2.0(<class 'decimal.Decimal'>"
|
|
|
|
in caplog.text
|
|
|
|
)
|
2022-06-22 19:59:51 +00:00
|
|
|
|
|
|
|
|
2023-02-07 09:26:56 +00:00
|
|
|
async def test_nan_serialized_to_null() -> None:
|
2022-06-22 19:59:51 +00:00
|
|
|
"""Test nan serialized to null JSON."""
|
2023-01-31 19:37:26 +00:00
|
|
|
response = HomeAssistantView.json(float("NaN"))
|
2022-06-22 19:59:51 +00:00
|
|
|
assert json.loads(response.body.decode("utf-8")) is None
|
2018-11-30 20:28:35 +00:00
|
|
|
|
|
|
|
|
2023-05-21 18:36:03 +00:00
|
|
|
async def test_handling_unauthorized(mock_request: Mock) -> None:
|
2018-11-30 20:28:35 +00:00
|
|
|
"""Test handling unauth exceptions."""
|
|
|
|
with pytest.raises(HTTPUnauthorized):
|
|
|
|
await request_handler_factory(
|
2024-03-07 17:03:44 +00:00
|
|
|
mock_request.app[KEY_HASS],
|
2023-05-21 18:36:03 +00:00
|
|
|
Mock(requires_auth=False),
|
|
|
|
AsyncMock(side_effect=Unauthorized),
|
2018-11-30 20:28:35 +00:00
|
|
|
)(mock_request)
|
|
|
|
|
|
|
|
|
2023-05-21 18:36:03 +00:00
|
|
|
async def test_handling_invalid_data(mock_request: Mock) -> None:
|
2018-11-30 20:28:35 +00:00
|
|
|
"""Test handling unauth exceptions."""
|
|
|
|
with pytest.raises(HTTPBadRequest):
|
|
|
|
await request_handler_factory(
|
2024-03-07 17:03:44 +00:00
|
|
|
mock_request.app[KEY_HASS],
|
2023-05-21 18:36:03 +00:00
|
|
|
Mock(requires_auth=False),
|
|
|
|
AsyncMock(side_effect=vol.Invalid("yo")),
|
2018-11-30 20:28:35 +00:00
|
|
|
)(mock_request)
|
|
|
|
|
|
|
|
|
2023-05-21 18:36:03 +00:00
|
|
|
async def test_handling_service_not_found(mock_request: Mock) -> None:
|
2018-11-30 20:28:35 +00:00
|
|
|
"""Test handling unauth exceptions."""
|
|
|
|
with pytest.raises(HTTPInternalServerError):
|
|
|
|
await request_handler_factory(
|
2024-03-07 17:03:44 +00:00
|
|
|
mock_request.app[KEY_HASS],
|
2018-11-30 20:28:35 +00:00
|
|
|
Mock(requires_auth=False),
|
2020-04-30 23:31:00 +00:00
|
|
|
AsyncMock(side_effect=ServiceNotFound("test", "test")),
|
2018-11-30 20:28:35 +00:00
|
|
|
)(mock_request)
|
2020-06-02 18:54:11 +00:00
|
|
|
|
|
|
|
|
2023-05-21 18:36:03 +00:00
|
|
|
async def test_not_running(mock_request_with_stopping: Mock) -> None:
|
2020-06-02 18:54:11 +00:00
|
|
|
"""Test we get a 503 when not running."""
|
|
|
|
response = await request_handler_factory(
|
2024-03-07 17:03:44 +00:00
|
|
|
mock_request_with_stopping.app[KEY_HASS],
|
2023-05-21 18:36:03 +00:00
|
|
|
Mock(requires_auth=False),
|
|
|
|
AsyncMock(side_effect=Unauthorized),
|
2020-06-02 18:54:11 +00:00
|
|
|
)(mock_request_with_stopping)
|
2021-10-23 18:34:53 +00:00
|
|
|
assert response.status == HTTPStatus.SERVICE_UNAVAILABLE
|
2023-05-21 18:36:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_invalid_handler(mock_request: Mock) -> None:
|
|
|
|
"""Test an invalid handler."""
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
await request_handler_factory(
|
2024-03-07 17:03:44 +00:00
|
|
|
mock_request.app[KEY_HASS],
|
2023-05-21 18:36:03 +00:00
|
|
|
Mock(requires_auth=False),
|
|
|
|
AsyncMock(return_value=["not valid"]),
|
|
|
|
)(mock_request)
|