github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+incompatible/command/v3/v3_push_original_command_test.go (about)

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