github.com/randomtask1155/cli@v6.41.1-0.20181227003417-a98eed78cbde+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 231 Context("(401) Unauthorized", func() { 232 BeforeEach(func() { 233 serverResponseCode = http.StatusUnauthorized 234 }) 235 236 Context("generic 401", func() { 237 It("returns a UnauthorizedError", func() { 238 Expect(executeErr).To(MatchError(ccerror.UnauthorizedError{Message: "SomeCC Error Message"})) 239 }) 240 }) 241 242 Context("invalid token", func() { 243 BeforeEach(func() { 244 serverResponse = `{ 245 "code": 1000, 246 "description": "Invalid Auth Token", 247 "error_code": "CF-InvalidAuthToken" 248 }` 249 }) 250 251 It("returns an InvalidAuthTokenError", func() { 252 Expect(executeErr).To(MatchError(ccerror.InvalidAuthTokenError{Message: "Invalid Auth Token"})) 253 }) 254 }) 255 }) 256 257 Context("(403) Forbidden", func() { 258 BeforeEach(func() { 259 serverResponseCode = http.StatusForbidden 260 }) 261 262 It("returns a ForbiddenError", func() { 263 Expect(executeErr).To(MatchError(ccerror.ForbiddenError{Message: "SomeCC Error Message"})) 264 }) 265 }) 266 267 Context("(404) Not Found", func() { 268 BeforeEach(func() { 269 serverResponseCode = http.StatusNotFound 270 }) 271 272 When("the error is a json response from the cloud controller", func() { 273 It("returns a ResourceNotFoundError", func() { 274 Expect(executeErr).To(MatchError(ccerror.ResourceNotFoundError{Message: "SomeCC Error Message"})) 275 }) 276 }) 277 }) 278 279 Context("(422) Unprocessable Entity", func() { 280 BeforeEach(func() { 281 serverResponseCode = http.StatusUnprocessableEntity 282 }) 283 284 Context("generic Unprocessable entity", func() { 285 It("returns a UnprocessableEntityError", func() { 286 Expect(executeErr).To(MatchError(ccerror.UnprocessableEntityError{Message: "SomeCC Error Message"})) 287 }) 288 }) 289 290 When("creating a buildpack causes a name and stack collision", func() { 291 BeforeEach(func() { 292 serverResponse = `{ 293 "code": 290000, 294 "description": "The buildpack name foo is already in use for the stack bar", 295 "error_code": "CF-BuildpackNameStackTaken" 296 }` 297 }) 298 299 It("returns an BuildpackAlreadyExistsForStackError", func() { 300 Expect(executeErr).To(MatchError(ccerror.BuildpackAlreadyExistsForStackError{ 301 Message: "The buildpack name foo is already in use for the stack bar", 302 })) 303 }) 304 }) 305 306 }) 307 308 Context("unhandled Error Codes", func() { 309 BeforeEach(func() { 310 serverResponseCode = http.StatusTeapot 311 }) 312 313 It("returns an UnexpectedResponseError", func() { 314 Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{ 315 ResponseCode: http.StatusTeapot, 316 V2ErrorResponse: ccerror.V2ErrorResponse{ 317 Code: 777, 318 Description: "SomeCC Error Message", 319 ErrorCode: "CF-SomeError", 320 }, 321 RequestIDs: []string{ 322 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", 323 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f", 324 }, 325 })) 326 }) 327 }) 328 }) 329 330 When("the error is a 5XX error", func() { 331 BeforeEach(func() { 332 serverResponseCode = http.StatusInternalServerError 333 serverResponse = "{}" 334 }) 335 336 Context("(502) Bad Gateway", func() { 337 BeforeEach(func() { 338 serverResponseCode = http.StatusBadGateway 339 }) 340 341 When("the service broker catalog is invalid", func() { 342 BeforeEach(func() { 343 serverResponse = `{ 344 "description": "Service broker catalog is invalid: \nService overview-service\n Service dashboard client id must be unique\n", 345 "error_code": "CF-ServiceBrokerCatalogInvalid", 346 "code": 270012 347 }` 348 }) 349 350 It("returns a ServiceBrokerCatalogInvalidError", func() { 351 Expect(executeErr).To(MatchError(ccerror.ServiceBrokerCatalogInvalidError{ 352 Message: "Service broker catalog is invalid: \nService overview-service\n Service dashboard client id must be unique\n", 353 })) 354 }) 355 }) 356 357 When("the error_code is unknown", func() { 358 It("returns a V2UnexpectedResponseError with no json", func() { 359 Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{ 360 ResponseCode: http.StatusBadGateway, 361 V2ErrorResponse: ccerror.V2ErrorResponse{ 362 Description: serverResponse, 363 }, 364 RequestIDs: []string{ 365 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", 366 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f", 367 }, 368 })) 369 }) 370 }) 371 }) 372 373 Context("unhandled error codes", func() { 374 It("returns a V2UnexpectedResponseError with no json", func() { 375 Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{ 376 ResponseCode: http.StatusInternalServerError, 377 V2ErrorResponse: ccerror.V2ErrorResponse{ 378 Description: serverResponse, 379 }, 380 RequestIDs: []string{ 381 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95", 382 "6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f", 383 }, 384 })) 385 }) 386 }) 387 }) 388 }) 389 }) 390 })