Skip to content

Commit 227607c

Browse files
authored
refact(decision-reasons): Refactoring reasons for decide api (#303)
1 parent 238332f commit 227607c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+529
-442
lines changed

pkg/client/client.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ func (o *OptimizelyClient) decide(userContext OptimizelyUserContext, key string,
9696
decisionReasons := decide.NewDecisionReasons(&allOptions)
9797
decisionContext.Variable = entities.Variable{}
9898

99-
featureDecision, err := o.DecisionService.GetFeatureDecision(decisionContext, usrContext, &allOptions, decisionReasons)
99+
featureDecision, reasons, err := o.DecisionService.GetFeatureDecision(decisionContext, usrContext, &allOptions)
100+
decisionReasons.Append(reasons)
101+
100102
if err != nil {
101103
o.logger.Warning(fmt.Sprintf(`Received error while making a decision for feature "%s": %s`, key, err))
102104
}
@@ -116,7 +118,8 @@ func (o *OptimizelyClient) decide(userContext OptimizelyUserContext, key string,
116118

117119
variableMap := map[string]interface{}{}
118120
if !allOptions.ExcludeVariables {
119-
variableMap = o.getDecisionVariableMap(feature, featureDecision.Variation, flagEnabled, decisionReasons)
121+
variableMap, reasons = o.getDecisionVariableMap(feature, featureDecision.Variation, flagEnabled)
122+
decisionReasons.Append(reasons)
120123
}
121124
optimizelyJSON := optimizelyjson.NewOptimizelyJSONfromMap(variableMap)
122125
reasonsToReport := decisionReasons.ToReport()
@@ -808,7 +811,7 @@ func (o *OptimizelyClient) getFeatureDecision(featureKey, variableKey string, us
808811

809812
decisionContext.Variable = variable
810813
options := &decide.Options{}
811-
featureDecision, err = o.DecisionService.GetFeatureDecision(decisionContext, userContext, options, decide.NewDecisionReasons(options))
814+
featureDecision, _, err = o.DecisionService.GetFeatureDecision(decisionContext, userContext, options)
812815
if err != nil {
813816
o.logger.Warning(fmt.Sprintf(`Received error while making a decision for feature "%s": %s`, featureKey, err))
814817
return decisionContext, featureDecision, nil
@@ -839,7 +842,7 @@ func (o *OptimizelyClient) getExperimentDecision(experimentKey string, userConte
839842
}
840843

841844
options := &decide.Options{}
842-
experimentDecision, err = o.DecisionService.GetExperimentDecision(decisionContext, userContext, options, decide.NewDecisionReasons(options))
845+
experimentDecision, _, err = o.DecisionService.GetExperimentDecision(decisionContext, userContext, options)
843846
if err != nil {
844847
o.logger.Warning(fmt.Sprintf(`Received error while making a decision for experiment "%s": %s`, experimentKey, err))
845848
return decisionContext, experimentDecision, nil
@@ -947,7 +950,8 @@ func (o *OptimizelyClient) Close() {
947950
o.execGroup.TerminateAndWait()
948951
}
949952

950-
func (o *OptimizelyClient) getDecisionVariableMap(feature entities.Feature, variation *entities.Variation, featureEnabled bool, decisionReasons decide.DecisionReasons) map[string]interface{} {
953+
func (o *OptimizelyClient) getDecisionVariableMap(feature entities.Feature, variation *entities.Variation, featureEnabled bool) (map[string]interface{}, decide.DecisionReasons) {
954+
reasons := decide.NewDecisionReasons(nil)
951955
valuesMap := map[string]interface{}{}
952956

953957
for _, v := range feature.VariableMap {
@@ -961,12 +965,12 @@ func (o *OptimizelyClient) getDecisionVariableMap(feature entities.Feature, vari
961965

962966
typedValue, typedError := o.getTypedValue(val, v.Type)
963967
if typedError != nil {
964-
decisionReasons.AddError(decide.GetDecideMessage(decide.VariableValueInvalid, v.Key))
968+
reasons.AddError(decide.GetDecideMessage(decide.VariableValueInvalid, v.Key))
965969
}
966970
valuesMap[v.Key] = typedValue
967971
}
968972

969-
return valuesMap
973+
return valuesMap, reasons
970974
}
971975

972976
func isNil(v interface{}) bool {

pkg/client/client_test.go

Lines changed: 30 additions & 30 deletions
Large diffs are not rendered by default.

pkg/client/fixtures_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,14 @@ type MockDecisionService struct {
117117
mock.Mock
118118
}
119119

120-
func (m *MockDecisionService) GetFeatureDecision(decisionContext decision.FeatureDecisionContext, userContext entities.UserContext, options *decide.Options, reasons decide.DecisionReasons) (decision.FeatureDecision, error) {
121-
args := m.Called(decisionContext, userContext, options, reasons)
122-
return args.Get(0).(decision.FeatureDecision), args.Error(1)
120+
func (m *MockDecisionService) GetFeatureDecision(decisionContext decision.FeatureDecisionContext, userContext entities.UserContext, options *decide.Options) (decision.FeatureDecision, decide.DecisionReasons, error) {
121+
args := m.Called(decisionContext, userContext, options)
122+
return args.Get(0).(decision.FeatureDecision), args.Get(1).(decide.DecisionReasons), args.Error(2)
123123
}
124124

125-
func (m *MockDecisionService) GetExperimentDecision(decisionContext decision.ExperimentDecisionContext, userContext entities.UserContext, options *decide.Options, reasons decide.DecisionReasons) (decision.ExperimentDecision, error) {
126-
args := m.Called(decisionContext, userContext, options, reasons)
127-
return args.Get(0).(decision.ExperimentDecision), args.Error(1)
125+
func (m *MockDecisionService) GetExperimentDecision(decisionContext decision.ExperimentDecisionContext, userContext entities.UserContext, options *decide.Options) (decision.ExperimentDecision, decide.DecisionReasons, error) {
126+
args := m.Called(decisionContext, userContext, options)
127+
return args.Get(0).(decision.ExperimentDecision), args.Get(1).(decide.DecisionReasons), args.Error(2)
128128
}
129129

130130
func (m *MockDecisionService) OnDecision(callback func(note notification.DecisionNotification)) (int, error) {
@@ -160,11 +160,11 @@ func (m *PanickingConfigManager) GetConfig() (config.ProjectConfig, error) {
160160
type PanickingDecisionService struct {
161161
}
162162

163-
func (m *PanickingDecisionService) GetFeatureDecision(decisionContext decision.FeatureDecisionContext, userContext entities.UserContext, options *decide.Options, reasons decide.DecisionReasons) (decision.FeatureDecision, error) {
163+
func (m *PanickingDecisionService) GetFeatureDecision(decisionContext decision.FeatureDecisionContext, userContext entities.UserContext, options *decide.Options) (decision.FeatureDecision, decide.DecisionReasons, error) {
164164
panic("I'm panicking")
165165
}
166166

167-
func (m *PanickingDecisionService) GetExperimentDecision(decisionContext decision.ExperimentDecisionContext, userContext entities.UserContext, options *decide.Options, reasons decide.DecisionReasons) (decision.ExperimentDecision, error) {
167+
func (m *PanickingDecisionService) GetExperimentDecision(decisionContext decision.ExperimentDecisionContext, userContext entities.UserContext, options *decide.Options) (decision.ExperimentDecision, decide.DecisionReasons, error) {
168168
panic("I'm panicking")
169169
}
170170

pkg/decide/decision_reasons.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ package decide
2121
type DecisionReasons interface {
2222
AddError(format string, arguments ...interface{})
2323
AddInfo(format string, arguments ...interface{}) string
24+
Append(reasons DecisionReasons)
2425
ToReport() []string
2526
}

pkg/decide/decision_reasons_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,37 @@ func TestInfoLogsAreOnlyReportedWhenIncludeReasonsOptionIsSet(t *testing.T) {
7575
assert.Equal(t, "info message", reportedReasons[2])
7676
assert.Equal(t, "info message: unexpected string", reportedReasons[3])
7777
}
78+
79+
func TestAppend(t *testing.T) {
80+
options := &Options{
81+
DisableDecisionEvent: true,
82+
EnabledFlagsOnly: true,
83+
IgnoreUserProfileService: true,
84+
ExcludeVariables: true,
85+
IncludeReasons: true,
86+
}
87+
reasons1 := NewDecisionReasons(options)
88+
reasons1.AddError("error message")
89+
reasons1.AddError("error message: code %d", 121)
90+
reasons1.AddInfo("info message")
91+
reasons1.AddInfo("info message: %s", "unexpected string")
92+
93+
// Shouldn't append info logs if include reasons is set to false
94+
reasons2 := NewDecisionReasons(nil)
95+
reasons2.Append(reasons1)
96+
reportedReasons := reasons2.ToReport()
97+
assert.Equal(t, 2, len(reportedReasons))
98+
assert.Equal(t, "error message", reportedReasons[0])
99+
assert.Equal(t, "error message: code 121", reportedReasons[1])
100+
101+
// Should append info logs if include reasons is set to true
102+
options.IncludeReasons = true
103+
reasons2 = NewDecisionReasons(options)
104+
reasons2.Append(reasons1)
105+
reportedReasons = reasons2.ToReport()
106+
assert.Equal(t, 4, len(reportedReasons))
107+
assert.Equal(t, "error message", reportedReasons[0])
108+
assert.Equal(t, "error message: code 121", reportedReasons[1])
109+
assert.Equal(t, "info message", reportedReasons[2])
110+
assert.Equal(t, "info message: unexpected string", reportedReasons[3])
111+
}

pkg/decide/default_decision_reasons.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ type DefaultDecisionReasons struct {
2929

3030
// NewDecisionReasons returns a new instance of DecisionReasons.
3131
func NewDecisionReasons(options *Options) *DefaultDecisionReasons {
32+
includeReasons := false
33+
if options != nil {
34+
includeReasons = options.IncludeReasons
35+
}
3236
return &DefaultDecisionReasons{
3337
errors: []string{},
3438
logs: []string{},
35-
includeReasons: options.IncludeReasons,
39+
includeReasons: includeReasons,
3640
}
3741
}
3842

@@ -51,6 +55,16 @@ func (o *DefaultDecisionReasons) AddInfo(format string, arguments ...interface{}
5155
return message
5256
}
5357

58+
// Append appends given reasons.
59+
func (o *DefaultDecisionReasons) Append(reasons DecisionReasons) {
60+
if decisionReasons, ok := reasons.(*DefaultDecisionReasons); ok {
61+
o.errors = append(o.errors, decisionReasons.errors...)
62+
if o.includeReasons {
63+
o.logs = append(o.logs, decisionReasons.logs...)
64+
}
65+
}
66+
}
67+
5468
// ToReport returns reasons to be reported.
5569
func (o *DefaultDecisionReasons) ToReport() []string {
5670
reasons := o.errors

pkg/decision/composite_experiment_service.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,20 @@ func NewCompositeExperimentService(sdkKey string, options ...CESOptionFunc) *Com
8383
}
8484

8585
// GetDecision returns a decision for the given experiment and user context
86-
func (s CompositeExperimentService) GetDecision(decisionContext ExperimentDecisionContext, userContext entities.UserContext, options *decide.Options, reasons decide.DecisionReasons) (decision ExperimentDecision, err error) {
86+
func (s CompositeExperimentService) GetDecision(decisionContext ExperimentDecisionContext, userContext entities.UserContext, options *decide.Options) (decision ExperimentDecision, reasons decide.DecisionReasons, err error) {
8787
// Run through the various decision services until we get a decision
88+
reasons = decide.NewDecisionReasons(options)
8889
for _, experimentService := range s.experimentServices {
89-
decision, err = experimentService.GetDecision(decisionContext, userContext, options, reasons)
90+
var decisionReasons decide.DecisionReasons
91+
decision, decisionReasons, err = experimentService.GetDecision(decisionContext, userContext, options)
92+
reasons.Append(decisionReasons)
9093
if err != nil {
9194
s.logger.Debug(fmt.Sprintf("%v", err))
9295
}
9396
if decision.Variation != nil && err == nil {
94-
return decision, err
97+
return decision, reasons, err
9598
}
9699
}
97100

98-
return decision, err
101+
return decision, reasons, err
99102
}

pkg/decision/composite_experiment_service_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ func (s *CompositeExperimentTestSuite) TestGetDecision() {
6161
expectedExperimentDecision := ExperimentDecision{
6262
Variation: &expectedVariation,
6363
}
64-
s.mockExperimentService.On("GetDecision", s.testDecisionContext, testUserContext, s.options, s.reasons).Return(expectedExperimentDecision, nil)
64+
s.mockExperimentService.On("GetDecision", s.testDecisionContext, testUserContext, s.options).Return(expectedExperimentDecision, s.reasons, nil)
6565

6666
compositeExperimentService := &CompositeExperimentService{
6767
experimentServices: []ExperimentService{s.mockExperimentService, s.mockExperimentService2},
6868
logger: logging.GetLogger("sdkKey", "ExperimentService"),
6969
}
70-
decision, err := compositeExperimentService.GetDecision(s.testDecisionContext, testUserContext, s.options, s.reasons)
70+
decision, _, err := compositeExperimentService.GetDecision(s.testDecisionContext, testUserContext, s.options)
7171
s.Equal(expectedExperimentDecision, decision)
7272
s.NoError(err)
7373
s.mockExperimentService.AssertExpectations(s.T())
@@ -83,18 +83,18 @@ func (s *CompositeExperimentTestSuite) TestGetDecisionFallthrough() {
8383

8484
expectedVariation := testExp1111.Variations["2222"]
8585
expectedExperimentDecision := ExperimentDecision{}
86-
s.mockExperimentService.On("GetDecision", s.testDecisionContext, testUserContext, s.options, s.reasons).Return(expectedExperimentDecision, nil)
86+
s.mockExperimentService.On("GetDecision", s.testDecisionContext, testUserContext, s.options).Return(expectedExperimentDecision, s.reasons, nil)
8787

8888
expectedExperimentDecision2 := ExperimentDecision{
8989
Variation: &expectedVariation,
9090
}
91-
s.mockExperimentService2.On("GetDecision", s.testDecisionContext, testUserContext, s.options, s.reasons).Return(expectedExperimentDecision2, nil)
91+
s.mockExperimentService2.On("GetDecision", s.testDecisionContext, testUserContext, s.options).Return(expectedExperimentDecision2, s.reasons, nil)
9292

9393
compositeExperimentService := &CompositeExperimentService{
9494
experimentServices: []ExperimentService{s.mockExperimentService, s.mockExperimentService2},
9595
logger: logging.GetLogger("sdkKey", "CompositeExperimentService"),
9696
}
97-
decision, err := compositeExperimentService.GetDecision(s.testDecisionContext, testUserContext, s.options, s.reasons)
97+
decision, _, err := compositeExperimentService.GetDecision(s.testDecisionContext, testUserContext, s.options)
9898

9999
s.NoError(err)
100100
s.Equal(expectedExperimentDecision2, decision)
@@ -108,16 +108,16 @@ func (s *CompositeExperimentTestSuite) TestGetDecisionNoDecisionsMade() {
108108
ID: "test_user_1",
109109
}
110110
expectedExperimentDecision := ExperimentDecision{}
111-
s.mockExperimentService.On("GetDecision", s.testDecisionContext, testUserContext, s.options, s.reasons).Return(expectedExperimentDecision, nil)
111+
s.mockExperimentService.On("GetDecision", s.testDecisionContext, testUserContext, s.options).Return(expectedExperimentDecision, s.reasons, nil)
112112

113113
expectedExperimentDecision2 := ExperimentDecision{}
114-
s.mockExperimentService2.On("GetDecision", s.testDecisionContext, testUserContext, s.options, s.reasons).Return(expectedExperimentDecision2, nil)
114+
s.mockExperimentService2.On("GetDecision", s.testDecisionContext, testUserContext, s.options).Return(expectedExperimentDecision2, s.reasons, nil)
115115

116116
compositeExperimentService := &CompositeExperimentService{
117117
experimentServices: []ExperimentService{s.mockExperimentService, s.mockExperimentService2},
118118
logger: logging.GetLogger("sdkKey", "CompositeExperimentService"),
119119
}
120-
decision, err := compositeExperimentService.GetDecision(s.testDecisionContext, testUserContext, s.options, s.reasons)
120+
decision, _, err := compositeExperimentService.GetDecision(s.testDecisionContext, testUserContext, s.options)
121121

122122
s.NoError(err)
123123
s.Equal(expectedExperimentDecision2, decision)
@@ -139,12 +139,12 @@ func (s *CompositeExperimentTestSuite) TestGetDecisionReturnsError() {
139139
shouldBeIgnoredDecision := ExperimentDecision{
140140
Variation: &testExp1114Var2225,
141141
}
142-
s.mockExperimentService.On("GetDecision", testDecisionContext, testUserContext, s.options, s.reasons).Return(shouldBeIgnoredDecision, errors.New("Error making decision"))
142+
s.mockExperimentService.On("GetDecision", testDecisionContext, testUserContext, s.options).Return(shouldBeIgnoredDecision, s.reasons, errors.New("Error making decision"))
143143

144144
expectedDecision := ExperimentDecision{
145145
Variation: &testExp1114Var2226,
146146
}
147-
s.mockExperimentService2.On("GetDecision", testDecisionContext, testUserContext, s.options, s.reasons).Return(expectedDecision, nil)
147+
s.mockExperimentService2.On("GetDecision", testDecisionContext, testUserContext, s.options).Return(expectedDecision, s.reasons, nil)
148148

149149
compositeExperimentService := &CompositeExperimentService{
150150
experimentServices: []ExperimentService{
@@ -153,7 +153,7 @@ func (s *CompositeExperimentTestSuite) TestGetDecisionReturnsError() {
153153
},
154154
logger: logging.GetLogger("sdkKey", "CompositeExperimentService"),
155155
}
156-
decision, err := compositeExperimentService.GetDecision(testDecisionContext, testUserContext, s.options, s.reasons)
156+
decision, _, err := compositeExperimentService.GetDecision(testDecisionContext, testUserContext, s.options)
157157
s.Equal(expectedDecision, decision)
158158
s.NoError(err)
159159
s.mockExperimentService.AssertExpectations(s.T())

pkg/decision/composite_feature_service.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,21 @@ func NewCompositeFeatureService(sdkKey string, compositeExperimentService Experi
4343
}
4444

4545
// GetDecision returns a decision for the given feature and user context
46-
func (f CompositeFeatureService) GetDecision(decisionContext FeatureDecisionContext, userContext entities.UserContext, options *decide.Options, reasons decide.DecisionReasons) (FeatureDecision, error) {
46+
func (f CompositeFeatureService) GetDecision(decisionContext FeatureDecisionContext, userContext entities.UserContext, options *decide.Options) (FeatureDecision, decide.DecisionReasons, error) {
4747
var featureDecision = FeatureDecision{}
48+
reasons := decide.NewDecisionReasons(options)
4849
var err error
4950
for _, featureDecisionService := range f.featureServices {
50-
featureDecision, err = featureDecisionService.GetDecision(decisionContext, userContext, options, reasons)
51+
var decisionReasons decide.DecisionReasons
52+
featureDecision, decisionReasons, err = featureDecisionService.GetDecision(decisionContext, userContext, options)
53+
reasons.Append(decisionReasons)
5154
if err != nil {
5255
f.logger.Debug(fmt.Sprintf("%v", err))
5356
}
5457

5558
if featureDecision.Variation != nil && err == nil {
56-
return featureDecision, err
59+
return featureDecision, reasons, err
5760
}
5861
}
59-
return featureDecision, err
62+
return featureDecision, reasons, err
6063
}

0 commit comments

Comments
 (0)