github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/command/v6/v3_zdt_push_command_test.go (about) 1 package v6_test 2 3 import ( 4 "errors" 5 "time" 6 7 "code.cloudfoundry.org/cli/actor/actionerror" 8 "code.cloudfoundry.org/cli/actor/pushaction" 9 "code.cloudfoundry.org/cli/actor/v2action" 10 "code.cloudfoundry.org/cli/actor/v3action" 11 "code.cloudfoundry.org/cli/actor/v3action/v3actionfakes" 12 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 13 "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" 14 "code.cloudfoundry.org/cli/command/commandfakes" 15 "code.cloudfoundry.org/cli/command/flag" 16 "code.cloudfoundry.org/cli/command/translatableerror" 17 . "code.cloudfoundry.org/cli/command/v6" 18 "code.cloudfoundry.org/cli/command/v6/shared" 19 "code.cloudfoundry.org/cli/command/v6/shared/sharedfakes" 20 "code.cloudfoundry.org/cli/command/v6/v6fakes" 21 "code.cloudfoundry.org/cli/types" 22 "code.cloudfoundry.org/cli/util/configv3" 23 "code.cloudfoundry.org/cli/util/ui" 24 . "github.com/onsi/ginkgo" 25 . "github.com/onsi/ginkgo/extensions/table" 26 . "github.com/onsi/gomega" 27 . "github.com/onsi/gomega/gbytes" 28 ) 29 30 var _ = Describe("v3-zdt-push Command", func() { 31 var ( 32 cmd V3ZeroDowntimePushCommand 33 testUI *ui.UI 34 fakeConfig *commandfakes.FakeConfig 35 fakeSharedActor *commandfakes.FakeSharedActor 36 fakeNOAAClient *v3actionfakes.FakeNOAAClient 37 fakeZdtActor *v6fakes.FakeV3ZeroDowntimeVersionActor 38 fakeV3PushActor *v6fakes.FakeV3PushActor 39 fakeV2PushActor *v6fakes.FakeOriginalV2PushActor 40 fakeV2AppActor *sharedfakes.FakeV2AppActor 41 binaryName string 42 executeErr error 43 app string 44 userName string 45 spaceName string 46 orgName string 47 ) 48 49 BeforeEach(func() { 50 testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) 51 fakeConfig = new(commandfakes.FakeConfig) 52 fakeSharedActor = new(commandfakes.FakeSharedActor) 53 fakeZdtActor = new(v6fakes.FakeV3ZeroDowntimeVersionActor) 54 fakeV3PushActor = new(v6fakes.FakeV3PushActor) 55 fakeV2PushActor = new(v6fakes.FakeOriginalV2PushActor) 56 fakeV2AppActor = new(sharedfakes.FakeV2AppActor) 57 fakeNOAAClient = new(v3actionfakes.FakeNOAAClient) 58 59 fakeConfig.StagingTimeoutReturns(10 * time.Minute) 60 61 binaryName = "faceman" 62 fakeConfig.BinaryNameReturns(binaryName) 63 app = "some-app" 64 userName = "banana" 65 spaceName = "some-space" 66 orgName = "some-org" 67 68 appSummaryDisplayer := shared.AppSummaryDisplayer{ 69 UI: testUI, 70 Config: fakeConfig, 71 Actor: fakeV3PushActor, 72 V2AppActor: fakeV2AppActor, 73 AppName: app, 74 } 75 packageDisplayer := shared.NewPackageDisplayer( 76 testUI, 77 fakeConfig, 78 ) 79 80 cmd = V3ZeroDowntimePushCommand{ 81 RequiredArgs: flag.AppName{AppName: app}, 82 83 UI: testUI, 84 Config: fakeConfig, 85 SharedActor: fakeSharedActor, 86 ZdtActor: fakeZdtActor, 87 OriginalV2PushActor: fakeV2PushActor, 88 89 NOAAClient: fakeNOAAClient, 90 AppSummaryDisplayer: appSummaryDisplayer, 91 PackageDisplayer: packageDisplayer, 92 } 93 fakeZdtActor.CloudControllerAPIVersionReturns(ccversion.MinVersionZeroDowntimePushV3) 94 95 // we stub out StagePackage out here so the happy paths below don't hang 96 fakeZdtActor.StagePackageStub = func(_ string, _ string) (<-chan v3action.Droplet, <-chan v3action.Warnings, <-chan error) { 97 dropletStream := make(chan v3action.Droplet) 98 warningsStream := make(chan v3action.Warnings) 99 errorStream := make(chan error) 100 101 go func() { 102 defer close(dropletStream) 103 defer close(warningsStream) 104 defer close(errorStream) 105 }() 106 107 return dropletStream, warningsStream, errorStream 108 } 109 }) 110 111 JustBeforeEach(func() { 112 executeErr = cmd.Execute(nil) 113 }) 114 115 When("the API version is at the minimum documented version", func() { 116 const MinVersionDocumentedZDTPush = "3.55.0" // CAPI docs show that 3.55.0 should work, but it doesn't, 117 // so we're using 3.55 as the "version below the version we support" in this test to document this fact. 118 BeforeEach(func() { 119 fakeZdtActor.CloudControllerAPIVersionReturns(MinVersionDocumentedZDTPush) 120 }) 121 122 It("returns a MinimumAPIVersionNotMetError", func() { 123 Expect(executeErr).To(MatchError(translatableerror.MinimumCFAPIVersionNotMetError{ 124 CurrentVersion: MinVersionDocumentedZDTPush, 125 MinimumVersion: ccversion.MinVersionZeroDowntimePushV3, 126 })) 127 }) 128 129 It("displays the experimental warning", func() { 130 Expect(testUI.Err).To(Say("This command is in EXPERIMENTAL stage and may change without notice")) 131 }) 132 }) 133 134 When("the API version is the oldest supported by the CLI", func() { 135 BeforeEach(func() { 136 fakeZdtActor.CloudControllerAPIVersionReturns(ccversion.MinSupportedV3ClientVersion) 137 }) 138 139 It("returns a MinimumAPIVersionNotMetError", func() { 140 Expect(executeErr).To(MatchError(translatableerror.MinimumCFAPIVersionNotMetError{ 141 CurrentVersion: ccversion.MinSupportedV3ClientVersion, 142 MinimumVersion: ccversion.MinVersionZeroDowntimePushV3, 143 })) 144 }) 145 146 It("displays the experimental warning", func() { 147 Expect(testUI.Err).To(Say("This command is in EXPERIMENTAL stage and may change without notice")) 148 }) 149 }) 150 151 DescribeTable("argument combinations", 152 func(dockerImage string, dockerUsername string, dockerPassword string, 153 buildpacks []string, appPath string, 154 expectedErr error) { 155 cmd.DockerImage.Path = dockerImage 156 cmd.DockerUsername = dockerUsername 157 fakeConfig.DockerPasswordReturns(dockerPassword) 158 cmd.Buildpacks = buildpacks 159 cmd.AppPath = flag.PathWithExistenceCheck(appPath) 160 Expect(cmd.Execute(nil)).To(MatchError(expectedErr)) 161 }, 162 Entry("docker username", 163 "", "some-docker-username", "", []string{}, "", 164 translatableerror.RequiredFlagsError{ 165 Arg1: "--docker-image, -o", 166 Arg2: "--docker-username", 167 }), 168 Entry("docker username, password", 169 "", "some-docker-username", "my-password", []string{}, "", 170 translatableerror.RequiredFlagsError{ 171 Arg1: "--docker-image, -o", 172 Arg2: "--docker-username", 173 }), 174 Entry("docker username, app path", 175 "", "some-docker-username", "", []string{}, "some/app/path", 176 translatableerror.RequiredFlagsError{ 177 Arg1: "--docker-image, -o", 178 Arg2: "--docker-username", 179 }), 180 Entry("docker username, buildpacks", 181 "", "some-docker-username", "", []string{"ruby_buildpack"}, "", 182 translatableerror.RequiredFlagsError{ 183 Arg1: "--docker-image, -o", 184 Arg2: "--docker-username", 185 }), 186 Entry("docker image, docker username", 187 "some-docker-image", "some-docker-username", "", []string{}, "", 188 translatableerror.DockerPasswordNotSetError{}), 189 Entry("docker image, app path", 190 "some-docker-image", "", "", []string{}, "some/app/path", 191 translatableerror.ArgumentCombinationError{ 192 Args: []string{"--docker-image", "-o", "-p"}, 193 }), 194 Entry("docker image, buildpacks", 195 "some-docker-image", "", "", []string{"ruby_buildpack"}, "", 196 translatableerror.ArgumentCombinationError{ 197 Args: []string{"-b", "--docker-image", "-o"}, 198 }), 199 ) 200 201 Context("when checking target fails", func() { 202 BeforeEach(func() { 203 fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName}) 204 }) 205 206 It("returns an error", func() { 207 Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: binaryName})) 208 209 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 210 checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 211 Expect(checkTargetedOrg).To(BeTrue()) 212 Expect(checkTargetedSpace).To(BeTrue()) 213 }) 214 }) 215 216 Context("when the user is logged in", func() { 217 BeforeEach(func() { 218 fakeConfig.CurrentUserReturns(configv3.User{Name: userName}, nil) 219 fakeConfig.TargetedSpaceReturns(configv3.Space{Name: spaceName, GUID: "some-space-guid"}) 220 fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: orgName, GUID: "some-org-guid"}) 221 }) 222 223 Context("when looking up the application returns some api error", func() { 224 BeforeEach(func() { 225 fakeZdtActor.GetApplicationByNameAndSpaceReturns(v3action.Application{}, v3action.Warnings{"get-warning"}, errors.New("some-error")) 226 }) 227 228 It("returns the error and displays all warnings", func() { 229 Expect(executeErr).To(MatchError("some-error")) 230 231 Expect(testUI.Err).To(Say("get-warning")) 232 }) 233 }) 234 235 Context("when the application doesn't exist", func() { 236 BeforeEach(func() { 237 fakeZdtActor.GetApplicationByNameAndSpaceReturns(v3action.Application{}, v3action.Warnings{"get-warning"}, actionerror.ApplicationNotFoundError{Name: "some-app"}) 238 }) 239 240 Context("when creating the application returns an error", func() { 241 var expectedErr error 242 243 BeforeEach(func() { 244 expectedErr = errors.New("I am an error") 245 fakeZdtActor.CreateApplicationInSpaceReturns(v3action.Application{}, v3action.Warnings{"I am a warning", "I am also a warning"}, expectedErr) 246 }) 247 248 It("displays the warnings and error", func() { 249 Expect(executeErr).To(MatchError(expectedErr)) 250 251 Expect(testUI.Err).To(Say("I am a warning")) 252 Expect(testUI.Err).To(Say("I am also a warning")) 253 Expect(testUI.Out).ToNot(Say("app some-app in org some-org / space some-space as banana...")) 254 }) 255 }) 256 257 Context("when creating the application does not error", func() { 258 BeforeEach(func() { 259 fakeZdtActor.CreateApplicationInSpaceReturns(v3action.Application{Name: "some-app", GUID: "some-app-guid", State: constant.ApplicationStopped}, v3action.Warnings{"I am a warning", "I am also a warning"}, nil) 260 }) 261 262 It("calls CreateApplication", func() { 263 Expect(fakeZdtActor.CreateApplicationInSpaceCallCount()).To(Equal(1), "Expected CreateApplicationInSpace to be called once") 264 createApp, createSpaceGUID := fakeZdtActor.CreateApplicationInSpaceArgsForCall(0) 265 Expect(createApp).To(Equal(v3action.Application{ 266 Name: "some-app", 267 LifecycleType: constant.AppLifecycleTypeBuildpack, 268 })) 269 Expect(createSpaceGUID).To(Equal("some-space-guid")) 270 }) 271 272 Context("when creating the package fails", func() { 273 var expectedErr error 274 275 BeforeEach(func() { 276 expectedErr = errors.New("I am an error") 277 fakeZdtActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceReturns(v3action.Package{}, v3action.Warnings{"I am a package warning", "I am also a package warning"}, expectedErr) 278 }) 279 280 It("displays the header and error", func() { 281 Expect(executeErr).To(MatchError(expectedErr)) 282 283 Expect(testUI.Out).To(Say("Uploading and creating bits package for app some-app in org some-org / space some-space as banana...")) 284 285 Expect(testUI.Err).To(Say("I am a package warning")) 286 Expect(testUI.Err).To(Say("I am also a package warning")) 287 288 Expect(testUI.Out).ToNot(Say("Staging package for %s in org some-org / space some-space as banana...", app)) 289 }) 290 }) 291 292 Context("when creating the package succeeds", func() { 293 BeforeEach(func() { 294 fakeZdtActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceReturns(v3action.Package{GUID: "some-guid"}, v3action.Warnings{"I am a package warning", "I am also a package warning"}, nil) 295 }) 296 297 Context("when the -p flag is provided", func() { 298 BeforeEach(func() { 299 cmd.AppPath = "some-app-path" 300 }) 301 302 It("creates the package with the provided path", func() { 303 Expect(testUI.Out).To(Say("Uploading and creating bits package for app %s in org %s / space %s as %s", app, orgName, spaceName, userName)) 304 Expect(testUI.Err).To(Say("I am a package warning")) 305 Expect(testUI.Err).To(Say("I am also a package warning")) 306 Expect(testUI.Out).To(Say("OK")) 307 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 308 309 Expect(fakeZdtActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceCallCount()).To(Equal(1)) 310 _, _, appPath := fakeZdtActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceArgsForCall(0) 311 312 Expect(appPath).To(Equal("some-app-path")) 313 }) 314 }) 315 316 Context("when the -o flag is provided", func() { 317 BeforeEach(func() { 318 cmd.DockerImage.Path = "example.com/docker/docker/docker:docker" 319 fakeZdtActor.CreateDockerPackageByApplicationNameAndSpaceReturns(v3action.Package{GUID: "some-guid"}, v3action.Warnings{"I am a docker package warning", "I am also a docker package warning"}, nil) 320 }) 321 322 It("creates a docker package with the provided image path", func() { 323 324 Expect(testUI.Out).To(Say("Creating docker package for app %s in org %s / space %s as %s", app, orgName, spaceName, userName)) 325 Expect(testUI.Err).To(Say("I am a docker package warning")) 326 Expect(testUI.Err).To(Say("I am also a docker package warning")) 327 Expect(testUI.Out).To(Say("OK")) 328 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 329 330 Expect(fakeZdtActor.CreateDockerPackageByApplicationNameAndSpaceCallCount()).To(Equal(1)) 331 _, _, dockerImageCredentials := fakeZdtActor.CreateDockerPackageByApplicationNameAndSpaceArgsForCall(0) 332 333 Expect(dockerImageCredentials.Path).To(Equal("example.com/docker/docker/docker:docker")) 334 }) 335 }) 336 337 Context("when neither -p nor -o flags are provided", func() { 338 It("calls CreateAndUploadBitsPackageByApplicationNameAndSpace with empty string", func() { 339 Expect(testUI.Out).To(Say("Uploading and creating bits package for app %s in org %s / space %s as %s", app, orgName, spaceName, userName)) 340 341 Expect(fakeZdtActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceCallCount()).To(Equal(1)) 342 _, _, appPath := fakeZdtActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceArgsForCall(0) 343 344 Expect(appPath).To(BeEmpty()) 345 }) 346 }) 347 348 Context("when getting streaming logs fails", func() { 349 var expectedErr error 350 BeforeEach(func() { 351 expectedErr = errors.New("something is wrong!") 352 fakeZdtActor.GetStreamingLogsForApplicationByNameAndSpaceReturns(nil, nil, v3action.Warnings{"some-logging-warning", "some-other-logging-warning"}, expectedErr) 353 }) 354 355 It("returns the error and displays warnings", func() { 356 Expect(executeErr).To(Equal(expectedErr)) 357 358 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 359 360 Expect(testUI.Err).To(Say("some-logging-warning")) 361 Expect(testUI.Err).To(Say("some-other-logging-warning")) 362 363 }) 364 }) 365 366 Context("when --no-start is provided", func() { 367 BeforeEach(func() { 368 cmd.NoStart = true 369 }) 370 371 It("does not stage the package and returns", func() { 372 Expect(testUI.Out).To(Say("Uploading and creating bits package for app %s in org %s / space %s as %s", app, orgName, spaceName, userName)) 373 Expect(fakeZdtActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceCallCount()).To(Equal(1)) 374 Expect(fakeZdtActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(0)) 375 376 Expect(executeErr).ToNot(HaveOccurred()) 377 }) 378 }) 379 380 Context("when the logging does not error", func() { 381 var allLogsWritten chan bool 382 383 BeforeEach(func() { 384 allLogsWritten = make(chan bool) 385 fakeZdtActor.GetStreamingLogsForApplicationByNameAndSpaceStub = func(appName string, spaceGUID string, client v3action.NOAAClient) (<-chan *v3action.LogMessage, <-chan error, v3action.Warnings, error) { 386 logStream := make(chan *v3action.LogMessage) 387 errorStream := make(chan error) 388 389 go func() { 390 logStream <- v3action.NewLogMessage("Here are some staging logs!", 1, time.Now(), v3action.StagingLog, "sourceInstance") 391 logStream <- v3action.NewLogMessage("Here are some other staging logs!", 1, time.Now(), v3action.StagingLog, "sourceInstance") 392 logStream <- v3action.NewLogMessage("not from staging", 1, time.Now(), "potato", "sourceInstance") 393 allLogsWritten <- true 394 }() 395 396 return logStream, errorStream, v3action.Warnings{"steve for all I care"}, nil 397 } 398 }) 399 400 Context("when the staging returns an error", func() { 401 var expectedErr error 402 403 BeforeEach(func() { 404 expectedErr = errors.New("any gibberish") 405 fakeZdtActor.StagePackageStub = func(packageGUID string, _ string) (<-chan v3action.Droplet, <-chan v3action.Warnings, <-chan error) { 406 dropletStream := make(chan v3action.Droplet) 407 warningsStream := make(chan v3action.Warnings) 408 errorStream := make(chan error) 409 410 go func() { 411 <-allLogsWritten 412 defer close(dropletStream) 413 defer close(warningsStream) 414 defer close(errorStream) 415 warningsStream <- v3action.Warnings{"some-staging-warning", "some-other-staging-warning"} 416 errorStream <- expectedErr 417 }() 418 419 return dropletStream, warningsStream, errorStream 420 } 421 }) 422 423 It("returns the error and displays warnings", func() { 424 Expect(executeErr).To(Equal(expectedErr)) 425 426 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 427 428 Expect(testUI.Err).To(Say("some-staging-warning")) 429 Expect(testUI.Err).To(Say("some-other-staging-warning")) 430 431 Expect(testUI.Out).ToNot(Say("Setting app some-app to droplet some-droplet-guid in org some-org / space some-space as banana...")) 432 }) 433 }) 434 435 Context("when the staging is successful", func() { 436 BeforeEach(func() { 437 fakeZdtActor.StagePackageStub = func(packageGUID string, _ string) (<-chan v3action.Droplet, <-chan v3action.Warnings, <-chan error) { 438 dropletStream := make(chan v3action.Droplet) 439 warningsStream := make(chan v3action.Warnings) 440 errorStream := make(chan error) 441 442 go func() { 443 <-allLogsWritten 444 defer close(dropletStream) 445 defer close(warningsStream) 446 defer close(errorStream) 447 warningsStream <- v3action.Warnings{"some-staging-warning", "some-other-staging-warning"} 448 dropletStream <- v3action.Droplet{GUID: "some-droplet-guid"} 449 }() 450 451 return dropletStream, warningsStream, errorStream 452 } 453 }) 454 455 It("outputs the staging message and warnings", func() { 456 Expect(executeErr).ToNot(HaveOccurred()) 457 458 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 459 Expect(testUI.Out).To(Say("OK")) 460 461 Expect(testUI.Err).To(Say("some-staging-warning")) 462 Expect(testUI.Err).To(Say("some-other-staging-warning")) 463 }) 464 465 It("stages the package", func() { 466 Expect(executeErr).ToNot(HaveOccurred()) 467 Expect(fakeZdtActor.StagePackageCallCount()).To(Equal(1)) 468 guidArg, _ := fakeZdtActor.StagePackageArgsForCall(0) 469 Expect(guidArg).To(Equal("some-guid")) 470 }) 471 472 It("displays staging logs and their warnings", func() { 473 Expect(testUI.Out).To(Say("Here are some staging logs!")) 474 Expect(testUI.Out).To(Say("Here are some other staging logs!")) 475 Expect(testUI.Out).ToNot(Say("not from staging")) 476 477 Expect(testUI.Err).To(Say("steve for all I care")) 478 479 Expect(fakeZdtActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(1)) 480 appName, spaceGUID, noaaClient := fakeZdtActor.GetStreamingLogsForApplicationByNameAndSpaceArgsForCall(0) 481 Expect(appName).To(Equal(app)) 482 Expect(spaceGUID).To(Equal("some-space-guid")) 483 Expect(noaaClient).To(Equal(fakeNOAAClient)) 484 485 guidArg, _ := fakeZdtActor.StagePackageArgsForCall(0) 486 Expect(guidArg).To(Equal("some-guid")) 487 }) 488 489 Context("when --no-route flag is set to true", func() { 490 BeforeEach(func() { 491 cmd.NoRoute = true 492 }) 493 494 It("does not create any routes", func() { 495 Expect(fakeV2PushActor.CreateAndMapDefaultApplicationRouteCallCount()).To(Equal(0)) 496 497 Expect(fakeZdtActor.RestartApplicationCallCount()).To(Equal(1)) 498 }) 499 }) 500 501 Context("when buildpack(s) are provided via -b flag", func() { 502 BeforeEach(func() { 503 cmd.Buildpacks = []string{"some-buildpack"} 504 }) 505 506 It("creates the app with the specified buildpack and prints the buildpack name in the summary", func() { 507 Expect(fakeZdtActor.CreateApplicationInSpaceCallCount()).To(Equal(1), "Expected CreateApplicationInSpace to be called once") 508 createApp, createSpaceGUID := fakeZdtActor.CreateApplicationInSpaceArgsForCall(0) 509 Expect(createApp).To(Equal(v3action.Application{ 510 Name: "some-app", 511 LifecycleType: constant.AppLifecycleTypeBuildpack, 512 LifecycleBuildpacks: []string{"some-buildpack"}, 513 })) 514 Expect(createSpaceGUID).To(Equal("some-space-guid")) 515 }) 516 }) 517 518 Context("when a docker image is specified", func() { 519 BeforeEach(func() { 520 cmd.DockerImage.Path = "example.com/docker/docker/docker:docker" 521 }) 522 523 It("creates the app with a docker lifecycle", func() { 524 Expect(fakeZdtActor.CreateApplicationInSpaceCallCount()).To(Equal(1), "Expected CreateApplicationInSpace to be called once") 525 createApp, createSpaceGUID := fakeZdtActor.CreateApplicationInSpaceArgsForCall(0) 526 Expect(createApp).To(Equal(v3action.Application{ 527 Name: "some-app", 528 LifecycleType: constant.AppLifecycleTypeDocker, 529 })) 530 Expect(createSpaceGUID).To(Equal("some-space-guid")) 531 }) 532 }) 533 534 Context("when mapping routes fails", func() { 535 BeforeEach(func() { 536 fakeV2PushActor.CreateAndMapDefaultApplicationRouteReturns(pushaction.Warnings{"route-warning"}, errors.New("some-error")) 537 }) 538 539 It("returns the error", func() { 540 Expect(executeErr).To(MatchError("some-error")) 541 Expect(testUI.Out).To(Say(`Mapping routes\.\.\.`)) 542 Expect(testUI.Err).To(Say("route-warning")) 543 544 Expect(fakeZdtActor.RestartApplicationCallCount()).To(Equal(0)) 545 }) 546 }) 547 548 Context("when mapping routes succeeds and the app doesn't have a current droplet", func() { 549 BeforeEach(func() { 550 fakeV2PushActor.CreateAndMapDefaultApplicationRouteReturns(pushaction.Warnings{"route-warning"}, nil) 551 fakeZdtActor.GetCurrentDropletByApplicationReturns(v3action.Droplet{}, v3action.Warnings{}, actionerror.DropletNotFoundError{AppGUID: "some-app-guid"}) 552 }) 553 554 It("displays the header and OK", func() { 555 Expect(testUI.Out).To(Say(`Mapping routes\.\.\.`)) 556 Expect(testUI.Out).To(Say("OK")) 557 558 Expect(testUI.Err).To(Say("route-warning")) 559 560 Expect(fakeV2PushActor.CreateAndMapDefaultApplicationRouteCallCount()).To(Equal(1), "Expected CreateAndMapDefaultApplicationRoute to be called") 561 orgArg, spaceArg, appArg := fakeV2PushActor.CreateAndMapDefaultApplicationRouteArgsForCall(0) 562 Expect(orgArg).To(Equal("some-org-guid")) 563 Expect(spaceArg).To(Equal("some-space-guid")) 564 Expect(appArg).To(Equal(v2action.Application{Name: "some-app", GUID: "some-app-guid"})) 565 566 Expect(fakeZdtActor.RestartApplicationCallCount()).To(Equal(1)) 567 }) 568 569 It("restarts the application", func() { 570 Expect(executeErr).NotTo(HaveOccurred()) 571 Expect(fakeZdtActor.RestartApplicationCallCount()).To(Equal(1)) 572 }) 573 574 Context("when restarting the application fails", func() { 575 BeforeEach(func() { 576 fakeZdtActor.RestartApplicationReturns(v3action.Warnings{"start-warning-1", "start-warning-2"}, errors.New("some-error")) 577 }) 578 579 It("says that the app failed to start", func() { 580 Expect(executeErr).To(Equal(errors.New("some-error"))) 581 Expect(testUI.Out).To(Say(`Starting app some-app in org some-org / space some-space as banana\.\.\.`)) 582 583 Expect(testUI.Err).To(Say("start-warning-1")) 584 Expect(testUI.Err).To(Say("start-warning-2")) 585 586 Expect(testUI.Out).ToNot(Say(`Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.`)) 587 }) 588 }) 589 590 Context("when restarting the application succeeds", func() { 591 BeforeEach(func() { 592 fakeZdtActor.RestartApplicationReturns(v3action.Warnings{"start-warning-1", "start-warning-2"}, nil) 593 }) 594 595 It("says that the app was started and outputs warnings", func() { 596 Expect(testUI.Out).To(Say(`Starting app some-app in org some-org / space some-space as banana\.\.\.`)) 597 598 Expect(testUI.Err).To(Say("start-warning-1")) 599 Expect(testUI.Err).To(Say("start-warning-2")) 600 Expect(testUI.Out).To(Say("OK")) 601 602 Expect(fakeZdtActor.RestartApplicationCallCount()).To(Equal(1)) 603 appGUID := fakeZdtActor.RestartApplicationArgsForCall(0) 604 Expect(appGUID).To(Equal("some-app-guid")) 605 }) 606 607 }) 608 609 Context("it polls the application", func() { 610 Context("when polling the start fails", func() { 611 BeforeEach(func() { 612 fakeZdtActor.PollStartStub = func(appGUID string, warnings chan<- v3action.Warnings) error { 613 warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"} 614 return errors.New("some-error") 615 } 616 }) 617 618 It("displays all warnings and fails", func() { 619 Expect(testUI.Out).To(Say(`Waiting for app to start\.\.\.`)) 620 621 Expect(testUI.Err).To(Say("some-poll-warning-1")) 622 Expect(testUI.Err).To(Say("some-poll-warning-2")) 623 624 Expect(executeErr).To(MatchError("some-error")) 625 }) 626 }) 627 628 Context("when polling times out", func() { 629 BeforeEach(func() { 630 fakeZdtActor.PollStartReturns(actionerror.StartupTimeoutError{}) 631 }) 632 633 It("returns the StartupTimeoutError", func() { 634 Expect(executeErr).To(MatchError(translatableerror.StartupTimeoutError{ 635 AppName: "some-app", 636 BinaryName: binaryName, 637 })) 638 }) 639 }) 640 641 Context("when polling the start succeeds", func() { 642 BeforeEach(func() { 643 fakeZdtActor.PollStartStub = func(appGUID string, warnings chan<- v3action.Warnings) error { 644 warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"} 645 return nil 646 } 647 }) 648 649 It("displays all warnings", func() { 650 Expect(testUI.Out).To(Say(`Waiting for app to start\.\.\.`)) 651 652 Expect(testUI.Err).To(Say("some-poll-warning-1")) 653 Expect(testUI.Err).To(Say("some-poll-warning-2")) 654 655 Expect(executeErr).ToNot(HaveOccurred()) 656 }) 657 658 Context("when displaying the application info fails", func() { 659 BeforeEach(func() { 660 var expectedErr error 661 expectedErr = actionerror.ApplicationNotFoundError{Name: app} 662 fakeV3PushActor.GetApplicationSummaryByNameAndSpaceReturns(v3action.ApplicationSummary{}, v3action.Warnings{"display-warning-1", "display-warning-2"}, expectedErr) 663 }) 664 665 It("returns the error and prints warnings", func() { 666 Expect(executeErr).To(Equal(actionerror.ApplicationNotFoundError{Name: app})) 667 668 Expect(testUI.Out).To(Say(`Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.`)) 669 670 Expect(testUI.Err).To(Say("display-warning-1")) 671 Expect(testUI.Err).To(Say("display-warning-2")) 672 673 Expect(testUI.Out).ToNot(Say(`name:\s+some-app`)) 674 }) 675 }) 676 677 Context("when getting the application summary is successful", func() { 678 BeforeEach(func() { 679 summary := v3action.ApplicationSummary{ 680 Application: v3action.Application{ 681 Name: "some-app", 682 GUID: "some-app-guid", 683 State: "started", 684 }, 685 CurrentDroplet: v3action.Droplet{ 686 Stack: "cflinuxfs2", 687 Buildpacks: []v3action.Buildpack{ 688 { 689 Name: "ruby_buildpack", 690 DetectOutput: "some-detect-output", 691 }, 692 }, 693 }, 694 ProcessSummaries: []v3action.ProcessSummary{ 695 { 696 Process: v3action.Process{ 697 Type: "worker", 698 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 699 }, 700 InstanceDetails: []v3action.ProcessInstance{ 701 v3action.ProcessInstance{ 702 Index: 0, 703 State: constant.ProcessInstanceRunning, 704 MemoryUsage: 4000000, 705 DiskUsage: 4000000, 706 MemoryQuota: 67108864, 707 DiskQuota: 8000000, 708 Uptime: time.Now().Sub(time.Unix(1371859200, 0)), 709 }, 710 }, 711 }, 712 }, 713 } 714 715 fakeV3PushActor.GetApplicationSummaryByNameAndSpaceReturns(summary, v3action.Warnings{"display-warning-1", "display-warning-2"}, nil) 716 }) 717 718 Context("when getting the application routes fails", func() { 719 BeforeEach(func() { 720 fakeV2AppActor.GetApplicationRoutesReturns([]v2action.Route{}, 721 v2action.Warnings{"route-warning-1", "route-warning-2"}, errors.New("some-error")) 722 }) 723 724 It("displays all warnings and returns the error", func() { 725 Expect(executeErr).To(MatchError("some-error")) 726 727 Expect(testUI.Out).To(Say(`Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.`)) 728 729 Expect(testUI.Err).To(Say("display-warning-1")) 730 Expect(testUI.Err).To(Say("display-warning-2")) 731 Expect(testUI.Err).To(Say("route-warning-1")) 732 Expect(testUI.Err).To(Say("route-warning-2")) 733 734 Expect(testUI.Out).ToNot(Say(`name:\s+some-app`)) 735 }) 736 }) 737 738 Context("when getting the application routes is successful", func() { 739 BeforeEach(func() { 740 fakeV2AppActor.GetApplicationRoutesReturns([]v2action.Route{ 741 {Domain: v2action.Domain{Name: "some-other-domain"}}, { 742 Domain: v2action.Domain{Name: "some-domain"}}}, 743 v2action.Warnings{"route-warning-1", "route-warning-2"}, nil) 744 }) 745 746 It("prints the application summary and outputs warnings", func() { 747 Expect(executeErr).ToNot(HaveOccurred()) 748 749 Expect(testUI.Out).To(Say(`(?m)Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.\n\n`)) 750 Expect(testUI.Out).To(Say(`name:\s+some-app`)) 751 Expect(testUI.Out).To(Say(`requested state:\s+started`)) 752 Expect(testUI.Out).To(Say(`routes:\s+some-other-domain, some-domain`)) 753 Expect(testUI.Out).To(Say(`stack:\s+cflinuxfs2`)) 754 Expect(testUI.Out).To(Say(`(?m)buildpacks:\s+some-detect-output\n\n`)) 755 756 Expect(testUI.Out).To(Say(`type:\s+worker`)) 757 Expect(testUI.Out).To(Say(`instances:\s+1/1`)) 758 Expect(testUI.Out).To(Say(`memory usage:\s+64M`)) 759 Expect(testUI.Out).To(Say(`\s+state\s+since\s+cpu\s+memory\s+disk`)) 760 Expect(testUI.Out).To(Say(`#0\s+running\s+2013-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [AP]M\s+0.0%\s+3.8M of 64M\s+3.8M of 7.6M`)) 761 762 Expect(testUI.Err).To(Say("display-warning-1")) 763 Expect(testUI.Err).To(Say("display-warning-2")) 764 Expect(testUI.Err).To(Say("route-warning-1")) 765 Expect(testUI.Err).To(Say("route-warning-2")) 766 767 Expect(fakeV3PushActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 768 appName, spaceGUID, withObfuscatedValues := fakeV3PushActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 769 Expect(appName).To(Equal("some-app")) 770 Expect(spaceGUID).To(Equal("some-space-guid")) 771 772 Expect(fakeV2AppActor.GetApplicationRoutesCallCount()).To(Equal(1)) 773 Expect(fakeV2AppActor.GetApplicationRoutesArgsForCall(0)).To(Equal("some-app-guid")) 774 Expect(withObfuscatedValues).To(BeFalse()) 775 }) 776 }) 777 }) 778 }) 779 }) 780 781 }) 782 }) 783 }) 784 }) 785 }) 786 }) 787 788 Context("when looking up the application succeeds", func() { 789 BeforeEach(func() { 790 fakeZdtActor.GetApplicationByNameAndSpaceReturns(v3action.Application{ 791 Name: "some-app", 792 GUID: "some-app-guid", 793 State: constant.ApplicationStarted, 794 }, v3action.Warnings{"get-warning"}, nil) 795 }) 796 797 It("updates the application", func() { 798 Expect(fakeZdtActor.CreateApplicationInSpaceCallCount()).To(Equal(0)) 799 Expect(fakeZdtActor.UpdateApplicationCallCount()).To(Equal(1)) 800 }) 801 802 Context("when updating the application fails", func() { 803 BeforeEach(func() { 804 fakeZdtActor.UpdateApplicationReturns(v3action.Application{}, v3action.Warnings{"update-warning-1"}, errors.New("some-error")) 805 }) 806 807 It("returns the error and displays warnings", func() { 808 Expect(executeErr).To(MatchError("some-error")) 809 810 Expect(testUI.Err).To(Say("get-warning")) 811 Expect(testUI.Err).To(Say("update-warning")) 812 }) 813 }) 814 815 Context("when a docker image is provided", func() { 816 BeforeEach(func() { 817 cmd.DockerImage.Path = "example.com/docker/docker/docker:docker" 818 cmd.DockerUsername = "username" 819 fakeConfig.DockerPasswordReturns("password") 820 }) 821 822 Context("when a username/password are provided", func() { 823 It("updates the app with the provided credentials", func() { 824 appName, spaceGuid, dockerImageCredentials := fakeZdtActor.CreateDockerPackageByApplicationNameAndSpaceArgsForCall(0) 825 Expect(appName).To(Equal("some-app")) 826 Expect(spaceGuid).To(Equal("some-space-guid")) 827 Expect(dockerImageCredentials.Path).To(Equal(cmd.DockerImage.Path)) 828 Expect(dockerImageCredentials.Username).To(Equal("username")) 829 Expect(dockerImageCredentials.Password).To(Equal("password")) 830 }) 831 }) 832 833 It("updates the app with a docker lifecycle", func() { 834 Expect(fakeZdtActor.UpdateApplicationCallCount()).To(Equal(1), "Expected UpdateApplication to be called once") 835 updateApp := fakeZdtActor.UpdateApplicationArgsForCall(0) 836 Expect(updateApp).To(Equal(v3action.Application{ 837 GUID: "some-app-guid", 838 LifecycleType: constant.AppLifecycleTypeDocker, 839 })) 840 }) 841 }) 842 843 Context("when the app has a buildpack lifecycle", func() { 844 Context("when a buildpack was not provided", func() { 845 BeforeEach(func() { 846 cmd.Buildpacks = []string{} 847 }) 848 849 It("does not update the buildpack", func() { 850 appArg := fakeZdtActor.UpdateApplicationArgsForCall(0) 851 Expect(appArg).To(Equal(v3action.Application{ 852 GUID: "some-app-guid", 853 LifecycleType: constant.AppLifecycleTypeBuildpack, 854 LifecycleBuildpacks: []string{}, 855 })) 856 }) 857 }) 858 859 Context("when a buildpack was provided", func() { 860 BeforeEach(func() { 861 cmd.Buildpacks = []string{"some-buildpack"} 862 }) 863 864 It("updates the buildpack", func() { 865 appArg := fakeZdtActor.UpdateApplicationArgsForCall(0) 866 Expect(appArg).To(Equal(v3action.Application{ 867 GUID: "some-app-guid", 868 LifecycleType: constant.AppLifecycleTypeBuildpack, 869 LifecycleBuildpacks: []string{"some-buildpack"}, 870 })) 871 }) 872 }) 873 874 Context("when a stack was provided", func() { 875 BeforeEach(func() { 876 cmd.StackName = "cflinuxfs9000" 877 }) 878 879 It("updates the stack", func() { 880 appArg := fakeZdtActor.UpdateApplicationArgsForCall(0) 881 Expect(appArg).To(Equal(v3action.Application{ 882 GUID: "some-app-guid", 883 LifecycleType: constant.AppLifecycleTypeBuildpack, 884 StackName: "cflinuxfs9000", 885 })) 886 }) 887 }) 888 889 Context("when multiple buildpacks are provided", func() { 890 BeforeEach(func() { 891 cmd.Buildpacks = []string{"some-buildpack-1", "some-buildpack-2"} 892 }) 893 894 It("updates the buildpacks", func() { 895 appArg := fakeZdtActor.UpdateApplicationArgsForCall(0) 896 Expect(appArg).To(Equal(v3action.Application{ 897 GUID: "some-app-guid", 898 LifecycleType: constant.AppLifecycleTypeBuildpack, 899 LifecycleBuildpacks: []string{"some-buildpack-1", "some-buildpack-2"}, 900 })) 901 }) 902 903 Context("when default was also provided", func() { 904 BeforeEach(func() { 905 cmd.Buildpacks = []string{"default", "some-buildpack-2"} 906 }) 907 908 It("returns the ConflictingBuildpacksError", func() { 909 Expect(executeErr).To(Equal(translatableerror.ConflictingBuildpacksError{})) 910 Expect(fakeZdtActor.UpdateApplicationCallCount()).To(Equal(0)) 911 }) 912 }) 913 914 Context("when null was also provided", func() { 915 BeforeEach(func() { 916 cmd.Buildpacks = []string{"null", "some-buildpack-2"} 917 }) 918 919 It("returns the ConflictingBuildpacksError", func() { 920 Expect(executeErr).To(Equal(translatableerror.ConflictingBuildpacksError{})) 921 Expect(fakeZdtActor.UpdateApplicationCallCount()).To(Equal(0)) 922 }) 923 }) 924 }) 925 }) 926 927 Context("when updating the application succeeds", func() { 928 Context("when the application is stopped", func() { 929 BeforeEach(func() { 930 fakeZdtActor.UpdateApplicationReturns(v3action.Application{GUID: "some-app-guid", State: constant.ApplicationStopped}, v3action.Warnings{"update-warning"}, nil) 931 }) 932 933 It("sets the droplet and restarts the app", func() { 934 Expect(executeErr).ToNot(HaveOccurred()) 935 936 Expect(testUI.Err).To(Say("get-warning")) 937 Expect(testUI.Err).To(Say("update-warning")) 938 939 Expect(fakeZdtActor.RestartApplicationCallCount()).To(Equal(1)) 940 Expect(fakeZdtActor.SetApplicationDropletByApplicationNameAndSpaceCallCount()).To(Equal(1)) 941 Expect(fakeZdtActor.PollStartCallCount()).To(Equal(1)) 942 }) 943 944 Context("when the wait-for-deploy-complete flag is not provided", func() { 945 Context("when polling the start fails", func() { 946 BeforeEach(func() { 947 fakeZdtActor.PollStartStub = func(appGUID string, warnings chan<- v3action.Warnings) error { 948 warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"} 949 return errors.New("some-error") 950 } 951 }) 952 953 It("displays all warnings and fails", func() { 954 Expect(testUI.Out).To(Say(`Waiting for app to start\.\.\.`)) 955 956 Expect(testUI.Err).To(Say("some-poll-warning-1")) 957 Expect(testUI.Err).To(Say("some-poll-warning-2")) 958 959 Expect(executeErr).To(MatchError("some-error")) 960 }) 961 }) 962 963 Context("when polling times out", func() { 964 BeforeEach(func() { 965 fakeZdtActor.PollStartReturns(actionerror.StartupTimeoutError{}) 966 }) 967 968 It("returns the StartupTimeoutError", func() { 969 Expect(executeErr).To(MatchError(translatableerror.StartupTimeoutError{ 970 AppName: "some-app", 971 BinaryName: binaryName, 972 })) 973 }) 974 }) 975 976 Context("when polling the start succeeds", func() { 977 BeforeEach(func() { 978 fakeZdtActor.PollStartStub = func(appGUID string, warnings chan<- v3action.Warnings) error { 979 warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"} 980 return nil 981 } 982 }) 983 984 It("displays all warnings", func() { 985 Expect(testUI.Out).To(Say(`Waiting for app to start\.\.\.`)) 986 987 Expect(testUI.Err).To(Say("some-poll-warning-1")) 988 Expect(testUI.Err).To(Say("some-poll-warning-2")) 989 990 Expect(executeErr).ToNot(HaveOccurred()) 991 }) 992 993 Context("when displaying the application info fails", func() { 994 BeforeEach(func() { 995 var expectedErr error 996 expectedErr = actionerror.ApplicationNotFoundError{Name: app} 997 fakeV3PushActor.GetApplicationSummaryByNameAndSpaceReturns(v3action.ApplicationSummary{}, v3action.Warnings{"display-warning-1", "display-warning-2"}, expectedErr) 998 }) 999 1000 It("returns the error and prints warnings", func() { 1001 Expect(executeErr).To(Equal(actionerror.ApplicationNotFoundError{Name: app})) 1002 1003 Expect(testUI.Out).To(Say(`Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.`)) 1004 1005 Expect(testUI.Err).To(Say("display-warning-1")) 1006 Expect(testUI.Err).To(Say("display-warning-2")) 1007 1008 Expect(testUI.Out).ToNot(Say(`name:\s+some-app`)) 1009 }) 1010 }) 1011 1012 Context("when getting the application summary is successful", func() { 1013 BeforeEach(func() { 1014 summary := v3action.ApplicationSummary{ 1015 Application: v3action.Application{ 1016 Name: "some-app", 1017 GUID: "some-app-guid", 1018 State: "started", 1019 }, 1020 CurrentDroplet: v3action.Droplet{ 1021 Stack: "cflinuxfs2", 1022 Buildpacks: []v3action.Buildpack{ 1023 { 1024 Name: "ruby_buildpack", 1025 DetectOutput: "some-detect-output", 1026 }, 1027 }, 1028 }, 1029 ProcessSummaries: []v3action.ProcessSummary{ 1030 { 1031 Process: v3action.Process{ 1032 Type: "worker", 1033 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 1034 }, 1035 InstanceDetails: []v3action.ProcessInstance{ 1036 v3action.ProcessInstance{ 1037 Index: 0, 1038 State: constant.ProcessInstanceRunning, 1039 MemoryUsage: 4000000, 1040 DiskUsage: 4000000, 1041 MemoryQuota: 67108864, 1042 DiskQuota: 8000000, 1043 Uptime: time.Now().Sub(time.Unix(1371859200, 0)), 1044 }, 1045 }, 1046 }, 1047 }, 1048 } 1049 1050 fakeV3PushActor.GetApplicationSummaryByNameAndSpaceReturns(summary, v3action.Warnings{"display-warning-1", "display-warning-2"}, nil) 1051 }) 1052 1053 Context("when getting the application routes fails", func() { 1054 BeforeEach(func() { 1055 fakeV2AppActor.GetApplicationRoutesReturns([]v2action.Route{}, 1056 v2action.Warnings{"route-warning-1", "route-warning-2"}, errors.New("some-error")) 1057 }) 1058 1059 It("displays all warnings and returns the error", func() { 1060 Expect(executeErr).To(MatchError("some-error")) 1061 1062 Expect(testUI.Out).To(Say(`Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.`)) 1063 1064 Expect(testUI.Err).To(Say("display-warning-1")) 1065 Expect(testUI.Err).To(Say("display-warning-2")) 1066 Expect(testUI.Err).To(Say("route-warning-1")) 1067 Expect(testUI.Err).To(Say("route-warning-2")) 1068 1069 Expect(testUI.Out).ToNot(Say(`name:\s+some-app`)) 1070 }) 1071 }) 1072 1073 Context("when getting the application routes is successful", func() { 1074 BeforeEach(func() { 1075 fakeV2AppActor.GetApplicationRoutesReturns([]v2action.Route{ 1076 {Domain: v2action.Domain{Name: "some-other-domain"}}, { 1077 Domain: v2action.Domain{Name: "some-domain"}}}, 1078 v2action.Warnings{"route-warning-1", "route-warning-2"}, nil) 1079 }) 1080 1081 It("prints the application summary and outputs warnings", func() { 1082 Expect(executeErr).ToNot(HaveOccurred()) 1083 1084 Expect(testUI.Out).To(Say(`(?m)Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.\n\n`)) 1085 Expect(testUI.Out).To(Say(`name:\s+some-app`)) 1086 Expect(testUI.Out).To(Say(`requested state:\s+started`)) 1087 Expect(testUI.Out).To(Say(`routes:\s+some-other-domain, some-domain`)) 1088 Expect(testUI.Out).To(Say(`stack:\s+cflinuxfs2`)) 1089 Expect(testUI.Out).To(Say(`(?m)buildpacks:\s+some-detect-output\n\n`)) 1090 1091 Expect(testUI.Out).To(Say(`type:\s+worker`)) 1092 Expect(testUI.Out).To(Say(`instances:\s+1/1`)) 1093 Expect(testUI.Out).To(Say(`memory usage:\s+64M`)) 1094 Expect(testUI.Out).To(Say(`\s+state\s+since\s+cpu\s+memory\s+disk`)) 1095 Expect(testUI.Out).To(Say(`#0\s+running\s+2013-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [AP]M\s+0.0%\s+3.8M of 64M\s+3.8M of 7.6M`)) 1096 1097 Expect(testUI.Err).To(Say("display-warning-1")) 1098 Expect(testUI.Err).To(Say("display-warning-2")) 1099 Expect(testUI.Err).To(Say("route-warning-1")) 1100 Expect(testUI.Err).To(Say("route-warning-2")) 1101 1102 Expect(fakeV3PushActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 1103 appName, spaceGUID, withObfuscatedValues := fakeV3PushActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 1104 Expect(appName).To(Equal("some-app")) 1105 Expect(spaceGUID).To(Equal("some-space-guid")) 1106 1107 Expect(fakeV2AppActor.GetApplicationRoutesCallCount()).To(Equal(1)) 1108 Expect(fakeV2AppActor.GetApplicationRoutesArgsForCall(0)).To(Equal("some-app-guid")) 1109 Expect(withObfuscatedValues).To(BeFalse()) 1110 }) 1111 }) 1112 }) 1113 }) 1114 }) 1115 }) 1116 1117 Context("when the application is started", func() { 1118 BeforeEach(func() { 1119 fakeZdtActor.UpdateApplicationReturns(v3action.Application{GUID: "some-app-guid", State: constant.ApplicationStarted}, nil, nil) 1120 }) 1121 1122 It("creates a deployment", func() { 1123 Expect(executeErr).ToNot(HaveOccurred()) 1124 Expect(testUI.Out).To(Say("Starting deployment for app some-app in org some-org / space some-space as banana...")) 1125 1126 Expect(fakeZdtActor.RestartApplicationCallCount()).To(Equal(0)) 1127 Expect(fakeZdtActor.CreateDeploymentCallCount()).To(Equal(1)) 1128 }) 1129 1130 Context("when the wait-for-deploy-complete flag is not provided", func() { 1131 Context("when polling the start fails", func() { 1132 BeforeEach(func() { 1133 fakeZdtActor.ZeroDowntimePollStartStub = func(appGUID string, warnings chan<- v3action.Warnings) error { 1134 warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"} 1135 return errors.New("some-error") 1136 } 1137 }) 1138 1139 It("displays all warnings and fails", func() { 1140 Expect(testUI.Out).To(Say(`Waiting for app to start\.\.\.`)) 1141 1142 Expect(testUI.Err).To(Say("some-poll-warning-1")) 1143 Expect(testUI.Err).To(Say("some-poll-warning-2")) 1144 1145 Expect(executeErr).To(MatchError("some-error")) 1146 }) 1147 }) 1148 1149 Context("when polling times out", func() { 1150 BeforeEach(func() { 1151 fakeZdtActor.ZeroDowntimePollStartReturns(actionerror.StartupTimeoutError{}) 1152 }) 1153 1154 It("returns the StartupTimeoutError", func() { 1155 Expect(executeErr).To(MatchError(translatableerror.StartupTimeoutError{ 1156 AppName: "some-app", 1157 BinaryName: binaryName, 1158 })) 1159 }) 1160 }) 1161 1162 Context("when polling the start succeeds", func() { 1163 BeforeEach(func() { 1164 fakeZdtActor.ZeroDowntimePollStartStub = func(appGUID string, warnings chan<- v3action.Warnings) error { 1165 warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"} 1166 return nil 1167 } 1168 }) 1169 1170 It("displays all warnings", func() { 1171 Expect(testUI.Out).To(Say(`Waiting for app to start\.\.\.`)) 1172 1173 Expect(testUI.Err).To(Say("some-poll-warning-1")) 1174 Expect(testUI.Err).To(Say("some-poll-warning-2")) 1175 1176 Expect(executeErr).ToNot(HaveOccurred()) 1177 }) 1178 1179 Context("when displaying the application info fails", func() { 1180 BeforeEach(func() { 1181 var expectedErr error 1182 expectedErr = actionerror.ApplicationNotFoundError{Name: app} 1183 fakeV3PushActor.GetApplicationSummaryByNameAndSpaceReturns(v3action.ApplicationSummary{}, v3action.Warnings{"display-warning-1", "display-warning-2"}, expectedErr) 1184 }) 1185 1186 It("returns the error and prints warnings", func() { 1187 Expect(executeErr).To(Equal(actionerror.ApplicationNotFoundError{Name: app})) 1188 1189 Expect(testUI.Out).To(Say(`Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.`)) 1190 1191 Expect(testUI.Err).To(Say("display-warning-1")) 1192 Expect(testUI.Err).To(Say("display-warning-2")) 1193 1194 Expect(testUI.Out).ToNot(Say(`name:\s+some-app`)) 1195 }) 1196 }) 1197 1198 Context("when getting the application summary is successful", func() { 1199 BeforeEach(func() { 1200 summary := v3action.ApplicationSummary{ 1201 Application: v3action.Application{ 1202 Name: "some-app", 1203 GUID: "some-app-guid", 1204 State: "started", 1205 }, 1206 CurrentDroplet: v3action.Droplet{ 1207 Stack: "cflinuxfs2", 1208 Buildpacks: []v3action.Buildpack{ 1209 { 1210 Name: "ruby_buildpack", 1211 DetectOutput: "some-detect-output", 1212 }, 1213 }, 1214 }, 1215 ProcessSummaries: []v3action.ProcessSummary{ 1216 { 1217 Process: v3action.Process{ 1218 Type: "worker", 1219 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 1220 }, 1221 InstanceDetails: []v3action.ProcessInstance{ 1222 v3action.ProcessInstance{ 1223 Index: 0, 1224 State: constant.ProcessInstanceRunning, 1225 MemoryUsage: 4000000, 1226 DiskUsage: 4000000, 1227 MemoryQuota: 67108864, 1228 DiskQuota: 8000000, 1229 Uptime: time.Now().Sub(time.Unix(1371859200, 0)), 1230 }, 1231 }, 1232 }, 1233 }, 1234 } 1235 1236 fakeV3PushActor.GetApplicationSummaryByNameAndSpaceReturns(summary, v3action.Warnings{"display-warning-1", "display-warning-2"}, nil) 1237 }) 1238 1239 Context("when getting the application routes fails", func() { 1240 BeforeEach(func() { 1241 fakeV2AppActor.GetApplicationRoutesReturns([]v2action.Route{}, 1242 v2action.Warnings{"route-warning-1", "route-warning-2"}, errors.New("some-error")) 1243 }) 1244 1245 It("displays all warnings and returns the error", func() { 1246 Expect(executeErr).To(MatchError("some-error")) 1247 1248 Expect(testUI.Out).To(Say(`Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.`)) 1249 1250 Expect(testUI.Err).To(Say("display-warning-1")) 1251 Expect(testUI.Err).To(Say("display-warning-2")) 1252 Expect(testUI.Err).To(Say("route-warning-1")) 1253 Expect(testUI.Err).To(Say("route-warning-2")) 1254 1255 Expect(testUI.Out).ToNot(Say(`name:\s+some-app`)) 1256 }) 1257 }) 1258 1259 Context("when getting the application routes is successful", func() { 1260 BeforeEach(func() { 1261 fakeV2AppActor.GetApplicationRoutesReturns([]v2action.Route{ 1262 {Domain: v2action.Domain{Name: "some-other-domain"}}, { 1263 Domain: v2action.Domain{Name: "some-domain"}}}, 1264 v2action.Warnings{"route-warning-1", "route-warning-2"}, nil) 1265 }) 1266 1267 It("prints the application summary and outputs warnings", func() { 1268 Expect(executeErr).ToNot(HaveOccurred()) 1269 1270 Expect(testUI.Out).To(Say(`(?m)Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.\n\n`)) 1271 Expect(testUI.Out).To(Say(`name:\s+some-app`)) 1272 Expect(testUI.Out).To(Say(`requested state:\s+started`)) 1273 Expect(testUI.Out).To(Say(`routes:\s+some-other-domain, some-domain`)) 1274 Expect(testUI.Out).To(Say(`stack:\s+cflinuxfs2`)) 1275 Expect(testUI.Out).To(Say(`(?m)buildpacks:\s+some-detect-output\n\n`)) 1276 1277 Expect(testUI.Out).To(Say(`type:\s+worker`)) 1278 Expect(testUI.Out).To(Say(`instances:\s+1/1`)) 1279 Expect(testUI.Out).To(Say(`memory usage:\s+64M`)) 1280 Expect(testUI.Out).To(Say(`\s+state\s+since\s+cpu\s+memory\s+disk`)) 1281 Expect(testUI.Out).To(Say(`#0\s+running\s+2013-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [AP]M\s+0.0%\s+3.8M of 64M\s+3.8M of 7.6M`)) 1282 1283 Expect(testUI.Err).To(Say("display-warning-1")) 1284 Expect(testUI.Err).To(Say("display-warning-2")) 1285 Expect(testUI.Err).To(Say("route-warning-1")) 1286 Expect(testUI.Err).To(Say("route-warning-2")) 1287 1288 Expect(fakeV3PushActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 1289 appName, spaceGUID, withObfuscatedValues := fakeV3PushActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 1290 Expect(appName).To(Equal("some-app")) 1291 Expect(spaceGUID).To(Equal("some-space-guid")) 1292 1293 Expect(fakeV2AppActor.GetApplicationRoutesCallCount()).To(Equal(1)) 1294 Expect(fakeV2AppActor.GetApplicationRoutesArgsForCall(0)).To(Equal("some-app-guid")) 1295 Expect(withObfuscatedValues).To(BeFalse()) 1296 }) 1297 }) 1298 }) 1299 }) 1300 }) 1301 1302 Context("when the wait-for-deploy-complete is provided", func() { 1303 BeforeEach(func() { 1304 cmd.WaitUntilDeployed = true 1305 }) 1306 1307 Context("When polling the deployment fails", func() { 1308 BeforeEach(func() { 1309 fakeZdtActor.PollDeploymentStub = func(deploymentGUID string, warnings chan<- v3action.Warnings) error { 1310 warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"} 1311 return errors.New("some-polling-error") 1312 } 1313 }) 1314 1315 It("Displays all warnings and fails", func() { 1316 Expect(testUI.Out).To(Say(`Waiting for app to start\.\.\.`)) 1317 1318 Expect(testUI.Err).To(Say("some-poll-warning-1")) 1319 Expect(testUI.Err).To(Say("some-poll-warning-2")) 1320 1321 Expect(executeErr).To(MatchError("some-polling-error")) 1322 }) 1323 }) 1324 1325 Context("When polling the deployment timesout", func() { 1326 BeforeEach(func() { 1327 fakeZdtActor.PollDeploymentReturns(actionerror.StartupTimeoutError{}) 1328 }) 1329 1330 It("Returns the StartupTimeoutError", func() { 1331 Expect(executeErr).To(MatchError(translatableerror.StartupTimeoutError{ 1332 AppName: "some-app", 1333 BinaryName: binaryName, 1334 })) 1335 }) 1336 }) 1337 1338 Context("When polling the deployment succeeds", func() { 1339 BeforeEach(func() { 1340 fakeZdtActor.PollDeploymentStub = func(deploymentGUID string, warnings chan<- v3action.Warnings) error { 1341 warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"} 1342 return nil 1343 } 1344 }) 1345 1346 It("displays all warnings", func() { 1347 Expect(testUI.Out).To(Say(`Waiting for app to start\.\.\.`)) 1348 1349 Expect(testUI.Err).To(Say("some-poll-warning-1")) 1350 Expect(testUI.Err).To(Say("some-poll-warning-2")) 1351 1352 Expect(executeErr).ToNot(HaveOccurred()) 1353 }) 1354 1355 Context("when displaying the application info fails", func() { 1356 BeforeEach(func() { 1357 var expectedErr error 1358 expectedErr = actionerror.ApplicationNotFoundError{Name: app} 1359 fakeV3PushActor.GetApplicationSummaryByNameAndSpaceReturns(v3action.ApplicationSummary{}, v3action.Warnings{"display-warning-1", "display-warning-2"}, expectedErr) 1360 }) 1361 1362 It("returns the error and prints warnings", func() { 1363 Expect(executeErr).To(Equal(actionerror.ApplicationNotFoundError{Name: app})) 1364 1365 Expect(testUI.Out).To(Say(`Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.`)) 1366 1367 Expect(testUI.Err).To(Say("display-warning-1")) 1368 Expect(testUI.Err).To(Say("display-warning-2")) 1369 1370 Expect(testUI.Out).ToNot(Say(`name:\s+some-app`)) 1371 }) 1372 }) 1373 1374 Context("when getting the application summary is successful", func() { 1375 BeforeEach(func() { 1376 summary := v3action.ApplicationSummary{ 1377 Application: v3action.Application{ 1378 Name: "some-app", 1379 GUID: "some-app-guid", 1380 State: "started", 1381 }, 1382 CurrentDroplet: v3action.Droplet{ 1383 Stack: "cflinuxfs2", 1384 Buildpacks: []v3action.Buildpack{ 1385 { 1386 Name: "ruby_buildpack", 1387 DetectOutput: "some-detect-output", 1388 }, 1389 }, 1390 }, 1391 ProcessSummaries: []v3action.ProcessSummary{ 1392 { 1393 Process: v3action.Process{ 1394 Type: "worker", 1395 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 1396 }, 1397 InstanceDetails: []v3action.ProcessInstance{ 1398 v3action.ProcessInstance{ 1399 Index: 0, 1400 State: constant.ProcessInstanceRunning, 1401 MemoryUsage: 4000000, 1402 DiskUsage: 4000000, 1403 MemoryQuota: 67108864, 1404 DiskQuota: 8000000, 1405 Uptime: time.Now().Sub(time.Unix(1371859200, 0)), 1406 }, 1407 }, 1408 }, 1409 }, 1410 } 1411 1412 fakeV3PushActor.GetApplicationSummaryByNameAndSpaceReturns(summary, v3action.Warnings{"display-warning-1", "display-warning-2"}, nil) 1413 }) 1414 1415 Context("when getting the application routes fails", func() { 1416 BeforeEach(func() { 1417 fakeV2AppActor.GetApplicationRoutesReturns([]v2action.Route{}, 1418 v2action.Warnings{"route-warning-1", "route-warning-2"}, errors.New("some-error")) 1419 }) 1420 1421 It("displays all warnings and returns the error", func() { 1422 Expect(executeErr).To(MatchError("some-error")) 1423 1424 Expect(testUI.Out).To(Say(`Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.`)) 1425 1426 Expect(testUI.Err).To(Say("display-warning-1")) 1427 Expect(testUI.Err).To(Say("display-warning-2")) 1428 Expect(testUI.Err).To(Say("route-warning-1")) 1429 Expect(testUI.Err).To(Say("route-warning-2")) 1430 1431 Expect(testUI.Out).ToNot(Say(`name:\s+some-app`)) 1432 }) 1433 }) 1434 1435 Context("when getting the application routes is successful", func() { 1436 BeforeEach(func() { 1437 fakeV2AppActor.GetApplicationRoutesReturns([]v2action.Route{ 1438 {Domain: v2action.Domain{Name: "some-other-domain"}}, { 1439 Domain: v2action.Domain{Name: "some-domain"}}}, 1440 v2action.Warnings{"route-warning-1", "route-warning-2"}, nil) 1441 }) 1442 1443 It("prints the application summary and outputs warnings", func() { 1444 Expect(executeErr).ToNot(HaveOccurred()) 1445 1446 Expect(testUI.Out).To(Say(`(?m)Showing health and status for app some-app in org some-org / space some-space as banana\.\.\.\n\n`)) 1447 Expect(testUI.Out).To(Say(`name:\s+some-app`)) 1448 Expect(testUI.Out).To(Say(`requested state:\s+started`)) 1449 Expect(testUI.Out).To(Say(`routes:\s+some-other-domain, some-domain`)) 1450 Expect(testUI.Out).To(Say(`stack:\s+cflinuxfs2`)) 1451 Expect(testUI.Out).To(Say(`(?m)buildpacks:\s+some-detect-output\n\n`)) 1452 1453 Expect(testUI.Out).To(Say(`type:\s+worker`)) 1454 Expect(testUI.Out).To(Say(`instances:\s+1/1`)) 1455 Expect(testUI.Out).To(Say(`memory usage:\s+64M`)) 1456 Expect(testUI.Out).To(Say(`\s+state\s+since\s+cpu\s+memory\s+disk`)) 1457 Expect(testUI.Out).To(Say(`#0\s+running\s+2013-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [AP]M\s+0.0%\s+3.8M of 64M\s+3.8M of 7.6M`)) 1458 1459 Expect(testUI.Err).To(Say("display-warning-1")) 1460 Expect(testUI.Err).To(Say("display-warning-2")) 1461 Expect(testUI.Err).To(Say("route-warning-1")) 1462 Expect(testUI.Err).To(Say("route-warning-2")) 1463 1464 Expect(fakeV3PushActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 1465 appName, spaceGUID, withObfuscatedValues := fakeV3PushActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 1466 Expect(appName).To(Equal("some-app")) 1467 Expect(spaceGUID).To(Equal("some-space-guid")) 1468 1469 Expect(fakeV2AppActor.GetApplicationRoutesCallCount()).To(Equal(1)) 1470 Expect(fakeV2AppActor.GetApplicationRoutesArgsForCall(0)).To(Equal("some-app-guid")) 1471 Expect(withObfuscatedValues).To(BeFalse()) 1472 }) 1473 }) 1474 }) 1475 }) 1476 }) 1477 1478 Context("when no-start is provided", func() { 1479 BeforeEach(func() { 1480 cmd.NoStart = true 1481 }) 1482 1483 It("does nothing", func() { 1484 Expect(executeErr).ToNot(HaveOccurred()) 1485 1486 Expect(fakeZdtActor.RestartApplicationCallCount()).To(Equal(0)) 1487 Expect(fakeZdtActor.CreateDeploymentCallCount()).To(Equal(0)) 1488 }) 1489 }) 1490 }) 1491 }) 1492 }) 1493 }) 1494 })