github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/api/cloudcontroller/wrapper/retry_request_test.go (about)

     1  package wrapper_test
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"strings"
     8  
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/cloudcontrollerfakes"
    12  	. "code.cloudfoundry.org/cli/api/cloudcontroller/wrapper"
    13  	. "github.com/onsi/ginkgo"
    14  	. "github.com/onsi/ginkgo/extensions/table"
    15  	. "github.com/onsi/gomega"
    16  )
    17  
    18  var _ = Describe("Retry Request", func() {
    19  	DescribeTable("number of retries",
    20  		func(requestMethod string, responseStatusCode int, expectedNumberOfRetries int) {
    21  			rawRequestBody := "banana pants"
    22  			body := strings.NewReader(rawRequestBody)
    23  
    24  			req, err := http.NewRequest(requestMethod, "https://foo.bar.com/banana", body)
    25  			Expect(err).NotTo(HaveOccurred())
    26  			request := cloudcontroller.NewRequest(req, body)
    27  
    28  			response := &cloudcontroller.Response{
    29  				HTTPResponse: &http.Response{
    30  					StatusCode: responseStatusCode,
    31  				},
    32  			}
    33  
    34  			fakeConnection := new(cloudcontrollerfakes.FakeConnection)
    35  			expectedErr := ccerror.RawHTTPStatusError{
    36  				StatusCode: responseStatusCode,
    37  			}
    38  			fakeConnection.MakeStub = func(req *cloudcontroller.Request, passedResponse *cloudcontroller.Response) error {
    39  				defer req.Body.Close()
    40  				body, readErr := ioutil.ReadAll(request.Body)
    41  				Expect(readErr).ToNot(HaveOccurred())
    42  				Expect(string(body)).To(Equal(rawRequestBody))
    43  				return expectedErr
    44  			}
    45  
    46  			wrapper := NewRetryRequest(2).Wrap(fakeConnection)
    47  			err = wrapper.Make(request, response)
    48  			Expect(err).To(MatchError(expectedErr))
    49  			Expect(fakeConnection.MakeCallCount()).To(Equal(expectedNumberOfRetries))
    50  		},
    51  
    52  		Entry("maxRetries for Non-Post (500) Internal Server Error", http.MethodGet, http.StatusInternalServerError, 3),
    53  		Entry("maxRetries for Non-Post (502) Bad Gateway", http.MethodGet, http.StatusBadGateway, 3),
    54  		Entry("maxRetries for Non-Post (503) Service Unavailable", http.MethodGet, http.StatusServiceUnavailable, 3),
    55  		Entry("maxRetries for Non-Post (504) Gateway Timeout", http.MethodGet, http.StatusGatewayTimeout, 3),
    56  
    57  		Entry("1 for Post (500) Internal Server Error", http.MethodPost, http.StatusInternalServerError, 1),
    58  		Entry("1 for Post (502) Bad Gateway", http.MethodPost, http.StatusBadGateway, 1),
    59  		Entry("1 for Post (503) Service Unavailable", http.MethodPost, http.StatusServiceUnavailable, 1),
    60  		Entry("1 for Post (504) Gateway Timeout", http.MethodPost, http.StatusGatewayTimeout, 1),
    61  
    62  		Entry("1 for Get 4XX Errors", http.MethodGet, http.StatusNotFound, 1),
    63  	)
    64  
    65  	It("does not retry on success", func() {
    66  		req, err := http.NewRequest(http.MethodGet, "https://foo.bar.com/banana", nil)
    67  		Expect(err).NotTo(HaveOccurred())
    68  		request := cloudcontroller.NewRequest(req, nil)
    69  		response := &cloudcontroller.Response{
    70  			HTTPResponse: &http.Response{
    71  				StatusCode: http.StatusOK,
    72  			},
    73  		}
    74  
    75  		fakeConnection := new(cloudcontrollerfakes.FakeConnection)
    76  		wrapper := NewRetryRequest(2).Wrap(fakeConnection)
    77  
    78  		err = wrapper.Make(request, response)
    79  		Expect(err).ToNot(HaveOccurred())
    80  		Expect(fakeConnection.MakeCallCount()).To(Equal(1))
    81  	})
    82  
    83  	Context("when a PipeSeekError is returned from ResetBody", func() {
    84  		var (
    85  			expectedErr error
    86  			request     *cloudcontroller.Request
    87  			response    *cloudcontroller.Response
    88  
    89  			fakeConnection *cloudcontrollerfakes.FakeConnection
    90  			wrapper        cloudcontroller.Connection
    91  		)
    92  
    93  		BeforeEach(func() {
    94  			body, _ := cloudcontroller.NewPipeBomb()
    95  			req, err := http.NewRequest(http.MethodGet, "https://foo.bar.com/banana", body)
    96  			Expect(err).NotTo(HaveOccurred())
    97  			request = cloudcontroller.NewRequest(req, body)
    98  			response = &cloudcontroller.Response{
    99  				HTTPResponse: &http.Response{
   100  					StatusCode: http.StatusInternalServerError,
   101  				},
   102  			}
   103  
   104  			fakeConnection = new(cloudcontrollerfakes.FakeConnection)
   105  			expectedErr = errors.New("oh noes")
   106  			fakeConnection.MakeReturns(expectedErr)
   107  
   108  			wrapper = NewRetryRequest(2).Wrap(fakeConnection)
   109  		})
   110  
   111  		It("sets the err on PipeSeekError", func() {
   112  			err := wrapper.Make(request, response)
   113  			Expect(err).To(MatchError(ccerror.PipeSeekError{Err: expectedErr}))
   114  			Expect(fakeConnection.MakeCallCount()).To(Equal(1))
   115  		})
   116  	})
   117  })