Skip to content

Commit 5d40bce

Browse files
oakbanimikeproeng37
authored andcommitted
Improve code coverage (#114)
1 parent cd09d20 commit 5d40bce

File tree

5 files changed

+136
-10
lines changed

5 files changed

+136
-10
lines changed

optimizely/project_config.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,6 @@ def get_forced_variation(self, experiment_key, user_id):
575575
return None
576576

577577
variation = self.get_variation_from_id(experiment_key, variation_id)
578-
if not variation:
579-
# The invalid variation ID will be logged inside this call.
580-
return None
581578

582579
self.logger.log(enums.LogLevels.DEBUG,
583580
'Variation "%s" is mapped to experiment "%s" and user "%s" in the forced variation map'

tests/test_bucketing.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2016-2017, Optimizely
1+
# Copyright 2016-2018, Optimizely
22
# Licensed under the Apache License, Version 2.0 (the "License");
33
# you may not use this file except in compliance with the License.
44
# You may obtain a copy of the License at
@@ -79,6 +79,18 @@ def test_bucket__invalid_experiment(self):
7979
'test_user',
8080
'test_user'))
8181

82+
def test_bucket__invalid_group(self):
83+
""" Test that bucket returns None for unknown group. """
84+
85+
project_config = self.project_config
86+
experiment = project_config.get_experiment_from_key('group_exp_1')
87+
# Set invalid group ID for the experiment
88+
experiment.groupId = 'aabbcc'
89+
90+
self.assertIsNone(self.bucketer.bucket(experiment,
91+
'test_user',
92+
'test_user'))
93+
8294
def test_bucket__experiment_in_group(self):
8395
""" Test that for provided bucket values correct variation ID is returned. """
8496

tests/test_config.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,17 @@ def test_get_rollout_from_id__valid_rollout_id(self):
887887
}])
888888
self.assertEqual(expected_rollout, project_config.get_rollout_from_id('211111'))
889889

890+
def test_get_rollout_from_id__invalid_rollout_id(self):
891+
""" Test that None is returned for an unknown Rollout ID """
892+
893+
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features),
894+
logger=logger.NoOpLogger())
895+
project_config = opt_obj.config
896+
with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logging:
897+
self.assertIsNone(project_config.get_rollout_from_id('aabbccdd'))
898+
899+
mock_logging.assert_called_once_with(enums.LogLevels.ERROR, 'Rollout with ID "aabbccdd" is not in datafile.')
900+
890901
def test_get_variable_value_for_variation__returns_valid_value(self):
891902
""" Test that the right value is returned. """
892903
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features))
@@ -971,6 +982,29 @@ def test_get_forced_variation__invalid_experiment_key(self):
971982
self.assertIsNone(self.project_config.get_forced_variation(None, 'test_user'))
972983
self.assertIsNone(self.project_config.get_forced_variation('', 'test_user'))
973984

985+
def test_get_forced_variation_with_none_set_for_user(self):
986+
""" Test get_forced_variation when none set for user ID in forced variation map. """
987+
self.project_config.forced_variation_map = {}
988+
self.project_config.forced_variation_map['test_user'] = {}
989+
990+
with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logging:
991+
self.assertIsNone(self.project_config.get_forced_variation('test_experiment', 'test_user'))
992+
mock_logging.assert_called_once_with(
993+
enums.LogLevels.DEBUG,
994+
'No experiment "test_experiment" mapped to user "test_user" in the forced variation map.')
995+
996+
def test_get_forced_variation_missing_variation_mapped_to_experiment(self):
997+
""" Test get_forced_variation when no variation found against given experiment for the user. """
998+
self.project_config.forced_variation_map = {}
999+
self.project_config.forced_variation_map['test_user'] = {}
1000+
self.project_config.forced_variation_map['test_user']['test_experiment'] = None
1001+
1002+
with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logging:
1003+
self.assertIsNone(self.project_config.get_forced_variation('test_experiment', 'test_user'))
1004+
mock_logging.assert_called_once_with(
1005+
enums.LogLevels.DEBUG,
1006+
'No variation mapped to experiment "test_experiment" in the forced variation map.')
1007+
9741008
# set_forced_variation tests
9751009
def test_set_forced_variation__invalid_user_id(self):
9761010
""" Test invalid user IDs set fail to set a forced variation """
@@ -1017,6 +1051,28 @@ def test_set_forced_variation__multiple_sets(self):
10171051
self.assertEqual(self.project_config.get_forced_variation('test_experiment', 'test_user_1').key, 'control')
10181052
self.assertEqual(self.project_config.get_forced_variation('group_exp_1', 'test_user_1').key, 'group_exp_1_control')
10191053

