Raise an exception when event_type exceeds the max length (#48115)

* raise an exception when event_type exceeds the max length that the recorder supports

* add test

* use max length constant in recorder

* update config entry reloaded service name

* remove exception string function because it's not needed

* increase limit to 64 and revert event name change

* fix test

* assert exception args

* fix test

* add comment about migration
This commit is contained in:
Raman Gupta 2021-04-08 14:46:28 -04:00 committed by GitHub
parent 1f80c756ab
commit 3ca69f5568
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 1 deletions

View File

@ -18,6 +18,7 @@ from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.orm.session import Session
from homeassistant.const import MAX_LENGTH_EVENT_TYPE
from homeassistant.core import Context, Event, EventOrigin, State, split_entity_id
from homeassistant.helpers.json import JSONEncoder
import homeassistant.util.dt as dt_util
@ -53,7 +54,7 @@ class Events(Base): # type: ignore
}
__tablename__ = TABLE_EVENTS
event_id = Column(Integer, primary_key=True)
event_type = Column(String(64))
event_type = Column(String(MAX_LENGTH_EVENT_TYPE))
event_data = Column(Text().with_variant(mysql.LONGTEXT, "mysql"))
origin = Column(String(32))
time_fired = Column(DATETIME_TYPE, index=True)

View File

@ -22,6 +22,10 @@ ENTITY_MATCH_ALL = "all"
# If no name is specified
DEVICE_DEFAULT_NAME = "Unnamed Device"
# Max characters for an event_type (changing this requires a recorder
# database migration)
MAX_LENGTH_EVENT_TYPE = 64
# Sun events
SUN_EVENT_SUNSET = "sunset"
SUN_EVENT_SUNRISE = "sunrise"

View File

@ -58,12 +58,14 @@ from homeassistant.const import (
EVENT_TIMER_OUT_OF_SYNC,
LENGTH_METERS,
MATCH_ALL,
MAX_LENGTH_EVENT_TYPE,
__version__,
)
from homeassistant.exceptions import (
HomeAssistantError,
InvalidEntityFormatError,
InvalidStateError,
MaxLengthExceeded,
ServiceNotFound,
Unauthorized,
)
@ -697,6 +699,9 @@ class EventBus:
This method must be run in the event loop.
"""
if len(event_type) > MAX_LENGTH_EVENT_TYPE:
raise MaxLengthExceeded(event_type, "event_type", MAX_LENGTH_EVENT_TYPE)
listeners = self._listeners.get(event_type, [])
# EVENT_HOMEASSISTANT_CLOSE should go only to his listeners

View File

@ -154,3 +154,20 @@ class ServiceNotFound(HomeAssistantError):
def __str__(self) -> str:
"""Return string representation."""
return f"Unable to find service {self.domain}.{self.service}"
class MaxLengthExceeded(HomeAssistantError):
"""Raised when a property value has exceeded the max character length."""
def __init__(self, value: str, property_name: str, max_length: int) -> None:
"""Initialize error."""
super().__init__(
self,
(
f"Value {value} for property {property_name} has a max length of "
f"{max_length} characters"
),
)
self.value = value
self.property_name = property_name
self.max_length = max_length

View File

@ -36,6 +36,7 @@ import homeassistant.core as ha
from homeassistant.exceptions import (
InvalidEntityFormatError,
InvalidStateError,
MaxLengthExceeded,
ServiceNotFound,
)
import homeassistant.util.dt as dt_util
@ -524,6 +525,21 @@ async def test_eventbus_coroutine_event_listener(hass):
assert len(coroutine_calls) == 1
async def test_eventbus_max_length_exceeded(hass):
"""Test that an exception is raised when the max character length is exceeded."""
long_evt_name = (
"this_event_exceeds_the_max_character_length_even_with_the_new_limit"
)
with pytest.raises(MaxLengthExceeded) as exc_info:
hass.bus.async_fire(long_evt_name)
assert exc_info.value.property_name == "event_type"
assert exc_info.value.max_length == 64
assert exc_info.value.value == long_evt_name
def test_state_init():
"""Test state.init."""
with pytest.raises(InvalidEntityFormatError):