Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
updated compare fn, added more unit tests also added semver_audience …
…with its test
  • Loading branch information
Amna Ejaz committed Jul 15, 2020
commit fb1cbc0641592c52f4d18aa5a682e83de2c9d04a
39 changes: 14 additions & 25 deletions optimizely/helpers/condition.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,44 +244,29 @@ def semver_equal_evaluator(self, index):
condition_value = self.condition_data[index][1]
user_value = self.attributes.get(condition_name)

if self.compare_user_version_with_target_version(user_value, condition_value) is None:
return True
else:
return False
return self.compare_user_version_with_target_version(user_value, condition_value) is 0

def semver_greater_than_evaluator(self, index):

condition_name = self.condition_data[index][0]
condition_value = self.condition_data[index][1]
user_value = self.attributes.get(condition_name)

if self.compare_user_version_with_target_version(user_value, condition_value) is True:
return True
else:
return False
return self.compare_user_version_with_target_version(user_value, condition_value) is 1

def semver_less_than_evaluator(self, index):

condition_name = self.condition_data[index][0]
condition_value = self.condition_data[index][1]
user_value = self.attributes.get(condition_name)

if self.compare_user_version_with_target_version(user_value, condition_value) is False:
return True
else:
return False
return self.compare_user_version_with_target_version(user_value, condition_value) is -1

def semver_less_than_and_equal_evaluator(self, index):
if self.semver_less_than_evaluator(index) is True or self.semver_equal_evaluator(index) is True:
return True
else:
return False
return self.semver_less_than_evaluator(index) is True or self.semver_equal_evaluator(index) is True

def semver_greater_than_and_equal_evaluator(self, index):
if self.semver_greater_than_evaluator(index) is True or self.semver_equal_evaluator(index) is True:
return True
else:
return False
return self.semver_greater_than_evaluator(index) is True or self.semver_equal_evaluator(index) is True

def compare_user_version_with_target_version(self, user_version, target_version):

Expand All @@ -299,13 +284,17 @@ def compare_user_version_with_target_version(self, user_version, target_version)
for i in range(condition_version_parts_len, user_version_parts_len):
condition_version_parts.append("0")

# returns True if Greater, False if smaller and None if equal
for (idx, _) in enumerate(condition_version_parts):
if int(user_version_parts[idx]) > int(condition_version_parts[idx]):
return True
# compare strings e.g: n1.n2.n3-alpha/beta
if not user_version_parts[idx].isnumeric():
if user_version_parts[idx] != condition_version_parts[idx]:
return -1
# compare numbers e.g: n1.n2.n3
elif int(user_version_parts[idx]) > int(condition_version_parts[idx]):
return 1
elif int(user_version_parts[idx]) < int(condition_version_parts[idx]):
return False
return None
return -1
return 0

EVALUATORS_BY_MATCH_TYPE = {
ConditionMatchTypes.EXACT: exact_evaluator,
Expand Down
42 changes: 39 additions & 3 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ def setUp(self, config_dict='config_dict'):
'3468206647',
'3468206644',
'3468206643',
'18278344267'
],
'variations': [
{'variables': [], 'id': '11557362669', 'key': '11557362669', 'featureEnabled': True}
Expand Down Expand Up @@ -556,7 +557,7 @@ def setUp(self, config_dict='config_dict'):
'audienceConditions': [
'and',
['or', '3468206642', '3988293898'],
['or', '3988293899', '3468206646', '3468206647', '3468206644', '3468206643'],
['or', '3988293899', '3468206646', '3468206647', '3468206644', '3468206643', '18278344267'],
],
'variations': [
{'variables': [], 'id': '11557362670', 'key': '11557362670', 'featureEnabled': True}
Expand Down Expand Up @@ -626,6 +627,7 @@ def setUp(self, config_dict='config_dict'):
'3468206647',
'3468206644',
'3468206643',
'18278344267'
],
'variations': [
{
Expand Down Expand Up @@ -653,6 +655,7 @@ def setUp(self, config_dict='config_dict'):
'3468206647',
'3468206644',
'3468206643',
'18278344267'
],
'forcedVariations': {},
},
Expand All @@ -667,7 +670,7 @@ def setUp(self, config_dict='config_dict'):
'audienceConditions': [
'and',
['or', '3468206642', '3988293898'],
['or', '3988293899', '3468206646', '3468206647', '3468206644', '3468206643'],
['or', '3988293899', '3468206646', '3468206647', '3468206644', '3468206643', '18278344267'],
],
'forcedVariations': {},
},
Expand All @@ -689,7 +692,7 @@ def setUp(self, config_dict='config_dict'):
'audienceConditions': [
'and',
['or', '3468206642', '3988293898'],
['or', '3988293899', '3468206646', '3468206647', '3468206644', '3468206643'],
['or', '3988293899', '3468206646', '3468206647', '3468206644', '3468206643', '18278344267'],
],
'forcedVariations': {},
},
Expand Down Expand Up @@ -837,13 +840,46 @@ def setUp(self, config_dict='config_dict'):
],
],
},
{
"id": "18278344267",
"name": "semver_audience",
"conditions": [
"and",
[
"or",
[
"or",
{
"value": "1.2.3",
"type": "custom_attribute",
"name": "Android",
"match": "semver_lt"
}
]
],
[
"or",
[
"or",
{
"value": "1.0.0",
"type": "custom_attribute",
"name": "Android",
"match": "semver_gt"
}
]
]
]
}
],
'groups': [],
'attributes': [
{'key': 'house', 'id': '594015'},
{'key': 'lasers', 'id': '594016'},
{'key': 'should_do_it', 'id': '594017'},
{'key': 'favorite_ice_cream', 'id': '594018'},
{'key': 'Android', 'id': '594019'},

],
'botFiltering': False,
'accountId': '4879520872',
Expand Down
62 changes: 49 additions & 13 deletions tests/helpers_tests/test_condition.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@
integerCondition = ['num_users', 10, 'custom_attribute', 'exact']
doubleCondition = ['pi_value', 3.14, 'custom_attribute', 'exact']

