github.com/arunkumar7540/cli@v6.45.0+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 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 11 . "github.com/onsi/ginkgo" 12 . "github.com/onsi/gomega" 13 . "github.com/onsi/gomega/ghttp" 14 ) 15 16 type DummyResponse struct { 17 Val1 string `json:"val1"` 18 Val2 int `json:"val2"` 19 Val3 interface{} `json:"val3,omitempty"` 20 } 21 22 var _ = Describe("Cloud Controller Connection", func() { 23 var connection *CloudControllerConnection 24 25 BeforeEach(func() { 26 connection = NewConnection(Config{SkipSSLValidation: true}) 27 }) 28 29 Describe("Make", func() { 30 Describe("Data Unmarshalling", func() { 31 var request *Request 32 33 BeforeEach(func() { 34 response := `{ 35 "val1":"2.59.0", 36 "val2":2, 37 "val3":1111111111111111111 38 }` 39 server.AppendHandlers( 40 CombineHandlers( 41 VerifyRequest(http.MethodGet, "/v2/foo", ""), 42 RespondWith(http.StatusOK, response), 43 ), 44 ) 45 46 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil) 47 Expect(err).ToNot(HaveOccurred()) 48 request = &Request{Request: req} 49 }) 50 51 When("passed a response with a result set", func() { 52 It("unmarshals the data into a struct", func() { 53 var body DummyResponse 54 response := Response{ 55 DecodeJSONResponseInto: &body, 56 } 57 58 err := connection.Make(request, &response) 59 Expect(err).NotTo(HaveOccurred()) 60 61 Expect(body.Val1).To(Equal("2.59.0")) 62 Expect(body.Val2).To(Equal(2)) 63 }) 64 65 It("keeps numbers unmarshalled to interfaces as interfaces", func() { 66 var body DummyResponse 67 response := Response{ 68 DecodeJSONResponseInto: &body, 69 } 70 71 err := connection.Make(request, &response) 72 Expect(err).NotTo(HaveOccurred()) 73 Expect(fmt.Sprint(body.Val3)).To(Equal("1111111111111111111")) 74 }) 75 }) 76 77 When("passed an empty response", func() { 78 It("skips the unmarshalling step", func() { 79 var response Response 80 err := connection.Make(request, &response) 81 Expect(err).NotTo(HaveOccurred()) 82 Expect(response.DecodeJSONResponseInto).To(BeNil()) 83 }) 84 }) 85 }) 86 87 Describe("HTTP Response", func() { 88 var request *Request 89 90 BeforeEach(func() { 91 response := `{}` 92 server.AppendHandlers( 93 CombineHandlers( 94 VerifyRequest(http.MethodGet, "/v2/foo", ""), 95 RespondWith(http.StatusOK, response), 96 ), 97 ) 98 99 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil) 100 Expect(err).ToNot(HaveOccurred()) 101 request = &Request{Request: req} 102 }) 103 104 It("returns the status", func() { 105 response := Response{} 106 107 err := connection.Make(request, &response) 108 Expect(err).NotTo(HaveOccurred()) 109 110 Expect(response.HTTPResponse.Status).To(Equal("200 OK")) 111 }) 112 }) 113 114 Describe("Response Headers", func() { 115 Describe("Location", func() { 116 BeforeEach(func() { 117 server.AppendHandlers( 118 CombineHandlers( 119 VerifyRequest(http.MethodGet, "/v2/foo"), 120 RespondWith(http.StatusAccepted, "{}", http.Header{"Location": {"/v2/some-location"}}), 121 ), 122 ) 123 }) 124 125 It("returns the location in the ResourceLocationURL", func() { 126 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil) 127 Expect(err).ToNot(HaveOccurred()) 128 request := &Request{Request: req} 129 130 var response Response 131 err = connection.Make(request, &response) 132 Expect(err).NotTo(HaveOccurred()) 133 134 Expect(server.ReceivedRequests()).To(HaveLen(1)) 135 Expect(response.ResourceLocationURL).To(Equal("/v2/some-location")) 136 }) 137 }) 138 139 Describe("X-Cf-Warnings", func() { 140 When("there are warnings", func() { 141 BeforeEach(func() { 142 server.AppendHandlers( 143 CombineHandlers( 144 VerifyRequest(http.MethodGet, "/v2/foo"), 145 RespondWith(http.StatusOK, "{}", http.Header{"X-Cf-Warnings": {"42,+Ed+McMann,+the+1942+doggers,a%2Cb"}}), 146 ), 147 ) 148 }) 149 150 It("returns them in Response", func() { 151 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil) 152 Expect(err).ToNot(HaveOccurred()) 153 request := &Request{Request: req} 154 155 var response Response 156 err = connection.Make(request, &response) 157 Expect(err).NotTo(HaveOccurred()) 158 159 Expect(server.ReceivedRequests()).To(HaveLen(1)) 160 161 warnings := response.Warnings 162 Expect(warnings).ToNot(BeNil()) 163 Expect(warnings).To(HaveLen(4)) 164 Expect(warnings).To(ContainElement("42")) 165 Expect(warnings).To(ContainElement("Ed McMann")) 166 Expect(warnings).To(ContainElement("the 1942 doggers")) 167 Expect(warnings).To(ContainElement("a,b")) 168 }) 169 }) 170 171 When("there are no warnings", func() { 172 BeforeEach(func() { 173 server.AppendHandlers( 174 CombineHandlers( 175 VerifyRequest(http.MethodGet, "/v2/foo"), 176 RespondWith(http.StatusOK, "{}"), 177 ), 178 ) 179 }) 180 181 It("returns them in Response", func() { 182 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil) 183 Expect(err).ToNot(HaveOccurred()) 184 request := &Request{Request: req} 185 186 var response Response 187 err = connection.Make(request, &response) 188 Expect(err).NotTo(HaveOccurred()) 189 190 Expect(response.Warnings).To(BeEmpty()) 191 Expect(server.ReceivedRequests()).To(HaveLen(1)) 192 }) 193 }) 194 }) 195 }) 196 197 Describe("Errors", func() { 198 When("the server does not exist", func() { 199 BeforeEach(func() { 200 connection = NewConnection(Config{}) 201 }) 202 203 It("returns a RequestError", func() { 204 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", "http://garbledyguk.com"), nil) 205 Expect(err).ToNot(HaveOccurred()) 206 request := &Request{Request: req} 207 208 var response Response 209 err = connection.Make(request, &response) 210 Expect(err).To(HaveOccurred()) 211 212 requestErr, ok := err.(ccerror.RequestError) 213 Expect(ok).To(BeTrue()) 214 Expect(requestErr.Error()).To(MatchRegexp(".*http://garbledyguk.com/v2/foo.*[nN]o such host")) 215 }) 216 }) 217 218 When("the server does not have a verified certificate", func() { 219 Context("skipSSLValidation is false", func() { 220 BeforeEach(func() { 221 server.AppendHandlers( 222 CombineHandlers( 223 VerifyRequest(http.MethodGet, "/v2/foo"), 224 ), 225 ) 226 227 connection = NewConnection(Config{}) 228 }) 229 230 It("returns a UnverifiedServerError", func() { 231 req, err := http.NewRequest(http.MethodGet, server.URL(), nil) 232 Expect(err).ToNot(HaveOccurred()) 233 request := &Request{Request: req} 234 235 var response Response 236 err = connection.Make(request, &response) 237 Expect(err).To(MatchError(ccerror.UnverifiedServerError{URL: server.URL()})) 238 }) 239 }) 240 }) 241 242 When("the server's certificate does not match the hostname", func() { 243 Context("skipSSLValidation is false", func() { 244 BeforeEach(func() { 245 if runtime.GOOS == "windows" { 246 Skip("ssl validation has a different order on windows, will not be returned properly") 247 } 248 server.AppendHandlers( 249 CombineHandlers( 250 VerifyRequest(http.MethodGet, "/"), 251 ), 252 ) 253 254 connection = NewConnection(Config{}) 255 }) 256 257 // loopback.cli.fun is a custom DNS record setup to point to 127.0.0.1 258 It("returns a SSLValidationHostnameError", func() { 259 altHostURL := strings.Replace(server.URL(), "127.0.0.1", "loopback.cli.fun", -1) 260 req, err := http.NewRequest(http.MethodGet, altHostURL, nil) 261 Expect(err).ToNot(HaveOccurred()) 262 request := &Request{Request: req} 263 264 var response Response 265 err = connection.Make(request, &response) 266 Expect(err).To(MatchError(ccerror.SSLValidationHostnameError{ 267 Message: "x509: certificate is valid for example.com, not loopback.cli.fun", 268 })) 269 }) 270 }) 271 }) 272 273 Describe("RawHTTPStatusError", func() { 274 var ccResponse string 275 BeforeEach(func() { 276 ccResponse = `{ 277 "code": 90004, 278 "description": "The service binding could not be found: some-guid", 279 "error_code": "CF-ServiceBindingNotFound" 280 }` 281 282 server.AppendHandlers( 283 CombineHandlers( 284 VerifyRequest(http.MethodGet, "/v2/foo"), 285 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"}}), 286 ), 287 ) 288 }) 289 290 It("returns a CCRawResponse", func() { 291 req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/foo", server.URL()), nil) 292 Expect(err).ToNot(HaveOccurred()) 293 request := &Request{Request: req} 294 295 var response Response 296 err = connection.Make(request, &response) 297 Expect(err).To(MatchError(ccerror.RawHTTPStatusError{ 298 StatusCode: http.StatusNotFound, 299 RawResponse: []byte(ccResponse), 300 RequestIDs: []string{"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f"}, 301 })) 302 303 Expect(server.ReceivedRequests()).To(HaveLen(1)) 304 }) 305 }) 306 }) 307 }) 308 })