github.com/dcarley/cf-cli@v6.24.1-0.20170220111324-4225ff346898+incompatible/api/cloudcontroller/cloud_controller_connection_test.go (about)

     1  package cloudcontroller_test
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"runtime"
     7  	"strings"
     8  
     9  	. "code.cloudfoundry.org/cli/api/cloudcontroller"
    10  	. "github.com/onsi/ginkgo"
    11  	. "github.com/onsi/gomega"
    12  	. "github.com/onsi/gomega/ghttp"
    13  )
    14  
    15  type DummyResponse struct {
    16  	Val1 string `json:"val1"`
    17  	Val2 int    `json:"val2"`
    18  }
    19  
    20  var _ = Describe("Cloud Controller Connection", func() {
    21  	var connection *CloudControllerConnection
    22  
    23  	BeforeEach(func() {
    24  		connection = NewConnection(Config{SkipSSLValidation: true})
    25  	})
    26  
    27  	Describe("Make", func() {
    28  		Describe("Data Unmarshalling", func() {
    29  			var request *http.Request
    30  
    31  			BeforeEach(func() {
    32  				response := `{
    33  					"val1":"2.59.0",
    34  					"val2":2
    35  				}`
    36  				server.AppendHandlers(
    37  					CombineHandlers(
    38  						VerifyRequest(http.MethodGet, "/v2/foo", ""),
    39  						RespondWith(http.StatusOK, response),
    40  					),
    41  				)
    42  
    43  				var err error
    44  				request, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
    45  				Expect(err).ToNot(HaveOccurred())
    46  			})
    47  
    48  			Context("when passed a response with a result set", func() {
    49  				It("unmarshals the data into a struct", func() {
    50  					var body DummyResponse
    51  					response := Response{
    52  						Result: &body,
    53  					}
    54  
    55  					err := connection.Make(request, &response)
    56  					Expect(err).NotTo(HaveOccurred())
    57  
    58  					Expect(body.Val1).To(Equal("2.59.0"))
    59  					Expect(body.Val2).To(Equal(2))
    60  				})
    61  			})
    62  
    63  			Context("when passed an empty response", func() {
    64  				It("skips the unmarshalling step", func() {
    65  					var response Response
    66  					err := connection.Make(request, &response)
    67  					Expect(err).NotTo(HaveOccurred())
    68  					Expect(response.Result).To(BeNil())
    69  				})
    70  			})
    71  		})
    72  
    73  		Describe("HTTP Response", func() {
    74  			var request *http.Request
    75  
    76  			BeforeEach(func() {
    77  				response := `{}`
    78  				server.AppendHandlers(
    79  					CombineHandlers(
    80  						VerifyRequest(http.MethodGet, "/v2/foo", ""),
    81  						RespondWith(http.StatusOK, response),
    82  					),
    83  				)
    84  
    85  				var err error
    86  				request, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
    87  				Expect(err).ToNot(HaveOccurred())
    88  			})
    89  
    90  			It("returns the status", func() {
    91  				response := Response{}
    92  
    93  				err := connection.Make(request, &response)
    94  				Expect(err).NotTo(HaveOccurred())
    95  
    96  				Expect(response.HTTPResponse.Status).To(Equal("200 OK"))
    97  			})
    98  		})
    99  
   100  		Describe("Response Headers", func() {
   101  			Describe("X-Cf-Warnings", func() {
   102  				BeforeEach(func() {
   103  					server.AppendHandlers(
   104  						CombineHandlers(
   105  							VerifyRequest(http.MethodGet, "/v2/foo"),
   106  							RespondWith(http.StatusOK, "{}", http.Header{"X-Cf-Warnings": {"42, Ed McMann, the 1942 doggers"}}),
   107  						),
   108  					)
   109  				})
   110  
   111  				It("returns them in Response", func() {
   112  					request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
   113  					Expect(err).ToNot(HaveOccurred())
   114  
   115  					var response Response
   116  					err = connection.Make(request, &response)
   117  					Expect(err).NotTo(HaveOccurred())
   118  
   119  					Expect(server.ReceivedRequests()).To(HaveLen(1))
   120  
   121  					warnings := response.Warnings
   122  					Expect(warnings).ToNot(BeNil())
   123  					Expect(warnings).To(HaveLen(3))
   124  					Expect(warnings).To(ContainElement("42"))
   125  					Expect(warnings).To(ContainElement("Ed McMann"))
   126  					Expect(warnings).To(ContainElement("the 1942 doggers"))
   127  				})
   128  			})
   129  		})
   130  
   131  		Describe("Errors", func() {
   132  			Context("when the server does not exist", func() {
   133  				BeforeEach(func() {
   134  					connection = NewConnection(Config{})
   135  				})
   136  
   137  				It("returns a RequestError", func() {
   138  					request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", "http://garbledyguk.com"), nil)
   139  					Expect(err).ToNot(HaveOccurred())
   140  
   141  					var response Response
   142  					err = connection.Make(request, &response)
   143  					Expect(err).To(HaveOccurred())
   144  
   145  					requestErr, ok := err.(RequestError)
   146  					Expect(ok).To(BeTrue())
   147  					Expect(requestErr.Error()).To(MatchRegexp(".*http://garbledyguk.com/v2/foo.*[nN]o such host"))
   148  				})
   149  			})
   150  
   151  			Context("when the server does not have a verified certificate", func() {
   152  				Context("skipSSLValidation is false", func() {
   153  					BeforeEach(func() {
   154  						server.AppendHandlers(
   155  							CombineHandlers(
   156  								VerifyRequest(http.MethodGet, "/v2/foo"),
   157  							),
   158  						)
   159  
   160  						connection = NewConnection(Config{})
   161  					})
   162  
   163  					It("returns a UnverifiedServerError", func() {
   164  						request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s", server.URL()), nil)
   165  						Expect(err).ToNot(HaveOccurred())
   166  
   167  						var response Response
   168  						err = connection.Make(request, &response)
   169  						Expect(err).To(MatchError(UnverifiedServerError{URL: server.URL()}))
   170  					})
   171  				})
   172  			})
   173  
   174  			Context("when the server's certificate does not match the hostname", func() {
   175  				Context("skipSSLValidation is false", func() {
   176  					BeforeEach(func() {
   177  						if runtime.GOOS == "windows" {
   178  							Skip("ssl validation has a different order on windows, will not be returned properly")
   179  						}
   180  						server.AppendHandlers(
   181  							CombineHandlers(
   182  								VerifyRequest(http.MethodGet, "/"),
   183  							),
   184  						)
   185  
   186  						connection = NewConnection(Config{})
   187  					})
   188  
   189  					// loopback.cli.ci.cf-app.com is a custom DNS record setup to point to 127.0.0.1
   190  					It("returns a SSLValidationHostnameError", func() {
   191  						altHostURL := strings.Replace(server.URL(), "127.0.0.1", "loopback.cli.ci.cf-app.com", -1)
   192  						request, err := http.NewRequest(http.MethodGet, altHostURL, nil)
   193  						Expect(err).ToNot(HaveOccurred())
   194  
   195  						var response Response
   196  						err = connection.Make(request, &response)
   197  						Expect(err).To(MatchError(SSLValidationHostnameError{
   198  							Message: "x509: certificate is valid for example.com, not loopback.cli.ci.cf-app.com",
   199  						}))
   200  					})
   201  				})
   202  			})
   203  
   204  			Describe("RawHTTPStatusError", func() {
   205  				var ccResponse string
   206  				BeforeEach(func() {
   207  					ccResponse = `{
   208  						"code": 90004,
   209  						"description": "The service binding could not be found: some-guid",
   210  						"error_code": "CF-ServiceBindingNotFound"
   211  					}`
   212  
   213  					server.AppendHandlers(
   214  						CombineHandlers(
   215  							VerifyRequest(http.MethodGet, "/v2/foo"),
   216  							RespondWith(http.StatusNotFound, ccResponse, http.Header{"X-Vcap-Request-Id": {"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f"}}),
   217  						),
   218  					)
   219  				})
   220  
   221  				It("returns a CCRawResponse", func() {
   222  					request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil)
   223  					Expect(err).ToNot(HaveOccurred())
   224  
   225  					var response Response
   226  					err = connection.Make(request, &response)
   227  					Expect(err).To(MatchError(RawHTTPStatusError{
   228  						StatusCode:  http.StatusNotFound,
   229  						RawResponse: []byte(ccResponse),
   230  						RequestIDs:  []string{"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f"},
   231  					}))
   232  
   233  					Expect(server.ReceivedRequests()).To(HaveLen(1))
   234  				})
   235  			})
   236  		})
   237  	})
   238  })