Skip to content

Commit 098c7fa

Browse files
refac: put URL as a parameter for a requester method (#195)
refac: put URI as a parameter for a requester method (not the requester itself)
1 parent ab7cfc3 commit 098c7fa

File tree

8 files changed

+129
-133
lines changed

8 files changed

+129
-133
lines changed

pkg/client/factory.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func (f OptimizelyFactory) Client(clientOptions ...OptionFunc) (*OptimizelyClien
102102

103103
// Initialize the default services with the execution context
104104
if pollingConfigManager, ok := appClient.ConfigManager.(*config.PollingProjectConfigManager); ok {
105-
pollingConfigManager.Start(appClient.executionCtx)
105+
pollingConfigManager.Start(f.SDKKey, appClient.executionCtx)
106106
}
107107

108108
if batchProcessor, ok := appClient.EventProcessor.(*event.BatchEventProcessor); ok {

pkg/client/factory_test.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@ package client
1818

1919
import (
2020
"errors"
21-
"fmt"
22-
"log"
2321
"net/http"
24-
"net/http/httptest"
2522
"testing"
2623
"time"
2724

@@ -32,8 +29,19 @@ import (
3229
"github.com/optimizely/go-sdk/pkg/utils"
3330

3431
"github.com/stretchr/testify/assert"
32+
"github.com/stretchr/testify/mock"
3533
)
3634

35+
type MockRequester struct {
36+
utils.Requester
37+
mock.Mock
38+
}
39+
40+
func (m *MockRequester) Get(uri string, headers ...utils.Header) (response []byte, responseHeaders http.Header, code int, err error) {
41+
args := m.Called(headers)
42+
return args.Get(0).([]byte), args.Get(1).(http.Header), args.Int(2), args.Error(3)
43+
}
44+
3745
type MockDispatcher struct {
3846
Events []event.LogEvent
3947
}
@@ -75,16 +83,11 @@ func TestClientWithPollingConfigManager(t *testing.T) {
7583

7684
func TestClientWithPollingConfigManagerRequester(t *testing.T) {
7785

78-
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
79-
log.Print(">request: ", r)
80-
if r.URL.String() == "/good" {
81-
fmt.Fprintln(w, "Hello, client")
82-
}
83-
}))
84-
8586
factory := OptimizelyFactory{}
86-
requester := utils.NewHTTPRequester(ts.URL + "/good")
87-
optimizelyClient, err := factory.Client(WithPollingConfigManagerRequester(requester, time.Minute, nil))
87+
mockRequester := new(MockRequester)
88+
mockRequester.On("Get", []utils.Header(nil)).Return([]byte(`{"revision":"42"}`), http.Header{}, http.StatusOK, nil)
89+
90+
optimizelyClient, err := factory.Client(WithPollingConfigManagerRequester(mockRequester, time.Minute, nil))
8891
assert.NoError(t, err)
8992
assert.NotNil(t, optimizelyClient.ConfigManager)
9093
assert.NotNil(t, optimizelyClient.DecisionService)

pkg/config/polling_manager.go

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,25 @@ import (
3434
// DefaultPollingInterval sets default interval for polling manager
3535
const DefaultPollingInterval = 5 * time.Minute // default to 5 minutes for polling
3636

37-
// DatafileURLTemplate is used to construct the endpoint for retrieving the datafile from the CDN
38-
const DatafileURLTemplate = "https://cdn.optimizely.com/datafiles/%s.json"
39-
4037
// ModifiedSince header key for request
4138
const ModifiedSince = "If-Modified-Since"
4239

4340
// LastModified header key for response
4441
const LastModified = "Last-Modified"
4542

43+
// DatafileURLTemplate is used to construct the endpoint for retrieving the datafile from the CDN
44+
const DatafileURLTemplate = "https://cdn.optimizely.com/datafiles/%s.json"
45+
4646
var cmLogger = logging.GetLogger("PollingConfigManager")
4747

4848
// PollingProjectConfigManager maintains a dynamic copy of the project config
4949
type PollingProjectConfigManager struct {
50-
requester utils.Requester
51-
pollingInterval time.Duration
52-
notificationCenter notification.Center
53-
initDatafile []byte
54-
lastModified string
50+
requester utils.Requester
51+
pollingInterval time.Duration
52+
notificationCenter notification.Center
53+
initDatafile []byte
54+
lastModified string
55+
datafileURLTemplate string
5556

5657
configLock sync.RWMutex
5758
err error
@@ -61,21 +62,17 @@ type PollingProjectConfigManager struct {
6162
// OptionFunc is a type to a proper func
6263
type OptionFunc func(*PollingProjectConfigManager)
6364

64-
// DefaultRequester is an optional function, sets default requester based on a key.
65-
func DefaultRequester(sdkKey string) OptionFunc {
65+
// Requester is an optional function, sets a passed requester
66+
func Requester(requester utils.Requester) OptionFunc {
6667
return func(p *PollingProjectConfigManager) {
67-
68-
url := fmt.Sprintf(DatafileURLTemplate, sdkKey)
69-
requester := utils.NewHTTPRequester(url)
70-
7168
p.requester = requester
7269
}
7370
}
7471

75-
// Requester is an optional function, sets a passed requester
76-
func Requester(requester utils.Requester) OptionFunc {
72+
// DatafileTemplate is an optional function, sets a passed datafile URL template
73+
func DatafileTemplate(datafileTemplate string) OptionFunc {
7774
return func(p *PollingProjectConfigManager) {
78-
p.requester = requester
75+
p.datafileURLTemplate = datafileTemplate
7976
}
8077
}
8178

@@ -94,7 +91,7 @@ func InitialDatafile(datafile []byte) OptionFunc {
9491
}
9592

9693
// SyncConfig gets current datafile and updates projectConfig
97-
func (cm *PollingProjectConfigManager) SyncConfig(datafile []byte) {
94+
func (cm *PollingProjectConfigManager) SyncConfig(sdkKey string, datafile []byte) {
9895
var e error
9996
var code int
10097
var respHeaders http.Header
@@ -104,12 +101,13 @@ func (cm *PollingProjectConfigManager) SyncConfig(datafile []byte) {
104101
cm.configLock.Unlock()
105102
}
106103

104+
url := fmt.Sprintf(cm.datafileURLTemplate, sdkKey)
107105
if len(datafile) == 0 {
108106
if cm.lastModified != "" {
109107
lastModifiedHeader := utils.Header{Name: ModifiedSince, Value: cm.lastModified}
110-
datafile, respHeaders, code, e = cm.requester.Get(lastModifiedHeader)
108+
datafile, respHeaders, code, e = cm.requester.Get(url, lastModifiedHeader)
111109
} else {
112-
datafile, respHeaders, code, e = cm.requester.Get()
110+
datafile, respHeaders, code, e = cm.requester.Get(url)
113111
}
114112

115113
if e != nil {
@@ -168,14 +166,14 @@ func (cm *PollingProjectConfigManager) SyncConfig(datafile []byte) {
168166
}
169167

170168
// Start starts the polling
171-
func (cm *PollingProjectConfigManager) Start(exeCtx utils.ExecutionCtx) {
169+
func (cm *PollingProjectConfigManager) Start(sdkKey string, exeCtx utils.ExecutionCtx) {
172170
go func() {
173171
cmLogger.Debug("Polling Config Manager Initiated")
174172
t := time.NewTicker(cm.pollingInterval)
175173
for {
176174
select {
177175
case <-t.C:
178-
cm.SyncConfig([]byte{})
176+
cm.SyncConfig(sdkKey, []byte{})
179177
case <-exeCtx.GetContext().Done():
180178
cmLogger.Debug("Polling Config Manager Stopped")
181179
return
@@ -186,20 +184,20 @@ func (cm *PollingProjectConfigManager) Start(exeCtx utils.ExecutionCtx) {
186184

187185
// NewPollingProjectConfigManager returns an instance of the polling config manager with the customized configuration
188186
func NewPollingProjectConfigManager(sdkKey string, pollingMangerOptions ...OptionFunc) *PollingProjectConfigManager {
189-
url := fmt.Sprintf(DatafileURLTemplate, sdkKey)
190187

191188
pollingProjectConfigManager := PollingProjectConfigManager{
192-
notificationCenter: registry.GetNotificationCenter(sdkKey),
193-
pollingInterval: DefaultPollingInterval,
194-
requester: utils.NewHTTPRequester(url),
189+
notificationCenter: registry.GetNotificationCenter(sdkKey),
190+
pollingInterval: DefaultPollingInterval,
191+
requester: utils.NewHTTPRequester(),
192+
datafileURLTemplate: DatafileURLTemplate,
195193
}
196194

197195
for _, opt := range pollingMangerOptions {
198196
opt(&pollingProjectConfigManager)
199197
}
200198

201199
initDatafile := pollingProjectConfigManager.initDatafile
202-
pollingProjectConfigManager.SyncConfig(initDatafile) // initial poll
200+
pollingProjectConfigManager.SyncConfig(sdkKey, initDatafile) // initial poll
203201
return &pollingProjectConfigManager
204202
}
205203

pkg/config/polling_manager_test.go

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ type MockRequester struct {
3434
mock.Mock
3535
}
3636

37-
func (m *MockRequester) Get(headers ...utils.Header) (response []byte, responseHeaders http.Header, code int, err error) {
37+
func (m *MockRequester) Get(uri string, headers ...utils.Header) (response []byte, responseHeaders http.Header, code int, err error) {
3838
args := m.Called(headers)
3939
return args.Get(0).([]byte), args.Get(1).(http.Header), args.Int(2), args.Error(3)
4040
}
@@ -51,7 +51,7 @@ func TestNewPollingProjectConfigManagerWithOptions(t *testing.T) {
5151

5252
exeCtx := utils.NewCancelableExecutionCtx()
5353
configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester))
54-
configManager.Start(exeCtx)
54+
configManager.Start(sdkKey, exeCtx)
5555
mockRequester.AssertExpectations(t)
5656

5757
actual, err := configManager.GetConfig()
@@ -72,7 +72,7 @@ func TestNewPollingProjectConfigManagerWithNull(t *testing.T) {
7272

7373
exeCtx := utils.NewCancelableExecutionCtx()
7474
configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester))
75-
configManager.Start(exeCtx)
75+
configManager.Start(sdkKey, exeCtx)
7676
mockRequester.AssertExpectations(t)
7777

7878
_, err := configManager.GetConfig()
@@ -90,15 +90,15 @@ func TestNewPollingProjectConfigManagerWithSimilarDatafileRevisions(t *testing.T
9090

9191
exeCtx := utils.NewCancelableExecutionCtx()
9292
configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester))
93-
configManager.Start(exeCtx)
93+
configManager.Start(sdkKey, exeCtx)
9494
mockRequester.AssertExpectations(t)
9595

9696
actual, err := configManager.GetConfig()
9797
assert.Nil(t, err)
9898
assert.NotNil(t, actual)
9999
assert.Equal(t, projectConfig1, actual)
100100

101-
configManager.SyncConfig(mockDatafile2)
101+
configManager.SyncConfig(sdkKey, mockDatafile2)
102102
actual, err = configManager.GetConfig()
103103
assert.Equal(t, projectConfig1, actual)
104104
}
@@ -118,7 +118,7 @@ func TestNewPollingProjectConfigManagerWithLastModifiedDates(t *testing.T) {
118118

119119
exeCtx := utils.NewCancelableExecutionCtx()
120120
configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester))
121-
configManager.Start(exeCtx)
121+
configManager.Start(sdkKey, exeCtx)
122122

123123
// Fetch valid config
124124
actual, err := configManager.GetConfig()
@@ -127,7 +127,7 @@ func TestNewPollingProjectConfigManagerWithLastModifiedDates(t *testing.T) {
127127
assert.Equal(t, projectConfig1, actual)
128128

129129
// Sync and check no changes were made to the previous config because of 304 error code
130-
configManager.SyncConfig([]byte{})
130+
configManager.SyncConfig(sdkKey, []byte{})
131131
actual, err = configManager.GetConfig()
132132
assert.Nil(t, err)
133133
assert.NotNil(t, actual)
@@ -148,15 +148,15 @@ func TestNewPollingProjectConfigManagerWithDifferentDatafileRevisions(t *testing
148148

149149
exeCtx := utils.NewCancelableExecutionCtx()
150150
configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester))
151-
configManager.Start(exeCtx)
151+
configManager.Start(sdkKey, exeCtx)
152152
mockRequester.AssertExpectations(t)
153153

154154
actual, err := configManager.GetConfig()
155155
assert.Nil(t, err)
156156
assert.NotNil(t, actual)
157157
assert.Equal(t, projectConfig1, actual)
158158

159-
configManager.SyncConfig(mockDatafile2)
159+
configManager.SyncConfig(sdkKey, mockDatafile2)
160160
actual, err = configManager.GetConfig()
161161
assert.Equal(t, projectConfig2, actual)
162162
}
@@ -175,20 +175,20 @@ func TestNewPollingProjectConfigManagerWithErrorHandling(t *testing.T) {
175175

176176
exeCtx := utils.NewCancelableExecutionCtx()
177177
configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester))
178-
configManager.Start(exeCtx)
178+
configManager.Start(sdkKey, exeCtx)
179179
mockRequester.AssertExpectations(t)
180180

181181
actual, err := configManager.GetConfig() // polling for bad file
182182
assert.NotNil(t, err)
183183
assert.Nil(t, actual)
184184
assert.Nil(t, projectConfig1)
185185

186-
configManager.SyncConfig(mockDatafile2) // polling for good file
186+
configManager.SyncConfig(sdkKey, mockDatafile2) // polling for good file
187187
actual, err = configManager.GetConfig()
188188
assert.Nil(t, err)
189189
assert.Equal(t, projectConfig2, actual)
190190

191-
configManager.SyncConfig(mockDatafile1) // polling for bad file, error not null but good project
191+
configManager.SyncConfig(sdkKey, mockDatafile1) // polling for bad file, error not null but good project
192192
actual, err = configManager.GetConfig()
193193
assert.Nil(t, err)
194194
assert.Equal(t, projectConfig2, actual)
@@ -206,7 +206,7 @@ func TestNewPollingProjectConfigManagerOnDecision(t *testing.T) {
206206

207207
exeCtx := utils.NewCancelableExecutionCtx()
208208
configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester))
209-
configManager.Start(exeCtx)
209+
configManager.Start(sdkKey, exeCtx)
210210

211211
var numberOfCalls = 0
212212
callback := func(notification notification.ProjectConfigUpdateNotification) {
@@ -219,7 +219,7 @@ func TestNewPollingProjectConfigManagerOnDecision(t *testing.T) {
219219
assert.Nil(t, err)
220220
assert.NotNil(t, actual)
221221

222-
configManager.SyncConfig(mockDatafile2)
222+
configManager.SyncConfig(sdkKey, mockDatafile2)
223223
actual, err = configManager.GetConfig()
224224
assert.Nil(t, err)
225225
assert.NotNil(t, actual)
@@ -234,37 +234,32 @@ func TestNewPollingProjectConfigManagerOnDecision(t *testing.T) {
234234
assert.Nil(t, err)
235235
}
236236

237-
func TestDefaultRequester(t *testing.T) {
238-
239-
sdkKey := "test_sdk_key"
240-
DefaultRequester(sdkKey)
241-
exeCtx := utils.NewCancelableExecutionCtx()
242-
configManager := NewPollingProjectConfigManager(sdkKey, DefaultRequester(sdkKey))
243-
configManager.Start(exeCtx)
244-
245-
requester := configManager.requester
246-
assert.NotNil(t, requester)
247-
assert.Equal(t, requester.String(), "{url: https://cdn.optimizely.com/datafiles/test_sdk_key.json, timeout: 5s, retries: 1}")
248-
}
249-
250237
func TestPollingInterval(t *testing.T) {
251238

252239
sdkKey := "test_sdk_key"
253-
DefaultRequester(sdkKey)
240+
254241
exeCtx := utils.NewCancelableExecutionCtx()
255242
configManager := NewPollingProjectConfigManager(sdkKey, PollingInterval(5*time.Second))
256-
configManager.Start(exeCtx)
243+
configManager.Start(sdkKey, exeCtx)
257244

258245
assert.Equal(t, configManager.pollingInterval, 5*time.Second)
259246
}
260247

261248
func TestInitialDatafile(t *testing.T) {
262249

263250
sdkKey := "test_sdk_key"
264-
DefaultRequester(sdkKey)
265251
exeCtx := utils.NewCancelableExecutionCtx()
266252
configManager := NewPollingProjectConfigManager(sdkKey, InitialDatafile([]byte("test")))
267-
configManager.Start(exeCtx)
253+
configManager.Start(sdkKey, exeCtx)
268254

269255
assert.Equal(t, configManager.initDatafile, []byte("test"))
270256
}
257+
258+
func TestDatafileTemplate(t *testing.T) {
259+
260+
sdkKey := "test_sdk_key"
261+
datafileTemplate := "https://localhost/v1/%s.json"
262+
configManager := NewPollingProjectConfigManager(sdkKey, DatafileTemplate(datafileTemplate))
263+
264+
assert.Equal(t, datafileTemplate, configManager.datafileURLTemplate)
265+
}

pkg/config/static_manager.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ type StaticProjectConfigManager struct {
3737
// NewStaticProjectConfigManagerFromURL returns new instance of StaticProjectConfigManager for URL
3838
func NewStaticProjectConfigManagerFromURL(sdkKey string) (*StaticProjectConfigManager, error) {
3939

40-
requester := utils.NewHTTPRequester(fmt.Sprintf(DatafileURLTemplate, sdkKey))
41-
datafile, _, code, e := requester.Get()
40+
requester := utils.NewHTTPRequester()
41+
42+
url := fmt.Sprintf(DatafileURLTemplate, sdkKey)
43+
datafile, _, code, e := requester.Get(url)
4244
if e != nil {
4345
cmLogger.Error(fmt.Sprintf("request returned with http code=%d", code), e)
4446
return nil, e

pkg/event/dispatcher.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ type HTTPEventDispatcher struct {
4646
// DispatchEvent dispatches event with callback
4747
func (*HTTPEventDispatcher) DispatchEvent(event LogEvent) (bool, error) {
4848

49-
requester := utils.NewHTTPRequester(event.EndPoint)
50-
_, _, code, err := requester.Post(event.Event)
49+
requester := utils.NewHTTPRequester()
50+
_, _, code, err := requester.Post(event.EndPoint, event.Event)
5151

5252
// also check response codes
5353
// resp.StatusCode == 400 is an error

0 commit comments

Comments
 (0)