github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/actor/v7action/application_test.go (about) 1 package v7action_test 2 3 import ( 4 "errors" 5 "fmt" 6 "time" 7 8 "code.cloudfoundry.org/cli/actor/actionerror" 9 . "code.cloudfoundry.org/cli/actor/v7action" 10 "code.cloudfoundry.org/cli/actor/v7action/v7actionfakes" 11 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 12 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 13 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 14 "code.cloudfoundry.org/cli/resources" 15 "code.cloudfoundry.org/cli/types" 16 "code.cloudfoundry.org/cli/util/batcher" 17 "code.cloudfoundry.org/clock/fakeclock" 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 fakeClock *fakeclock.FakeClock 28 ) 29 30 BeforeEach(func() { 31 fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient) 32 fakeConfig = new(v7actionfakes.FakeConfig) 33 fakeClock = fakeclock.NewFakeClock(time.Now()) 34 actor = NewActor(fakeCloudControllerClient, fakeConfig, nil, nil, nil, fakeClock) 35 }) 36 37 Describe("DeleteApplicationByNameAndSpace", func() { 38 var ( 39 warnings Warnings 40 executeErr error 41 deleteMappedRoutes bool 42 appName string 43 ) 44 45 JustBeforeEach(func() { 46 appName = "some-app" 47 warnings, executeErr = actor.DeleteApplicationByNameAndSpace(appName, "some-space-guid", deleteMappedRoutes) 48 }) 49 50 When("looking up the app guid fails", func() { 51 BeforeEach(func() { 52 fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{}, ccv3.Warnings{"some-get-app-warning"}, errors.New("some-get-app-error")) 53 }) 54 55 It("returns the warnings and error", func() { 56 Expect(warnings).To(ConsistOf("some-get-app-warning")) 57 Expect(executeErr).To(MatchError("some-get-app-error")) 58 }) 59 }) 60 61 When("looking up the app guid succeeds without routes", func() { 62 BeforeEach(func() { 63 fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{{Name: "some-app", GUID: "abc123"}}, ccv3.Warnings{"some-get-app-warning"}, nil) 64 deleteMappedRoutes = false 65 }) 66 67 When("sending the delete fails", func() { 68 BeforeEach(func() { 69 fakeCloudControllerClient.DeleteApplicationReturns("", ccv3.Warnings{"some-delete-app-warning"}, errors.New("some-delete-app-error")) 70 }) 71 72 It("returns the warnings and error", func() { 73 Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning")) 74 Expect(executeErr).To(MatchError("some-delete-app-error")) 75 }) 76 }) 77 78 When("sending the delete succeeds", func() { 79 BeforeEach(func() { 80 fakeCloudControllerClient.DeleteApplicationReturns("/some-job-url", ccv3.Warnings{"some-delete-app-warning"}, nil) 81 }) 82 83 When("polling fails", func() { 84 BeforeEach(func() { 85 fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"some-poll-warning"}, errors.New("some-poll-error")) 86 }) 87 88 It("returns the warnings and poll error", func() { 89 Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning", "some-poll-warning")) 90 Expect(executeErr).To(MatchError("some-poll-error")) 91 }) 92 }) 93 94 When("polling succeeds", func() { 95 BeforeEach(func() { 96 fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"some-poll-warning"}, nil) 97 }) 98 99 It("returns all the warnings and no error", func() { 100 Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning", "some-poll-warning")) 101 Expect(executeErr).ToNot(HaveOccurred()) 102 }) 103 }) 104 }) 105 }) 106 107 When("looking up the app guid succeeds with routes", func() { 108 BeforeEach(func() { 109 deleteMappedRoutes = true 110 fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{{Name: "some-app", GUID: "abc123"}}, nil, nil) 111 }) 112 113 When("getting the routes fails", func() { 114 BeforeEach(func() { 115 fakeCloudControllerClient.GetApplicationRoutesReturns(nil, ccv3.Warnings{"get-routes-warning"}, errors.New("get-routes-error")) 116 }) 117 118 It("returns the warnings and an error", func() { 119 Expect(warnings).To(ConsistOf("get-routes-warning")) 120 Expect(executeErr).To(MatchError("get-routes-error")) 121 }) 122 }) 123 124 When("getting the routes succeeds", func() { 125 When("there are no routes", func() { 126 BeforeEach(func() { 127 fakeCloudControllerClient.GetApplicationRoutesReturns([]resources.Route{}, nil, nil) 128 }) 129 130 It("does not delete any routes", func() { 131 Expect(fakeCloudControllerClient.DeleteRouteCallCount()).To(Equal(0)) 132 }) 133 }) 134 135 When("there are routes", func() { 136 BeforeEach(func() { 137 fakeCloudControllerClient.GetApplicationRoutesReturns([]resources.Route{{GUID: "route-1-guid"}, {GUID: "route-2-guid", URL: "route-2.example.com"}}, nil, nil) 138 }) 139 140 It("deletes the routes", func() { 141 Expect(fakeCloudControllerClient.GetApplicationRoutesCallCount()).To(Equal(1)) 142 Expect(fakeCloudControllerClient.GetApplicationRoutesArgsForCall(0)).To(Equal("abc123")) 143 Expect(fakeCloudControllerClient.DeleteRouteCallCount()).To(Equal(2)) 144 guids := []string{fakeCloudControllerClient.DeleteRouteArgsForCall(0), fakeCloudControllerClient.DeleteRouteArgsForCall(1)} 145 Expect(guids).To(ConsistOf("route-1-guid", "route-2-guid")) 146 }) 147 148 When("the route has already been deleted", func() { 149 BeforeEach(func() { 150 fakeCloudControllerClient.DeleteRouteReturnsOnCall(0, 151 "", 152 ccv3.Warnings{"delete-route-1-warning"}, 153 ccerror.ResourceNotFoundError{}, 154 ) 155 fakeCloudControllerClient.DeleteRouteReturnsOnCall(1, 156 "poll-job-url", 157 ccv3.Warnings{"delete-route-2-warning"}, 158 nil, 159 ) 160 fakeCloudControllerClient.PollJobReturnsOnCall(1, ccv3.Warnings{"poll-job-warning"}, nil) 161 }) 162 163 It("does **not** fail", func() { 164 Expect(executeErr).ToNot(HaveOccurred()) 165 Expect(warnings).To(ConsistOf("delete-route-1-warning", "delete-route-2-warning", "poll-job-warning")) 166 Expect(fakeCloudControllerClient.DeleteRouteCallCount()).To(Equal(2)) 167 Expect(fakeCloudControllerClient.PollJobCallCount()).To(Equal(2)) 168 Expect(fakeCloudControllerClient.PollJobArgsForCall(1)).To(BeEquivalentTo("poll-job-url")) 169 }) 170 }) 171 172 When("app to delete has a route bound to another app", func() { 173 BeforeEach(func() { 174 fakeCloudControllerClient.GetApplicationRoutesReturns( 175 []resources.Route{ 176 {GUID: "route-1-guid"}, 177 {GUID: "route-2-guid", 178 URL: "route-2.example.com", 179 Destinations: []resources.RouteDestination{ 180 {App: resources.RouteDestinationApp{GUID: "abc123"}}, 181 {App: resources.RouteDestinationApp{GUID: "different-app-guid"}}, 182 }, 183 }, 184 }, 185 nil, 186 nil, 187 ) 188 }) 189 190 It("refuses the entire operation", func() { 191 Expect(executeErr).To(MatchError(actionerror.RouteBoundToMultipleAppsError{AppName: "some-app", RouteURL: "route-2.example.com"})) 192 Expect(warnings).To(BeEmpty()) 193 Expect(fakeCloudControllerClient.DeleteApplicationCallCount()).To(Equal(0)) 194 Expect(fakeCloudControllerClient.DeleteRouteCallCount()).To(Equal(0)) 195 }) 196 }) 197 198 When("deleting the route fails", func() { 199 BeforeEach(func() { 200 fakeCloudControllerClient.DeleteRouteReturnsOnCall(0, 201 "poll-job-url", 202 ccv3.Warnings{"delete-route-1-warning"}, 203 nil, 204 ) 205 fakeCloudControllerClient.DeleteRouteReturnsOnCall(1, 206 "", 207 ccv3.Warnings{"delete-route-2-warning"}, 208 errors.New("delete-route-2-error"), 209 ) 210 }) 211 212 It("returns the error", func() { 213 Expect(executeErr).To(MatchError("delete-route-2-error")) 214 Expect(warnings).To(ConsistOf("delete-route-1-warning", "delete-route-2-warning")) 215 }) 216 }) 217 218 When("the polling job fails", func() { 219 BeforeEach(func() { 220 fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"poll-job-warning"}, errors.New("poll-job-error")) 221 }) 222 223 It("returns the error", func() { 224 Expect(executeErr).To(MatchError("poll-job-error")) 225 }) 226 }) 227 228 }) 229 }) 230 }) 231 }) 232 233 Describe("GetApplicationsByGUIDs", func() { 234 When("all of the requested apps exist", func() { 235 BeforeEach(func() { 236 fakeCloudControllerClient.GetApplicationsReturns( 237 []resources.Application{ 238 { 239 Name: "some-app-name", 240 GUID: "some-app-guid", 241 }, 242 { 243 Name: "other-app-name", 244 GUID: "other-app-guid", 245 }, 246 }, 247 ccv3.Warnings{"some-warning"}, 248 nil, 249 ) 250 }) 251 252 It("returns the applications and warnings", func() { 253 apps, warnings, err := actor.GetApplicationsByGUIDs([]string{"some-app-guid", "other-app-guid"}) 254 Expect(err).ToNot(HaveOccurred()) 255 Expect(apps).To(ConsistOf( 256 resources.Application{ 257 Name: "some-app-name", 258 GUID: "some-app-guid", 259 }, 260 resources.Application{ 261 Name: "other-app-name", 262 GUID: "other-app-guid", 263 }, 264 )) 265 Expect(warnings).To(ConsistOf("some-warning")) 266 267 Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1)) 268 Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf( 269 ccv3.Query{Key: ccv3.GUIDFilter, Values: []string{"some-app-guid", "other-app-guid"}}, 270 )) 271 }) 272 }) 273 274 When("at least one of the requested apps does not exist", func() { 275 BeforeEach(func() { 276 fakeCloudControllerClient.GetApplicationsReturns( 277 []resources.Application{ 278 { 279 Name: "some-app-name", 280 GUID: "some-app-guid", 281 }, 282 }, 283 ccv3.Warnings{"some-warning"}, 284 nil, 285 ) 286 }) 287 288 It("returns an ApplicationNotFoundError and the warnings", func() { 289 _, warnings, err := actor.GetApplicationsByGUIDs([]string{"some-app-guid", "nonexistent-app-guid"}) 290 Expect(warnings).To(ConsistOf("some-warning")) 291 Expect(err).To(MatchError(actionerror.ApplicationsNotFoundError{})) 292 }) 293 }) 294 295 When("a single app has two routes", func() { 296 BeforeEach(func() { 297 fakeCloudControllerClient.GetApplicationsReturns( 298 []resources.Application{ 299 { 300 Name: "some-app-name", 301 GUID: "some-app-guid", 302 }, 303 }, 304 ccv3.Warnings{"some-warning"}, 305 nil, 306 ) 307 }) 308 309 It("returns an ApplicationNotFoundError and the warnings", func() { 310 _, warnings, err := actor.GetApplicationsByGUIDs([]string{"some-app-guid", "some-app-guid"}) 311 Expect(err).ToNot(HaveOccurred()) 312 Expect(warnings).To(ConsistOf("some-warning")) 313 }) 314 }) 315 316 When("the cloud controller client returns an error", func() { 317 var expectedError error 318 319 BeforeEach(func() { 320 expectedError = errors.New("I am a CloudControllerClient Error") 321 fakeCloudControllerClient.GetApplicationsReturns( 322 []resources.Application{}, 323 ccv3.Warnings{"some-warning"}, 324 expectedError) 325 }) 326 327 It("returns the warnings and the error", func() { 328 _, warnings, err := actor.GetApplicationsByGUIDs([]string{"some-app-guid"}) 329 Expect(warnings).To(ConsistOf("some-warning")) 330 Expect(err).To(MatchError(expectedError)) 331 }) 332 }) 333 334 When("there are many guids", func() { 335 const batches = 10 336 var guids []string 337 338 BeforeEach(func() { 339 var apps []resources.Application 340 341 for i := 0; i < batcher.BatchSize*batches; i++ { 342 guids = append(guids, fmt.Sprintf("app-%d-guid", i)) 343 apps = append(apps, resources.Application{ 344 Name: fmt.Sprintf("app-%d-name", i), 345 GUID: fmt.Sprintf("app-%d-guid", i), 346 }) 347 } 348 349 for b := 0; b < batches; b++ { 350 fakeCloudControllerClient.GetApplicationsReturnsOnCall( 351 b, 352 apps[:batcher.BatchSize], 353 ccv3.Warnings{"some-warning"}, 354 nil, 355 ) 356 apps = apps[batcher.BatchSize:] 357 } 358 }) 359 360 It("makes many calls", func() { 361 apps, warnings, err := actor.GetApplicationsByGUIDs(guids) 362 Expect(len(apps)).To(Equal(batches * batcher.BatchSize)) 363 Expect(apps).To(HaveLen(batcher.BatchSize * 10)) 364 Expect(warnings).To(HaveLen(10)) 365 Expect(err).NotTo(HaveOccurred()) 366 367 Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(10)) 368 Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)). 369 NotTo(Equal(fakeCloudControllerClient.GetApplicationsArgsForCall(1))) 370 }) 371 }) 372 }) 373 374 Describe("GetApplicationsByNameAndSpace", func() { 375 When("all of the requested apps exist", func() { 376 BeforeEach(func() { 377 fakeCloudControllerClient.GetApplicationsReturns( 378 []resources.Application{ 379 { 380 Name: "some-app-name", 381 GUID: "some-app-guid", 382 }, 383 { 384 Name: "other-app-name", 385 GUID: "other-app-guid", 386 }, 387 }, 388 ccv3.Warnings{"some-warning"}, 389 nil, 390 ) 391 }) 392 393 It("returns the applications and warnings", func() { 394 apps, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name", "other-app-name"}, "some-space-guid") 395 Expect(err).ToNot(HaveOccurred()) 396 Expect(apps).To(ConsistOf( 397 resources.Application{ 398 Name: "some-app-name", 399 GUID: "some-app-guid", 400 }, 401 resources.Application{ 402 Name: "other-app-name", 403 GUID: "other-app-guid", 404 }, 405 )) 406 Expect(warnings).To(ConsistOf("some-warning")) 407 408 Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1)) 409 Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf( 410 ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name", "other-app-name"}}, 411 ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}}, 412 )) 413 }) 414 }) 415 416 When("at least one of the requested apps does not exist", func() { 417 BeforeEach(func() { 418 fakeCloudControllerClient.GetApplicationsReturns( 419 []resources.Application{ 420 { 421 Name: "some-app-name", 422 }, 423 }, 424 ccv3.Warnings{"some-warning"}, 425 nil, 426 ) 427 }) 428 429 It("returns an ApplicationNotFoundError and the warnings", func() { 430 _, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name", "other-app-name"}, "some-space-guid") 431 Expect(warnings).To(ConsistOf("some-warning")) 432 Expect(err).To(MatchError(actionerror.ApplicationsNotFoundError{})) 433 }) 434 }) 435 436 When("a given app has two routes", func() { 437 BeforeEach(func() { 438 fakeCloudControllerClient.GetApplicationsReturns( 439 []resources.Application{ 440 { 441 Name: "some-app-name", 442 }, 443 }, 444 ccv3.Warnings{"some-warning"}, 445 nil, 446 ) 447 }) 448 449 It("returns an ApplicationNotFoundError and the warnings", func() { 450 _, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name", "some-app-name"}, "some-space-guid") 451 Expect(err).ToNot(HaveOccurred()) 452 Expect(warnings).To(ConsistOf("some-warning")) 453 }) 454 }) 455 456 When("the cloud controller client returns an error", func() { 457 var expectedError error 458 459 BeforeEach(func() { 460 expectedError = errors.New("I am a CloudControllerClient Error") 461 fakeCloudControllerClient.GetApplicationsReturns( 462 []resources.Application{}, 463 ccv3.Warnings{"some-warning"}, 464 expectedError) 465 }) 466 467 It("returns the warnings and the error", func() { 468 _, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name"}, "some-space-guid") 469 Expect(warnings).To(ConsistOf("some-warning")) 470 Expect(err).To(MatchError(expectedError)) 471 }) 472 }) 473 }) 474 475 Describe("GetApplicationByNameAndSpace", func() { 476 When("the app exists", func() { 477 BeforeEach(func() { 478 fakeCloudControllerClient.GetApplicationsReturns( 479 []resources.Application{ 480 { 481 Name: "some-app-name", 482 GUID: "some-app-guid", 483 Metadata: &resources.Metadata{ 484 Labels: map[string]types.NullString{ 485 "some-key": types.NewNullString("some-value"), 486 }, 487 }, 488 }, 489 }, 490 ccv3.Warnings{"some-warning"}, 491 nil, 492 ) 493 }) 494 495 It("returns the application and warnings", func() { 496 app, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid") 497 Expect(err).ToNot(HaveOccurred()) 498 Expect(app).To(Equal(resources.Application{ 499 Name: "some-app-name", 500 GUID: "some-app-guid", 501 Metadata: &resources.Metadata{ 502 Labels: map[string]types.NullString{"some-key": types.NewNullString("some-value")}, 503 }, 504 })) 505 Expect(warnings).To(ConsistOf("some-warning")) 506 507 Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1)) 508 Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf( 509 ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}}, 510 ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}}, 511 )) 512 }) 513 }) 514 515 When("the cloud controller client returns an error", func() { 516 var expectedError error 517 518 BeforeEach(func() { 519 expectedError = errors.New("I am a CloudControllerClient Error") 520 fakeCloudControllerClient.GetApplicationsReturns( 521 []resources.Application{}, 522 ccv3.Warnings{"some-warning"}, 523 expectedError) 524 }) 525 526 It("returns the warnings and the error", func() { 527 _, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid") 528 Expect(warnings).To(ConsistOf("some-warning")) 529 Expect(err).To(MatchError(expectedError)) 530 }) 531 }) 532 533 When("the app does not exist", func() { 534 BeforeEach(func() { 535 fakeCloudControllerClient.GetApplicationsReturns( 536 []resources.Application{}, 537 ccv3.Warnings{"some-warning"}, 538 nil, 539 ) 540 }) 541 542 It("returns an ApplicationNotFoundError and the warnings", func() { 543 _, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid") 544 Expect(warnings).To(ConsistOf("some-warning")) 545 Expect(err).To(MatchError(actionerror.ApplicationNotFoundError{Name: "some-app-name"})) 546 }) 547 }) 548 }) 549 550 Describe("GetApplicationsBySpace", func() { 551 When("the there are applications in the space", func() { 552 BeforeEach(func() { 553 fakeCloudControllerClient.GetApplicationsReturns( 554 []resources.Application{ 555 { 556 GUID: "some-app-guid-1", 557 Name: "some-app-1", 558 }, 559 { 560 GUID: "some-app-guid-2", 561 Name: "some-app-2", 562 }, 563 }, 564 ccv3.Warnings{"warning-1", "warning-2"}, 565 nil, 566 ) 567 }) 568 569 It("returns the application and warnings", func() { 570 apps, warnings, err := actor.GetApplicationsBySpace("some-space-guid") 571 Expect(err).ToNot(HaveOccurred()) 572 Expect(apps).To(ConsistOf( 573 resources.Application{ 574 GUID: "some-app-guid-1", 575 Name: "some-app-1", 576 }, 577 resources.Application{ 578 GUID: "some-app-guid-2", 579 Name: "some-app-2", 580 }, 581 )) 582 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 583 584 Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1)) 585 Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf( 586 ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}}, 587 )) 588 }) 589 }) 590 591 When("the cloud controller client returns an error", func() { 592 var expectedError error 593 594 BeforeEach(func() { 595 expectedError = errors.New("I am a CloudControllerClient Error") 596 fakeCloudControllerClient.GetApplicationsReturns( 597 []resources.Application{}, 598 ccv3.Warnings{"some-warning"}, 599 expectedError) 600 }) 601 602 It("returns the error and warnings", func() { 603 _, warnings, err := actor.GetApplicationsBySpace("some-space-guid") 604 Expect(warnings).To(ConsistOf("some-warning")) 605 Expect(err).To(MatchError(expectedError)) 606 }) 607 }) 608 }) 609 610 Describe("CreateApplicationInSpace", func() { 611 var ( 612 application resources.Application 613 warnings Warnings 614 err error 615 ) 616 617 JustBeforeEach(func() { 618 application, warnings, err = actor.CreateApplicationInSpace(resources.Application{ 619 Name: "some-app-name", 620 LifecycleType: constant.AppLifecycleTypeBuildpack, 621 LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"}, 622 }, "some-space-guid") 623 }) 624 625 When("the app successfully gets created", func() { 626 BeforeEach(func() { 627 fakeCloudControllerClient.CreateApplicationReturns( 628 resources.Application{ 629 Name: "some-app-name", 630 GUID: "some-app-guid", 631 LifecycleType: constant.AppLifecycleTypeBuildpack, 632 LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"}, 633 }, 634 ccv3.Warnings{"some-warning"}, 635 nil, 636 ) 637 }) 638 639 It("creates and returns the application and warnings", func() { 640 Expect(err).ToNot(HaveOccurred()) 641 Expect(application).To(Equal(resources.Application{ 642 Name: "some-app-name", 643 GUID: "some-app-guid", 644 LifecycleType: constant.AppLifecycleTypeBuildpack, 645 LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"}, 646 })) 647 Expect(warnings).To(ConsistOf("some-warning")) 648 649 Expect(fakeCloudControllerClient.CreateApplicationCallCount()).To(Equal(1)) 650 Expect(fakeCloudControllerClient.CreateApplicationArgsForCall(0)).To(Equal(resources.Application{ 651 Name: "some-app-name", 652 SpaceGUID: "some-space-guid", 653 LifecycleType: constant.AppLifecycleTypeBuildpack, 654 LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"}, 655 })) 656 }) 657 }) 658 659 When("the cc client returns an error", func() { 660 var expectedError error 661 662 BeforeEach(func() { 663 expectedError = errors.New("I am a CloudControllerClient Error") 664 fakeCloudControllerClient.CreateApplicationReturns( 665 resources.Application{}, 666 ccv3.Warnings{"some-warning"}, 667 expectedError, 668 ) 669 }) 670 671 It("raises the error and warnings", func() { 672 Expect(err).To(MatchError(expectedError)) 673 Expect(warnings).To(ConsistOf("some-warning")) 674 }) 675 }) 676 677 When("the cc client returns an NameNotUniqueInSpaceError", func() { 678 BeforeEach(func() { 679 fakeCloudControllerClient.CreateApplicationReturns( 680 resources.Application{}, 681 ccv3.Warnings{"some-warning"}, 682 ccerror.NameNotUniqueInSpaceError{}, 683 ) 684 }) 685 686 It("returns the NameNotUniqueInSpaceError and warnings", func() { 687 Expect(err).To(MatchError(ccerror.NameNotUniqueInSpaceError{})) 688 Expect(warnings).To(ConsistOf("some-warning")) 689 }) 690 }) 691 }) 692 693 Describe("UpdateApplication", func() { 694 var ( 695 submitApp, resultApp resources.Application 696 warnings Warnings 697 err error 698 ) 699 700 JustBeforeEach(func() { 701 submitApp = resources.Application{ 702 GUID: "some-app-guid", 703 StackName: "some-stack-name", 704 Name: "some-app-name", 705 LifecycleType: constant.AppLifecycleTypeBuildpack, 706 LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"}, 707 Metadata: &resources.Metadata{Labels: map[string]types.NullString{ 708 "some-label": types.NewNullString("some-value"), 709 "other-label": types.NewNullString("other-value"), 710 }}, 711 } 712 713 resultApp, warnings, err = actor.UpdateApplication(submitApp) 714 }) 715 716 When("the app successfully gets updated", func() { 717 var apiResponseApp resources.Application 718 719 BeforeEach(func() { 720 apiResponseApp = resources.Application{ 721 GUID: "response-app-guid", 722 StackName: "response-stack-name", 723 Name: "response-app-name", 724 LifecycleType: constant.AppLifecycleTypeBuildpack, 725 LifecycleBuildpacks: []string{"response-buildpack-1", "response-buildpack-2"}, 726 } 727 fakeCloudControllerClient.UpdateApplicationReturns( 728 apiResponseApp, 729 ccv3.Warnings{"some-warning"}, 730 nil, 731 ) 732 }) 733 734 It("creates and returns the application and warnings", func() { 735 Expect(err).ToNot(HaveOccurred()) 736 Expect(resultApp).To(Equal(resources.Application{ 737 Name: apiResponseApp.Name, 738 GUID: apiResponseApp.GUID, 739 StackName: apiResponseApp.StackName, 740 LifecycleType: apiResponseApp.LifecycleType, 741 LifecycleBuildpacks: apiResponseApp.LifecycleBuildpacks, 742 })) 743 Expect(warnings).To(ConsistOf("some-warning")) 744 745 Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1)) 746 Expect(fakeCloudControllerClient.UpdateApplicationArgsForCall(0)).To(Equal(resources.Application{ 747 GUID: submitApp.GUID, 748 StackName: submitApp.StackName, 749 LifecycleType: submitApp.LifecycleType, 750 LifecycleBuildpacks: submitApp.LifecycleBuildpacks, 751 Name: submitApp.Name, 752 Metadata: submitApp.Metadata, 753 })) 754 }) 755 }) 756 757 When("the cc client returns an error", func() { 758 var expectedError error 759 760 BeforeEach(func() { 761 expectedError = errors.New("I am a CloudControllerClient Error") 762 fakeCloudControllerClient.UpdateApplicationReturns( 763 resources.Application{}, 764 ccv3.Warnings{"some-warning"}, 765 expectedError, 766 ) 767 }) 768 769 It("raises the error and warnings", func() { 770 Expect(err).To(MatchError(expectedError)) 771 Expect(warnings).To(ConsistOf("some-warning")) 772 }) 773 }) 774 }) 775 776 Describe("UpdateApplicationName", func() { 777 var ( 778 resultApp resources.Application 779 newAppName, appGUID string 780 warnings Warnings 781 err error 782 ) 783 784 JustBeforeEach(func() { 785 newAppName = "some-new-app-name" 786 appGUID = "some-app-guid" 787 788 resultApp, warnings, err = actor.UpdateApplicationName(newAppName, appGUID) 789 }) 790 791 When("the app successfully gets updated", func() { 792 var apiResponseApp resources.Application 793 794 BeforeEach(func() { 795 apiResponseApp = resources.Application{ 796 GUID: "response-app-guid", 797 StackName: "response-stack-name", 798 Name: "response-app-name", 799 LifecycleType: constant.AppLifecycleTypeBuildpack, 800 LifecycleBuildpacks: []string{"response-buildpack-1", "response-buildpack-2"}, 801 } 802 fakeCloudControllerClient.UpdateApplicationNameReturns( 803 apiResponseApp, 804 ccv3.Warnings{"some-warning"}, 805 nil, 806 ) 807 }) 808 809 It("creates and returns the application and warnings", func() { 810 Expect(err).ToNot(HaveOccurred()) 811 Expect(resultApp).To(Equal(resources.Application{ 812 Name: apiResponseApp.Name, 813 GUID: apiResponseApp.GUID, 814 StackName: apiResponseApp.StackName, 815 LifecycleType: apiResponseApp.LifecycleType, 816 LifecycleBuildpacks: apiResponseApp.LifecycleBuildpacks, 817 })) 818 Expect(warnings).To(ConsistOf("some-warning")) 819 820 Expect(fakeCloudControllerClient.UpdateApplicationNameCallCount()).To(Equal(1)) 821 appName, appGuid := fakeCloudControllerClient.UpdateApplicationNameArgsForCall(0) 822 Expect(appName).To(Equal("some-new-app-name")) 823 Expect(appGuid).To(Equal("some-app-guid")) 824 }) 825 }) 826 827 When("the cc client returns an error", func() { 828 var expectedError error 829 830 BeforeEach(func() { 831 expectedError = errors.New("I am a CloudControllerClient Error") 832 fakeCloudControllerClient.UpdateApplicationNameReturns( 833 resources.Application{}, 834 ccv3.Warnings{"some-warning"}, 835 expectedError, 836 ) 837 }) 838 839 It("raises the error and warnings", func() { 840 Expect(err).To(MatchError(expectedError)) 841 Expect(warnings).To(ConsistOf("some-warning")) 842 }) 843 }) 844 }) 845 846 Describe("PollStart", func() { 847 var ( 848 app resources.Application 849 noWait bool 850 handleInstanceDetails func(string) 851 852 done chan bool 853 854 warnings Warnings 855 executeErr error 856 reportedInstanceDetails []string 857 ) 858 859 BeforeEach(func() { 860 done = make(chan bool) 861 fakeConfig.StartupTimeoutReturns(2 * time.Second) 862 fakeConfig.PollingIntervalReturns(1 * time.Second) 863 app = resources.Application{GUID: "some-guid"} 864 noWait = false 865 866 reportedInstanceDetails = []string{} 867 handleInstanceDetails = func(instanceDetails string) { 868 reportedInstanceDetails = append(reportedInstanceDetails, instanceDetails) 869 } 870 }) 871 872 JustBeforeEach(func() { 873 go func() { 874 defer close(done) 875 warnings, executeErr = actor.PollStart(app, noWait, handleInstanceDetails) 876 done <- true 877 }() 878 }) 879 880 It("gets the apps processes", func() { 881 // advanced clock so function exits 882 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 883 884 // wait for function to finish 885 Eventually(done).Should(Receive(BeTrue())) 886 887 Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1)) 888 Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal("some-guid")) 889 890 }) 891 892 When("getting the application processes fails", func() { 893 BeforeEach(func() { 894 fakeCloudControllerClient.GetApplicationProcessesReturns(nil, ccv3.Warnings{"get-app-warning-1", "get-app-warning-2"}, errors.New("some-error")) 895 }) 896 897 It("returns the error and all warnings", func() { 898 // wait for function to finish 899 Eventually(done).Should(Receive(BeTrue())) 900 901 Expect(executeErr).To(MatchError(errors.New("some-error"))) 902 Expect(warnings).To(ConsistOf("get-app-warning-1", "get-app-warning-2")) 903 }) 904 }) 905 906 When("getting the application process succeeds", func() { 907 BeforeEach(func() { 908 fakeCloudControllerClient.GetApplicationProcessesReturns( 909 []resources.Process{ 910 {GUID: "process1", Type: "web"}, 911 }, 912 ccv3.Warnings{"get-app-warning-1"}, 913 nil, 914 ) 915 916 }) 917 918 It("gets the startup timeout", func() { 919 // advanced clock so function exits 920 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 921 922 // wait for function to finish 923 Eventually(done).Should(Receive(BeTrue())) 924 925 Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1)) 926 }) 927 928 When("the no-wait flag is provided", func() { 929 BeforeEach(func() { 930 noWait = true 931 fakeCloudControllerClient.GetApplicationProcessesReturns( 932 []resources.Process{ 933 {GUID: "process1", Type: "web"}, 934 {GUID: "process2", Type: "worker"}, 935 }, 936 ccv3.Warnings{"get-app-warning-1"}, 937 nil, 938 ) 939 }) 940 941 It("filters out the non web processes", func() { 942 // send something on the timer channel 943 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 944 945 // Wait for function to finish 946 Eventually(done).Should(Receive(BeTrue())) 947 948 // assert on the cc call made within poll processes to make sure there is only the web process 949 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(1)) 950 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process1")) 951 952 }) 953 }) 954 955 When("polling processes returns an error", func() { 956 BeforeEach(func() { 957 fakeCloudControllerClient.GetProcessInstancesReturns(nil, ccv3.Warnings{"poll-process-warning"}, errors.New("poll-process-error")) 958 }) 959 960 It("returns the error and warnings", func() { 961 // send something on the timer channel 962 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 963 964 // Wait for function to finish 965 Eventually(done).Should(Receive(BeTrue())) 966 967 Expect(executeErr).Should(MatchError("poll-process-error")) 968 Expect(warnings).Should(ConsistOf("poll-process-warning", "get-app-warning-1")) 969 }) 970 }) 971 972 When("polling start times out", func() { 973 BeforeEach(func() { 974 fakeCloudControllerClient.GetProcessInstancesReturns( 975 []ccv3.ProcessInstance{ 976 {State: constant.ProcessInstanceStarting}, 977 }, 978 ccv3.Warnings{"poll-process-warning"}, 979 nil, 980 ) 981 982 fakeConfig.StartupTimeoutReturns(2 * time.Millisecond) 983 }) 984 985 It("returns a timeout error and any warnings", func() { 986 // send something on the timer channel for first tick 987 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 988 989 fakeClock.Increment(1 * time.Millisecond) 990 991 // Wait for function to finish 992 Eventually(done).Should(Receive(BeTrue())) 993 994 Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{})) 995 Expect(warnings).To(ConsistOf("poll-process-warning", "get-app-warning-1")) 996 }) 997 }) 998 999 When("polling process eventually returns we should stop polling", func() { 1000 BeforeEach(func() { 1001 fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(0, 1002 []ccv3.ProcessInstance{ 1003 {State: constant.ProcessInstanceStarting}, 1004 }, 1005 ccv3.Warnings{"poll-process-warning1"}, 1006 nil, 1007 ) 1008 1009 fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(1, 1010 []ccv3.ProcessInstance{ 1011 {State: constant.ProcessInstanceRunning}, 1012 }, 1013 ccv3.Warnings{"poll-process-warning2"}, 1014 nil, 1015 ) 1016 }) 1017 1018 It("returns success and any warnings", func() { 1019 // send something on the timer channel 1020 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1021 1022 Eventually(fakeConfig.PollingIntervalCallCount).Should(Equal(1)) 1023 1024 fakeClock.Increment(1 * time.Second) 1025 1026 // Wait for function to finish 1027 Eventually(done).Should(Receive(BeTrue())) 1028 Expect(executeErr).NotTo(HaveOccurred()) 1029 Expect(warnings).To(ConsistOf("poll-process-warning1", "get-app-warning-1", "poll-process-warning2")) 1030 }) 1031 1032 }) 1033 }) 1034 }) 1035 1036 Describe("PollStartForRolling", func() { 1037 var ( 1038 app resources.Application 1039 deploymentGUID string 1040 noWait bool 1041 handleInstanceDetails func(string) 1042 1043 done chan bool 1044 1045 warnings Warnings 1046 executeErr error 1047 reportedInstanceDetails []string 1048 ) 1049 1050 BeforeEach(func() { 1051 reportedInstanceDetails = []string{} 1052 handleInstanceDetails = func(instanceDetails string) { 1053 reportedInstanceDetails = append(reportedInstanceDetails, instanceDetails) 1054 } 1055 1056 app = resources.Application{GUID: "some-rolling-app-guid"} 1057 deploymentGUID = "some-deployment-guid" 1058 noWait = false 1059 1060 done = make(chan bool) 1061 1062 fakeConfig.StartupTimeoutReturns(5 * time.Second) 1063 fakeConfig.PollingIntervalReturns(1 * time.Second) 1064 }) 1065 1066 JustBeforeEach(func() { 1067 go func() { 1068 warnings, executeErr = actor.PollStartForRolling(app, deploymentGUID, noWait, handleInstanceDetails) 1069 done <- true 1070 }() 1071 }) 1072 1073 When("There is a non-timeout failure in the loop", func() { 1074 // this may need to be expanded to also include when the deployment is superseded or cancelled 1075 When("getting the deployment fails", func() { 1076 When("it is because the deployment was cancelled", func() { 1077 BeforeEach(func() { 1078 fakeCloudControllerClient.GetDeploymentReturns( 1079 resources.Deployment{ 1080 StatusValue: constant.DeploymentStatusValueFinalized, 1081 StatusReason: constant.DeploymentStatusReasonCanceled, 1082 }, 1083 ccv3.Warnings{"get-deployment-warning"}, 1084 nil, 1085 ) 1086 }) 1087 1088 It("returns warnings and the error", func() { 1089 // initial tick 1090 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1091 1092 // wait for func to finish 1093 Eventually(done).Should(Receive(BeTrue())) 1094 1095 Expect(executeErr).To(MatchError("Deployment has been canceled")) 1096 Expect(warnings).To(ConsistOf("get-deployment-warning")) 1097 1098 Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(1)) 1099 Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID)) 1100 1101 Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(0)) 1102 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(0)) 1103 1104 Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1)) 1105 }) 1106 1107 }) 1108 1109 When("it is because the deployment was superseded", func() { 1110 BeforeEach(func() { 1111 fakeCloudControllerClient.GetDeploymentReturns( 1112 resources.Deployment{ 1113 StatusValue: constant.DeploymentStatusValueFinalized, 1114 StatusReason: constant.DeploymentStatusReasonSuperseded, 1115 }, 1116 ccv3.Warnings{"get-deployment-warning"}, 1117 nil, 1118 ) 1119 }) 1120 1121 It("returns warnings and the error", func() { 1122 // initial tick 1123 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1124 1125 // wait for func to finish 1126 Eventually(done).Should(Receive(BeTrue())) 1127 1128 Expect(executeErr).To(MatchError("Deployment has been superseded")) 1129 Expect(warnings).To(ConsistOf("get-deployment-warning")) 1130 1131 Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(1)) 1132 Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID)) 1133 1134 Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(0)) 1135 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(0)) 1136 1137 Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1)) 1138 }) 1139 1140 }) 1141 1142 When("it is because of an API error", func() { 1143 BeforeEach(func() { 1144 fakeCloudControllerClient.GetDeploymentReturns( 1145 resources.Deployment{}, 1146 ccv3.Warnings{"get-deployment-warning"}, 1147 errors.New("get-deployment-error"), 1148 ) 1149 }) 1150 1151 It("returns warnings and the error", func() { 1152 // initial tick 1153 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1154 1155 // wait for func to finish 1156 Eventually(done).Should(Receive(BeTrue())) 1157 1158 Expect(executeErr).To(MatchError("get-deployment-error")) 1159 Expect(warnings).To(ConsistOf("get-deployment-warning")) 1160 1161 Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(1)) 1162 Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID)) 1163 1164 Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(0)) 1165 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(0)) 1166 1167 Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1)) 1168 }) 1169 1170 }) 1171 }) 1172 1173 When("getting the deployment succeeds", func() { 1174 BeforeEach(func() { 1175 // get processes requires the deployment to be deployed so we need this to indirectly test the error case 1176 fakeCloudControllerClient.GetDeploymentReturns( 1177 resources.Deployment{StatusValue: constant.DeploymentStatusValueFinalized, StatusReason: constant.DeploymentStatusReasonDeployed}, 1178 ccv3.Warnings{"get-deployment-warning"}, 1179 nil, 1180 ) 1181 1182 }) 1183 1184 When("getting the processes fails", func() { 1185 BeforeEach(func() { 1186 fakeCloudControllerClient.GetApplicationProcessesReturns( 1187 []resources.Process{}, 1188 ccv3.Warnings{"get-processes-warning"}, 1189 errors.New("get-processes-error"), 1190 ) 1191 }) 1192 1193 It("returns warnings and the error", func() { 1194 // initial tick 1195 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1196 1197 // wait for func to finish 1198 Eventually(done).Should(Receive(BeTrue())) 1199 1200 Expect(executeErr).To(MatchError("get-processes-error")) 1201 Expect(warnings).To(ConsistOf("get-deployment-warning", "get-processes-warning")) 1202 1203 Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(1)) 1204 Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID)) 1205 1206 Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1)) 1207 Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal(app.GUID)) 1208 1209 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(0)) 1210 1211 }) 1212 }) 1213 1214 When("getting the processes succeeds", func() { 1215 BeforeEach(func() { 1216 fakeCloudControllerClient.GetApplicationProcessesReturns( 1217 []resources.Process{{GUID: "process-guid"}}, 1218 ccv3.Warnings{"get-processes-warning"}, 1219 nil, 1220 ) 1221 }) 1222 1223 When("polling the processes fails", func() { 1224 BeforeEach(func() { 1225 fakeCloudControllerClient.GetProcessInstancesReturns( 1226 []ccv3.ProcessInstance{}, 1227 ccv3.Warnings{"poll-processes-warning"}, 1228 errors.New("poll-processes-error"), 1229 ) 1230 }) 1231 1232 It("returns all warnings and errors", func() { 1233 // initial tick 1234 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1235 1236 // wait for func to finish 1237 Eventually(done).Should(Receive(BeTrue())) 1238 1239 Expect(executeErr).To(MatchError("poll-processes-error")) 1240 Expect(warnings).To(ConsistOf("get-deployment-warning", "get-processes-warning", "poll-processes-warning")) 1241 1242 Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(1)) 1243 Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID)) 1244 1245 Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1)) 1246 Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal(app.GUID)) 1247 1248 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(1)) 1249 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process-guid")) 1250 }) 1251 1252 }) 1253 }) 1254 1255 }) 1256 1257 }) 1258 1259 // intentionally ignore the no-wait flag here for simplicity. One of these two things must cause timeout regardless of no-wait state 1260 When("there is a timeout error", func() { 1261 BeforeEach(func() { 1262 // 1 millisecond for initial tick then 1 to trigger timeout 1263 fakeConfig.StartupTimeoutReturns(2 * time.Millisecond) 1264 }) 1265 1266 When("the deployment never deploys", func() { 1267 BeforeEach(func() { 1268 fakeCloudControllerClient.GetDeploymentReturns( 1269 resources.Deployment{StatusValue: constant.DeploymentStatusValueActive}, 1270 ccv3.Warnings{"get-deployment-warning"}, 1271 nil, 1272 ) 1273 fakeCloudControllerClient.CancelDeploymentReturns( 1274 ccv3.Warnings{"cancel-deployment-warning"}, 1275 nil, 1276 ) 1277 }) 1278 1279 It("returns a timeout error and any warnings and cancels the deployment", func() { 1280 // initial tick 1281 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1282 1283 Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(1)) 1284 1285 // timeout tick 1286 fakeClock.Increment(1 * time.Millisecond) 1287 1288 Eventually(fakeCloudControllerClient.CancelDeploymentCallCount).Should(Equal(1)) 1289 1290 // wait for func to finish 1291 Eventually(done).Should(Receive(BeTrue())) 1292 1293 Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{})) 1294 Expect(warnings).To(ConsistOf("get-deployment-warning", "cancel-deployment-warning")) 1295 }) 1296 1297 When("the cancel deployment fails", func() { 1298 BeforeEach(func() { 1299 fakeCloudControllerClient.CancelDeploymentReturns( 1300 ccv3.Warnings{"cancel-deployment-warning"}, 1301 errors.New("cancel-deployment-error"), 1302 ) 1303 }) 1304 1305 It("returns a timeout error and any warnings and cancels the deployment", func() { 1306 // initial tick 1307 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1308 1309 Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(1)) 1310 1311 // timeout tick 1312 fakeClock.Increment(1 * time.Millisecond) 1313 1314 Eventually(fakeCloudControllerClient.CancelDeploymentCallCount).Should(Equal(1)) 1315 1316 // wait for func to finish 1317 Eventually(done).Should(Receive(BeTrue())) 1318 1319 Expect(executeErr).To(MatchError("cancel-deployment-error")) 1320 Expect(warnings).To(ConsistOf("get-deployment-warning", "cancel-deployment-warning")) 1321 }) 1322 1323 }) 1324 1325 }) 1326 1327 When("the processes dont become healthy", func() { 1328 BeforeEach(func() { 1329 fakeCloudControllerClient.GetDeploymentReturns( 1330 resources.Deployment{StatusValue: constant.DeploymentStatusValueFinalized, StatusReason: constant.DeploymentStatusReasonDeployed}, 1331 ccv3.Warnings{"get-deployment-warning"}, 1332 nil, 1333 ) 1334 1335 fakeCloudControllerClient.GetApplicationProcessesReturns( 1336 []resources.Process{{GUID: "process-guid"}}, 1337 ccv3.Warnings{"get-processes-warning"}, 1338 nil, 1339 ) 1340 1341 fakeCloudControllerClient.GetProcessInstancesReturns( 1342 []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}}, 1343 ccv3.Warnings{"poll-processes-warning"}, 1344 nil, 1345 ) 1346 }) 1347 1348 It("returns a timeout error and any warnings", func() { 1349 // initial tick 1350 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1351 1352 Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(1)) 1353 Eventually(fakeCloudControllerClient.GetApplicationProcessesCallCount).Should(Equal(1)) 1354 Eventually(fakeCloudControllerClient.GetProcessInstancesCallCount).Should(Equal(1)) 1355 1356 // timeout tick 1357 fakeClock.Increment(1 * time.Millisecond) 1358 1359 // wait for func to finish 1360 Eventually(done).Should(Receive(BeTrue())) 1361 1362 Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{})) 1363 Expect(warnings).To(ConsistOf("get-deployment-warning", "get-processes-warning", "poll-processes-warning")) 1364 }) 1365 1366 }) 1367 }) 1368 1369 When("things eventually become healthy", func() { 1370 When("the no wait flag is given", func() { 1371 BeforeEach(func() { 1372 // in total three loops 1: deployment still deploying 2: deployment deployed processes starting 3: processes started 1373 noWait = true 1374 1375 // Always return deploying as a way to check we respect no wait 1376 fakeCloudControllerClient.GetDeploymentReturns( 1377 resources.Deployment{ 1378 StatusValue: constant.DeploymentStatusValueActive, 1379 NewProcesses: []resources.Process{{GUID: "new-deployment-process"}}, 1380 }, 1381 ccv3.Warnings{"get-deployment-warning"}, 1382 nil, 1383 ) 1384 1385 // We only poll the processes. Two loops for fun 1386 fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(0, 1387 []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}}, 1388 ccv3.Warnings{"poll-processes-warning-1"}, 1389 nil, 1390 ) 1391 1392 fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(1, 1393 []ccv3.ProcessInstance{{State: constant.ProcessInstanceRunning}}, 1394 ccv3.Warnings{"poll-processes-warning-2"}, 1395 nil, 1396 ) 1397 }) 1398 1399 It("polls the start of the application correctly and returns warnings and no error", func() { 1400 // Initial tick 1401 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1402 1403 // assert one of our watcher is the timeout 1404 Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1)) 1405 1406 // the first time through we always get the deployment regardless of no-wait 1407 Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(1)) 1408 Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID)) 1409 Eventually(fakeCloudControllerClient.GetProcessInstancesCallCount).Should(Equal(1)) 1410 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("new-deployment-process")) 1411 Eventually(fakeConfig.PollingIntervalCallCount).Should(Equal(1)) 1412 1413 fakeClock.Increment(1 * time.Second) 1414 1415 Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(2)) 1416 Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID)) 1417 Eventually(fakeCloudControllerClient.GetProcessInstancesCallCount).Should(Equal(2)) 1418 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("new-deployment-process")) 1419 1420 Eventually(done).Should(Receive(BeTrue())) 1421 1422 Expect(executeErr).NotTo(HaveOccurred()) 1423 Expect(warnings).To(ConsistOf( 1424 "get-deployment-warning", 1425 "poll-processes-warning-1", 1426 "get-deployment-warning", 1427 "poll-processes-warning-2", 1428 )) 1429 1430 Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(2)) 1431 Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(0)) 1432 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(2)) 1433 Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1)) 1434 1435 }) 1436 1437 }) 1438 1439 When("the no wait flag is not given", func() { 1440 BeforeEach(func() { 1441 // in total three loops 1: deployment still deploying 2: deployment deployed processes starting 3: processes started 1442 fakeCloudControllerClient.GetDeploymentReturnsOnCall(0, 1443 resources.Deployment{StatusValue: constant.DeploymentStatusValueActive}, 1444 ccv3.Warnings{"get-deployment-warning-1"}, 1445 nil, 1446 ) 1447 1448 // Poll the deployment twice to make sure we are polling (one in the above before each) 1449 fakeCloudControllerClient.GetDeploymentReturnsOnCall(1, 1450 resources.Deployment{StatusValue: constant.DeploymentStatusValueFinalized, StatusReason: constant.DeploymentStatusReasonDeployed}, 1451 ccv3.Warnings{"get-deployment-warning-2"}, 1452 nil, 1453 ) 1454 1455 // then we get the processes. This should only be called once 1456 fakeCloudControllerClient.GetApplicationProcessesReturns( 1457 []resources.Process{{GUID: "process-guid"}}, 1458 ccv3.Warnings{"get-processes-warning"}, 1459 nil, 1460 ) 1461 1462 // then we poll the processes. Two loops for fun 1463 fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(0, 1464 []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}}, 1465 ccv3.Warnings{"poll-processes-warning-1"}, 1466 nil, 1467 ) 1468 1469 fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(1, 1470 []ccv3.ProcessInstance{{State: constant.ProcessInstanceRunning}}, 1471 ccv3.Warnings{"poll-processes-warning-2"}, 1472 nil, 1473 ) 1474 }) 1475 1476 It("polls the start of the application correctly and returns warnings and no error", func() { 1477 // Initial tick 1478 fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2) 1479 1480 // assert one of our watchers is for the timeout 1481 Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1)) 1482 1483 Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(1)) 1484 Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID)) 1485 Eventually(fakeConfig.PollingIntervalCallCount).Should(Equal(1)) 1486 1487 // start the second loop where the deployment is deployed so we poll processes 1488 fakeClock.Increment(1 * time.Second) 1489 1490 Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(2)) 1491 Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(1)).To(Equal(deploymentGUID)) 1492 Eventually(fakeCloudControllerClient.GetApplicationProcessesCallCount).Should(Equal(1)) 1493 Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal(app.GUID)) 1494 Eventually(fakeCloudControllerClient.GetProcessInstancesCallCount).Should(Equal(1)) 1495 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process-guid")) 1496 Eventually(fakeConfig.PollingIntervalCallCount).Should(Equal(2)) 1497 1498 fakeClock.Increment(1 * time.Second) 1499 1500 // we should stop polling because it is deployed 1501 Eventually(fakeCloudControllerClient.GetProcessInstancesCallCount).Should(Equal(2)) 1502 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process-guid")) 1503 1504 Eventually(done).Should(Receive(BeTrue())) 1505 1506 Expect(executeErr).NotTo(HaveOccurred()) 1507 Expect(warnings).To(ConsistOf( 1508 "get-deployment-warning-1", 1509 "get-deployment-warning-2", 1510 "get-processes-warning", 1511 "poll-processes-warning-1", 1512 "poll-processes-warning-2", 1513 )) 1514 1515 Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(2)) 1516 Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1)) 1517 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(2)) 1518 Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(2)) 1519 1520 }) 1521 1522 }) 1523 1524 }) 1525 }) 1526 1527 Describe("SetApplicationProcessHealthCheckTypeByNameAndSpace", func() { 1528 var ( 1529 healthCheckType constant.HealthCheckType 1530 healthCheckEndpoint string 1531 1532 warnings Warnings 1533 err error 1534 app resources.Application 1535 ) 1536 1537 BeforeEach(func() { 1538 healthCheckType = constant.HTTP 1539 healthCheckEndpoint = "some-http-endpoint" 1540 }) 1541 1542 JustBeforeEach(func() { 1543 app, warnings, err = actor.SetApplicationProcessHealthCheckTypeByNameAndSpace( 1544 "some-app-name", 1545 "some-space-guid", 1546 healthCheckType, 1547 healthCheckEndpoint, 1548 "some-process-type", 1549 42, 1550 ) 1551 }) 1552 1553 When("getting application returns an error", func() { 1554 var expectedErr error 1555 1556 BeforeEach(func() { 1557 expectedErr = errors.New("some-error") 1558 fakeCloudControllerClient.GetApplicationsReturns( 1559 []resources.Application{}, 1560 ccv3.Warnings{"some-warning"}, 1561 expectedErr, 1562 ) 1563 }) 1564 1565 It("returns the error and warnings", func() { 1566 Expect(err).To(Equal(expectedErr)) 1567 Expect(warnings).To(ConsistOf("some-warning")) 1568 }) 1569 }) 1570 1571 When("application exists", func() { 1572 var ccv3App resources.Application 1573 1574 BeforeEach(func() { 1575 ccv3App = resources.Application{ 1576 GUID: "some-app-guid", 1577 } 1578 1579 fakeCloudControllerClient.GetApplicationsReturns( 1580 []resources.Application{ccv3App}, 1581 ccv3.Warnings{"some-warning"}, 1582 nil, 1583 ) 1584 }) 1585 1586 When("setting the health check returns an error", func() { 1587 var expectedErr error 1588 1589 BeforeEach(func() { 1590 expectedErr = errors.New("some-error") 1591 fakeCloudControllerClient.GetApplicationProcessByTypeReturns( 1592 resources.Process{}, 1593 ccv3.Warnings{"some-process-warning"}, 1594 expectedErr, 1595 ) 1596 }) 1597 1598 It("returns the error and warnings", func() { 1599 Expect(err).To(Equal(expectedErr)) 1600 Expect(warnings).To(ConsistOf("some-warning", "some-process-warning")) 1601 }) 1602 }) 1603 1604 When("application process exists", func() { 1605 BeforeEach(func() { 1606 fakeCloudControllerClient.GetApplicationProcessByTypeReturns( 1607 resources.Process{GUID: "some-process-guid"}, 1608 ccv3.Warnings{"some-process-warning"}, 1609 nil, 1610 ) 1611 1612 fakeCloudControllerClient.UpdateProcessReturns( 1613 resources.Process{GUID: "some-process-guid"}, 1614 ccv3.Warnings{"some-health-check-warning"}, 1615 nil, 1616 ) 1617 }) 1618 1619 It("returns the application", func() { 1620 Expect(err).NotTo(HaveOccurred()) 1621 Expect(warnings).To(ConsistOf("some-warning", "some-process-warning", "some-health-check-warning")) 1622 1623 Expect(app).To(Equal(resources.Application{ 1624 GUID: ccv3App.GUID, 1625 })) 1626 1627 Expect(fakeCloudControllerClient.GetApplicationProcessByTypeCallCount()).To(Equal(1)) 1628 appGUID, processType := fakeCloudControllerClient.GetApplicationProcessByTypeArgsForCall(0) 1629 Expect(appGUID).To(Equal("some-app-guid")) 1630 Expect(processType).To(Equal("some-process-type")) 1631 1632 Expect(fakeCloudControllerClient.UpdateProcessCallCount()).To(Equal(1)) 1633 process := fakeCloudControllerClient.UpdateProcessArgsForCall(0) 1634 Expect(process.GUID).To(Equal("some-process-guid")) 1635 Expect(process.HealthCheckType).To(Equal(constant.HTTP)) 1636 Expect(process.HealthCheckEndpoint).To(Equal("some-http-endpoint")) 1637 Expect(process.HealthCheckInvocationTimeout).To(BeEquivalentTo(42)) 1638 }) 1639 }) 1640 }) 1641 }) 1642 1643 Describe("StopApplication", func() { 1644 var ( 1645 warnings Warnings 1646 executeErr error 1647 ) 1648 1649 JustBeforeEach(func() { 1650 warnings, executeErr = actor.StopApplication("some-app-guid") 1651 }) 1652 1653 When("there are no client errors", func() { 1654 BeforeEach(func() { 1655 fakeCloudControllerClient.UpdateApplicationStopReturns( 1656 resources.Application{GUID: "some-app-guid"}, 1657 ccv3.Warnings{"stop-application-warning"}, 1658 nil, 1659 ) 1660 }) 1661 1662 It("stops the application", func() { 1663 Expect(executeErr).ToNot(HaveOccurred()) 1664 Expect(warnings).To(ConsistOf("stop-application-warning")) 1665 1666 Expect(fakeCloudControllerClient.UpdateApplicationStopCallCount()).To(Equal(1)) 1667 Expect(fakeCloudControllerClient.UpdateApplicationStopArgsForCall(0)).To(Equal("some-app-guid")) 1668 }) 1669 }) 1670 1671 When("stopping the application fails", func() { 1672 var expectedErr error 1673 BeforeEach(func() { 1674 expectedErr = errors.New("some set stop-application error") 1675 fakeCloudControllerClient.UpdateApplicationStopReturns( 1676 resources.Application{}, 1677 ccv3.Warnings{"stop-application-warning"}, 1678 expectedErr, 1679 ) 1680 }) 1681 1682 It("returns the error", func() { 1683 Expect(executeErr).To(Equal(expectedErr)) 1684 Expect(warnings).To(ConsistOf("stop-application-warning")) 1685 }) 1686 }) 1687 }) 1688 1689 Describe("StartApplication", func() { 1690 var ( 1691 warnings Warnings 1692 executeErr error 1693 ) 1694 1695 BeforeEach(func() { 1696 fakeConfig.StartupTimeoutReturns(time.Second) 1697 fakeConfig.PollingIntervalReturns(0) 1698 }) 1699 1700 JustBeforeEach(func() { 1701 warnings, executeErr = actor.StartApplication("some-app-guid") 1702 }) 1703 1704 When("there are no client errors", func() { 1705 BeforeEach(func() { 1706 fakeCloudControllerClient.UpdateApplicationStartReturns( 1707 resources.Application{GUID: "some-app-guid"}, 1708 ccv3.Warnings{"start-application-warning"}, 1709 nil, 1710 ) 1711 }) 1712 1713 It("starts the application", func() { 1714 Expect(executeErr).ToNot(HaveOccurred()) 1715 Expect(warnings).To(ConsistOf("start-application-warning")) 1716 1717 Expect(fakeCloudControllerClient.UpdateApplicationStartCallCount()).To(Equal(1)) 1718 Expect(fakeCloudControllerClient.UpdateApplicationStartArgsForCall(0)).To(Equal("some-app-guid")) 1719 }) 1720 }) 1721 1722 When("starting the application fails", func() { 1723 var expectedErr error 1724 1725 BeforeEach(func() { 1726 expectedErr = errors.New("some set start-application error") 1727 fakeCloudControllerClient.UpdateApplicationStartReturns( 1728 resources.Application{}, 1729 ccv3.Warnings{"start-application-warning"}, 1730 expectedErr, 1731 ) 1732 }) 1733 1734 It("returns the error", func() { 1735 warnings, err := actor.StartApplication("some-app-guid") 1736 1737 Expect(err).To(Equal(expectedErr)) 1738 Expect(warnings).To(ConsistOf("start-application-warning")) 1739 }) 1740 }) 1741 }) 1742 1743 Describe("RestartApplication", func() { 1744 var ( 1745 warnings Warnings 1746 executeErr error 1747 noWait bool 1748 ) 1749 1750 BeforeEach(func() { 1751 fakeConfig.StartupTimeoutReturns(time.Second) 1752 fakeConfig.PollingIntervalReturns(0) 1753 noWait = false 1754 }) 1755 1756 JustBeforeEach(func() { 1757 warnings, executeErr = actor.RestartApplication("some-app-guid", noWait) 1758 }) 1759 1760 When("restarting the application is successful", func() { 1761 BeforeEach(func() { 1762 fakeCloudControllerClient.UpdateApplicationRestartReturns( 1763 resources.Application{GUID: "some-app-guid"}, 1764 ccv3.Warnings{"restart-application-warning"}, 1765 nil, 1766 ) 1767 }) 1768 1769 It("does not error", func() { 1770 Expect(executeErr).ToNot(HaveOccurred()) 1771 Expect(warnings).To(ConsistOf("restart-application-warning")) 1772 }) 1773 }) 1774 1775 When("restarting the application fails", func() { 1776 var expectedErr error 1777 1778 BeforeEach(func() { 1779 expectedErr = errors.New("some set restart-application error") 1780 fakeCloudControllerClient.UpdateApplicationRestartReturns( 1781 resources.Application{}, 1782 ccv3.Warnings{"restart-application-warning"}, 1783 expectedErr, 1784 ) 1785 }) 1786 1787 It("returns the warnings and error", func() { 1788 Expect(executeErr).To(Equal(expectedErr)) 1789 Expect(warnings).To(ConsistOf("restart-application-warning")) 1790 }) 1791 }) 1792 }) 1793 1794 Describe("PollProcesses", func() { 1795 var ( 1796 processes []resources.Process 1797 handleInstanceDetails func(string) 1798 reportedInstanceDetails []string 1799 1800 keepPolling bool 1801 warnings Warnings 1802 executeErr error 1803 ) 1804 1805 BeforeEach(func() { 1806 reportedInstanceDetails = []string{} 1807 handleInstanceDetails = func(instanceDetails string) { 1808 reportedInstanceDetails = append(reportedInstanceDetails, instanceDetails) 1809 } 1810 1811 processes = []resources.Process{ 1812 {GUID: "process-1"}, 1813 {GUID: "process-2"}, 1814 } 1815 }) 1816 1817 JustBeforeEach(func() { 1818 keepPolling, warnings, executeErr = actor.PollProcesses(processes, handleInstanceDetails) 1819 }) 1820 1821 It("gets process instances for each process", func() { 1822 Expect(executeErr).NotTo(HaveOccurred()) 1823 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(2)) 1824 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process-1")) 1825 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(1)).To(Equal("process-2")) 1826 }) 1827 1828 When("getting the process instances fails", func() { 1829 BeforeEach(func() { 1830 fakeCloudControllerClient.GetProcessInstancesReturns(nil, ccv3.Warnings{"get-instances-warning"}, errors.New("get-instances-error")) 1831 }) 1832 1833 It("returns an error and warnings and terminates the loop", func() { 1834 Expect(executeErr).To(MatchError("get-instances-error")) 1835 Expect(warnings).To(ConsistOf("get-instances-warning")) 1836 Expect(keepPolling).To(BeTrue()) 1837 1838 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(1)) 1839 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process-1")) 1840 }) 1841 }) 1842 1843 When("getting the process instances is always successful", func() { 1844 When("a process has all instances crashed", func() { 1845 BeforeEach(func() { 1846 fakeCloudControllerClient.GetProcessInstancesReturns( 1847 []ccv3.ProcessInstance{ 1848 {State: constant.ProcessInstanceCrashed, Details: "details1"}, 1849 }, 1850 ccv3.Warnings{"get-process1-instances-warning"}, 1851 nil, 1852 ) 1853 }) 1854 1855 It("calls the callback function with the retrieved instances", func() { 1856 Expect(reportedInstanceDetails).To(Equal([]string{ 1857 "Error starting instances: 'details1'", 1858 })) 1859 }) 1860 1861 It("returns an all instances crashed error", func() { 1862 Expect(executeErr).To(MatchError(actionerror.AllInstancesCrashedError{})) 1863 Expect(warnings).To(ConsistOf("get-process1-instances-warning")) 1864 Expect(keepPolling).To(BeTrue()) 1865 }) 1866 }) 1867 1868 When("there are still instances in the starting state for a process", func() { 1869 BeforeEach(func() { 1870 fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(0, 1871 []ccv3.ProcessInstance{ 1872 {State: constant.ProcessInstanceRunning}, 1873 }, 1874 ccv3.Warnings{"get-process1-instances-warning"}, 1875 nil, 1876 ) 1877 1878 fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(1, 1879 []ccv3.ProcessInstance{ 1880 {State: constant.ProcessInstanceStarting, Details: "details2"}, 1881 }, 1882 ccv3.Warnings{"get-process2-instances-warning"}, 1883 nil, 1884 ) 1885 }) 1886 1887 It("calls the callback function with the retrieved instances", func() { 1888 Expect(reportedInstanceDetails).To(Equal([]string{ 1889 "Instances starting...", 1890 "Error starting instances: 'details2'", 1891 })) 1892 }) 1893 1894 It("returns success and that we should keep polling", func() { 1895 Expect(executeErr).NotTo(HaveOccurred()) 1896 Expect(warnings).To(ConsistOf("get-process1-instances-warning", "get-process2-instances-warning")) 1897 Expect(keepPolling).To(BeFalse()) 1898 }) 1899 }) 1900 1901 When("all the instances of all processes are stable", func() { 1902 BeforeEach(func() { 1903 fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(0, 1904 []ccv3.ProcessInstance{ 1905 {State: constant.ProcessInstanceRunning, Details: "details1"}, 1906 }, 1907 ccv3.Warnings{"get-process1-instances-warning"}, 1908 nil, 1909 ) 1910 1911 fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(1, 1912 []ccv3.ProcessInstance{ 1913 {State: constant.ProcessInstanceRunning}, 1914 }, 1915 ccv3.Warnings{"get-process2-instances-warning"}, 1916 nil, 1917 ) 1918 }) 1919 1920 It("calls the callback function with the retrieved instances", func() { 1921 Expect(reportedInstanceDetails).To(Equal([]string{ 1922 "Error starting instances: 'details1'", 1923 "Instances starting...", 1924 })) 1925 }) 1926 1927 It("returns success and that we should keep polling", func() { 1928 Expect(executeErr).NotTo(HaveOccurred()) 1929 Expect(warnings).To(ConsistOf("get-process1-instances-warning", "get-process2-instances-warning")) 1930 Expect(keepPolling).To(BeTrue()) 1931 }) 1932 1933 }) 1934 }) 1935 1936 }) 1937 1938 Describe("GetUnstagedNewestPackageGUID", func() { 1939 var ( 1940 packageToStage string 1941 warnings Warnings 1942 executeErr error 1943 ) 1944 1945 JustBeforeEach(func() { 1946 packageToStage, warnings, executeErr = actor.GetUnstagedNewestPackageGUID("some-app-guid") 1947 }) 1948 1949 // Nothing to stage. 1950 When("There are no packages on the app", func() { 1951 When("getting the packages succeeds", func() { 1952 BeforeEach(func() { 1953 fakeCloudControllerClient.GetPackagesReturns([]resources.Package{}, ccv3.Warnings{"get-packages-warnings"}, nil) 1954 }) 1955 1956 It("checks for packages", func() { 1957 Expect(fakeCloudControllerClient.GetPackagesCallCount()).To(Equal(1)) 1958 Expect(fakeCloudControllerClient.GetPackagesArgsForCall(0)).To(ConsistOf( 1959 ccv3.Query{Key: ccv3.AppGUIDFilter, Values: []string{"some-app-guid"}}, 1960 ccv3.Query{Key: ccv3.OrderBy, Values: []string{ccv3.CreatedAtDescendingOrder}}, 1961 ccv3.Query{Key: ccv3.PerPage, Values: []string{"1"}}, 1962 ccv3.Query{Key: ccv3.Page, Values: []string{"1"}}, 1963 )) 1964 }) 1965 1966 It("returns empty string", func() { 1967 Expect(packageToStage).To(Equal("")) 1968 Expect(warnings).To(ConsistOf("get-packages-warnings")) 1969 Expect(executeErr).To(BeNil()) 1970 }) 1971 }) 1972 1973 When("getting the packages fails", func() { 1974 BeforeEach(func() { 1975 fakeCloudControllerClient.GetPackagesReturns( 1976 nil, 1977 ccv3.Warnings{"get-packages-warnings"}, 1978 errors.New("get-packages-error"), 1979 ) 1980 }) 1981 1982 It("returns the error", func() { 1983 Expect(warnings).To(ConsistOf("get-packages-warnings")) 1984 Expect(executeErr).To(MatchError("get-packages-error")) 1985 }) 1986 }) 1987 }) 1988 1989 When("there are packages", func() { 1990 BeforeEach(func() { 1991 fakeCloudControllerClient.GetPackagesReturns( 1992 []resources.Package{{GUID: "package-guid", CreatedAt: "2019-01-01T06:00:00Z"}}, 1993 ccv3.Warnings{"get-packages-warning"}, 1994 nil) 1995 }) 1996 1997 It("checks for the packages latest droplet", func() { 1998 Expect(fakeCloudControllerClient.GetPackageDropletsCallCount()).To(Equal(1)) 1999 packageGuid, queries := fakeCloudControllerClient.GetPackageDropletsArgsForCall(0) 2000 Expect(packageGuid).To(Equal("package-guid")) 2001 Expect(queries).To(ConsistOf( 2002 ccv3.Query{Key: ccv3.StatesFilter, Values: []string{"STAGED"}}, 2003 ccv3.Query{Key: ccv3.PerPage, Values: []string{"1"}}, 2004 ccv3.Query{Key: ccv3.Page, Values: []string{"1"}}, 2005 )) 2006 }) 2007 2008 When("the newest package's has a STAGED droplet", func() { 2009 BeforeEach(func() { 2010 fakeCloudControllerClient.GetPackageDropletsReturns( 2011 []resources.Droplet{{State: constant.DropletStaged}}, 2012 ccv3.Warnings{"get-package-droplet-warning"}, 2013 nil, 2014 ) 2015 }) 2016 2017 It("returns empty string", func() { 2018 Expect(packageToStage).To(Equal("")) 2019 Expect(warnings).To(ConsistOf("get-packages-warning", "get-package-droplet-warning")) 2020 Expect(executeErr).To(BeNil()) 2021 }) 2022 }) 2023 2024 When("the package has no STAGED droplets", func() { 2025 BeforeEach(func() { 2026 fakeCloudControllerClient.GetPackageDropletsReturns( 2027 []resources.Droplet{}, 2028 ccv3.Warnings{"get-package-droplet-warning"}, 2029 nil, 2030 ) 2031 }) 2032 2033 It("returns the guid of the newest package", func() { 2034 Expect(packageToStage).To(Equal("package-guid")) 2035 Expect(warnings).To(ConsistOf("get-packages-warning", "get-package-droplet-warning")) 2036 Expect(executeErr).To(BeNil()) 2037 }) 2038 }) 2039 }) 2040 }) 2041 2042 Describe("RenameApplicationByNameAndSpaceGUID", func() { 2043 When("the app does not exist", func() { 2044 BeforeEach(func() { 2045 fakeCloudControllerClient.GetApplicationsReturns( 2046 []resources.Application{}, 2047 ccv3.Warnings{"some-warning"}, 2048 nil, 2049 ) 2050 }) 2051 2052 It("returns an ApplicationNotFoundError and the warnings", func() { 2053 _, warnings, err := actor.RenameApplicationByNameAndSpaceGUID("old-app-name", "new-app-name", "space-guid") 2054 Expect(warnings).To(ConsistOf("some-warning")) 2055 Expect(err).To(MatchError(actionerror.ApplicationNotFoundError{Name: "old-app-name"})) 2056 }) 2057 }) 2058 2059 When("the cloud controller client returns an error on application find", func() { 2060 var expectedError error 2061 2062 BeforeEach(func() { 2063 expectedError = errors.New("I am a CloudControllerClient Error") 2064 fakeCloudControllerClient.GetApplicationsReturns( 2065 []resources.Application{}, 2066 ccv3.Warnings{"some-warning"}, 2067 expectedError) 2068 }) 2069 2070 It("returns the warnings and the error", func() { 2071 _, warnings, err := actor.RenameApplicationByNameAndSpaceGUID("old-app-name", "new-app-name", "space-guid") 2072 Expect(warnings).To(ConsistOf("some-warning")) 2073 Expect(err).To(MatchError(expectedError)) 2074 }) 2075 }) 2076 2077 When("the cloud controller client returns an error on application update", func() { 2078 var expectedError error 2079 2080 BeforeEach(func() { 2081 expectedError = errors.New("I am a CloudControllerClient Error") 2082 fakeCloudControllerClient.GetApplicationsReturns( 2083 []resources.Application{ 2084 { 2085 Name: "old-app-name", 2086 GUID: "old-app-guid", 2087 }, 2088 }, 2089 ccv3.Warnings{"get-app-warning"}, 2090 nil) 2091 fakeCloudControllerClient.UpdateApplicationNameReturns( 2092 resources.Application{}, 2093 ccv3.Warnings{"update-app-warning"}, 2094 expectedError) 2095 }) 2096 2097 It("returns the warnings and the error", func() { 2098 _, warnings, err := actor.RenameApplicationByNameAndSpaceGUID("old-app-name", "new-app-name", "space-guid") 2099 Expect(warnings).To(ConsistOf("get-app-warning", "update-app-warning")) 2100 Expect(err).To(MatchError(expectedError)) 2101 }) 2102 }) 2103 2104 When("the app exists", func() { 2105 BeforeEach(func() { 2106 fakeCloudControllerClient.GetApplicationsReturns( 2107 []resources.Application{ 2108 { 2109 Name: "old-app-name", 2110 GUID: "old-app-guid", 2111 }, 2112 }, 2113 ccv3.Warnings{"get-app-warning"}, 2114 nil, 2115 ) 2116 2117 fakeCloudControllerClient.UpdateApplicationNameReturns( 2118 resources.Application{ 2119 Name: "new-app-name", 2120 GUID: "old-app-guid", 2121 }, 2122 ccv3.Warnings{"update-app-warning"}, 2123 nil, 2124 ) 2125 }) 2126 2127 It("changes the app name and returns the application and warnings", func() { 2128 app, warnings, err := actor.RenameApplicationByNameAndSpaceGUID("old-app-name", "new-app-name", "some-space-guid") 2129 Expect(err).ToNot(HaveOccurred()) 2130 Expect(app).To(Equal(resources.Application{ 2131 Name: "new-app-name", 2132 GUID: "old-app-guid", 2133 })) 2134 Expect(warnings).To(ConsistOf("get-app-warning", "update-app-warning")) 2135 appName, appGuid := fakeCloudControllerClient.UpdateApplicationNameArgsForCall(0) 2136 Expect(appName).To(Equal("new-app-name")) 2137 Expect(appGuid).To(Equal("old-app-guid")) 2138 }) 2139 }) 2140 2141 }) 2142 })