Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions pkg/config/datafileprojectconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,20 @@ var datafileVersions = map[string]struct{}{
type DatafileProjectConfig struct {
datafile string
accountID string
attributes []entities.Attribute
projectID string
revision string
experimentKeyToIDMap map[string]string
audiences []entities.Audience
audienceMap map[string]entities.Audience
attributeMap map[string]entities.Attribute
events []entities.Event
eventMap map[string]entities.Event
attributeKeyToIDMap map[string]string
experimentMap map[string]entities.Experiment
featureMap map[string]entities.Feature
groupMap map[string]entities.Group
rollouts []entities.Rollout
rolloutMap map[string]entities.Rollout
anonymizeIP bool
botFiltering bool
Expand Down Expand Up @@ -77,6 +81,11 @@ func (c DatafileProjectConfig) GetAnonymizeIP() bool {
return c.anonymizeIP
}

// GetAttributes returns attributes
func (c DatafileProjectConfig) GetAttributes() []entities.Attribute {
return c.attributes
}

// GetAttributeID returns attributeID
func (c DatafileProjectConfig) GetAttributeID(key string) string {
return c.attributeKeyToIDMap[key]
Expand All @@ -97,6 +106,11 @@ func (c DatafileProjectConfig) GetEnvironmentKey() string {
return c.environmentKey
}

// GetEvents returns all events
func (c DatafileProjectConfig) GetEvents() []entities.Event {
return c.events
}

// GetEventByKey returns the event with the given key
func (c DatafileProjectConfig) GetEventByKey(eventKey string) (entities.Event, error) {
if event, ok := c.eventMap[eventKey]; ok {
Expand Down Expand Up @@ -157,6 +171,16 @@ func (c DatafileProjectConfig) GetExperimentList() (experimentList []entities.Ex
return experimentList
}

// GetRolloutList returns an array of all the rollouts
func (c DatafileProjectConfig) GetRolloutList() (rolloutList []entities.Rollout) {
return c.rollouts
}

// GetAudienceList returns an array of all the audiences
func (c DatafileProjectConfig) GetAudienceList() (audienceList []entities.Audience) {
return c.audiences
}

// GetAudienceByID returns the audience with the given ID
func (c DatafileProjectConfig) GetAudienceByID(audienceID string) (entities.Audience, error) {
if audience, ok := c.audienceMap[audienceID]; ok {
Expand Down Expand Up @@ -210,32 +234,38 @@ func NewDatafileProjectConfig(jsonDatafile []byte, logger logging.OptimizelyLogP
return nil, err
}

attributeMap, attributeKeyToIDMap := mappers.MapAttributes(datafile.Attributes)
attributes, attributeMap, attributeKeyToIDMap := mappers.MapAttributes(datafile.Attributes)
allExperiments := mappers.MergeExperiments(datafile.Experiments, datafile.Groups)
groupMap, experimentGroupMap := mappers.MapGroups(datafile.Groups)
experimentMap, experimentKeyMap := mappers.MapExperiments(allExperiments, experimentGroupMap)

rolloutMap := mappers.MapRollouts(datafile.Rollouts)
eventMap := mappers.MapEvents(datafile.Events)
rollouts, rolloutMap := mappers.MapRollouts(datafile.Rollouts)
events, eventMap := mappers.MapEvents(datafile.Events)
mergedAudiences := append(datafile.TypedAudiences, datafile.Audiences...)
featureMap := mappers.MapFeatures(datafile.FeatureFlags, rolloutMap, experimentMap)
audiences, audienceMap := mappers.MapAudiences(mergedAudiences)

config := &DatafileProjectConfig{
datafile: string(jsonDatafile),
accountID: datafile.AccountID,
attributes: attributes,
anonymizeIP: datafile.AnonymizeIP,
attributeKeyToIDMap: attributeKeyToIDMap,
audienceMap: mappers.MapAudiences(mergedAudiences),
audiences: audiences,
audienceMap: audienceMap,
attributeMap: attributeMap,
botFiltering: datafile.BotFiltering,
sdkKey: datafile.SDKKey,
environmentKey: datafile.EnvironmentKey,
experimentKeyToIDMap: experimentKeyMap,
experimentMap: experimentMap,
groupMap: groupMap,
events: events,
eventMap: eventMap,
featureMap: featureMap,
projectID: datafile.ProjectID,
revision: datafile.Revision,
rollouts: rollouts,
rolloutMap: rolloutMap,
sendFlagDecisions: datafile.SendFlagDecisions,
}
Expand Down
54 changes: 51 additions & 3 deletions pkg/config/datafileprojectconfig/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ func TestNewDatafileProjectConfigNil(t *testing.T) {
}

func TestNewDatafileProjectConfigNotNil(t *testing.T) {
dpc := DatafileProjectConfig{accountID: "123", revision: "1", projectID: "12345", sdkKey: "a", environmentKey: "production"}
jsonDatafileStr := `{"accountID": "123", "revision": "1", "projectId": "12345", "version": "4", "sdkKey": "a", "environmentKey": "production"}`
dpc := DatafileProjectConfig{accountID: "123", revision: "1", projectID: "12345", sdkKey: "a", environmentKey: "production", events: []entities.Event{{Key: "event_single_targeted_exp"}}, attributes: []entities.Attribute{{ID: "10401066170"}}}
jsonDatafileStr := `{"accountID":"123","revision":"1","projectId":"12345","version":"4","sdkKey":"a","environmentKey":"production","events":[{"key":"event_single_targeted_exp"}],"attributes":[{"id":"10401066170"}]}`
jsonDatafile := []byte(jsonDatafileStr)
projectConfig, err := NewDatafileProjectConfig(jsonDatafile, logging.GetLogger("", "DatafileProjectConfig"))
assert.Nil(t, err)
Expand All @@ -50,6 +50,18 @@ func TestNewDatafileProjectConfigNotNil(t *testing.T) {
assert.Equal(t, dpc.projectID, projectConfig.projectID)
assert.Equal(t, dpc.environmentKey, projectConfig.environmentKey)
assert.Equal(t, dpc.sdkKey, projectConfig.sdkKey)
assert.Equal(t, dpc.events, projectConfig.events)
assert.Equal(t, dpc.attributes, projectConfig.attributes)
}

func TestGetDatafile(t *testing.T) {
jsonDatafileStr := `{"accountID": "123", "revision": "1", "projectId": "12345", "version": "4", "sdkKey": "a", "environmentKey": "production"}`
jsonDatafile := []byte(jsonDatafileStr)
config := &DatafileProjectConfig{
datafile: string(jsonDatafile),
}

assert.Equal(t, string(jsonDatafile), config.GetDatafile())
}

func TestGetProjectID(t *testing.T) {
Expand Down Expand Up @@ -88,6 +100,14 @@ func TestGetAnonymizeIP(t *testing.T) {
assert.Equal(t, anonymizeIP, config.GetAnonymizeIP())
}

func TestGetAttributes(t *testing.T) {
config := &DatafileProjectConfig{
attributes: []entities.Attribute{{ID: "id1", Key: "key"}, {ID: "id1", Key: "key"}},
}

assert.Equal(t, config.attributes, config.GetAttributes())
}

func TestGetAttributeID(t *testing.T) {
id := "id"
key := "key"
Expand Down Expand Up @@ -115,6 +135,13 @@ func TestGetEnvironmentKey(t *testing.T) {
assert.Equal(t, "production", config.GetEnvironmentKey())
}

func TestGetEvents(t *testing.T) {
config := &DatafileProjectConfig{
events: []entities.Event{{ID: "5"}},
}
assert.Equal(t, config.events, config.GetEvents())
}

func TestGetBotFiltering(t *testing.T) {
botFiltering := true
config := &DatafileProjectConfig{
Expand Down Expand Up @@ -298,20 +325,34 @@ func TestGetExperimentList(t *testing.T) {
experiment := entities.Experiment{
Key: key,
}

experimentMap := make(map[string]entities.Experiment)
experimentMap[id] = experiment

config := &DatafileProjectConfig{
experimentKeyToIDMap: experimentKeyToIDMap,
experimentMap: experimentMap,
}

experiments := config.GetExperimentList()

assert.Equal(t, 1, len(experiments))
assert.Equal(t, experiment, experiments[0])
}

func TestGetRolloutList(t *testing.T) {
config := &DatafileProjectConfig{
rollouts: []entities.Rollout{{ID: "5"}},
}
assert.Equal(t, config.rollouts, config.GetRolloutList())
}

func TestGetAudienceList(t *testing.T) {
config := &DatafileProjectConfig{
audiences: []entities.Audience{{ID: "5", Name: "one"}, {ID: "5", Name: "two"}},
}
assert.Equal(t, config.audiences, config.GetAudienceList())
}

func TestGetAudienceByID(t *testing.T) {
id := "id"
audience := entities.Audience{
Expand Down Expand Up @@ -409,6 +450,13 @@ func TestGetGroupByID(t *testing.T) {
assert.Equal(t, group, actual)
}

func TestSendFlagDecisions(t *testing.T) {
config := &DatafileProjectConfig{
sendFlagDecisions: true,
}
assert.Equal(t, config.sendFlagDecisions, config.SendFlagDecisions())
}

func TestGetGroupByIDMissingIDError(t *testing.T) {
config := &DatafileProjectConfig{}
_, err := config.GetGroupByID("id")
Expand Down
15 changes: 9 additions & 6 deletions pkg/config/datafileprojectconfig/mappers/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,22 @@ import (
)

// MapAttributes maps the raw datafile attribute entities to SDK Attribute entities
func MapAttributes(attributes []datafileEntities.Attribute) (attributeMap map[string]entities.Attribute, attributeKeyToIDMap map[string]string) {
func MapAttributes(attributes []datafileEntities.Attribute) (attributesList []entities.Attribute, attributeMap map[string]entities.Attribute, attributeKeyToIDMap map[string]string) {

attributesList = []entities.Attribute{}
attributeMap = make(map[string]entities.Attribute)
attributeKeyToIDMap = make(map[string]string)
for _, attribute := range attributes {
tmpAttribute := entities.Attribute{
ID: attribute.ID,
Key: attribute.Key,
}
_, ok := attributeMap[attribute.ID]
if !ok {
attributeMap[attribute.ID] = entities.Attribute{
ID: attribute.ID,
Key: attribute.Key,
}
attributeMap[attribute.ID] = tmpAttribute
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of this change?

attributeKeyToIDMap[attribute.Key] = attribute.ID
}
attributesList = append(attributesList, tmpAttribute)
}
return attributeMap, attributeKeyToIDMap
return attributesList, attributeMap, attributeKeyToIDMap
}
13 changes: 9 additions & 4 deletions pkg/config/datafileprojectconfig/mappers/attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ import (

func TestMapAttributesWithEmptyList(t *testing.T) {

attributeMap, attributeKeyToIDMap := MapAttributes(nil)
attributes, attributeMap, attributeKeyToIDMap := MapAttributes(nil)

attributesList := []entities.Attribute{}
expectedAttributeMap := map[string]entities.Attribute{}
expectedAttributeKeyToIDMap := map[string]string{}

assert.Equal(t, attributesList, attributes)
assert.Equal(t, attributeMap, expectedAttributeMap)
assert.Equal(t, attributeKeyToIDMap, expectedAttributeKeyToIDMap)
}
Expand All @@ -40,12 +42,15 @@ func TestMapAttributes(t *testing.T) {
attrList := []datafileEntities.Attribute{{ID: "1", Key: "one"}, {ID: "2", Key: "two"},
{ID: "3", Key: "three"}, {ID: "2", Key: "four"}, {ID: "5", Key: "one"}}

attributeMap, attributeKeyToIDMap := MapAttributes(attrList)
attributes, attributeMap, attributeKeyToIDMap := MapAttributes(attrList)

expectedAttributeMap := map[string]entities.Attribute{"1": {"1", "one"},
"2": {"2", "two"}, "3": {"3", "three"}, "5": {"5", "one"}}
expectedAttributeMap := map[string]entities.Attribute{"1": {ID: "1", Key: "one"},
"2": {ID: "2", Key: "two"}, "3": {ID: "3", Key: "three"}, "5": {ID: "5", Key: "one"}}
expectedAttributeKeyToIDMap := map[string]string{"one": "5", "three": "3", "two": "2"}

for _, attr := range attributes {
assert.Equal(t, entities.Attribute{ID: attr.ID, Key: attr.Key}, attr)
}
assert.Equal(t, attributeMap, expectedAttributeMap)
assert.Equal(t, attributeKeyToIDMap, expectedAttributeKeyToIDMap)
}
29 changes: 17 additions & 12 deletions pkg/config/datafileprojectconfig/mappers/audience.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/****************************************************************************
* Copyright 2019, Optimizely, Inc. and contributors *
* Copyright 2019,2021, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
Expand All @@ -23,23 +23,28 @@ import (
)

// MapAudiences maps the raw datafile audience entities to SDK Audience entities
func MapAudiences(audiences []datafileEntities.Audience) map[string]entities.Audience {
func MapAudiences(audiences []datafileEntities.Audience) (audienceList []entities.Audience, audienceMap map[string]entities.Audience) {

audienceMap := make(map[string]entities.Audience)
audienceList = []entities.Audience{}
audienceMap = make(map[string]entities.Audience)
// Since typed audiences were added prior to audiences,
// they will be given priority in the audienceMap and list
for _, audience := range audiences {
_, ok := audienceMap[audience.ID]
if !ok {
conditionTree, err := buildConditionTree(audience.Conditions)
if err != nil {
// @TODO: handle error
func() {}() // cheat the linters
audience := entities.Audience{
ID: audience.ID,
Name: audience.Name,
Conditions: audience.Conditions,
}
audienceMap[audience.ID] = entities.Audience{
ID: audience.ID,
Name: audience.Name,
ConditionTree: conditionTree,
conditionTree, err := buildConditionTree(audience.Conditions)
if err == nil {
audience.ConditionTree = conditionTree
}

audienceMap[audience.ID] = audience
audienceList = append(audienceList, audience)
}
}
return audienceMap
return audienceList, audienceMap
}
50 changes: 39 additions & 11 deletions pkg/config/datafileprojectconfig/mappers/audience_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/****************************************************************************
* Copyright 2019, Optimizely, Inc. and contributors *
* Copyright 2019,2021 Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
Expand Down Expand Up @@ -28,22 +28,50 @@ import (

func TestMapAudiencesEmptyList(t *testing.T) {

audienceMap := MapAudiences(nil)
audienceList, audienceMap := MapAudiences(nil)

expectedAudienceList := []entities.Audience{}
expectedAudienceMap := map[string]entities.Audience{}

assert.Equal(t, audienceMap, expectedAudienceMap)

assert.Equal(t, expectedAudienceList, audienceList)
assert.Equal(t, expectedAudienceMap, audienceMap)
}
func TestMapAudiences(t *testing.T) {

audienceList := []datafileEntities.Audience{{ID: "1", Name: "one"}, {ID: "2", Name: "two"},
{ID: "3", Name: "three"}, {ID: "2", Name: "four"}, {ID: "5", Name: "one"}}
func TestMapAudiences(t *testing.T) {

audienceMap := MapAudiences(audienceList)
expectedConditions := "[\"and\", [\"or\", [\"or\", {\"name\": \"s_foo\", \"type\": \"custom_attribute\", \"value\": \"foo\"}]]]"
audienceList := []datafileEntities.Audience{{ID: "1", Name: "one", Conditions: expectedConditions}, {ID: "2", Name: "two"},
{ID: "3", Name: "three"}, {ID: "2", Name: "four"}, {ID: "1", Name: "one"}}
audiences, audienceMap := MapAudiences(audienceList)

expectedAudienceMap := map[string]entities.Audience{"1": {ID: "1", Name: "one"}, "2": {ID: "2", Name: "two"},
"3": {ID: "3", Name: "three"}, "5": {ID: "5", Name: "one"}}
expectedConditionTree := &entities.TreeNode{
Operator: "and",
Nodes: []*entities.TreeNode{
{
Operator: "or",
Nodes: []*entities.TreeNode{
{
Operator: "or",
Nodes: []*entities.TreeNode{
{
Item: entities.Condition{
Name: "s_foo",
Type: "custom_attribute",
Value: "foo",
StringRepresentation: `{"name":"s_foo","type":"custom_attribute","value":"foo"}`,
},
},
},
},
},
},
},
}
expectedAudienceMap := map[string]entities.Audience{"1": {ID: "1", Name: "one", ConditionTree: expectedConditionTree, Conditions: expectedConditions}, "2": {ID: "2", Name: "two"},
"3": {ID: "3", Name: "three"}}
expectedAudienceList := []entities.Audience{{ID: "1", Name: "one", ConditionTree: expectedConditionTree, Conditions: expectedConditions}, {ID: "2", Name: "two"},
{ID: "3", Name: "three"}}

assert.Equal(t, audienceMap, expectedAudienceMap)
assert.Equal(t, expectedAudienceList, audiences)
assert.Equal(t, expectedAudienceMap, audienceMap)
}
Loading