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