github.com/arunkumar7540/cli@v6.45.0+incompatible/api/cloudcontroller/ccv2/errors_test.go (about) 1 package ccv2_test 2 3 import ( 4 "fmt" 5 "net/http" 6 7 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 8 . "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2" 9 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 . "github.com/onsi/gomega/ghttp" 13 ) 14 15 var _ = Describe("Error Wrapper", func() { 16 var ( 17 serverResponse string 18 serverResponseCode int 19 executeErr error 20 21 client *Client 22 ) 23 24 Describe("Make", func() { 25 BeforeEach(func() { 26 serverResponse = `{ 27 "code": 777, 28 "description": "SomeCC Error Message", 29 "error_code": "CF-SomeError" 30 }` 31 32 client = NewTestClient() 33 }) 34 35 JustBeforeEach(func() { 36 server.AppendHandlers( 37 CombineHandlers( 38 VerifyRequest(http.MethodGet, "/v2/apps"), 39 RespondWith(serverResponseCode, serverResponse, http.Header{ 40 "X-Vcap-Request-Id": { 41 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", 42 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f", 43 }, 44 }, 45 ), 46 ), 47 ) 48 49 // Make a request to a CC endpoint - we stub the response, so the actual endpoint isn't relevant 50 _, _, executeErr = client.GetApplications() 51 }) 52 53 When("we can't unmarshal the response successfully", func() { 54 BeforeEach(func() { 55 serverResponse = "I am not unmarshallable" 56 }) 57 58 When("response code is 4XX", func() { 59 BeforeEach(func() { 60 serverResponseCode = http.StatusNotFound 61 }) 62 63 It("returns an unknown http source error", func() { 64 Expect(executeErr).To(MatchError(ccerror.UnknownHTTPSourceError{StatusCode: serverResponseCode, RawResponse: []byte(serverResponse)})) 65 }) 66 }) 67 68 When("response code is 5XX", func() { 69 BeforeEach(func() { 70 serverResponseCode = http.StatusBadGateway 71 }) 72 73 It("returns an unknown http source error", func() { 74 Expect(executeErr).To(MatchError(ccerror.UnknownHTTPSourceError{StatusCode: serverResponseCode, RawResponse: []byte(serverResponse)})) 75 }) 76 }) 77 }) 78 79 When("the error is from the cloud controller", func() { 80 When("the error is a 4XX error", func() { 81 Context("(400) Bad Request", func() { 82 BeforeEach(func() { 83 serverResponseCode = http.StatusBadRequest 84 }) 85 86 Context("generic 400", func() { 87 BeforeEach(func() { 88 serverResponse = `{ 89 "description": "bad request", 90 "error_code": "CF-BadRequest" 91 }` 92 }) 93 94 It("returns a BadRequestError", func() { 95 Expect(executeErr).To(MatchError(ccerror.BadRequestError{ 96 Message: "bad request", 97 })) 98 }) 99 }) 100 101 When("a not staged error is encountered", func() { 102 BeforeEach(func() { 103 serverResponse = `{ 104 "description": "App has not finished staging", 105 "error_code": "CF-NotStaged" 106 }` 107 }) 108 109 It("returns a NotStagedError", func() { 110 Expect(executeErr).To(MatchError(ccerror.NotStagedError{ 111 Message: "App has not finished staging", 112 })) 113 }) 114 }) 115 116 When("an instances error is encountered", func() { 117 BeforeEach(func() { 118 serverResponse = `{ 119 "description": "instances went bananas", 120 "error_code": "CF-InstancesError" 121 }` 122 }) 123 124 It("returns an InstancesError", func() { 125 Expect(executeErr).To(MatchError(ccerror.InstancesError{ 126 Message: "instances went bananas", 127 })) 128 }) 129 }) 130 131 When("creating a relation that is invalid", func() { 132 BeforeEach(func() { 133 serverResponse = `{ 134 "code": 1002, 135 "description": "The requested app relation is invalid: the app and route must belong to the same space", 136 "error_code": "CF-InvalidRelation" 137 }` 138 }) 139 140 It("returns an InvalidRelationError", func() { 141 Expect(executeErr).To(MatchError(ccerror.InvalidRelationError{ 142 Message: "The requested app relation is invalid: the app and route must belong to the same space", 143 })) 144 }) 145 }) 146 147 Context("getting stats for a stopped app", func() { 148 BeforeEach(func() { 149 serverResponse = `{ 150 "code": 200003, 151 "description": "Could not fetch stats for stopped app: some-app", 152 "error_code": "CF-AppStoppedStatsError" 153 }` 154 }) 155 156 It("returns an AppStoppedStatsError", func() { 157 Expect(executeErr).To(MatchError(ccerror.ApplicationStoppedStatsError{ 158 Message: "Could not fetch stats for stopped app: some-app", 159 })) 160 }) 161 }) 162 163 When("creating a buildpack with nil stack that already exists", func() { 164 BeforeEach(func() { 165 serverResponse = `{ 166 "description": "Buildpack is invalid: stack unique", 167 "error_code": "CF-BuildpackInvalid", 168 "code": 290003 169 }` 170 }) 171 172 It("returns an BuildpackAlreadyExistsWithoutStackError", func() { 173 Expect(executeErr).To(MatchError(ccerror.BuildpackAlreadyExistsWithoutStackError{ 174 Message: "Buildpack is invalid: stack unique", 175 })) 176 }) 177 }) 178 179 When("creating a buildpack causes a name collision", func() { 180 BeforeEach(func() { 181 serverResponse = `{ 182 "code": 290001, 183 "description": "The buildpack name is already in use: foo", 184 "error_code": "CF-BuildpackNameTaken" 185 }` 186 }) 187 188 It("returns an BuildpackNameTakenError", func() { 189 Expect(executeErr).To(MatchError(ccerror.BuildpackNameTakenError{ 190 Message: "The buildpack name is already in use: foo", 191 })) 192 }) 193 }) 194 195 When("creating an organization fails because the name is taken", func() { 196 BeforeEach(func() { 197 serverResponse = `{ 198 "code": 30002, 199 "description": "The organization name is taken: potato", 200 "error_code": "CF-OrganizationNameTaken" 201 }` 202 }) 203 204 It("returns a OrganizationNameTakenError", func() { 205 Expect(executeErr).To(MatchError(ccerror.OrganizationNameTakenError{ 206 Message: "The organization name is taken: potato", 207 })) 208 }) 209 }) 210 211 When("creating a space fails because the name is taken", func() { 212 BeforeEach(func() { 213 serverResponse = `{ 214 "code": 40002, 215 "description": "The app space name is taken: potato", 216 "error_code": "CF-SpaceNameTaken" 217 }` 218 }) 219 220 It("returns a SpaceNameTakenError", func() { 221 if e, ok := executeErr.(ccerror.UnknownHTTPSourceError); ok { 222 fmt.Printf("TV %s", string(e.RawResponse)) 223 } 224 Expect(executeErr).To(MatchError(ccerror.SpaceNameTakenError{ 225 Message: "The app space name is taken: potato", 226 })) 227 }) 228 }) 229 230 When("creating a service instance fails because the name is taken", func() { 231 BeforeEach(func() { 232 serverResponse = `{ 233 "code": 40002, 234 "description": "Service instance name is taken: potato", 235 "error_code": "CF-ServiceInstanceNameTaken" 236 }` 237 }) 238 239 It("returns a ServiceInstanceNameTakenError", func() { 240 Expect(executeErr).To(MatchError(ccerror.ServiceInstanceNameTakenError{ 241 Message: "Service instance name is taken: potato", 242 })) 243 }) 244 }) 245 246 When("creating a service plan visibility fails because it already exists", func() { 247 BeforeEach(func() { 248 serverResponse = `{ 249 "code": 40002, 250 "description": "Service plan visibility already exists", 251 "error_code": "CF-ServicePlanVisibilityAlreadyExists" 252 }` 253 }) 254 255 It("returns a ServicePlanVisibilityExistsError", func() { 256 Expect(executeErr).To(MatchError(ccerror.ServicePlanVisibilityExistsError{ 257 Message: "Service plan visibility already exists", 258 })) 259 }) 260 }) 261 }) 262 263 Context("(401) Unauthorized", func() { 264 BeforeEach(func() { 265 serverResponseCode = http.StatusUnauthorized 266 }) 267 268 Context("generic 401", func() { 269 It("returns a UnauthorizedError", func() { 270 Expect(executeErr).To(MatchError(ccerror.UnauthorizedError{Message: "SomeCC Error Message"})) 271 }) 272 }) 273 274 Context("invalid token", func() { 275 BeforeEach(func() { 276 serverResponse = `{ 277 "code": 1000, 278 "description": "Invalid Auth Token", 279 "error_code": "CF-InvalidAuthToken" 280 }` 281 }) 282 283 It("returns an InvalidAuthTokenError", func() { 284 Expect(executeErr).To(MatchError(ccerror.InvalidAuthTokenError{Message: "Invalid Auth Token"})) 285 }) 286 }) 287 }) 288 289 Context("(403) Forbidden", func() { 290 BeforeEach(func() { 291 serverResponseCode = http.StatusForbidden 292 }) 293 294 It("returns a ForbiddenError", func() { 295 Expect(executeErr).To(MatchError(ccerror.ForbiddenError{Message: "SomeCC Error Message"})) 296 }) 297 }) 298 299 Context("(404) Not Found", func() { 300 BeforeEach(func() { 301 serverResponseCode = http.StatusNotFound 302 }) 303 304 When("the error is a json response from the cloud controller", func() { 305 It("returns a ResourceNotFoundError", func() { 306 Expect(executeErr).To(MatchError(ccerror.ResourceNotFoundError{Message: "SomeCC Error Message"})) 307 }) 308 }) 309 }) 310 311 Context("(422) Unprocessable Entity", func() { 312 BeforeEach(func() { 313 serverResponseCode = http.StatusUnprocessableEntity 314 }) 315 316 Context("generic Unprocessable entity", func() { 317 It("returns a UnprocessableEntityError", func() { 318 Expect(executeErr).To(MatchError(ccerror.UnprocessableEntityError{Message: "SomeCC Error Message"})) 319 }) 320 }) 321 322 When("creating a buildpack causes a name and stack collision", func() { 323 BeforeEach(func() { 324 serverResponse = `{ 325 "code": 290000, 326 "description": "The buildpack name foo is already in use for the stack bar", 327 "error_code": "CF-BuildpackNameStackTaken" 328 }` 329 }) 330 331 It("returns an BuildpackAlreadyExistsForStackError", func() { 332 Expect(executeErr).To(MatchError(ccerror.BuildpackAlreadyExistsForStackError{ 333 Message: "The buildpack name foo is already in use for the stack bar", 334 })) 335 }) 336 }) 337 338 }) 339 340 Context("unhandled Error Codes", func() { 341 BeforeEach(func() { 342 serverResponseCode = http.StatusTeapot 343 }) 344 345 It("returns an UnexpectedResponseError", func() { 346 Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{ 347 ResponseCode: http.StatusTeapot, 348 V2ErrorResponse: ccerror.V2ErrorResponse{ 349 Code: 777, 350 Description: "SomeCC Error Message", 351 ErrorCode: "CF-SomeError", 352 }, 353 RequestIDs: []string{ 354 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", 355 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f", 356 }, 357 })) 358 }) 359 }) 360 }) 361 362 When("the error is a 5XX error", func() { 363 BeforeEach(func() { 364 serverResponseCode = http.StatusInternalServerError 365 serverResponse = "{}" 366 }) 367 368 Context("(502) Bad Gateway", func() { 369 BeforeEach(func() { 370 serverResponseCode = http.StatusBadGateway 371 }) 372 373 When("the service broker catalog is invalid", func() { 374 BeforeEach(func() { 375 serverResponse = `{ 376 "description": "Service broker catalog is invalid: \nService overview-service\n Service dashboard client id must be unique\n", 377 "error_code": "CF-ServiceBrokerCatalogInvalid", 378 "code": 270012 379 }` 380 }) 381 382 It("returns a ServiceBrokerCatalogInvalidError", func() { 383 Expect(executeErr).To(MatchError(ccerror.ServiceBrokerCatalogInvalidError{ 384 Message: "Service broker catalog is invalid: \nService overview-service\n Service dashboard client id must be unique\n", 385 })) 386 }) 387 }) 388 389 When("the service broker rejected the request", func() { 390 BeforeEach(func() { 391 serverResponse = `{ 392 "description": "The service broker rejected the request to https://broker.example.com/v2/service_instances/1a3794e9-7ddf-4cae-b66a-6a0453c85a3e?accepts_incomplete=true. Status Code: 400 Bad Request, Body: instance requires property \"name\"", 393 "error_code": "CF-ServiceBrokerRequestRejected", 394 "code": 10001 395 }` 396 }) 397 398 It("returns a ServiceBrokerRequestRejectedError", func() { 399 Expect(executeErr).To(MatchError(ccerror.ServiceBrokerRequestRejectedError{ 400 Message: `The service broker rejected the request to https://broker.example.com/v2/service_instances/1a3794e9-7ddf-4cae-b66a-6a0453c85a3e?accepts_incomplete=true. Status Code: 400 Bad Request, Body: instance requires property "name"`, 401 })) 402 }) 403 }) 404 405 When("the service broker responded with bad response", func() { 406 BeforeEach(func() { 407 serverResponse = `{ 408 "description": "Service broker error", 409 "error_code": "CF-ServiceBrokerBadResponse", 410 "code": 10001, 411 "http": { 412 "uri": "https://broker.url/v2/service_instances/593fe03a-3eda-4a53-93ed-aa30f309b120?accepts_incomplete=true", 413 "method": "PUT", 414 "status": 500 415 } 416 }` 417 }) 418 419 It("returns a ServiceBrokerBadResponseError", func() { 420 Expect(executeErr).To(MatchError(ccerror.ServiceBrokerBadResponseError{ 421 Message: `Service broker error`, 422 })) 423 }) 424 }) 425 426 When("the error_code is unknown", func() { 427 It("returns a V2UnexpectedResponseError with no json", func() { 428 Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{ 429 ResponseCode: http.StatusBadGateway, 430 V2ErrorResponse: ccerror.V2ErrorResponse{ 431 Description: serverResponse, 432 }, 433 RequestIDs: []string{ 434 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", 435 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f", 436 }, 437 })) 438 }) 439 }) 440 }) 441 442 Context("unhandled error codes", func() { 443 It("returns a V2UnexpectedResponseError with no json", func() { 444 Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{ 445 ResponseCode: http.StatusInternalServerError, 446 V2ErrorResponse: ccerror.V2ErrorResponse{ 447 Description: serverResponse, 448 }, 449 RequestIDs: []string{ 450 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", 451 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f", 452 }, 453 })) 454 }) 455 }) 456 }) 457 }) 458 }) 459 })