Skip to content

Commit c65fd01

Browse files
committed
added models, events config data and events metadata
1 parent 09e8b45 commit c65fd01

File tree

6 files changed

+262
-1
lines changed

6 files changed

+262
-1
lines changed

splitio/events/__init__.py

Whitespace-only changes.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
"""Events Manager Configuration."""
2+
from splitio.models.events import SdkEvent, SdkInternalEvent
3+
4+
class EventsManagerConfig(object):
5+
"""Events Manager Configurations class."""
6+
7+
def __init__(self):
8+
"""
9+
Construct Events Manager Configuration instance.
10+
"""
11+
self._require_all = self._get_require_all()
12+
self._prerequisites = self._get_prerequisites()
13+
self._require_any = self._get_require_any()
14+
self._suppressed_by = self._get_suppressed_by()
15+
self._execution_limits = self._get_execution_limits()
16+
self._evaluation_order = self._get_sorted_events()
17+
18+
@property
19+
def require_all(self):
20+
"""Return require all dict"""
21+
return self._require_all
22+
23+
@property
24+
def prerequisites(self):
25+
"""Return prerequisites dict"""
26+
return self._prerequisites
27+
28+
@property
29+
def require_any(self):
30+
"""Return require_any dict"""
31+
return self._require_any
32+
33+
@property
34+
def suppressed_by(self):
35+
"""Return suppressed_by dict"""
36+
return self._suppressed_by
37+
38+
@property
39+
def execution_limits(self):
40+
"""Return execution_limits dict"""
41+
return self._execution_limits
42+
43+
@property
44+
def prerequisites(self):
45+
"""Return require all dict"""
46+
return self._prerequisites
47+
48+
@property
49+
def evaluation_order(self):
50+
"""Return evaluation_order dict"""
51+
return self._evaluation_order
52+
53+
@property
54+
def sorted_events(self):
55+
"""Return sorted_events dict"""
56+
return self._sorted_events
57+
58+
def _get_require_all(self):
59+
"""Return require all dict"""
60+
return {
61+
SdkEvent.SDK_READY: {SdkInternalEvent.SDK_READY}
62+
}
63+
64+
def _get_prerequisites(self):
65+
"""Return prerequisites dict"""
66+
return {
67+
SdkEvent.SDK_UPDATE: {SdkEvent.SDK_READY}
68+
}
69+
70+
def _get_require_any(self):
71+
"""Return require_any dict"""
72+
return {
73+
SdkEvent.SDK_UPDATE: {SdkInternalEvent.FLAG_KILLED_NOTIFICATION, SdkInternalEvent.FLAGS_UPDATED,
74+
SdkInternalEvent.RB_SEGMENTS_UPDATED, SdkInternalEvent.SEGMENTS_UPDATED},
75+
SdkEvent.SDK_READY_TIMED_OUT: {SdkInternalEvent.SDK_TIMED_OUT}
76+
}
77+
78+
def _get_suppressed_by(self):
79+
"""Return suppressed_by dict"""
80+
return {
81+
SdkEvent.SDK_READY_TIMED_OUT: {SdkEvent.SDK_READY}
82+
}
83+
84+
def _get_execution_limits(self):
85+
"""Return execution_limits dict"""
86+
return {
87+
SdkEvent.SDK_READY: 1,
88+
SdkEvent.SDK_READY_TIMED_OUT: -1,
89+
SdkEvent.SDK_UPDATE: -1
90+
}
91+
92+
def _get_sorted_events(self):
93+
"""Return dorted events set"""
94+
sorted_events = []
95+
for sdk_event in [SdkEvent.SDK_READY, SdkEvent.SDK_READY_TIMED_OUT, SdkEvent.SDK_UPDATE]:
96+
sorted_events = self._dfs_recursive(sdk_event, sorted_events)
97+
98+
return sorted_events
99+
100+
101+
def _dfs_recursive(self, sdk_event, added):
102+
"""Return sorted events set based on the dependency rules"""
103+
if sdk_event in added:
104+
return added
105+
106+
for dependent_event in self._get_dependencies(sdk_event):
107+
added = self._dfs_recursive(dependent_event, added)
108+
109+
added.append(sdk_event)
110+
return added
111+
112+
def _get_dependencies(self, sdk_event):
113+
"""Return dependencies set from prerequisites and suppressed events for a given event"""
114+
dependencies = set()
115+
for prerequisites_event_name, prerequisites_event_value in self.prerequisites.items():
116+
if prerequisites_event_name == sdk_event:
117+
for prereq_event in prerequisites_event_value:
118+
dependencies.add(prereq_event)
119+
120+
for suppressed_event_name, suppressed_event_value in self.suppressed_by.items():
121+
if sdk_event in suppressed_event_value:
122+
dependencies.add(suppressed_event_name)
123+
124+
return dependencies

