Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

2 changes: 0 additions & 2 deletions evaluation/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,13 @@ func NewEvaluator(query Query, postEvalCallback PostEvaluateCallback, logger log

func (e Evaluator) evaluateClause(clause *rest.Clause, target *Target) bool {
if clause == nil || len(clause.Values) == 0 || clause.Op == "" {
e.logger.Debugf("Clause cannot be evaluated because operator is either nil, has no values or operation: Clause (%v)", clause)
return false
}

value := clause.Values[0]
attrValue := getAttrValue(target, clause.Attribute)

if clause.Op != segmentMatchOperator && attrValue == "" {
e.logger.Debugf("Operator is not a segment match and attribute value is not valid: Operator (%s), attributeVal (%s)", clause.Op, attrValue)
return false
}

Expand Down
36 changes: 18 additions & 18 deletions evaluation/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1988,7 +1988,7 @@ func TestEvaluator_JSONVariation(t *testing.T) {

// BENCHMARK
func BenchmarkEvaluateClause_NilClause(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
var clause *rest.Clause = nil
target := &Target{
Identifier: "harness",
Expand All @@ -1999,7 +1999,7 @@ func BenchmarkEvaluateClause_NilClause(b *testing.B) {
}

func BenchmarkEvaluateClause_EmptyOperator(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Op: "",
Values: []string{"harness"},
Expand All @@ -2010,7 +2010,7 @@ func BenchmarkEvaluateClause_EmptyOperator(b *testing.B) {
}

func BenchmarkEvaluateClause_NilValues(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Values: nil,
}
Expand All @@ -2020,7 +2020,7 @@ func BenchmarkEvaluateClause_NilValues(b *testing.B) {
}

func BenchmarkEvaluateClause_EmptyValues(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Values: []string{},
}
Expand All @@ -2030,7 +2030,7 @@ func BenchmarkEvaluateClause_EmptyValues(b *testing.B) {
}

func BenchmarkEvaluateClause_WrongOperator(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "greaterthan",
Expand All @@ -2045,7 +2045,7 @@ func BenchmarkEvaluateClause_WrongOperator(b *testing.B) {
}

func BenchmarkEvaluateClause_EmptyAttribute(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "",
Op: "equalOperator",
Expand All @@ -2060,7 +2060,7 @@ func BenchmarkEvaluateClause_EmptyAttribute(b *testing.B) {
}

func BenchmarkEvaluateClause_MatchOperator(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "matchOperator",
Expand All @@ -2075,7 +2075,7 @@ func BenchmarkEvaluateClause_MatchOperator(b *testing.B) {
}

func BenchmarkEvaluateClause_MatchOperatorError(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "matchOperator",
Expand All @@ -2090,7 +2090,7 @@ func BenchmarkEvaluateClause_MatchOperatorError(b *testing.B) {
}

func BenchmarkEvaluateClause_InOperator(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "inOperator",
Expand All @@ -2105,7 +2105,7 @@ func BenchmarkEvaluateClause_InOperator(b *testing.B) {
}

func BenchmarkEvaluateClause_InOperatorNotFound(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "inOperator",
Expand All @@ -2120,7 +2120,7 @@ func BenchmarkEvaluateClause_InOperatorNotFound(b *testing.B) {
}

func BenchmarkEvaluateClause_EqualOperator(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "equalOperator",
Expand All @@ -2135,7 +2135,7 @@ func BenchmarkEvaluateClause_EqualOperator(b *testing.B) {
}

func BenchmarkEvaluateClause_EqualSensitiveOperator(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "equalSensitiveOperator",
Expand All @@ -2150,7 +2150,7 @@ func BenchmarkEvaluateClause_EqualSensitiveOperator(b *testing.B) {
}

func BenchmarkEvaluateClause_GTOperator(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "gtOperator",
Expand All @@ -2165,7 +2165,7 @@ func BenchmarkEvaluateClause_GTOperator(b *testing.B) {
}

func BenchmarkEvaluateClause_GTOperatorNegative(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "gtOperator",
Expand All @@ -2180,7 +2180,7 @@ func BenchmarkEvaluateClause_GTOperatorNegative(b *testing.B) {
}

func BenchmarkEvaluateClause_StartsWithOperator(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "startsWithOperator",
Expand All @@ -2195,7 +2195,7 @@ func BenchmarkEvaluateClause_StartsWithOperator(b *testing.B) {
}

func BenchmarkEvaluateClause_EndsWithOperator(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "endsWithOperator",
Expand All @@ -2210,7 +2210,7 @@ func BenchmarkEvaluateClause_EndsWithOperator(b *testing.B) {
}

func BenchmarkEvaluateClause_ContainsOperator(b *testing.B) {
evaluator := Evaluator{}
evaluator := Evaluator{logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Attribute: "identifier",
Op: "containsOperator",
Expand All @@ -2225,7 +2225,7 @@ func BenchmarkEvaluateClause_ContainsOperator(b *testing.B) {
}

func BenchmarkEvaluateClause_SegmentMatchOperator(b *testing.B) {
evaluator := Evaluator{query: testRepo}
evaluator := Evaluator{query: testRepo, logger: logger.NoOpLogger{}}
clause := &rest.Clause{
Op: "segmentMatchOperator",
Values: []string{"beta"},
Expand Down
26 changes: 23 additions & 3 deletions evaluation/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package evaluation

import (
"fmt"
"strconv"
"strings"

jsoniter "github.com/json-iterator/go"

"github.com/harness/ff-golang-server-sdk/sdk_codes"

"github.com/harness/ff-golang-server-sdk/log"
Expand All @@ -12,19 +15,36 @@ import (
)

func getAttrValue(target *Target, attr string) string {
if target == nil {
if target == nil || attr == "" {
return ""
}

switch strings.ToLower(attr) {
switch attr {
case "identifier":
return target.Identifier
case "name":
return target.Name
default:
if target.Attributes != nil {
if val, ok := (*target.Attributes)[attr]; ok {
return fmt.Sprint(val)
switch v := val.(type) {
case string:
return v
case int:
return strconv.Itoa(v)
case float64:
return strconv.FormatFloat(v, 'f', -1, 64)
case bool:
return strconv.FormatBool(v)
case map[string]interface{}:
marshalledValue, err := jsoniter.MarshalToString(v)
if err != nil {
return fmt.Sprint(v)
}
return marshalledValue
default:
return fmt.Sprint(v)
}
}
}
}
Expand Down
92 changes: 92 additions & 0 deletions evaluation/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,3 +437,95 @@ func Test_isTargetInList(t *testing.T) {
})
}
}

// Benchmark scenarios
func BenchmarkGetAttrValueNilTarget(b *testing.B) {
for i := 0; i < b.N; i++ {
getAttrValue(nil, "identifier")
}
}

func BenchmarkGetAttrValueEmptyAttribute(b *testing.B) {
var target Target
for i := 0; i < b.N; i++ {
getAttrValue(&target, "")
}
}

func BenchmarkGetAttrValueIdentifier(b *testing.B) {
var target = Target{Identifier: "1234"}
for i := 0; i < b.N; i++ {
getAttrValue(&target, "identifier")
}
}

func BenchmarkGetAttrValueName(b *testing.B) {
var target = Target{Name: "targetName"}
for i := 0; i < b.N; i++ {
getAttrValue(&target, "name")
}
}

func BenchmarkGetAttrValueUnmatched(b *testing.B) {
var target = Target{}
for i := 0; i < b.N; i++ {
getAttrValue(&target, "unmatched")
}
}

func BenchmarkGetAttrValueStringAttr(b *testing.B) {
attributes := map[string]interface{}{"city": "New York"}
var target = Target{Attributes: &attributes}
for i := 0; i < b.N; i++ {
getAttrValue(&target, "city")
}
}

func BenchmarkGetAttrValueIntegerAttr(b *testing.B) {
attributes := map[string]interface{}{"age": 30}
var target = Target{Attributes: &attributes}
for i := 0; i < b.N; i++ {
getAttrValue(&target, "age")
}
}

func BenchmarkGetAttrValueFloatAttr(b *testing.B) {
attributes := map[string]interface{}{"temperature": 98.6}
var target = Target{Attributes: &attributes}
for i := 0; i < b.N; i++ {
getAttrValue(&target, "temperature")
}
}

func BenchmarkGetAttrValueBoolAttr(b *testing.B) {
attributes := map[string]interface{}{"active": true}
var target = Target{Attributes: &attributes}
for i := 0; i < b.N; i++ {
getAttrValue(&target, "active")
}
}

func BenchmarkGetAttrValueBasicJSON(b *testing.B) {
basicJSON := map[string]interface{}{
"myName": "Stephen",
}
attributes := map[string]interface{}{"basicJson": basicJSON}
var target = Target{Attributes: &attributes}
for i := 0; i < b.N; i++ {
getAttrValue(&target, "basicJson")
}
}

func BenchmarkGetAttrValueComplexJSON(b *testing.B) {
complexJSON := map[string]interface{}{
"config": map[string]interface{}{
"setting": "on",
"level": 5,
},
}
attributes := map[string]interface{}{"complexJSON": complexJSON}
var target = Target{Attributes: &attributes}
for i := 0; i < b.N; i++ {
getAttrValue(&target, "complexJSON")
}
}