Improve error handling in /api/states POST (#99810)

This commit is contained in:
Erik Montnemery 2023-09-07 13:33:38 +02:00 committed by GitHub
parent eee5705458
commit 368acaf6fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 5 deletions

View File

@ -30,7 +30,13 @@ from homeassistant.const import (
) )
import homeassistant.core as ha import homeassistant.core as ha
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceNotFound, TemplateError, Unauthorized from homeassistant.exceptions import (
InvalidEntityFormatError,
InvalidStateError,
ServiceNotFound,
TemplateError,
Unauthorized,
)
from homeassistant.helpers import config_validation as cv, template from homeassistant.helpers import config_validation as cv, template
from homeassistant.helpers.json import json_dumps from homeassistant.helpers.json import json_dumps
from homeassistant.helpers.service import async_get_all_descriptions from homeassistant.helpers.service import async_get_all_descriptions
@ -236,7 +242,7 @@ class APIEntityStateView(HomeAssistantView):
"""Update state of entity.""" """Update state of entity."""
if not request["hass_user"].is_admin: if not request["hass_user"].is_admin:
raise Unauthorized(entity_id=entity_id) raise Unauthorized(entity_id=entity_id)
hass = request.app["hass"] hass: HomeAssistant = request.app["hass"]
try: try:
data = await request.json() data = await request.json()
except ValueError: except ValueError:
@ -251,9 +257,16 @@ class APIEntityStateView(HomeAssistantView):
is_new_state = hass.states.get(entity_id) is None is_new_state = hass.states.get(entity_id) is None
# Write state # Write state
try:
hass.states.async_set( hass.states.async_set(
entity_id, new_state, attributes, force_update, self.context(request) entity_id, new_state, attributes, force_update, self.context(request)
) )
except InvalidEntityFormatError:
return self.json_message(
"Invalid entity ID specified.", HTTPStatus.BAD_REQUEST
)
except InvalidStateError:
return self.json_message("Invalid state specified.", HTTPStatus.BAD_REQUEST)
# Read the state back for our response # Read the state back for our response
status_code = HTTPStatus.CREATED if is_new_state else HTTPStatus.OK status_code = HTTPStatus.CREATED if is_new_state else HTTPStatus.OK

View File

@ -97,6 +97,28 @@ async def test_api_state_change_of_non_existing_entity(
assert hass.states.get("test_entity.that_does_not_exist").state == new_state assert hass.states.get("test_entity.that_does_not_exist").state == new_state
async def test_api_state_change_with_bad_entity_id(
hass: HomeAssistant, mock_api_client: TestClient
) -> None:
"""Test if API sends appropriate error if we omit state."""
resp = await mock_api_client.post(
"/api/states/bad.entity.id", json={"state": "new_state"}
)
assert resp.status == HTTPStatus.BAD_REQUEST
async def test_api_state_change_with_bad_state(
hass: HomeAssistant, mock_api_client: TestClient
) -> None:
"""Test if API sends appropriate error if we omit state."""
resp = await mock_api_client.post(
"/api/states/test.test", json={"state": "x" * 256}
)
assert resp.status == HTTPStatus.BAD_REQUEST
async def test_api_state_change_with_bad_data( async def test_api_state_change_with_bad_data(
hass: HomeAssistant, mock_api_client: TestClient hass: HomeAssistant, mock_api_client: TestClient
) -> None: ) -> None: