github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/command/v6/v3_push_command_test.go (about)

     1  package v6_test
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	"code.cloudfoundry.org/cli/actor/actionerror"
     8  	"code.cloudfoundry.org/cli/actor/pushaction"
     9  	"code.cloudfoundry.org/cli/actor/v2action"
    10  	"code.cloudfoundry.org/cli/actor/v3action"
    11  	"code.cloudfoundry.org/cli/actor/v3action/v3actionfakes"
    12  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    13  	"code.cloudfoundry.org/cli/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.FakeV3PushActor
    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.FakeV3PushActor)
    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  			Actor:               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.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.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  })