From a3ddd6fb428c5d604ac547e06f42b0b7e10fce9d Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 17:25:44 +0530 Subject: [PATCH 01/12] Common: Create directory and files for event serializer --- monkey/common/event_serializers/__init__.py | 0 monkey/common/event_serializers/i_event_serialize.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 monkey/common/event_serializers/__init__.py create mode 100644 monkey/common/event_serializers/i_event_serialize.py diff --git a/monkey/common/event_serializers/__init__.py b/monkey/common/event_serializers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/common/event_serializers/i_event_serialize.py b/monkey/common/event_serializers/i_event_serialize.py new file mode 100644 index 000000000..e69de29bb From c09adfb01b1948ce6e2812e27881247ff86033e3 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 17:57:28 +0530 Subject: [PATCH 02/12] Common: Add IEventSerializer --- .../event_serializers/i_event_serialize.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/monkey/common/event_serializers/i_event_serialize.py b/monkey/common/event_serializers/i_event_serialize.py index e69de29bb..f78d2eb43 100644 --- a/monkey/common/event_serializers/i_event_serialize.py +++ b/monkey/common/event_serializers/i_event_serialize.py @@ -0,0 +1,34 @@ +from abc import ABC, abstractmethod +from typing import Dict, List, Type, Union + +from common.events import AbstractEvent + +JSONSerializable = Union[ + Dict[str, "JSONSerializable"], List["JSONSerializable"], int, str, float, bool, Type[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 vent to deserialize + :return: Deserialized event + """ + pass From 0b9191ca438f040596e9b47c3c1e17284defa017 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 21:28:33 +0530 Subject: [PATCH 03/12] Common: Add IEventSerializer to common/event_serializers/__init__.py --- monkey/common/event_serializers/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/monkey/common/event_serializers/__init__.py b/monkey/common/event_serializers/__init__.py index e69de29bb..1a5289f46 100644 --- a/monkey/common/event_serializers/__init__.py +++ b/monkey/common/event_serializers/__init__.py @@ -0,0 +1 @@ +from .i_event_serialize import IEventSerializer From 141c766b51d8faa55b8bd66582958ff34d521091 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 21:29:06 +0530 Subject: [PATCH 04/12] Common: Add EventSerializerRegistry --- .../event_serializer_registry.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 monkey/common/event_serializers/event_serializer_registry.py diff --git a/monkey/common/event_serializers/event_serializer_registry.py b/monkey/common/event_serializers/event_serializer_registry.py new file mode 100644 index 000000000..2b49f4223 --- /dev/null +++ b/monkey/common/event_serializers/event_serializer_registry.py @@ -0,0 +1,17 @@ +from common.event_serializers import IEventSerializer + + +class EventSerializerRegistry: + """ + Registry for event serializers + """ + + def __init__(self): + self._registry = {} + + def __setitem__(self, event_class_name: str, event_serializer: IEventSerializer): + self._registry[event_class_name] = event_serializer + + def __getitem__(self, event_class_name: str): + event_serializer = self._registry[event_class_name] + return event_serializer From 132f3a3473f49c07b5cd8fcd41459eb356601b1d Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 17 Aug 2022 21:31:35 +0530 Subject: [PATCH 05/12] Project: Add event serializer entries to Vulture allowlist --- vulture_allowlist.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vulture_allowlist.py b/vulture_allowlist.py index f547e8e5c..3d0f6840f 100644 --- a/vulture_allowlist.py +++ b/vulture_allowlist.py @@ -275,3 +275,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 From 23604009a05c27f51344f165e1adf2a9c15651bb Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 18 Aug 2022 09:32:02 +0200 Subject: [PATCH 06/12] Common: Fix hint in IEventSerializer --- monkey/common/event_serializers/i_event_serialize.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monkey/common/event_serializers/i_event_serialize.py b/monkey/common/event_serializers/i_event_serialize.py index f78d2eb43..5544e6ede 100644 --- a/monkey/common/event_serializers/i_event_serialize.py +++ b/monkey/common/event_serializers/i_event_serialize.py @@ -1,10 +1,10 @@ from abc import ABC, abstractmethod -from typing import Dict, List, Type, Union +from typing import Dict, List, Union from common.events import AbstractEvent JSONSerializable = Union[ - Dict[str, "JSONSerializable"], List["JSONSerializable"], int, str, float, bool, Type[None] + Dict[str, "JSONSerializable"], List["JSONSerializable"], int, str, float, bool, None ] @@ -28,7 +28,7 @@ class IEventSerializer(ABC): """ Deserializes an event - :param serialized_event: Serialized vent to deserialize + :param serialized_event: Serialized event to deserialize :return: Deserialized event """ pass From a32d9359b0722565d46a0efc99a770178897c4ad Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 18 Aug 2022 09:42:05 +0200 Subject: [PATCH 07/12] Common: Accept Union[str, Type[AbstractEvent]] in EventSerializerRegistry --- .../event_serializer_registry.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/monkey/common/event_serializers/event_serializer_registry.py b/monkey/common/event_serializers/event_serializer_registry.py index 2b49f4223..c5710c850 100644 --- a/monkey/common/event_serializers/event_serializer_registry.py +++ b/monkey/common/event_serializers/event_serializer_registry.py @@ -1,17 +1,21 @@ +from typing import Type, Union + from common.event_serializers import IEventSerializer +from common.events import AbstractEvent class EventSerializerRegistry: """ - Registry for event serializers + Registry for event serializers using event class. """ def __init__(self): self._registry = {} - def __setitem__(self, event_class_name: str, event_serializer: IEventSerializer): - self._registry[event_class_name] = event_serializer + def __setitem__( + self, event_class: Union[str, Type[AbstractEvent]], event_serializer: IEventSerializer + ): + self._registry[event_class] = event_serializer - def __getitem__(self, event_class_name: str): - event_serializer = self._registry[event_class_name] - return event_serializer + def __getitem__(self, event_class: Union[str, Type[AbstractEvent]]): + return self._registry[event_class] From e83503e65a96015af780ba2b6b6c6e101b9b8977 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 18 Aug 2022 10:30:38 +0200 Subject: [PATCH 08/12] Common: Export EventSerializerRegistry from __init__ --- monkey/common/event_serializers/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/monkey/common/event_serializers/__init__.py b/monkey/common/event_serializers/__init__.py index 1a5289f46..2b60471b1 100644 --- a/monkey/common/event_serializers/__init__.py +++ b/monkey/common/event_serializers/__init__.py @@ -1 +1,2 @@ from .i_event_serialize import IEventSerializer +from .event_serializer_registry import EventSerializerRegistry From aeaabbccc4b40f639632432a87d3f63ca4296d39 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 18 Aug 2022 10:31:10 +0200 Subject: [PATCH 09/12] UT: Test EventSerializerRegistry --- .../test_event_serializer_registry.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 monkey/tests/unit_tests/common/event_serializers/test_event_serializer_registry.py diff --git a/monkey/tests/unit_tests/common/event_serializers/test_event_serializer_registry.py b/monkey/tests/unit_tests/common/event_serializers/test_event_serializer_registry.py new file mode 100644 index 000000000..0e56fcb1b --- /dev/null +++ b/monkey/tests/unit_tests/common/event_serializers/test_event_serializer_registry.py @@ -0,0 +1,28 @@ +from dataclasses import dataclass, field + +from common.event_serializers import EventSerializerRegistry +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) + + +def test_event_serializer_registry(): + + event_serializer_registry = EventSerializerRegistry() + + some_event = SomeEvent(some_param=123) + other_event = OtherEvent() + + event_serializer_registry[SomeEvent] = some_event + event_serializer_registry[OtherEvent] = other_event + + assert event_serializer_registry[some_event.__class__] == some_event + assert event_serializer_registry[other_event.__class__] == other_event From 4b1ad70f848ba8c40070c3414afdfe858d35f092 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 18 Aug 2022 10:33:10 +0200 Subject: [PATCH 10/12] Common: Set event to registry only by class --- monkey/common/event_serializers/event_serializer_registry.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/monkey/common/event_serializers/event_serializer_registry.py b/monkey/common/event_serializers/event_serializer_registry.py index c5710c850..3e1ada7e8 100644 --- a/monkey/common/event_serializers/event_serializer_registry.py +++ b/monkey/common/event_serializers/event_serializer_registry.py @@ -12,9 +12,7 @@ class EventSerializerRegistry: def __init__(self): self._registry = {} - def __setitem__( - self, event_class: Union[str, Type[AbstractEvent]], event_serializer: IEventSerializer - ): + def __setitem__(self, event_class: Type[AbstractEvent], event_serializer: IEventSerializer): self._registry[event_class] = event_serializer def __getitem__(self, event_class: Union[str, Type[AbstractEvent]]): From b541dc465d55d5b19f5029f57312faa5466f8d14 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 18 Aug 2022 15:21:33 +0200 Subject: [PATCH 11/12] Common: Type checking in EventSerializerRegistry --- .../event_serializer_registry.py | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/monkey/common/event_serializers/event_serializer_registry.py b/monkey/common/event_serializers/event_serializer_registry.py index 3e1ada7e8..fd02045d1 100644 --- a/monkey/common/event_serializers/event_serializer_registry.py +++ b/monkey/common/event_serializers/event_serializer_registry.py @@ -7,13 +7,35 @@ 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): - self._registry[event_class] = event_serializer + 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__}" + ) - def __getitem__(self, event_class: Union[str, Type[AbstractEvent]]): return self._registry[event_class] From ff0469690ffce18516b218afb289c1df83105325 Mon Sep 17 00:00:00 2001 From: Ilija Lazoroski Date: Thu, 18 Aug 2022 15:22:09 +0200 Subject: [PATCH 12/12] UT: Add type checking tests for EventSerializer Registry --- .../test_event_serializer_registry.py | 59 ++++++++++++++++--- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/monkey/tests/unit_tests/common/event_serializers/test_event_serializer_registry.py b/monkey/tests/unit_tests/common/event_serializers/test_event_serializer_registry.py index 0e56fcb1b..43f909bec 100644 --- a/monkey/tests/unit_tests/common/event_serializers/test_event_serializer_registry.py +++ b/monkey/tests/unit_tests/common/event_serializers/test_event_serializer_registry.py @@ -1,6 +1,9 @@ from dataclasses import dataclass, field +from unittest.mock import MagicMock -from common.event_serializers import EventSerializerRegistry +import pytest + +from common.event_serializers import EventSerializerRegistry, IEventSerializer from common.events import AbstractEvent @@ -14,15 +17,55 @@ class OtherEvent(AbstractEvent): other_param: float = field(default=123.456) -def test_event_serializer_registry(): +@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() - some_event = SomeEvent(some_param=123) - other_event = OtherEvent() + event_serializer_registry[SomeEvent] = SOME_SERIALIZER + event_serializer_registry[OtherEvent] = OTHER_SERIALIZER - event_serializer_registry[SomeEvent] = some_event - event_serializer_registry[OtherEvent] = other_event + return event_serializer_registry - assert event_serializer_registry[some_event.__class__] == some_event - assert event_serializer_registry[other_event.__class__] == other_event + +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__]