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