Skip to content

Commit c715e78

Browse files
author
Michael Ng
authored
feat(err): Panic handling in the IsFeatureEnabled API. (#51)
1 parent 2e11ef8 commit c715e78

File tree

3 files changed

+38
-7
lines changed

3 files changed

+38
-7
lines changed

examples/main.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ import (
1313
func main() {
1414
logging.SetLogLevel(logging.LogLevelDebug)
1515
optimizelyFactory := &client.OptimizelyFactory{
16-
SDKKey: "4SLpaJA1r1pgE6T2CoMs9q",
17-
Datafile: []byte("datafile_string"),
16+
SDKKey: "4SLpaJA1r1pgE6T2CoMs9q",
1817
}
1918
client, err := optimizelyFactory.Client()
2019

@@ -31,7 +30,7 @@ func main() {
3130
},
3231
}
3332

34-
enabled, _ := client.IsFeatureEnabled("binary_feature", user)
33+
enabled, _ := client.IsFeatureEnabled("mutext_feat", user)
3534
fmt.Printf("Is feature enabled? %v", enabled)
3635

3736
processor := event.NewEventProcessor(100, 100)

optimizely/client/client.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package client
1919
import (
2020
"errors"
2121
"fmt"
22+
"runtime/debug"
2223

2324
"github.com/optimizely/go-sdk/optimizely"
2425
"github.com/optimizely/go-sdk/optimizely/decision"
@@ -36,19 +37,27 @@ type OptimizelyClient struct {
3637
}
3738

3839
// IsFeatureEnabled returns true if the feature is enabled for the given user
39-
func (o *OptimizelyClient) IsFeatureEnabled(featureKey string, userContext entities.UserContext) (bool, error) {
40+
func (o *OptimizelyClient) IsFeatureEnabled(featureKey string, userContext entities.UserContext) (result bool, err error) {
4041
if !o.isValid {
4142
errorMessage := "Optimizely instance is not valid. Failing IsFeatureEnabled."
4243
err := errors.New(errorMessage)
4344
logger.Error(errorMessage, nil)
4445
return false, err
4546
}
4647

48+
defer func() {
49+
if r := recover(); r != nil {
50+
errorMessage := fmt.Sprintf(`Optimizely SDK is panicking with the error "%s"`, string(debug.Stack()))
51+
err = errors.New(errorMessage)
52+
logger.Error(errorMessage, err)
53+
}
54+
}()
55+
4756
projectConfig := o.configManager.GetConfig()
4857
feature, err := projectConfig.GetFeatureByKey(featureKey)
4958
if err != nil {
5059
logger.Error("Error retrieving feature", err)
51-
return false, err
60+
return result, err
5261
}
5362
featureDecisionContext := decision.FeatureDecisionContext{
5463
Feature: &feature,
@@ -60,17 +69,18 @@ func (o *OptimizelyClient) IsFeatureEnabled(featureKey string, userContext entit
6069
featureDecision, err := o.decisionService.GetFeatureDecision(featureDecisionContext, userContext)
6170
if err != nil {
6271
logger.Error("Received an error while computing feature decision", err)
63-
return false, err
72+
return result, err
6473
}
6574

6675
logger.Debug(fmt.Sprintf(`Decision made for feature "%s" for user "%s" with the following reason: "%s". Source: "%s".`, featureKey, userID, featureDecision.Reason, featureDecision.Source))
6776

6877
if featureDecision.Variation.FeatureEnabled == true {
78+
result = true
6979
logger.Info(fmt.Sprintf(`Feature "%s" is enabled for user "%s".`, featureKey, userID))
7080
} else {
7181
logger.Info(fmt.Sprintf(`Feature "%s" is not enabled for user "%s".`, featureKey, userID))
7282
}
7383

7484
// @TODO(mng): send impression event
75-
return featureDecision.Variation.FeatureEnabled, nil
85+
return result, nil
7686
}

optimizely/client/client_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,25 @@ func TestIsFeatureEnabledErrorCases(t *testing.T) {
146146
mockConfigManager.AssertExpectations(t)
147147
mockDecisionService.AssertNotCalled(t, "GetDecision")
148148
}
149+
150+
func TestIsFeatureEnabledPanic(t *testing.T) {
151+
testUserContext := entities.UserContext{ID: "test_user_1"}
152+
testFeatureKey := "test_feature_key"
153+
154+
mockConfigManager := new(MockProjectConfigManager)
155+
mockDecisionService := new(MockDecisionService)
156+
157+
client := OptimizelyClient{
158+
configManager: mockConfigManager,
159+
decisionService: mockDecisionService,
160+
isValid: true,
161+
}
162+
163+
// returning an error object will cause the Client to panic
164+
mockConfigManager.On("GetFeatureByKey", testFeatureKey, testUserContext).Return(errors.New("failure"))
165+
166+
// ensure that the client calms back down and recovers
167+
result, err := client.IsFeatureEnabled(testFeatureKey, testUserContext)
168+
assert.False(t, result)
169+
assert.True(t, assert.Error(t, err))
170+
}

0 commit comments

Comments
 (0)