Skip to content

Commit 9c23077

Browse files
author
Mike Davis
authored
Add bootstrap sdk key config. (#75)
* Remove support for default client in client middleware. * Bootstrap SDK instances based on config.
1 parent 436bde6 commit 9c23077

File tree

5 files changed

+41
-46
lines changed

5 files changed

+41
-46
lines changed

pkg/api/middleware/cached.go

+4-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package middleware
1919

2020
import (
2121
"context"
22+
"fmt"
2223
"net/http"
2324

2425
"github.com/go-chi/chi"
@@ -49,18 +50,13 @@ type CachedOptlyMiddleware struct {
4950
// else the default OptlyClient will be used.
5051
func (ctx *CachedOptlyMiddleware) ClientCtx(next http.Handler) http.Handler {
5152
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
52-
5353
sdkKey := r.Header.Get(OptlySDKHeader)
54-
55-
GetLogger(r).Info().Msg("Fetching OptimizelyClient")
56-
var err error
57-
var optlyClient *optimizely.OptlyClient
5854
if sdkKey == "" {
59-
optlyClient, err = ctx.Cache.GetDefaultClient()
60-
} else {
61-
optlyClient, err = ctx.Cache.GetClient(sdkKey)
55+
http.Error(w, fmt.Sprintf("Missing required %s header", OptlySDKHeader), http.StatusBadRequest)
56+
return
6257
}
6358

59+
optlyClient, err := ctx.Cache.GetClient(sdkKey)
6460
if err != nil {
6561
GetLogger(r).Error().Err(err).Msg("Initializing OptimizelyClient")
6662
http.Error(w, "Failed to instantiate Optimizely", http.StatusInternalServerError)

pkg/api/middleware/cached_test.go

+3-7
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,6 @@ func (m *MockCache) GetClient(key string) (*optimizely.OptlyClient, error) {
4242
return args.Get(0).(*optimizely.OptlyClient), args.Error(1)
4343
}
4444

45-
func (m *MockCache) GetDefaultClient() (*optimizely.OptlyClient, error) {
46-
return &defaultClient, nil
47-
}
48-
4945
type OptlyMiddlewareTestSuite struct {
5046
suite.Suite
5147
mw *CachedOptlyMiddleware
@@ -68,15 +64,15 @@ func (suite *OptlyMiddlewareTestSuite) TestGetError() {
6864
suite.Equal(http.StatusInternalServerError, rec.Code)
6965
}
7066

71-
func (suite *OptlyMiddlewareTestSuite) TestGetDefault() {
67+
func (suite *OptlyMiddlewareTestSuite) TestGetClientMissingHeader() {
7268
handler := suite.mw.ClientCtx(AssertOptlyClientHandler(suite, &defaultClient))
7369
req := httptest.NewRequest("GET", "/", nil)
7470
rec := httptest.NewRecorder()
7571
handler.ServeHTTP(rec, req)
76-
suite.Equal(http.StatusOK, rec.Code)
72+
suite.Equal(http.StatusBadRequest, rec.Code)
7773
}
7874

79-
func (suite *OptlyMiddlewareTestSuite) TestGetExpected() {
75+
func (suite *OptlyMiddlewareTestSuite) TestGetClient() {
8076
handler := suite.mw.ClientCtx(AssertOptlyClientHandler(suite, &expectedClient))
8177
req := httptest.NewRequest("GET", "/", nil)
8278
req.Header.Add(OptlySDKHeader, "EXPECTED")

pkg/optimizely/cache.go

+24-18
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
package optimizely
1919

2020
import (
21-
"os"
22-
2321
"github.com/optimizely/go-sdk/pkg/config"
22+
"github.com/rs/zerolog/log"
23+
"github.com/spf13/viper"
2424

2525
"github.com/optimizely/go-sdk/pkg/client"
2626
"github.com/optimizely/go-sdk/pkg/decision"
@@ -30,26 +30,28 @@ import (
3030
// OptlyCache implements the Cache interface backed by a concurrent map.
3131
// The default OptlyClient lookup is based on supplied configuration via env variables.
3232
type OptlyCache struct {
33-
defaultKey string
34-
loader func(string) (*OptlyClient, error)
35-
optlyMap cmap.ConcurrentMap
33+
loader func(string) (*OptlyClient, error)
34+
optlyMap cmap.ConcurrentMap
3635
}
3736

3837
// NewCache returns a new implementation of OptlyCache interface backed by a concurrent map.
3938
func NewCache() *OptlyCache {
40-
// TODO replace with actual configuration component
41-
// If Map lookup are expensive we can store a direct reference to the "default" client.
42-
sdkKey := os.Getenv("SDK_KEY")
43-
return &OptlyCache{
44-
defaultKey: sdkKey,
45-
optlyMap: cmap.New(),
46-
loader: initOptlyClient,
39+
cache := &OptlyCache{
40+
optlyMap: cmap.New(),
41+
loader: initOptlyClient,
4742
}
43+
44+
cache.init()
45+
return cache
4846
}
4947

50-
// GetDefaultClient returns a default OptlyClient where the SDK Key is sourced via server configuration.
51-
func (c *OptlyCache) GetDefaultClient() (*OptlyClient, error) {
52-
return c.GetClient(c.defaultKey)
48+
func (c *OptlyCache) init() {
49+
sdkKeys := viper.GetStringSlice("optimizely.sdkKeys")
50+
for _, sdkKey := range sdkKeys {
51+
if _, err := c.GetClient(sdkKey); err != nil {
52+
log.Warn().Str("sdkKey", sdkKey).Msg("Failed to initialize Opimizely Client.")
53+
}
54+
}
5355
}
5456

5557
// GetClient is used to fetch an instance of the OptlyClient when the SDK Key is explicitly supplied.
@@ -61,7 +63,7 @@ func (c *OptlyCache) GetClient(sdkKey string) (*OptlyClient, error) {
6163

6264
oc, err := c.loader(sdkKey)
6365
if err != nil {
64-
return &OptlyClient{}, err
66+
return oc, err
6567
}
6668

6769
set := c.optlyMap.SetIfAbsent(sdkKey, oc)
@@ -75,10 +77,14 @@ func (c *OptlyCache) GetClient(sdkKey string) (*OptlyClient, error) {
7577
}
7678

7779
func initOptlyClient(sdkKey string) (*OptlyClient, error) {
78-
79-
optimizelyFactory := &client.OptimizelyFactory{}
80+
log.Info().Str("sdkKey", sdkKey).Msg("Loading Optimizely instance")
8081
configManager := config.NewPollingProjectConfigManager(sdkKey)
82+
if _, err := configManager.GetConfig(); err != nil {
83+
return &OptlyClient{}, err
84+
}
85+
8186
forcedVariations := decision.NewMapExperimentOverridesStore()
87+
optimizelyFactory := &client.OptimizelyFactory{}
8288
optimizelyClient, err := optimizelyFactory.Client(
8389
client.WithConfigManager(configManager),
8490
client.WithExperimentOverrides(forcedVariations),

pkg/optimizely/cache_test.go

+10-12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"testing"
2323

2424
cmap "github.com/orcaman/concurrent-map"
25+
"github.com/spf13/viper"
2526
"github.com/stretchr/testify/suite"
2627

2728
"github.com/optimizely/sidedoor/pkg/optimizelytest"
@@ -36,21 +37,11 @@ type CacheTestSuite struct {
3637

3738
func (suite *CacheTestSuite) SetupTest() {
3839
suite.cache = &OptlyCache{
39-
defaultKey: "default",
40-
loader: mockLoader,
41-
optlyMap: cmap.New(),
40+
loader: mockLoader,
41+
optlyMap: cmap.New(),
4242
}
4343
}
4444

45-
func (suite *CacheTestSuite) TestGetDefault() {
46-
optltyClient1, err1 := suite.cache.GetDefaultClient()
47-
optltyClient2, err2 := suite.cache.GetDefaultClient()
48-
49-
suite.NoError(err1)
50-
suite.NoError(err2)
51-
suite.Equal(optltyClient1, optltyClient2)
52-
}
53-
5445
func (suite *CacheTestSuite) TestGetCacheHit() {
5546
optltyClient1, err1 := suite.cache.GetClient("one")
5647
optltyClient2, err2 := suite.cache.GetClient("one")
@@ -74,6 +65,13 @@ func (suite *CacheTestSuite) TestGetError() {
7465
suite.Error(err1)
7566
}
7667

68+
func (suite *CacheTestSuite) TestInit() {
69+
viper.SetDefault("optimizely.sdkKeys", "one")
70+
suite.cache.init()
71+
suite.True(suite.cache.optlyMap.Has("one"))
72+
suite.False(suite.cache.optlyMap.Has("two"))
73+
}
74+
7775
// In order for 'go test' to run this suite, we need to create
7876
// a normal test function and pass our suite to suite.Run
7977
func TestCacheTestSuite(t *testing.T) {

pkg/optimizely/interface.go

-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,5 @@ package optimizely
1919

2020
// Cache defines a basic interface for retrieving an instance of the OptlyClient keyed off of the SDK Key
2121
type Cache interface {
22-
GetDefaultClient() (*OptlyClient, error)
2322
GetClient(sdkKey string) (*OptlyClient, error)
2423
}

0 commit comments

Comments
 (0)