github.com/cloudfoundry-community/cloudfoundry-cli@v6.44.1-0.20240130060226-cda5ed8e89a5+incompatible/actor/v7action/application_test.go (about) 1 package v7action_test 2 3 import ( 4 "code.cloudfoundry.org/cli/resources" 5 "errors" 6 "fmt" 7 "strings" 8 "time" 9 10 "code.cloudfoundry.org/cli/actor/actionerror" 11 . "code.cloudfoundry.org/cli/actor/v7action" 12 "code.cloudfoundry.org/cli/actor/v7action/v7actionfakes" 13 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 14 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 15 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 16 "code.cloudfoundry.org/cli/types" 17 18 . "github.com/onsi/ginkgo" 19 . "github.com/onsi/gomega" 20 ) 21 22 var _ = Describe("Application Actions", func() { 23 var ( 24 actor *Actor 25 fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient 26 fakeConfig *v7actionfakes.FakeConfig 27 ) 28 29 BeforeEach(func() { 30 fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient) 31 fakeConfig = new(v7actionfakes.FakeConfig) 32 actor = NewActor(fakeCloudControllerClient, fakeConfig, nil, nil) 33 }) 34 35 Describe("DeleteApplicationByNameAndSpace", func() { 36 var ( 37 warnings Warnings 38 executeErr error 39 ) 40 41 JustBeforeEach(func() { 42 warnings, executeErr = actor.DeleteApplicationByNameAndSpace("some-app", "some-space-guid") 43 }) 44 45 When("looking up the app guid fails", func() { 46 BeforeEach(func() { 47 fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{}, ccv3.Warnings{"some-get-app-warning"}, errors.New("some-get-app-error")) 48 }) 49 50 It("returns the warnings and error", func() { 51 Expect(warnings).To(ConsistOf("some-get-app-warning")) 52 Expect(executeErr).To(MatchError("some-get-app-error")) 53 }) 54 }) 55 56 When("looking up the app guid succeeds", func() { 57 BeforeEach(func() { 58 fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{{Name: "some-app", GUID: "abc123"}}, ccv3.Warnings{"some-get-app-warning"}, nil) 59 }) 60 61 When("sending the delete fails", func() { 62 BeforeEach(func() { 63 fakeCloudControllerClient.DeleteApplicationReturns("", ccv3.Warnings{"some-delete-app-warning"}, errors.New("some-delete-app-error")) 64 }) 65 66 It("returns the warnings and error", func() { 67 Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning")) 68 Expect(executeErr).To(MatchError("some-delete-app-error")) 69 }) 70 }) 71 72 When("sending the delete succeeds", func() { 73 BeforeEach(func() { 74 fakeCloudControllerClient.DeleteApplicationReturns("/some-job-url", ccv3.Warnings{"some-delete-app-warning"}, nil) 75 }) 76 77 When("polling fails", func() { 78 BeforeEach(func() { 79 fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"some-poll-warning"}, errors.New("some-poll-error")) 80 }) 81 82 It("returns the warnings and poll error", func() { 83 Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning", "some-poll-warning")) 84 Expect(executeErr).To(MatchError("some-poll-error")) 85 }) 86 }) 87 88 When("polling succeeds", func() { 89 BeforeEach(func() { 90 fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"some-poll-warning"}, nil) 91 }) 92 93 It("returns all the warnings and no error", func() { 94 Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning", "some-poll-warning")) 95 Expect(executeErr).ToNot(HaveOccurred()) 96 }) 97 }) 98 }) 99 }) 100 }) 101 102 Describe("GetApplicationsByNameAndSpace", func() { 103 When("all of the requested apps exist", func() { 104 BeforeEach(func() { 105 fakeCloudControllerClient.GetApplicationsReturns( 106 []resources.Application{ 107 { 108 Name: "some-app-name", 109 GUID: "some-app-guid", 110 }, 111 { 112 Name: "other-app-name", 113 GUID: "other-app-guid", 114 }, 115 }, 116 ccv3.Warnings{"some-warning"}, 117 nil, 118 ) 119 }) 120 121 It("returns the applications and warnings", func() { 122 apps, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name", "other-app-name"}, "some-space-guid") 123 Expect(err).ToNot(HaveOccurred()) 124 Expect(apps).To(ConsistOf( 125 Application{ 126 Name: "some-app-name", 127 GUID: "some-app-guid", 128 }, 129 Application{ 130 Name: "other-app-name", 131 GUID: "other-app-guid", 132 }, 133 )) 134 Expect(warnings).To(ConsistOf("some-warning")) 135 136 Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1)) 137 Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf( 138 ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name", "other-app-name"}}, 139 ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}}, 140 )) 141 }) 142 }) 143 144 When("at least one of the requested apps does not exist", func() { 145 BeforeEach(func() { 146 fakeCloudControllerClient.GetApplicationsReturns( 147 []resources.Application{ 148 { 149 Name: "some-app-name", 150 }, 151 }, 152 ccv3.Warnings{"some-warning"}, 153 nil, 154 ) 155 }) 156 157 It("returns an ApplicationNotFoundError and the warnings", func() { 158 _, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name", "other-app-name"}, "some-space-guid") 159 Expect(warnings).To(ConsistOf("some-warning")) 160 Expect(err).To(MatchError(actionerror.ApplicationsNotFoundError{})) 161 }) 162 }) 163 164 When("the cloud controller client returns an error", func() { 165 var expectedError error 166 167 BeforeEach(func() { 168 expectedError = errors.New("I am a CloudControllerClient Error") 169 fakeCloudControllerClient.GetApplicationsReturns( 170 []resources.Application{}, 171 ccv3.Warnings{"some-warning"}, 172 expectedError) 173 }) 174 175 It("returns the warnings and the error", func() { 176 _, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name"}, "some-space-guid") 177 Expect(warnings).To(ConsistOf("some-warning")) 178 Expect(err).To(MatchError(expectedError)) 179 }) 180 }) 181 }) 182 183 Describe("GetApplicationByNameAndSpace", func() { 184 When("the app exists", func() { 185 BeforeEach(func() { 186 fakeCloudControllerClient.GetApplicationsReturns( 187 []resources.Application{ 188 { 189 Name: "some-app-name", 190 GUID: "some-app-guid", 191 Metadata: &resources.Metadata{ 192 Labels: map[string]types.NullString{ 193 "some-key": types.NewNullString("some-value"), 194 }, 195 }, 196 }, 197 }, 198 ccv3.Warnings{"some-warning"}, 199 nil, 200 ) 201 }) 202 203 It("returns the application and warnings", func() { 204 app, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid") 205 Expect(err).ToNot(HaveOccurred()) 206 Expect(app).To(Equal(Application{ 207 Name: "some-app-name", 208 GUID: "some-app-guid", 209 Metadata: &Metadata{ 210 Labels: map[string]types.NullString{"some-key": types.NewNullString("some-value")}, 211 }, 212 })) 213 Expect(warnings).To(ConsistOf("some-warning")) 214 215 Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1)) 216 Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf( 217 ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}}, 218 ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}}, 219 )) 220 }) 221 }) 222 223 When("the cloud controller client returns an error", func() { 224 var expectedError error 225 226 BeforeEach(func() { 227 expectedError = errors.New("I am a CloudControllerClient Error") 228 fakeCloudControllerClient.GetApplicationsReturns( 229 []resources.Application{}, 230 ccv3.Warnings{"some-warning"}, 231 expectedError) 232 }) 233 234 It("returns the warnings and the error", func() { 235 _, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid") 236 Expect(warnings).To(ConsistOf("some-warning")) 237 Expect(err).To(MatchError(expectedError)) 238 }) 239 }) 240 241 When("the app does not exist", func() { 242 BeforeEach(func() { 243 fakeCloudControllerClient.GetApplicationsReturns( 244 []resources.Application{}, 245 ccv3.Warnings{"some-warning"}, 246 nil, 247 ) 248 }) 249 250 It("returns an ApplicationNotFoundError and the warnings", func() { 251 _, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid") 252 Expect(warnings).To(ConsistOf("some-warning")) 253 Expect(err).To(MatchError(actionerror.ApplicationNotFoundError{Name: "some-app-name"})) 254 }) 255 }) 256 }) 257 258 Describe("GetApplicationsBySpace", func() { 259 When("the there are applications in the space", func() { 260 BeforeEach(func() { 261 fakeCloudControllerClient.GetApplicationsReturns( 262 []resources.Application{ 263 { 264 GUID: "some-app-guid-1", 265 Name: "some-app-1", 266 }, 267 { 268 GUID: "some-app-guid-2", 269 Name: "some-app-2", 270 }, 271 }, 272 ccv3.Warnings{"warning-1", "warning-2"}, 273 nil, 274 ) 275 }) 276 277 It("returns the application and warnings", func() { 278 apps, warnings, err := actor.GetApplicationsBySpace("some-space-guid") 279 Expect(err).ToNot(HaveOccurred()) 280 Expect(apps).To(ConsistOf( 281 Application{ 282 GUID: "some-app-guid-1", 283 Name: "some-app-1", 284 }, 285 Application{ 286 GUID: "some-app-guid-2", 287 Name: "some-app-2", 288 }, 289 )) 290 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 291 292 Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1)) 293 Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf( 294 ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}}, 295 )) 296 }) 297 }) 298 299 When("the cloud controller client returns an error", func() { 300 var expectedError error 301 302 BeforeEach(func() { 303 expectedError = errors.New("I am a CloudControllerClient Error") 304 fakeCloudControllerClient.GetApplicationsReturns( 305 []resources.Application{}, 306 ccv3.Warnings{"some-warning"}, 307 expectedError) 308 }) 309 310 It("returns the error and warnings", func() { 311 _, warnings, err := actor.GetApplicationsBySpace("some-space-guid") 312 Expect(warnings).To(ConsistOf("some-warning")) 313 Expect(err).To(MatchError(expectedError)) 314 }) 315 }) 316 }) 317 318 Describe("CreateApplicationInSpace", func() { 319 var ( 320 application Application 321 warnings Warnings 322 err error 323 ) 324 325 JustBeforeEach(func() { 326 application, warnings, err = actor.CreateApplicationInSpace(Application{ 327 Name: "some-app-name", 328 LifecycleType: constant.AppLifecycleTypeBuildpack, 329 LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"}, 330 }, "some-space-guid") 331 }) 332 333 When("the app successfully gets created", func() { 334 BeforeEach(func() { 335 fakeCloudControllerClient.CreateApplicationReturns( 336 resources.Application{ 337 Name: "some-app-name", 338 GUID: "some-app-guid", 339 LifecycleType: constant.AppLifecycleTypeBuildpack, 340 LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"}, 341 }, 342 ccv3.Warnings{"some-warning"}, 343 nil, 344 ) 345 }) 346 347 It("creates and returns the application and warnings", func() { 348 Expect(err).ToNot(HaveOccurred()) 349 Expect(application).To(Equal(Application{ 350 Name: "some-app-name", 351 GUID: "some-app-guid", 352 LifecycleType: constant.AppLifecycleTypeBuildpack, 353 LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"}, 354 })) 355 Expect(warnings).To(ConsistOf("some-warning")) 356 357 Expect(fakeCloudControllerClient.CreateApplicationCallCount()).To(Equal(1)) 358 Expect(fakeCloudControllerClient.CreateApplicationArgsForCall(0)).To(Equal(resources.Application{ 359 Name: "some-app-name", 360 SpaceGUID: "some-space-guid", 361 LifecycleType: constant.AppLifecycleTypeBuildpack, 362 LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"}, 363 })) 364 }) 365 }) 366 367 When("the cc client returns an error", func() { 368 var expectedError error 369 370 BeforeEach(func() { 371 expectedError = errors.New("I am a CloudControllerClient Error") 372 fakeCloudControllerClient.CreateApplicationReturns( 373 resources.Application{}, 374 ccv3.Warnings{"some-warning"}, 375 expectedError, 376 ) 377 }) 378 379 It("raises the error and warnings", func() { 380 Expect(err).To(MatchError(expectedError)) 381 Expect(warnings).To(ConsistOf("some-warning")) 382 }) 383 }) 384 385 When("the cc client returns an NameNotUniqueInSpaceError", func() { 386 BeforeEach(func() { 387 fakeCloudControllerClient.CreateApplicationReturns( 388 resources.Application{}, 389 ccv3.Warnings{"some-warning"}, 390 ccerror.NameNotUniqueInSpaceError{}, 391 ) 392 }) 393 394 It("returns the ApplicationAlreadyExistsError and warnings", func() { 395 Expect(err).To(MatchError(actionerror.ApplicationAlreadyExistsError{Name: "some-app-name"})) 396 Expect(warnings).To(ConsistOf("some-warning")) 397 }) 398 }) 399 }) 400 401 Describe("UpdateApplication", func() { 402 var ( 403 submitApp, resultApp Application 404 warnings Warnings 405 err error 406 ) 407 408 JustBeforeEach(func() { 409 submitApp = Application{ 410 GUID: "some-app-guid", 411 StackName: "some-stack-name", 412 LifecycleType: constant.AppLifecycleTypeBuildpack, 413 LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"}, 414 Metadata: &Metadata{Labels: map[string]types.NullString{ 415 "some-label": types.NewNullString("some-value"), 416 "other-label": types.NewNullString("other-value"), 417 }}, 418 } 419 420 resultApp, warnings, err = actor.UpdateApplication(submitApp) 421 }) 422 423 When("the app successfully gets updated", func() { 424 var apiResponseApp resources.Application 425 426 BeforeEach(func() { 427 apiResponseApp = resources.Application{ 428 GUID: "response-app-guid", 429 StackName: "response-stack-name", 430 LifecycleType: constant.AppLifecycleTypeBuildpack, 431 LifecycleBuildpacks: []string{"response-buildpack-1", "response-buildpack-2"}, 432 } 433 fakeCloudControllerClient.UpdateApplicationReturns( 434 apiResponseApp, 435 ccv3.Warnings{"some-warning"}, 436 nil, 437 ) 438 }) 439 440 It("creates and returns the application and warnings", func() { 441 Expect(err).ToNot(HaveOccurred()) 442 Expect(resultApp).To(Equal(Application{ 443 GUID: apiResponseApp.GUID, 444 StackName: apiResponseApp.StackName, 445 LifecycleType: apiResponseApp.LifecycleType, 446 LifecycleBuildpacks: apiResponseApp.LifecycleBuildpacks, 447 })) 448 Expect(warnings).To(ConsistOf("some-warning")) 449 450 Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1)) 451 Expect(fakeCloudControllerClient.UpdateApplicationArgsForCall(0)).To(Equal(resources.Application{ 452 GUID: submitApp.GUID, 453 StackName: submitApp.StackName, 454 LifecycleType: submitApp.LifecycleType, 455 LifecycleBuildpacks: submitApp.LifecycleBuildpacks, 456 Metadata: (*resources.Metadata)(submitApp.Metadata), 457 })) 458 }) 459 }) 460 461 When("the cc client returns an error", func() { 462 var expectedError error 463 464 BeforeEach(func() { 465 expectedError = errors.New("I am a CloudControllerClient Error") 466 fakeCloudControllerClient.UpdateApplicationReturns( 467 resources.Application{}, 468 ccv3.Warnings{"some-warning"}, 469 expectedError, 470 ) 471 }) 472 473 It("raises the error and warnings", func() { 474 Expect(err).To(MatchError(expectedError)) 475 Expect(warnings).To(ConsistOf("some-warning")) 476 }) 477 }) 478 }) 479 480 Describe("PollStart", func() { 481 var ( 482 appGUID string 483 484 warnings Warnings 485 executeErr error 486 ) 487 488 BeforeEach(func() { 489 appGUID = "some-guid" 490 }) 491 492 JustBeforeEach(func() { 493 warnings, executeErr = actor.PollStart(appGUID) 494 }) 495 496 When("getting the application processes fails", func() { 497 BeforeEach(func() { 498 fakeCloudControllerClient.GetApplicationProcessesReturns(nil, ccv3.Warnings{"get-app-warning-1", "get-app-warning-2"}, errors.New("some-error")) 499 }) 500 501 It("returns the error and all warnings", func() { 502 Expect(executeErr).To(MatchError(errors.New("some-error"))) 503 Expect(warnings).To(ConsistOf("get-app-warning-1", "get-app-warning-2")) 504 }) 505 }) 506 507 When("getting the application processes succeeds", func() { 508 var processes []resources.Process 509 510 BeforeEach(func() { 511 fakeConfig.StartupTimeoutReturns(time.Second) 512 fakeConfig.PollingIntervalReturns(0) 513 }) 514 515 When("there is a single process", func() { 516 BeforeEach(func() { 517 processes = []resources.Process{{GUID: "abc123"}} 518 fakeCloudControllerClient.GetApplicationProcessesReturns( 519 processes, 520 ccv3.Warnings{"get-app-warning-1"}, nil) 521 }) 522 523 When("the polling times out", func() { 524 BeforeEach(func() { 525 fakeConfig.StartupTimeoutReturns(time.Millisecond) 526 fakeConfig.PollingIntervalReturns(time.Millisecond * 2) 527 fakeCloudControllerClient.GetProcessInstancesReturns( 528 []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}}, 529 ccv3.Warnings{"get-process-warning-1", "get-process-warning-2"}, 530 nil, 531 ) 532 }) 533 534 It("returns the timeout error", func() { 535 Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{})) 536 Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2")) 537 }) 538 539 It("gets polling and timeout values from the config", func() { 540 Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1)) 541 Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1)) 542 }) 543 }) 544 545 When("getting the process instances errors", func() { 546 BeforeEach(func() { 547 fakeCloudControllerClient.GetProcessInstancesReturns( 548 nil, 549 ccv3.Warnings{"get-process-warning-1", "get-process-warning-2"}, 550 errors.New("some-error"), 551 ) 552 }) 553 554 It("returns the error", func() { 555 Expect(executeErr).To(MatchError("some-error")) 556 Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2")) 557 }) 558 }) 559 560 When("getting the process instances succeeds", func() { 561 var ( 562 initialInstanceStates []ccv3.ProcessInstance 563 eventualInstanceStates []ccv3.ProcessInstance 564 processInstanceCallCount int 565 ) 566 567 BeforeEach(func() { 568 processInstanceCallCount = 0 569 570 fakeCloudControllerClient.GetProcessInstancesStub = func(processGuid string) ([]ccv3.ProcessInstance, ccv3.Warnings, error) { 571 defer func() { processInstanceCallCount++ }() 572 if processInstanceCallCount == 0 { 573 return initialInstanceStates, 574 ccv3.Warnings{"get-process-warning-1", "get-process-warning-2"}, 575 nil 576 } else { 577 return eventualInstanceStates, 578 ccv3.Warnings{fmt.Sprintf("get-process-warning-%d", processInstanceCallCount+2)}, 579 nil 580 } 581 } 582 }) 583 584 When("there are no process instances", func() { 585 BeforeEach(func() { 586 initialInstanceStates = []ccv3.ProcessInstance{} 587 eventualInstanceStates = []ccv3.ProcessInstance{} 588 }) 589 590 It("should not return an error", func() { 591 Expect(executeErr).NotTo(HaveOccurred()) 592 }) 593 594 It("should only call GetProcessInstances once before exiting", func() { 595 Expect(processInstanceCallCount).To(Equal(1)) 596 }) 597 598 It("should return correct warnings", func() { 599 Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2")) 600 }) 601 }) 602 603 When("all instances become running by the second call", func() { 604 BeforeEach(func() { 605 initialInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}} 606 eventualInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceRunning}, {State: constant.ProcessInstanceRunning}} 607 }) 608 609 It("should not return an error", func() { 610 Expect(executeErr).NotTo(HaveOccurred()) 611 }) 612 613 It("should call GetProcessInstances twice", func() { 614 Expect(processInstanceCallCount).To(Equal(2)) 615 }) 616 617 It("should return correct warnings", func() { 618 Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2", "get-process-warning-3")) 619 }) 620 }) 621 622 When("at least one instance has become running by the second call", func() { 623 BeforeEach(func() { 624 initialInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}} 625 eventualInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceRunning}} 626 }) 627 628 It("should not return an error", func() { 629 Expect(executeErr).NotTo(HaveOccurred()) 630 }) 631 632 It("should call GetProcessInstances twice", func() { 633 Expect(processInstanceCallCount).To(Equal(2)) 634 }) 635 636 It("should return correct warnings", func() { 637 Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2", "get-process-warning-3")) 638 }) 639 }) 640 641 When("all of the instances have crashed by the second call", func() { 642 BeforeEach(func() { 643 initialInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}} 644 eventualInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceCrashed}, {State: constant.ProcessInstanceCrashed}, {State: constant.ProcessInstanceCrashed}} 645 }) 646 647 It("should not return an error", func() { 648 Expect(executeErr).To(MatchError(actionerror.AllInstancesCrashedError{})) 649 }) 650 651 It("should call GetProcessInstances twice", func() { 652 Expect(processInstanceCallCount).To(Equal(2)) 653 }) 654 655 It("should return correct warnings", func() { 656 Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2", "get-process-warning-3")) 657 }) 658 }) 659 }) 660 }) 661 662 Context("where there are multiple processes", func() { 663 var ( 664 processInstanceCallCount int 665 ) 666 667 BeforeEach(func() { 668 processInstanceCallCount = 0 669 fakeConfig.StartupTimeoutReturns(time.Millisecond) 670 fakeConfig.PollingIntervalReturns(time.Millisecond * 2) 671 672 fakeCloudControllerClient.GetProcessInstancesStub = func(processGuid string) ([]ccv3.ProcessInstance, ccv3.Warnings, error) { 673 defer func() { processInstanceCallCount++ }() 674 if strings.HasPrefix(processGuid, "good") { 675 return []ccv3.ProcessInstance{{State: constant.ProcessInstanceRunning}}, nil, nil 676 } else { 677 return []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}}, nil, nil 678 } 679 } 680 }) 681 682 When("none of the processes are ready", func() { 683 BeforeEach(func() { 684 processes = []resources.Process{{GUID: "bad-1"}, {GUID: "bad-2"}} 685 fakeCloudControllerClient.GetApplicationProcessesReturns( 686 processes, 687 ccv3.Warnings{"get-app-warning-1"}, nil) 688 }) 689 690 It("returns the timeout error", func() { 691 Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{})) 692 }) 693 }) 694 695 When("some of the processes are ready", func() { 696 BeforeEach(func() { 697 processes = []resources.Process{{GUID: "bad-1"}, {GUID: "good-1"}} 698 fakeCloudControllerClient.GetApplicationProcessesReturns( 699 processes, 700 ccv3.Warnings{"get-app-warning-1"}, nil) 701 }) 702 703 It("returns the timeout error", func() { 704 Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{})) 705 }) 706 }) 707 708 When("all of the processes are ready", func() { 709 BeforeEach(func() { 710 processes = []resources.Process{{GUID: "good-1"}, {GUID: "good-2"}} 711 fakeCloudControllerClient.GetApplicationProcessesReturns( 712 processes, 713 ccv3.Warnings{"get-app-warning-1"}, nil) 714 }) 715 716 It("returns nil", func() { 717 Expect(executeErr).ToNot(HaveOccurred()) 718 }) 719 }) 720 }) 721 }) 722 }) 723 724 Describe("SetApplicationProcessHealthCheckTypeByNameAndSpace", func() { 725 var ( 726 healthCheckType constant.HealthCheckType 727 healthCheckEndpoint string 728 729 warnings Warnings 730 err error 731 app Application 732 ) 733 734 BeforeEach(func() { 735 healthCheckType = constant.HTTP 736 healthCheckEndpoint = "some-http-endpoint" 737 }) 738 739 JustBeforeEach(func() { 740 app, warnings, err = actor.SetApplicationProcessHealthCheckTypeByNameAndSpace( 741 "some-app-name", 742 "some-space-guid", 743 healthCheckType, 744 healthCheckEndpoint, 745 "some-process-type", 746 42, 747 ) 748 }) 749 750 When("getting application returns an error", func() { 751 var expectedErr error 752 753 BeforeEach(func() { 754 expectedErr = errors.New("some-error") 755 fakeCloudControllerClient.GetApplicationsReturns( 756 []resources.Application{}, 757 ccv3.Warnings{"some-warning"}, 758 expectedErr, 759 ) 760 }) 761 762 It("returns the error and warnings", func() { 763 Expect(err).To(Equal(expectedErr)) 764 Expect(warnings).To(ConsistOf("some-warning")) 765 }) 766 }) 767 768 When("application exists", func() { 769 var ccv3App resources.Application 770 771 BeforeEach(func() { 772 ccv3App = resources.Application{ 773 GUID: "some-app-guid", 774 } 775 776 fakeCloudControllerClient.GetApplicationsReturns( 777 []resources.Application{ccv3App}, 778 ccv3.Warnings{"some-warning"}, 779 nil, 780 ) 781 }) 782 783 When("setting the health check returns an error", func() { 784 var expectedErr error 785 786 BeforeEach(func() { 787 expectedErr = errors.New("some-error") 788 fakeCloudControllerClient.GetApplicationProcessByTypeReturns( 789 resources.Process{}, 790 ccv3.Warnings{"some-process-warning"}, 791 expectedErr, 792 ) 793 }) 794 795 It("returns the error and warnings", func() { 796 Expect(err).To(Equal(expectedErr)) 797 Expect(warnings).To(ConsistOf("some-warning", "some-process-warning")) 798 }) 799 }) 800 801 When("application process exists", func() { 802 BeforeEach(func() { 803 fakeCloudControllerClient.GetApplicationProcessByTypeReturns( 804 resources.Process{ 805 GUID: "some-process-guid", 806 }, 807 ccv3.Warnings{"some-process-warning"}, 808 nil, 809 ) 810 811 fakeCloudControllerClient.UpdateProcessReturns( 812 resources.Process{GUID: "some-process-guid"}, 813 ccv3.Warnings{"some-health-check-warning"}, 814 nil, 815 ) 816 }) 817 818 It("returns the application", func() { 819 Expect(err).NotTo(HaveOccurred()) 820 Expect(warnings).To(ConsistOf("some-warning", "some-process-warning", "some-health-check-warning")) 821 822 Expect(app).To(Equal(Application{ 823 GUID: ccv3App.GUID, 824 })) 825 826 Expect(fakeCloudControllerClient.GetApplicationProcessByTypeCallCount()).To(Equal(1)) 827 appGUID, processType := fakeCloudControllerClient.GetApplicationProcessByTypeArgsForCall(0) 828 Expect(appGUID).To(Equal("some-app-guid")) 829 Expect(processType).To(Equal("some-process-type")) 830 831 Expect(fakeCloudControllerClient.UpdateProcessCallCount()).To(Equal(1)) 832 process := fakeCloudControllerClient.UpdateProcessArgsForCall(0) 833 Expect(process.GUID).To(Equal("some-process-guid")) 834 Expect(process.HealthCheckType).To(Equal(constant.HTTP)) 835 Expect(process.HealthCheckEndpoint).To(Equal("some-http-endpoint")) 836 Expect(process.HealthCheckInvocationTimeout).To(BeEquivalentTo(42)) 837 }) 838 }) 839 }) 840 }) 841 842 Describe("StopApplication", func() { 843 var ( 844 warnings Warnings 845 executeErr error 846 ) 847 848 JustBeforeEach(func() { 849 warnings, executeErr = actor.StopApplication("some-app-guid") 850 }) 851 852 When("there are no client errors", func() { 853 BeforeEach(func() { 854 fakeCloudControllerClient.UpdateApplicationStopReturns( 855 resources.Application{GUID: "some-app-guid"}, 856 ccv3.Warnings{"stop-application-warning"}, 857 nil, 858 ) 859 }) 860 861 It("stops the application", func() { 862 Expect(executeErr).ToNot(HaveOccurred()) 863 Expect(warnings).To(ConsistOf("stop-application-warning")) 864 865 Expect(fakeCloudControllerClient.UpdateApplicationStopCallCount()).To(Equal(1)) 866 Expect(fakeCloudControllerClient.UpdateApplicationStopArgsForCall(0)).To(Equal("some-app-guid")) 867 }) 868 }) 869 870 When("stopping the application fails", func() { 871 var expectedErr error 872 BeforeEach(func() { 873 expectedErr = errors.New("some set stop-application error") 874 fakeCloudControllerClient.UpdateApplicationStopReturns( 875 resources.Application{}, 876 ccv3.Warnings{"stop-application-warning"}, 877 expectedErr, 878 ) 879 }) 880 881 It("returns the error", func() { 882 Expect(executeErr).To(Equal(expectedErr)) 883 Expect(warnings).To(ConsistOf("stop-application-warning")) 884 }) 885 }) 886 }) 887 888 Describe("StartApplication", func() { 889 When("there are no client errors", func() { 890 BeforeEach(func() { 891 fakeCloudControllerClient.UpdateApplicationStartReturns( 892 resources.Application{GUID: "some-app-guid"}, 893 ccv3.Warnings{"start-application-warning"}, 894 nil, 895 ) 896 }) 897 898 It("starts the application", func() { 899 app, warnings, err := actor.StartApplication("some-app-guid") 900 901 Expect(err).ToNot(HaveOccurred()) 902 Expect(warnings).To(ConsistOf("start-application-warning")) 903 Expect(app).To(Equal(Application{GUID: "some-app-guid"})) 904 905 Expect(fakeCloudControllerClient.UpdateApplicationStartCallCount()).To(Equal(1)) 906 Expect(fakeCloudControllerClient.UpdateApplicationStartArgsForCall(0)).To(Equal("some-app-guid")) 907 }) 908 }) 909 910 When("starting the application fails", func() { 911 var expectedErr error 912 BeforeEach(func() { 913 expectedErr = errors.New("some set start-application error") 914 fakeCloudControllerClient.UpdateApplicationStartReturns( 915 resources.Application{}, 916 ccv3.Warnings{"start-application-warning"}, 917 expectedErr, 918 ) 919 }) 920 921 It("returns the error", func() { 922 _, warnings, err := actor.StartApplication("some-app-guid") 923 924 Expect(err).To(Equal(expectedErr)) 925 Expect(warnings).To(ConsistOf("start-application-warning")) 926 }) 927 }) 928 }) 929 930 Describe("RestartApplication", func() { 931 var ( 932 warnings Warnings 933 executeErr error 934 ) 935 936 BeforeEach(func() { 937 fakeConfig.StartupTimeoutReturns(time.Second) 938 fakeConfig.PollingIntervalReturns(0) 939 }) 940 941 JustBeforeEach(func() { 942 warnings, executeErr = actor.RestartApplication("some-app-guid") 943 }) 944 945 When("restarting the application is successful", func() { 946 BeforeEach(func() { 947 fakeCloudControllerClient.UpdateApplicationRestartReturns( 948 resources.Application{GUID: "some-app-guid"}, 949 ccv3.Warnings{"restart-application-warning"}, 950 nil, 951 ) 952 }) 953 954 When("polling the application start is successful", func() { 955 BeforeEach(func() { 956 processes := []resources.Process{{GUID: "some-process-guid"}} 957 fakeCloudControllerClient.GetApplicationProcessesReturns(processes, ccv3.Warnings{"get-process-warnings"}, nil) 958 fakeCloudControllerClient.GetProcessInstancesReturns(nil, ccv3.Warnings{"some-process-instance-warnings"}, nil) 959 }) 960 961 It("returns all the warnings", func() { 962 Expect(executeErr).ToNot(HaveOccurred()) 963 Expect(warnings).To(ConsistOf("restart-application-warning", "get-process-warnings", "some-process-instance-warnings")) 964 }) 965 966 It("calls restart", func() { 967 Expect(fakeCloudControllerClient.UpdateApplicationRestartCallCount()).To(Equal(1)) 968 Expect(fakeCloudControllerClient.UpdateApplicationRestartArgsForCall(0)).To(Equal("some-app-guid")) 969 }) 970 971 It("polls for the application's process to start", func() { 972 Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1)) 973 Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal("some-app-guid")) 974 975 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(1)) 976 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("some-process-guid")) 977 }) 978 }) 979 980 When("polling the application start errors", func() { 981 var expectedErr error 982 BeforeEach(func() { 983 expectedErr = errors.New("some polling error") 984 fakeCloudControllerClient.GetApplicationProcessesReturns(nil, ccv3.Warnings{"get-process-warnings"}, expectedErr) 985 }) 986 987 It("returns the warnings and error", func() { 988 Expect(executeErr).To(Equal(expectedErr)) 989 Expect(warnings).To(ConsistOf("restart-application-warning", "get-process-warnings")) 990 }) 991 }) 992 }) 993 994 When("restarting the application fails", func() { 995 var expectedErr error 996 BeforeEach(func() { 997 expectedErr = errors.New("some set restart-application error") 998 fakeCloudControllerClient.UpdateApplicationRestartReturns( 999 resources.Application{}, 1000 ccv3.Warnings{"restart-application-warning"}, 1001 expectedErr, 1002 ) 1003 }) 1004 1005 It("returns the warnings and error", func() { 1006 Expect(executeErr).To(Equal(expectedErr)) 1007 Expect(warnings).To(ConsistOf("restart-application-warning")) 1008 }) 1009 }) 1010 }) 1011 })