Skip to content

Commit 5530baa

Browse files
committed
polish and integration tests
1 parent d7b06a0 commit 5530baa

File tree

14 files changed

+1007
-19
lines changed

14 files changed

+1007
-19
lines changed

splitio/api/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def set_telemetry_data(self, metric_name, telemetry_runtime_producer):
133133
self._metric_name = metric_name
134134

135135
def is_sdk_endpoint_overridden(self):
136-
return self._urls['sdk'] == SDK_URL
136+
return self._urls['sdk'] != SDK_URL
137137

138138
def _get_headers(self, extra_headers, sdk_key):
139139
headers = _build_basic_headers(sdk_key)

splitio/engine/evaluator.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,19 @@ def context_for(self, key, feature_names):
125125
pending = set()
126126
for feature in features.values():
127127
cf, cs, crbs = get_dependencies(feature)
128+
for rbs in crbs:
129+
rbs_cf, rbs_cs, rbs_crbs = get_dependencies(self._rbs_segment_storage.get(rbs))
130+
cf.extend(rbs_cf)
131+
cs.extend(rbs_cs)
132+
crbs.extend(rbs_crbs)
133+
128134
pending.update(filter(lambda f: f not in splits, cf))
129135
pending_memberships.update(cs)
130136
pending_rbs_memberships.update(crbs)
131137

132138
rbs_segment_memberships = {}
133139
rbs_segment_conditions = {}
134-
excluded_rbs_segments = {}
140+
excluded_rbs_segments = set()
135141
key_membership = False
136142
segment_memberhsip = False
137143
for rbs_segment in pending_rbs_memberships:
@@ -147,7 +153,7 @@ def context_for(self, key, feature_names):
147153
if excluded_segment.type == SegmentType.RULE_BASED:
148154
rbs_segment = self._rbs_segment_storage.get(excluded_segment.name)
149155
if rbs_segment is not None:
150-
excluded_rbs_segments.update()
156+
excluded_rbs_segments.add(rbs_segment)
151157

152158
rbs_segment_memberships.update({rbs_segment: segment_memberhsip or key_membership})
153159
if not (segment_memberhsip or key_membership):
@@ -189,7 +195,7 @@ async def context_for(self, key, feature_names):
189195
splits.update(features)
190196
pending = set()
191197
for feature in features.values():
192-
cf, cs, crbs = get_dependencies(feature)
198+
cf, cs, crbs = get_dependencies(feature)
193199
pending.update(filter(lambda f: f not in splits, cf))
194200
pending_memberships.update(cs)
195201
pending_rbs_memberships.update(crbs)

splitio/models/grammar/matchers/rule_based_segment.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def _match(self, key, attributes=None, context=None):
3434
return False
3535

3636
for rbs_segment in context['ec'].excluded_rbs_segments:
37-
if self._match_conditions(rbs_segment, key, attributes, context):
37+
if self._match_conditions(rbs_segment.conditions, key, attributes, context):
3838
return True
3939

4040
if self._match_conditions(context['ec'].segment_rbs_conditions.get(self._rbs_segment_name), key, attributes, context):
@@ -50,7 +50,7 @@ def _add_matcher_specific_properties_to_json(self):
5050
}
5151
}
5252

53-
def _match_conditions(self, rbs_segment, key, attributes, context):
54-
for parsed_condition in rbs_segment:
53+
def _match_conditions(self, rbs_segment_conditions, key, attributes, context):
54+
for parsed_condition in rbs_segment_conditions:
5555
if parsed_condition.matches(key, attributes, context):
5656
return True

