github.com/jghiloni/cli@v6.28.1-0.20170628223758-0ce05fe032a2+incompatible/api/cloudcontroller/wrapper/request_logger_test.go (about)

     1  package wrapper_test
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"net/url"
     9  	"time"
    10  
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller"
    12  	"code.cloudfoundry.org/cli/api/cloudcontroller/cloudcontrollerfakes"
    13  	. "code.cloudfoundry.org/cli/api/cloudcontroller/wrapper"
    14  	"code.cloudfoundry.org/cli/api/cloudcontroller/wrapper/wrapperfakes"
    15  
    16  	. "github.com/onsi/ginkgo"
    17  	. "github.com/onsi/gomega"
    18  )
    19  
    20  var _ = Describe("Request Logger", func() {
    21  	var (
    22  		fakeConnection *cloudcontrollerfakes.FakeConnection
    23  		fakeOutput     *wrapperfakes.FakeRequestLoggerOutput
    24  
    25  		wrapper cloudcontroller.Connection
    26  
    27  		request  *cloudcontroller.Request
    28  		response *cloudcontroller.Response
    29  		err      error
    30  	)
    31  
    32  	BeforeEach(func() {
    33  		fakeConnection = new(cloudcontrollerfakes.FakeConnection)
    34  		fakeOutput = new(wrapperfakes.FakeRequestLoggerOutput)
    35  
    36  		wrapper = NewRequestLogger(fakeOutput).Wrap(fakeConnection)
    37  
    38  		body := bytes.NewReader([]byte("foo"))
    39  
    40  		req, err := http.NewRequest(http.MethodGet, "https://foo.bar.com/banana", body)
    41  		Expect(err).NotTo(HaveOccurred())
    42  
    43  		req.URL.RawQuery = url.Values{
    44  			"query1": {"a"},
    45  			"query2": {"b"},
    46  		}.Encode()
    47  
    48  		headers := http.Header{}
    49  		headers.Add("Aghi", "bar")
    50  		headers.Add("Abc", "json")
    51  		headers.Add("Adef", "application/json")
    52  		req.Header = headers
    53  
    54  		response = &cloudcontroller.Response{
    55  			RawResponse:  []byte("some-response-body"),
    56  			HTTPResponse: &http.Response{},
    57  		}
    58  		request = cloudcontroller.NewRequest(req, body)
    59  	})
    60  
    61  	JustBeforeEach(func() {
    62  		err = wrapper.Make(request, response)
    63  	})
    64  
    65  	Describe("Make", func() {
    66  		It("outputs the request", func() {
    67  			Expect(err).NotTo(HaveOccurred())
    68  
    69  			Expect(fakeOutput.DisplayTypeCallCount()).To(BeNumerically(">=", 1))
    70  			name, date := fakeOutput.DisplayTypeArgsForCall(0)
    71  			Expect(name).To(Equal("REQUEST"))
    72  			Expect(date).To(BeTemporally("~", time.Now(), time.Second))
    73  
    74  			Expect(fakeOutput.DisplayRequestHeaderCallCount()).To(Equal(1))
    75  			method, uri, protocol := fakeOutput.DisplayRequestHeaderArgsForCall(0)
    76  			Expect(method).To(Equal(http.MethodGet))
    77  			Expect(uri).To(MatchRegexp("/banana\\?(?:query1=a&query2=b|query2=b&query1=a)"))
    78  			Expect(protocol).To(Equal("HTTP/1.1"))
    79  
    80  			Expect(fakeOutput.DisplayHostCallCount()).To(Equal(1))
    81  			host := fakeOutput.DisplayHostArgsForCall(0)
    82  			Expect(host).To(Equal("foo.bar.com"))
    83  
    84  			Expect(fakeOutput.DisplayHeaderCallCount()).To(BeNumerically(">=", 3))
    85  			name, value := fakeOutput.DisplayHeaderArgsForCall(0)
    86  			Expect(name).To(Equal("Abc"))
    87  			Expect(value).To(Equal("json"))
    88  			name, value = fakeOutput.DisplayHeaderArgsForCall(1)
    89  			Expect(name).To(Equal("Adef"))
    90  			Expect(value).To(Equal("application/json"))
    91  			name, value = fakeOutput.DisplayHeaderArgsForCall(2)
    92  			Expect(name).To(Equal("Aghi"))
    93  			Expect(value).To(Equal("bar"))
    94  		})
    95  
    96  		Context("when an authorization header is in the request", func() {
    97  			BeforeEach(func() {
    98  				request.Header = http.Header{"Authorization": []string{"should not be shown"}}
    99  			})
   100  
   101  			It("redacts the contents of the authorization header", func() {
   102  				Expect(err).NotTo(HaveOccurred())
   103  				Expect(fakeOutput.DisplayHeaderCallCount()).To(Equal(1))
   104  				key, value := fakeOutput.DisplayHeaderArgsForCall(0)
   105  				Expect(key).To(Equal("Authorization"))
   106  				Expect(value).To(Equal("[PRIVATE DATA HIDDEN]"))
   107  			})
   108  		})
   109  
   110  		Context("when passed a body", func() {
   111  			Context("when the request's Content-Type is application/json", func() {
   112  				BeforeEach(func() {
   113  					request.Header.Set("Content-Type", "application/json")
   114  				})
   115  
   116  				It("outputs the body", func() {
   117  					Expect(err).NotTo(HaveOccurred())
   118  
   119  					Expect(fakeOutput.DisplayJSONBodyCallCount()).To(BeNumerically(">=", 1))
   120  					Expect(fakeOutput.DisplayJSONBodyArgsForCall(0)).To(Equal([]byte("foo")))
   121  
   122  					bytes, err := ioutil.ReadAll(request.Body)
   123  					Expect(err).NotTo(HaveOccurred())
   124  					Expect(bytes).To(Equal([]byte("foo")))
   125  				})
   126  			})
   127  
   128  			Context("when request's Content-Type is anything else", func() {
   129  				BeforeEach(func() {
   130  					request.Header.Set("Content-Type", "banana")
   131  				})
   132  
   133  				It("does not display the body", func() {
   134  					Expect(fakeOutput.DisplayJSONBodyCallCount()).To(Equal(1)) // Once for response body only
   135  				})
   136  			})
   137  		})
   138  
   139  		Context("when an error occures while trying to log the request", func() {
   140  			var expectedErr error
   141  
   142  			BeforeEach(func() {
   143  				expectedErr = errors.New("this should never block the request")
   144  
   145  				calledOnce := false
   146  				fakeOutput.StartStub = func() error {
   147  					if !calledOnce {
   148  						calledOnce = true
   149  						return expectedErr
   150  					}
   151  					return nil
   152  				}
   153  			})
   154  
   155  			It("should display the error and continue on", func() {
   156  				Expect(err).NotTo(HaveOccurred())
   157  
   158  				Expect(fakeOutput.HandleInternalErrorCallCount()).To(Equal(1))
   159  				Expect(fakeOutput.HandleInternalErrorArgsForCall(0)).To(MatchError(expectedErr))
   160  			})
   161  		})
   162  
   163  		Context("when the request is successful", func() {
   164  			BeforeEach(func() {
   165  				response = &cloudcontroller.Response{
   166  					RawResponse: []byte("some-response-body"),
   167  					HTTPResponse: &http.Response{
   168  						Proto:  "HTTP/1.1",
   169  						Status: "200 OK",
   170  						Header: http.Header{
   171  							"BBBBB": {"second"},
   172  							"AAAAA": {"first"},
   173  							"CCCCC": {"third"},
   174  						},
   175  					},
   176  				}
   177  			})
   178  
   179  			It("outputs the response", func() {
   180  				Expect(err).NotTo(HaveOccurred())
   181  
   182  				Expect(fakeOutput.DisplayTypeCallCount()).To(Equal(2))
   183  				name, date := fakeOutput.DisplayTypeArgsForCall(1)
   184  				Expect(name).To(Equal("RESPONSE"))
   185  				Expect(date).To(BeTemporally("~", time.Now(), time.Second))
   186  
   187  				Expect(fakeOutput.DisplayResponseHeaderCallCount()).To(Equal(1))
   188  				protocol, status := fakeOutput.DisplayResponseHeaderArgsForCall(0)
   189  				Expect(protocol).To(Equal("HTTP/1.1"))
   190  				Expect(status).To(Equal("200 OK"))
   191  
   192  				Expect(fakeOutput.DisplayHeaderCallCount()).To(BeNumerically(">=", 6))
   193  				name, value := fakeOutput.DisplayHeaderArgsForCall(3)
   194  				Expect(name).To(Equal("AAAAA"))
   195  				Expect(value).To(Equal("first"))
   196  				name, value = fakeOutput.DisplayHeaderArgsForCall(4)
   197  				Expect(name).To(Equal("BBBBB"))
   198  				Expect(value).To(Equal("second"))
   199  				name, value = fakeOutput.DisplayHeaderArgsForCall(5)
   200  				Expect(name).To(Equal("CCCCC"))
   201  				Expect(value).To(Equal("third"))
   202  
   203  				Expect(fakeOutput.DisplayJSONBodyCallCount()).To(BeNumerically(">=", 1))
   204  				Expect(fakeOutput.DisplayJSONBodyArgsForCall(0)).To(Equal([]byte("some-response-body")))
   205  			})
   206  		})
   207  
   208  		Context("when the request is unsuccessful", func() {
   209  			var expectedErr error
   210  
   211  			BeforeEach(func() {
   212  				expectedErr = errors.New("banana")
   213  				fakeConnection.MakeReturns(expectedErr)
   214  			})
   215  
   216  			Context("when the http response is not set", func() {
   217  				BeforeEach(func() {
   218  					response = &cloudcontroller.Response{}
   219  				})
   220  
   221  				It("outputs nothing", func() {
   222  					Expect(err).To(MatchError(expectedErr))
   223  					Expect(fakeOutput.DisplayResponseHeaderCallCount()).To(Equal(0))
   224  				})
   225  			})
   226  
   227  			Context("when the http response is set", func() {
   228  				BeforeEach(func() {
   229  					response = &cloudcontroller.Response{
   230  						RawResponse: []byte("some-error-body"),
   231  						HTTPResponse: &http.Response{
   232  							Proto:  "HTTP/1.1",
   233  							Status: "200 OK",
   234  							Header: http.Header{
   235  								"BBBBB": {"second"},
   236  								"AAAAA": {"first"},
   237  								"CCCCC": {"third"},
   238  							},
   239  						},
   240  					}
   241  				})
   242  
   243  				It("outputs the response", func() {
   244  					Expect(err).To(MatchError(expectedErr))
   245  
   246  					Expect(fakeOutput.DisplayTypeCallCount()).To(Equal(2))
   247  					name, date := fakeOutput.DisplayTypeArgsForCall(1)
   248  					Expect(name).To(Equal("RESPONSE"))
   249  					Expect(date).To(BeTemporally("~", time.Now(), time.Second))
   250  
   251  					Expect(fakeOutput.DisplayResponseHeaderCallCount()).To(Equal(1))
   252  					protocol, status := fakeOutput.DisplayResponseHeaderArgsForCall(0)
   253  					Expect(protocol).To(Equal("HTTP/1.1"))
   254  					Expect(status).To(Equal("200 OK"))
   255  
   256  					Expect(fakeOutput.DisplayHeaderCallCount()).To(BeNumerically(">=", 6))
   257  					name, value := fakeOutput.DisplayHeaderArgsForCall(3)
   258  					Expect(name).To(Equal("AAAAA"))
   259  					Expect(value).To(Equal("first"))
   260  					name, value = fakeOutput.DisplayHeaderArgsForCall(4)
   261  					Expect(name).To(Equal("BBBBB"))
   262  					Expect(value).To(Equal("second"))
   263  					name, value = fakeOutput.DisplayHeaderArgsForCall(5)
   264  					Expect(name).To(Equal("CCCCC"))
   265  					Expect(value).To(Equal("third"))
   266  
   267  					Expect(fakeOutput.DisplayJSONBodyCallCount()).To(BeNumerically(">=", 1))
   268  					Expect(fakeOutput.DisplayJSONBodyArgsForCall(0)).To(Equal([]byte("some-error-body")))
   269  				})
   270  			})
   271  		})
   272  
   273  		Context("when an error occures while trying to log the response", func() {
   274  			var (
   275  				originalErr error
   276  				expectedErr error
   277  			)
   278  
   279  			BeforeEach(func() {
   280  				originalErr = errors.New("this error should not be overwritten")
   281  				fakeConnection.MakeReturns(originalErr)
   282  
   283  				expectedErr = errors.New("this should never block the request")
   284  
   285  				calledOnce := false
   286  				fakeOutput.StartStub = func() error {
   287  					if !calledOnce {
   288  						calledOnce = true
   289  						return nil
   290  					}
   291  					return expectedErr
   292  				}
   293  			})
   294  
   295  			It("should display the error and continue on", func() {
   296  				Expect(err).To(MatchError(originalErr))
   297  
   298  				Expect(fakeOutput.HandleInternalErrorCallCount()).To(Equal(1))
   299  				Expect(fakeOutput.HandleInternalErrorArgsForCall(0)).To(MatchError(expectedErr))
   300  			})
   301  		})
   302  
   303  		It("starts and stops the output", func() {
   304  			Expect(fakeOutput.StartCallCount()).To(Equal(2))
   305  			Expect(fakeOutput.StopCallCount()).To(Equal(2))
   306  		})
   307  
   308  		Context("when displaying the logs have an error", func() {
   309  			var expectedErr error
   310  			BeforeEach(func() {
   311  				expectedErr = errors.New("Display error on request")
   312  				fakeOutput.StartReturns(expectedErr)
   313  			})
   314  
   315  			It("calls handle internal error", func() {
   316  				Expect(err).ToNot(HaveOccurred())
   317  
   318  				Expect(fakeOutput.HandleInternalErrorCallCount()).To(Equal(2))
   319  				Expect(fakeOutput.HandleInternalErrorArgsForCall(0)).To(MatchError(expectedErr))
   320  				Expect(fakeOutput.HandleInternalErrorArgsForCall(1)).To(MatchError(expectedErr))
   321  			})
   322  		})
   323  	})
   324  })