Skip to content

Commit 3812cdb

Browse files
Merge branch 'go-alpha' into pawel/OASIS-4943
# Conflicts: # optimizely/decision/experiment_targeting_service.go
2 parents 6e1b6ba + 42d6d54 commit 3812cdb

20 files changed

+506
-173
lines changed

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,55 @@
11
# Optimizely Go SDK
2+
3+
## Command line interface
4+
A CLI has been provided to illustrate the functionality of the SDK. Simply run `go-sdk` for help.
5+
```$sh
6+
go-sdk provides cli access to your Optimizely fullstack project
7+
8+
Usage:
9+
go-sdk [command]
10+
11+
Available Commands:
12+
help Help about any command
13+
is_feature_enabled Is feature enabled?
14+
15+
Flags:
16+
-h, --help help for go-sdk
17+
-s, --sdkKey string Optimizely project SDK key
18+
19+
Use "go-sdk [command] --help" for more information about a command.
20+
```
21+
22+
Each supported SDK API method is it's own [cobra](https://github.com/spf13/cobra) command and requires the
23+
input of an `--sdkKey`.
24+
25+
### Installation
26+
Install the CLI from github:
27+
28+
```$sh
29+
go install github.com/optimizely/go-sdk
30+
```
31+
32+
Install the CLI from source:
33+
```$sh
34+
go get github.com/optimizely/go-sdk
35+
cd $GOPATH/src/github.com/optimizely/go-sdk
36+
go install
37+
```
38+
39+
### Commands
40+
41+
#### is_feature_enabled
42+
```
43+
Determines if a feature is enabled
44+
45+
Usage:
46+
go-sdk is_feature_enabled [flags]
47+
48+
Flags:
49+
-f, --featureKey string feature key to enable
50+
-h, --help help for is_feature_enabled
51+
-u, --userId string user id
52+
53+
Global Flags:
54+
-s, --sdkKey string Optimizely project SDK key
55+
```

cmd/is_feature_enabled.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package cmd
18+
19+
import (
20+
"fmt"
21+
"github.com/optimizely/go-sdk/optimizely/client"
22+
"github.com/optimizely/go-sdk/optimizely/entities"
23+
"github.com/spf13/cobra"
24+
)
25+
26+
var (
27+
userId string
28+
featurekKey string
29+
)
30+
31+
var isFeatureEnabledCmd = &cobra.Command{
32+
Use: "is_feature_enabled",
33+
Short: "Is feature enabled?",
34+
Long: `Determines if a feature is enabled`,
35+
Run: func(cmd *cobra.Command, args []string) {
36+
optimizelyFactory := &client.OptimizelyFactory{
37+
SDKKey: sdkKey,
38+
}
39+
40+
client, err := optimizelyFactory.Client()
41+
42+
if err != nil {
43+
fmt.Printf("Error instantiating client: %s\n", err)
44+
return
45+
}
46+
47+
user := entities.UserContext{
48+
ID: userId,
49+
Attributes: entities.UserAttributes{},
50+
}
51+
52+
enabled, _ := client.IsFeatureEnabled(featurekKey, user)
53+
fmt.Printf("Is feature \"%s\" enabled for \"%s\"? %t\n", featurekKey, userId, enabled)
54+
},
55+
}
56+
57+
func init() {
58+
rootCmd.AddCommand(isFeatureEnabledCmd)
59+
isFeatureEnabledCmd.Flags().StringVarP(&userId, "userId", "u", "", "user id")
60+
isFeatureEnabledCmd.MarkFlagRequired("userId")
61+
isFeatureEnabledCmd.Flags().StringVarP(&featurekKey, "featureKey", "f", "", "feature key to enable")
62+
isFeatureEnabledCmd.MarkFlagRequired("featureKey")
63+
}

