github.com/cloudfoundry-attic/cli-with-i18n@v6.32.1-0.20171002233121-7401370d3b85+incompatible/command/v3/v3_push_command_test.go (about) 1 package v3_test 2 3 import ( 4 "errors" 5 "time" 6 7 "code.cloudfoundry.org/cli/actor/pushaction" 8 "code.cloudfoundry.org/cli/actor/sharedaction" 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/ccversion" 13 "code.cloudfoundry.org/cli/command/commandfakes" 14 "code.cloudfoundry.org/cli/command/flag" 15 "code.cloudfoundry.org/cli/command/translatableerror" 16 "code.cloudfoundry.org/cli/command/v3" 17 "code.cloudfoundry.org/cli/command/v3/shared" 18 "code.cloudfoundry.org/cli/command/v3/shared/sharedfakes" 19 "code.cloudfoundry.org/cli/command/v3/v3fakes" 20 "code.cloudfoundry.org/cli/types" 21 "code.cloudfoundry.org/cli/util/configv3" 22 "code.cloudfoundry.org/cli/util/ui" 23 . "github.com/onsi/ginkgo" 24 . "github.com/onsi/ginkgo/extensions/table" 25 . "github.com/onsi/gomega" 26 . "github.com/onsi/gomega/gbytes" 27 ) 28 29 var _ = Describe("v3-push Command", func() { 30 var ( 31 cmd v3.V3PushCommand 32 testUI *ui.UI 33 fakeConfig *commandfakes.FakeConfig 34 fakeSharedActor *commandfakes.FakeSharedActor 35 fakeNOAAClient *v3actionfakes.FakeNOAAClient 36 fakeActor *v3fakes.FakeV3PushActor 37 fakeV2PushActor *v3fakes.FakeV2PushActor 38 fakeV2AppActor *sharedfakes.FakeV2AppRouteActor 39 binaryName string 40 executeErr error 41 app string 42 userName string 43 spaceName string 44 orgName string 45 ) 46 47 BeforeEach(func() { 48 testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) 49 fakeConfig = new(commandfakes.FakeConfig) 50 fakeSharedActor = new(commandfakes.FakeSharedActor) 51 fakeActor = new(v3fakes.FakeV3PushActor) 52 fakeV2PushActor = new(v3fakes.FakeV2PushActor) 53 fakeV2AppActor = new(sharedfakes.FakeV2AppRouteActor) 54 fakeNOAAClient = new(v3actionfakes.FakeNOAAClient) 55 56 fakeConfig.StagingTimeoutReturns(10 * time.Minute) 57 58 binaryName = "faceman" 59 fakeConfig.BinaryNameReturns(binaryName) 60 app = "some-app" 61 userName = "banana" 62 spaceName = "some-space" 63 orgName = "some-org" 64 65 appSummaryDisplayer := shared.AppSummaryDisplayer{ 66 UI: testUI, 67 Config: fakeConfig, 68 Actor: fakeActor, 69 V2AppRouteActor: fakeV2AppActor, 70 AppName: app, 71 } 72 packageDisplayer := shared.NewPackageDisplayer( 73 testUI, 74 fakeConfig, 75 ) 76 77 cmd = v3.V3PushCommand{ 78 RequiredArgs: flag.AppName{AppName: app}, 79 80 UI: testUI, 81 Config: fakeConfig, 82 SharedActor: fakeSharedActor, 83 Actor: fakeActor, 84 V2PushActor: fakeV2PushActor, 85 86 NOAAClient: fakeNOAAClient, 87 AppSummaryDisplayer: appSummaryDisplayer, 88 PackageDisplayer: packageDisplayer, 89 } 90 fakeActor.CloudControllerAPIVersionReturns(ccversion.MinVersionV3) 91 92 // we stub out StagePackage out here so the happy paths below don't hang 93 fakeActor.StagePackageStub = func(_ string, _ string) (<-chan v3action.Droplet, <-chan v3action.Warnings, <-chan error) { 94 dropletStream := make(chan v3action.Droplet) 95 warningsStream := make(chan v3action.Warnings) 96 errorStream := make(chan error) 97 98 go func() { 99 defer close(dropletStream) 100 defer close(warningsStream) 101 defer close(errorStream) 102 }() 103 104 return dropletStream, warningsStream, errorStream 105 } 106 }) 107 108 JustBeforeEach(func() { 109 executeErr = cmd.Execute(nil) 110 }) 111 112 Context("when the API version is below the minimum", func() { 113 BeforeEach(func() { 114 fakeActor.CloudControllerAPIVersionReturns("0.0.0") 115 }) 116 117 It("returns a MinimumAPIVersionNotMetError", func() { 118 Expect(executeErr).To(MatchError(translatableerror.MinimumAPIVersionNotMetError{ 119 CurrentVersion: "0.0.0", 120 MinimumVersion: ccversion.MinVersionV3, 121 })) 122 }) 123 }) 124 125 DescribeTable("argument combinations", 126 func(dockerImage string, dockerUsername string, dockerPassword string, 127 buildpacks []string, appPath string, 128 expectedErr error) { 129 cmd.DockerImage.Path = dockerImage 130 cmd.DockerUsername = dockerUsername 131 fakeConfig.DockerPasswordReturns(dockerPassword) 132 cmd.Buildpacks = buildpacks 133 cmd.AppPath = flag.PathWithExistenceCheck(appPath) 134 Expect(cmd.Execute(nil)).To(MatchError(expectedErr)) 135 }, 136 Entry("docker username", 137 "", "some-docker-username", "", []string{}, "", 138 translatableerror.RequiredFlagsError{ 139 Arg1: "--docker-image, -o", 140 Arg2: "--docker-username", 141 }), 142 Entry("docker username, password", 143 "", "some-docker-username", "my-password", []string{}, "", 144 translatableerror.RequiredFlagsError{ 145 Arg1: "--docker-image, -o", 146 Arg2: "--docker-username", 147 }), 148 Entry("docker username, app path", 149 "", "some-docker-username", "", []string{}, "some/app/path", 150 translatableerror.RequiredFlagsError{ 151 Arg1: "--docker-image, -o", 152 Arg2: "--docker-username", 153 }), 154 Entry("docker username, buildpacks", 155 "", "some-docker-username", "", []string{"ruby_buildpack"}, "", 156 translatableerror.RequiredFlagsError{ 157 Arg1: "--docker-image, -o", 158 Arg2: "--docker-username", 159 }), 160 Entry("docker image, docker username", 161 "some-docker-image", "some-docker-username", "", []string{}, "", 162 translatableerror.DockerPasswordNotSetError{}), 163 Entry("docker image, app path", 164 "some-docker-image", "", "", []string{}, "some/app/path", 165 translatableerror.ArgumentCombinationError{ 166 Args: []string{"--docker-image", "-o", "-p"}, 167 }), 168 Entry("docker image, buildpacks", 169 "some-docker-image", "", "", []string{"ruby_buildpack"}, "", 170 translatableerror.ArgumentCombinationError{ 171 Args: []string{"-b", "--docker-image", "-o"}, 172 }), 173 ) 174 175 Context("when checking target fails", func() { 176 BeforeEach(func() { 177 fakeSharedActor.CheckTargetReturns(sharedaction.NotLoggedInError{BinaryName: binaryName}) 178 }) 179 180 It("returns an error", func() { 181 Expect(executeErr).To(MatchError(translatableerror.NotLoggedInError{BinaryName: binaryName})) 182 183 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 184 _, checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 185 Expect(checkTargetedOrg).To(BeTrue()) 186 Expect(checkTargetedSpace).To(BeTrue()) 187 }) 188 }) 189 190 Context("when the user is logged in", func() { 191 BeforeEach(func() { 192 fakeConfig.CurrentUserReturns(configv3.User{Name: userName}, nil) 193 fakeConfig.TargetedSpaceReturns(configv3.Space{Name: spaceName, GUID: "some-space-guid"}) 194 fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: orgName, GUID: "some-org-guid"}) 195 196 }) 197 198 Context("when looking up the application returns some api error", func() { 199 BeforeEach(func() { 200 fakeActor.GetApplicationByNameAndSpaceReturns(v3action.Application{}, v3action.Warnings{"get-warning"}, errors.New("some-error")) 201 }) 202 203 It("returns the error and displays all warnings", func() { 204 Expect(executeErr).To(MatchError("some-error")) 205 206 Expect(testUI.Err).To(Say("get-warning")) 207 }) 208 }) 209 210 Context("when looking up the application returns an application not found error", func() { 211 BeforeEach(func() { 212 fakeActor.GetApplicationByNameAndSpaceReturns(v3action.Application{}, v3action.Warnings{"get-warning"}, v3action.ApplicationNotFoundError{Name: "some-app"}) 213 }) 214 215 Context("when creating the application returns an error", func() { 216 var expectedErr error 217 218 BeforeEach(func() { 219 expectedErr = errors.New("I am an error") 220 fakeActor.CreateApplicationInSpaceReturns(v3action.Application{}, v3action.Warnings{"I am a warning", "I am also a warning"}, expectedErr) 221 }) 222 223 It("displays the warnings and error", func() { 224 Expect(executeErr).To(MatchError(expectedErr)) 225 226 Expect(testUI.Err).To(Say("I am a warning")) 227 Expect(testUI.Err).To(Say("I am also a warning")) 228 Expect(testUI.Out).ToNot(Say("app some-app in org some-org / space some-space as banana...")) 229 }) 230 }) 231 232 Context("when creating the application does not error", func() { 233 BeforeEach(func() { 234 fakeActor.CreateApplicationInSpaceReturns(v3action.Application{Name: "some-app", GUID: "some-app-guid"}, v3action.Warnings{"I am a warning", "I am also a warning"}, nil) 235 }) 236 237 It("calls CreateApplication", func() { 238 Expect(fakeActor.CreateApplicationInSpaceCallCount()).To(Equal(1), "Expected CreateApplicationInSpace to be called once") 239 createApp, createSpaceGUID := fakeActor.CreateApplicationInSpaceArgsForCall(0) 240 Expect(createApp).To(Equal(v3action.Application{ 241 Name: "some-app", 242 Lifecycle: v3action.AppLifecycle{ 243 Type: v3action.BuildpackAppLifecycleType, 244 }, 245 })) 246 Expect(createSpaceGUID).To(Equal("some-space-guid")) 247 }) 248 249 Context("when creating the package fails", func() { 250 var expectedErr error 251 252 BeforeEach(func() { 253 expectedErr = errors.New("I am an error") 254 fakeActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceReturns(v3action.Package{}, v3action.Warnings{"I am a package warning", "I am also a package warning"}, expectedErr) 255 }) 256 257 It("displays the header and error", func() { 258 Expect(executeErr).To(MatchError(expectedErr)) 259 260 Expect(testUI.Out).To(Say("Uploading and creating bits package for app some-app in org some-org / space some-space as banana...")) 261 262 Expect(testUI.Err).To(Say("I am a package warning")) 263 Expect(testUI.Err).To(Say("I am also a package warning")) 264 265 Expect(testUI.Out).ToNot(Say("Staging package for %s in org some-org / space some-space as banana...", app)) 266 }) 267 }) 268 269 Context("when creating the package succeeds", func() { 270 BeforeEach(func() { 271 fakeActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceReturns(v3action.Package{GUID: "some-guid"}, v3action.Warnings{"I am a package warning", "I am also a package warning"}, nil) 272 }) 273 274 Context("when the -p flag is provided", func() { 275 BeforeEach(func() { 276 cmd.AppPath = "some-app-path" 277 }) 278 279 It("creates the package with the provided path", func() { 280 Expect(testUI.Out).To(Say("Uploading and creating bits package for app %s in org %s / space %s as %s", app, orgName, spaceName, userName)) 281 Expect(testUI.Err).To(Say("I am a package warning")) 282 Expect(testUI.Err).To(Say("I am also a package warning")) 283 Expect(testUI.Out).To(Say("OK")) 284 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 285 286 Expect(fakeActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceCallCount()).To(Equal(1)) 287 _, _, appPath := fakeActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceArgsForCall(0) 288 289 Expect(appPath).To(Equal("some-app-path")) 290 }) 291 }) 292 293 Context("when the -o flag is provided", func() { 294 BeforeEach(func() { 295 cmd.DockerImage.Path = "example.com/docker/docker/docker:docker" 296 fakeActor.CreateDockerPackageByApplicationNameAndSpaceReturns(v3action.Package{GUID: "some-guid"}, v3action.Warnings{"I am a docker package warning", "I am also a docker package warning"}, nil) 297 }) 298 299 It("creates a docker package with the provided image path", func() { 300 301 Expect(testUI.Out).To(Say("Creating docker package for app %s in org %s / space %s as %s", app, orgName, spaceName, userName)) 302 Expect(testUI.Err).To(Say("I am a docker package warning")) 303 Expect(testUI.Err).To(Say("I am also a docker package warning")) 304 Expect(testUI.Out).To(Say("OK")) 305 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 306 307 Expect(fakeActor.CreateDockerPackageByApplicationNameAndSpaceCallCount()).To(Equal(1)) 308 _, _, dockerImageCredentials := fakeActor.CreateDockerPackageByApplicationNameAndSpaceArgsForCall(0) 309 310 Expect(dockerImageCredentials.Path).To(Equal("example.com/docker/docker/docker:docker")) 311 }) 312 }) 313 314 Context("when neither -p nor -o flags are provided", func() { 315 It("calls CreateAndUploadBitsPackageByApplicationNameAndSpace with empty string", func() { 316 Expect(testUI.Out).To(Say("Uploading and creating bits package for app %s in org %s / space %s as %s", app, orgName, spaceName, userName)) 317 318 Expect(fakeActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceCallCount()).To(Equal(1)) 319 _, _, appPath := fakeActor.CreateAndUploadBitsPackageByApplicationNameAndSpaceArgsForCall(0) 320 321 Expect(appPath).To(BeEmpty()) 322 }) 323 }) 324 325 Context("when getting streaming logs fails", func() { 326 var expectedErr error 327 BeforeEach(func() { 328 expectedErr = errors.New("something is wrong!") 329 fakeActor.GetStreamingLogsForApplicationByNameAndSpaceReturns(nil, nil, v3action.Warnings{"some-logging-warning", "some-other-logging-warning"}, expectedErr) 330 }) 331 332 It("returns the error and displays warnings", func() { 333 Expect(executeErr).To(Equal(expectedErr)) 334 335 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 336 337 Expect(testUI.Err).To(Say("some-logging-warning")) 338 Expect(testUI.Err).To(Say("some-other-logging-warning")) 339 340 }) 341 }) 342 343 Context("when the logging does not error", func() { 344 var allLogsWritten chan bool 345 346 BeforeEach(func() { 347 allLogsWritten = make(chan bool) 348 fakeActor.GetStreamingLogsForApplicationByNameAndSpaceStub = func(appName string, spaceGUID string, client v3action.NOAAClient) (<-chan *v3action.LogMessage, <-chan error, v3action.Warnings, error) { 349 logStream := make(chan *v3action.LogMessage) 350 errorStream := make(chan error) 351 352 go func() { 353 logStream <- v3action.NewLogMessage("Here are some staging logs!", 1, time.Now(), v3action.StagingLog, "sourceInstance") 354 logStream <- v3action.NewLogMessage("Here are some other staging logs!", 1, time.Now(), v3action.StagingLog, "sourceInstance") 355 logStream <- v3action.NewLogMessage("not from staging", 1, time.Now(), "potato", "sourceInstance") 356 allLogsWritten <- true 357 }() 358 359 return logStream, errorStream, v3action.Warnings{"steve for all I care"}, nil 360 } 361 }) 362 363 Context("when the staging returns an error", func() { 364 var expectedErr error 365 366 BeforeEach(func() { 367 expectedErr = errors.New("any gibberish") 368 fakeActor.StagePackageStub = func(packageGUID string, _ string) (<-chan v3action.Droplet, <-chan v3action.Warnings, <-chan error) { 369 dropletStream := make(chan v3action.Droplet) 370 warningsStream := make(chan v3action.Warnings) 371 errorStream := make(chan error) 372 373 go func() { 374 <-allLogsWritten 375 defer close(dropletStream) 376 defer close(warningsStream) 377 defer close(errorStream) 378 warningsStream <- v3action.Warnings{"some-staging-warning", "some-other-staging-warning"} 379 errorStream <- expectedErr 380 }() 381 382 return dropletStream, warningsStream, errorStream 383 } 384 }) 385 386 It("returns the error and displays warnings", func() { 387 Expect(executeErr).To(Equal(expectedErr)) 388 389 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 390 391 Expect(testUI.Err).To(Say("some-staging-warning")) 392 Expect(testUI.Err).To(Say("some-other-staging-warning")) 393 394 Expect(testUI.Out).ToNot(Say("Setting app some-app to droplet some-droplet-guid in org some-org / space some-space as banana...")) 395 }) 396 }) 397 398 Context("when the staging is successful", func() { 399 BeforeEach(func() { 400 fakeActor.StagePackageStub = func(packageGUID string, _ string) (<-chan v3action.Droplet, <-chan v3action.Warnings, <-chan error) { 401 dropletStream := make(chan v3action.Droplet) 402 warningsStream := make(chan v3action.Warnings) 403 errorStream := make(chan error) 404 405 go func() { 406 <-allLogsWritten 407 defer close(dropletStream) 408 defer close(warningsStream) 409 defer close(errorStream) 410 warningsStream <- v3action.Warnings{"some-staging-warning", "some-other-staging-warning"} 411 dropletStream <- v3action.Droplet{GUID: "some-droplet-guid"} 412 }() 413 414 return dropletStream, warningsStream, errorStream 415 } 416 }) 417 418 It("outputs the staging message and warnings", func() { 419 Expect(executeErr).ToNot(HaveOccurred()) 420 421 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 422 Expect(testUI.Out).To(Say("OK")) 423 424 Expect(testUI.Err).To(Say("some-staging-warning")) 425 Expect(testUI.Err).To(Say("some-other-staging-warning")) 426 }) 427 428 It("stages the package", func() { 429 Expect(executeErr).ToNot(HaveOccurred()) 430 Expect(fakeActor.StagePackageCallCount()).To(Equal(1)) 431 guidArg, _ := fakeActor.StagePackageArgsForCall(0) 432 Expect(guidArg).To(Equal("some-guid")) 433 }) 434 435 It("displays staging logs and their warnings", func() { 436 Expect(testUI.Out).To(Say("Here are some staging logs!")) 437 Expect(testUI.Out).To(Say("Here are some other staging logs!")) 438 Expect(testUI.Out).ToNot(Say("not from staging")) 439 440 Expect(testUI.Err).To(Say("steve for all I care")) 441 442 Expect(fakeActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(1)) 443 appName, spaceGUID, noaaClient := fakeActor.GetStreamingLogsForApplicationByNameAndSpaceArgsForCall(0) 444 Expect(appName).To(Equal(app)) 445 Expect(spaceGUID).To(Equal("some-space-guid")) 446 Expect(noaaClient).To(Equal(fakeNOAAClient)) 447 448 guidArg, _ := fakeActor.StagePackageArgsForCall(0) 449 Expect(guidArg).To(Equal("some-guid")) 450 }) 451 452 Context("when setting the droplet fails", func() { 453 BeforeEach(func() { 454 fakeActor.SetApplicationDropletReturns(v3action.Warnings{"droplet-warning-1", "droplet-warning-2"}, errors.New("some-error")) 455 }) 456 457 It("returns the error", func() { 458 Expect(executeErr).To(Equal(errors.New("some-error"))) 459 460 Expect(testUI.Out).To(Say("Setting app some-app to droplet some-droplet-guid in org some-org / space some-space as banana...")) 461 462 Expect(testUI.Err).To(Say("droplet-warning-1")) 463 Expect(testUI.Err).To(Say("droplet-warning-2")) 464 465 Expect(testUI.Out).ToNot(Say("Starting app some-app in org some-org / space some-space as banana\\.\\.\\.")) 466 }) 467 }) 468 469 Context("when setting the application droplet is successful", func() { 470 BeforeEach(func() { 471 fakeActor.SetApplicationDropletReturns(v3action.Warnings{"droplet-warning-1", "droplet-warning-2"}, nil) 472 }) 473 474 It("displays that the droplet was assigned", func() { 475 Expect(testUI.Out).To(Say("Staging package for app %s in org some-org / space some-space as banana...", app)) 476 Expect(testUI.Out).To(Say("OK")) 477 478 Expect(testUI.Out).ToNot(Say("Stopping .*")) 479 480 Expect(testUI.Out).To(Say("Setting app some-app to droplet some-droplet-guid in org some-org / space some-space as banana...")) 481 482 Expect(testUI.Err).To(Say("droplet-warning-1")) 483 Expect(testUI.Err).To(Say("droplet-warning-2")) 484 Expect(testUI.Out).To(Say("OK")) 485 486 Expect(fakeActor.SetApplicationDropletCallCount()).To(Equal(1)) 487 appName, spaceGUID, dropletGUID := fakeActor.SetApplicationDropletArgsForCall(0) 488 Expect(appName).To(Equal("some-app")) 489 Expect(spaceGUID).To(Equal("some-space-guid")) 490 Expect(dropletGUID).To(Equal("some-droplet-guid")) 491 }) 492 493 Context("when --no-route flag is set to true", func() { 494 BeforeEach(func() { 495 cmd.NoRoute = true 496 }) 497 498 It("does not create any routes", func() { 499 Expect(fakeV2PushActor.CreateAndBindApplicationRoutesCallCount()).To(Equal(0)) 500 501 Expect(fakeActor.StartApplicationCallCount()).To(Equal(1)) 502 }) 503 }) 504 505 Context("when buildpack(s) are provided via -b flag", func() { 506 BeforeEach(func() { 507 cmd.Buildpacks = []string{"some-buildpack"} 508 }) 509 510 It("creates the app with the specified buildpack and prints the buildpack name in the summary", func() { 511 Expect(fakeActor.CreateApplicationInSpaceCallCount()).To(Equal(1), "Expected CreateApplicationInSpace to be called once") 512 createApp, createSpaceGUID := fakeActor.CreateApplicationInSpaceArgsForCall(0) 513 Expect(createApp).To(Equal(v3action.Application{ 514 Name: "some-app", 515 Lifecycle: v3action.AppLifecycle{ 516 Type: v3action.BuildpackAppLifecycleType, 517 Data: v3action.AppLifecycleData{ 518 Buildpacks: []string{"some-buildpack"}, 519 }, 520 }, 521 })) 522 Expect(createSpaceGUID).To(Equal("some-space-guid")) 523 }) 524 }) 525 526 Context("when a docker image is specified", func() { 527 BeforeEach(func() { 528 cmd.DockerImage.Path = "example.com/docker/docker/docker:docker" 529 }) 530 531 It("creates the app with a docker lifecycle", func() { 532 Expect(fakeActor.CreateApplicationInSpaceCallCount()).To(Equal(1), "Expected CreateApplicationInSpace to be called once") 533 createApp, createSpaceGUID := fakeActor.CreateApplicationInSpaceArgsForCall(0) 534 Expect(createApp).To(Equal(v3action.Application{ 535 Name: "some-app", 536 Lifecycle: v3action.AppLifecycle{ 537 Type: v3action.DockerAppLifecycleType, 538 Data: v3action.AppLifecycleData{}, 539 }, 540 })) 541 Expect(createSpaceGUID).To(Equal("some-space-guid")) 542 }) 543 }) 544 545 Context("when mapping routes fails", func() { 546 BeforeEach(func() { 547 fakeV2PushActor.CreateAndBindApplicationRoutesReturns(pushaction.Warnings{"route-warning"}, errors.New("some-error")) 548 }) 549 550 It("returns the error", func() { 551 Expect(executeErr).To(MatchError("some-error")) 552 Expect(testUI.Out).To(Say("Mapping routes\\.\\.\\.")) 553 Expect(testUI.Err).To(Say("route-warning")) 554 555 Expect(fakeActor.StartApplicationCallCount()).To(Equal(0)) 556 }) 557 }) 558 559 Context("when mapping routes succeeds", func() { 560 BeforeEach(func() { 561 fakeV2PushActor.CreateAndBindApplicationRoutesReturns(pushaction.Warnings{"route-warning"}, nil) 562 }) 563 564 It("displays the header and OK", func() { 565 Expect(testUI.Out).To(Say("Mapping routes\\.\\.\\.")) 566 Expect(testUI.Out).To(Say("OK")) 567 568 Expect(testUI.Err).To(Say("route-warning")) 569 570 Expect(fakeV2PushActor.CreateAndBindApplicationRoutesCallCount()).To(Equal(1), "Expected CreateAndBindApplicationRoutes to be called") 571 orgArg, spaceArg, appArg := fakeV2PushActor.CreateAndBindApplicationRoutesArgsForCall(0) 572 Expect(orgArg).To(Equal("some-org-guid")) 573 Expect(spaceArg).To(Equal("some-space-guid")) 574 Expect(appArg).To(Equal(v2action.Application{Name: "some-app", GUID: "some-app-guid"})) 575 576 Expect(fakeActor.StartApplicationCallCount()).To(Equal(1)) 577 }) 578 579 Context("when starting the application fails", func() { 580 BeforeEach(func() { 581 fakeActor.StartApplicationReturns(v3action.Application{}, v3action.Warnings{"start-warning-1", "start-warning-2"}, errors.New("some-error")) 582 }) 583 584 It("says that the app failed to start", func() { 585 Expect(executeErr).To(Equal(errors.New("some-error"))) 586 Expect(testUI.Out).To(Say("Starting app some-app in org some-org / space some-space as banana\\.\\.\\.")) 587 588 Expect(testUI.Err).To(Say("start-warning-1")) 589 Expect(testUI.Err).To(Say("start-warning-2")) 590 591 Expect(testUI.Out).ToNot(Say("Showing health and status for app some-app in org some-org / space some-space as banana\\.\\.\\.")) 592 }) 593 }) 594 595 Context("when starting the application succeeds", func() { 596 BeforeEach(func() { 597 fakeActor.StartApplicationReturns(v3action.Application{GUID: "some-app-guid"}, v3action.Warnings{"start-warning-1", "start-warning-2"}, nil) 598 }) 599 600 It("says that the app was started and outputs warnings", func() { 601 Expect(testUI.Out).To(Say("Starting app some-app in org some-org / space some-space as banana\\.\\.\\.")) 602 603 Expect(testUI.Err).To(Say("start-warning-1")) 604 Expect(testUI.Err).To(Say("start-warning-2")) 605 Expect(testUI.Out).To(Say("OK")) 606 607 Expect(fakeActor.StartApplicationCallCount()).To(Equal(1)) 608 appGUID := fakeActor.StartApplicationArgsForCall(0) 609 Expect(appGUID).To(Equal("some-app-guid")) 610 }) 611 }) 612 613 Context("when polling the start fails", func() { 614 BeforeEach(func() { 615 fakeActor.PollStartStub = func(appGUID string, warnings chan<- v3action.Warnings) error { 616 warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"} 617 return errors.New("some-error") 618 } 619 }) 620 621 It("displays all warnings and fails", func() { 622 Expect(testUI.Out).To(Say("Waiting for app to start\\.\\.\\.")) 623 624 Expect(testUI.Err).To(Say("some-poll-warning-1")) 625 Expect(testUI.Err).To(Say("some-poll-warning-2")) 626 627 Expect(executeErr).To(MatchError("some-error")) 628 }) 629 }) 630 631 Context("when polling times out", func() { 632 BeforeEach(func() { 633 fakeActor.PollStartReturns(v3action.StartupTimeoutError{}) 634 }) 635 636 It("returns the StartupTimeoutError", func() { 637 Expect(executeErr).To(MatchError(translatableerror.StartupTimeoutError{ 638 AppName: "some-app", 639 BinaryName: binaryName, 640 })) 641 }) 642 }) 643 644 Context("when polling the start succeeds", func() { 645 BeforeEach(func() { 646 fakeActor.PollStartStub = func(appGUID string, warnings chan<- v3action.Warnings) error { 647 warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"} 648 return nil 649 } 650 }) 651 652 It("displays all warnings", func() { 653 Expect(testUI.Out).To(Say("Waiting for app to start\\.\\.\\.")) 654 655 Expect(testUI.Err).To(Say("some-poll-warning-1")) 656 Expect(testUI.Err).To(Say("some-poll-warning-2")) 657 658 Expect(executeErr).ToNot(HaveOccurred()) 659 }) 660 661 Context("when displaying the application info fails", func() { 662 BeforeEach(func() { 663 var expectedErr error 664 expectedErr = v3action.ApplicationNotFoundError{Name: app} 665 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(v3action.ApplicationSummary{}, v3action.Warnings{"display-warning-1", "display-warning-2"}, expectedErr) 666 }) 667 668 It("returns the error and prints warnings", func() { 669 Expect(executeErr).To(Equal(translatableerror.ApplicationNotFoundError{Name: app})) 670 671 Expect(testUI.Out).To(Say("Showing health and status for app some-app in org some-org / space some-space as banana\\.\\.\\.")) 672 673 Expect(testUI.Err).To(Say("display-warning-1")) 674 Expect(testUI.Err).To(Say("display-warning-2")) 675 676 Expect(testUI.Out).ToNot(Say("name:\\s+some-app")) 677 }) 678 }) 679 680 Context("when getting the application summary is successful", func() { 681 BeforeEach(func() { 682 summary := v3action.ApplicationSummary{ 683 Application: v3action.Application{ 684 Name: "some-app", 685 GUID: "some-app-guid", 686 State: "started", 687 }, 688 CurrentDroplet: v3action.Droplet{ 689 Stack: "cflinuxfs2", 690 Buildpacks: []v3action.Buildpack{ 691 { 692 Name: "ruby_buildpack", 693 DetectOutput: "some-detect-output", 694 }, 695 }, 696 }, 697 ProcessSummaries: []v3action.ProcessSummary{ 698 { 699 Process: v3action.Process{ 700 Type: "worker", 701 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 702 }, 703 InstanceDetails: []v3action.Instance{ 704 v3action.Instance{ 705 Index: 0, 706 State: "RUNNING", 707 MemoryUsage: 4000000, 708 DiskUsage: 4000000, 709 MemoryQuota: 67108864, 710 DiskQuota: 8000000, 711 Uptime: int(time.Now().Sub(time.Unix(1371859200, 0)).Seconds()), 712 }, 713 }, 714 }, 715 }, 716 } 717 718 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(summary, v3action.Warnings{"display-warning-1", "display-warning-2"}, nil) 719 }) 720 721 Context("when getting the application routes fails", func() { 722 BeforeEach(func() { 723 fakeV2AppActor.GetApplicationRoutesReturns([]v2action.Route{}, 724 v2action.Warnings{"route-warning-1", "route-warning-2"}, errors.New("some-error")) 725 }) 726 727 It("displays all warnings and returns the error", func() { 728 Expect(executeErr).To(MatchError("some-error")) 729 730 Expect(testUI.Out).To(Say("Showing health and status for app some-app in org some-org / space some-space as banana\\.\\.\\.")) 731 732 Expect(testUI.Err).To(Say("display-warning-1")) 733 Expect(testUI.Err).To(Say("display-warning-2")) 734 Expect(testUI.Err).To(Say("route-warning-1")) 735 Expect(testUI.Err).To(Say("route-warning-2")) 736 737 Expect(testUI.Out).ToNot(Say("name:\\s+some-app")) 738 }) 739 }) 740 741 Context("when getting the application routes is successful", func() { 742 BeforeEach(func() { 743 fakeV2AppActor.GetApplicationRoutesReturns([]v2action.Route{ 744 {Domain: v2action.Domain{Name: "some-other-domain"}}, { 745 Domain: v2action.Domain{Name: "some-domain"}}}, 746 v2action.Warnings{"route-warning-1", "route-warning-2"}, nil) 747 }) 748 749 It("prints the application summary and outputs warnings", func() { 750 Expect(executeErr).ToNot(HaveOccurred()) 751 752 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")) 753 Expect(testUI.Out).To(Say("name:\\s+some-app")) 754 Expect(testUI.Out).To(Say("requested state:\\s+started")) 755 Expect(testUI.Out).To(Say("processes:\\s+worker:1/1")) 756 Expect(testUI.Out).To(Say("memory usage:\\s+64M x 1")) 757 Expect(testUI.Out).To(Say("routes:\\s+some-other-domain, some-domain")) 758 Expect(testUI.Out).To(Say("stack:\\s+cflinuxfs2")) 759 Expect(testUI.Out).To(Say("(?m)buildpacks:\\s+some-detect-output\n\n")) 760 761 Expect(testUI.Out).To(Say("worker:1/1")) 762 Expect(testUI.Out).To(Say("\\s+state\\s+since\\s+cpu\\s+memory\\s+disk")) 763 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")) 764 765 Expect(testUI.Err).To(Say("display-warning-1")) 766 Expect(testUI.Err).To(Say("display-warning-2")) 767 Expect(testUI.Err).To(Say("route-warning-1")) 768 Expect(testUI.Err).To(Say("route-warning-2")) 769 770 Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 771 appName, spaceGUID := fakeActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 772 Expect(appName).To(Equal("some-app")) 773 Expect(spaceGUID).To(Equal("some-space-guid")) 774 775 Expect(fakeV2AppActor.GetApplicationRoutesCallCount()).To(Equal(1)) 776 Expect(fakeV2AppActor.GetApplicationRoutesArgsForCall(0)).To(Equal("some-app-guid")) 777 }) 778 }) 779 }) 780 }) 781 }) 782 }) 783 }) 784 }) 785 }) 786 }) 787 }) 788 789 Context("when looking up the application succeeds", func() { 790 BeforeEach(func() { 791 fakeActor.GetApplicationByNameAndSpaceReturns(v3action.Application{ 792 Name: "some-app", 793 GUID: "some-app-guid", 794 }, v3action.Warnings{"get-warning"}, nil) 795 }) 796 797 It("updates the application", func() { 798 Expect(fakeActor.CreateApplicationInSpaceCallCount()).To(Equal(0)) 799 Expect(fakeActor.UpdateApplicationCallCount()).To(Equal(1)) 800 }) 801 802 Context("when a docker image is provided", func() { 803 BeforeEach(func() { 804 cmd.DockerImage.Path = "example.com/docker/docker/docker:docker" 805 cmd.DockerUsername = "username" 806 fakeConfig.DockerPasswordReturns("password") 807 }) 808 809 Context("when a username/password are provided", func() { 810 It("updates the app with the provided credentials", func() { 811 appName, spaceGuid, dockerImageCredentials := fakeActor.CreateDockerPackageByApplicationNameAndSpaceArgsForCall(0) 812 Expect(appName).To(Equal("some-app")) 813 Expect(spaceGuid).To(Equal("some-space-guid")) 814 Expect(dockerImageCredentials.Path).To(Equal(cmd.DockerImage.Path)) 815 Expect(dockerImageCredentials.Username).To(Equal("username")) 816 Expect(dockerImageCredentials.Password).To(Equal("password")) 817 }) 818 }) 819 820 It("updates the app with a docker lifecycle", func() { 821 Expect(fakeActor.UpdateApplicationCallCount()).To(Equal(1), "Expected UpdateApplication to be called once") 822 updateApp := fakeActor.UpdateApplicationArgsForCall(0) 823 Expect(updateApp).To(Equal(v3action.Application{ 824 GUID: "some-app-guid", 825 Lifecycle: v3action.AppLifecycle{ 826 Type: v3action.DockerAppLifecycleType, 827 Data: v3action.AppLifecycleData{}, 828 }, 829 })) 830 }) 831 }) 832 Context("when updating the application fails", func() { 833 BeforeEach(func() { 834 fakeActor.UpdateApplicationReturns(v3action.Application{}, v3action.Warnings{"update-warning-1"}, errors.New("some-error")) 835 }) 836 837 It("returns the error and displays warnings", func() { 838 Expect(executeErr).To(MatchError("some-error")) 839 840 Expect(testUI.Err).To(Say("get-warning")) 841 Expect(testUI.Err).To(Say("update-warning")) 842 }) 843 }) 844 845 Context("when the app has a buildpack lifecycle", func() { 846 Context("when a buildpack was not provided", func() { 847 BeforeEach(func() { 848 cmd.Buildpacks = []string{} 849 }) 850 851 It("does not update the buildpack", func() { 852 appArg := fakeActor.UpdateApplicationArgsForCall(0) 853 Expect(appArg).To(Equal(v3action.Application{ 854 GUID: "some-app-guid", 855 Lifecycle: v3action.AppLifecycle{ 856 Type: v3action.BuildpackAppLifecycleType, 857 Data: v3action.AppLifecycleData{ 858 Buildpacks: []string{}, 859 }, 860 }, 861 })) 862 }) 863 }) 864 865 Context("when a buildpack was provided", func() { 866 BeforeEach(func() { 867 cmd.Buildpacks = []string{"some-buildpack"} 868 }) 869 870 It("updates the buildpack", func() { 871 appArg := fakeActor.UpdateApplicationArgsForCall(0) 872 Expect(appArg).To(Equal(v3action.Application{ 873 GUID: "some-app-guid", 874 Lifecycle: v3action.AppLifecycle{ 875 Type: v3action.BuildpackAppLifecycleType, 876 Data: v3action.AppLifecycleData{ 877 Buildpacks: []string{"some-buildpack"}, 878 }, 879 }, 880 })) 881 }) 882 }) 883 884 Context("when multiple buildpacks are provided", func() { 885 BeforeEach(func() { 886 cmd.Buildpacks = []string{"some-buildpack-1", "some-buildpack-2"} 887 }) 888 889 It("updates the buildpacks", func() { 890 appArg := fakeActor.UpdateApplicationArgsForCall(0) 891 Expect(appArg).To(Equal(v3action.Application{ 892 GUID: "some-app-guid", 893 Lifecycle: v3action.AppLifecycle{ 894 Type: v3action.BuildpackAppLifecycleType, 895 Data: v3action.AppLifecycleData{ 896 Buildpacks: []string{"some-buildpack-1", "some-buildpack-2"}, 897 }, 898 }, 899 })) 900 }) 901 902 Context("when default was also provided", func() { 903 BeforeEach(func() { 904 cmd.Buildpacks = []string{"default", "some-buildpack-2"} 905 }) 906 907 It("returns the ConflictingBuildpacksError", func() { 908 Expect(executeErr).To(Equal(translatableerror.ConflictingBuildpacksError{})) 909 Expect(fakeActor.UpdateApplicationCallCount()).To(Equal(0)) 910 }) 911 }) 912 913 Context("when null was also provided", func() { 914 BeforeEach(func() { 915 cmd.Buildpacks = []string{"null", "some-buildpack-2"} 916 }) 917 918 It("returns the ConflictingBuildpacksError", func() { 919 Expect(executeErr).To(Equal(translatableerror.ConflictingBuildpacksError{})) 920 Expect(fakeActor.UpdateApplicationCallCount()).To(Equal(0)) 921 }) 922 }) 923 }) 924 }) 925 926 Context("when updating the application succeeds", func() { 927 Context("when the application is stopped", func() { 928 BeforeEach(func() { 929 fakeActor.UpdateApplicationReturns(v3action.Application{GUID: "some-app-guid", State: "STOPPED"}, v3action.Warnings{"update-warning"}, nil) 930 }) 931 932 It("skips stopping the application and pushes it", func() { 933 Expect(executeErr).ToNot(HaveOccurred()) 934 935 Expect(testUI.Err).To(Say("get-warning")) 936 Expect(testUI.Err).To(Say("update-warning")) 937 938 Expect(testUI.Out).ToNot(Say("Stopping")) 939 940 Expect(fakeActor.StopApplicationCallCount()).To(Equal(0), "Expected StopApplication to not be called") 941 942 Expect(fakeActor.StartApplicationCallCount()).To(Equal(1), "Expected StartApplication to be called") 943 }) 944 }) 945 946 Context("when the application is started", func() { 947 BeforeEach(func() { 948 fakeActor.UpdateApplicationReturns(v3action.Application{GUID: "some-app-guid", State: "STARTED"}, nil, nil) 949 }) 950 951 It("stops the application and pushes it", func() { 952 Expect(executeErr).ToNot(HaveOccurred()) 953 Expect(testUI.Out).To(Say("Stopping app some-app in org some-org / space some-space as banana...")) 954 955 Expect(fakeActor.StopApplicationCallCount()).To(Equal(1)) 956 957 Expect(fakeActor.StartApplicationCallCount()).To(Equal(1), "Expected StartApplication to be called") 958 }) 959 }) 960 }) 961 }) 962 }) 963 })