github.com/arunkumar7540/cli@v6.45.0+incompatible/api/cloudcontroller/ccv3/errors_test.go (about) 1 package ccv3_test 2 3 import ( 4 "net/http" 5 6 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 7 . "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 8 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 . "github.com/onsi/gomega/ghttp" 12 ) 13 14 var _ = Describe("Error Wrapper", func() { 15 var client *Client 16 17 BeforeEach(func() { 18 client, _ = NewTestClient() 19 }) 20 21 Describe("Make", func() { 22 var ( 23 serverResponse string 24 serverResponseCode int 25 makeError error 26 ) 27 28 BeforeEach(func() { 29 serverResponse = ` 30 { 31 "errors": [ 32 { 33 "code": 777, 34 "detail": "SomeCC Error Message", 35 "title": "CF-SomeError" 36 } 37 ] 38 }` 39 40 }) 41 42 JustBeforeEach(func() { 43 server.AppendHandlers( 44 CombineHandlers( 45 VerifyRequest(http.MethodGet, "/v3/apps"), 46 RespondWith(serverResponseCode, serverResponse, http.Header{ 47 "X-Vcap-Request-Id": { 48 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", 49 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f", 50 }, 51 }, 52 ), 53 ), 54 ) 55 56 _, _, makeError = client.GetApplications() 57 }) 58 59 When("we can't unmarshal the response successfully", func() { 60 BeforeEach(func() { 61 serverResponse = "I am not unmarshallable" 62 serverResponseCode = http.StatusNotFound 63 }) 64 65 It("returns an unknown http source error", func() { 66 Expect(makeError).To(MatchError(ccerror.UnknownHTTPSourceError{StatusCode: serverResponseCode, RawResponse: []byte(serverResponse)})) 67 }) 68 }) 69 70 When("the error is from the cloud controller", func() { 71 When("an empty list of errors is returned", func() { 72 BeforeEach(func() { 73 serverResponseCode = http.StatusUnauthorized 74 serverResponse = `{ "errors": [] }` 75 }) 76 77 It("returns an UnexpectedResponseError", func() { 78 Expect(makeError).To(MatchError(ccerror.V3UnexpectedResponseError{ 79 ResponseCode: http.StatusUnauthorized, 80 V3ErrorResponse: ccerror.V3ErrorResponse{Errors: []ccerror.V3Error{}}, 81 })) 82 }) 83 }) 84 85 When("the error is a 4XX error", func() { 86 Context("(401) Unauthorized", func() { 87 BeforeEach(func() { 88 serverResponseCode = http.StatusUnauthorized 89 }) 90 91 Context("generic 401", func() { 92 It("returns a UnauthorizedError", func() { 93 Expect(makeError).To(MatchError(ccerror.UnauthorizedError{Message: "SomeCC Error Message"})) 94 }) 95 }) 96 97 Context("invalid token", func() { 98 BeforeEach(func() { 99 serverResponse = `{ 100 "errors": [ 101 { 102 "code": 1000, 103 "detail": "Invalid Auth Token", 104 "title": "CF-InvalidAuthToken" 105 } 106 ] 107 }` 108 }) 109 110 It("returns an InvalidAuthTokenError", func() { 111 Expect(makeError).To(MatchError(ccerror.InvalidAuthTokenError{Message: "Invalid Auth Token"})) 112 }) 113 }) 114 }) 115 116 Context("(403) Forbidden", func() { 117 BeforeEach(func() { 118 serverResponseCode = http.StatusForbidden 119 }) 120 121 It("returns a ForbiddenError", func() { 122 Expect(makeError).To(MatchError(ccerror.ForbiddenError{Message: "SomeCC Error Message"})) 123 }) 124 }) 125 126 Context("(404) Not Found", func() { 127 BeforeEach(func() { 128 serverResponseCode = http.StatusNotFound 129 }) 130 131 Context("API is not found", func() { 132 133 BeforeEach(func() { 134 serverResponse = `{ 135 "errors": [ 136 { 137 "detail": "Unknown request", 138 "title": "CF-NotFound", 139 "code": 10000 140 } 141 ] 142 }` 143 }) 144 145 It("returns a APINotFoundError", func() { 146 Expect(makeError).To(MatchError(ccerror.APINotFoundError{URL: server.URL() + "/v3/apps"})) 147 }) 148 }) 149 150 When("a process is not found", func() { 151 BeforeEach(func() { 152 serverResponse = ` 153 { 154 "errors": [ 155 { 156 "code": 10010, 157 "detail": "Process not found", 158 "title": "CF-ResourceNotFound" 159 } 160 ] 161 }` 162 }) 163 164 It("returns a ProcessNotFoundError", func() { 165 Expect(makeError).To(MatchError(ccerror.ProcessNotFoundError{})) 166 }) 167 }) 168 169 When("an instance is not found", func() { 170 BeforeEach(func() { 171 serverResponse = ` 172 { 173 "errors": [ 174 { 175 "code": 10010, 176 "detail": "Instance not found", 177 "title": "CF-ResourceNotFound" 178 } 179 ] 180 }` 181 }) 182 183 It("returns an InstanceNotFoundError", func() { 184 Expect(makeError).To(MatchError(ccerror.InstanceNotFoundError{})) 185 }) 186 }) 187 188 When("an application is not found", func() { 189 BeforeEach(func() { 190 serverResponse = ` 191 { 192 "errors": [ 193 { 194 "code": 10010, 195 "detail": "App not found", 196 "title": "CF-ResourceNotFound" 197 } 198 ] 199 }` 200 }) 201 202 It("returns an AppNotFoundError", func() { 203 Expect(makeError).To(MatchError(ccerror.ApplicationNotFoundError{})) 204 }) 205 }) 206 207 When("a droplet is not found", func() { 208 BeforeEach(func() { 209 serverResponse = ` 210 { 211 "errors": [ 212 { 213 "code": 10010, 214 "detail": "Droplet not found", 215 "title": "CF-ResourceNotFound" 216 } 217 ] 218 }` 219 }) 220 221 It("returns a DropletNotFoundError", func() { 222 Expect(makeError).To(MatchError(ccerror.DropletNotFoundError{})) 223 }) 224 }) 225 226 Context("generic not found", func() { 227 228 It("returns a ResourceNotFoundError", func() { 229 Expect(makeError).To(MatchError(ccerror.ResourceNotFoundError{Message: "SomeCC Error Message"})) 230 }) 231 }) 232 }) 233 234 Context("(422) Unprocessable Entity", func() { 235 BeforeEach(func() { 236 serverResponseCode = http.StatusUnprocessableEntity 237 }) 238 239 When("the name isn't unique to space", func() { 240 BeforeEach(func() { 241 serverResponse = ` 242 { 243 "errors": [ 244 { 245 "code": 10008, 246 "detail": "name must be unique in space", 247 "title": "CF-UnprocessableEntity" 248 } 249 ] 250 }` 251 }) 252 253 It("returns a NameNotUniqueInSpaceError", func() { 254 Expect(makeError).To(MatchError(ccerror.NameNotUniqueInSpaceError{})) 255 }) 256 }) 257 258 When("the buildpack is invalid", func() { 259 BeforeEach(func() { 260 serverResponse = ` 261 { 262 "errors": [ 263 { 264 "code": 10008, 265 "detail": "Buildpack must be an existing admin buildpack or a valid git URI", 266 "title": "CF-UnprocessableEntity" 267 } 268 ] 269 }` 270 }) 271 272 It("returns an InvalidBuildpackError", func() { 273 Expect(makeError).To(MatchError(ccerror.InvalidBuildpackError{})) 274 }) 275 }) 276 277 When("the detail describes something else", func() { 278 BeforeEach(func() { 279 serverResponse = ` 280 { 281 "errors": [ 282 { 283 "code": 10008, 284 "detail": "SomeCC Error Message", 285 "title": "CF-UnprocessableEntity" 286 } 287 ] 288 }` 289 }) 290 291 It("returns a UnprocessableEntityError", func() { 292 Expect(makeError).To(MatchError(ccerror.UnprocessableEntityError{Message: "SomeCC Error Message"})) 293 }) 294 }) 295 }) 296 }) 297 298 When("the error is a 5XX error", func() { 299 Context("(503) Service Unavailable", func() { 300 BeforeEach(func() { 301 serverResponseCode = http.StatusServiceUnavailable 302 }) 303 304 It("returns a ServiceUnavailableError", func() { 305 Expect(makeError).To(MatchError(ccerror.ServiceUnavailableError{Message: "SomeCC Error Message"})) 306 }) 307 308 When("the title is 'CF-TaskWorkersUnavailable'", func() { 309 BeforeEach(func() { 310 serverResponse = `{ 311 "errors": [ 312 { 313 "code": 170020, 314 "detail": "Task workers are unavailable: Failed to open TCP connection to nsync.service.cf.internal:8787 (getaddrinfo: Name or service not known)", 315 "title": "CF-TaskWorkersUnavailable" 316 } 317 ] 318 }` 319 }) 320 321 It("returns a TaskWorkersUnavailableError", func() { 322 Expect(makeError).To(MatchError(ccerror.TaskWorkersUnavailableError{Message: "Task workers are unavailable: Failed to open TCP connection to nsync.service.cf.internal:8787 (getaddrinfo: Name or service not known)"})) 323 }) 324 }) 325 }) 326 327 Context("all other 5XX", func() { 328 BeforeEach(func() { 329 serverResponseCode = http.StatusBadGateway 330 serverResponse = "I am some text" 331 }) 332 333 It("returns a ServiceUnavailableError", func() { 334 Expect(makeError).To(MatchError(ccerror.V3UnexpectedResponseError{ 335 ResponseCode: http.StatusBadGateway, 336 RequestIDs: []string{ 337 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", 338 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f", 339 }, 340 V3ErrorResponse: ccerror.V3ErrorResponse{ 341 Errors: []ccerror.V3Error{{ 342 Detail: serverResponse, 343 }}, 344 }, 345 })) 346 }) 347 }) 348 }) 349 350 Context("Unhandled Error Codes", func() { 351 BeforeEach(func() { 352 serverResponseCode = http.StatusTeapot 353 }) 354 355 It("returns an UnexpectedResponseError", func() { 356 Expect(makeError).To(MatchError(ccerror.V3UnexpectedResponseError{ 357 ResponseCode: http.StatusTeapot, 358 V3ErrorResponse: ccerror.V3ErrorResponse{ 359 Errors: []ccerror.V3Error{ 360 { 361 Code: 777, 362 Detail: "SomeCC Error Message", 363 Title: "CF-SomeError", 364 }, 365 }, 366 }, 367 RequestIDs: []string{ 368 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", 369 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f", 370 }, 371 })) 372 }) 373 }) 374 375 Context("multiple errors", func() { 376 BeforeEach(func() { 377 serverResponseCode = http.StatusTeapot 378 serverResponse = `{ 379 "errors": [ 380 { 381 "code": 1000, 382 "detail": "Some CC Error Message", 383 "title": "CF-UnprocessableEntity" 384 }, 385 { 386 "code": 1001, 387 "detail": "Some CC Error Message", 388 "title": "CF-UnprocessableEntity" 389 } 390 ] 391 }` 392 }) 393 394 It("returns a MultiError", func() { 395 Expect(makeError).To(MatchError(ccerror.MultiError{ 396 ResponseCode: http.StatusTeapot, 397 Errors: []ccerror.V3Error{ 398 { 399 Code: 1000, 400 Detail: "Some CC Error Message", 401 Title: "CF-UnprocessableEntity", 402 }, 403 { 404 Code: 1001, 405 Detail: "Some CC Error Message", 406 Title: "CF-UnprocessableEntity", 407 }, 408 }, 409 })) 410 }) 411 }) 412 }) 413 }) 414 })