@@ -1074,6 +1074,184 @@ def test_get_variation_cmab_experiment_with_whitelisted_variation(self):
10741074 mock_bucket .assert_not_called ()
10751075 mock_cmab_decision .assert_not_called ()
10761076
1077+ def test_get_variation_cmab_experiment_skips_ups_lookup (self ):
1078+ """Test that get_variation skips UPS lookup for CMAB experiments."""
1079+
1080+ # Create a user context
1081+ user = optimizely_user_context .OptimizelyUserContext (
1082+ optimizely_client = None ,
1083+ logger = None ,
1084+ user_id = "test_user" ,
1085+ user_attributes = {}
1086+ )
1087+
1088+ # Create a CMAB experiment
1089+ cmab_experiment = entities .Experiment (
1090+ '111150' ,
1091+ 'cmab_experiment' ,
1092+ 'Running' ,
1093+ '111150' ,
1094+ [],
1095+ {},
1096+ [entities .Variation ('111151' , 'variation_1' )],
1097+ [{'entityId' : '111151' , 'endOfRange' : 10000 }],
1098+ cmab = {'trafficAllocation' : 5000 }
1099+ )
1100+
1101+ # Set up a user profile tracker with a stored variation
1102+ user_profile_tracker = user_profile .UserProfileTracker (
1103+ 'test_user' , self .decision_service .user_profile_service , self .decision_service .logger
1104+ )
1105+ user_profile_tracker .user_profile = user_profile .UserProfile (
1106+ 'test_user' ,
1107+ {'111150' : {'variation_id' : '111151' }}
1108+ )
1109+
1110+ with mock .patch ('optimizely.helpers.audience.does_user_meet_audience_conditions' ,
1111+ return_value = [True , []]), \
1112+ mock .patch .object (self .decision_service .bucketer , 'bucket_to_entity_id' ,
1113+ return_value = ['$' , []]), \
1114+ mock .patch .object (self .decision_service , 'cmab_service' ) as mock_cmab_service , \
1115+ mock .patch .object (self .project_config , 'get_variation_from_id' ,
1116+ return_value = entities .Variation ('111151' , 'variation_1' )), \
1117+ mock .patch .object (self .decision_service , 'get_stored_variation' ) as mock_get_stored :
1118+
1119+ mock_cmab_service .get_decision .return_value = (
1120+ {'variation_id' : '111151' , 'cmab_uuid' : 'test-cmab-uuid' },
1121+ []
1122+ )
1123+
1124+ variation_result = self .decision_service .get_variation (
1125+ self .project_config ,
1126+ cmab_experiment ,
1127+ user ,
1128+ user_profile_tracker
1129+ )
1130+
1131+ # Verify UPS lookup was NOT called for CMAB experiment
1132+ mock_get_stored .assert_not_called ()
1133+
1134+ # Verify the decision reason for UPS exclusion is present
1135+ self .assertIn (
1136+ 'Skipping user profile service for CMAB experiment "cmab_experiment".' ,
1137+ variation_result ['reasons' ]
1138+ )
1139+
1140+ # Verify CMAB service was still called
1141+ mock_cmab_service .get_decision .assert_called_once ()
1142+
1143+ def test_get_variation_cmab_experiment_skips_ups_save (self ):
1144+ """Test that get_variation skips saving to UPS for CMAB experiments."""
1145+
1146+ # Create a user context
1147+ user = optimizely_user_context .OptimizelyUserContext (
1148+ optimizely_client = None ,
1149+ logger = None ,
1150+ user_id = "test_user" ,
1151+ user_attributes = {}
1152+ )
1153+
1154+ # Create a CMAB experiment
1155+ cmab_experiment = entities .Experiment (
1156+ '111150' ,
1157+ 'cmab_experiment' ,
1158+ 'Running' ,
1159+ '111150' ,
1160+ [],
1161+ {},
1162+ [entities .Variation ('111151' , 'variation_1' )],
1163+ [{'entityId' : '111151' , 'endOfRange' : 10000 }],
1164+ cmab = {'trafficAllocation' : 5000 }
1165+ )
1166+
1167+ # Set up a user profile tracker
1168+ user_profile_tracker = user_profile .UserProfileTracker (
1169+ 'test_user' , self .decision_service .user_profile_service , self .decision_service .logger
1170+ )
1171+
1172+ with mock .patch ('optimizely.helpers.audience.does_user_meet_audience_conditions' ,
1173+ return_value = [True , []]), \
1174+ mock .patch .object (self .decision_service .bucketer , 'bucket_to_entity_id' ,
1175+ return_value = ['$' , []]), \
1176+ mock .patch .object (self .decision_service , 'cmab_service' ) as mock_cmab_service , \
1177+ mock .patch .object (self .project_config , 'get_variation_from_id' ,
1178+ return_value = entities .Variation ('111151' , 'variation_1' )), \
1179+ mock .patch .object (user_profile_tracker , 'update_user_profile' ) as mock_update_profile :
1180+
1181+ mock_cmab_service .get_decision .return_value = (
1182+ {'variation_id' : '111151' , 'cmab_uuid' : 'test-cmab-uuid' },
1183+ []
1184+ )
1185+
1186+ variation_result = self .decision_service .get_variation (
1187+ self .project_config ,
1188+ cmab_experiment ,
1189+ user ,
1190+ user_profile_tracker
1191+ )
1192+
1193+ # Verify UPS save was NOT called for CMAB experiment
1194+ mock_update_profile .assert_not_called ()
1195+
1196+ # Verify we still got the correct variation
1197+ self .assertEqual (entities .Variation ('111151' , 'variation_1' ), variation_result ['variation' ])
1198+ self .assertEqual ('test-cmab-uuid' , variation_result ['cmab_uuid' ])
1199+ self .assertStrictFalse (variation_result ['error' ])
1200+
1201+ def test_get_variation_non_cmab_experiment_still_uses_ups (self ):
1202+ """Test that non-CMAB experiments still use UPS for lookup and save."""
1203+
1204+ # Create a user context
1205+ user = optimizely_user_context .OptimizelyUserContext (
1206+ optimizely_client = None ,
1207+ logger = None ,
1208+ user_id = "test_user" ,
1209+ user_attributes = {}
1210+ )
1211+
1212+ # Create a non-CMAB experiment (no cmab attribute)
1213+ experiment = entities .Experiment (
1214+ '111150' ,
1215+ 'regular_experiment' ,
1216+ 'Running' ,
1217+ '111150' ,
1218+ [],
1219+ {},
1220+ [entities .Variation ('111151' , 'variation_1' )],
1221+ [{'entityId' : '111151' , 'endOfRange' : 10000 }]
1222+ )
1223+
1224+ stored_variation = entities .Variation ('111151' , 'variation_1' )
1225+
1226+ # Set up a user profile tracker with a stored variation
1227+ user_profile_tracker = user_profile .UserProfileTracker (
1228+ 'test_user' , self .decision_service .user_profile_service , self .decision_service .logger
1229+ )
1230+ user_profile_tracker .user_profile = user_profile .UserProfile (
1231+ 'test_user' ,
1232+ {'111150' : {'variation_id' : '111151' }}
1233+ )
1234+
1235+ with mock .patch .object (self .decision_service , 'get_stored_variation' ,
1236+ return_value = stored_variation ) as mock_get_stored :
1237+
1238+ variation_result = self .decision_service .get_variation (
1239+ self .project_config ,
1240+ experiment ,
1241+ user ,
1242+ user_profile_tracker
1243+ )
1244+
1245+ # Verify UPS lookup WAS called for non-CMAB experiment
1246+ mock_get_stored .assert_called_once ()
1247+
1248+ # Verify the UPS exclusion message is NOT in reasons
1249+ for reason in variation_result ['reasons' ]:
1250+ self .assertNotIn ('Skipping user profile service' , reason )
1251+
1252+ # Verify we got the stored variation
1253+ self .assertEqual (stored_variation , variation_result ['variation' ])
1254+
10771255
10781256class FeatureFlagDecisionTests (base .BaseTest ):
10791257 def setUp (self ):
0 commit comments