123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- // Copyright (c) 2015-2019 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
- // resty source code and usage is governed by a MIT style
- // license that can be found in the LICENSE file.
- package resty
- import (
- "encoding/json"
- "errors"
- "net/http"
- "reflect"
- "strconv"
- "strings"
- "testing"
- "time"
- )
- func TestBackoffSuccess(t *testing.T) {
- attempts := 3
- externalCounter := 0
- retryErr := Backoff(func() (*Response, error) {
- externalCounter++
- if externalCounter < attempts {
- return nil, errors.New("not yet got the number we're after")
- }
- return nil, nil
- })
- assertError(t, retryErr)
- assertEqual(t, externalCounter, attempts)
- }
- func TestBackoffTenAttemptsSuccess(t *testing.T) {
- attempts := 10
- externalCounter := 0
- retryErr := Backoff(func() (*Response, error) {
- externalCounter++
- if externalCounter < attempts {
- return nil, errors.New("not yet got the number we're after")
- }
- return nil, nil
- }, Retries(attempts), WaitTime(5), MaxWaitTime(500))
- assertError(t, retryErr)
- assertEqual(t, externalCounter, attempts)
- }
- // Check to make sure the conditional of the retry condition is being used
- func TestConditionalBackoffCondition(t *testing.T) {
- attempts := 3
- counter := 0
- check := RetryConditionFunc(func(*Response) (bool, error) {
- return attempts != counter, nil
- })
- retryErr := Backoff(func() (*Response, error) {
- counter++
- return nil, nil
- }, RetryConditions([]RetryConditionFunc{check}))
- assertError(t, retryErr)
- assertEqual(t, counter, attempts)
- }
- // Check to make sure that errors in the conditional cause a retry
- func TestConditionalBackoffConditionError(t *testing.T) {
- attempts := 3
- counter := 0
- check := RetryConditionFunc(func(*Response) (bool, error) {
- if attempts != counter {
- return false, errors.New("attempts not equal Counter")
- }
- return false, nil
- })
- retryErr := Backoff(func() (*Response, error) {
- counter++
- return nil, nil
- }, RetryConditions([]RetryConditionFunc{check}))
- assertError(t, retryErr)
- assertEqual(t, counter, attempts)
- }
- // Check to make sure that if the conditional is false we don't retry
- func TestConditionalBackoffConditionNonExecution(t *testing.T) {
- attempts := 3
- counter := 0
- retryErr := Backoff(func() (*Response, error) {
- counter++
- return nil, nil
- }, RetryConditions([]RetryConditionFunc{filler}))
- assertError(t, retryErr)
- assertNotEqual(t, counter, attempts)
- }
- // Check to make sure the functions added to add conditionals work
- func TestConditionalGet(t *testing.T) {
- ts := createGetServer(t)
- defer ts.Close()
- attemptCount := 1
- externalCounter := 0
- // This check should pass on first run, and let the response through
- check := RetryConditionFunc(func(*Response) (bool, error) {
- externalCounter++
- if attemptCount != externalCounter {
- return false, errors.New("attempts not equal Counter")
- }
- return false, nil
- })
- client := dc().AddRetryCondition(check).SetRetryCount(1)
- resp, err := client.R().
- SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)).
- Get(ts.URL + "/")
- assertError(t, err)
- assertEqual(t, http.StatusOK, resp.StatusCode())
- assertEqual(t, "200 OK", resp.Status())
- assertNotNil(t, resp.Body())
- assertEqual(t, "TestGet: text response", resp.String())
- assertEqual(t, externalCounter, attemptCount)
- logResponse(t, resp)
- }
- // Check to make sure the package Function works.
- func TestConditionalGetDefaultClient(t *testing.T) {
- ts := createGetServer(t)
- defer ts.Close()
- attemptCount := 1
- externalCounter := 0
- // This check should pass on first run, and let the response through
- check := RetryConditionFunc(func(*Response) (bool, error) {
- externalCounter++
- if attemptCount != externalCounter {
- return false, errors.New("attempts not equal Counter")
- }
- return false, nil
- })
- // Clear the default client.
- _ = dc()
- // Proceed to check.
- client := AddRetryCondition(check).SetRetryCount(1)
- resp, err := client.R().
- SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)).
- Get(ts.URL + "/")
- assertError(t, err)
- assertEqual(t, http.StatusOK, resp.StatusCode())
- assertEqual(t, "200 OK", resp.Status())
- assertNotNil(t, resp.Body())
- assertEqual(t, "TestGet: text response", resp.String())
- assertEqual(t, externalCounter, attemptCount)
- logResponse(t, resp)
- }
- func TestClientRetryGet(t *testing.T) {
- ts := createGetServer(t)
- defer ts.Close()
- c := dc()
- c.SetHTTPMode().
- SetTimeout(time.Second * 3).
- SetRetryCount(3)
- resp, err := c.R().Get(ts.URL + "/set-retrycount-test")
- assertEqual(t, "", resp.Status())
- assertEqual(t, 0, resp.StatusCode())
- assertEqual(t, 0, len(resp.Cookies()))
- assertNotNil(t, resp.Body())
- assertEqual(t, 0, len(resp.Header()))
- assertEqual(t, true, strings.HasPrefix(err.Error(), "Get "+ts.URL+"/set-retrycount-test"))
- }
- func TestClientRetryWait(t *testing.T) {
- ts := createGetServer(t)
- defer ts.Close()
- attempt := 0
- retryCount := 5
- retryIntervals := make([]uint64, retryCount)
- // Set retry wait times that do not intersect with default ones
- retryWaitTime := time.Duration(3) * time.Second
- retryMaxWaitTime := time.Duration(9) * time.Second
- c := dc()
- c.SetHTTPMode().
- SetRetryCount(retryCount).
- SetRetryWaitTime(retryWaitTime).
- SetRetryMaxWaitTime(retryMaxWaitTime).
- AddRetryCondition(
- func(r *Response) (bool, error) {
- timeSlept, _ := strconv.ParseUint(string(r.Body()), 10, 64)
- retryIntervals[attempt] = timeSlept
- attempt++
- return true, nil
- },
- )
- _, _ = c.R().Get(ts.URL + "/set-retrywaittime-test")
- // 5 attempts were made
- assertEqual(t, attempt, 5)
- // Initial attempt has 0 time slept since last request
- assertEqual(t, retryIntervals[0], uint64(0))
- for i := 1; i < len(retryIntervals); i++ {
- slept := time.Duration(retryIntervals[i])
- // Ensure that client has slept some duration between
- // waitTime and maxWaitTime for consequent requests
- if slept < retryWaitTime || slept > retryMaxWaitTime {
- t.Errorf("Client has slept %f seconds before retry %d", slept.Seconds(), i)
- }
- }
- }
- func TestClientRetryPost(t *testing.T) {
- ts := createPostServer(t)
- defer ts.Close()
- usersmap := map[string]interface{}{
- "user1": map[string]interface{}{"FirstName": "firstname1", "LastName": "lastname1", "ZipCode": "10001"},
- }
- var users []map[string]interface{}
- users = append(users, usersmap)
- c := dc()
- c.SetRetryCount(3)
- c.AddRetryCondition(RetryConditionFunc(func(r *Response) (bool, error) {
- if r.StatusCode() >= http.StatusInternalServerError {
- return false, errors.New("error")
- }
- return true, nil
- }))
- resp, _ := c.R().
- SetBody(&users).
- Post(ts.URL + "/usersmap?status=500")
- if resp != nil {
- if resp.StatusCode() == http.StatusInternalServerError {
- t.Logf("Got response body: %s", string(resp.body))
- var usersResponse []map[string]interface{}
- err := json.Unmarshal(resp.body, &usersResponse)
- assertError(t, err)
- if !reflect.DeepEqual(users, usersResponse) {
- t.Errorf("Expected request body to be echoed back as response body. Instead got: %s", string(resp.body))
- }
- return
- }
- t.Errorf("Got unexpected response code: %d with body: %s", resp.StatusCode(), string(resp.body))
- }
- }
- func filler(*Response) (bool, error) {
- return false, nil
- }
|