Merge pull request #2205 from guardicore/2179-create-ieventserializer

Event serializer
This commit is contained in:
ilija-lazoroski 2022-08-18 16:06:14 +02:00 committed by GitHub
commit 808bf5fee9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 156 additions and 0 deletions

View File

@ -0,0 +1,2 @@
from .i_event_serialize import IEventSerializer
from .event_serializer_registry import EventSerializerRegistry

View File

@ -0,0 +1,41 @@
from typing import Type, Union
from common.event_serializers import IEventSerializer
from common.events import AbstractEvent
class EventSerializerRegistry:
"""
Registry for event serializers using event class.
Example:
event_serializer_registry = EventSerializerRegistry()
event_serializer_registry[MyEvent] = MyEventSerializer()
my_event_dict = {"type": "MyEvent", "data": "123"}
serializer = event_serializer_registry[my_event_dict["type"]]
my_event_object = serializer.deserialize(my_event_dict)
"""
def __init__(self):
self._registry = {}
def __setitem__(self, event_class: Type[AbstractEvent], event_serializer: IEventSerializer):
if not issubclass(event_class, AbstractEvent):
raise TypeError(f"Event class must be of type: {AbstractEvent.__name__}")
if not isinstance(event_serializer, IEventSerializer):
raise TypeError(f"Event serializer must be of type: {IEventSerializer.__name__}")
self._registry[event_class] = event_serializer
self._registry[event_class.__name__] = event_serializer
def __getitem__(self, event_class: Union[str, Type[AbstractEvent]]) -> IEventSerializer:
if not (isinstance(event_class, str) or issubclass(event_class, AbstractEvent)):
raise TypeError(
f"Registry get key {event_class} must be of type: {AbstractEvent.__name__} or "
f"{str.__name__}"
)
return self._registry[event_class]

View File

@ -0,0 +1,34 @@
from abc import ABC, abstractmethod
from typing import Dict, List, Union
from common.events import AbstractEvent
JSONSerializable = Union[
Dict[str, "JSONSerializable"], List["JSONSerializable"], int, str, float, bool, None
]
class IEventSerializer(ABC):
"""
Manages serialization and deserialization of events
"""
@abstractmethod
def serialize(self, event: AbstractEvent) -> JSONSerializable:
"""
Serializes an event
:param event: Event to serialize
:return: Serialized event
"""
pass
@abstractmethod
def deserialize(self, serialized_event: JSONSerializable) -> AbstractEvent:
"""
Deserializes an event
:param serialized_event: Serialized event to deserialize
:return: Deserialized event
"""
pass

View File

@ -0,0 +1,71 @@
from dataclasses import dataclass, field
from unittest.mock import MagicMock
import pytest
from common.event_serializers import EventSerializerRegistry, IEventSerializer
from common.events import AbstractEvent
@dataclass(frozen=True)
class SomeEvent(AbstractEvent):
some_param: int = field(default=435)
@dataclass(frozen=True)
class OtherEvent(AbstractEvent):
other_param: float = field(default=123.456)
@dataclass(frozen=True)
class NoneEvent(AbstractEvent):
none_param: float = field(default=1.0)
SOME_SERIALIZER = MagicMock(spec=IEventSerializer)
OTHER_SERIALIZER = MagicMock(spec=IEventSerializer)
@pytest.fixture
def event_serializer_registry():
event_serializer_registry = EventSerializerRegistry()
event_serializer_registry[SomeEvent] = SOME_SERIALIZER
event_serializer_registry[OtherEvent] = OTHER_SERIALIZER
return event_serializer_registry
def test_event_serializer_registry_event(event_serializer_registry):
assert event_serializer_registry[SomeEvent] == SOME_SERIALIZER
assert event_serializer_registry[OtherEvent] == OTHER_SERIALIZER
def test_event_serializer_registry_string(event_serializer_registry):
assert event_serializer_registry[SomeEvent.__name__] == SOME_SERIALIZER
assert event_serializer_registry[OtherEvent.__name__] == OTHER_SERIALIZER
def test_event_serializer_registry_set_unsupported_type(event_serializer_registry):
with pytest.raises(TypeError):
event_serializer_registry[SomeEvent] = "SomethingBogusVogus"
def test_event_serializer_registry_set_unsupported_type_key(event_serializer_registry):
with pytest.raises(TypeError):
event_serializer_registry["BogusKey"] = MagicMock(spec=IEventSerializer)
def test_event_serializer_registry_get_unsuported_type(event_serializer_registry):
with pytest.raises(TypeError):
event_serializer_registry[1]
def test_event_serializer_registry_get_unexisting_type(event_serializer_registry):
with pytest.raises(KeyError):
event_serializer_registry[NoneEvent]
def test_event_serializer_registry_get_unexisting_string(event_serializer_registry):
with pytest.raises(KeyError):
event_serializer_registry[NoneEvent.__name__]

View File

@ -266,3 +266,11 @@ subscribe_tag # common\event_queue\pypubsub_event_queue.py
publish # common\event_queue\pypubsub_event_queue.py
PyPubSubEventQueue # common\event_queue\pypubsub_event_queue.py
subscribe_all_events # common\event_queue\pypubsub_event_queue.py
# TODO: Remove once #2179 is closed
EventSerializerRegistry
serialize
event
deserialize
serialized_event