Skip to content

Commit

Permalink
merge conflict resolution
Browse files Browse the repository at this point in the history
Signed-off-by: James-Milligan <[email protected]>
  • Loading branch information
james-milligan committed Sep 27, 2022
2 parents c6ce99e + fc4b871 commit b1f7e9a
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 201 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ While you'll likely want a provider for your specific backend, we've provided a
package main

import (
"context"
"github.com/open-feature/go-sdk/pkg/openfeature"
)

func main() {
openfeature.SetProvider(openfeature.NoopProvider{})
client := openfeature.NewClient("app")
value, err := client.BooleanValue("v2_enabled", false, openfeature.EvaluationContext{}, openfeature.EvaluationOptions{})
value, err := client.BooleanValue(
context.Background(), "v2_enabled", false, openfeature.EvaluationContext{}, openfeature.EvaluationOptions{},
)
}
```

Expand Down
233 changes: 185 additions & 48 deletions pkg/openfeature/client.go

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions pkg/openfeature/client_example_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package openfeature_test

import (
"context"
"encoding/json"
"fmt"
"log"
Expand All @@ -17,7 +18,7 @@ func ExampleNewClient() {
func ExampleClient_BooleanValue() {
client := openfeature.NewClient("example-client")
value, err := client.BooleanValue(
"test-flag", true, openfeature.EvaluationContext{}, openfeature.EvaluationOptions{},
context.Background(), "test-flag", true, openfeature.EvaluationContext{},
)
if err != nil {
log.Fatal("error while getting boolean value : ", err)
Expand All @@ -30,7 +31,7 @@ func ExampleClient_BooleanValue() {
func ExampleClient_StringValue() {
client := openfeature.NewClient("example-client")
value, err := client.StringValue(
"test-flag", "openfeature", openfeature.EvaluationContext{}, openfeature.EvaluationOptions{},
context.Background(), "test-flag", "openfeature", openfeature.EvaluationContext{},
)
if err != nil {
log.Fatal("error while getting string value : ", err)
Expand All @@ -43,7 +44,7 @@ func ExampleClient_StringValue() {
func ExampleClient_FloatValue() {
client := openfeature.NewClient("example-client")
value, err := client.FloatValue(
"test-flag", 0.55, openfeature.EvaluationContext{}, openfeature.EvaluationOptions{},
context.Background(), "test-flag", 0.55, openfeature.EvaluationContext{},
)
if err != nil {
log.Fatalf("error while getting float value: %v", err)
Expand All @@ -56,7 +57,7 @@ func ExampleClient_FloatValue() {
func ExampleClient_IntValue() {
client := openfeature.NewClient("example-client")
value, err := client.IntValue(
"test-flag", 3, openfeature.EvaluationContext{}, openfeature.EvaluationOptions{},
context.Background(), "test-flag", 3, openfeature.EvaluationContext{},
)
if err != nil {
log.Fatalf("error while getting int value: %v", err)
Expand All @@ -69,7 +70,7 @@ func ExampleClient_IntValue() {
func ExampleClient_ObjectValue() {
client := openfeature.NewClient("example-client")
value, err := client.ObjectValue(
"test-flag", map[string]string{"foo": "bar"}, openfeature.EvaluationContext{}, openfeature.EvaluationOptions{},
context.Background(), "test-flag", map[string]string{"foo": "bar"}, openfeature.EvaluationContext{},
)
if err != nil {
log.Fatal("error while getting object value : ", err)
Expand Down
113 changes: 75 additions & 38 deletions pkg/openfeature/client_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package openfeature

import (
"context"
"reflect"
"testing"

Expand Down Expand Up @@ -60,11 +61,11 @@ func TestRequirements_1_3(t *testing.T) {
client := NewClient("test-client")

type requirements interface {
BooleanValue(flag string, defaultValue bool, evalCtx EvaluationContext, options EvaluationOptions) (bool, error)
StringValue(flag string, defaultValue string, evalCtx EvaluationContext, options EvaluationOptions) (string, error)
FloatValue(flag string, defaultValue float64, evalCtx EvaluationContext, options EvaluationOptions) (float64, error)
IntValue(flag string, defaultValue int64, evalCtx EvaluationContext, options EvaluationOptions) (int64, error)
ObjectValue(flag string, defaultValue interface{}, evalCtx EvaluationContext, options EvaluationOptions) (interface{}, error)
BooleanValue(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) (bool, error)
StringValue(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) (string, error)
FloatValue(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (float64, error)
IntValue(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (int64, error)
ObjectValue(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (interface{}, error)
}

var clientI interface{} = client
Expand All @@ -81,11 +82,11 @@ func TestRequirement_1_4_1(t *testing.T) {
client := NewClient("test-client")

type requirements interface {
BooleanValueDetails(flag string, defaultValue bool, evalCtx EvaluationContext, options EvaluationOptions) (EvaluationDetails, error)
StringValueDetails(flag string, defaultValue string, evalCtx EvaluationContext, options EvaluationOptions) (EvaluationDetails, error)
FloatValueDetails(flag string, defaultValue float64, evalCtx EvaluationContext, options EvaluationOptions) (EvaluationDetails, error)
IntValueDetails(flag string, defaultValue int64, evalCtx EvaluationContext, options EvaluationOptions) (EvaluationDetails, error)
ObjectValueDetails(flag string, defaultValue interface{}, evalCtx EvaluationContext, options EvaluationOptions) (EvaluationDetails, error)
BooleanValueDetails(ctx context.Context, flag string, defaultValue bool, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
StringValueDetails(ctx context.Context, flag string, defaultValue string, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
FloatValueDetails(ctx context.Context, flag string, defaultValue float64, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
IntValueDetails(ctx context.Context, flag string, defaultValue int64, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
ObjectValueDetails(ctx context.Context, flag string, defaultValue interface{}, evalCtx EvaluationContext, options ...Option) (EvaluationDetails, error)
}

var clientI interface{} = client
Expand All @@ -110,7 +111,7 @@ func TestRequirement_1_4_4(t *testing.T) {
flagKey := "foo"

t.Run("BooleanValueDetails", func(t *testing.T) {
evDetails, err := client.BooleanValueDetails(flagKey, true, EvaluationContext{}, EvaluationOptions{})
evDetails, err := client.BooleanValueDetails(context.Background(), flagKey, true, EvaluationContext{})
if err != nil {
t.Error(err)
}
Expand All @@ -123,7 +124,7 @@ func TestRequirement_1_4_4(t *testing.T) {
})

t.Run("StringValueDetails", func(t *testing.T) {
evDetails, err := client.StringValueDetails(flagKey, "", EvaluationContext{}, EvaluationOptions{})
evDetails, err := client.StringValueDetails(context.Background(), flagKey, "", EvaluationContext{})
if err != nil {
t.Error(err)
}
Expand All @@ -136,7 +137,7 @@ func TestRequirement_1_4_4(t *testing.T) {
})

t.Run("FloatValueDetails", func(t *testing.T) {
evDetails, err := client.FloatValueDetails(flagKey, 1, EvaluationContext{}, EvaluationOptions{})
evDetails, err := client.FloatValueDetails(context.Background(), flagKey, 1, EvaluationContext{})
if err != nil {
t.Error(err)
}
Expand All @@ -149,7 +150,7 @@ func TestRequirement_1_4_4(t *testing.T) {
})

t.Run("IntValueDetails", func(t *testing.T) {
evDetails, err := client.IntValueDetails(flagKey, 1, EvaluationContext{}, EvaluationOptions{})
evDetails, err := client.IntValueDetails(context.Background(), flagKey, 1, EvaluationContext{})
if err != nil {
t.Error(err)
}
Expand All @@ -162,7 +163,7 @@ func TestRequirement_1_4_4(t *testing.T) {
})

t.Run("ObjectValueDetails", func(t *testing.T) {
evDetails, err := client.ObjectValueDetails(flagKey, 1, EvaluationContext{}, EvaluationOptions{})
evDetails, err := client.ObjectValueDetails(context.Background(), flagKey, 1, EvaluationContext{})
if err != nil {
t.Error(err)
}
Expand Down Expand Up @@ -222,7 +223,7 @@ func TestRequirement_1_4_9(t *testing.T) {
defaultValue := true
mockProvider.EXPECT().Metadata().AnyTimes()
mockProvider.EXPECT().Hooks().AnyTimes()
mockProvider.EXPECT().BooleanEvaluation(flagKey, defaultValue, flatCtx).
mockProvider.EXPECT().BooleanEvaluation(context.Background(), flagKey, defaultValue, flatCtx).
Return(BoolResolutionDetail{
Value: false,
ResolutionDetail: ResolutionDetail{
Expand All @@ -232,7 +233,7 @@ func TestRequirement_1_4_9(t *testing.T) {
}).Times(2)
SetProvider(mockProvider)

value, err := client.BooleanValue(flagKey, defaultValue, evalCtx, EvaluationOptions{})
value, err := client.BooleanValue(context.Background(), flagKey, defaultValue, evalCtx)
if err == nil {
t.Error("expected BooleanValue to return an error, got nil")
}
Expand All @@ -241,7 +242,7 @@ func TestRequirement_1_4_9(t *testing.T) {
t.Errorf("expected default value from BooleanValue, got %v", value)
}

valueDetails, err := client.BooleanValueDetails(flagKey, defaultValue, evalCtx, EvaluationOptions{})
valueDetails, err := client.BooleanValueDetails(context.Background(), flagKey, defaultValue, evalCtx)
if err == nil {
t.Error("expected BooleanValueDetails to return an error, got nil")
}
Expand All @@ -257,7 +258,7 @@ func TestRequirement_1_4_9(t *testing.T) {
defaultValue := "default"
mockProvider.EXPECT().Metadata().AnyTimes()
mockProvider.EXPECT().Hooks().AnyTimes()
mockProvider.EXPECT().StringEvaluation(flagKey, defaultValue, flatCtx).
mockProvider.EXPECT().StringEvaluation(context.Background(), flagKey, defaultValue, flatCtx).
Return(StringResolutionDetail{
Value: "foo",
ResolutionDetail: ResolutionDetail{
Expand All @@ -267,7 +268,7 @@ func TestRequirement_1_4_9(t *testing.T) {
}).Times(2)
SetProvider(mockProvider)

value, err := client.StringValue(flagKey, defaultValue, evalCtx, EvaluationOptions{})
value, err := client.StringValue(context.Background(), flagKey, defaultValue, evalCtx)
if err == nil {
t.Error("expected StringValue to return an error, got nil")
}
Expand All @@ -276,7 +277,7 @@ func TestRequirement_1_4_9(t *testing.T) {
t.Errorf("expected default value from StringValue, got %v", value)
}

valueDetails, err := client.StringValueDetails(flagKey, defaultValue, evalCtx, EvaluationOptions{})
valueDetails, err := client.StringValueDetails(context.Background(), flagKey, defaultValue, evalCtx)
if err == nil {
t.Error("expected StringValueDetails to return an error, got nil")
}
Expand All @@ -292,7 +293,7 @@ func TestRequirement_1_4_9(t *testing.T) {
defaultValue := 3.14159
mockProvider.EXPECT().Metadata().AnyTimes()
mockProvider.EXPECT().Hooks().AnyTimes()
mockProvider.EXPECT().FloatEvaluation(flagKey, defaultValue, flatCtx).
mockProvider.EXPECT().FloatEvaluation(context.Background(), flagKey, defaultValue, flatCtx).
Return(FloatResolutionDetail{
Value: 0,
ResolutionDetail: ResolutionDetail{
Expand All @@ -302,7 +303,7 @@ func TestRequirement_1_4_9(t *testing.T) {
}).Times(2)
SetProvider(mockProvider)

value, err := client.FloatValue(flagKey, defaultValue, evalCtx, EvaluationOptions{})
value, err := client.FloatValue(context.Background(), flagKey, defaultValue, evalCtx)
if err == nil {
t.Error("expected FloatValue to return an error, got nil")
}
Expand All @@ -311,7 +312,7 @@ func TestRequirement_1_4_9(t *testing.T) {
t.Errorf("expected default value from FloatValue, got %v", value)
}

valueDetails, err := client.FloatValueDetails(flagKey, defaultValue, evalCtx, EvaluationOptions{})
valueDetails, err := client.FloatValueDetails(context.Background(), flagKey, defaultValue, evalCtx)
if err == nil {
t.Error("expected FloatValueDetails to return an error, got nil")
}
Expand All @@ -327,7 +328,7 @@ func TestRequirement_1_4_9(t *testing.T) {
var defaultValue int64 = 3
mockProvider.EXPECT().Metadata().AnyTimes()
mockProvider.EXPECT().Hooks().AnyTimes()
mockProvider.EXPECT().IntEvaluation(flagKey, defaultValue, flatCtx).
mockProvider.EXPECT().IntEvaluation(context.Background(), flagKey, defaultValue, flatCtx).
Return(IntResolutionDetail{
Value: 0,
ResolutionDetail: ResolutionDetail{
Expand All @@ -337,7 +338,7 @@ func TestRequirement_1_4_9(t *testing.T) {
}).Times(2)
SetProvider(mockProvider)

value, err := client.IntValue(flagKey, defaultValue, evalCtx, EvaluationOptions{})
value, err := client.IntValue(context.Background(), flagKey, defaultValue, evalCtx)
if err == nil {
t.Error("expected IntValue to return an error, got nil")
}
Expand All @@ -346,7 +347,7 @@ func TestRequirement_1_4_9(t *testing.T) {
t.Errorf("expected default value from IntValue, got %v", value)
}

valueDetails, err := client.IntValueDetails(flagKey, defaultValue, evalCtx, EvaluationOptions{})
valueDetails, err := client.IntValueDetails(context.Background(), flagKey, defaultValue, evalCtx)
if err == nil {
t.Error("expected FloatValueDetails to return an error, got nil")
}
Expand All @@ -365,7 +366,7 @@ func TestRequirement_1_4_9(t *testing.T) {
defaultValue := obj{foo: "bar"}
mockProvider.EXPECT().Metadata().AnyTimes()
mockProvider.EXPECT().Hooks().AnyTimes()
mockProvider.EXPECT().ObjectEvaluation(flagKey, defaultValue, flatCtx).
mockProvider.EXPECT().ObjectEvaluation(context.Background(), flagKey, defaultValue, flatCtx).
Return(InterfaceResolutionDetail{
ResolutionDetail: ResolutionDetail{
ErrorCode: "GENERAL",
Expand All @@ -374,7 +375,7 @@ func TestRequirement_1_4_9(t *testing.T) {
}).Times(2)
SetProvider(mockProvider)

value, err := client.ObjectValue(flagKey, defaultValue, evalCtx, EvaluationOptions{})
value, err := client.ObjectValue(context.Background(), flagKey, defaultValue, evalCtx)
if err == nil {
t.Error("expected ObjectValue to return an error, got nil")
}
Expand All @@ -383,7 +384,7 @@ func TestRequirement_1_4_9(t *testing.T) {
t.Errorf("expected default value from ObjectValue, got %v", value)
}

valueDetails, err := client.ObjectValueDetails(flagKey, defaultValue, evalCtx, EvaluationOptions{})
valueDetails, err := client.ObjectValueDetails(context.Background(), flagKey, defaultValue, evalCtx)
if err == nil {
t.Error("expected ObjectValueDetails to return an error, got nil")
}
Expand Down Expand Up @@ -415,7 +416,7 @@ func TestRequirement_1_4_9(t *testing.T) {
func TestFlattenContext(t *testing.T) {
tests := map[string]struct {
inCtx EvaluationContext
outCtx map[string]interface{}
outCtx FlattenedContext
}{
"happy path": {
inCtx: EvaluationContext{
Expand All @@ -426,7 +427,7 @@ func TestFlattenContext(t *testing.T) {
},
TargetingKey: "user",
},
outCtx: map[string]interface{}{
outCtx: FlattenedContext{
TargetingKey: "user",
"1": "string",
"2": 0.01,
Expand All @@ -441,7 +442,7 @@ func TestFlattenContext(t *testing.T) {
"3": false,
},
},
outCtx: map[string]interface{}{
outCtx: FlattenedContext{
"1": "string",
"2": 0.01,
"3": false,
Expand All @@ -457,7 +458,7 @@ func TestFlattenContext(t *testing.T) {
"3": false,
},
},
outCtx: map[string]interface{}{
outCtx: FlattenedContext{
TargetingKey: "user",
"1": "string",
"2": 0.01,
Expand All @@ -468,7 +469,7 @@ func TestFlattenContext(t *testing.T) {
inCtx: EvaluationContext{
TargetingKey: "user",
},
outCtx: map[string]interface{}{
outCtx: FlattenedContext{
TargetingKey: "user",
},
},
Expand Down Expand Up @@ -505,10 +506,10 @@ func TestBeforeHookNilContext(t *testing.T) {
client := NewClient("test")
attributes := map[string]interface{}{"should": "persist"}
evalCtx := EvaluationContext{Attributes: attributes}
mockProvider.EXPECT().BooleanEvaluation(gomock.Any(), gomock.Any(), attributes)
mockProvider.EXPECT().BooleanEvaluation(gomock.Any(), gomock.Any(), gomock.Any(), attributes)

_, err := client.BooleanValue(
"foo", false, evalCtx, NewEvaluationOptions([]Hook{hookNilContext}, HookHints{}),
context.Background(), "foo", false, evalCtx, WithHooks(hookNilContext),
)
if err != nil {
t.Fatal(err)
Expand All @@ -534,7 +535,7 @@ func TestClientLoggerUsesLatestGlobalLogger(t *testing.T) {

client := NewClient("test")
SetLogger(logr.New(l))
_, err := client.BooleanValue("foo", false, EvaluationContext{}, EvaluationOptions{})
_, err := client.BooleanValue(context.Background(), "foo", false, EvaluationContext{})
if err != nil {
t.Fatal(err)
}
Expand All @@ -543,3 +544,39 @@ func TestClientLoggerUsesLatestGlobalLogger(t *testing.T) {
t.Error("client didn't use the updated global logger")
}
}

func TestErrorCodeFromProviderReturnedInEvaluationDetails(t *testing.T) {
defer t.Cleanup(initSingleton)
ctrl := gomock.NewController(t)

const errorCode = "TIMEOUT"

mockProvider := NewMockFeatureProvider(ctrl)
mockProvider.EXPECT().Metadata().AnyTimes()
mockProvider.EXPECT().Hooks().AnyTimes()
SetProvider(mockProvider)
mockProvider.EXPECT().BooleanEvaluation(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
Return(BoolResolutionDetail{
Value: true,
ResolutionDetail: ResolutionDetail{
ErrorCode: errorCode,
Reason: "",
Variant: "",
},
})

client := NewClient("test")
evalDetails, err := client.evaluate(
context.Background(), "foo", Boolean, true, EvaluationContext{}, EvaluationOptions{},
)
if err == nil {
t.Error("expected err, got nil")
}

if evalDetails.ErrorCode != errorCode {
t.Errorf(
"expected evaluation details to contain error code '%s', got '%s'",
errorCode, evalDetails.ErrorCode,
)
}
}
Loading

0 comments on commit b1f7e9a

Please sign in to comment.