@@ -457,9 +457,10 @@ def test_get_variation__experiment_not_running(self):
457
457
) as mock_lookup , mock .patch (
458
458
"optimizely.user_profile.UserProfileService.save"
459
459
) as mock_save :
460
- variation , _ , _ = self .decision_service .get_variation (
460
+ variation_result = self .decision_service .get_variation (
461
461
self .project_config , experiment , user , None
462
462
)
463
+ variation = variation_result ['variation' ]
463
464
self .assertIsNone (
464
465
variation
465
466
)
@@ -500,7 +501,7 @@ def test_get_variation__bucketing_id_provided(self):
500
501
"optimizely.bucketer.Bucketer.bucket" ,
501
502
return_value = [self .project_config .get_variation_from_id ("211127" , "211129" ), []],
502
503
) as mock_bucket :
503
- variation , _ , _ = self .decision_service .get_variation (
504
+ _ = self .decision_service .get_variation (
504
505
self .project_config ,
505
506
experiment ,
506
507
user ,
@@ -535,9 +536,9 @@ def test_get_variation__user_whitelisted_for_variation(self):
535
536
) as mock_lookup , mock .patch (
536
537
"optimizely.user_profile.UserProfileService.save"
537
538
) as mock_save :
538
- variation , _ , _ = self .decision_service .get_variation (
539
+ variation = self .decision_service .get_variation (
539
540
self .project_config , experiment , user , user_profile_tracker
540
- )
541
+ )[ 'variation' ]
541
542
self .assertEqual (
542
543
entities .Variation ("111128" , "control" ),
543
544
variation ,
@@ -573,9 +574,9 @@ def test_get_variation__user_has_stored_decision(self):
573
574
) as mock_audience_check , mock .patch (
574
575
"optimizely.bucketer.Bucketer.bucket"
575
576
) as mock_bucket :
576
- variation , _ , _ = self .decision_service .get_variation (
577
+ variation = self .decision_service .get_variation (
577
578
self .project_config , experiment , user , user_profile_tracker
578
- )
579
+ )[ 'variation' ]
579
580
self .assertEqual (
580
581
entities .Variation ("111128" , "control" ),
581
582
variation ,
@@ -619,9 +620,9 @@ def test_get_variation__user_bucketed_for_new_experiment__user_profile_tracker_a
619
620
"optimizely.bucketer.Bucketer.bucket" ,
620
621
return_value = [entities .Variation ("111129" , "variation" ), []],
621
622
) as mock_bucket :
622
- variation , _ , _ = self .decision_service .get_variation (
623
+ variation = self .decision_service .get_variation (
623
624
self .project_config , experiment , user , user_profile_tracker
624
- )
625
+ )[ 'variation' ]
625
626
self .assertEqual (
626
627
entities .Variation ("111129" , "variation" ),
627
628
variation ,
@@ -669,9 +670,9 @@ def test_get_variation__user_does_not_meet_audience_conditions(self):
669
670
) as mock_bucket , mock .patch (
670
671
"optimizely.user_profile.UserProfileService.save"
671
672
) as mock_save :
672
- variation , _ , _ = self .decision_service .get_variation (
673
+ variation = self .decision_service .get_variation (
673
674
self .project_config , experiment , user , user_profile_tracker
674
- )
675
+ )[ 'variation' ]
675
676
self .assertIsNone (
676
677
variation
677
678
)
@@ -719,14 +720,14 @@ def test_get_variation__ignore_user_profile_when_specified(self):
719
720
) as mock_lookup , mock .patch (
720
721
"optimizely.user_profile.UserProfileService.save"
721
722
) as mock_save :
722
- variation , _ , _ = self .decision_service .get_variation (
723
+ variation = self .decision_service .get_variation (
723
724
self .project_config ,
724
725
experiment ,
725
726
user ,
726
727
user_profile_tracker ,
727
728
[],
728
729
options = ['IGNORE_USER_PROFILE_SERVICE' ],
729
- )
730
+ )[ 'variation' ]
730
731
self .assertEqual (
731
732
entities .Variation ("111129" , "variation" ),
732
733
variation ,
@@ -796,16 +797,22 @@ def test_get_variation_cmab_experiment_user_in_traffic_allocation(self):
796
797
'logger' ) as mock_logger :
797
798
798
799
# Call get_variation with the CMAB experiment
799
- variation , reasons , cmab_uuid = self .decision_service .get_variation (
800
+ variation_result = self .decision_service .get_variation (
800
801
self .project_config ,
801
802
cmab_experiment ,
802
803
user ,
803
804
None
804
805
)
806
+ cmab_uuid = variation_result ['cmab_uuid' ]
807
+ variation = variation_result ['variation' ]
808
+ error = variation_result ['error' ]
809
+ reasons = variation_result ['reasons' ]
805
810
806
811
# Verify the variation and cmab_uuid
807
812
self .assertEqual (entities .Variation ('111151' , 'variation_1' ), variation )
808
813
self .assertEqual ('test-cmab-uuid-123' , cmab_uuid )
814
+ self .assertStrictFalse (error )
815
+ self .assertIn ('User "test_user" is in variation "variation_1" of experiment cmab_experiment.' , reasons )
809
816
810
817
# Verify logger was called
811
818
mock_logger .info .assert_any_call ('User "test_user" is in variation '
@@ -844,16 +851,23 @@ def test_get_variation_cmab_experiment_user_not_in_traffic_allocation(self):
844
851
'logger' ) as mock_logger :
845
852
846
853
# Call get_variation with the CMAB experiment
847
- variation , reasons , cmab_uuid = self .decision_service .get_variation (
854
+ variation_result = self .decision_service .get_variation (
848
855
self .project_config ,
849
856
cmab_experiment ,
850
857
user ,
851
858
None
852
859
)
860
+ variation = variation_result ['variation' ]
861
+ cmab_uuid = variation_result ['cmab_uuid' ]
862
+ error = variation_result ['error' ]
863
+ reasons = variation_result ['reasons' ]
853
864
854
865
# Verify we get no variation and CMAB service wasn't called
855
866
self .assertIsNone (variation )
856
867
self .assertIsNone (cmab_uuid )
868
+ self .assertStrictFalse (error )
869
+ self .assertIn ('User "test_user" not in CMAB experiment "cmab_experiment" due to traffic allocation.' ,
870
+ reasons )
857
871
mock_cmab_decision .assert_not_called ()
858
872
859
873
# Verify logger was called
@@ -888,25 +902,25 @@ def test_get_variation_cmab_experiment_service_error(self):
888
902
mock .patch ('optimizely.helpers.audience.does_user_meet_audience_conditions' , return_value = [True , []]), \
889
903
mock .patch ('optimizely.bucketer.Bucketer.bucket_to_entity_id' , return_value = ['$' , []]), \
890
904
mock .patch ('optimizely.decision_service.DecisionService._get_decision_for_cmab_experiment' ,
891
- return_value = {'error' : True , 'result' : None , 'reasons' : ['CMAB service error' ]}), \
892
- mock .patch .object (self .decision_service ,
893
- 'logger' ) as mock_logger :
905
+ return_value = {'error' : True , 'result' : None , 'reasons' : ['CMAB service error' ]}):
894
906
895
907
# Call get_variation with the CMAB experiment
896
- variation , reasons , cmab_uuid = self .decision_service .get_variation (
908
+ variation_result = self .decision_service .get_variation (
897
909
self .project_config ,
898
910
cmab_experiment ,
899
911
user ,
900
912
None
901
913
)
914
+ variation = variation_result ['variation' ]
915
+ cmab_uuid = variation_result ['cmab_uuid' ]
916
+ reasons = variation_result ['reasons' ]
917
+ error = variation_result ['error' ]
902
918
903
919
# Verify we get no variation due to CMAB service error
904
920
self .assertIsNone (variation )
905
921
self .assertIsNone (cmab_uuid )
906
922
self .assertIn ('CMAB service error' , reasons )
907
-
908
- # Verify logger was called
909
- mock_logger .error .assert_any_call ('CMAB decision fetch failed with status: CMAB service error' )
923
+ self .assertStrictTrue (error )
910
924
911
925
def test_get_variation_cmab_experiment_deep_mock_500_error (self ):
912
926
"""Test the full flow of a CMAB experiment with a 500 error from the HTTP request layer."""
@@ -1015,17 +1029,22 @@ def test_get_variation_cmab_experiment_forced_variation(self):
1015
1029
) as mock_cmab_decision :
1016
1030
1017
1031
# Call get_variation with the CMAB experiment
1018
- variation , reasons , cmab_uuid = self .decision_service .get_variation (
1032
+ variation_result = self .decision_service .get_variation (
1019
1033
self .project_config ,
1020
1034
cmab_experiment ,
1021
1035
user ,
1022
1036
None
1023
1037
)
1038
+ variation = variation_result ['variation' ]
1039
+ reasons = variation_result ['reasons' ]
1040
+ cmab_uuid = variation_result ['cmab_uuid' ]
1041
+ error = variation_result ['error' ]
1024
1042
1025
1043
# Verify we get the forced variation
1026
1044
self .assertEqual (forced_variation , variation )
1027
1045
self .assertIsNone (cmab_uuid )
1028
1046
self .assertIn ('User is forced into variation' , reasons )
1047
+ self .assertStrictFalse (error )
1029
1048
1030
1049
# Verify CMAB-specific methods weren't called
1031
1050
mock_bucket .assert_not_called ()
@@ -1072,17 +1091,22 @@ def test_get_variation_cmab_experiment_with_whitelisted_variation(self):
1072
1091
) as mock_cmab_decision :
1073
1092
1074
1093
# Call get_variation with the CMAB experiment
1075
- variation , reasons , cmab_uuid = self .decision_service .get_variation (
1094
+ variation_result = self .decision_service .get_variation (
1076
1095
self .project_config ,
1077
1096
cmab_experiment ,
1078
1097
user ,
1079
1098
None
1080
1099
)
1100
+ variation = variation_result ['variation' ]
1101
+ cmab_uuid = variation_result ['cmab_uuid' ]
1102
+ reasons = variation_result ['reasons' ]
1103
+ error = variation_result ['error' ]
1081
1104
1082
1105
# Verify we get the whitelisted variation
1083
1106
self .assertEqual (whitelisted_variation , variation )
1084
1107
self .assertIsNone (cmab_uuid )
1085
1108
self .assertIn ('User is whitelisted into variation' , reasons )
1109
+ self .assertStrictFalse (error )
1086
1110
1087
1111
# Verify CMAB-specific methods weren't called
1088
1112
mock_bucket .assert_not_called ()
@@ -1353,7 +1377,7 @@ def test_get_variation_for_feature__returns_variation_for_feature_in_experiment(
1353
1377
)
1354
1378
decision_patch = mock .patch (
1355
1379
"optimizely.decision_service.DecisionService.get_variation" ,
1356
- return_value = [ expected_variation , [], None ] ,
1380
+ return_value = { 'variation' : expected_variation , 'cmab_uuid' : None , 'reasons' : [], 'error' : False } ,
1357
1381
)
1358
1382
with decision_patch as mock_decision , self .mock_decision_logger :
1359
1383
variation_received , _ = self .decision_service .get_variation_for_feature (
@@ -1485,7 +1509,7 @@ def test_get_variation_for_feature__returns_variation_for_feature_in_group(self)
1485
1509
)
1486
1510
with mock .patch (
1487
1511
"optimizely.decision_service.DecisionService.get_variation" ,
1488
- return_value = ( expected_variation , [], None ) ,
1512
+ return_value = { 'variation' : expected_variation , 'cmab_uuid' : None , 'reasons' : [], 'error' : False } ,
1489
1513
) as mock_decision :
1490
1514
variation_received , _ = self .decision_service .get_variation_for_feature (
1491
1515
self .project_config , feature , user , options = None
@@ -1520,7 +1544,7 @@ def test_get_variation_for_feature__returns_none_for_user_not_in_experiment(self
1520
1544
1521
1545
with mock .patch (
1522
1546
"optimizely.decision_service.DecisionService.get_variation" ,
1523
- return_value = [ None , [], None ] ,
1547
+ return_value = { 'variation' : None , 'cmab_uuid' : None , 'reasons' : [], 'error' : False } ,
1524
1548
) as mock_decision :
1525
1549
variation_received , _ = self .decision_service .get_variation_for_feature (
1526
1550
self .project_config , feature , user
@@ -1552,7 +1576,7 @@ def test_get_variation_for_feature__returns_none_for_user_in_group_experiment_no
1552
1576
feature = self .project_config .get_feature_from_key ("test_feature_in_group" )
1553
1577
with mock .patch (
1554
1578
"optimizely.decision_service.DecisionService.get_variation" ,
1555
- return_value = [ None , [], None ] ,
1579
+ return_value = { 'variation' : None , 'cmab_uuid' : None , 'reasons' : [], 'error' : False } ,
1556
1580
) as mock_decision :
1557
1581
variation_received , _ = self .decision_service .get_variation_for_feature (
1558
1582
self .project_config , feature , user , False
0 commit comments