cmd/root.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package cmd
18+
19+
import (
20+
"fmt"
21+
"os"
22+
23+
"github.com/spf13/cobra"
24+
)
25+
26+
var sdkKey string
27+
28+
var rootCmd = &cobra.Command{
29+
Use: "go-sdk",
30+
Short: "go-sdk provides cli access to your Optimizely fullstack project",
31+
}
32+
33+
func Execute() {
34+
if err := rootCmd.Execute(); err != nil {
35+
fmt.Println(err)
36+
os.Exit(1)
37+
}
38+
}
39+
40+
func init() {
41+
rootCmd.PersistentFlags().StringVarP(&sdkKey, "sdkKey", "s", "", "Optimizely project SDK key")
42+
rootCmd.MarkPersistentFlagRequired("sdkKey")
43+
}

examples/main.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ func main() {
1414
optimizelyFactory := &client.OptimizelyFactory{
1515
SDKKey: "ABC",
1616
}
17-
client := optimizelyFactory.Client()
17+
client, err := optimizelyFactory.Client()
18+
19+
if err != nil {
20+
fmt.Printf("Error instantiating client: %s", err)
21+
return
22+
}
1823

1924
user := entities.UserContext{
2025
ID: "mike ng",

main.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/****************************************************************************
2+
* Copyright 2019, Optimizely, Inc. and contributors *
3+
* *
4+
* Licensed under the Apache License, Version 2.0 (the "License"); *
5+
* you may not use this file except in compliance with the License. *
6+
* You may obtain a copy of the License at *
7+
* *
8+
* http://www.apache.org/licenses/LICENSE-2.0 *
9+
* *
10+
* Unless required by applicable law or agreed to in writing, software *
11+
* distributed under the License is distributed on an "AS IS" BASIS, *
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13+
* See the License for the specific language governing permissions and *
14+
* limitations under the License. *
15+
***************************************************************************/
16+
17+
package main
18+
19+
import "github.com/optimizely/go-sdk/cmd"
20+
21+
func main() {
22+
cmd.Execute()
23+
}

optimizely/client/client.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package client
1919
import (
2020
"errors"
2121

22-
"github.com/optimizely/go-sdk/optimizely/config"
22+
"github.com/optimizely/go-sdk/optimizely"
2323
"github.com/optimizely/go-sdk/optimizely/decision"
2424
"github.com/optimizely/go-sdk/optimizely/entities"
2525
"github.com/optimizely/go-sdk/optimizely/logging"
@@ -29,7 +29,7 @@ var logger = logging.GetLogger("Client")
2929

3030
// OptimizelyClient is the entry point to the Optimizely SDK
3131
type OptimizelyClient struct {
32-
configManager config.ProjectConfigManager
32+
configManager optimizely.ProjectConfigManager
3333
decisionService decision.DecisionService
3434
isValid bool
3535
}
@@ -44,14 +44,9 @@ func (o *OptimizelyClient) IsFeatureEnabled(featureKey string, userContext entit
4444
}
4545

4646
projectConfig := o.configManager.GetConfig()
47-
feature, err := projectConfig.GetFeatureByKey(featureKey)
48-
if err != nil {
49-
return false, err
50-
}
51-
52-
// @TODO(mng): Include assigned group for mutex support
5347
featureDecisionContext := decision.FeatureDecisionContext{
54-
Feature: feature,
48+
FeatureKey: featureKey,
49+
ProjectConfig: projectConfig,
5550
}
5651

5752
featureDecision, err := o.decisionService.GetFeatureDecision(featureDecisionContext, userContext)
@@ -61,5 +56,5 @@ func (o *OptimizelyClient) IsFeatureEnabled(featureKey string, userContext entit
6156
}
6257

6358
// @TODO(mng): send impression event
64-
return featureDecision.FeatureEnabled, nil
59+
return featureDecision.Variation.FeatureEnabled, nil
6560
}

optimizely/client/client_test.go

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ import (
2222

2323
"github.com/stretchr/testify/assert"
2424

25-
"github.com/optimizely/go-sdk/optimizely/config"
25+
"github.com/optimizely/go-sdk/optimizely"
2626
"github.com/optimizely/go-sdk/optimizely/decision"
2727
"github.com/optimizely/go-sdk/optimizely/entities"
2828
"github.com/stretchr/testify/mock"
2929
)
3030

3131
type MockProjectConfig struct {
32-
config.ProjectConfig
32+
optimizely.ProjectConfig
3333
mock.Mock
3434
}
3535

@@ -42,9 +42,9 @@ type MockProjectConfigManager struct {
4242
mock.Mock
4343
}
4444

45-
func (p *MockProjectConfigManager) GetConfig() config.ProjectConfig {
45+
func (p *MockProjectConfigManager) GetConfig() optimizely.ProjectConfig {
4646
args := p.Called()
47-
return args.Get(0).(config.ProjectConfig)
47+
return args.Get(0).(optimizely.ProjectConfig)
4848
}
4949

5050
type MockDecisionService struct {
@@ -58,37 +58,31 @@ func (m *MockDecisionService) GetFeatureDecision(decisionContext decision.Featur
5858

5959
func TestIsFeatureEnabled(t *testing.T) {
6060
testUserContext := entities.UserContext{ID: "test_user_1"}
61-
testFeatureKey := "test_feature_key"
62-
testFeature := entities.Feature{
63-
Key: testFeatureKey,
64-
FeatureExperiments: []entities.Experiment{
65-
entities.Experiment{
66-
ID: "111111",
67-
Variations: map[string]entities.Variation{
68-
"22222": entities.Variation{
69-
ID: "22222",
70-
Key: "22222",
71-
FeatureEnabled: true,
72-
},
73-
},
74-
},
75-
},
61+
testVariation := entities.Variation{
62+
ID: "22222",
63+
Key: "22222",
64+
FeatureEnabled: true,
7665
}
66+
testExperiment := entities.Experiment{
67+
ID: "111111",
68+
Variations: map[string]entities.Variation{"22222": testVariation},
69+
}
70+
testFeatureKey := "test_feature_key"
7771

7872
// Test happy path
7973
mockConfig := new(MockProjectConfig)
80-
mockConfig.On("GetFeatureByKey", testFeatureKey).Return(testFeature, nil)
81-
8274
mockConfigManager := new(MockProjectConfigManager)
8375
mockConfigManager.On("GetConfig").Return(mockConfig)
8476

8577
// Set up the mock decision service and its return value
8678
testDecisionContext := decision.FeatureDecisionContext{
87-
Feature: testFeature,
79+
FeatureKey: testFeatureKey,
80+
ProjectConfig: mockConfig,
8881
}
8982

9083
expectedFeatureDecision := decision.FeatureDecision{
91-
FeatureEnabled: true,
84+
Experiment: testExperiment,
85+
Variation: testVariation,
9286
Decision: decision.Decision{
9387
DecisionMade: true,
9488
},
@@ -127,15 +121,19 @@ func TestIsFeatureEnabledErrorCases(t *testing.T) {
127121
mockConfigManager.AssertNotCalled(t, "GetFeatureByKey")
128122
mockDecisionService.AssertNotCalled(t, "GetFeatureDecision")
129123

130-
// Test invalid feature key
124+
// Test decision serviceinvalid feature key
131125
expectedError := errors.New("Invalid feature key")
132126
mockConfig := new(MockProjectConfig)
133-
mockConfig.On("GetFeatureByKey", testFeatureKey).Return(entities.Feature{}, expectedError)
134127

135128
mockConfigManager = new(MockProjectConfigManager)
136129
mockConfigManager.On("GetConfig").Return(mockConfig)
137-
mockDecisionService = new(MockDecisionService)
138130

131+
testFeatureDecisionContext := decision.FeatureDecisionContext{
132+
FeatureKey: testFeatureKey,
133+
ProjectConfig: mockConfig,
134+
}
135+
mockDecisionService = new(MockDecisionService)
136+
mockDecisionService.On("GetFeatureDecision", testFeatureDecisionContext, testUserContext).Return(decision.FeatureDecision{}, expectedError)
139137
client = OptimizelyClient{
140138
configManager: mockConfigManager,
141139
decisionService: mockDecisionService,
@@ -146,4 +144,6 @@ func TestIsFeatureEnabledErrorCases(t *testing.T) {
146144
assert.Equal(t, expectedError, err)
147145
}
148146
assert.False(t, result)
147+
mockConfigManager.AssertExpectations(t)
148+
mockDecisionService.AssertExpectations(t)
149149
}

0 commit comments

Comments
 (0)