Skip to content

Commit 38329f2

Browse files
authored
Merge branch 'Feature/FlagSets' into flagsets-tests-e2e
2 parents 837e571 + db469a5 commit 38329f2

File tree

6 files changed

+66
-56
lines changed

6 files changed

+66
-56
lines changed

splitio/client/client.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,12 @@ def _get_feature_flag_names_by_flag_sets(self, flag_sets):
430430
"""
431431
sanitized_flag_sets = config.sanitize_flag_sets(flag_sets)
432432
feature_flags = []
433-
[feature_flags.extend(self._split_storage.get_feature_flags_by_set(flag_set)) for flag_set in sanitized_flag_sets]
433+
for flag_set in sanitized_flag_sets:
434+
feature_flags_by_set = self._split_storage.get_feature_flags_by_sets(flag_set)
435+
if feature_flags_by_set is None:
436+
_LOGGER.warning("Fetching feature flags for flag set %s encountered an error, skipping this flag set." % (flag_set))
437+
continue
438+
feature_flags.extend(feature_flags_by_set)
434439
feature_flags_names = []
435440
[feature_flags_names.append(feature_flag) for feature_flag in feature_flags]
436441
return feature_flags_names

splitio/client/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
'storageWrapper': None,
6161
'storagePrefix': None,
6262
'storageType': None,
63-
'FlagSetsFilter': None
63+
'flagSetsFilter': None
6464
}
6565

6666
def _parse_operation_mode(sdk_key, config):
@@ -179,6 +179,6 @@ def sanitize(sdk_key, config):
179179
_LOGGER.warning('metricRefreshRate parameter minimum value is 60 seconds, defaulting to 3600 seconds.')
180180
processed['metricsRefreshRate'] = 3600
181181

182-
processed['FlagSetsFilter'] = sanitize_flag_sets(processed['FlagSetsFilter']) if processed['FlagSetsFilter'] is not None else None
182+
processed['flagSetsFilter'] = sanitize_flag_sets(processed['flagSetsFilter']) if processed['flagSetsFilter'] is not None else None
183183

184184
return processed

splitio/client/factory.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ def _build_in_memory_factory(api_key, cfg, sdk_url=None, events_url=None, # pyl
350350
}
351351

352352
storages = {
353-
'splits': InMemorySplitStorage(),
353+
'splits': InMemorySplitStorage(cfg['flagSetsFilter'] if cfg['flagSetsFilter'] is not None else []),
354354
'segments': InMemorySegmentStorage(),
355355
'impressions': InMemoryImpressionStorage(cfg['impressionsQueueSize'], telemetry_runtime_producer),
356356
'events': InMemoryEventStorage(cfg['eventsQueueSize'], telemetry_runtime_producer),
@@ -523,7 +523,7 @@ def _build_pluggable_factory(api_key, cfg):
523523
pluggable_adapter = cfg.get('storageWrapper')
524524
storage_prefix = cfg.get('storagePrefix')
525525
storages = {
526-
'splits': PluggableSplitStorage(pluggable_adapter, storage_prefix),
526+
'splits': PluggableSplitStorage(pluggable_adapter, storage_prefix, cfg['flagSetsFilter'] if cfg['flagSetsFilter'] is not None else []),
527527
'segments': PluggableSegmentStorage(pluggable_adapter, storage_prefix),
528528
'impressions': PluggableImpressionsStorage(pluggable_adapter, sdk_metadata, storage_prefix),
529529
'events': PluggableEventsStorage(pluggable_adapter, sdk_metadata, storage_prefix),

splitio/models/telemetry.py

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class CounterConstants(Enum):
2727
EVENTS_QUEUED = 'eventsQueued'
2828
EVENTS_DROPPED = 'eventsDropped'
2929

30-
class ConfigParams(Enum):
30+
class _ConfigParams(Enum):
3131
"""Config parameters constants"""
3232
SPLITS_REFRESH_RATE = 'featuresRefreshRate'
3333
SEGMENTS_REFRESH_RATE = 'segmentsRefreshRate'
@@ -41,8 +41,9 @@ class ConfigParams(Enum):
4141
EVENTS_QUEUE_SIZE = 'eventsQueueSize'
4242
IMPRESSIONS_MODE = 'impressionsMode'
4343
IMPRESSIONS_LISTENER = 'impressionListener'
44+
FLAG_SETS = 'flagSetsFilter'
4445

45-
class ExtraConfig(Enum):
46+
class _ExtraConfig(Enum):
4647
"""Extra config constants"""
4748
ACTIVE_FACTORY_COUNT = 'activeFactoryCount'
4849
REDUNDANT_FACTORY_COUNT = 'redundantFactoryCount'
@@ -53,7 +54,7 @@ class ExtraConfig(Enum):
5354
HTTP_PROXY = 'httpProxy'
5455
HTTPS_PROXY_ENV = 'HTTPS_PROXY'
5556

56-
class ApiURLs(Enum):
57+
class _ApiURLs(Enum):
5758
"""Api URL constants"""
5859
SDK_URL = 'sdk_url'
5960
EVENTS_URL = 'events_url'
@@ -88,7 +89,7 @@ class MethodExceptionsAndLatencies(Enum):
8889
TREATMENTS_WITH_CONFIG_BY_FLAG_SETS = 'treatments_with_config_by_flag_sets'
8990
TRACK = 'track'
9091

91-
class LastSynchronizationConstants(Enum):
92+
class _LastSynchronizationConstants(Enum):
9293
"""Last sync constants"""
9394
LAST_SYNCHRONIZATIONS = 'lastSynchronizations'
9495

@@ -108,7 +109,7 @@ class SSESyncMode(Enum):
108109
STREAMING = 0
109110
POLLING = 1
110111

111-
class StreamingEventsConstant(Enum):
112+
class _StreamingEventsConstant(Enum):
112113
"""Storage types constant"""
113114
STREAMING_EVENTS = 'streamingEvents'
114115

@@ -426,7 +427,7 @@ def get_all(self):
426427
:rtype: dict
427428
"""
428429
with self._lock:
429-
return {LastSynchronizationConstants.LAST_SYNCHRONIZATIONS.value: {HTTPExceptionsAndLatencies.SPLIT.value: self._split, HTTPExceptionsAndLatencies.SEGMENT.value: self._segment, HTTPExceptionsAndLatencies.IMPRESSION.value: self._impression,
430+
return {_LastSynchronizationConstants.LAST_SYNCHRONIZATIONS.value: {HTTPExceptionsAndLatencies.SPLIT.value: self._split, HTTPExceptionsAndLatencies.SEGMENT.value: self._segment, HTTPExceptionsAndLatencies.IMPRESSION.value: self._impression,
430431
HTTPExceptionsAndLatencies.IMPRESSION_COUNT.value: self._impression_count, HTTPExceptionsAndLatencies.EVENT.value: self._event,
431432
HTTPExceptionsAndLatencies.TELEMETRY.value: self._telemetry, HTTPExceptionsAndLatencies.TOKEN.value: self._token}
432433
}
@@ -671,6 +672,8 @@ def pop_update_from_sse(self, event):
671672
:rtype: int
672673
"""
673674
with self._lock:
675+
if self._update_from_sse.get(event.value) is None:
676+
return 0
674677
update_from_sse = self._update_from_sse[event.value]
675678
self._update_from_sse[event.value] = 0
676679
return update_from_sse
@@ -758,7 +761,7 @@ def pop_streaming_events(self):
758761
with self._lock:
759762
streaming_events = self._streaming_events
760763
self._streaming_events = []
761-
return {StreamingEventsConstant.STREAMING_EVENTS.value: [{'e': streaming_event.type, 'd': streaming_event.data,
764+
return {_StreamingEventsConstant.STREAMING_EVENTS.value: [{'e': streaming_event.type, 'd': streaming_event.data,
762765
't': streaming_event.time} for streaming_event in streaming_events]}
763766

764767
class TelemetryConfig(object):
@@ -780,10 +783,10 @@ def _reset_all(self):
780783
self._operation_mode = None
781784
self._storage_type = None
782785
self._streaming_enabled = None
783-
self._refresh_rate = {ConfigParams.SPLITS_REFRESH_RATE.value: 0, ConfigParams.SEGMENTS_REFRESH_RATE.value: 0,
784-
ConfigParams.IMPRESSIONS_REFRESH_RATE.value: 0, ConfigParams.EVENTS_REFRESH_RATE.value: 0, ConfigParams.TELEMETRY_REFRESH_RATE.value: 0}
785-
self._url_override = {ApiURLs.SDK_URL.value: False, ApiURLs.EVENTS_URL.value: False, ApiURLs.AUTH_URL.value: False,
786-
ApiURLs.STREAMING_URL.value: False, ApiURLs.TELEMETRY_URL.value: False}
786+
self._refresh_rate = {_ConfigParams.SPLITS_REFRESH_RATE.value: 0, _ConfigParams.SEGMENTS_REFRESH_RATE.value: 0,
787+
_ConfigParams.IMPRESSIONS_REFRESH_RATE.value: 0, _ConfigParams.EVENTS_REFRESH_RATE.value: 0, _ConfigParams.TELEMETRY_REFRESH_RATE.value: 0}
788+
self._url_override = {_ApiURLs.SDK_URL.value: False, _ApiURLs.EVENTS_URL.value: False, _ApiURLs.AUTH_URL.value: False,
789+
_ApiURLs.STREAMING_URL.value: False, _ApiURLs.TELEMETRY_URL.value: False}
787790
self._impressions_queue_size = 0
788791
self._events_queue_size = 0
789792
self._impressions_mode = None
@@ -816,16 +819,17 @@ def record_config(self, config, extra_config):
816819
:type config: dict
817820
"""
818821
with self._lock:
819-
self._operation_mode = self._get_operation_mode(config[ConfigParams.OPERATION_MODE.value])
820-
self._storage_type = self._get_storage_type(config[ConfigParams.OPERATION_MODE.value], config[ConfigParams.STORAGE_TYPE.value])
821-
self._streaming_enabled = config[ConfigParams.STREAMING_ENABLED.value]
822+
self._operation_mode = self._get_operation_mode(config[_ConfigParams.OPERATION_MODE.value])
823+
self._storage_type = self._get_storage_type(config[_ConfigParams.OPERATION_MODE.value], config[_ConfigParams.STORAGE_TYPE.value])
824+
self._streaming_enabled = config[_ConfigParams.STREAMING_ENABLED.value]
822825
self._refresh_rate = self._get_refresh_rates(config)
823826
self._url_override = self._get_url_overrides(extra_config)
824-
self._impressions_queue_size = config[ConfigParams.IMPRESSIONS_QUEUE_SIZE.value]
825-
self._events_queue_size = config[ConfigParams.EVENTS_QUEUE_SIZE.value]
826-
self._impressions_mode = self._get_impressions_mode(config[ConfigParams.IMPRESSIONS_MODE.value])
827-
self._impression_listener = True if config[ConfigParams.IMPRESSIONS_LISTENER.value] is not None else False
827+
self._impressions_queue_size = config[_ConfigParams.IMPRESSIONS_QUEUE_SIZE.value]
828+
self._events_queue_size = config[_ConfigParams.EVENTS_QUEUE_SIZE.value]
829+
self._impressions_mode = self._get_impressions_mode(config[_ConfigParams.IMPRESSIONS_MODE.value])
830+
self._impression_listener = True if config[_ConfigParams.IMPRESSIONS_LISTENER.value] is not None else False
828831
self._http_proxy = self._check_if_proxy_detected()
832+
self._flag_sets = len(config[_ConfigParams.FLAG_SETS.value]) if config[_ConfigParams.FLAG_SETS.value] is not None else 0
829833

830834
def record_active_and_redundant_factories(self, active_factory_count, redundant_factory_count):
831835
with self._lock:
@@ -911,16 +915,16 @@ def get_stats(self):
911915
'oM': self._operation_mode,
912916
'sT': self._storage_type,
913917
'sE': self._streaming_enabled,
914-
'rR': {'sp': self._refresh_rate[ConfigParams.SPLITS_REFRESH_RATE.value],
915-
'se': self._refresh_rate[ConfigParams.SEGMENTS_REFRESH_RATE.value],
916-
'im': self._refresh_rate[ConfigParams.IMPRESSIONS_REFRESH_RATE.value],
917-
'ev': self._refresh_rate[ConfigParams.EVENTS_REFRESH_RATE.value],
918-
'te': self._refresh_rate[ConfigParams.TELEMETRY_REFRESH_RATE.value]},
919-
'uO': {'s': self._url_override[ApiURLs.SDK_URL.value],
920-
'e': self._url_override[ApiURLs.EVENTS_URL.value],
921-
'a': self._url_override[ApiURLs.AUTH_URL.value],
922-
'st': self._url_override[ApiURLs.STREAMING_URL.value],
923-
't': self._url_override[ApiURLs.TELEMETRY_URL.value]},
918+
'rR': {'sp': self._refresh_rate[_ConfigParams.SPLITS_REFRESH_RATE.value],
919+
'se': self._refresh_rate[_ConfigParams.SEGMENTS_REFRESH_RATE.value],
920+
'im': self._refresh_rate[_ConfigParams.IMPRESSIONS_REFRESH_RATE.value],
921+
'ev': self._refresh_rate[_ConfigParams.EVENTS_REFRESH_RATE.value],
922+
'te': self._refresh_rate[_ConfigParams.TELEMETRY_REFRESH_RATE.value]},
923+
'uO': {'s': self._url_override[_ApiURLs.SDK_URL.value],
924+
'e': self._url_override[_ApiURLs.EVENTS_URL.value],
925+
'a': self._url_override[_ApiURLs.AUTH_URL.value],
926+
'st': self._url_override[_ApiURLs.STREAMING_URL.value],
927+
't': self._url_override[_ApiURLs.TELEMETRY_URL.value]},
924928
'iQ': self._impressions_queue_size,
925929
'eQ': self._events_queue_size,
926930
'iM': self._impressions_mode,
@@ -979,11 +983,11 @@ def _get_refresh_rates(self, config):
979983
"""
980984
with self._lock:
981985
return {
982-
ConfigParams.SPLITS_REFRESH_RATE.value: config[ConfigParams.SPLITS_REFRESH_RATE.value],
983-
ConfigParams.SEGMENTS_REFRESH_RATE.value: config[ConfigParams.SEGMENTS_REFRESH_RATE.value],
984-
ConfigParams.IMPRESSIONS_REFRESH_RATE.value: config[ConfigParams.IMPRESSIONS_REFRESH_RATE.value],
985-
ConfigParams.EVENTS_REFRESH_RATE.value: config[ConfigParams.EVENTS_REFRESH_RATE.value],
986-
ConfigParams.TELEMETRY_REFRESH_RATE.value: config[ConfigParams.TELEMETRY_REFRESH_RATE.value]
986+
_ConfigParams.SPLITS_REFRESH_RATE.value: config[_ConfigParams.SPLITS_REFRESH_RATE.value],
987+
_ConfigParams.SEGMENTS_REFRESH_RATE.value: config[_ConfigParams.SEGMENTS_REFRESH_RATE.value],
988+
_ConfigParams.IMPRESSIONS_REFRESH_RATE.value: config[_ConfigParams.IMPRESSIONS_REFRESH_RATE.value],
989+
_ConfigParams.EVENTS_REFRESH_RATE.value: config[_ConfigParams.EVENTS_REFRESH_RATE.value],
990+
_ConfigParams.TELEMETRY_REFRESH_RATE.value: config[_ConfigParams.TELEMETRY_REFRESH_RATE.value]
987991
}
988992

989993
def _get_url_overrides(self, config):
@@ -998,11 +1002,11 @@ def _get_url_overrides(self, config):
9981002
"""
9991003
with self._lock:
10001004
return {
1001-
ApiURLs.SDK_URL.value: True if ApiURLs.SDK_URL.value in config else False,
1002-
ApiURLs.EVENTS_URL.value: True if ApiURLs.EVENTS_URL.value in config else False,
1003-
ApiURLs.AUTH_URL.value: True if ApiURLs.AUTH_URL.value in config else False,
1004-
ApiURLs.STREAMING_URL.value: True if ApiURLs.STREAMING_URL.value in config else False,
1005-
ApiURLs.TELEMETRY_URL.value: True if ApiURLs.TELEMETRY_URL.value in config else False
1005+
_ApiURLs.SDK_URL.value: True if _ApiURLs.SDK_URL.value in config else False,
1006+
_ApiURLs.EVENTS_URL.value: True if _ApiURLs.EVENTS_URL.value in config else False,
1007+
_ApiURLs.AUTH_URL.value: True if _ApiURLs.AUTH_URL.value in config else False,
1008+
_ApiURLs.STREAMING_URL.value: True if _ApiURLs.STREAMING_URL.value in config else False,
1009+
_ApiURLs.TELEMETRY_URL.value: True if _ApiURLs.TELEMETRY_URL.value in config else False
10061010
}
10071011

10081012
def _get_impressions_mode(self, imp_mode):
@@ -1032,6 +1036,6 @@ def _check_if_proxy_detected(self):
10321036
"""
10331037
with self._lock:
10341038
for x in os.environ:
1035-
if x.upper() == ExtraConfig.HTTPS_PROXY_ENV.value:
1039+
if x.upper() == _ExtraConfig.HTTPS_PROXY_ENV.value:
10361040
return True
10371041
return False

tests/models/test_telemetry_model.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,8 @@ def test_telemetry_config(self):
297297
'impressionsRefreshRate': 60,
298298
'eventsPushRate': 60,
299299
'metricsRefreshRate': 10,
300-
'storageType': None
300+
'storageType': None,
301+
'flagSetsFilter': None
301302
}
302303
telemetry_config.record_config(config, {})
303304
assert(telemetry_config.get_stats() == {'oM': 0,

tests/storage/test_pluggable.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ def test_init(self):
141141
prefix = 'myprefix.'
142142
else:
143143
prefix = ''
144-
assert(pluggable_split_storage._prefix == prefix + "SPLITIO.split.{split_name}")
144+
assert(pluggable_split_storage._prefix == prefix + "SPLITIO.split.{feature_flag_name}")
145145
assert(pluggable_split_storage._traffic_type_prefix == prefix + "SPLITIO.trafficType.{traffic_type_name}")
146-
assert(pluggable_split_storage._split_till_prefix == prefix + "SPLITIO.splits.till")
146+
assert(pluggable_split_storage._feature_flag_till_prefix == prefix + "SPLITIO.splits.till")
147147

148148
# TODO: To be added when producer mode is aupported
149149
# def test_put_many(self):
@@ -166,10 +166,10 @@ def test_get(self):
166166
pluggable_split_storage = PluggableSplitStorage(self.mock_adapter, prefix=sprefix)
167167

168168
split1 = splits.from_raw(splits_json['splitChange1_2']['splits'][0])
169-
split_name = splits_json['splitChange1_2']['splits'][0]['name']
169+
feature_flag_name = splits_json['splitChange1_2']['splits'][0]['name']
170170

171-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split_name), split1.to_json())
172-
assert(pluggable_split_storage.get(split_name).to_json() == splits.from_raw(splits_json['splitChange1_2']['splits'][0]).to_json())
171+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=feature_flag_name), split1.to_json())
172+
assert(pluggable_split_storage.get(feature_flag_name).to_json() == splits.from_raw(splits_json['splitChange1_2']['splits'][0]).to_json())
173173
assert(pluggable_split_storage.get('not_existing') == None)
174174

175175
def test_fetch_many(self):
@@ -181,8 +181,8 @@ def test_fetch_many(self):
181181
split2_temp['name'] = 'another_split'
182182
split2 = splits.from_raw(split2_temp)
183183

184-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split1.name), split1.to_json())
185-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split2.name), split2.to_json())
184+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split1.name), split1.to_json())
185+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split2.name), split2.to_json())
186186
fetched = pluggable_split_storage.fetch_many([split1.name, split2.name])
187187
assert(fetched[split1.name].to_json() == split1.to_json())
188188
assert(fetched[split2.name].to_json() == split2.to_json())
@@ -220,8 +220,8 @@ def test_get_split_names(self):
220220
split2_temp = splits_json['splitChange1_2']['splits'][0].copy()
221221
split2_temp['name'] = 'another_split'
222222
split2 = splits.from_raw(split2_temp)
223-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split1.name), split1.to_json())
224-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split2.name), split2.to_json())
223+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split1.name), split1.to_json())
224+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split2.name), split2.to_json())
225225
assert(pluggable_split_storage.get_split_names() == [split1.name, split2.name])
226226

227227
def test_get_all(self):
@@ -233,8 +233,8 @@ def test_get_all(self):
233233
split2_temp['name'] = 'another_split'
234234
split2 = splits.from_raw(split2_temp)
235235

236-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split1.name), split1.to_json())
237-
self.mock_adapter.set(pluggable_split_storage._prefix.format(split_name=split2.name), split2.to_json())
236+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split1.name), split1.to_json())
237+
self.mock_adapter.set(pluggable_split_storage._prefix.format(feature_flag_name=split2.name), split2.to_json())
238238
all_splits = pluggable_split_storage.get_all()
239239
assert([all_splits[0].to_json(), all_splits[1].to_json()] == [split1.to_json(), split2.to_json()])
240240

0 commit comments

Comments
 (0)