github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/router/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/router" 12 "code.cloudfoundry.org/cli/api/router/routerfakes" 13 . "code.cloudfoundry.org/cli/api/router/wrapper" 14 "code.cloudfoundry.org/cli/api/router/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 *routerfakes.FakeConnection 23 fakeOutput *wrapperfakes.FakeRequestLoggerOutput 24 25 wrapper router.Connection 26 27 request *router.Request 28 response *router.Response 29 makeErr error 30 ) 31 32 BeforeEach(func() { 33 fakeConnection = new(routerfakes.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 = &router.Response{ 55 RawResponse: []byte("some-response-body"), 56 HTTPResponse: &http.Response{}, 57 } 58 request = router.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("a Set-Cookie header is in the request", func() { 113 BeforeEach(func() { 114 request.Header = http.Header{"Set-Cookie": []string{"should not be shown"}} 115 }) 116 117 It("redacts the contents of the Set-Cookie header", func() { 118 Expect(makeErr).NotTo(HaveOccurred()) 119 Expect(fakeOutput.DisplayHeaderCallCount()).To(Equal(1)) 120 key, value := fakeOutput.DisplayHeaderArgsForCall(0) 121 Expect(key).To(Equal("Set-Cookie")) 122 Expect(value).To(Equal("[PRIVATE DATA HIDDEN]")) 123 }) 124 }) 125 126 When("passed a body", func() { 127 When("the request's Content-Type is application/json", func() { 128 BeforeEach(func() { 129 request.Header.Set("Content-Type", "application/json") 130 }) 131 132 It("outputs the body", func() { 133 Expect(makeErr).NotTo(HaveOccurred()) 134 135 Expect(fakeOutput.DisplayJSONBodyCallCount()).To(BeNumerically(">=", 1)) 136 Expect(fakeOutput.DisplayJSONBodyArgsForCall(0)).To(Equal([]byte("foo"))) 137 138 bytes, err := ioutil.ReadAll(request.Body) 139 Expect(err).NotTo(HaveOccurred()) 140 Expect(bytes).To(Equal([]byte("foo"))) 141 }) 142 }) 143 144 When("the request's Content-Type is application/x-www-form-urlencoded", func() { 145 BeforeEach(func() { 146 request.Header.Set("Content-Type", "application/x-www-form-urlencoded") 147 }) 148 149 It("outputs the body", func() { 150 Expect(makeErr).NotTo(HaveOccurred()) 151 152 bytes, err := ioutil.ReadAll(request.Body) 153 Expect(err).NotTo(HaveOccurred()) 154 Expect(bytes).To(Equal([]byte("foo"))) 155 Expect(fakeOutput.DisplayMessageCallCount()).To(Equal(1)) 156 Expect(fakeOutput.DisplayMessageArgsForCall(0)).To(Equal("[application/x-www-form-urlencoded foo]")) 157 }) 158 }) 159 160 When("request's Content-Type is anything else", func() { 161 BeforeEach(func() { 162 request.Header.Set("Content-Type", "banana;rama") 163 }) 164 165 It("does not display the body", func() { 166 Expect(makeErr).NotTo(HaveOccurred()) 167 Expect(fakeOutput.DisplayJSONBodyCallCount()).To(Equal(1)) // Once for response body only 168 Expect(fakeOutput.DisplayMessageCallCount()).To(Equal(1)) 169 Expect(fakeOutput.DisplayMessageArgsForCall(0)).To(Equal("[banana Content Hidden]")) 170 }) 171 }) 172 }) 173 174 When("an error occurs while trying to log the request", func() { 175 var expectedErr error 176 177 BeforeEach(func() { 178 expectedErr = errors.New("this should never block the request") 179 180 calledOnce := false 181 fakeOutput.StartStub = func() error { 182 if !calledOnce { 183 calledOnce = true 184 return expectedErr 185 } 186 return nil 187 } 188 }) 189 190 It("should display the error and continue on", func() { 191 Expect(makeErr).NotTo(HaveOccurred()) 192 193 Expect(fakeOutput.HandleInternalErrorCallCount()).To(Equal(1)) 194 Expect(fakeOutput.HandleInternalErrorArgsForCall(0)).To(MatchError(expectedErr)) 195 }) 196 }) 197 198 When("the request is successful", func() { 199 BeforeEach(func() { 200 response = &router.Response{ 201 RawResponse: []byte("some-response-body"), 202 HTTPResponse: &http.Response{ 203 Proto: "HTTP/1.1", 204 Status: "200 OK", 205 Header: http.Header{ 206 "BBBBB": {"second"}, 207 "AAAAA": {"first"}, 208 "CCCCC": {"third"}, 209 }, 210 }, 211 } 212 }) 213 214 It("outputs the response", func() { 215 Expect(makeErr).NotTo(HaveOccurred()) 216 217 Expect(fakeOutput.DisplayTypeCallCount()).To(Equal(2)) 218 name, date := fakeOutput.DisplayTypeArgsForCall(1) 219 Expect(name).To(Equal("RESPONSE")) 220 Expect(date).To(BeTemporally("~", time.Now(), time.Second)) 221 222 Expect(fakeOutput.DisplayResponseHeaderCallCount()).To(Equal(1)) 223 protocol, status := fakeOutput.DisplayResponseHeaderArgsForCall(0) 224 Expect(protocol).To(Equal("HTTP/1.1")) 225 Expect(status).To(Equal("200 OK")) 226 227 Expect(fakeOutput.DisplayHeaderCallCount()).To(BeNumerically(">=", 6)) 228 name, value := fakeOutput.DisplayHeaderArgsForCall(3) 229 Expect(name).To(Equal("AAAAA")) 230 Expect(value).To(Equal("first")) 231 name, value = fakeOutput.DisplayHeaderArgsForCall(4) 232 Expect(name).To(Equal("BBBBB")) 233 Expect(value).To(Equal("second")) 234 name, value = fakeOutput.DisplayHeaderArgsForCall(5) 235 Expect(name).To(Equal("CCCCC")) 236 Expect(value).To(Equal("third")) 237 238 Expect(fakeOutput.DisplayJSONBodyCallCount()).To(BeNumerically(">=", 1)) 239 Expect(fakeOutput.DisplayJSONBodyArgsForCall(0)).To(Equal([]byte("some-response-body"))) 240 }) 241 }) 242 243 When("the request is unsuccessful", func() { 244 var expectedErr error 245 246 BeforeEach(func() { 247 expectedErr = errors.New("banana") 248 fakeConnection.MakeReturns(expectedErr) 249 }) 250 251 When("the http response is not set", func() { 252 BeforeEach(func() { 253 response = &router.Response{} 254 }) 255 256 It("outputs nothing", func() { 257 Expect(makeErr).To(MatchError(expectedErr)) 258 Expect(fakeOutput.DisplayResponseHeaderCallCount()).To(Equal(0)) 259 }) 260 }) 261 262 When("the http response is set", func() { 263 BeforeEach(func() { 264 response = &router.Response{ 265 RawResponse: []byte("some-error-body"), 266 HTTPResponse: &http.Response{ 267 Proto: "HTTP/1.1", 268 Status: "200 OK", 269 Header: http.Header{ 270 "BBBBB": {"second"}, 271 "AAAAA": {"first"}, 272 "CCCCC": {"third"}, 273 }, 274 }, 275 } 276 }) 277 278 It("outputs the response", func() { 279 Expect(makeErr).To(MatchError(expectedErr)) 280 281 Expect(fakeOutput.DisplayTypeCallCount()).To(Equal(2)) 282 name, date := fakeOutput.DisplayTypeArgsForCall(1) 283 Expect(name).To(Equal("RESPONSE")) 284 Expect(date).To(BeTemporally("~", time.Now(), time.Second)) 285 286 Expect(fakeOutput.DisplayResponseHeaderCallCount()).To(Equal(1)) 287 protocol, status := fakeOutput.DisplayResponseHeaderArgsForCall(0) 288 Expect(protocol).To(Equal("HTTP/1.1")) 289 Expect(status).To(Equal("200 OK")) 290 291 Expect(fakeOutput.DisplayHeaderCallCount()).To(BeNumerically(">=", 6)) 292 name, value := fakeOutput.DisplayHeaderArgsForCall(3) 293 Expect(name).To(Equal("AAAAA")) 294 Expect(value).To(Equal("first")) 295 name, value = fakeOutput.DisplayHeaderArgsForCall(4) 296 Expect(name).To(Equal("BBBBB")) 297 Expect(value).To(Equal("second")) 298 name, value = fakeOutput.DisplayHeaderArgsForCall(5) 299 Expect(name).To(Equal("CCCCC")) 300 Expect(value).To(Equal("third")) 301 302 Expect(fakeOutput.DisplayJSONBodyCallCount()).To(BeNumerically(">=", 1)) 303 Expect(fakeOutput.DisplayJSONBodyArgsForCall(0)).To(Equal([]byte("some-error-body"))) 304 }) 305 }) 306 }) 307 308 When("an error occurs while trying to log the response", func() { 309 var ( 310 originalErr error 311 expectedErr error 312 ) 313 314 BeforeEach(func() { 315 originalErr = errors.New("this error should not be overwritten") 316 fakeConnection.MakeReturns(originalErr) 317 318 expectedErr = errors.New("this should never block the request") 319 320 calledOnce := false 321 fakeOutput.StartStub = func() error { 322 if !calledOnce { 323 calledOnce = true 324 return nil 325 } 326 return expectedErr 327 } 328 }) 329 330 It("should display the error and continue on", func() { 331 Expect(makeErr).To(MatchError(originalErr)) 332 333 Expect(fakeOutput.HandleInternalErrorCallCount()).To(Equal(1)) 334 Expect(fakeOutput.HandleInternalErrorArgsForCall(0)).To(MatchError(expectedErr)) 335 }) 336 }) 337 338 It("starts and stops the output", func() { 339 Expect(fakeOutput.StartCallCount()).To(Equal(2)) 340 Expect(fakeOutput.StopCallCount()).To(Equal(2)) 341 }) 342 343 When("displaying the logs have an error", func() { 344 var expectedErr error 345 BeforeEach(func() { 346 expectedErr = errors.New("Display error on request") 347 fakeOutput.StartReturns(expectedErr) 348 }) 349 350 It("calls handle internal error", func() { 351 Expect(makeErr).ToNot(HaveOccurred()) 352 353 Expect(fakeOutput.HandleInternalErrorCallCount()).To(Equal(2)) 354 Expect(fakeOutput.HandleInternalErrorArgsForCall(0)).To(MatchError(expectedErr)) 355 Expect(fakeOutput.HandleInternalErrorArgsForCall(1)).To(MatchError(expectedErr)) 356 }) 357 }) 358 }) 359 })