Skip to content

Commit

Permalink
feat: call error hooks on short circuits
Browse files Browse the repository at this point in the history
Signed-off-by: Bernd Warmuth <[email protected]>
  • Loading branch information
warber committed Nov 7, 2024
1 parent ccfb895 commit 2654d57
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 10 deletions.
20 changes: 12 additions & 8 deletions openfeature/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -659,14 +659,6 @@ func (c *Client) evaluate(
},
}

if c.State() == NotReadyState {
return evalDetails, ProviderNotReadyError
}

if c.State() == FatalState {
return evalDetails, ProviderFatalError
}

if !utf8.Valid([]byte(flag)) {
return evalDetails, NewParseErrorResolutionError("flag key is not a UTF-8 encoded string")
}
Expand All @@ -692,6 +684,18 @@ func (c *Client) evaluate(
c.finallyHooks(ctx, hookCtx, providerInvocationClientApiHooks, options)
}()

// short circuit if provider is in NOT READY state
if c.State() == NotReadyState {
c.errorHooks(ctx, hookCtx, providerInvocationClientApiHooks, ProviderNotReadyError, options)
return evalDetails, ProviderNotReadyError
}

// short circuit if provider is in FATAL state
if c.State() == FatalState {
c.errorHooks(ctx, hookCtx, providerInvocationClientApiHooks, ProviderFatalError, options)
return evalDetails, ProviderFatalError
}

evalCtx, err = c.beforeHooks(ctx, hookCtx, apiClientInvocationProviderHooks, evalCtx, options)
hookCtx.evaluationContext = evalCtx
if err != nil {
Expand Down
63 changes: 61 additions & 2 deletions openfeature/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1232,18 +1232,77 @@ func TestRequirement_1_7_5(t *testing.T) {
// is in NOT_READY.
func TestRequirement_1_7_6(t *testing.T) {
defer t.Cleanup(initSingleton)
t.Skip("Test not yet implemented")

ctrl := gomock.NewController(t)
mockHook := NewMockHook(ctrl)
mockHook.EXPECT().Error(gomock.Any(), gomock.Any(), ProviderNotReadyError, gomock.Any())
mockHook.EXPECT().Finally(gomock.Any(), gomock.Any(), gomock.Any())

client := GetApiInstance().GetNamedClient(t.Name())
client.AddHooks(mockHook)

if client.State() != NotReadyState {
t.Fatalf("expected client to report NOT READY state")
}

defaultVal := true
res, err := client.BooleanValue(context.Background(), "a-flag", defaultVal, EvaluationContext{})
if err == nil {
t.Fatalf("expected client to report an error")
}

if res != defaultVal {
t.Fatalf("expected resolved boolean value to default to %t, got %t", defaultVal, res)
}

}

// The client MUST default, run error hooks, and indicate an error if flag resolution is attempted while the provider
// is in FATAL.
func TestRequirement_1_7_7(t *testing.T) {
t.Skip("Test not yet implemented")
defer t.Cleanup(initSingleton)
provider := struct {
FeatureProvider
StateHandler
EventHandler
}{
NoopProvider{},
&stateHandlerForTests{
initF: func(e EvaluationContext) error {
return &ProviderInitError{ErrorCode: ProviderFatalCode}
},
},
&ProviderEventing{},
}

_ = SetNamedProviderAndWait(t.Name(), provider)

ctrl := gomock.NewController(t)
mockHook := NewMockHook(ctrl)
mockHook.EXPECT().Error(gomock.Any(), gomock.Any(), ProviderFatalError, gomock.Any())
mockHook.EXPECT().Finally(gomock.Any(), gomock.Any(), gomock.Any())

client := GetApiInstance().GetNamedClient(t.Name())
client.AddHooks(mockHook)

if client.State() != FatalState {
t.Fatalf("expected client to report FATAL state")
}

defaultVal := true
res, err := client.BooleanValue(context.Background(), "a-flag", defaultVal, EvaluationContext{})
if err == nil {
t.Fatalf("expected client to report an error")
}

if res != defaultVal {
t.Fatalf("expected resolved boolean value to default to %t, got %t", defaultVal, res)
}
}

// Implementations SHOULD propagate the error code returned from any provider lifecycle methods.
func TestRequirement_1_7_8(t *testing.T) {

t.Skip("Test not yet implemented")
}

Expand Down

0 comments on commit 2654d57

Please sign in to comment.