Skip to content

Commit f5acd50

Browse files
author
Michael Ng
authored
refac(decision): Use entities object reference and added helpers file (#42)
1 parent 896f726 commit f5acd50

16 files changed

+142
-140
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.cover
2+
coverage.html

optimizely/client/client.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,13 @@ func (o *OptimizelyClient) IsFeatureEnabled(featureKey string, userContext entit
4444
}
4545

4646
projectConfig := o.configManager.GetConfig()
47+
feature, err := projectConfig.GetFeatureByKey(featureKey)
48+
if err != nil {
49+
logger.Error("Error retrieving feature", err)
50+
return false, err
51+
}
4752
featureDecisionContext := decision.FeatureDecisionContext{
48-
FeatureKey: featureKey,
53+
Feature: &feature,
4954
ProjectConfig: projectConfig,
5055
}
5156

optimizely/client/client_test.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,19 @@ func TestIsFeatureEnabled(t *testing.T) {
6868
Variations: map[string]entities.Variation{"22222": testVariation},
6969
}
7070
testFeatureKey := "test_feature_key"
71-
71+
testFeature := entities.Feature{
72+
ID: "22222",
73+
Key: testFeatureKey,
74+
FeatureExperiments: []entities.Experiment{testExperiment},
75+
}
7276
// Test happy path
7377
mockConfig := new(MockProjectConfig)
78+
mockConfig.On("GetFeatureByKey", testFeatureKey).Return(testFeature, nil)
7479
mockConfigManager := new(MockProjectConfigManager)
7580
mockConfigManager.On("GetConfig").Return(mockConfig)
76-
7781
// Set up the mock decision service and its return value
7882
testDecisionContext := decision.FeatureDecisionContext{
79-
FeatureKey: testFeatureKey,
83+
Feature: &testFeature,
8084
ProjectConfig: mockConfig,
8185
}
8286

@@ -121,19 +125,14 @@ func TestIsFeatureEnabledErrorCases(t *testing.T) {
121125
mockConfigManager.AssertNotCalled(t, "GetFeatureByKey")
122126
mockDecisionService.AssertNotCalled(t, "GetFeatureDecision")
123127

124-
// Test decision serviceinvalid feature key
128+
// Test invalid feature key
125129
expectedError := errors.New("Invalid feature key")
126130
mockConfig := new(MockProjectConfig)
131+
mockConfig.On("GetFeatureByKey", testFeatureKey).Return(entities.Feature{}, expectedError)
127132

128133
mockConfigManager = new(MockProjectConfigManager)
129134
mockConfigManager.On("GetConfig").Return(mockConfig)
130-
131-
testFeatureDecisionContext := decision.FeatureDecisionContext{
132-
FeatureKey: testFeatureKey,
133-
ProjectConfig: mockConfig,
134-
}
135135
mockDecisionService = new(MockDecisionService)
136-
mockDecisionService.On("GetFeatureDecision", testFeatureDecisionContext, testUserContext).Return(decision.FeatureDecision{}, expectedError)
137136
client = OptimizelyClient{
138137
configManager: mockConfigManager,
139138
decisionService: mockDecisionService,
@@ -145,5 +144,5 @@ func TestIsFeatureEnabledErrorCases(t *testing.T) {
145144
}
146145
assert.False(t, result)
147146
mockConfigManager.AssertExpectations(t)
148-
mockDecisionService.AssertExpectations(t)
147+
mockDecisionService.AssertNotCalled(t, "GetDecision")
149148
}

optimizely/config/datafileProjectConfig/entities/entities.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type Variation struct {
5959
FeatureEnabled bool `json:"featureEnabled"`
6060
}
6161

62+
// Event represents an event from the Optimizely datafile
6263
type Event struct {
6364
ID string `json:"id"`
6465
Key string `json:"key"`

optimizely/decision/composite_experiment_service.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,6 @@ func NewCompositeExperimentService() *CompositeExperimentService {
4242

4343
// GetDecision returns a decision for the given experiment and user context
4444
func (s CompositeExperimentService) GetDecision(decisionContext ExperimentDecisionContext, userContext entities.UserContext) (ExperimentDecision, error) {
45-
_, err := decisionContext.ProjectConfig.GetExperimentByKey(decisionContext.ExperimentKey)
46-
if err != nil {
47-
return ExperimentDecision{}, err
48-
}
49-
5045
for _, experimentService := range s.experimentDecisionServices {
5146
decision, err := experimentService.GetDecision(decisionContext, userContext)
5247
if decision.DecisionMade == true {

optimizely/decision/composite_experiment_service_test.go

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,34 +22,12 @@ import (
2222
"github.com/stretchr/testify/assert"
2323

2424
"github.com/optimizely/go-sdk/optimizely/entities"
25-
"github.com/stretchr/testify/mock"
2625
)
2726

28-
type MockExperimentDecisionService struct {
29-
mock.Mock
30-
}
31-
32-
func (m *MockExperimentDecisionService) GetDecision(decisionContext ExperimentDecisionContext, userContext entities.UserContext) (ExperimentDecision, error) {
33-
args := m.Called(decisionContext, userContext)
34-
return args.Get(0).(ExperimentDecision), args.Error(1)
35-
}
36-
3727
func TestCompositeExperimentServiceGetDecision(t *testing.T) {
38-
testExperimentKey := "test_experiment"
39-
testExperiment := entities.Experiment{
40-
ID: "111111",
41-
Key: testExperimentKey,
42-
Variations: map[string]entities.Variation{
43-
"22222": entities.Variation{
44-
ID: "22222",
45-
Key: "22222",
46-
},
47-
},
48-
}
49-
mockProjectConfig := new(MockProjectConfig)
50-
mockProjectConfig.On("GetExperimentByKey", testExperimentKey).Return(testExperiment, nil)
28+
mockProjectConfig := new(mockProjectConfig)
5129
testDecisionContext := ExperimentDecisionContext{
52-
ExperimentKey: testExperimentKey,
30+
Experiment: &testExp1111,
5331
ProjectConfig: mockProjectConfig,
5432
}
5533

@@ -58,7 +36,7 @@ func TestCompositeExperimentServiceGetDecision(t *testing.T) {
5836
}
5937

6038
expectedExperimentDecision := ExperimentDecision{
61-
Variation: testExperiment.Variations["22222"],
39+
Variation: testExp1111.Variations["2222"],
6240
Decision: Decision{
6341
DecisionMade: true,
6442
},
@@ -92,7 +70,7 @@ func TestCompositeExperimentServiceGetDecision(t *testing.T) {
9270

9371
mockExperimentDecisionService2 = new(MockExperimentDecisionService)
9472
expectedExperimentDecision2 := ExperimentDecision{
95-
Variation: testExperiment.Variations["22222"],
73+
Variation: testExp1111.Variations["2222"],
9674
Decision: Decision{
9775
DecisionMade: true,
9876
},

optimizely/decision/composite_feature_service.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,13 @@ func NewCompositeFeatureService(experimentDecisionService ExperimentDecisionServ
3939
// GetDecision returns a decision for the given feature and user context
4040
func (featureService CompositeFeatureService) GetDecision(decisionContext FeatureDecisionContext, userContext entities.UserContext) (FeatureDecision, error) {
4141
featureDecision := FeatureDecision{}
42-
feature, err := decisionContext.ProjectConfig.GetFeatureByKey(decisionContext.FeatureKey)
43-
if err != nil {
44-
return featureDecision, err
45-
}
42+
feature := decisionContext.Feature
4643

4744
// Check if user is bucketed in feature experiment
4845
// @TODO: add in a feature decision service that takes into account multiple experiments (via group mutex)
4946
experiment := feature.FeatureExperiments[0]
5047
experimentDecisionContext := ExperimentDecisionContext{
51-
ExperimentKey: experiment.Key,
48+
Experiment: &experiment,
5249
ProjectConfig: decisionContext.ProjectConfig,
5350
}
5451

optimizely/decision/composite_service_test.go

Lines changed: 5 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -21,58 +21,14 @@ import (
2121

2222
"github.com/stretchr/testify/assert"
2323

24-
"github.com/stretchr/testify/mock"
25-
26-
"github.com/optimizely/go-sdk/optimizely"
2724
"github.com/optimizely/go-sdk/optimizely/entities"
2825
)
2926

30-
type MockProjectConfig struct {
31-
optimizely.ProjectConfig
32-
mock.Mock
33-
}
34-
35-
func (c *MockProjectConfig) GetFeatureByKey(featureKey string) (entities.Feature, error) {
36-
args := c.Called(featureKey)
37-
return args.Get(0).(entities.Feature), args.Error(1)
38-
}
39-
40-
func (c *MockProjectConfig) GetExperimentByKey(experimentKey string) (entities.Experiment, error) {
41-
args := c.Called(experimentKey)
42-
return args.Get(0).(entities.Experiment), args.Error(1)
43-
}
44-
45-
func (c *MockProjectConfig) GetAudienceByID(audienceID string) (entities.Audience, error) {
46-
args := c.Called(audienceID)
47-
return args.Get(0).(entities.Audience), args.Error(1)
48-
}
49-
50-
type MockFeatureDecisionService struct {
51-
mock.Mock
52-
}
53-
54-
func (m *MockFeatureDecisionService) GetDecision(decisionContext FeatureDecisionContext, userContext entities.UserContext) (FeatureDecision, error) {
55-
args := m.Called(decisionContext, userContext)
56-
return args.Get(0).(FeatureDecision), args.Error(1)
57-
}
58-
5927
func TestGetFeatureDecision(t *testing.T) {
60-
testFeatureKey := "my_test_feature"
61-
testVariation := entities.Variation{
62-
ID: "11111",
63-
FeatureEnabled: true,
64-
}
65-
testExperiment := entities.Experiment{
66-
Variations: map[string]entities.Variation{"11111": testVariation},
67-
}
68-
testFeature := entities.Feature{
69-
Key: testFeatureKey,
70-
FeatureExperiments: []entities.Experiment{testExperiment},
71-
}
72-
mockProjectConfig := new(MockProjectConfig)
73-
mockProjectConfig.On("GetFeatureByKey", testFeatureKey).Return(testFeature, nil)
28+
mockProjectConfig := new(mockProjectConfig)
29+
mockProjectConfig.On("GetFeatureByKey", testFeat3333Key).Return(testFeat3333, nil)
7430
decisionContext := FeatureDecisionContext{
75-
FeatureKey: testFeatureKey,
31+
Feature: &testFeat3333,
7632
ProjectConfig: mockProjectConfig,
7733
}
7834

@@ -81,8 +37,8 @@ func TestGetFeatureDecision(t *testing.T) {
8137
}
8238

8339
expectedFeatureDecision := FeatureDecision{
84-
Experiment: testExperiment,
85-
Variation: testVariation,
40+
Experiment: testExp1111,
41+
Variation: testExp1111Var2222,
8642
Decision: Decision{DecisionMade: true},
8743
}
8844

optimizely/decision/entities.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ import (
2323

2424
// ExperimentDecisionContext contains the information needed to be able to make a decision for a given experiment
2525
type ExperimentDecisionContext struct {
26-
ExperimentKey string
26+
Experiment *entities.Experiment
2727
ProjectConfig optimizely.ProjectConfig
2828
}
2929

3030
// FeatureDecisionContext contains the information needed to be able to make a decision for a given feature
3131
type FeatureDecisionContext struct {
32-
FeatureKey string
32+
Feature *entities.Feature
3333
ProjectConfig optimizely.ProjectConfig
3434
}
3535

optimizely/decision/experiment_bucketer_service.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func NewExperimentBucketerService() *ExperimentBucketerService {
4343
// GetDecision returns the decision with the variation the user is bucketed into
4444
func (s ExperimentBucketerService) GetDecision(decisionContext ExperimentDecisionContext, userContext entities.UserContext) (ExperimentDecision, error) {
4545
experimentDecision := ExperimentDecision{}
46-
experiment, _ := decisionContext.ProjectConfig.GetExperimentByKey(decisionContext.ExperimentKey)
46+
experiment := decisionContext.Experiment
4747
var group entities.Group
4848
if experiment.GroupID != "" {
4949
// @TODO: figure out what to do if group is not found
@@ -56,7 +56,7 @@ func (s ExperimentBucketerService) GetDecision(decisionContext ExperimentDecisio
5656
} else {
5757
bLogger.Debug(fmt.Sprintf(`Using bucketing ID: "%s"`, bucketingID))
5858
}
59-
variation := s.bucketer.Bucket(bucketingID, experiment, group)
59+
variation := s.bucketer.Bucket(bucketingID, *experiment, group)
6060
experimentDecision.DecisionMade = true
6161
experimentDecision.Variation = variation
6262
return experimentDecision, nil

0 commit comments

Comments
 (0)