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