Skip to content

Commit f03357f

Browse files
authored
add conditional to check if cmab experiment (#433)
1 parent 8d346f4 commit f03357f

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

pkg/decision/persisting_experiment_service.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2019-2021, Optimizely, Inc. and contributors *
2+
* Copyright 2019-2026, Optimizely, Inc. and contributors *
33
* *
44
* Licensed under the Apache License, Version 2.0 (the "License"); *
55
* you may not use this file except in compliance with the License. *
@@ -48,7 +48,8 @@ func NewPersistingExperimentService(userProfileService UserProfileService, exper
4848
// GetDecision returns the decision with the variation the user is bucketed into
4949
func (p PersistingExperimentService) GetDecision(decisionContext ExperimentDecisionContext, userContext entities.UserContext, options *decide.Options) (experimentDecision ExperimentDecision, reasons decide.DecisionReasons, err error) {
5050
reasons = decide.NewDecisionReasons(options)
51-
if p.userProfileService == nil || options.IgnoreUserProfileService {
51+
// Skip UPS for CMAB experiments - CMAB decisions are dynamic and not stored for sticky bucketing
52+
if p.userProfileService == nil || options.IgnoreUserProfileService || isCmabExperiment(decisionContext.Experiment) {
5253
return p.experimentBucketedService.GetDecision(decisionContext, userContext, options)
5354
}
5455

@@ -123,3 +124,8 @@ func (p PersistingExperimentService) saveDecision(userProfile UserProfile, decis
123124
p.logger.Debug(fmt.Sprintf(`Decision saved for user %q.`, userProfile.ID))
124125
}
125126
}
127+
128+
// isCmabExperiment checks if the experiment is a CMAB experiment
129+
func isCmabExperiment(experiment *entities.Experiment) bool {
130+
return experiment != nil && experiment.Cmab != nil
131+
}

pkg/decision/persisting_experiment_service_test.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/****************************************************************************
2-
* Copyright 2019-2021, Optimizely, Inc. and contributors *
2+
* Copyright 2019-2026, Optimizely, Inc. and contributors *
33
* *
44
* Licensed under the Apache License, Version 2.0 (the "License"); *
55
* you may not use this file except in compliance with the License. *
@@ -137,6 +137,45 @@ func (s *PersistingExperimentServiceTestSuite) TestSavedVariationNoLongerValid()
137137
s.mockUserProfileService.AssertExpectations(s.T())
138138
}
139139

140+
func (s *PersistingExperimentServiceTestSuite) TestCmabExperimentSkipsUserProfileService() {
141+
// Create a CMAB experiment (has Cmab field set)
142+
cmabExperiment := entities.Experiment{
143+
ID: "cmab_exp_1",
144+
Key: "cmab_experiment",
145+
Variations: map[string]entities.Variation{
146+
"var1": {ID: "var1", Key: "variation_1"},
147+
},
148+
Cmab: &entities.Cmab{
149+
AttributeIds: []string{"attr1"},
150+
TrafficAllocation: 5000,
151+
},
152+
}
153+
154+
cmabDecisionContext := ExperimentDecisionContext{
155+
Experiment: &cmabExperiment,
156+
ProjectConfig: s.mockProjectConfig,
157+
}
158+
159+
cmabVariation := cmabExperiment.Variations["var1"]
160+
cmabDecision := ExperimentDecision{
161+
Variation: &cmabVariation,
162+
}
163+
164+
// Setup mock to return decision from bucketer service
165+
s.mockExperimentService.On("GetDecision", cmabDecisionContext, testUserContext, s.options).Return(cmabDecision, s.reasons, nil)
166+
167+
persistingExperimentService := NewPersistingExperimentService(s.mockUserProfileService, s.mockExperimentService, logging.GetLogger("", "NewPersistingExperimentService"))
168+
decision, _, err := persistingExperimentService.GetDecision(cmabDecisionContext, testUserContext, s.options)
169+
170+
s.Equal(cmabDecision, decision)
171+
s.NoError(err)
172+
// Verify bucketer service was called
173+
s.mockExperimentService.AssertCalled(s.T(), "GetDecision", cmabDecisionContext, testUserContext, s.options)
174+
// Verify UPS was NOT called - CMAB should skip user profile service entirely
175+
s.mockUserProfileService.AssertNotCalled(s.T(), "Lookup", mock.Anything)
176+
s.mockUserProfileService.AssertNotCalled(s.T(), "Save", mock.Anything)
177+
}
178+
140179
func TestPersistingExperimentServiceTestSuite(t *testing.T) {
141180
suite.Run(t, new(PersistingExperimentServiceTestSuite))
142181
}

0 commit comments

Comments
 (0)