splitio/models/rule_based_segments.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ def from_raw(raw_rule_based_segment):
111111
_LOGGER.error(str(e))
112112
_LOGGER.debug("Using default conditions template for feature flag: %s", raw_rule_based_segment['name'])
113113
conditions = [condition.from_raw(_DEFAULT_CONDITIONS_TEMPLATE)]
114+
115+
if raw_rule_based_segment.get('excluded') == None:
116+
raw_rule_based_segment['excluded'] = {'keys': [], 'segments': []}
117+
118+
if raw_rule_based_segment['excluded'].get('keys') == None:
119+
raw_rule_based_segment['excluded']['keys'] = []
120+
121+
if raw_rule_based_segment['excluded'].get('segments') == None:
122+
raw_rule_based_segment['excluded']['segments'] = []
123+
114124
return RuleBasedSegment(
115125
raw_rule_based_segment['name'],
116126
raw_rule_based_segment['trafficTypeName'],

splits.json

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{"ff": {"d": [], "t": -1, "s": -1},
2+
"rbs": {"t": -1, "s": -1, "d":
3+
[{
4+
"changeNumber": 5,
5+
"name": "dependent_rbs",
6+
"status": "ACTIVE",
7+
"trafficTypeName": "user",
8+
"excluded":{"keys":["[email protected]","[email protected]"],"segments":[]},
9+
"conditions": [
10+
{
11+
"matcherGroup": {
12+
"combiner": "AND",
13+
"matchers": [
14+
{
15+
"keySelector": {
16+
"trafficType": "user",
17+
"attribute": "email"
18+
},
19+
"matcherType": "ENDS_WITH",
20+
"negate": false,
21+
"whitelistMatcherData": {
22+
"whitelist": [
23+
"@split.io"
24+
]
25+
}
26+
}
27+
]
28+
}
29+
}
30+
]},
31+
{
32+
"changeNumber": 5,
33+
"name": "sample_rule_based_segment",
34+
"status": "ACTIVE",
35+
"trafficTypeName": "user",
36+
"excluded": {
37+
"keys": [],
38+
"segments": []
39+
},
40+
"conditions": [
41+
{
42+
"conditionType": "ROLLOUT",
43+
"matcherGroup": {
44+
"combiner": "AND",
45+
"matchers": [
46+
{
47+
"keySelector": {
48+
"trafficType": "user"
49+
},
50+
"matcherType": "IN_RULE_BASED_SEGMENT",
51+
"negate": false,
52+
"userDefinedSegmentMatcherData": {
53+
"segmentName": "dependent_rbs"
54+
}
55+
}
56+
]
57+
}
58+
}
59+
]
60+
}]
61+
}}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{"ff": {"d": [], "t": -1, "s": -1},
2+
"rbs": {"t": -1, "s": -1, "d": [
3+
{
4+
"changeNumber": 5,
5+
"name": "sample_rule_based_segment",
6+
"status": "ACTIVE",
7+
"trafficTypeName": "user",
8+
"excluded":{
9+
10+
"segments":[{"type":"rule-based", "name":"no_excludes"}]
11+
},
12+
"conditions": [
13+
{
14+
"matcherGroup": {
15+
"combiner": "AND",
16+
"matchers": [
17+
{
18+
"keySelector": {
19+
"trafficType": "user",
20+
"attribute": "email"
21+
},
22+
"matcherType": "ENDS_WITH",
23+
"negate": false,
24+
"whitelistMatcherData": {
25+
"whitelist": [
26+
"@split.io"
27+
]
28+
}
29+
}
30+
]
31+
}
32+
}
33+
]
34+
},
35+
{
36+
"changeNumber": 5,
37+
"name": "no_excludes",
38+
"status": "ACTIVE",
39+
"trafficTypeName": "user",
40+
"conditions": [
41+
{
42+
"matcherGroup": {
43+
"combiner": "AND",
44+
"matchers": [
45+
{
46+
"keySelector": {
47+
"trafficType": "user",
48+
"attribute": "email"
49+
},
50+
"matcherType": "ENDS_WITH",
51+
"negate": false,
52+
"whitelistMatcherData": {
53+
"whitelist": [
54+
"@split.io"
55+
]
56+
}
57+
}
58+
]
59+
}
60+
}
61+
]
62+
}
63+
]}}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{"ff": {"d": [], "t": -1, "s": -1},
2+
"rbs": {"t": -1, "s": -1, "d": [
3+
{
4+
"changeNumber": 5,
5+
"name": "sample_rule_based_segment",
6+
"status": "ACTIVE",
7+
"trafficTypeName": "user",
8+
"excluded":{
9+
10+
"segments":[{"type":"standard", "name":"segment1"}]
11+
},
12+
"conditions": [
13+
{
14+
"matcherGroup": {
15+
"combiner": "AND",
16+
"matchers": [
17+
{
18+
"keySelector": {
19+
"trafficType": "user",
20+
"attribute": "email"
21+
},
22+
"matcherType": "ENDS_WITH",
23+
"negate": false,
24+
"whitelistMatcherData": {
25+
"whitelist": [
26+
"@split.io"
27+
]
28+
}
29+
}
30+
]
31+
}
32+
}
33+
]
34+
}
35+
]}}

tests/engine/test_evaluator.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
"""Evaluator tests module."""
2+
import json
23
import logging
4+
import os
35
import pytest
46
import copy
57

68
from splitio.models.splits import Split, Status
9+
from splitio.models import segments
710
from splitio.models.grammar.condition import Condition, ConditionType
811
from splitio.models.impressions import Label
912
from splitio.models.grammar import condition
@@ -245,6 +248,74 @@ def test_evaluate_treatment_with_rule_based_segment(self, mocker):
245248
result = e.eval_with_context('[email protected]', '[email protected]', 'some', {'email': '[email protected]'}, ctx)
246249
assert result['treatment'] == 'off'
247250

251+
def test_evaluate_treatment_with_rbs_in_condition(self):
252+
e = evaluator.Evaluator(splitters.Splitter())
253+
splits_storage = InMemorySplitStorage()
254+
rbs_storage = InMemoryRuleBasedSegmentStorage()
255+
segment_storage = InMemorySegmentStorage()
256+
evaluation_facctory = EvaluationDataFactory(splits_storage, segment_storage, rbs_storage)
257+
258+
rbs_segments = os.path.join(os.path.dirname(__file__), 'files', 'rule_base_segments.json')
259+
with open(rbs_segments, 'r') as flo:
260+
data = json.loads(flo.read())
261+
262+
mocked_split = Split('some', 12345, False, 'off', 'user', Status.ACTIVE, 12, split_conditions, 1.2, 100, 1234, {}, None, False)
263+
rbs = rule_based_segments.from_raw(data["rbs"]["d"][0])
264+
rbs2 = rule_based_segments.from_raw(data["rbs"]["d"][1])
265+
rbs_storage.update([rbs, rbs2], [], 12)
266+
splits_storage.update([mocked_split], [], 12)
267+
268+
ctx = evaluation_facctory.context_for('[email protected]', ['some'])
269+
assert e.eval_with_context('[email protected]', '[email protected]', 'some', {'email': '[email protected]'}, ctx)['treatment'] == "on"
270+
ctx = evaluation_facctory.context_for('[email protected]', ['some'])
271+
assert e.eval_with_context('[email protected]', '[email protected]', 'some', {'email': '[email protected]'}, ctx)['treatment'] == "off"
272+
273+
274+
def test_using_segment_in_excluded(self):
275+
rbs_segments = os.path.join(os.path.dirname(__file__), 'files', 'rule_base_segments3.json')
276+
with open(rbs_segments, 'r') as flo:
277+
data = json.loads(flo.read())
278+
e = evaluator.Evaluator(splitters.Splitter())
279+
splits_storage = InMemorySplitStorage()
280+
rbs_storage = InMemoryRuleBasedSegmentStorage()
281+
segment_storage = InMemorySegmentStorage()
282+
evaluation_facctory = EvaluationDataFactory(splits_storage, segment_storage, rbs_storage)
283+
284+
mocked_split = Split('some', 12345, False, 'off', 'user', Status.ACTIVE, 12, split_conditions, 1.2, 100, 1234, {}, None, False)
285+
rbs = rule_based_segments.from_raw(data["rbs"]["d"][0])
286+
rbs_storage.update([rbs], [], 12)
287+
splits_storage.update([mocked_split], [], 12)
288+
segment = segments.from_raw({'name': 'segment1', 'added': ['[email protected]'], 'removed': [], 'till': 123})
289+
segment_storage.put(segment)
290+
291+
ctx = evaluation_facctory.context_for('[email protected]', ['some'])
292+
assert e.eval_with_context('[email protected]', '[email protected]', 'some', {'email': '[email protected]'}, ctx)['treatment'] == "on"
293+
ctx = evaluation_facctory.context_for('[email protected]', ['some'])
294+
assert e.eval_with_context('[email protected]', '[email protected]', 'some', {'email': '[email protected]'}, ctx)['treatment'] == "off"
295+
ctx = evaluation_facctory.context_for('[email protected]', ['some'])
296+
assert e.eval_with_context('[email protected]', '[email protected]', 'some', {'email': '[email protected]'}, ctx)['treatment'] == "off"
297+
298+
def test_using_rbs_in_excluded(self):
299+
rbs_segments = os.path.join(os.path.dirname(__file__), 'files', 'rule_base_segments2.json')
300+
with open(rbs_segments, 'r') as flo:
301+
data = json.loads(flo.read())
302+
e = evaluator.Evaluator(splitters.Splitter())
303+
splits_storage = InMemorySplitStorage()
304+
rbs_storage = InMemoryRuleBasedSegmentStorage()
305+
segment_storage = InMemorySegmentStorage()
306+
evaluation_facctory = EvaluationDataFactory(splits_storage, segment_storage, rbs_storage)
307+
308+
mocked_split = Split('some', 12345, False, 'off', 'user', Status.ACTIVE, 12, split_conditions, 1.2, 100, 1234, {}, None, False)
309+
rbs = rule_based_segments.from_raw(data["rbs"]["d"][0])
310+
rbs2 = rule_based_segments.from_raw(data["rbs"]["d"][1])
311+
rbs_storage.update([rbs, rbs2], [], 12)
312+
splits_storage.update([mocked_split], [], 12)
313+
314+
ctx = evaluation_facctory.context_for('[email protected]', ['some'])
315+
assert e.eval_with_context('[email protected]', '[email protected]', 'some', {'email': '[email protected]'}, ctx)['treatment'] == "on"
316+
ctx = evaluation_facctory.context_for('[email protected]', ['some'])
317+
assert e.eval_with_context('[email protected]', '[email protected]', 'some', {'email': '[email protected]'}, ctx)['treatment'] == "on"
318+
248319
class EvaluationDataFactoryTests(object):
249320
"""Test evaluation factory class."""
250321

0 commit comments

Comments
 (0)