Skip to content

Commit 540f3f3

Browse files
author
Michael Ng
authored
feat(config): Parse and map rollouts from the datafile. (#44)
* feat(config): Parse and map rollouts from the datafile. * fix: Remove references to variables.
1 parent ee2ea26 commit 540f3f3

File tree

11 files changed

+170
-54
lines changed

11 files changed

+170
-54
lines changed

optimizely/client/factory.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
package client
1818

1919
import (
20+
"fmt"
2021

2122
"github.com/optimizely/go-sdk/optimizely"
22-
"fmt"
2323
"github.com/optimizely/go-sdk/optimizely/config"
2424
"github.com/optimizely/go-sdk/optimizely/decision"
2525
)

optimizely/config/datafileProjectConfig/config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type DatafileProjectConfig struct {
4141
groupMap map[string]entities.Group
4242
projectID string
4343
revision string
44+
rolloutMap map[string]entities.Rollout
4445
}
4546

4647
func (c DatafileProjectConfig) GetProjectID() string {
@@ -76,10 +77,13 @@ func NewDatafileProjectConfig(jsonDatafile []byte) (*DatafileProjectConfig, erro
7677
}
7778

7879
experiments, experimentKeyMap := mappers.MapExperiments(datafile.Experiments)
80+
rolloutMap := mappers.MapRollouts(datafile.Rollouts)
7981
config := &DatafileProjectConfig{
8082
audienceMap: mappers.MapAudiences(datafile.Audiences),
8183
experimentMap: experiments,
8284
experimentKeyToIDMap: experimentKeyMap,
85+
rolloutMap: rolloutMap,
86+
featureMap: mappers.MapFeatureFlags(datafile.FeatureFlags, rolloutMap),
8387
}
8488

8589
logger.Info("Datafile is valid.")

optimizely/config/datafileProjectConfig/entities/entities.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,25 @@ type Event struct {
6666
ExperimentIds []string `json:"experimentIds"`
6767
}
6868

69+
// Rollout represents a rollout from the Optimizely datafile
70+
type Rollout struct {
71+
ID string `json:"id"`
72+
Experiments []Experiment `json:"experiments"`
73+
}
74+
6975
// Datafile represents the datafile we get from Optimizely
7076
type Datafile struct {
71-
AccountID string `json:"accountId"`
72-
AnonymizeIP bool `json:"anonymizeIP"`
73-
Audiences []Audience `json:"audiences"`
74-
BotFiltering bool `json:"botFiltering"`
75-
Experiments []Experiment `json:"experiments"`
76-
FeatureFlags []FeatureFlag `json:"featureFlags"`
77-
Events []Event `json:"events"`
78-
ProjectID string `json:"projectId"`
79-
Revision string `json:"revision"`
80-
Variables []string `json:"variables"`
81-
Version string `json:"version"`
77+
AccountID string `json:"accountId"`
78+
AnonymizeIP bool `json:"anonymizeIP"`
79+
Audiences []Audience `json:"audiences"`
80+
BotFiltering bool `json:"botFiltering"`
81+
Experiments []Experiment `json:"experiments"`
82+
FeatureFlags []FeatureFlag `json:"featureFlags"`
83+
Events []Event `json:"events"`
84+
ProjectID string `json:"projectId"`
85+
Revision string `json:"revision"`
86+
Rollouts []Rollout `json:"rollouts"`
87+
TypedAudiences []Audience `json:"typedAudiences"`
88+
Variables []string `json:"variables"`
89+
Version string `json:"version"`
8290
}

optimizely/config/datafileProjectConfig/mappers/experiment.go

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,8 @@ func MapExperiments(rawExperiments []datafileEntities.Experiment) (map[string]en
2727
experimentMap := make(map[string]entities.Experiment)
2828
experimentKeyMap := make(map[string]string)
2929
for _, rawExperiment := range rawExperiments {
30-
audienceConditionTree, err := buildAudienceConditionTree(rawExperiment.AudienceConditions)
31-
if err != nil {
32-
// @TODO: handle error
33-
}
34-
35-
experiment := entities.Experiment{
36-
AudienceIds: rawExperiment.AudienceIds,
37-
ID: rawExperiment.ID,
38-
Key: rawExperiment.Key,
39-
TrafficAllocation: make([]entities.Range, len(rawExperiment.TrafficAllocation)),
40-
Variations: make(map[string]entities.Variation),
41-
AudienceConditionTree: audienceConditionTree,
42-
}
43-
44-
for _, variation := range rawExperiment.Variations {
45-
experiment.Variations[variation.ID] = mapVariation(variation)
46-
}
47-
48-
for i, allocation := range rawExperiment.TrafficAllocation {
49-
experiment.TrafficAllocation[i] = entities.Range(allocation)
50-
}
5130

31+
experiment := mapExperiment(rawExperiment)
5232
experimentMap[experiment.ID] = experiment
5333
experimentKeyMap[experiment.Key] = experiment.ID
5434
}
@@ -66,3 +46,30 @@ func mapVariation(rawVariation datafileEntities.Variation) entities.Variation {
6646
}
6747
return variation
6848
}
49+
50+
// Maps the raw experiment entity from the datafile into an SDK Experiment entity
51+
func mapExperiment(rawExperiment datafileEntities.Experiment) entities.Experiment {
52+
audienceConditionTree, err := buildAudienceConditionTree(rawExperiment.AudienceConditions)
53+
if err != nil {
54+
// @TODO: handle error
55+
}
56+
57+
experiment := entities.Experiment{
58+
AudienceIds: rawExperiment.AudienceIds,
59+
ID: rawExperiment.ID,
60+
Key: rawExperiment.Key,
61+
TrafficAllocation: make([]entities.Range, len(rawExperiment.TrafficAllocation)),
62+
Variations: make(map[string]entities.Variation),
63+
AudienceConditionTree: audienceConditionTree,
64+
}
65+
66+
for _, variation := range rawExperiment.Variations {
67+
experiment.Variations[variation.ID] = mapVariation(variation)
68+
}
69+
70+
for i, allocation := range rawExperiment.TrafficAllocation {
71+
experiment.TrafficAllocation[i] = entities.Range(allocation)
72+
}
73+
74+
return experiment
75+
}

optimizely/config/datafileProjectConfig/mappers/feature.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,20 @@ import (
2121
"github.com/optimizely/go-sdk/optimizely/entities"
2222
)
2323

24-
// MapFeatureFlags maps the raw datafile feature flag entitiees to SDK Feature entities
25-
func MapFeatureFlags(featureFlags []datafileEntities.FeatureFlag) map[string]entities.Feature {
24+
// MapFeatureFlags maps the raw datafile feature flag entities to SDK Feature entities
25+
func MapFeatureFlags(featureFlags []datafileEntities.FeatureFlag, rolloutMap map[string]entities.Rollout) map[string]entities.Feature {
2626

2727
featureMap := make(map[string]entities.Feature)
2828
for _, featureFlag := range featureFlags {
2929
// @TODO(mng): include experiments in the Feature
30-
featureMap[featureFlag.Key] = entities.Feature{
30+
feature := entities.Feature{
3131
Key: featureFlag.Key,
3232
ID: featureFlag.ID,
3333
}
34+
if rollout, ok := rolloutMap[featureFlag.RolloutID]; ok {
35+
feature.Rollout = rollout
36+
}
37+
featureMap[featureFlag.Key] = feature
3438
}
3539
return featureMap
3640
}

optimizely/config/datafileProjectConfig/mappers/feature_test.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package mappers
1818

1919
import (
2020
"encoding/json"
21-
"fmt"
2221
"testing"
2322

2423
datafileEntities "github.com/optimizely/go-sdk/optimizely/config/datafileProjectConfig/entities"
@@ -29,19 +28,24 @@ import (
2928
func TestMapFeatures(t *testing.T) {
3029
const testFeatureFlagString = `{
3130
"id": "21111",
32-
"key": "test_feature_21111"
31+
"key": "test_feature_21111",
32+
"rolloutId": "41111"
3333
}`
3434

3535
var rawFeatureFlag datafileEntities.FeatureFlag
3636
json.Unmarshal([]byte(testFeatureFlagString), &rawFeatureFlag)
3737

38-
fmt.Printf("FLAG: %+v", rawFeatureFlag)
3938
rawFeatureFlags := []datafileEntities.FeatureFlag{rawFeatureFlag}
40-
featureMap := MapFeatureFlags(rawFeatureFlags)
39+
rollout := entities.Rollout{ID: "41111"}
40+
rolloutMap := map[string]entities.Rollout{
41+
"41111": rollout,
42+
}
43+
featureMap := MapFeatureFlags(rawFeatureFlags, rolloutMap)
4144
expectedFeatureMap := map[string]entities.Feature{
4245
"test_feature_21111": entities.Feature{
43-
ID: "21111",
44-
Key: "test_feature_21111",
46+
ID: "21111",
47+
Key: "test_feature_21111",
48+
Rollout: rollout,
4549
},
4650
}
4751

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package mappers
18+
19+
import (
20+
datafileEntities "github.com/optimizely/go-sdk/optimizely/config/datafileProjectConfig/entities"
21+
"github.com/optimizely/go-sdk/optimizely/entities"
22+
)
23+
24+
// MapRollouts maps the raw datafile rollout entities to SDK Rollout entities
25+
func MapRollouts(rollouts []datafileEntities.Rollout) map[string]entities.Rollout {
26+
rolloutMap := make(map[string]entities.Rollout)
27+
for _, rollout := range rollouts {
28+
rolloutMap[rollout.ID] = mapRollout(rollout)
29+
}
30+
31+
return rolloutMap
32+
}
33+
34+
func mapRollout(datafileRollout datafileEntities.Rollout) entities.Rollout {
35+
rolloutExperiments := make([]entities.Experiment, len(datafileRollout.Experiments))
36+
for i, datafileExperiment := range datafileRollout.Experiments {
37+
experiment := mapExperiment(datafileExperiment)
38+
rolloutExperiments[i] = experiment
39+
}
40+
41+
return entities.Rollout{
42+
ID: datafileRollout.ID,
43+
Experiments: rolloutExperiments,
44+
}
45+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package mappers
18+
19+
import (
20+
"encoding/json"
21+
"testing"
22+
23+
datafileEntities "github.com/optimizely/go-sdk/optimizely/config/datafileProjectConfig/entities"
24+
"github.com/optimizely/go-sdk/optimizely/entities"
25+
"github.com/stretchr/testify/assert"
26+
)
27+
28+
func TestMapRollouts(t *testing.T) {
29+
const testRolloutString = `{
30+
"id": "21111",
31+
"experiments": [
32+
{ "id": "11111", "key": "exp_11111" },
33+
{ "id": "11112", "key": "exp_11112" }
34+
]
35+
}`
36+
37+
var rawRollout datafileEntities.Rollout
38+
json.Unmarshal([]byte(testRolloutString), &rawRollout)
39+
40+
rawRollouts := []datafileEntities.Rollout{rawRollout}
41+
rolloutMap := MapRollouts(rawRollouts)
42+
expectedRolloutMap := map[string]entities.Rollout{
43+
"21111": entities.Rollout{
44+
ID: "21111",
45+
Experiments: []entities.Experiment{
46+
entities.Experiment{ID: "11111", Key: "exp_11111", Variations: map[string]entities.Variation{}, TrafficAllocation: []entities.Range{}},
47+
entities.Experiment{ID: "11112", Key: "exp_11112", Variations: map[string]entities.Variation{}, TrafficAllocation: []entities.Range{}},
48+
},
49+
},
50+
}
51+
52+
assert.Equal(t, expectedRolloutMap, rolloutMap)
53+
}

optimizely/entities/event.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package entities
22

3+
// Event represents a conversion event
34
type Event struct {
4-
ID string `json:"id"`
5-
Key string `json:"key"`
5+
ID string `json:"id"`
6+
Key string `json:"key"`
67
ExperimentIds []string `json:"experimentIds"`
78
}
8-

optimizely/entities/experiment.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ type Variation struct {
2121
ID string
2222
Key string
2323
FeatureEnabled bool
24-
Variables map[string]FeatureVariable
2524
}
2625

2726
// Experiment represents an experiment

0 commit comments

Comments
 (0)