github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+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 makeErr 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 makeErr = wrapper.Make(request, response) 63 }) 64 65 Describe("Make", func() { 66 It("outputs the request", func() { 67 Expect(makeErr).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 Expect(fakeOutput.DisplayMessageCallCount()).To(Equal(0)) 96 }) 97 98 When("an authorization header is in the request", func() { 99 BeforeEach(func() { 100 request.Header = http.Header{"Authorization": []string{"should not be shown"}} 101 }) 102 103 It("redacts the contents of the authorization header", func() { 104 Expect(makeErr).NotTo(HaveOccurred()) 105 Expect(fakeOutput.DisplayHeaderCallCount()).To(Equal(1)) 106 key, value := fakeOutput.DisplayHeaderArgsForCall(0) 107 Expect(key).To(Equal("Authorization")) 108 Expect(value).To(Equal("[PRIVATE DATA HIDDEN]")) 109 }) 110 }) 111 112 When("passed a body", func() { 113 When("the request's Content-Type is application/json", func() { 114 BeforeEach(func() { 115 request.Header.Set("Content-Type", "application/json") 116 }) 117 118 It("outputs the body", func() { 119 Expect(makeErr).NotTo(HaveOccurred()) 120 121 Expect(fakeOutput.DisplayJSONBodyCallCount()).To(BeNumerically(">=", 1)) 122 Expect(fakeOutput.DisplayJSONBodyArgsForCall(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 When("the request's Content-Type is application/x-www-form-urlencoded", func() { 131 BeforeEach(func() { 132 request.Header.Set("Content-Type", "application/x-www-form-urlencoded") 133 }) 134 135 It("outputs the body", func() { 136 Expect(makeErr).NotTo(HaveOccurred()) 137 138 bytes, err := ioutil.ReadAll(request.Body) 139 Expect(err).NotTo(HaveOccurred()) 140 Expect(bytes).To(Equal([]byte("foo"))) 141 Expect(fakeOutput.DisplayMessageCallCount()).To(Equal(1)) 142 Expect(fakeOutput.DisplayMessageArgsForCall(0)).To(Equal("[application/x-www-form-urlencoded foo]")) 143 }) 144 }) 145 146 When("request's Content-Type is anything else", func() { 147 BeforeEach(func() { 148 request.Header.Set("Content-Type", "banana;rama") 149 }) 150 151 It("does not display the body", func() { 152 Expect(makeErr).NotTo(HaveOccurred()) 153 Expect(fakeOutput.DisplayJSONBodyCallCount()).To(Equal(1)) // Once for response body only 154 Expect(fakeOutput.DisplayMessageCallCount()).To(Equal(1)) 155 Expect(fakeOutput.DisplayMessageArgsForCall(0)).To(Equal("[banana Content Hidden]")) 156 }) 157 }) 158 }) 159 160 When("an error occures while trying to log the request", func() { 161 var expectedErr error 162 163 BeforeEach(func() { 164 expectedErr = errors.New("this should never block the request") 165 166 calledOnce := false 167 fakeOutput.StartStub = func() error { 168 if !calledOnce { 169 calledOnce = true 170 return expectedErr 171 } 172 return nil 173 } 174 }) 175 176 It("should display the error and continue on", func() { 177 Expect(makeErr).NotTo(HaveOccurred()) 178 179 Expect(fakeOutput.HandleInternalErrorCallCount()).To(Equal(1)) 180 Expect(fakeOutput.HandleInternalErrorArgsForCall(0)).To(MatchError(expectedErr)) 181 }) 182 }) 183 184 When("the request is successful", func() { 185 When("the response body is not YAML", func() { 186 BeforeEach(func() { 187 response = &cloudcontroller.Response{ 188 RawResponse: []byte("some-response-body"), 189 HTTPResponse: &http.Response{ 190 Proto: "HTTP/1.1", 191 Status: "200 OK", 192 Header: http.Header{ 193 "BBBBB": {"second"}, 194 "AAAAA": {"first"}, 195 "CCCCC": {"third"}, 196 }, 197 }, 198 } 199 }) 200 201 It("outputs the response", func() { 202 Expect(makeErr).NotTo(HaveOccurred()) 203 204 Expect(fakeOutput.DisplayTypeCallCount()).To(Equal(2)) 205 name, date := fakeOutput.DisplayTypeArgsForCall(1) 206 Expect(name).To(Equal("RESPONSE")) 207 Expect(date).To(BeTemporally("~", time.Now(), time.Second)) 208 209 Expect(fakeOutput.DisplayResponseHeaderCallCount()).To(Equal(1)) 210 protocol, status := fakeOutput.DisplayResponseHeaderArgsForCall(0) 211 Expect(protocol).To(Equal("HTTP/1.1")) 212 Expect(status).To(Equal("200 OK")) 213 214 Expect(fakeOutput.DisplayHeaderCallCount()).To(BeNumerically(">=", 6)) 215 name, value := fakeOutput.DisplayHeaderArgsForCall(3) 216 Expect(name).To(Equal("AAAAA")) 217 Expect(value).To(Equal("first")) 218 name, value = fakeOutput.DisplayHeaderArgsForCall(4) 219 Expect(name).To(Equal("BBBBB")) 220 Expect(value).To(Equal("second")) 221 name, value = fakeOutput.DisplayHeaderArgsForCall(5) 222 Expect(name).To(Equal("CCCCC")) 223 Expect(value).To(Equal("third")) 224 225 Expect(fakeOutput.DisplayMessageCallCount()).To(BeNumerically("==", 0)) 226 227 Expect(fakeOutput.DisplayJSONBodyCallCount()).To(BeNumerically(">=", 1)) 228 Expect(fakeOutput.DisplayJSONBodyArgsForCall(0)).To(Equal([]byte("some-response-body"))) 229 }) 230 }) 231 232 When("the response body is YAML", func() { 233 BeforeEach(func() { 234 response = &cloudcontroller.Response{ 235 RawResponse: []byte(`---\n- some-response-body`), 236 HTTPResponse: &http.Response{ 237 Proto: "HTTP/1.1", 238 Status: "200 OK", 239 Header: http.Header{ 240 "Content-Type": {"application/x-yaml; charset=utf-16"}, 241 }, 242 }, 243 } 244 }) 245 246 It("redacts the body to prevent leaking manifest credentials", func() { 247 Expect(makeErr).NotTo(HaveOccurred()) 248 249 Expect(fakeOutput.DisplayTypeCallCount()).To(Equal(2)) 250 name, date := fakeOutput.DisplayTypeArgsForCall(1) 251 Expect(name).To(Equal("RESPONSE")) 252 Expect(date).To(BeTemporally("~", time.Now(), time.Second)) 253 254 Expect(fakeOutput.DisplayResponseHeaderCallCount()).To(Equal(1)) 255 protocol, status := fakeOutput.DisplayResponseHeaderArgsForCall(0) 256 Expect(protocol).To(Equal("HTTP/1.1")) 257 Expect(status).To(Equal("200 OK")) 258 259 Expect(fakeOutput.DisplayHeaderCallCount()).To(BeNumerically(">=", 4)) 260 name, value := fakeOutput.DisplayHeaderArgsForCall(3) 261 Expect(name).To(Equal("Content-Type")) 262 Expect(value).To(Equal("application/x-yaml; charset=utf-16")) 263 264 Expect(fakeOutput.DisplayMessageCallCount()).To(BeNumerically(">=", 1)) 265 Expect(fakeOutput.DisplayMessageArgsForCall(0)).To(Equal("[application/x-yaml Content Hidden]")) 266 267 Expect(fakeOutput.DisplayJSONBodyCallCount()).To(BeNumerically("==", 0)) 268 }) 269 }) 270 }) 271 272 When("the request is unsuccessful", func() { 273 var expectedErr error 274 275 BeforeEach(func() { 276 expectedErr = errors.New("banana") 277 fakeConnection.MakeReturns(expectedErr) 278 }) 279 280 When("the http response is not set", func() { 281 BeforeEach(func() { 282 response = &cloudcontroller.Response{} 283 }) 284 285 It("outputs nothing", func() { 286 Expect(makeErr).To(MatchError(expectedErr)) 287 Expect(fakeOutput.DisplayResponseHeaderCallCount()).To(Equal(0)) 288 }) 289 }) 290 291 When("the http response is set", func() { 292 BeforeEach(func() { 293 response = &cloudcontroller.Response{ 294 RawResponse: []byte("some-error-body"), 295 HTTPResponse: &http.Response{ 296 Proto: "HTTP/1.1", 297 Status: "200 OK", 298 Header: http.Header{ 299 "BBBBB": {"second"}, 300 "AAAAA": {"first"}, 301 "CCCCC": {"third"}, 302 }, 303 }, 304 } 305 }) 306 307 It("outputs the response", func() { 308 Expect(makeErr).To(MatchError(expectedErr)) 309 310 Expect(fakeOutput.DisplayTypeCallCount()).To(Equal(2)) 311 name, date := fakeOutput.DisplayTypeArgsForCall(1) 312 Expect(name).To(Equal("RESPONSE")) 313 Expect(date).To(BeTemporally("~", time.Now(), time.Second)) 314 315 Expect(fakeOutput.DisplayResponseHeaderCallCount()).To(Equal(1)) 316 protocol, status := fakeOutput.DisplayResponseHeaderArgsForCall(0) 317 Expect(protocol).To(Equal("HTTP/1.1")) 318 Expect(status).To(Equal("200 OK")) 319 320 Expect(fakeOutput.DisplayHeaderCallCount()).To(BeNumerically(">=", 6)) 321 name, value := fakeOutput.DisplayHeaderArgsForCall(3) 322 Expect(name).To(Equal("AAAAA")) 323 Expect(value).To(Equal("first")) 324 name, value = fakeOutput.DisplayHeaderArgsForCall(4) 325 Expect(name).To(Equal("BBBBB")) 326 Expect(value).To(Equal("second")) 327 name, value = fakeOutput.DisplayHeaderArgsForCall(5) 328 Expect(name).To(Equal("CCCCC")) 329 Expect(value).To(Equal("third")) 330 331 Expect(fakeOutput.DisplayJSONBodyCallCount()).To(BeNumerically(">=", 1)) 332 Expect(fakeOutput.DisplayJSONBodyArgsForCall(0)).To(Equal([]byte("some-error-body"))) 333 }) 334 }) 335 }) 336 337 When("an error occures while trying to log the response", func() { 338 var ( 339 originalErr error 340 expectedErr error 341 ) 342 343 BeforeEach(func() { 344 originalErr = errors.New("this error should not be overwritten") 345 fakeConnection.MakeReturns(originalErr) 346 347 expectedErr = errors.New("this should never block the request") 348 349 calledOnce := false 350 fakeOutput.StartStub = func() error { 351 if !calledOnce { 352 calledOnce = true 353 return nil 354 } 355 return expectedErr 356 } 357 }) 358 359 It("should display the error and continue on", func() { 360 Expect(makeErr).To(MatchError(originalErr)) 361 362 Expect(fakeOutput.HandleInternalErrorCallCount()).To(Equal(1)) 363 Expect(fakeOutput.HandleInternalErrorArgsForCall(0)).To(MatchError(expectedErr)) 364 }) 365 }) 366 367 It("starts and stops the output", func() { 368 Expect(fakeOutput.StartCallCount()).To(Equal(2)) 369 Expect(fakeOutput.StopCallCount()).To(Equal(2)) 370 }) 371 372 When("displaying the logs have an error", func() { 373 var expectedErr error 374 BeforeEach(func() { 375 expectedErr = errors.New("Display error on request") 376 fakeOutput.StartReturns(expectedErr) 377 }) 378 379 It("calls handle internal error", func() { 380 Expect(makeErr).ToNot(HaveOccurred()) 381 382 Expect(fakeOutput.HandleInternalErrorCallCount()).To(Equal(2)) 383 Expect(fakeOutput.HandleInternalErrorArgsForCall(0)).To(MatchError(expectedErr)) 384 Expect(fakeOutput.HandleInternalErrorArgsForCall(1)).To(MatchError(expectedErr)) 385 }) 386 }) 387 }) 388 })