eq_semver_condition_list = [['Android', "2.0", 'custom_attribute', 'semver_eq']]
eq_semver_condition_list_variation_1 = [['Android', "2.0", 'custom_attribute', 'semver_eq']]
eq_semver_condition_list_variation_2 = [['Android', "2.0.1-beta.0", 'custom_attribute', 'semver_eq']]
eq_semver_condition_list_variation_3 = [['Android', "2.0.0", 'custom_attribute', 'semver_eq']]
eq_semver_condition_list_variation_4 = [['Android', "2.0.1-beta", 'custom_attribute', 'semver_eq']]

lt_semver_condition_list = [['Android', "2.0", 'custom_attribute', 'semver_lt']]
gt_semver_condition_list = [['Android', "2.0", 'custom_attribute', 'semver_gt']]
le_semver_condition_list = [['Android', "2.0", 'custom_attribute', 'semver_le']]
ge_semver_condition_list = [['Android', "2.0", 'custom_attribute', 'semver_ge']]
gt_semver_condition_list = [['Android', "2.0.0", 'custom_attribute', 'semver_gt']]
ge_semver_condition_list_variation_1 = [['Android', "2.0.9", 'custom_attribute', 'semver_ge']]
ge_semver_condition_list_variation_2 = [['Android', "2.0.9-beta", 'custom_attribute', 'semver_ge']]
le_semver_condition_list_variation_1 = [['Android', "2.0.1", 'custom_attribute', 'semver_le']]
le_semver_condition_list_variation_2 = [['Android', "2.0.1-apha", 'custom_attribute', 'semver_le']]

