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