From 6fdf65519f99cabb0ec31270a3b25e2da3c35626 Mon Sep 17 00:00:00 2001 From: Ali Abbas Rizvi Date: Wed, 30 Aug 2017 09:52:58 +0530 Subject: [PATCH] Update unit tests and add more tests (#73) --- optimizely/decision_service.py | 9 +- optimizely/project_config.py | 16 +-- tests/base.py | 6 + tests/test_config.py | 48 ++++---- tests/test_decision_service.py | 216 ++++++++++++++++++--------------- 5 files changed, 158 insertions(+), 137 deletions(-) diff --git a/optimizely/decision_service.py b/optimizely/decision_service.py index 6fa3d8e4..76588e26 100644 --- a/optimizely/decision_service.py +++ b/optimizely/decision_service.py @@ -155,7 +155,7 @@ def get_variation(self, experiment, user_id, attributes, ignore_user_profile=Fal return None - def get_variation_for_rollout(self, rollout, user_id, attributes=None, ignore_user_profile=False): + def get_variation_for_rollout(self, rollout, user_id, attributes=None): """ Determine which variation the user is in for a given rollout. Returns the variation of the first experiment the user qualifies for. @@ -163,10 +163,9 @@ def get_variation_for_rollout(self, rollout, user_id, attributes=None, ignore_us rollout: Rollout for which we are getting the variation. user_id: ID for user. attributes: Dict representing user attributes. - ignore_user_profile: True to ignore the user profile lookup. Defaults to False. Returns: - Variation the user should see. None if the user is not in any of the layer's experiments. + Variation the user should see. None if the user is not in any of the rollout's targeting rules. """ # Go through each experiment in order and try to get the variation for the user @@ -249,8 +248,8 @@ def get_variation_for_feature(self, feature, user_id, attributes=None): # Next check if user is part of a rollout if not variation and feature.rolloutId: - rollout = self.config.get_layer_from_id(feature.rolloutId) - variation = self.get_variation_for_rollout(rollout, user_id, attributes, ignore_user_profile=True) + rollout = self.config.get_rollout_from_id(feature.rolloutId) + variation = self.get_variation_for_rollout(rollout, user_id, attributes) return variation diff --git a/optimizely/project_config.py b/optimizely/project_config.py index fc4612f7..8b3a33b9 100644 --- a/optimizely/project_config.py +++ b/optimizely/project_config.py @@ -62,8 +62,8 @@ def __init__(self, datafile, logger, error_handler): self.event_key_map = self._generate_key_map(self.events, 'key', entities.Event) self.attribute_key_map = self._generate_key_map(self.attributes, 'key', entities.Attribute) self.audience_id_map = self._generate_key_map(self.audiences, 'id', entities.Audience) - self.layer_id_map = self._generate_key_map(self.rollouts, 'id', entities.Layer) - for layer in self.layer_id_map.values(): + self.rollout_id_map = self._generate_key_map(self.rollouts, 'id', entities.Layer) + for layer in self.rollout_id_map.values(): for experiment in layer.experiments: self.experiment_key_map[experiment['key']] = entities.Experiment(**experiment) @@ -399,21 +399,21 @@ def get_feature_from_key(self, feature_key): self.logger.log(enums.LogLevels.ERROR, 'Feature "%s" is not in datafile.' % feature_key) return None - def get_layer_from_id(self, layer_id): - """ Get layer for the provided layer id. + def get_rollout_from_id(self, rollout_id): + """ Get rollout for the provided ID. Args: - layer_id: ID of the layer to be fetched. + rollout_id: ID of the rollout to be fetched. Returns: - Layer corresponding to the provided layer id. + Rollout corresponding to the provided ID. """ - layer = self.layer_id_map.get(layer_id) + layer = self.rollout_id_map.get(rollout_id) if layer: return layer - self.logger.log(enums.LogLevels.ERROR, 'Layer with ID "%s" is not in datafile.' % layer_id) + self.logger.log(enums.LogLevels.ERROR, 'Rollout with ID "%s" is not in datafile.' % rollout_id) return None def get_variable_value_for_variation(self, variable, variation): diff --git a/tests/base.py b/tests/base.py index a205ba50..76f0daf1 100644 --- a/tests/base.py +++ b/tests/base.py @@ -258,6 +258,9 @@ def setUp(self): 'id': '11159' }], 'rollouts': [{ + 'id': '201111', + 'experiments': [] + }, { 'id': '211111', 'experiments': [{ 'id': '211127', @@ -524,6 +527,9 @@ def setUp(self): 'id': '11159' }], 'rollouts': [{ + 'id': '201111', + 'experiments': [] + }, { 'id': '211111', 'experiments': [{ 'id': '211127', diff --git a/tests/test_config.py b/tests/test_config.py index fd818dc5..e902a102 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -913,7 +913,7 @@ def test_init__with_v4_datafile(self): 'test_feature_in_group': entities.FeatureFlag('91113', 'test_feature_in_group', ['32222'], '', {}, '19228') } - expected_layer_id_map = { + expected_rollout_id_map = { '211111': entities.Layer('211111', [{ 'key': '211112', 'status': 'Running', @@ -970,7 +970,7 @@ def test_init__with_v4_datafile(self): self.assertEqual(expected_variation_key_map, project_config.variation_key_map) self.assertEqual(expected_variation_id_map, project_config.variation_id_map) self.assertEqual(expected_feature_key_map, project_config.feature_key_map) - self.assertEqual(expected_layer_id_map, project_config.layer_id_map) + self.assertEqual(expected_rollout_id_map, project_config.rollout_id_map) self.assertEqual(expected_variation_variable_usage_map, project_config.variation_variable_usage_map) def test_get_version(self): @@ -1128,8 +1128,8 @@ def test_get_group__invalid_id(self): def test_get_feature_from_key__valid_feature_key(self): """ Test that a valid feature is returned given a valid feature key. """ - optimizely_instance = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = optimizely_instance.config + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + project_config = opt_obj.config expected_feature = entities.FeatureFlag('91112', 'test_feature_in_rollout', [], '211111', {}) self.assertEqual(expected_feature, project_config.get_feature_from_key('test_feature_in_rollout')) @@ -1137,18 +1137,18 @@ def test_get_feature_from_key__valid_feature_key(self): def test_get_feature_from_key__invalid_feature_key(self): """ Test that None is returned given an invalid feature key. """ - optimizely_instance = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = optimizely_instance.config + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + project_config = opt_obj.config self.assertIsNone(project_config.get_feature_from_key('invalid_feature_key')) - def test_get_layer_from_id__valid_layer_id(self): - """ Test that a valid layer is returned """ + def test_get_rollout_from_id__valid_rollout_id(self): + """ Test that a valid rollout is returned """ - optimizely_instance = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = optimizely_instance.config + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + project_config = opt_obj.config - expected_layer = entities.Layer('211111', [{ + expected_rollout = entities.Layer('211111', [{ 'id': '211127', 'key': '211127', 'status': 'Running', @@ -1194,12 +1194,12 @@ def test_get_layer_from_id__valid_layer_id(self): 'id': '211149' }] }]) - self.assertEqual(expected_layer, project_config.get_layer_from_id('211111')) + self.assertEqual(expected_rollout, project_config.get_rollout_from_id('211111')) def test_get_variable_value_for_variation__returns_valid_value(self): """ Test that the right value and type are returned. """ - optimizely_instance = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = optimizely_instance.config + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + project_config = opt_obj.config variation = project_config.get_variation_from_id('test_experiment', '111128') is_working_variable = project_config.get_variable_for_feature('test_feature_in_experiment', 'is_working') @@ -1210,8 +1210,8 @@ def test_get_variable_value_for_variation__returns_valid_value(self): def test_get_variable_value_for_variation__invalid_variable(self): """ Test that an invalid variable key will return None. """ - optimizely_instance = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = optimizely_instance.config + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + project_config = opt_obj.config variation = project_config.get_variation_from_id('test_experiment', '111128') self.assertIsNone(project_config.get_variable_value_for_variation(None, variation)) @@ -1219,8 +1219,8 @@ def test_get_variable_value_for_variation__invalid_variable(self): def test_get_variable_value_for_variation__no_variables_for_variation(self): """ Test that a variation with no variables will return None. """ - optimizely_instance = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = optimizely_instance.config + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + project_config = opt_obj.config variation = entities.Variation('1111281', 'invalid_variation', []) is_working_variable = project_config.get_variable_for_feature('test_feature_in_experiment', 'is_working') @@ -1229,8 +1229,8 @@ def test_get_variable_value_for_variation__no_variables_for_variation(self): def test_get_variable_for_feature__returns_valid_variable(self): """ Test that the feature variable is returned. """ - optimizely_instance = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = optimizely_instance.config + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + project_config = opt_obj.config variable = project_config.get_variable_for_feature('test_feature_in_experiment', 'is_working') self.assertEqual(entities.Variable('127', 'is_working', 'boolean', 'true'), variable) @@ -1238,16 +1238,16 @@ def test_get_variable_for_feature__returns_valid_variable(self): def test_get_variable_for_feature__invalid_feature_key(self): """ Test that an invalid feature key will return None. """ - optimizely_instance = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = optimizely_instance.config + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + project_config = opt_obj.config self.assertIsNone(project_config.get_variable_for_feature('invalid_feature', 'is_working')) def test_get_variable_for_feature__invalid_variable_key(self): """ Test that an invalid variable key will return None. """ - optimizely_instance = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = optimizely_instance.config + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + project_config = opt_obj.config self.assertIsNone(project_config.get_variable_for_feature('test_feature_in_experiment', 'invalid_variable_key')) diff --git a/tests/test_decision_service.py b/tests/test_decision_service.py index e468a669..d05631ee 100644 --- a/tests/test_decision_service.py +++ b/tests/test_decision_service.py @@ -329,61 +329,127 @@ def test_get_variation__ignore_user_profile_when_specified(self): self.assertEqual(0, mock_lookup.call_count) self.assertEqual(0, mock_save.call_count) - def test_get_variation_for_feature__returns_variation_for_feature_in_experiment(self): - """ Test that get_variation_for_feature returns the variation of the experiment the feature is associated with. """ +@mock.patch('optimizely.logger.NoOpLogger.log') +class FeatureFlagDecisionTests(base.BaseTest): + + def setUp(self): + base.BaseTest.setUp(self) opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = opt_obj.config - decision_service = opt_obj.decision_service - feature = project_config.get_feature_from_key('test_feature_in_experiment') + self.project_config = opt_obj.config + self.decision_service = opt_obj.decision_service + + def test_get_variation_for_rollout__returns_none_if_no_experiments(self, mock_logging): + """ Test that get_variation_for_rollout returns None if there are no experiments (targeting rules). """ + + no_experiment_rollout = self.project_config.get_rollout_from_id('201111') + self.assertIsNone(self.decision_service.get_variation_for_rollout(no_experiment_rollout, 'test_user')) + + # Assert no log messages were generated + self.assertEqual(0, mock_logging.call_count) + + def test_get_variation_for_rollout__skips_to_everyone_else_rule(self, mock_logging): + """ Test that if a user is in an audience, but does not qualify + for the experiment, then it skips to the Everyone Else rule. """ + + rollout = self.project_config.get_rollout_from_id('211111') + + with mock.patch('optimizely.helpers.audience.is_user_in_experiment', return_value=True) as mock_audience_check,\ + mock.patch('optimizely.bucketer.Bucketer.bucket', return_value=None): + self.assertIsNone(self.decision_service.get_variation_for_rollout(rollout, 'test_user')) + + # Check that after first experiment, it skips to the last experiment to check + self.assertEqual( + [mock.call(self.project_config, self.project_config.get_experiment_from_key('211127'), None), + mock.call(self.project_config, self.project_config.get_experiment_from_key('211147'), None)], + mock_audience_check.call_args_list + ) + + # Check all log messages + self.assertEqual( + [mock.call(enums.LogLevels.DEBUG, 'User "test_user" meets conditions for targeting rule 1.'), + mock.call(enums.LogLevels.DEBUG, 'User "test_user" is not in the traffic group for the targeting else. ' + 'Checking "Everyone Else" rule now.') + ], mock_logging.call_args_list) + + def test_get_variation_for_rollout__returns_none_for_user_not_in_rollout(self, mock_logging): + """ Test that get_variation_for_rollouts returns None for the user not in the associated rollout. """ - expected_variation = project_config.get_variation_from_id('test_experiment', '111129') + rollout = self.project_config.get_rollout_from_id('211111') + + with mock.patch('optimizely.helpers.audience.is_user_in_experiment', return_value=False) as mock_audience_check: + self.assertIsNone(self.decision_service.get_variation_for_rollout(rollout, 'test_user')) + + # Check that all experiments in rollout layer were checked + self.assertEqual( + [mock.call(self.project_config, self.project_config.get_experiment_from_key('211127'), None), + mock.call(self.project_config, self.project_config.get_experiment_from_key('211137'), None), + mock.call(self.project_config, self.project_config.get_experiment_from_key('211147'), None)], + mock_audience_check.call_args_list + ) + + # Check all log messages + self.assertEqual( + [mock.call(enums.LogLevels.DEBUG, 'User "test_user" does not meet conditions for targeting rule 1.'), + mock.call(enums.LogLevels.DEBUG, 'User "test_user" does not meet conditions for targeting rule 2.')], + mock_logging.call_args_list) + + def test_get_variation_for_feature__returns_variation_for_feature_in_experiment(self, mock_logging): + """ Test that get_variation_for_feature returns the variation of the experiment the feature is associated with. """ + + feature = self.project_config.get_feature_from_key('test_feature_in_experiment') + + expected_variation = self.project_config.get_variation_from_id('test_experiment', '111129') with mock.patch( 'optimizely.decision_service.DecisionService.get_variation', return_value=expected_variation) as mock_decision: - self.assertEqual(expected_variation, decision_service.get_variation_for_feature(feature, 'user1')) + self.assertEqual(expected_variation, self.decision_service.get_variation_for_feature(feature, 'user1')) mock_decision.assert_called_once_with( - project_config.get_experiment_from_key('test_experiment'), 'user1', None + self.project_config.get_experiment_from_key('test_experiment'), 'user1', None ) - def test_get_variation_for_feature__returns_variation_for_feature_in_rollout(self): + # Check log message + mock_logging.assert_called_once_with(enums.LogLevels.DEBUG, + 'User "user1" is in variation variation of experiment test_experiment.') + + def test_get_variation_for_feature__returns_variation_for_feature_in_rollout(self, mock_logging): """ Test that get_variation_for_feature returns the variation of the experiment in the rollout that the user is bucketed into. """ - opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = opt_obj.config - decision_service = opt_obj.decision_service - feature = project_config.get_feature_from_key('test_feature_in_rollout') + feature = self.project_config.get_feature_from_key('test_feature_in_rollout') - expected_variation = project_config.get_variation_from_id('211127', '211129') - with mock.patch('optimizely.helpers.audience.is_user_in_experiment', return_value=True) as mock_audience_check,\ - mock.patch('optimizely.bucketer.Bucketer.bucket', return_value=expected_variation): - self.assertEqual(expected_variation, decision_service.get_variation_for_feature(feature, 'user1')) + expected_variation = self.project_config.get_variation_from_id('211127', '211129') + with mock.patch('optimizely.decision_service.DecisionService.get_variation_for_rollout', + return_value=expected_variation) as mock_get_variation_for_rollout: + self.assertEqual(expected_variation, self.decision_service.get_variation_for_feature(feature, 'test_user')) + + expected_rollout = self.project_config.get_rollout_from_id('211111') + mock_get_variation_for_rollout.assert_called_once_with(expected_rollout, 'test_user', None) - mock_audience_check.assert_called_once_with(project_config, project_config.get_experiment_from_key('211127'), None) + # Assert no log messages were generated + self.assertEqual(0, mock_logging.call_count) - def test_get_variation_for_feature__returns_variation_if_user_not_in_experiment_but_in_rollout(self): + def test_get_variation_for_feature__returns_variation_if_user_not_in_experiment_but_in_rollout(self, _): """ Test that get_variation_for_feature returns the variation of the experiment in the feature's rollout even if the user is not bucketed into the feature's experiment. """ - opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = opt_obj.config - decision_service = opt_obj.decision_service - feature = project_config.get_feature_from_key('test_feature_in_experiment_and_rollout') + feature = self.project_config.get_feature_from_key('test_feature_in_experiment_and_rollout') - expected_variation = project_config.get_variation_from_id('211127', '211129') + expected_variation = self.project_config.get_variation_from_id('211127', '211129') with mock.patch( 'optimizely.helpers.audience.is_user_in_experiment', side_effect=[False, True]) as mock_audience_check, \ mock.patch('optimizely.bucketer.Bucketer.bucket', return_value=expected_variation): - self.assertEqual(expected_variation, decision_service.get_variation_for_feature(feature, 'user1')) + self.assertEqual(expected_variation, self.decision_service.get_variation_for_feature(feature, 'user1')) self.assertEqual(2, mock_audience_check.call_count) - mock_audience_check.assert_any_call(project_config, project_config.get_experiment_from_key('test_experiment'), None) - mock_audience_check.assert_any_call(project_config, project_config.get_experiment_from_key('211127'), None) + mock_audience_check.assert_any_call(self.project_config, + self.project_config.get_experiment_from_key('test_experiment'), None) + mock_audience_check.assert_any_call(self.project_config, + self.project_config.get_experiment_from_key('211127'), None) - def test_get_variation_for_feature__returns_variation_for_feature_in_group(self): + def test_get_variation_for_feature__returns_variation_for_feature_in_group(self, _): """ Test that get_variation_for_feature returns the variation of the experiment the user is bucketed in the feature's group. """ @@ -397,115 +463,65 @@ def test_get_variation_for_feature__returns_variation_for_feature_in_group(self) 'optimizely.decision_service.DecisionService.get_experiment_in_group', return_value=project_config.get_experiment_from_key('group_exp_1')) as mock_get_experiment_in_group, \ mock.patch('optimizely.decision_service.DecisionService.get_variation', - return_value=expected_variation) as mock_decision: + return_value=expected_variation) as mock_decision: self.assertEqual(expected_variation, decision_service.get_variation_for_feature(feature, 'user1')) mock_get_experiment_in_group.assert_called_once_with(project_config.get_group('19228'), 'user1') mock_decision.assert_called_once_with(project_config.get_experiment_from_key('group_exp_1'), 'user1', None) - def test_get_variation_for_feature__returns_none_for_user_not_in_group(self): + def test_get_variation_for_feature__returns_none_for_user_not_in_group(self, _): """ Test that get_variation_for_feature returns None for user not in group and the feature is not part of a rollout. """ - opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = opt_obj.config - decision_service = opt_obj.decision_service - feature = project_config.get_feature_from_key('test_feature_in_group') + feature = self.project_config.get_feature_from_key('test_feature_in_group') - with mock.patch( - 'optimizely.decision_service.DecisionService.get_experiment_in_group', - return_value=None) as mock_get_experiment_in_group, \ + with mock.patch('optimizely.decision_service.DecisionService.get_experiment_in_group', + return_value=None) as mock_get_experiment_in_group, \ mock.patch('optimizely.decision_service.DecisionService.get_variation') as mock_decision: - self.assertIsNone(decision_service.get_variation_for_feature(feature, 'user1')) + self.assertIsNone(self.decision_service.get_variation_for_feature(feature, 'user1')) - mock_get_experiment_in_group.assert_called_once_with(project_config.get_group('19228'), 'user1') + mock_get_experiment_in_group.assert_called_once_with(self.project_config.get_group('19228'), 'user1') self.assertFalse(mock_decision.called) - def test_get_variation_for_feature__returns_none_for_user_not_in_experiment(self): + def test_get_variation_for_feature__returns_none_for_user_not_in_experiment(self, _): """ Test that get_variation_for_feature returns None for user not in the associated experiment. """ - opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = opt_obj.config - decision_service = opt_obj.decision_service - feature = project_config.get_feature_from_key('test_feature_in_experiment') + feature = self.project_config.get_feature_from_key('test_feature_in_experiment') - with mock.patch( - 'optimizely.decision_service.DecisionService.get_variation', - return_value=None) as mock_decision: - self.assertIsNone(decision_service.get_variation_for_feature(feature, 'user1')) + with mock.patch('optimizely.decision_service.DecisionService.get_variation', return_value=None) as mock_decision: + self.assertIsNone(self.decision_service.get_variation_for_feature(feature, 'user1')) mock_decision.assert_called_once_with( - project_config.get_experiment_from_key('test_experiment'), 'user1', None + self.project_config.get_experiment_from_key('test_experiment'), 'user1', None ) - def test_get_variation_for_feature__returns_none_for_user_not_in_rollout(self): - """ Test that get_variation_for_feature returns None for the user not in the associated rollout. """ - - opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = opt_obj.config - decision_service = opt_obj.decision_service - feature = project_config.get_feature_from_key('test_feature_in_rollout') - - with mock.patch('optimizely.helpers.audience.is_user_in_experiment', return_value=False) as mock_audience_check: - self.assertIsNone(decision_service.get_variation_for_feature(feature, 'user1')) - - # Check that all experiments in rollout layer were checked - self.assertEqual(3, mock_audience_check.call_count) - mock_audience_check.assert_any_call(project_config, project_config.get_experiment_from_key('211127'), None) - mock_audience_check.assert_any_call(project_config, project_config.get_experiment_from_key('211137'), None) - mock_audience_check.assert_any_call(project_config, project_config.get_experiment_from_key('211147'), None) - - def test_get_variation_for_feature__returns_none_for_user_in_group_but_experiment_not_associated_with_feature(self): + def test_get_variation_for_feature__returns_none_for_user_in_group_experiment_not_associated_with_feature(self, _): """ Test that if a user is in the mutex group but the experiment is not targeting a feature, then None is returned. """ - opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = opt_obj.config - decision_service = opt_obj.decision_service - feature = project_config.get_feature_from_key('test_feature_in_group') + feature = self.project_config.get_feature_from_key('test_feature_in_group') - with mock.patch( - 'optimizely.decision_service.DecisionService.get_experiment_in_group', - return_value=project_config.get_experiment_from_key('group_exp_2')) as mock_decision: - self.assertIsNone(decision_service.get_variation_for_feature(feature, 'user_1')) - - mock_decision.assert_called_once_with(project_config.get_group('19228'), 'user_1') + with mock.patch('optimizely.decision_service.DecisionService.get_experiment_in_group', + return_value=self.project_config.get_experiment_from_key('group_exp_2')) as mock_decision: + self.assertIsNone(self.decision_service.get_variation_for_feature(feature, 'user_1')) - def test_get_variation_for_feature__skips_to_everyone_else_rule(self): - """ Test that if a user is in an audience, but does not qualify - for the experiment, then it skips to the Everyone Else rule. """ - - opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) - project_config = opt_obj.config - decision_service = opt_obj.decision_service - feature = project_config.get_feature_from_key('test_feature_in_rollout') - - with mock.patch('optimizely.helpers.audience.is_user_in_experiment', return_value=True) as mock_audience_check,\ - mock.patch('optimizely.bucketer.Bucketer.bucket', return_value=None): - self.assertIsNone(decision_service.get_variation_for_feature(feature, 'user1')) - - # Check that after first experiment, it skips to the last experiment to check - self.assertEqual(2, mock_audience_check.call_count) - mock_audience_check.assert_any_call(project_config, project_config.get_experiment_from_key('211127'), None) - mock_audience_check.assert_any_call(project_config, project_config.get_experiment_from_key('211147'), None) + mock_decision.assert_called_once_with(self.project_config.get_group('19228'), 'user_1') - def test_get_experiment_in_group(self): + def test_get_experiment_in_group(self, mock_logging): """ Test that get_experiment_in_group returns the bucketed experiment for the user. """ group = self.project_config.get_group('19228') experiment = self.project_config.get_experiment_from_id('32222') - with mock.patch('optimizely.bucketer.Bucketer.find_bucket', return_value='32222'),\ - mock.patch('optimizely.logger.NoOpLogger.log') as mock_logging: + with mock.patch('optimizely.bucketer.Bucketer.find_bucket', return_value='32222'): self.assertEqual(experiment, self.decision_service.get_experiment_in_group(group, 'user_1')) mock_logging.assert_called_with(enums.LogLevels.INFO, 'User "user_1" is in experiment group_exp_1 of group 19228.') - def test_get_experiment_in_group__returns_none_if_user_not_in_group(self): + def test_get_experiment_in_group__returns_none_if_user_not_in_group(self, mock_logging): """ Test that get_experiment_in_group returns None if the user is not bucketed into the group. """ group = self.project_config.get_group('19228') - with mock.patch('optimizely.bucketer.Bucketer.find_bucket', return_value=None), \ - mock.patch('optimizely.logger.NoOpLogger.log') as mock_logging: + with mock.patch('optimizely.bucketer.Bucketer.find_bucket', return_value=None): self.assertIsNone(self.decision_service.get_experiment_in_group(group, 'user_1')) mock_logging.assert_called_with(enums.LogLevels.INFO, 'User "user_1" is not in any experiments of group 19228.')