1054+
def test_set_forced_variation_when_called_to_remove_forced_variation(self):
1055+
""" Test set_forced_variation when no variation is given. """
1056+
# Test case where both user and experiment are present in the forced variation map
1057+
self.project_config.forced_variation_map = {}
1058+
self.project_config.set_forced_variation('test_experiment', 'test_user', 'variation')
1059+
1060+
with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logging:
1061+
self.assertTrue(self.project_config.set_forced_variation('test_experiment', 'test_user', None))
1062+
mock_logging.assert_called_once_with(
1063+
enums.LogLevels.DEBUG,
1064+
'Variation mapped to experiment "test_experiment" has been removed for user "test_user".')
1065+
1066+
# Test case where user is present in the forced variation map, but the given experiment isn't
1067+
self.project_config.forced_variation_map = {}
1068+
self.project_config.set_forced_variation('test_experiment', 'test_user', 'variation')
1069+
1070+
with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logging:
1071+
self.assertTrue(self.project_config.set_forced_variation('group_exp_1', 'test_user', None))
1072+
mock_logging.assert_called_once_with(
1073+
enums.LogLevels.DEBUG,
1074+
'Nothing to remove. Variation mapped to experiment "group_exp_1" for user "test_user" does not exist.')
1075+
10201076

10211077
class ConfigLoggingTest(base.BaseTest):
10221078
def setUp(self):

