Skip to content

Commit 05ea76e

Browse files
committed
🖊️ Return default value when no variable usage found for variation
1 parent 9972c3d commit 05ea76e

File tree

4 files changed

+93
-18
lines changed

4 files changed

+93
-18
lines changed

optimizely/optimizely.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -230,11 +230,7 @@ def _get_feature_variable_for_type(self, feature_key, variable_key, variable_typ
230230
decision = self.decision_service.get_variation_for_feature(feature_flag, user_id, attributes)
231231
if decision.variation:
232232
variable_value = self.config.get_variable_value_for_variation(variable, decision.variation)
233-
self.logger.log(
234-
enums.LogLevels.INFO,
235-
'Value for variable "%s" of feature flag "%s" is %s for user "%s".' % (
236-
variable_key, feature_key, variable_value, user_id
237-
))
233+
238234
else:
239235
variable_value = variable.defaultValue
240236
self.logger.log(

optimizely/project_config.py

Lines changed: 24 additions & 8 deletions
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
@@ -90,10 +90,9 @@ def __init__(self, datafile, logger, error_handler):
9090
self.variation_id_map[experiment.key] = {}
9191
for variation in self.variation_key_map.get(experiment.key).values():
9292
self.variation_id_map[experiment.key][variation.id] = variation
93-
if variation.variables:
94-
self.variation_variable_usage_map[variation.id] = self._generate_key_map(
95-
variation.variables, 'id', entities.Variation.VariableUsage
96-
)
93+
self.variation_variable_usage_map[variation.id] = self._generate_key_map(
94+
variation.variables, 'id', entities.Variation.VariableUsage
95+
)
9796

9897
self.feature_key_map = self._generate_key_map(self.feature_flags, 'key', entities.FeatureFlag)
9998
for feature in self.feature_key_map.values():
@@ -439,10 +438,27 @@ def get_variable_value_for_variation(self, variable, variation):
439438
variable_usages = self.variation_variable_usage_map[variation.id]
440439

441440
# Find usage in given variation
442-
variable_usage = variable_usages.get(variable.id)
441+
variable_usage = None
442+
if variable_usages:
443+
variable_usage = variable_usages.get(variable.id)
444+
445+
if variable_usage:
446+
variable_value = variable_usage.value
447+
self.logger.log(
448+
enums.LogLevels.INFO,
449+
'Value for variable "%s" for variation "%s" is "%s".' % (
450+
variable.key, variation.key, variable_value
451+
))
443452

444-
# Return default value in case there is no variable usage for the variable.
445-
return variable_usage.value if variable_usage else variable.defaultValue
453+
else:
454+
variable_value = variable.defaultValue
455+
self.logger.log(
456+
enums.LogLevels.INFO,
457+
'Variable "%s" is not used in variation "%s". Assinging default value "%s".' % (
458+
variable.key, variation.key, variable_value
459+
))
460+
461+
return variable_value
446462

447463
def get_variable_for_feature(self, feature_key, variable_key):
448464
""" Get the variable with the given variable key for the given feature.

tests/test_config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,8 @@ def test_init__with_v4_datafile(self):
616616
'129': entities.Variation.VariableUsage('129', '112'),
617617
'130': entities.Variation.VariableUsage('130', '1.211')
618618
},
619+
'28905': {},
620+
'28906': {},
619621
'211113': {
620622
'131': entities.Variation.VariableUsage('131', '15')
621623
}

tests/test_optimizely.py

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,7 +1436,7 @@ def test_get_feature_variable_boolean(self):
14361436

14371437
mock_logger.assert_called_once_with(
14381438
enums.LogLevels.INFO,
1439-
'Value for variable "is_working" of feature flag "test_feature_in_experiment" is true for user "test_user".'
1439+
'Value for variable "is_working" for variation "variation" is "true".'
14401440
)
14411441

14421442
def test_get_feature_variable_double(self):
@@ -1454,7 +1454,7 @@ def test_get_feature_variable_double(self):
14541454

14551455
mock_logger.assert_called_once_with(
14561456
enums.LogLevels.INFO,
1457-
'Value for variable "cost" of feature flag "test_feature_in_experiment" is 10.02 for user "test_user".'
1457+
'Value for variable "cost" for variation "variation" is "10.02".'
14581458
)
14591459

14601460
def test_get_feature_variable_integer(self):
@@ -1472,7 +1472,7 @@ def test_get_feature_variable_integer(self):
14721472

14731473
mock_logger.assert_called_once_with(
14741474
enums.LogLevels.INFO,
1475-
'Value for variable "count" of feature flag "test_feature_in_experiment" is 4243 for user "test_user".'
1475+
'Value for variable "count" for variation "variation" is "4243".'
14761476
)
14771477

14781478
def test_get_feature_variable_string(self):
@@ -1491,10 +1491,71 @@ def test_get_feature_variable_string(self):
14911491

14921492
mock_logger.assert_called_once_with(
14931493
enums.LogLevels.INFO,
1494-
'Value for variable "environment" of feature flag "test_feature_in_experiment" is staging for user "test_user".'
1494+
'Value for variable "environment" for variation "variation" is "staging".'
14951495
)
14961496

1497-
def test_get_feature_variable__returns_default_value(self):
1497+
def test_get_feature_variable__returns_default_value_if_variable_usage_not_in_variation(self):
1498+
""" Test that get_feature_variable_* returns default value if variable usage not present in variation. """
1499+
1500+
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features))
1501+
mock_experiment = opt_obj.config.get_experiment_from_key('test_experiment')
1502+
mock_variation = opt_obj.config.get_variation_from_id('test_experiment', '111129')
1503+
1504+
# Empty variable usage map for the mocked variation
1505+
opt_obj.config.variation_variable_usage_map['111129'] = None
1506+
1507+
# Boolean
1508+
with mock.patch('optimizely.decision_service.DecisionService.get_variation_for_feature',
1509+
return_value=decision_service.Decision(mock_experiment, mock_variation,
1510+
decision_service.DECISION_SOURCE_EXPERIMENT)), \
1511+
mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger:
1512+
self.assertTrue(opt_obj.get_feature_variable_boolean('test_feature_in_experiment', 'is_working', 'test_user'))
1513+
1514+
mock_logger.assert_called_once_with(
1515+
enums.LogLevels.INFO,
1516+
'Variable "is_working" is not used in variation "variation". Assinging default value "true".'
1517+
)
1518+
1519+
# Double
1520+
with mock.patch('optimizely.decision_service.DecisionService.get_variation_for_feature',
1521+
return_value=decision_service.Decision(mock_experiment, mock_variation,
1522+
decision_service.DECISION_SOURCE_EXPERIMENT)), \
1523+
mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger:
1524+
self.assertEqual(10.99,
1525+
opt_obj.get_feature_variable_double('test_feature_in_experiment', 'cost', 'test_user'))
1526+
1527+
mock_logger.assert_called_once_with(
1528+
enums.LogLevels.INFO,
1529+
'Variable "cost" is not used in variation "variation". Assinging default value "10.99".'
1530+
)
1531+
1532+
# Integer
1533+
with mock.patch('optimizely.decision_service.DecisionService.get_variation_for_feature',
1534+
return_value=decision_service.Decision(mock_experiment, mock_variation,
1535+
decision_service.DECISION_SOURCE_EXPERIMENT)), \
1536+
mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger:
1537+
self.assertEqual(999,
1538+
opt_obj.get_feature_variable_integer('test_feature_in_experiment', 'count', 'test_user'))
1539+
1540+
mock_logger.assert_called_once_with(
1541+
enums.LogLevels.INFO,
1542+
'Variable "count" is not used in variation "variation". Assinging default value "999".'
1543+
)
1544+
1545+
# String
1546+
with mock.patch('optimizely.decision_service.DecisionService.get_variation_for_feature',
1547+
return_value=decision_service.Decision(mock_experiment, mock_variation,
1548+
decision_service.DECISION_SOURCE_EXPERIMENT)), \
1549+
mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger:
1550+
self.assertEqual('devel',
1551+
opt_obj.get_feature_variable_string('test_feature_in_experiment', 'environment', 'test_user'))
1552+
1553+
mock_logger.assert_called_once_with(
1554+
enums.LogLevels.INFO,
1555+
'Variable "environment" is not used in variation "variation". Assinging default value "devel".'
1556+
)
1557+
1558+
def test_get_feature_variable__returns_default_value_if_no_variation(self):
14981559
""" Test that get_feature_variable_* returns default value if no variation. """
14991560

15001561
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features))

0 commit comments

Comments
 (0)