splitio/events/events_metadata.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""Events Metadata."""
2+
from splitio.models.events import SdkEvent, SdkInternalEvent
3+
4+
class EventsMetadata(object):
5+
"""Events Metadata class."""
6+
7+
def __init__(self, metadata):
8+
"""
9+
Construct Events Metadata instance.
10+
"""
11+
self._metadata = self._sanitize(metadata)
12+
13+
def get_data(self):
14+
"""Return metadata dict"""
15+
return self._metadata
16+
17+
def get_keys(self):
18+
"""Return metadata dict keys"""
19+
return self._metadata.keys()
20+
21+
def get_values(self):
22+
"""Return metadata dict values"""
23+
return self._metadata.values()
24+
25+
def contain_key(self, key):
26+
"""Return True if key is contained in metadata"""
27+
return key in self._metadata.keys()
28+
29+
def _sanitize(self, data):
30+
"""Return sanitized metadata dict with values either int, bool, str or list """
31+
santized_data = {}
32+
for item_name, item_value in data.items():
33+
if self._value_is_valid(item_value):
34+
santized_data[item_name] = item_value
35+
36+
return santized_data
37+
38+
def _value_is_valid(self, value):
39+
"""Return bool if values is int, bool, str or list[str] """
40+
if (value is not None) and (isinstance(value, int) or isinstance(value, bool) or isinstance(value, str)):
41+
return True
42+
43+
if isinstance(value, set):
44+
return any([isinstance(item, str) for item in value])
45+
46+
return False

splitio/models/events.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
The dto is implemented as a namedtuple for performance matters.
55
"""
66
from collections import namedtuple
7-
7+
from enum import Enum
88

