Skip to content

Commit 7fd816b

Browse files
oakbanimikeproeng37
authored andcommitted
Feature Toggle (#102)
1 parent 56279de commit 7fd816b

File tree

5 files changed

+194
-35
lines changed

5 files changed

+194
-35
lines changed

optimizely/entities.py

Lines changed: 3 additions & 2 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
@@ -109,7 +109,8 @@ def __init__(self, id, value, **kwards):
109109
self.id = id
110110
self.value = value
111111

112-
def __init__(self, id, key, variables=None, **kwargs):
112+
def __init__(self, id, key, featureEnabled=False, variables=None, **kwargs):
113113
self.id = id
114114
self.key = key
115+
self.featureEnabled = featureEnabled
115116
self.variables = variables or []

optimizely/optimizely.py

Lines changed: 2 additions & 2 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
@@ -399,7 +399,7 @@ def is_feature_enabled(self, feature_key, user_id, attributes=None):
399399
return False
400400

401401
decision = self.decision_service.get_variation_for_feature(feature, user_id, attributes)
402-
if decision.variation:
402+
if decision.variation and decision.variation.featureEnabled:
403403
self.logger.log(enums.LogLevels.INFO, 'Feature "%s" is enabled for user "%s".' % (feature_key, user_id))
404404
# Send event if Decision came from an experiment.
405405
if decision.source == decision_service.DECISION_SOURCE_EXPERIMENT:

tests/base.py

Lines changed: 9 additions & 4 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
@@ -172,6 +172,7 @@ def setUp(self):
172172
'variations': [{
173173
'key': 'control',
174174
'id': '111128',
175+
'featureEnabled': False,
175176
'variables': [{
176177
'id': '127', 'value': 'false'
177178
}, {
@@ -184,6 +185,7 @@ def setUp(self):
184185
}, {
185186
'key': 'variation',
186187
'id': '111129',
188+
'featureEnabled': True,
187189
'variables': [{
188190
'id': '127', 'value': 'true'
189191
}, {
@@ -288,7 +290,8 @@ def setUp(self):
288290
}],
289291
'variations': [{
290292
'key': '211129',
291-
'id': '211129'
293+
'id': '211129',
294+
'featureEnabled': True
292295
}]
293296
}, {
294297
'id': '211137',
@@ -303,7 +306,8 @@ def setUp(self):
303306
}],
304307
'variations': [{
305308
'key': '211139',
306-
'id': '211139'
309+
'id': '211139',
310+
'featureEnabled': True
307311
}]
308312
}, {
309313
'id': '211147',
@@ -318,7 +322,8 @@ def setUp(self):
318322
}],
319323
'variations': [{
320324
'key': '211149',
321-
'id': '211149'
325+
'id': '211149',
326+
'featureEnabled': True
322327
}]
323328
}]
324329
}],

tests/test_config.py

