diff --git a/pkg/client/factory.go b/pkg/client/factory.go index bdf3f7f54..01382f7d9 100644 --- a/pkg/client/factory.go +++ b/pkg/client/factory.go @@ -102,7 +102,7 @@ func (f OptimizelyFactory) Client(clientOptions ...OptionFunc) (*OptimizelyClien // Initialize the default services with the execution context if pollingConfigManager, ok := appClient.ConfigManager.(*config.PollingProjectConfigManager); ok { - pollingConfigManager.Start(appClient.executionCtx) + pollingConfigManager.Start(f.SDKKey, appClient.executionCtx) } if batchProcessor, ok := appClient.EventProcessor.(*event.BatchEventProcessor); ok { diff --git a/pkg/client/factory_test.go b/pkg/client/factory_test.go index b23cc0dcc..21e72775d 100644 --- a/pkg/client/factory_test.go +++ b/pkg/client/factory_test.go @@ -18,10 +18,7 @@ package client import ( "errors" - "fmt" - "log" "net/http" - "net/http/httptest" "testing" "time" @@ -32,8 +29,19 @@ import ( "github.com/optimizely/go-sdk/pkg/utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) +type MockRequester struct { + utils.Requester + mock.Mock +} + +func (m *MockRequester) Get(uri string, headers ...utils.Header) (response []byte, responseHeaders http.Header, code int, err error) { + args := m.Called(headers) + return args.Get(0).([]byte), args.Get(1).(http.Header), args.Int(2), args.Error(3) +} + type MockDispatcher struct { Events []event.LogEvent } @@ -75,16 +83,11 @@ func TestClientWithPollingConfigManager(t *testing.T) { func TestClientWithPollingConfigManagerRequester(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - log.Print(">request: ", r) - if r.URL.String() == "/good" { - fmt.Fprintln(w, "Hello, client") - } - })) - factory := OptimizelyFactory{} - requester := utils.NewHTTPRequester(ts.URL + "/good") - optimizelyClient, err := factory.Client(WithPollingConfigManagerRequester(requester, time.Minute, nil)) + mockRequester := new(MockRequester) + mockRequester.On("Get", []utils.Header(nil)).Return([]byte(`{"revision":"42"}`), http.Header{}, http.StatusOK, nil) + + optimizelyClient, err := factory.Client(WithPollingConfigManagerRequester(mockRequester, time.Minute, nil)) assert.NoError(t, err) assert.NotNil(t, optimizelyClient.ConfigManager) assert.NotNil(t, optimizelyClient.DecisionService) diff --git a/pkg/config/polling_manager.go b/pkg/config/polling_manager.go index 85bc3f54b..968a7303a 100644 --- a/pkg/config/polling_manager.go +++ b/pkg/config/polling_manager.go @@ -34,24 +34,25 @@ import ( // DefaultPollingInterval sets default interval for polling manager const DefaultPollingInterval = 5 * time.Minute // default to 5 minutes for polling -// DatafileURLTemplate is used to construct the endpoint for retrieving the datafile from the CDN -const DatafileURLTemplate = "https://cdn.optimizely.com/datafiles/%s.json" - // ModifiedSince header key for request const ModifiedSince = "If-Modified-Since" // LastModified header key for response const LastModified = "Last-Modified" +// DatafileURLTemplate is used to construct the endpoint for retrieving the datafile from the CDN +const DatafileURLTemplate = "https://cdn.optimizely.com/datafiles/%s.json" + var cmLogger = logging.GetLogger("PollingConfigManager") // PollingProjectConfigManager maintains a dynamic copy of the project config type PollingProjectConfigManager struct { - requester utils.Requester - pollingInterval time.Duration - notificationCenter notification.Center - initDatafile []byte - lastModified string + requester utils.Requester + pollingInterval time.Duration + notificationCenter notification.Center + initDatafile []byte + lastModified string + datafileURLTemplate string configLock sync.RWMutex err error @@ -61,21 +62,17 @@ type PollingProjectConfigManager struct { // OptionFunc is a type to a proper func type OptionFunc func(*PollingProjectConfigManager) -// DefaultRequester is an optional function, sets default requester based on a key. -func DefaultRequester(sdkKey string) OptionFunc { +// Requester is an optional function, sets a passed requester +func Requester(requester utils.Requester) OptionFunc { return func(p *PollingProjectConfigManager) { - - url := fmt.Sprintf(DatafileURLTemplate, sdkKey) - requester := utils.NewHTTPRequester(url) - p.requester = requester } } -// Requester is an optional function, sets a passed requester -func Requester(requester utils.Requester) OptionFunc { +// DatafileTemplate is an optional function, sets a passed datafile URL template +func DatafileTemplate(datafileTemplate string) OptionFunc { return func(p *PollingProjectConfigManager) { - p.requester = requester + p.datafileURLTemplate = datafileTemplate } } @@ -94,7 +91,7 @@ func InitialDatafile(datafile []byte) OptionFunc { } // SyncConfig gets current datafile and updates projectConfig -func (cm *PollingProjectConfigManager) SyncConfig(datafile []byte) { +func (cm *PollingProjectConfigManager) SyncConfig(sdkKey string, datafile []byte) { var e error var code int var respHeaders http.Header @@ -104,12 +101,13 @@ func (cm *PollingProjectConfigManager) SyncConfig(datafile []byte) { cm.configLock.Unlock() } + url := fmt.Sprintf(cm.datafileURLTemplate, sdkKey) if len(datafile) == 0 { if cm.lastModified != "" { lastModifiedHeader := utils.Header{Name: ModifiedSince, Value: cm.lastModified} - datafile, respHeaders, code, e = cm.requester.Get(lastModifiedHeader) + datafile, respHeaders, code, e = cm.requester.Get(url, lastModifiedHeader) } else { - datafile, respHeaders, code, e = cm.requester.Get() + datafile, respHeaders, code, e = cm.requester.Get(url) } if e != nil { @@ -168,14 +166,14 @@ func (cm *PollingProjectConfigManager) SyncConfig(datafile []byte) { } // Start starts the polling -func (cm *PollingProjectConfigManager) Start(exeCtx utils.ExecutionCtx) { +func (cm *PollingProjectConfigManager) Start(sdkKey string, exeCtx utils.ExecutionCtx) { go func() { cmLogger.Debug("Polling Config Manager Initiated") t := time.NewTicker(cm.pollingInterval) for { select { case <-t.C: - cm.SyncConfig([]byte{}) + cm.SyncConfig(sdkKey, []byte{}) case <-exeCtx.GetContext().Done(): cmLogger.Debug("Polling Config Manager Stopped") return @@ -186,12 +184,12 @@ func (cm *PollingProjectConfigManager) Start(exeCtx utils.ExecutionCtx) { // NewPollingProjectConfigManager returns an instance of the polling config manager with the customized configuration func NewPollingProjectConfigManager(sdkKey string, pollingMangerOptions ...OptionFunc) *PollingProjectConfigManager { - url := fmt.Sprintf(DatafileURLTemplate, sdkKey) pollingProjectConfigManager := PollingProjectConfigManager{ - notificationCenter: registry.GetNotificationCenter(sdkKey), - pollingInterval: DefaultPollingInterval, - requester: utils.NewHTTPRequester(url), + notificationCenter: registry.GetNotificationCenter(sdkKey), + pollingInterval: DefaultPollingInterval, + requester: utils.NewHTTPRequester(), + datafileURLTemplate: DatafileURLTemplate, } for _, opt := range pollingMangerOptions { @@ -199,7 +197,7 @@ func NewPollingProjectConfigManager(sdkKey string, pollingMangerOptions ...Optio } initDatafile := pollingProjectConfigManager.initDatafile - pollingProjectConfigManager.SyncConfig(initDatafile) // initial poll + pollingProjectConfigManager.SyncConfig(sdkKey, initDatafile) // initial poll return &pollingProjectConfigManager } diff --git a/pkg/config/polling_manager_test.go b/pkg/config/polling_manager_test.go index 3512db60c..cdd0f0765 100644 --- a/pkg/config/polling_manager_test.go +++ b/pkg/config/polling_manager_test.go @@ -34,7 +34,7 @@ type MockRequester struct { mock.Mock } -func (m *MockRequester) Get(headers ...utils.Header) (response []byte, responseHeaders http.Header, code int, err error) { +func (m *MockRequester) Get(uri string, headers ...utils.Header) (response []byte, responseHeaders http.Header, code int, err error) { args := m.Called(headers) return args.Get(0).([]byte), args.Get(1).(http.Header), args.Int(2), args.Error(3) } @@ -51,7 +51,7 @@ func TestNewPollingProjectConfigManagerWithOptions(t *testing.T) { exeCtx := utils.NewCancelableExecutionCtx() configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester)) - configManager.Start(exeCtx) + configManager.Start(sdkKey, exeCtx) mockRequester.AssertExpectations(t) actual, err := configManager.GetConfig() @@ -72,7 +72,7 @@ func TestNewPollingProjectConfigManagerWithNull(t *testing.T) { exeCtx := utils.NewCancelableExecutionCtx() configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester)) - configManager.Start(exeCtx) + configManager.Start(sdkKey, exeCtx) mockRequester.AssertExpectations(t) _, err := configManager.GetConfig() @@ -90,7 +90,7 @@ func TestNewPollingProjectConfigManagerWithSimilarDatafileRevisions(t *testing.T exeCtx := utils.NewCancelableExecutionCtx() configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester)) - configManager.Start(exeCtx) + configManager.Start(sdkKey, exeCtx) mockRequester.AssertExpectations(t) actual, err := configManager.GetConfig() @@ -98,7 +98,7 @@ func TestNewPollingProjectConfigManagerWithSimilarDatafileRevisions(t *testing.T assert.NotNil(t, actual) assert.Equal(t, projectConfig1, actual) - configManager.SyncConfig(mockDatafile2) + configManager.SyncConfig(sdkKey, mockDatafile2) actual, err = configManager.GetConfig() assert.Equal(t, projectConfig1, actual) } @@ -118,7 +118,7 @@ func TestNewPollingProjectConfigManagerWithLastModifiedDates(t *testing.T) { exeCtx := utils.NewCancelableExecutionCtx() configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester)) - configManager.Start(exeCtx) + configManager.Start(sdkKey, exeCtx) // Fetch valid config actual, err := configManager.GetConfig() @@ -127,7 +127,7 @@ func TestNewPollingProjectConfigManagerWithLastModifiedDates(t *testing.T) { assert.Equal(t, projectConfig1, actual) // Sync and check no changes were made to the previous config because of 304 error code - configManager.SyncConfig([]byte{}) + configManager.SyncConfig(sdkKey, []byte{}) actual, err = configManager.GetConfig() assert.Nil(t, err) assert.NotNil(t, actual) @@ -148,7 +148,7 @@ func TestNewPollingProjectConfigManagerWithDifferentDatafileRevisions(t *testing exeCtx := utils.NewCancelableExecutionCtx() configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester)) - configManager.Start(exeCtx) + configManager.Start(sdkKey, exeCtx) mockRequester.AssertExpectations(t) actual, err := configManager.GetConfig() @@ -156,7 +156,7 @@ func TestNewPollingProjectConfigManagerWithDifferentDatafileRevisions(t *testing assert.NotNil(t, actual) assert.Equal(t, projectConfig1, actual) - configManager.SyncConfig(mockDatafile2) + configManager.SyncConfig(sdkKey, mockDatafile2) actual, err = configManager.GetConfig() assert.Equal(t, projectConfig2, actual) } @@ -175,7 +175,7 @@ func TestNewPollingProjectConfigManagerWithErrorHandling(t *testing.T) { exeCtx := utils.NewCancelableExecutionCtx() configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester)) - configManager.Start(exeCtx) + configManager.Start(sdkKey, exeCtx) mockRequester.AssertExpectations(t) actual, err := configManager.GetConfig() // polling for bad file @@ -183,12 +183,12 @@ func TestNewPollingProjectConfigManagerWithErrorHandling(t *testing.T) { assert.Nil(t, actual) assert.Nil(t, projectConfig1) - configManager.SyncConfig(mockDatafile2) // polling for good file + configManager.SyncConfig(sdkKey, mockDatafile2) // polling for good file actual, err = configManager.GetConfig() assert.Nil(t, err) assert.Equal(t, projectConfig2, actual) - configManager.SyncConfig(mockDatafile1) // polling for bad file, error not null but good project + configManager.SyncConfig(sdkKey, mockDatafile1) // polling for bad file, error not null but good project actual, err = configManager.GetConfig() assert.Nil(t, err) assert.Equal(t, projectConfig2, actual) @@ -206,7 +206,7 @@ func TestNewPollingProjectConfigManagerOnDecision(t *testing.T) { exeCtx := utils.NewCancelableExecutionCtx() configManager := NewPollingProjectConfigManager(sdkKey, Requester(mockRequester)) - configManager.Start(exeCtx) + configManager.Start(sdkKey, exeCtx) var numberOfCalls = 0 callback := func(notification notification.ProjectConfigUpdateNotification) { @@ -219,7 +219,7 @@ func TestNewPollingProjectConfigManagerOnDecision(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, actual) - configManager.SyncConfig(mockDatafile2) + configManager.SyncConfig(sdkKey, mockDatafile2) actual, err = configManager.GetConfig() assert.Nil(t, err) assert.NotNil(t, actual) @@ -234,26 +234,13 @@ func TestNewPollingProjectConfigManagerOnDecision(t *testing.T) { assert.Nil(t, err) } -func TestDefaultRequester(t *testing.T) { - - sdkKey := "test_sdk_key" - DefaultRequester(sdkKey) - exeCtx := utils.NewCancelableExecutionCtx() - configManager := NewPollingProjectConfigManager(sdkKey, DefaultRequester(sdkKey)) - configManager.Start(exeCtx) - - requester := configManager.requester - assert.NotNil(t, requester) - assert.Equal(t, requester.String(), "{url: https://cdn.optimizely.com/datafiles/test_sdk_key.json, timeout: 5s, retries: 1}") -} - func TestPollingInterval(t *testing.T) { sdkKey := "test_sdk_key" - DefaultRequester(sdkKey) + exeCtx := utils.NewCancelableExecutionCtx() configManager := NewPollingProjectConfigManager(sdkKey, PollingInterval(5*time.Second)) - configManager.Start(exeCtx) + configManager.Start(sdkKey, exeCtx) assert.Equal(t, configManager.pollingInterval, 5*time.Second) } @@ -261,10 +248,18 @@ func TestPollingInterval(t *testing.T) { func TestInitialDatafile(t *testing.T) { sdkKey := "test_sdk_key" - DefaultRequester(sdkKey) exeCtx := utils.NewCancelableExecutionCtx() configManager := NewPollingProjectConfigManager(sdkKey, InitialDatafile([]byte("test"))) - configManager.Start(exeCtx) + configManager.Start(sdkKey, exeCtx) assert.Equal(t, configManager.initDatafile, []byte("test")) } + +func TestDatafileTemplate(t *testing.T) { + + sdkKey := "test_sdk_key" + datafileTemplate := "https://localhost/v1/%s.json" + configManager := NewPollingProjectConfigManager(sdkKey, DatafileTemplate(datafileTemplate)) + + assert.Equal(t, datafileTemplate, configManager.datafileURLTemplate) +} diff --git a/pkg/config/static_manager.go b/pkg/config/static_manager.go index 3b7bddfdf..08c975250 100644 --- a/pkg/config/static_manager.go +++ b/pkg/config/static_manager.go @@ -37,8 +37,10 @@ type StaticProjectConfigManager struct { // NewStaticProjectConfigManagerFromURL returns new instance of StaticProjectConfigManager for URL func NewStaticProjectConfigManagerFromURL(sdkKey string) (*StaticProjectConfigManager, error) { - requester := utils.NewHTTPRequester(fmt.Sprintf(DatafileURLTemplate, sdkKey)) - datafile, _, code, e := requester.Get() + requester := utils.NewHTTPRequester() + + url := fmt.Sprintf(DatafileURLTemplate, sdkKey) + datafile, _, code, e := requester.Get(url) if e != nil { cmLogger.Error(fmt.Sprintf("request returned with http code=%d", code), e) return nil, e diff --git a/pkg/event/dispatcher.go b/pkg/event/dispatcher.go index 2a4da9b14..dea882bb7 100644 --- a/pkg/event/dispatcher.go +++ b/pkg/event/dispatcher.go @@ -46,8 +46,8 @@ type HTTPEventDispatcher struct { // DispatchEvent dispatches event with callback func (*HTTPEventDispatcher) DispatchEvent(event LogEvent) (bool, error) { - requester := utils.NewHTTPRequester(event.EndPoint) - _, _, code, err := requester.Post(event.Event) + requester := utils.NewHTTPRequester() + _, _, code, err := requester.Post(event.EndPoint, event.Event) // also check response codes // resp.StatusCode == 400 is an error diff --git a/pkg/utils/requester.go b/pkg/utils/requester.go index c4220c3c6..036aac818 100644 --- a/pkg/utils/requester.go +++ b/pkg/utils/requester.go @@ -38,11 +38,11 @@ var json = jsoniter.ConfigCompatibleWithStandardLibrary // Requester is used to make outbound requests with type Requester interface { - Get(...Header) (response []byte, responseHeaders http.Header, code int, err error) - GetObj(result interface{}, headers ...Header) error + Get(url string, headers ...Header) (response []byte, responseHeaders http.Header, code int, err error) + GetObj(url string, result interface{}, headers ...Header) error - Post(body interface{}, headers ...Header) (response []byte, responseHeaders http.Header, code int, err error) - PostObj(body interface{}, result interface{}, headers ...Header) error + Post(url string, body interface{}, headers ...Header) (response []byte, responseHeaders http.Header, code int, err error) + PostObj(url string, body interface{}, result interface{}, headers ...Header) error String() string } @@ -76,18 +76,16 @@ func Headers(headers ...Header) func(r *HTTPRequester) { // HTTPRequester contains main info type HTTPRequester struct { - url string client http.Client retries int headers []Header } // NewHTTPRequester makes Requester with api and parameters. Sets defaults -// url has a complete url of the request like https://cdn.optimizely.com/datafiles/24234.json -func NewHTTPRequester(url string, params ...func(*HTTPRequester)) *HTTPRequester { +// api has the base part of request's url, like http://localhost/api/v1 +func NewHTTPRequester(params ...func(*HTTPRequester)) *HTTPRequester { res := HTTPRequester{ - url: url, retries: 1, headers: []Header{{"Content-Type", "application/json"}, {"Accept", "application/json"}}, client: http.Client{Timeout: defaultTTL}, @@ -100,14 +98,13 @@ func NewHTTPRequester(url string, params ...func(*HTTPRequester)) *HTTPRequester } // Get executes HTTP GET with url and optional extra headers, returns body in []bytes -// url created as url+sdkKey.json -func (r HTTPRequester) Get(headers ...Header) (response []byte, responseHeaders http.Header, code int, err error) { - return r.Do("GET", nil, headers) +func (r HTTPRequester) Get(url string, headers ...Header) (response []byte, responseHeaders http.Header, code int, err error) { + return r.Do(url, "GET", nil, headers) } // GetObj executes HTTP GET with url and optional extra headers, returns filled object -func (r HTTPRequester) GetObj(result interface{}, headers ...Header) error { - b, _, _, err := r.Do("GET", nil, headers) +func (r HTTPRequester) GetObj(url string, result interface{}, headers ...Header) error { + b, _, _, err := r.Do(url, "GET", nil, headers) if err != nil { return err } @@ -115,25 +112,25 @@ func (r HTTPRequester) GetObj(result interface{}, headers ...Header) error { } // Post executes HTTP POST with url, body and optional extra headers -func (r HTTPRequester) Post(body interface{}, headers ...Header) (response []byte, responseHeaders http.Header, code int, err error) { +func (r HTTPRequester) Post(url string, body interface{}, headers ...Header) (response []byte, responseHeaders http.Header, code int, err error) { b, err := json.Marshal(body) if err != nil { return nil, nil, http.StatusBadRequest, err } - return r.Do("POST", bytes.NewBuffer(b), headers) + return r.Do(url, "POST", bytes.NewBuffer(b), headers) } -// PostObj executes HTTP POST with uri, body and optional extra headers. Returns filled object -func (r HTTPRequester) PostObj(body, result interface{}, headers ...Header) error { - b, _, _, err := r.Post(body, headers...) +// PostObj executes HTTP POST with url, body and optional extra headers. Returns filled object +func (r HTTPRequester) PostObj(url string, body, result interface{}, headers ...Header) error { + b, _, _, err := r.Post(url, body, headers...) if err != nil { return err } return json.Unmarshal(b, result) } -// Do executes request and returns response body for requested uri (sdkKey.json). -func (r HTTPRequester) Do(method string, body io.Reader, headers []Header) (response []byte, responseHeaders http.Header, code int, err error) { +// Do executes request and returns response body for requested url +func (r HTTPRequester) Do(url, method string, body io.Reader, headers []Header) (response []byte, responseHeaders http.Header, code int, err error) { single := func(request *http.Request) (response []byte, responseHeaders http.Header, code int, e error) { resp, doErr := r.client.Do(request) @@ -160,10 +157,10 @@ func (r HTTPRequester) Do(method string, body io.Reader, headers []Header) (resp return response, resp.Header, resp.StatusCode, nil } - requesterLogger.Debug(fmt.Sprintf("request %s", r.url)) - req, err := http.NewRequest(method, r.url, body) + requesterLogger.Debug(fmt.Sprintf("request %s", url)) + req, err := http.NewRequest(method, url, body) if err != nil { - requesterLogger.Error(fmt.Sprintf("failed to make request %s", r.url), err) + requesterLogger.Error(fmt.Sprintf("failed to make request %s", url), err) return nil, nil, 0, err } @@ -176,10 +173,10 @@ func (r HTTPRequester) Do(method string, body io.Reader, headers []Header) (resp if i > 0 { triedMsg = fmt.Sprintf(", tried %d time(s)", i+1) } - requesterLogger.Debug(fmt.Sprintf("completed %s%s", r.url, triedMsg)) + requesterLogger.Debug(fmt.Sprintf("completed %s%s", url, triedMsg)) return response, responseHeaders, code, err } - requesterLogger.Debug(fmt.Sprintf("failed %s with %v", r.url, err)) + requesterLogger.Debug(fmt.Sprintf("failed %s with %v", url, err)) if i != r.retries { delay := time.Duration(500) * time.Millisecond @@ -201,6 +198,5 @@ func (r HTTPRequester) addHeaders(req *http.Request, headers []Header) *http.Req } func (r HTTPRequester) String() string { - return fmt.Sprintf("{url: %s, timeout: %v, retries: %d}", - r.url, r.client.Timeout, r.retries) + return fmt.Sprintf("{timeout: %v, retries: %d}", r.client.Timeout, r.retries) } diff --git a/pkg/utils/requester_test.go b/pkg/utils/requester_test.go index d62d1c5c0..35838b9da 100644 --- a/pkg/utils/requester_test.go +++ b/pkg/utils/requester_test.go @@ -62,14 +62,14 @@ func TestGet(t *testing.T) { defer ts.Close() var httpreq Requester - httpreq = NewHTTPRequester(ts.URL + "/good") - resp, headers, code, err := httpreq.Get() + httpreq = NewHTTPRequester() + resp, headers, code, err := httpreq.Get(ts.URL + "/good") assert.NotEqual(t, headers.Get("Content-Type"), "") assert.Nil(t, err) assert.Equal(t, "Hello, client\n", string(resp)) - httpreq = NewHTTPRequester(ts.URL + "/bad") - _, headers, code, err = httpreq.Get() + httpreq = NewHTTPRequester() + _, headers, code, err = httpreq.Get(ts.URL + "/bad") assert.Equal(t, errors.New("400 Bad Request"), err) assert.Equal(t, code, http.StatusBadRequest) } @@ -94,14 +94,14 @@ func TestGetObj(t *testing.T) { defer ts.Close() var httpreq Requester - httpreq = NewHTTPRequester(ts.URL + "/good") + httpreq = NewHTTPRequester() r := resp{} - err := httpreq.GetObj(&r) + err := httpreq.GetObj(ts.URL+"/good", &r) assert.Nil(t, err) assert.Equal(t, resp{Fld1: "Hello, client", Fld2: 123}, r) - httpreq = NewHTTPRequester(ts.URL + "/bad") - err = httpreq.GetObj(&r) + httpreq = NewHTTPRequester() + err = httpreq.GetObj(ts.URL+"/bad", &r) assert.NotNil(t, err) } @@ -124,16 +124,16 @@ func TestPost(t *testing.T) { defer ts.Close() b := body{"one", 1} var httpreq Requester - httpreq = NewHTTPRequester(ts.URL + "/good") - resp, headers, code, err := httpreq.Post(b) + httpreq = NewHTTPRequester() + resp, headers, code, err := httpreq.Post(ts.URL+"/good", b) assert.Nil(t, err) assert.NotEqual(t, headers.Get("Content-Type"), "") assert.Equal(t, "Hello, client\n", string(resp)) assert.Equal(t, code, http.StatusOK) - httpreq = NewHTTPRequester(ts.URL + "/bad") - _, _, code, err = httpreq.Post(nil) + httpreq = NewHTTPRequester() + _, _, code, err = httpreq.Post(ts.URL+"/bad", nil) assert.Equal(t, errors.New("400 Bad Request"), err) assert.Equal(t, code, http.StatusBadRequest) } @@ -158,21 +158,22 @@ func TestPostObj(t *testing.T) { defer ts.Close() var httpreq Requester - httpreq = NewHTTPRequester(ts.URL + "/good") + httpreq = NewHTTPRequester() b := body{"one", 1} r := body{} - err := httpreq.PostObj(b, &r) + err := httpreq.PostObj(ts.URL+"/good", b, &r) assert.Nil(t, err) assert.Equal(t, body{Fld1: "Hello, client", Fld2: 123}, r) - httpreq = NewHTTPRequester(ts.URL + "/bad") - err = httpreq.PostObj(b, &r) + httpreq = NewHTTPRequester() + err = httpreq.PostObj(ts.URL+"/bad", b, &r) assert.NotNil(t, err) } func TestGetBad(t *testing.T) { - httpreq := NewHTTPRequester("blah12345/good") - _, _, _, err := httpreq.Get() + + httpreq := NewHTTPRequester() + _, _, _, err := httpreq.Get("blah12345/good") _, ok := err.(*url.Error) assert.True(t, ok, "url error") } @@ -191,8 +192,8 @@ func TestGetBadWithResponse(t *testing.T) { })) defer ts.Close() - httpreq := NewHTTPRequester(ts.URL+"/bad", Retries(1)) - data, _, _, err := httpreq.Get() + httpreq := NewHTTPRequester(Retries(1)) + data, _, _, err := httpreq.Get(ts.URL + "/bad") assert.Equal(t, "400 Bad Request", err.Error()) assert.Equal(t, "bad bad response\n", string(data)) } @@ -220,10 +221,10 @@ func TestGetRetry(t *testing.T) { })) defer ts.Close() - httpreq := NewHTTPRequester(ts.URL+"/test", Retries(10)) + httpreq := NewHTTPRequester(Retries(10)) st := time.Now() - resp, _, _, err := httpreq.Get() + resp, _, _, err := httpreq.Get(ts.URL + "/test") assert.Nil(t, err) assert.Equal(t, "Hello, client\n", string(resp)) assert.Equal(t, 5, called, "called 5 retries") @@ -231,27 +232,28 @@ func TestGetRetry(t *testing.T) { assert.True(t, elapsed >= 400*5*time.Millisecond && elapsed <= 510*5*time.Second, "took %s", elapsed) - httpreq = NewHTTPRequester(ts.URL+"/test", Retries(3)) + httpreq = NewHTTPRequester(Retries(3)) called = 0 - _, _, _, err = httpreq.Get() + _, _, _, err = httpreq.Get(ts.URL + "/test") assert.Equal(t, errors.New("400 Bad Request"), err) assert.Equal(t, 3, called, "called 3 retries") - httpreq = NewHTTPRequester(ts.URL+"/test", Retries(1)) + httpreq = NewHTTPRequester(Retries(1)) called = 0 - _, _, _, err = httpreq.Get() + _, _, _, err = httpreq.Get(ts.URL + "/test") assert.Equal(t, errors.New("400 Bad Request"), err) assert.Equal(t, 1, called, "called 1 retries") - httpreq = NewHTTPRequester(ts.URL + "/test") + httpreq = NewHTTPRequester() called = 0 - _, _, _, err = httpreq.Get() + _, _, _, err = httpreq.Get(ts.URL + "/test") assert.Equal(t, errors.New("400 Bad Request"), err) assert.Equal(t, 1, called, "called 1 retries") } func TestString(t *testing.T) { - assert.Equal(t, "{url: 127.0.0.1/blah, timeout: 5s, retries: 1}", NewHTTPRequester("127.0.0.1/blah").String()) - assert.Equal(t, "{url: 127.0.0.1/blah, timeout: 19s, retries: 10}", - NewHTTPRequester("127.0.0.1/blah", Retries(10), Timeout(time.Duration(19)*time.Second)).String()) + assert.Equal(t, "{timeout: 5s, retries: 1}", NewHTTPRequester().String()) + assert.Equal(t, "{timeout: 19s, retries: 10}", + NewHTTPRequester(Retries(10), Timeout(time.Duration(19)*time.Second)).String()) + }