99
Event = namedtuple('Event', [
1010
'key',
@@ -19,3 +19,23 @@
1919
'event',
2020
'size',
2121
])
22+
23+
class SdkEvent(Enum):
24+
"""Public SDK events"""
25+
26+
SDK_READY = 'SDK_READY'
27+
SDK_READY_TIMED_OUT = 'SDK_READY_TIMED_OUT'
28+
SDK_UPDATE = 'SDK_UPDATE'
29+
30+
class SdkInternalEvent(Enum):
31+
"""Internal SDK events"""
32+
33+
SDK_READY = 'SDK_READY'
34+
SDK_TIMED_OUT = 'SDK_TIMED_OUT'
35+
FLAGS_UPDATED = 'FLAGS_UPDATED'
36+
FLAG_KILLED_NOTIFICATION = 'FLAG_KILLED_NOTIFICATION'
37+
SEGMENTS_UPDATED = 'SEGMENTS_UPDATED'
38+
RB_SEGMENTS_UPDATED = 'RB_SEGMENTS_UPDATED'
39+
LARGE_SEGMENTS_UPDATED = 'LARGE_SEGMENTS_UPDATED'
40+
41+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""EventsManagerConfig test module."""
2+
import pytest
3+
4+
from splitio.events.events_manager_config import EventsManagerConfig
5+
from splitio.models.events import SdkEvent, SdkInternalEvent
6+
7+
class EventsManagerConfigTests(object):
8+
"""Tests for EventsManagerConfig."""
9+
10+
def test_build_instance(self):
11+
config = EventsManagerConfig()
12+
13+
assert len(config.require_all[SdkEvent.SDK_READY]) == 1
14+
assert SdkInternalEvent.SDK_READY in config.require_all[SdkEvent.SDK_READY]
15+
16+
assert SdkEvent.SDK_READY in config.prerequisites[SdkEvent.SDK_UPDATE]
17+
18+
assert config.execution_limits[SdkEvent.SDK_READY_TIMED_OUT] == -1
19+
assert config.execution_limits[SdkEvent.SDK_UPDATE] == -1
20+
assert config.execution_limits[SdkEvent.SDK_READY] == 1
21+
22+
assert len(config.require_any[SdkEvent.SDK_READY_TIMED_OUT]) == 1
23+
assert SdkInternalEvent.SDK_TIMED_OUT in config.require_any[SdkEvent.SDK_READY_TIMED_OUT]
24+
25+
assert len(config.require_any[SdkEvent.SDK_UPDATE]) == 4
26+
assert SdkInternalEvent.FLAG_KILLED_NOTIFICATION in config.require_any[SdkEvent.SDK_UPDATE]
27+
assert SdkInternalEvent.FLAGS_UPDATED in config.require_any[SdkEvent.SDK_UPDATE]
28+
assert SdkInternalEvent.RB_SEGMENTS_UPDATED in config.require_any[SdkEvent.SDK_UPDATE]
29+
assert SdkInternalEvent.SEGMENTS_UPDATED in config.require_any[SdkEvent.SDK_UPDATE]
30+
31+
assert len(config.suppressed_by[SdkEvent.SDK_READY_TIMED_OUT]) == 1
32+
assert SdkEvent.SDK_READY in config.suppressed_by[SdkEvent.SDK_READY_TIMED_OUT]
33+
34+
order = 0
35+
assert len(config.evaluation_order) == 3
36+
for sdk_event in config.evaluation_order:
37+
order += 1
38+
if order == 1:
39+
assert sdk_event == SdkEvent.SDK_READY_TIMED_OUT
40+
if order == 2:
41+
assert sdk_event == SdkEvent.SDK_READY
42+
if order == 3:
43+
assert sdk_event == SdkEvent.SDK_UPDATE
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""EventsMetadata test module."""
2+
import pytest
3+
4+
from splitio.events.events_metadata import EventsMetadata
5+
from splitio.models.events import SdkEvent, SdkInternalEvent
6+
7+
class EventsMetadataTests(object):
8+
"""Tests for EventsMetadata."""
9+
10+
def test_build_instance(self):
11+
data = { "updatedFlags": { "feature1" }, "sdkTimeout": 10 , "boolValue": True, "strValue": "value" }
12+
metadata = EventsMetadata(data)
13+
14+
assert len(metadata.get_keys()) == 4
15+
assert metadata.get_data()["updatedFlags"].pop() == "feature1"
16+
assert len(metadata.get_data()["updatedFlags"]) == 0
17+
assert metadata.get_data()["sdkTimeout"] == 10
18+
assert metadata.get_data()["boolValue"] == True
19+
assert metadata.get_data()["strValue"] == "value"
20+
assert metadata.contain_key("updatedFlags")
21+
assert not metadata.contain_key("not_exist")
22+
assert len(metadata.get_values()) == 4
23+
24+
def test_sanitize_none_input(self):
25+
data = { "updatedFlags": { "feature1" }, "sdkTimeout": None, "strValue": [1, 2, 3] }
26+
metadata = EventsMetadata(data)
27+
assert len(metadata.get_keys()) == 1
28+
assert metadata.get_data()["updatedFlags"].pop() == "feature1"

0 commit comments

Comments
 (0)