exists_condition_list = [['input_value', None, 'custom_attribute', 'exists']]
exact_string_condition_list = [['favorite_constellation', 'Lacerta', 'custom_attribute', 'exact']]
Expand Down Expand Up @@ -117,15 +123,33 @@ def test_evaluate__returns_null__when_condition_has_an_invalid_type_property(sel
def test_evaluate__returns_true__when_audience_version_matches_condition_version(self):

evaluator = condition_helper.CustomAttributeConditionEvaluator(
eq_semver_condition_list, {'Android': '2.0.0'}, self.mock_client_logger
eq_semver_condition_list_variation_1, {'Android': '2.0.0'}, self.mock_client_logger
)

self.assertStrictTrue(evaluator.evaluate(0))

evaluator = condition_helper.CustomAttributeConditionEvaluator(
eq_semver_condition_list_variation_2, {'Android': '2.0.1-beta'}, self.mock_client_logger
)

self.assertStrictTrue(evaluator.evaluate(0))

evaluator = condition_helper.CustomAttributeConditionEvaluator(
eq_semver_condition_list_variation_3, {'Android': '2.0'}, self.mock_client_logger
)

self.assertStrictTrue(evaluator.evaluate(0))

evaluator = condition_helper.CustomAttributeConditionEvaluator(
eq_semver_condition_list_variation_4, {'Android': '2.0.1-beta.0.0'}, self.mock_client_logger
)

self.assertStrictTrue(evaluator.evaluate(0))

def test_evaluate__returns_true__when_audience_version_doesn_not_match_condition_version(self):
def test_evaluate__returns_true__when_audience_version_does_not_match_condition_version(self):

evaluator = condition_helper.CustomAttributeConditionEvaluator(
eq_semver_condition_list, {'Android': '2.1.1'}, self.mock_client_logger
eq_semver_condition_list_variation_1, {'Android': '2.1.1'}, self.mock_client_logger
)

self.assertStrictFalse(evaluator.evaluate(0))
Expand Down Expand Up @@ -165,43 +189,55 @@ def test_evaluate__returns_true__when_audience_version_is_not_lt_condition_versi
def test_evaluate__returns_true__when_audience_version_is_ge_condition_version(self):

evaluator = condition_helper.CustomAttributeConditionEvaluator(
ge_semver_condition_list, {'Android': '2.0.0'}, self.mock_client_logger
ge_semver_condition_list_variation_1, {'Android': '2.0.9'}, self.mock_client_logger
)

self.assertStrictTrue(evaluator.evaluate(0))

evaluator = condition_helper.CustomAttributeConditionEvaluator(
ge_semver_condition_list, {'Android': '2.0.7'}, self.mock_client_logger
ge_semver_condition_list_variation_1, {'Android': '2.9'}, self.mock_client_logger
)

self.assertStrictTrue(evaluator.evaluate(0))

evaluator = condition_helper.CustomAttributeConditionEvaluator(
ge_semver_condition_list_variation_1, {'Android': '2.0.9-beta'}, self.mock_client_logger
)

self.assertStrictTrue(evaluator.evaluate(0))

def test_evaluate__returns_true__when_audience_version_is_not_ge_condition_version(self):

evaluator = condition_helper.CustomAttributeConditionEvaluator(
ge_semver_condition_list, {'Android': '1.0.0'}, self.mock_client_logger
ge_semver_condition_list_variation_1, {'Android': '1.0.0'}, self.mock_client_logger
)

self.assertStrictFalse(evaluator.evaluate(0))

def test_evaluate__returns_true__when_audience_version_is_le_condition_version(self):

evaluator = condition_helper.CustomAttributeConditionEvaluator(
le_semver_condition_list, {'Android': '2.0'}, self.mock_client_logger
le_semver_condition_list_variation_1, {'Android': '2.0.1'}, self.mock_client_logger
)

self.assertStrictTrue(evaluator.evaluate(0))

evaluator = condition_helper.CustomAttributeConditionEvaluator(
le_semver_condition_list_variation_1, {'Android': '1.1'}, self.mock_client_logger
)

self.assertStrictTrue(evaluator.evaluate(0))

evaluator = condition_helper.CustomAttributeConditionEvaluator(
le_semver_condition_list, {'Android': '1.9.9'}, self.mock_client_logger
le_semver_condition_list_variation_2, {'Android': '2.0.1-beta'}, self.mock_client_logger
)

self.assertStrictTrue(evaluator.evaluate(0))

def test_evaluate__returns_true__when_audience_version_is_not_le_condition_version(self):

evaluator = condition_helper.CustomAttributeConditionEvaluator(
le_semver_condition_list, {'Android': '3.0.1'}, self.mock_client_logger
le_semver_condition_list_variation_1, {'Android': '3.0.1'}, self.mock_client_logger
)

self.assertStrictFalse(evaluator.evaluate(0))
Expand Down
42 changes: 42 additions & 0 deletions tests/test_optimizely.py
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,48 @@ def test_activate__with_attributes__typed_audience_match(self):

self.assertTrue(expected_attr in [x.__dict__ for x in mock_process.call_args[0][0].visitor_attributes])

def test_activate__with_attributes__typed_audience_with_semver_match(self):
""" Test that activate calls process with right params and returns expected
variation when attributes are provided and typed audience conditions are met. """
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_typed_audiences))

with mock.patch('optimizely.event.event_processor.ForwardingEventProcessor.process') as mock_process:
# Should be included via exact match string audience with id '18278344267'
self.assertEqual(
'A', opt_obj.activate('typed_audience_experiment', 'test_user', {'Android': '1.0.1'}),
)
expected_attr = {
'type': 'custom',
'value': '1.0.1',
'entity_id': '594019',
'key': 'Android',
}

self.assertTrue(expected_attr in [x.__dict__ for x in mock_process.call_args[0][0].visitor_attributes])

mock_process.reset()

with mock.patch('optimizely.event.event_processor.ForwardingEventProcessor.process') as mock_process:
self.assertEqual(
'A', opt_obj.activate('typed_audience_experiment', 'test_user', {'Android': "1.2.2"}),
)
expected_attr = {
'type': 'custom',
'value': "1.2.2",
'entity_id': '594019',
'key': 'Android',
}

self.assertTrue(expected_attr in [x.__dict__ for x in mock_process.call_args[0][0].visitor_attributes])

def test_activate__with_attributes__typed_audience_with_semver_mismatch(self):
""" Test that activate returns None when typed audience conditions do not match. """
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_typed_audiences))

with mock.patch('optimizely.event.event_processor.ForwardingEventProcessor.process') as mock_process:
self.assertIsNone(opt_obj.activate('typed_audience_experiment', 'test_user', {'Android': '1.2.9'}))
self.assertEqual(0, mock_process.call_count)

def test_activate__with_attributes__typed_audience_mismatch(self):
""" Test that activate returns None when typed audience conditions do not match. """
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_typed_audiences))
Expand Down