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 })