github.com/jghiloni/cli@v6.28.1-0.20170628223758-0ce05fe032a2+incompatible/api/cloudcontroller/ccv2/application_test.go (about) 1 package ccv2_test 2 3 import ( 4 "net/http" 5 "time" 6 7 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 8 . "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2" 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 . "github.com/onsi/gomega/ghttp" 12 ) 13 14 var _ = Describe("Application", func() { 15 var client *Client 16 17 BeforeEach(func() { 18 client = NewTestClient() 19 }) 20 21 Describe("CreateApplication", func() { 22 Context("when the update is successful", func() { 23 Context("when setting the minimum", func() { // are we **only** encoding the things we want 24 BeforeEach(func() { 25 response := ` 26 { 27 "metadata": { 28 "guid": "some-app-guid" 29 }, 30 "entity": { 31 "name": "some-app-name", 32 "space_guid": "some-space-guid" 33 } 34 }` 35 requestBody := map[string]string{ 36 "name": "some-app-name", 37 "space_guid": "some-space-guid", 38 } 39 server.AppendHandlers( 40 CombineHandlers( 41 VerifyRequest(http.MethodPost, "/v2/apps"), 42 VerifyJSONRepresenting(requestBody), 43 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 44 ), 45 ) 46 }) 47 48 It("returns the created object and warnings", func() { 49 app, warnings, err := client.CreateApplication(Application{ 50 Name: "some-app-name", 51 SpaceGUID: "some-space-guid", 52 }) 53 Expect(err).NotTo(HaveOccurred()) 54 55 Expect(app).To(Equal(Application{ 56 GUID: "some-app-guid", 57 Name: "some-app-name", 58 })) 59 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 60 }) 61 }) 62 }) 63 64 Context("when the create returns an error", func() { 65 BeforeEach(func() { 66 response := ` 67 { 68 "description": "Request invalid due to parse error: Field: name, Error: Missing field name, Field: space_guid, Error: Missing field space_guid", 69 "error_code": "CF-MessageParseError", 70 "code": 1001 71 } 72 ` 73 server.AppendHandlers( 74 CombineHandlers( 75 VerifyRequest(http.MethodPost, "/v2/apps"), 76 RespondWith(http.StatusBadRequest, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 77 ), 78 ) 79 }) 80 81 It("returns the error and warnings", func() { 82 _, warnings, err := client.CreateApplication(Application{}) 83 Expect(err).To(MatchError(ccerror.BadRequestError{Message: "Request invalid due to parse error: Field: name, Error: Missing field name, Field: space_guid, Error: Missing field space_guid"})) 84 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 85 }) 86 }) 87 }) 88 89 Describe("GetApplication", func() { 90 BeforeEach(func() { 91 response := `{ 92 "metadata": { 93 "guid": "app-guid-1", 94 "updated_at": null 95 }, 96 "entity": { 97 "buildpack": "ruby 1.6.29", 98 "detected_start_command": "echo 'I am a banana'", 99 "disk_quota": 586, 100 "detected_buildpack": null, 101 "docker_image": "some-docker-path", 102 "health_check_type": "port", 103 "health_check_http_endpoint": "/", 104 "instances": 13, 105 "memory": 1024, 106 "name": "app-name-1", 107 "package_state": "FAILED", 108 "package_updated_at": "2015-03-10T23:11:54Z", 109 "stack_guid": "some-stack-guid", 110 "staging_failed_description": "some-staging-failed-description", 111 "staging_failed_reason": "some-reason", 112 "state": "STOPPED" 113 } 114 }` 115 server.AppendHandlers( 116 CombineHandlers( 117 VerifyRequest(http.MethodGet, "/v2/apps/app-guid-1"), 118 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 119 ), 120 ) 121 }) 122 123 Context("when apps exist", func() { 124 It("returns the app", func() { 125 app, warnings, err := client.GetApplication("app-guid-1") 126 Expect(err).NotTo(HaveOccurred()) 127 128 updatedAt, err := time.Parse(time.RFC3339, "2015-03-10T23:11:54Z") 129 Expect(err).NotTo(HaveOccurred()) 130 131 Expect(app).To(Equal(Application{ 132 Buildpack: "ruby 1.6.29", 133 DetectedBuildpack: "", 134 DetectedStartCommand: "echo 'I am a banana'", 135 DiskQuota: 586, 136 DockerImage: "some-docker-path", 137 GUID: "app-guid-1", 138 HealthCheckType: "port", 139 HealthCheckHTTPEndpoint: "/", 140 Instances: 13, 141 Memory: 1024, 142 Name: "app-name-1", 143 PackageState: ApplicationPackageFailed, 144 PackageUpdatedAt: updatedAt, 145 StackGUID: "some-stack-guid", 146 StagingFailedDescription: "some-staging-failed-description", 147 StagingFailedReason: "some-reason", 148 State: ApplicationStopped, 149 })) 150 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 151 }) 152 }) 153 }) 154 155 Describe("GetApplications", func() { 156 BeforeEach(func() { 157 response1 := `{ 158 "next_url": "/v2/apps?q=space_guid:some-space-guid&page=2", 159 "resources": [ 160 { 161 "metadata": { 162 "guid": "app-guid-1", 163 "updated_at": null 164 }, 165 "entity": { 166 "buildpack": "ruby 1.6.29", 167 "detected_start_command": "echo 'I am a banana'", 168 "disk_quota": 586, 169 "detected_buildpack": null, 170 "health_check_type": "port", 171 "health_check_http_endpoint": "/", 172 "instances": 13, 173 "memory": 1024, 174 "name": "app-name-1", 175 "package_state": "FAILED", 176 "package_updated_at": "2015-03-10T23:11:54Z", 177 "stack_guid": "some-stack-guid", 178 "staging_failed_reason": "some-reason", 179 "state": "STOPPED" 180 } 181 }, 182 { 183 "metadata": { 184 "guid": "app-guid-2", 185 "updated_at": null 186 }, 187 "entity": { 188 "name": "app-name-2", 189 "detected_buildpack": "ruby 1.6.29", 190 "package_updated_at": null 191 } 192 } 193 ] 194 }` 195 response2 := `{ 196 "next_url": null, 197 "resources": [ 198 { 199 "metadata": { 200 "guid": "app-guid-3", 201 "updated_at": null 202 }, 203 "entity": { 204 "name": "app-name-3" 205 } 206 }, 207 { 208 "metadata": { 209 "guid": "app-guid-4", 210 "updated_at": null 211 }, 212 "entity": { 213 "name": "app-name-4" 214 } 215 } 216 ] 217 }` 218 server.AppendHandlers( 219 CombineHandlers( 220 VerifyRequest(http.MethodGet, "/v2/apps", "q=space_guid:some-space-guid"), 221 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 222 ), 223 ) 224 server.AppendHandlers( 225 CombineHandlers( 226 VerifyRequest(http.MethodGet, "/v2/apps", "q=space_guid:some-space-guid&page=2"), 227 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}), 228 ), 229 ) 230 }) 231 232 Context("when apps exist", func() { 233 It("returns all the queried apps", func() { 234 apps, warnings, err := client.GetApplications([]Query{{ 235 Filter: SpaceGUIDFilter, 236 Operator: EqualOperator, 237 Value: "some-space-guid", 238 }}) 239 Expect(err).NotTo(HaveOccurred()) 240 241 updatedAt, err := time.Parse(time.RFC3339, "2015-03-10T23:11:54Z") 242 Expect(err).NotTo(HaveOccurred()) 243 244 Expect(apps).To(ConsistOf([]Application{ 245 { 246 Buildpack: "ruby 1.6.29", 247 DetectedBuildpack: "", 248 DetectedStartCommand: "echo 'I am a banana'", 249 DiskQuota: 586, 250 GUID: "app-guid-1", 251 HealthCheckType: "port", 252 HealthCheckHTTPEndpoint: "/", 253 Instances: 13, 254 Memory: 1024, 255 Name: "app-name-1", 256 PackageState: ApplicationPackageFailed, 257 PackageUpdatedAt: updatedAt, 258 StackGUID: "some-stack-guid", 259 StagingFailedReason: "some-reason", 260 State: ApplicationStopped, 261 }, 262 {Name: "app-name-2", GUID: "app-guid-2", DetectedBuildpack: "ruby 1.6.29"}, 263 {Name: "app-name-3", GUID: "app-guid-3"}, 264 {Name: "app-name-4", GUID: "app-guid-4"}, 265 })) 266 Expect(warnings).To(ConsistOf(Warnings{"this is a warning", "this is another warning"})) 267 }) 268 }) 269 }) 270 271 Describe("UpdateApplication", func() { 272 Context("when the update is successful", func() { 273 Context("when updating all fields", func() { //are we encoding everything correctly? 274 BeforeEach(func() { 275 response1 := `{ 276 "metadata": { 277 "guid": "some-app-guid", 278 "updated_at": null 279 }, 280 "entity": { 281 "buildpack": "ruby 1.6.29", 282 "detected_start_command": "echo 'I am a banana'", 283 "disk_quota": 586, 284 "detected_buildpack": null, 285 "docker_image": "some-docker-path", 286 "health_check_type": "some-health-check-type", 287 "health_check_http_endpoint": "/anything", 288 "instances": 13, 289 "memory": 1024, 290 "name": "app-name-1", 291 "package_updated_at": "2015-03-10T23:11:54Z", 292 "stack_guid": "some-stack-guid", 293 "state": "STARTED" 294 } 295 }` 296 expectedBody := map[string]string{ 297 "health_check_http_endpoint": "/anything", 298 "health_check_type": "some-health-check-type", 299 "state": "STARTED", 300 "docker_image": "some-docker-path", 301 } 302 303 server.AppendHandlers( 304 CombineHandlers( 305 VerifyRequest(http.MethodPut, "/v2/apps/some-app-guid"), 306 VerifyJSONRepresenting(expectedBody), 307 RespondWith(http.StatusCreated, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 308 ), 309 ) 310 }) 311 312 It("returns the updated object and warnings and sends all updated field", func() { 313 app, warnings, err := client.UpdateApplication(Application{ 314 DockerImage: "some-docker-path", 315 GUID: "some-app-guid", 316 HealthCheckType: "some-health-check-type", 317 HealthCheckHTTPEndpoint: "/anything", 318 State: ApplicationStarted, 319 }) 320 Expect(err).NotTo(HaveOccurred()) 321 322 updatedAt, err := time.Parse(time.RFC3339, "2015-03-10T23:11:54Z") 323 Expect(err).NotTo(HaveOccurred()) 324 325 Expect(app).To(Equal(Application{ 326 Buildpack: "ruby 1.6.29", 327 DetectedBuildpack: "", 328 DetectedStartCommand: "echo 'I am a banana'", 329 DiskQuota: 586, 330 DockerImage: "some-docker-path", 331 GUID: "some-app-guid", 332 HealthCheckType: "some-health-check-type", 333 HealthCheckHTTPEndpoint: "/anything", 334 Instances: 13, 335 Memory: 1024, 336 Name: "app-name-1", 337 PackageUpdatedAt: updatedAt, 338 StackGUID: "some-stack-guid", 339 State: ApplicationStarted, 340 })) 341 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 342 }) 343 }) 344 345 Context("when only updating one field", func() { // are we **only** encoding the things we want 346 BeforeEach(func() { 347 response1 := `{ 348 "metadata": { 349 "guid": "some-app-guid", 350 "updated_at": null 351 }, 352 "entity": { 353 "buildpack": "ruby 1.6.29", 354 "detected_start_command": "echo 'I am a banana'", 355 "disk_quota": 586, 356 "detected_buildpack": null, 357 "health_check_type": "some-health-check-type", 358 "health_check_http_endpoint": "/", 359 "instances": 13, 360 "memory": 1024, 361 "name": "app-name-1", 362 "package_updated_at": "2015-03-10T23:11:54Z", 363 "stack_guid": "some-stack-guid", 364 "state": "STOPPED" 365 } 366 }` 367 server.AppendHandlers( 368 CombineHandlers( 369 VerifyRequest(http.MethodPut, "/v2/apps/some-app-guid"), 370 VerifyBody([]byte(`{"health_check_type":"some-health-check-type"}`)), 371 RespondWith(http.StatusCreated, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 372 ), 373 ) 374 }) 375 376 It("returns the updated object and warnings and sends only updated field", func() { 377 app, warnings, err := client.UpdateApplication(Application{ 378 GUID: "some-app-guid", 379 HealthCheckType: "some-health-check-type", 380 }) 381 Expect(err).NotTo(HaveOccurred()) 382 383 updatedAt, err := time.Parse(time.RFC3339, "2015-03-10T23:11:54Z") 384 Expect(err).NotTo(HaveOccurred()) 385 386 Expect(app).To(Equal(Application{ 387 Buildpack: "ruby 1.6.29", 388 DetectedBuildpack: "", 389 DetectedStartCommand: "echo 'I am a banana'", 390 DiskQuota: 586, 391 GUID: "some-app-guid", 392 HealthCheckType: "some-health-check-type", 393 HealthCheckHTTPEndpoint: "/", 394 Instances: 13, 395 Memory: 1024, 396 Name: "app-name-1", 397 PackageUpdatedAt: updatedAt, 398 StackGUID: "some-stack-guid", 399 State: ApplicationStopped, 400 })) 401 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 402 }) 403 }) 404 }) 405 406 Context("when the update returns an error", func() { 407 BeforeEach(func() { 408 response := ` 409 { 410 "code": 210002, 411 "description": "The app could not be found: some-app-guid", 412 "error_code": "CF-AppNotFound" 413 } 414 ` 415 server.AppendHandlers( 416 CombineHandlers( 417 VerifyRequest(http.MethodPut, "/v2/apps/some-app-guid"), 418 // VerifyBody([]byte(`{"health_check_type":"some-health-check-type"}`)), 419 RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 420 ), 421 ) 422 }) 423 424 It("returns the error and warnings", func() { 425 _, warnings, err := client.UpdateApplication(Application{ 426 GUID: "some-app-guid", 427 HealthCheckType: "some-health-check-type", 428 }) 429 Expect(err).To(MatchError(ccerror.ResourceNotFoundError{Message: "The app could not be found: some-app-guid"})) 430 Expect(warnings).To(ConsistOf(Warnings{"this is a warning"})) 431 }) 432 }) 433 }) 434 435 Describe("GetRouteApplications", func() { 436 Context("when the route guid is not found", func() { 437 BeforeEach(func() { 438 response := ` 439 { 440 "code": 210002, 441 "description": "The route could not be found: some-route-guid", 442 "error_code": "CF-RouteNotFound" 443 } 444 ` 445 server.AppendHandlers( 446 CombineHandlers( 447 VerifyRequest(http.MethodGet, "/v2/routes/some-route-guid/apps"), 448 RespondWith(http.StatusNotFound, response), 449 ), 450 ) 451 }) 452 453 It("returns an error", func() { 454 _, _, err := client.GetRouteApplications("some-route-guid", nil) 455 Expect(err).To(MatchError(ccerror.ResourceNotFoundError{ 456 Message: "The route could not be found: some-route-guid", 457 })) 458 }) 459 }) 460 461 Context("when there are applications associated with this route", func() { 462 BeforeEach(func() { 463 response1 := `{ 464 "next_url": "/v2/routes/some-route-guid/apps?q=space_guid:some-space-guid&page=2", 465 "resources": [ 466 { 467 "metadata": { 468 "guid": "app-guid-1", 469 "updated_at": null 470 }, 471 "entity": { 472 "name": "app-name-1" 473 } 474 }, 475 { 476 "metadata": { 477 "guid": "app-guid-2", 478 "updated_at": null 479 }, 480 "entity": { 481 "name": "app-name-2" 482 } 483 } 484 ] 485 }` 486 response2 := `{ 487 "next_url": null, 488 "resources": [ 489 { 490 "metadata": { 491 "guid": "app-guid-3", 492 "updated_at": null 493 }, 494 "entity": { 495 "name": "app-name-3" 496 } 497 }, 498 { 499 "metadata": { 500 "guid": "app-guid-4", 501 "updated_at": null 502 }, 503 "entity": { 504 "name": "app-name-4" 505 } 506 } 507 ] 508 }` 509 server.AppendHandlers( 510 CombineHandlers( 511 VerifyRequest(http.MethodGet, "/v2/routes/some-route-guid/apps", "q=space_guid:some-space-guid"), 512 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 513 ), 514 ) 515 server.AppendHandlers( 516 CombineHandlers( 517 VerifyRequest(http.MethodGet, "/v2/routes/some-route-guid/apps", "q=space_guid:some-space-guid&page=2"), 518 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}), 519 ), 520 ) 521 }) 522 523 It("returns all the applications and all warnings", func() { 524 apps, warnings, err := client.GetRouteApplications("some-route-guid", []Query{{ 525 Filter: SpaceGUIDFilter, 526 Operator: EqualOperator, 527 Value: "some-space-guid", 528 }}) 529 Expect(err).NotTo(HaveOccurred()) 530 Expect(apps).To(ConsistOf([]Application{ 531 {Name: "app-name-1", GUID: "app-guid-1"}, 532 {Name: "app-name-2", GUID: "app-guid-2"}, 533 {Name: "app-name-3", GUID: "app-guid-3"}, 534 {Name: "app-name-4", GUID: "app-guid-4"}, 535 })) 536 Expect(warnings).To(ConsistOf(Warnings{"this is a warning", "this is another warning"})) 537 }) 538 }) 539 540 Context("when there are no applications associated with this route", func() { 541 BeforeEach(func() { 542 response := `{ 543 "next_url": "", 544 "resources": [] 545 }` 546 server.AppendHandlers( 547 CombineHandlers( 548 VerifyRequest(http.MethodGet, "/v2/routes/some-route-guid/apps"), 549 RespondWith(http.StatusOK, response), 550 ), 551 ) 552 }) 553 554 It("returns an empty list of applications", func() { 555 apps, _, err := client.GetRouteApplications("some-route-guid", nil) 556 Expect(err).NotTo(HaveOccurred()) 557 Expect(apps).To(BeEmpty()) 558 }) 559 }) 560 }) 561 })