tests/test_decision_service.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2017, Optimizely
1+
# Copyright 2017-2018, Optimizely
22
# Licensed under the Apache License, Version 2.0 (the "License");
33
# you may not use this file except in compliance with the License.
44
# You may obtain a copy of the License at
@@ -437,11 +437,14 @@ def test_get_variation_for_rollout__skips_to_everyone_else_rule(self, mock_loggi
437437
for the experiment, then it skips to the Everyone Else rule. """
438438

439439
rollout = self.project_config.get_rollout_from_id('211111')
440+
everyone_else_exp = self.project_config.get_experiment_from_id('211147')
441+
variation_to_mock = self.project_config.get_variation_from_id('211147', '211149')
440442

441443
with mock.patch('optimizely.helpers.audience.is_user_in_experiment', return_value=True) as mock_audience_check,\
442-
mock.patch('optimizely.bucketer.Bucketer.bucket', return_value=None):
443-
self.assertEqual(decision_service.Decision(None, None, decision_service.DECISION_SOURCE_ROLLOUT),
444-
self.decision_service.get_variation_for_rollout(rollout, 'test_user'))
444+
mock.patch('optimizely.bucketer.Bucketer.bucket', side_effect=[None, variation_to_mock]):
445+
self.assertEqual(
446+
decision_service.Decision(everyone_else_exp, variation_to_mock, decision_service.DECISION_SOURCE_ROLLOUT),
447+
self.decision_service.get_variation_for_rollout(rollout, 'test_user'))
445448

446449
# Check that after first experiment, it skips to the last experiment to check
447450
self.assertEqual(
@@ -454,8 +457,9 @@ def test_get_variation_for_rollout__skips_to_everyone_else_rule(self, mock_loggi
454457
self.assertEqual(
455458
[mock.call(enums.LogLevels.DEBUG, 'User "test_user" meets conditions for targeting rule 1.'),
456459
mock.call(enums.LogLevels.DEBUG, 'User "test_user" is not in the traffic group for the targeting else. '
457-
'Checking "Everyone Else" rule now.')
458-
], mock_logging.call_args_list)
460+
'Checking "Everyone Else" rule now.'),
461+
mock.call(enums.LogLevels.DEBUG, 'User "test_user" meets conditions for targeting rule "Everyone Else".')],
462+
mock_logging.call_args_list)
459463

460464
def test_get_variation_for_rollout__returns_none_for_user_not_in_rollout(self, mock_logging):
461465
""" Test that get_variation_for_rollout returns None for the user not in the associated rollout. """
@@ -594,6 +598,20 @@ def test_get_variation_for_feature__returns_none_for_user_not_in_experiment(self
594598
self.project_config.get_experiment_from_key('test_experiment'), 'test_user', None
595599
)
596600

601+
def test_get_variation_for_feature__returns_none_for_invalid_group_id(self, mock_logging):
602+
""" Test that get_variation_for_feature returns None for unknown group ID. """
603+
604+
feature = self.project_config.get_feature_from_key('test_feature_in_group')
605+
feature.groupId = 'aabbccdd'
606+
607+
self.assertEqual(decision_service.Decision(None,
608+
None,
609+
decision_service.DECISION_SOURCE_EXPERIMENT),
610+
self.decision_service.get_variation_for_feature(feature, 'test_user')
611+
)
612+
mock_logging.assert_called_with(enums.LogLevels.ERROR,
613+
enums.Errors.INVALID_GROUP_ID_ERROR.format('_get_variation_for_feature'))
614+
597615
def test_get_variation_for_feature__returns_none_for_user_in_group_experiment_not_associated_with_feature(self, _):
598616
""" Test that if a user is in the mutex group but the experiment is
599617
not targeting a feature, then None is returned. """

tests/test_optimizely.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,19 @@ def test_track__experiment_not_running(self):
10961096
mock_is_experiment_running.assert_called_once_with(self.project_config.get_experiment_from_key('test_experiment'))
10971097
self.assertEqual(0, mock_dispatch_event.call_count)
10981098

1099+
def test_track_invalid_event_key(self):
1100+
""" Test that track does not call dispatch_event when event does not exist. """
1101+
1102+
with mock.patch('optimizely.event_dispatcher.EventDispatcher.dispatch_event') as mock_dispatch_event,\
1103+
mock.patch('optimizely.logger.NoOpLogger.log') as mock_logging:
1104+
self.optimizely.track('aabbcc_event', 'test_user')
1105+
1106+
self.assertEqual(0, mock_dispatch_event.call_count)
1107+
mock_logging.assert_called_with(
1108+
enums.LogLevels.INFO,
1109+
'Not tracking user "test_user" for event "aabbcc_event".'
1110+
)
1111+
10991112
def test_track__whitelisted_user_overrides_audience_check(self):
11001113
""" Test that track does not check for user in audience when user is in whitelist. """
11011114

@@ -1132,6 +1145,16 @@ def test_get_variation__invalid_object(self):
11321145

11331146
mock_logging.assert_called_once_with(enums.LogLevels.ERROR, 'Datafile has invalid format. Failing "get_variation".')
11341147

1148+
def test_get_variation_invalid_experiment_key(self):
1149+
""" Test that get_variation retuns None when invalid experiment key is given. """
1150+
with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logging:
1151+
self.optimizely.get_variation('aabbccdd', 'test_user', None)
1152+
1153+
mock_logging.assert_called_with(
1154+
enums.LogLevels.INFO,
1155+
'Experiment key "aabbccdd" is invalid. Not activating user "test_user".'
1156+
)
1157+
11351158
def test_is_feature_enabled__returns_false_for_none_feature_key(self):
11361159
""" Test that is_feature_enabled returns false if the provided feature key is None. """
11371160

@@ -1706,6 +1729,26 @@ def test_get_feature_variable__returns_none_if_type_mismatch(self):
17061729
'Use correct API to retrieve value. Returning None.'
17071730
)
17081731

1732+
def test_get_feature_variable__returns_none_if_unable_to_cast(self):
1733+
""" Test that get_feature_variable_* returns None if unable_to_cast_value """
1734+
1735+
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features))
1736+
mock_experiment = opt_obj.config.get_experiment_from_key('test_experiment')
1737+
mock_variation = opt_obj.config.get_variation_from_id('test_experiment', '111129')
1738+
with mock.patch('optimizely.decision_service.DecisionService.get_variation_for_feature',
1739+
return_value=decision_service.Decision(mock_experiment,
1740+
mock_variation,
1741+
decision_service.DECISION_SOURCE_EXPERIMENT)), \
1742+
mock.patch('optimizely.project_config.ProjectConfig.get_typecast_value',
1743+
side_effect=ValueError()),\
1744+
mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger:
1745+
self.assertEqual(None, opt_obj.get_feature_variable_integer('test_feature_in_experiment', 'count', 'test_user'))
1746+
1747+
mock_logger.assert_called_with(
1748+
enums.LogLevels.ERROR,
1749+
'Unable to cast value. Returning None.'
1750+
)
1751+
17091752

17101753
class OptimizelyWithExceptionTest(base.BaseTest):
17111754
def setUp(self):

0 commit comments

Comments
 (0)