Skip to content

Commit

Permalink
fix: support audience ids (#161)
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Ng authored Oct 31, 2019
1 parent da04ff2 commit e9a646e
Show file tree
Hide file tree
Showing 13 changed files with 81 additions and 30 deletions.
2 changes: 1 addition & 1 deletion pkg/config/datafileprojectconfig/entities/entities.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type Experiment struct {
TrafficAllocation []trafficAllocation `json:"trafficAllocation"`
AudienceIds []string `json:"audienceIds"`
ForcedVariations map[string]string `json:"forcedVariations"`
AudienceConditions interface{} `json:"audienceConditions"`
AudienceConditions []interface{} `json:"audienceConditions"`
}

// FeatureFlag represents a FeatureFlag object from the Optimizely datafile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func buildAudienceConditionTree(conditions interface{}) (conditionTree *entities
value := reflect.ValueOf(conditions)
visited := make(map[interface{}]bool)

conditionTree = &entities.TreeNode{}
conditionTree = &entities.TreeNode{ Operator: "or" }
var populateConditions func(v reflect.Value, root *entities.TreeNode)
populateConditions = func(v reflect.Value, root *entities.TreeNode) {

Expand Down
21 changes: 19 additions & 2 deletions pkg/config/datafileprojectconfig/mappers/condition_trees_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ func TestBuildAudienceConditionTreeEmpty(t *testing.T) {
json.Unmarshal([]byte(conditionString), &conditions)
conditionTree, err := buildAudienceConditionTree(conditions)

assert.NotNil(t, err)
assert.Equal(t, (*entities.TreeNode)(nil), conditionTree)
expectedTree := &entities.TreeNode{Operator: "or"}
assert.NoError(t, err)
assert.Equal(t, expectedTree, conditionTree)
}

func TestBuildAudienceConditionTreeSimpleAudienceCondition(t *testing.T) {
Expand Down Expand Up @@ -70,6 +71,22 @@ func TestBuildAudienceConditionTreeSimpleAudienceCondition(t *testing.T) {
assert.Equal(t, expectedConditionTree, conditionTree)
}

func TestBuildAudienceConditionTreeNoOperators(t *testing.T) {
conditions := []string{"123"}
expectedConditionTree := &entities.TreeNode{
Operator: "or",
Nodes: []*entities.TreeNode{
{
Item: "123",
},
},
}

conditionTree, err := buildAudienceConditionTree(conditions)
assert.Equal(t, expectedConditionTree, conditionTree)
assert.NoError(t, err)
}

func TestBuildConditionTreeUsingDatafileAudienceConditions(t *testing.T) {

audience := datafileConfig.Audience{
Expand Down
8 changes: 7 additions & 1 deletion pkg/config/datafileprojectconfig/mappers/experiment.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,13 @@ func mapVariation(rawVariation datafileEntities.Variation) entities.Variation {

// Maps the raw experiment entity from the datafile into an SDK Experiment entity
func mapExperiment(rawExperiment datafileEntities.Experiment) entities.Experiment {
audienceConditionTree, err := buildAudienceConditionTree(rawExperiment.AudienceConditions)
var audienceConditionTree *entities.TreeNode
var err error
if rawExperiment.AudienceConditions == nil && len(rawExperiment.AudienceIds) > 0 {
audienceConditionTree, err = buildAudienceConditionTree(rawExperiment.AudienceIds)
} else if len(rawExperiment.AudienceConditions) > 0 {
audienceConditionTree, err = buildAudienceConditionTree(rawExperiment.AudienceConditions)
}
if err != nil {
// @TODO: handle error
func() {}() // cheat the linters
Expand Down
30 changes: 29 additions & 1 deletion pkg/config/datafileprojectconfig/mappers/experiment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package mappers
import (
"testing"

"github.com/json-iterator/go"
jsoniter "github.com/json-iterator/go"
datafileEntities "github.com/optimizely/go-sdk/pkg/config/datafileprojectconfig/entities"
"github.com/optimizely/go-sdk/pkg/entities"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -113,3 +113,31 @@ func TestMapExperiments(t *testing.T) {
assert.Equal(t, expectedExperiments, experiments)
assert.Equal(t, expectedExperimentKeyMap, experimentKeyMap)
}

func TestMapExperimentsAudienceIdsOnly(t *testing.T) {
var rawExperiment datafileEntities.Experiment
rawExperiment.AudienceIds = []string{"11111", "11112"}
rawExperiment.Key = "test_experiment_1"
rawExperiment.ID = "22222"

expectedExperiment := entities.Experiment{
AudienceIds: rawExperiment.AudienceIds,
ID: rawExperiment.ID,
Key: rawExperiment.Key,
AudienceConditionTree: &entities.TreeNode{
Operator: "or",
Nodes: []*entities.TreeNode{
{
Operator: "",
Item: "11111",
},
{
Operator: "",
Item: "11112",
},
},
},
}
experiments, _ := MapExperiments([]datafileEntities.Experiment{rawExperiment})
assert.Equal(t, expectedExperiment.AudienceConditionTree, experiments[rawExperiment.ID].AudienceConditionTree)
}
6 changes: 3 additions & 3 deletions pkg/decision/evaluator/matchers/exact.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,23 @@ func (m ExactMatcher) Match(user entities.UserContext) (bool, error) {
if stringValue, ok := m.Condition.Value.(string); ok {
attributeValue, err := user.GetStringAttribute(m.Condition.Name)
if err != nil {
return false, err
return false, nil
}
return stringValue == attributeValue, nil
}

if boolValue, ok := m.Condition.Value.(bool); ok {
attributeValue, err := user.GetBoolAttribute(m.Condition.Name)
if err != nil {
return false, err
return false, nil
}
return boolValue == attributeValue, nil
}

if floatValue, ok := utils.ToFloat(m.Condition.Value); ok {
attributeValue, err := user.GetFloatAttribute(m.Condition.Name)
if err != nil {
return false, err
return false, nil
}
return floatValue == attributeValue, nil
}
Expand Down
16 changes: 8 additions & 8 deletions pkg/decision/evaluator/matchers/exact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ func TestExactMatcherString(t *testing.T) {
assert.NoError(t, err)
assert.False(t, result)

// Test error case
// Test attribute not found
user = entities.UserContext{
Attributes: map[string]interface{}{
"string_not_foo": "foo",
},
}

_, err = matcher.Match(user)
assert.Error(t, err)
assert.NoError(t, err)
}

func TestExactMatcherBool(t *testing.T) {
Expand Down Expand Up @@ -95,15 +95,15 @@ func TestExactMatcherBool(t *testing.T) {
assert.NoError(t, err)
assert.False(t, result)

// Test error case
// Test attribute not found
user = entities.UserContext{
Attributes: map[string]interface{}{
"not_bool_true": true,
},
}

_, err = matcher.Match(user)
assert.Error(t, err)
assert.NoError(t, err)
}

func TestExactMatcherInt(t *testing.T) {
Expand Down Expand Up @@ -147,15 +147,15 @@ func TestExactMatcherInt(t *testing.T) {
assert.NoError(t, err)
assert.False(t, result)

// Test error case
// Test attribute not found
user = entities.UserContext{
Attributes: map[string]interface{}{
"int_43": 42,
},
}

_, err = matcher.Match(user)
assert.Error(t, err)
assert.NoError(t, err)
}

func TestExactMatcherFloat(t *testing.T) {
Expand Down Expand Up @@ -188,13 +188,13 @@ func TestExactMatcherFloat(t *testing.T) {
assert.NoError(t, err)
assert.False(t, result)

// Test error case
// Test attribute not found
user = entities.UserContext{
Attributes: map[string]interface{}{
"float_4_3": 4.2,
},
}

_, err = matcher.Match(user)
assert.Error(t, err)
assert.NoError(t, err)
}
2 changes: 1 addition & 1 deletion pkg/decision/evaluator/matchers/gt.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (m GtMatcher) Match(user entities.UserContext) (bool, error) {
if floatValue, ok := utils.ToFloat(m.Condition.Value); ok {
attributeValue, err := user.GetFloatAttribute(m.Condition.Name)
if err != nil {
return false, err
return false, nil
}
return floatValue < attributeValue, nil
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/decision/evaluator/matchers/gt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ func TestGtMatcherInt(t *testing.T) {
assert.NoError(t, err)
assert.False(t, result)

// Test error case
// Test attribute not found
user = entities.UserContext{
Attributes: map[string]interface{}{
"int_43": 42,
},
}

_, err = matcher.Match(user)
assert.Error(t, err)
assert.NoError(t, err)
}

func TestGtMatcherFloat(t *testing.T) {
Expand Down Expand Up @@ -127,13 +127,13 @@ func TestGtMatcherFloat(t *testing.T) {
assert.NoError(t, err)
assert.False(t, result)

// Test error case
// Test attribute not found
user = entities.UserContext{
Attributes: map[string]interface{}{
"float_4_3": 4.2,
},
}

_, err = matcher.Match(user)
assert.Error(t, err)
assert.NoError(t, err)
}
2 changes: 1 addition & 1 deletion pkg/decision/evaluator/matchers/lt.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (m LtMatcher) Match(user entities.UserContext) (bool, error) {
if floatValue, ok := utils.ToFloat(m.Condition.Value); ok {
attributeValue, err := user.GetFloatAttribute(m.Condition.Name)
if err != nil {
return false, err
return false, nil
}
return floatValue > attributeValue, nil
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/decision/evaluator/matchers/lt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ func TestLtMatcherInt(t *testing.T) {
assert.NoError(t, err)
assert.False(t, result)

// Test error case
// Test attribute not found
user = entities.UserContext{
Attributes: map[string]interface{}{
"int_43": 42,
},
}

_, err = matcher.Match(user)
assert.Error(t, err)
assert.NoError(t, err)
}

func TestLtMatcherFloat(t *testing.T) {
Expand Down Expand Up @@ -127,13 +127,13 @@ func TestLtMatcherFloat(t *testing.T) {
assert.NoError(t, err)
assert.False(t, result)

// Test error case
// Test attribute not found
user = entities.UserContext{
Attributes: map[string]interface{}{
"float_4_3": 4.2,
},
}

_, err = matcher.Match(user)
assert.Error(t, err)
assert.NoError(t, err)
}
2 changes: 1 addition & 1 deletion pkg/decision/evaluator/matchers/substring.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (m SubstringMatcher) Match(user entities.UserContext) (bool, error) {
if stringValue, ok := m.Condition.Value.(string); ok {
attributeValue, err := user.GetStringAttribute(m.Condition.Name)
if err != nil {
return false, err
return false, nil
}
return strings.Contains(attributeValue, stringValue), nil
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/decision/evaluator/matchers/substring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ func TestSubstringMatcher(t *testing.T) {
assert.NoError(t, err)
assert.False(t, result)

// Test error case
// Test attribute not found
user = entities.UserContext{
Attributes: map[string]interface{}{
"not_string_foo": "foo",
},
}

_, err = matcher.Match(user)
assert.Error(t, err)
assert.NoError(t, err)
}

0 comments on commit e9a646e

Please sign in to comment.