Skip to content

Commit

Permalink
chore: wire evaluation ctx to store methods (open-feature#1273)
Browse files Browse the repository at this point in the history
## This PR

A follow-up to open-feature#1259 where
binds context from evaluation request to store contract (passing context
to `evaluateVariant()`)

No changes for evaluation logic or any other component

Signed-off-by: Kavindu Dodanduwa <kavindudodanduwa@gmail.com>
  • Loading branch information
Kavindu-Dodan authored Apr 5, 2024
1 parent 3a0a6a7 commit 0075932
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 20 deletions.
10 changes: 8 additions & 2 deletions core/pkg/evaluator/fractional_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evaluator

import (
"context"
"testing"

"github.com/open-feature/flagd/core/pkg/logger"
Expand All @@ -9,6 +10,8 @@ import (
)

func TestFractionalEvaluation(t *testing.T) {
ctx := context.Background()

flags := Flags{
Flags: map[string]model.Flag{
"headerColor": {
Expand Down Expand Up @@ -333,7 +336,7 @@ func TestFractionalEvaluation(t *testing.T) {
)
je.store.Flags = tt.flags.Flags

value, variant, reason, _, err := resolve[string](reqID, tt.flagKey, tt.context, je.evaluateVariant)
value, variant, reason, _, err := resolve[string](ctx, reqID, tt.flagKey, tt.context, je.evaluateVariant)

if value != tt.expectedValue {
t.Errorf("expected value '%s', got '%s'", tt.expectedValue, value)
Expand All @@ -358,6 +361,8 @@ func TestFractionalEvaluation(t *testing.T) {
}

func BenchmarkFractionalEvaluation(b *testing.B) {
ctx := context.Background()

flags := Flags{
Flags: map[string]model.Flag{
"headerColor": {
Expand Down Expand Up @@ -466,7 +471,8 @@ func BenchmarkFractionalEvaluation(b *testing.B) {
),
)
for i := 0; i < b.N; i++ {
value, variant, reason, _, err := resolve[string](reqID, tt.flagKey, tt.context, je.evaluateVariant)
value, variant, reason, _, err := resolve[string](
ctx, reqID, tt.flagKey, tt.context, je.evaluateVariant)

if value != tt.expectedValue {
b.Errorf("expected value '%s', got '%s'", tt.expectedValue, value)
Expand Down
30 changes: 17 additions & 13 deletions core/pkg/evaluator/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type flagdProperties struct {
Timestamp int64 `json:"timestamp"`
}

type variantEvaluator func(string, string, map[string]any) (
type variantEvaluator func(context.Context, string, string, map[string]any) (
variant string, variants map[string]interface{}, reason string, metadata map[string]interface{}, error error)

func WithEvaluator(name string, evalFunc func(interface{}, interface{}) interface{}) JSONEvaluatorOption {
Expand Down Expand Up @@ -169,27 +169,31 @@ func (je *Resolver) ResolveAllValues(ctx context.Context, reqID string, context
switch defaultValue.(type) {
case bool:
value, variant, reason, metadata, err = resolve[bool](
ctx,
reqID,
flagKey,
context,
je.evaluateVariant,
)
case string:
value, variant, reason, metadata, err = resolve[string](
ctx,
reqID,
flagKey,
context,
je.evaluateVariant,
)
case float64:
value, variant, reason, metadata, err = resolve[float64](
ctx,
reqID,
flagKey,
context,
je.evaluateVariant,
)
case map[string]any:
value, variant, reason, metadata, err = resolve[map[string]any](
ctx,
reqID,
flagKey,
context,
Expand All @@ -216,7 +220,7 @@ func (je *Resolver) ResolveBooleanValue(
defer span.End()

je.Logger.DebugWithID(reqID, fmt.Sprintf("evaluating boolean flag: %s", flagKey))
return resolve[bool](reqID, flagKey, context, je.evaluateVariant)
return resolve[bool](ctx, reqID, flagKey, context, je.evaluateVariant)
}

func (je *Resolver) ResolveStringValue(
Expand All @@ -231,7 +235,7 @@ func (je *Resolver) ResolveStringValue(
defer span.End()

je.Logger.DebugWithID(reqID, fmt.Sprintf("evaluating string flag: %s", flagKey))
return resolve[string](reqID, flagKey, context, je.evaluateVariant)
return resolve[string](ctx, reqID, flagKey, context, je.evaluateVariant)
}

func (je *Resolver) ResolveFloatValue(
Expand All @@ -246,7 +250,7 @@ func (je *Resolver) ResolveFloatValue(
defer span.End()

je.Logger.DebugWithID(reqID, fmt.Sprintf("evaluating float flag: %s", flagKey))
value, variant, reason, metadata, err = resolve[float64](reqID, flagKey, context, je.evaluateVariant)
value, variant, reason, metadata, err = resolve[float64](ctx, reqID, flagKey, context, je.evaluateVariant)
return
}

Expand All @@ -262,7 +266,7 @@ func (je *Resolver) ResolveIntValue(ctx context.Context, reqID string, flagKey s

je.Logger.DebugWithID(reqID, fmt.Sprintf("evaluating int flag: %s", flagKey))
var val float64
val, variant, reason, metadata, err = resolve[float64](reqID, flagKey, context, je.evaluateVariant)
val, variant, reason, metadata, err = resolve[float64](ctx, reqID, flagKey, context, je.evaluateVariant)
value = int64(val)
return
}
Expand All @@ -279,7 +283,7 @@ func (je *Resolver) ResolveObjectValue(
defer span.End()

je.Logger.DebugWithID(reqID, fmt.Sprintf("evaluating object flag: %s", flagKey))
return resolve[map[string]any](reqID, flagKey, context, je.evaluateVariant)
return resolve[map[string]any](ctx, reqID, flagKey, context, je.evaluateVariant)
}

func (je *Resolver) ResolveAsAnyValue(
Expand All @@ -292,15 +296,15 @@ func (je *Resolver) ResolveAsAnyValue(
defer span.End()

je.Logger.DebugWithID(reqID, fmt.Sprintf("evaluating flag `%s` as a generic flag", flagKey))
value, variant, reason, meta, err := resolve[interface{}](reqID, flagKey, context, je.evaluateVariant)
value, variant, reason, meta, err := resolve[interface{}](ctx, reqID, flagKey, context, je.evaluateVariant)
return NewAnyValue(value, variant, reason, flagKey, meta, err)
}

// resolve is a helper for generic flag resolving
func resolve[T constraints](reqID string, key string, context map[string]any, variantEval variantEvaluator) (
value T, variant string, reason string, metadata map[string]interface{}, err error,
func resolve[T constraints](ctx context.Context, reqID string, key string, context map[string]any,
variantEval variantEvaluator) (value T, variant string, reason string, metadata map[string]interface{}, err error,
) {
variant, variants, reason, metadata, err := variantEval(reqID, key, context)
variant, variants, reason, metadata, err := variantEval(ctx, reqID, key, context)
if err != nil {
return value, variant, reason, metadata, err
}
Expand All @@ -315,20 +319,20 @@ func resolve[T constraints](reqID string, key string, context map[string]any, va
}

// nolint: funlen
func (je *Resolver) evaluateVariant(reqID string, flagKey string, evalCtx map[string]any) (
func (je *Resolver) evaluateVariant(ctx context.Context, reqID string, flagKey string, evalCtx map[string]any) (
variant string, variants map[string]interface{}, reason string, metadata map[string]interface{}, err error,
) {
metadata = map[string]interface{}{}

flag, ok := je.store.Get(context.Background(), flagKey)
flag, ok := je.store.Get(ctx, flagKey)
if !ok {
// flag not found
je.Logger.DebugWithID(reqID, fmt.Sprintf("requested flag could not be found: %s", flagKey))
return "", map[string]interface{}{}, model.ErrorReason, metadata, errors.New(model.FlagNotFoundErrorCode)
}

// add selector to evaluation metadata
selector := je.store.SelectorForFlag(context.Background(), flag)
selector := je.store.SelectorForFlag(ctx, flag)
if selector != "" {
metadata[SelectorMetadataKey] = selector
}
Expand Down
5 changes: 4 additions & 1 deletion core/pkg/evaluator/legacy_fractional_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evaluator

import (
"context"
"testing"

"github.com/open-feature/flagd/core/pkg/logger"
Expand All @@ -9,6 +10,8 @@ import (
)

func TestLegacyFractionalEvaluation(t *testing.T) {
ctx := context.Background()

flags := Flags{
Flags: map[string]model.Flag{
"headerColor": {
Expand Down Expand Up @@ -279,7 +282,7 @@ func TestLegacyFractionalEvaluation(t *testing.T) {
)
je.store.Flags = tt.flags.Flags

value, variant, reason, _, err := resolve[string](reqID, tt.flagKey, tt.context, je.evaluateVariant)
value, variant, reason, _, err := resolve[string](ctx, reqID, tt.flagKey, tt.context, je.evaluateVariant)

if value != tt.expectedValue {
t.Errorf("expected value '%s', got '%s'", tt.expectedValue, value)
Expand Down
8 changes: 6 additions & 2 deletions core/pkg/evaluator/semver_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package evaluator

import (
"context"
"errors"
"testing"

"github.com/open-feature/flagd/core/pkg/logger"
Expand Down Expand Up @@ -217,6 +219,8 @@ func TestSemVerOperator_Compare(t *testing.T) {
}

func TestJSONEvaluator_semVerEvaluation(t *testing.T) {
ctx := context.Background()

tests := map[string]struct {
flags Flags
flagKey string
Expand Down Expand Up @@ -707,7 +711,7 @@ func TestJSONEvaluator_semVerEvaluation(t *testing.T) {
)
je.store.Flags = tt.flags.Flags

value, variant, reason, _, err := resolve[string](reqID, tt.flagKey, tt.context, je.evaluateVariant)
value, variant, reason, _, err := resolve[string](ctx, reqID, tt.flagKey, tt.context, je.evaluateVariant)

if value != tt.expectedValue {
t.Errorf("expected value '%s', got '%s'", tt.expectedValue, value)
Expand All @@ -721,7 +725,7 @@ func TestJSONEvaluator_semVerEvaluation(t *testing.T) {
t.Errorf("expected reason '%s', got '%s'", tt.expectedReason, reason)
}

if err != tt.expectedError {
if !errors.Is(err, tt.expectedError) {
t.Errorf("expected err '%v', got '%v'", tt.expectedError, err)
}
})
Expand Down
9 changes: 7 additions & 2 deletions core/pkg/evaluator/string_comparison_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evaluator

import (
"context"
"fmt"
"testing"

Expand All @@ -11,6 +12,8 @@ import (
)

func TestJSONEvaluator_startsWithEvaluation(t *testing.T) {
ctx := context.Background()

tests := map[string]struct {
flags Flags
flagKey string
Expand Down Expand Up @@ -191,7 +194,7 @@ func TestJSONEvaluator_startsWithEvaluation(t *testing.T) {
)
je.store.Flags = tt.flags.Flags

value, variant, reason, _, err := resolve[string](reqID, tt.flagKey, tt.context, je.evaluateVariant)
value, variant, reason, _, err := resolve[string](ctx, reqID, tt.flagKey, tt.context, je.evaluateVariant)

if value != tt.expectedValue {
t.Errorf("expected value '%s', got '%s'", tt.expectedValue, value)
Expand All @@ -213,6 +216,8 @@ func TestJSONEvaluator_startsWithEvaluation(t *testing.T) {
}

func TestJSONEvaluator_endsWithEvaluation(t *testing.T) {
ctx := context.Background()

tests := map[string]struct {
flags Flags
flagKey string
Expand Down Expand Up @@ -394,7 +399,7 @@ func TestJSONEvaluator_endsWithEvaluation(t *testing.T) {

je.store.Flags = tt.flags.Flags

value, variant, reason, _, err := resolve[string](reqID, tt.flagKey, tt.context, je.evaluateVariant)
value, variant, reason, _, err := resolve[string](ctx, reqID, tt.flagKey, tt.context, je.evaluateVariant)

if value != tt.expectedValue {
t.Errorf("expected value '%s', got '%s'", tt.expectedValue, value)
Expand Down

0 comments on commit 0075932

Please sign in to comment.