Lines changed: 61 additions & 22 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
@@ -226,13 +226,15 @@ def test_init__with_v3_datafile(self):
226226
'variations': [{
227227
'key': 'control',
228228
'id': '111128',
229+
'featureEnabled': False,
229230
'variables': [{
230231
'id': '127',
231232
'value': 'false'
232233
}]
233234
}, {
234235
'key': 'variation',
235236
'id': '111129',
237+
'featureEnabled': False,
236238
'variables': [{
237239
'id': '127',
238240
'value': 'true'
@@ -251,6 +253,7 @@ def test_init__with_v3_datafile(self):
251253
'variations': [{
252254
'key': 'group_exp_1_control',
253255
'id': '28901',
256+
'featureEnabled': False,
254257
'variables': [{
255258
'id': '128',
256259
'value': 'prod'
@@ -264,6 +267,7 @@ def test_init__with_v3_datafile(self):
264267
}, {
265268
'key': 'group_exp_1_variation',
266269
'id': '28902',
270+
'featureEnabled': False,
267271
'variables': [{
268272
'id': '128',
269273
'value': 'stage'
@@ -295,10 +299,12 @@ def test_init__with_v3_datafile(self):
295299
'variations': [{
296300
'key': 'group_exp_2_control',
297301
'id': '28905',
302+
'featureEnabled': False,
298303
'variables': []
299304
}, {
300305
'key': 'group_exp_2_variation',
301306
'id': '28906',
307+
'featureEnabled': False,
302308
'variables': []
303309
}],
304310
'forcedVariations': {
@@ -356,13 +362,15 @@ def test_init__with_v3_datafile(self):
356362
'111127', 'test_experiment', 'Running', ['11154'], [{
357363
'key': 'control',
358364
'id': '111128',
365+
'featureEnabled': False,
359366
'variables': [{
360367
'id': '127',
361368
'value': 'false'
362369
}]
363370
}, {
364371
'key': 'variation',
365372
'id': '111129',
373+
'featureEnabled': False,
366374
'variables': [{
367375
'id': '127',
368376
'value': 'true'
@@ -385,6 +393,7 @@ def test_init__with_v3_datafile(self):
385393
'32222', 'group_exp_1', 'Running', [], [{
386394
'key': 'group_exp_1_control',
387395
'id': '28901',
396+
'featureEnabled': False,
388397
'variables': [{
389398
'id': '128',
390399
'value': 'prod'
@@ -398,6 +407,7 @@ def test_init__with_v3_datafile(self):
398407
}, {
399408
'key': 'group_exp_1_variation',
400409
'id': '28902',
410+
'featureEnabled': False,
401411
'variables': [{
402412
'id': '128',
403413
'value': 'stage'
@@ -423,10 +433,12 @@ def test_init__with_v3_datafile(self):
423433
'32223', 'group_exp_2', 'Running', [], [{
424434
'key': 'group_exp_2_control',
425435
'id': '28905',
436+
'featureEnabled': False,
426437
'variables': []
427438
}, {
428439
'key': 'group_exp_2_variation',
429440
'id': '28906',
441+
'featureEnabled': False,
430442
'variables': []
431443
}], {
432444
'user_1': 'group_exp_2_control',
@@ -462,15 +474,15 @@ def test_init__with_v3_datafile(self):
462474
}
463475
expected_variation_key_map = {
464476
'test_experiment': {
465-
'control': entities.Variation('111128', 'control', [{'id': '127', 'value': 'false'}]),
466-
'variation': entities.Variation('111129', 'variation', [{'id': '127', 'value': 'true'}])
477+
'control': entities.Variation('111128', 'control', False, [{'id': '127', 'value': 'false'}]),
478+
'variation': entities.Variation('111129', 'variation', False, [{'id': '127', 'value': 'true'}])
467479
},
468480
'group_exp_1': {
469481
'group_exp_1_control': entities.Variation(
470-
'28901', 'group_exp_1_control', [
482+
'28901', 'group_exp_1_control', False, [
471483
{'id': '128', 'value': 'prod'}, {'id': '129', 'value': '1772'}, {'id': '130', 'value': '1.22992'}]),
472484
'group_exp_1_variation': entities.Variation(
473-
'28902', 'group_exp_1_variation', [
485+
'28902', 'group_exp_1_variation', False, [
474486
{'id': '128', 'value': 'stage'}, {'id': '129', 'value': '112'}, {'id': '130', 'value': '1.211'}])
475487
},
476488
'group_exp_2': {
@@ -480,13 +492,13 @@ def test_init__with_v3_datafile(self):
480492
}
481493
expected_variation_id_map = {
482494
'test_experiment': {
483-
'111128': entities.Variation('111128', 'control', [{'id': '127', 'value': 'false'}]),
484-
'111129': entities.Variation('111129', 'variation', [{'id': '127', 'value': 'true'}])
495+
'111128': entities.Variation('111128', 'control', False, [{'id': '127', 'value': 'false'}]),
496+
'111129': entities.Variation('111129', 'variation', False, [{'id': '127', 'value': 'true'}])
485497
},
486498
'group_exp_1': {
487-
'28901': entities.Variation('28901', 'group_exp_1_control', [
499+
'28901': entities.Variation('28901', 'group_exp_1_control', False, [
488500
{'id': '128', 'value': 'prod'}, {'id': '129', 'value': '1772'}, {'id': '130', 'value': '1.22992'}]),
489-
'28902': entities.Variation('28902', 'group_exp_1_variation', [
501+
'28902': entities.Variation('28902', 'group_exp_1_variation', False, [
490502
{'id': '128', 'value': 'stage'}, {'id': '129', 'value': '112'}, {'id': '130', 'value': '1.211'}])
491503
},
492504
'group_exp_2': {
@@ -861,42 +873,42 @@ def test_init__with_v4_datafile(self):
861873
}
862874
expected_variation_key_map = {
863875
'test_experiment': {
864-
'control': entities.Variation('111128', 'control', [{'id': '127', 'value': 'false'}]),
865-
'variation': entities.Variation('111129', 'variation', [{'id': '127', 'value': 'true'}])
876+
'control': entities.Variation('111128', 'control', False, [{'id': '127', 'value': 'false'}]),
877+
'variation': entities.Variation('111129', 'variation', False, [{'id': '127', 'value': 'true'}])
866878
},
867879
'group_exp_1': {
868880
'group_exp_1_control': entities.Variation(
869-
'28901', 'group_exp_1_control', [
881+
'28901', 'group_exp_1_control', False, [
870882
{'id': '128', 'value': 'prod'}, {'id': '129', 'value': '1772'}, {'id': '130', 'value': '1.22992'}]),
871883
'group_exp_1_variation': entities.Variation(
872-
'28902', 'group_exp_1_variation', [
884+
'28902', 'group_exp_1_variation', False, [
873885
{'id': '128', 'value': 'stage'}, {'id': '129', 'value': '112'}, {'id': '130', 'value': '1.211'}])
874886
},
875887
'group_exp_2': {
876888
'group_exp_2_control': entities.Variation('28905', 'group_exp_2_control'),
877889
'group_exp_2_variation': entities.Variation('28906', 'group_exp_2_variation')
878890
},
879891
'211112': {
880-
'211113': entities.Variation('211113', '211113', [{'id': '131', 'value': '15'}])
892+
'211113': entities.Variation('211113', '211113', False, [{'id': '131', 'value': '15'}])
881893
}
882894
}
883895
expected_variation_id_map = {
884896
'test_experiment': {
885-
'111128': entities.Variation('111128', 'control', [{'id': '127', 'value': 'false'}]),
886-
'111129': entities.Variation('111129', 'variation', [{'id': '127', 'value': 'true'}])
897+
'111128': entities.Variation('111128', 'control', False, [{'id': '127', 'value': 'false'}]),
898+
'111129': entities.Variation('111129', 'variation', False, [{'id': '127', 'value': 'true'}])
887899
},
888900
'group_exp_1': {
889-
'28901': entities.Variation('28901', 'group_exp_1_control', [
901+
'28901': entities.Variation('28901', 'group_exp_1_control', False, [
890902
{'id': '128', 'value': 'prod'}, {'id': '129', 'value': '1772'}, {'id': '130', 'value': '1.22992'}]),
891-
'28902': entities.Variation('28902', 'group_exp_1_variation', [
903+
'28902': entities.Variation('28902', 'group_exp_1_variation', False, [
892904
{'id': '128', 'value': 'stage'}, {'id': '129', 'value': '112'}, {'id': '130', 'value': '1.211'}])
893905
},
894906
'group_exp_2': {
895907
'28905': entities.Variation('28905', 'group_exp_2_control'),
896908
'28906': entities.Variation('28906', 'group_exp_2_variation')
897909
},
898910
'211112': {
899-
'211113': entities.Variation('211113', '211113', [{'id': '131', 'value': '15'}])
911+
'211113': entities.Variation('211113', '211113', False, [{'id': '131', 'value': '15'}])
900912
}
901913
}
902914

@@ -973,6 +985,30 @@ def test_init__with_v4_datafile(self):
973985
self.assertEqual(expected_rollout_id_map, project_config.rollout_id_map)
974986
self.assertEqual(expected_variation_variable_usage_map, project_config.variation_variable_usage_map)
975987

988+
def test_variation_has_featureEnabled_false_if_prop_undefined(self):
989+
""" Test that featureEnabled property by default is set to False, when not given in the data file"""
990+
variation = {
991+
'key': 'group_exp_1_variation',
992+
'id': '28902',
993+
'variables': [{
994+
'id': '128',
995+
'value': 'stage'
996+
}, {
997+
'id': '129',
998+
'value': '112'
999+
}, {
1000+
'id': '130',
1001+
'value': '1.211'
1002+
}]
1003+
}
1004+
1005+
variation_entity = entities.Variation(**variation)
1006+
1007+
self.assertEqual(variation['id'], variation_entity.id)
1008+
self.assertEqual(variation['key'], variation_entity.key)
1009+
self.assertEqual(variation['variables'], variation_entity.variables)
1010+
self.assertFalse(variation_entity.featureEnabled)
1011+
9761012
def test_get_version(self):
9771013
""" Test that JSON version is retrieved correctly when using get_version. """
9781014

@@ -1161,7 +1197,8 @@ def test_get_rollout_from_id__valid_rollout_id(self):
11611197
}],
11621198
'variations': [{
11631199
'key': '211129',
1164-
'id': '211129'
1200+
'id': '211129',
1201+
'featureEnabled': True
11651202
}]
11661203
}, {
11671204
'id': '211137',
@@ -1176,7 +1213,8 @@ def test_get_rollout_from_id__valid_rollout_id(self):
11761213
}],
11771214
'variations': [{
11781215
'key': '211139',
1179-
'id': '211139'
1216+
'id': '211139',
1217+
'featureEnabled': True
11801218
}]
11811219
}, {
11821220
'id': '211147',
@@ -1191,7 +1229,8 @@ def test_get_rollout_from_id__valid_rollout_id(self):
11911229
}],
11921230
'variations': [{
11931231
'key': '211149',
1194-
'id': '211149'
1232+
'id': '211149',
1233+
'featureEnabled': True
11951234
}]
11961235
}])
11971236
self.assertEqual(expected_rollout, project_config.get_rollout_from_id('211111'))

0 commit comments

Comments
 (0)