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