github.com/sleungcy/cli@v7.1.0+incompatible/command/v7/push_command_test.go (about)

     1  package v7_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"time"
     7  
     8  	"code.cloudfoundry.org/cli/actor/actionerror"
     9  	"code.cloudfoundry.org/cli/actor/sharedaction"
    10  	"code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes"
    11  	"code.cloudfoundry.org/cli/actor/v7action"
    12  	"code.cloudfoundry.org/cli/actor/v7pushaction"
    13  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    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/v7"
    18  	"code.cloudfoundry.org/cli/command/v7/v7fakes"
    19  	"code.cloudfoundry.org/cli/resources"
    20  	"code.cloudfoundry.org/cli/types"
    21  	"code.cloudfoundry.org/cli/util/configv3"
    22  	"code.cloudfoundry.org/cli/util/manifestparser"
    23  	"code.cloudfoundry.org/cli/util/ui"
    24  	"github.com/cloudfoundry/bosh-cli/director/template"
    25  	. "github.com/onsi/ginkgo"
    26  	. "github.com/onsi/ginkgo/extensions/table"
    27  	. "github.com/onsi/gomega"
    28  	. "github.com/onsi/gomega/gbytes"
    29  	"gopkg.in/yaml.v2"
    30  )
    31  
    32  type Step struct {
    33  	Plan     v7pushaction.PushPlan
    34  	Error    error
    35  	Event    v7pushaction.Event
    36  	Warnings v7pushaction.Warnings
    37  }
    38  
    39  func FillInEvents(steps []Step) <-chan *v7pushaction.PushEvent {
    40  	eventStream := make(chan *v7pushaction.PushEvent)
    41  
    42  	go func() {
    43  		defer close(eventStream)
    44  
    45  		for _, step := range steps {
    46  			eventStream <- &v7pushaction.PushEvent{Plan: step.Plan, Warnings: step.Warnings, Err: step.Error, Event: step.Event}
    47  		}
    48  	}()
    49  
    50  	return eventStream
    51  }
    52  
    53  type LogEvent struct {
    54  	Log   *sharedaction.LogMessage
    55  	Error error
    56  }
    57  
    58  func ReturnLogs(logevents []LogEvent, passedWarnings v7action.Warnings, passedError error) func(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error) {
    59  	return func(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error) {
    60  		logStream := make(chan sharedaction.LogMessage)
    61  		errStream := make(chan error)
    62  		go func() {
    63  			defer close(logStream)
    64  			defer close(errStream)
    65  
    66  			for _, log := range logevents {
    67  				if log.Log != nil {
    68  					logStream <- *log.Log
    69  				}
    70  				if log.Error != nil {
    71  					errStream <- log.Error
    72  				}
    73  			}
    74  		}()
    75  
    76  		return logStream, errStream, func() {}, passedWarnings, passedError
    77  	}
    78  }
    79  
    80  var _ = Describe("push Command", func() {
    81  	var (
    82  		cmd                 PushCommand
    83  		input               *Buffer
    84  		testUI              *ui.UI
    85  		fakeConfig          *commandfakes.FakeConfig
    86  		fakeSharedActor     *commandfakes.FakeSharedActor
    87  		fakeActor           *v7fakes.FakePushActor
    88  		fakeVersionActor    *v7fakes.FakeV7ActorForPush
    89  		fakeProgressBar     *v7fakes.FakeProgressBar
    90  		fakeLogCacheClient  *sharedactionfakes.FakeLogCacheClient
    91  		fakeManifestLocator *v7fakes.FakeManifestLocator
    92  		fakeManifestParser  *v7fakes.FakeManifestParser
    93  		binaryName          string
    94  		executeErr          error
    95  
    96  		appName1  string
    97  		appName2  string
    98  		userName  string
    99  		spaceName string
   100  		orgName   string
   101  		pwd       string
   102  	)
   103  
   104  	BeforeEach(func() {
   105  		input = NewBuffer()
   106  		testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer())
   107  		fakeConfig = new(commandfakes.FakeConfig)
   108  		fakeSharedActor = new(commandfakes.FakeSharedActor)
   109  		fakeActor = new(v7fakes.FakePushActor)
   110  		fakeVersionActor = new(v7fakes.FakeV7ActorForPush)
   111  		fakeProgressBar = new(v7fakes.FakeProgressBar)
   112  		fakeLogCacheClient = new(sharedactionfakes.FakeLogCacheClient)
   113  
   114  		appName1 = "first-app"
   115  		appName2 = "second-app"
   116  		userName = "some-user"
   117  		spaceName = "some-space"
   118  		orgName = "some-org"
   119  		pwd = "/push/cmd/test"
   120  		fakeManifestLocator = new(v7fakes.FakeManifestLocator)
   121  		fakeManifestParser = new(v7fakes.FakeManifestParser)
   122  
   123  		binaryName = "faceman"
   124  		fakeConfig.BinaryNameReturns(binaryName)
   125  
   126  		cmd = PushCommand{
   127  			BaseCommand: BaseCommand{
   128  				SharedActor: fakeSharedActor,
   129  				UI:          testUI,
   130  				Config:      fakeConfig,
   131  			},
   132  			PushActor:       fakeActor,
   133  			VersionActor:    fakeVersionActor,
   134  			ProgressBar:     fakeProgressBar,
   135  			LogCacheClient:  fakeLogCacheClient,
   136  			CWD:             pwd,
   137  			ManifestLocator: fakeManifestLocator,
   138  			ManifestParser:  fakeManifestParser,
   139  		}
   140  	})
   141  
   142  	Describe("Execute", func() {
   143  		JustBeforeEach(func() {
   144  			executeErr = cmd.Execute(nil)
   145  		})
   146  
   147  		BeforeEach(func() {
   148  			fakeActor.ActualizeStub = func(v7pushaction.PushPlan, v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent {
   149  				return FillInEvents([]Step{})
   150  			}
   151  		})
   152  
   153  		When("checking target fails", func() {
   154  			BeforeEach(func() {
   155  				fakeSharedActor.CheckTargetReturns(actionerror.NoOrganizationTargetedError{BinaryName: binaryName})
   156  			})
   157  
   158  			It("returns an error", func() {
   159  				Expect(executeErr).To(MatchError(actionerror.NoOrganizationTargetedError{BinaryName: binaryName}))
   160  
   161  				Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1))
   162  				checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0)
   163  				Expect(checkTargetedOrg).To(BeTrue())
   164  				Expect(checkTargetedSpace).To(BeTrue())
   165  			})
   166  		})
   167  
   168  		When("checking target fails because the user is not logged in", func() {
   169  			BeforeEach(func() {
   170  				fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName})
   171  			})
   172  
   173  			It("returns an error", func() {
   174  				Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: binaryName}))
   175  
   176  				Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1))
   177  				checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0)
   178  				Expect(checkTargetedOrg).To(BeTrue())
   179  				Expect(checkTargetedSpace).To(BeTrue())
   180  			})
   181  		})
   182  
   183  		When("the user is logged in, and org and space are targeted", func() {
   184  			BeforeEach(func() {
   185  				fakeConfig.CurrentUserReturns(configv3.User{Name: userName}, nil)
   186  
   187  				fakeConfig.TargetedOrganizationReturns(configv3.Organization{
   188  					Name: orgName,
   189  					GUID: "some-org-guid",
   190  				})
   191  				fakeConfig.TargetedSpaceReturns(configv3.Space{
   192  					Name: spaceName,
   193  					GUID: "some-space-guid",
   194  				})
   195  			})
   196  
   197  			When("invalid flags are passed", func() {
   198  				BeforeEach(func() {
   199  					cmd.DockerUsername = "some-docker-username"
   200  				})
   201  
   202  				It("returns a validation error", func() {
   203  					Expect(executeErr).To(MatchError(translatableerror.RequiredFlagsError{Arg1: "--docker-image, -o", Arg2: "--docker-username"}))
   204  				})
   205  			})
   206  
   207  			When("the flags are all valid", func() {
   208  				It("delegating to the GetBaseManifest", func() {
   209  					// This tells us GetBaseManifest is being called because we dont have a fake
   210  					Expect(fakeManifestLocator.PathCallCount()).To(Equal(1))
   211  				})
   212  
   213  				When("getting the base manifest fails", func() {
   214  					BeforeEach(func() {
   215  						fakeManifestLocator.PathReturns("", false, errors.New("locate-error"))
   216  					})
   217  
   218  					It("returns the error", func() {
   219  						Expect(executeErr).To(MatchError(errors.New("locate-error")))
   220  					})
   221  				})
   222  
   223  				When("getting the base manifest succeeds", func() {
   224  					BeforeEach(func() {
   225  						// essentially fakes GetBaseManifest
   226  						fakeManifestLocator.PathReturns("", true, nil)
   227  						fakeManifestParser.InterpolateAndParseReturns(
   228  							manifestparser.Manifest{
   229  								Applications: []manifestparser.Application{
   230  									{
   231  										Name: "some-app-name",
   232  									},
   233  								},
   234  							},
   235  							nil,
   236  						)
   237  					})
   238  
   239  					It("delegates to the flag override handler", func() {
   240  						Expect(fakeActor.HandleFlagOverridesCallCount()).To(Equal(1))
   241  						actualManifest, actualFlagOverrides := fakeActor.HandleFlagOverridesArgsForCall(0)
   242  						Expect(actualManifest).To(Equal(
   243  							manifestparser.Manifest{
   244  								Applications: []manifestparser.Application{
   245  									{Name: "some-app-name"},
   246  								},
   247  							},
   248  						))
   249  						Expect(actualFlagOverrides).To(Equal(v7pushaction.FlagOverrides{}))
   250  					})
   251  
   252  					When("handling the flag overrides fails", func() {
   253  						BeforeEach(func() {
   254  							fakeActor.HandleFlagOverridesReturns(manifestparser.Manifest{}, errors.New("override-handler-error"))
   255  						})
   256  
   257  						It("returns the error", func() {
   258  							Expect(executeErr).To(MatchError("override-handler-error"))
   259  						})
   260  					})
   261  
   262  					When("handling the flag overrides succeeds", func() {
   263  						BeforeEach(func() {
   264  							fakeActor.HandleFlagOverridesReturns(
   265  								manifestparser.Manifest{
   266  									Applications: []manifestparser.Application{
   267  										{Name: "some-app-name"},
   268  									},
   269  								},
   270  								nil,
   271  							)
   272  						})
   273  
   274  						When("the docker password is needed", func() {
   275  							// TODO remove this in favor of a fake manifest
   276  							BeforeEach(func() {
   277  								fakeActor.HandleFlagOverridesReturns(
   278  									manifestparser.Manifest{
   279  										Applications: []manifestparser.Application{
   280  											{
   281  												Name:   "some-app-name",
   282  												Docker: &manifestparser.Docker{Username: "username", Image: "image"},
   283  											},
   284  										},
   285  									},
   286  									nil,
   287  								)
   288  							})
   289  
   290  							It("delegates to the GetDockerPassword", func() {
   291  								Expect(fakeConfig.DockerPasswordCallCount()).To(Equal(1))
   292  							})
   293  						})
   294  
   295  						It("delegates to the manifest parser", func() {
   296  							Expect(fakeManifestParser.MarshalManifestCallCount()).To(Equal(1))
   297  							Expect(fakeManifestParser.MarshalManifestArgsForCall(0)).To(Equal(
   298  								manifestparser.Manifest{
   299  									Applications: []manifestparser.Application{
   300  										{Name: "some-app-name"},
   301  									},
   302  								},
   303  							))
   304  						})
   305  
   306  						When("marshalling the manifest fails", func() {
   307  							BeforeEach(func() {
   308  								fakeManifestParser.MarshalManifestReturns([]byte{}, errors.New("marshal error"))
   309  							})
   310  
   311  							It("returns the error", func() {
   312  								Expect(executeErr).To(MatchError("marshal error"))
   313  							})
   314  						})
   315  
   316  						When("marsahlling the manifest succeeds", func() {
   317  							BeforeEach(func() {
   318  								fakeManifestParser.MarshalManifestReturns([]byte("our-manifest"), nil)
   319  							})
   320  
   321  							It("delegates to the version actor", func() {
   322  								Expect(fakeVersionActor.SetSpaceManifestCallCount()).To(Equal(1))
   323  								actualSpaceGUID, actualManifestBytes := fakeVersionActor.SetSpaceManifestArgsForCall(0)
   324  								Expect(actualSpaceGUID).To(Equal("some-space-guid"))
   325  								Expect(actualManifestBytes).To(Equal([]byte("our-manifest")))
   326  							})
   327  
   328  							When("applying the manifest fails", func() {
   329  								BeforeEach(func() {
   330  									fakeVersionActor.SetSpaceManifestReturns(v7action.Warnings{"apply-manifest-warnings"}, errors.New("apply-manifest-error"))
   331  								})
   332  
   333  								It("returns an error and prints warnings", func() {
   334  									Expect(executeErr).To(MatchError("apply-manifest-error"))
   335  									Expect(testUI.Err).To(Say("apply-manifest-warnings"))
   336  								})
   337  
   338  							})
   339  
   340  							When("applying the manifest succeeds", func() {
   341  								BeforeEach(func() {
   342  									fakeVersionActor.SetSpaceManifestReturns(v7action.Warnings{"apply-manifest-warnings"}, nil)
   343  								})
   344  
   345  								It("delegates to the push actor", func() {
   346  									Expect(fakeActor.CreatePushPlansCallCount()).To(Equal(1))
   347  									spaceGUID, orgGUID, manifest, overrides := fakeActor.CreatePushPlansArgsForCall(0)
   348  									Expect(spaceGUID).To(Equal("some-space-guid"))
   349  									Expect(orgGUID).To(Equal("some-org-guid"))
   350  									Expect(manifest).To(Equal(
   351  										manifestparser.Manifest{
   352  											Applications: []manifestparser.Application{
   353  												{Name: "some-app-name"},
   354  											},
   355  										},
   356  									))
   357  									Expect(overrides).To(Equal(v7pushaction.FlagOverrides{}))
   358  								})
   359  
   360  								When("creating the push plans fails", func() {
   361  									BeforeEach(func() {
   362  										fakeActor.CreatePushPlansReturns(
   363  											nil,
   364  											v7action.Warnings{"create-push-plans-warnings"},
   365  											errors.New("create-push-plans-error"),
   366  										)
   367  									})
   368  
   369  									It("returns errors and warnings", func() {
   370  										Expect(executeErr).To(MatchError("create-push-plans-error"))
   371  										Expect(testUI.Err).To(Say("create-push-plans-warnings"))
   372  									})
   373  
   374  								})
   375  
   376  								When("creating the push plans succeeds", func() {
   377  									BeforeEach(func() {
   378  										fakeActor.CreatePushPlansReturns(
   379  											[]v7pushaction.PushPlan{
   380  												v7pushaction.PushPlan{Application: resources.Application{Name: "first-app", GUID: "potato"}},
   381  												v7pushaction.PushPlan{Application: resources.Application{Name: "second-app", GUID: "potato"}},
   382  											},
   383  											v7action.Warnings{"create-push-plans-warnings"},
   384  											nil,
   385  										)
   386  									})
   387  
   388  									It("it displays the warnings from create push plans", func() {
   389  										Expect(testUI.Err).To(Say("create-push-plans-warnings"))
   390  									})
   391  
   392  									Describe("delegating to Actor.Actualize", func() {
   393  										When("Actualize returns success", func() {
   394  											BeforeEach(func() {
   395  												fakeActor.ActualizeStub = func(v7pushaction.PushPlan, v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent {
   396  													return FillInEvents([]Step{
   397  														{Plan: v7pushaction.PushPlan{Application: resources.Application{GUID: "potato"}}},
   398  													})
   399  												}
   400  											})
   401  
   402  											Describe("actualize events", func() {
   403  												BeforeEach(func() {
   404  													fakeActor.ActualizeStub = func(pushPlan v7pushaction.PushPlan, _ v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent {
   405  														return FillInEvents([]Step{
   406  															{
   407  																Plan:  v7pushaction.PushPlan{Application: resources.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}},
   408  																Event: v7pushaction.CreatingArchive,
   409  															},
   410  															{
   411  																Plan:     v7pushaction.PushPlan{Application: resources.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}},
   412  																Event:    v7pushaction.UploadingApplicationWithArchive,
   413  																Warnings: v7pushaction.Warnings{"upload app archive warning"},
   414  															},
   415  															{
   416  																Plan:     v7pushaction.PushPlan{Application: resources.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}},
   417  																Event:    v7pushaction.RetryUpload,
   418  																Warnings: v7pushaction.Warnings{"retry upload warning"},
   419  															},
   420  															{
   421  																Plan:  v7pushaction.PushPlan{Application: resources.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}},
   422  																Event: v7pushaction.UploadWithArchiveComplete,
   423  															},
   424  															{
   425  																Plan:  v7pushaction.PushPlan{Application: resources.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}},
   426  																Event: v7pushaction.RestartingApplication,
   427  															},
   428  															{
   429  																Plan:  v7pushaction.PushPlan{Application: resources.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}},
   430  																Event: v7pushaction.StartingDeployment,
   431  															},
   432  															{
   433  																Plan:  v7pushaction.PushPlan{Application: resources.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}},
   434  																Event: v7pushaction.WaitingForDeployment,
   435  															},
   436  														})
   437  													}
   438  												})
   439  
   440  												It("actualizes the application and displays events/warnings", func() {
   441  													Expect(executeErr).ToNot(HaveOccurred())
   442  
   443  													Expect(fakeProgressBar.ReadyCallCount()).Should(Equal(2))
   444  													Expect(fakeProgressBar.CompleteCallCount()).Should(Equal(2))
   445  
   446  													Expect(testUI.Out).To(Say("Packaging files to upload..."))
   447  
   448  													Expect(testUI.Out).To(Say("Uploading files..."))
   449  													Expect(testUI.Err).To(Say("upload app archive warning"))
   450  
   451  													Expect(testUI.Out).To(Say("Retrying upload due to an error..."))
   452  													Expect(testUI.Err).To(Say("retry upload warning"))
   453  
   454  													Expect(testUI.Out).To(Say("Waiting for API to complete processing files..."))
   455  
   456  													Expect(testUI.Out).To(Say("Waiting for app first-app to start..."))
   457  
   458  													Expect(testUI.Out).To(Say("Packaging files to upload..."))
   459  
   460  													Expect(testUI.Out).To(Say("Uploading files..."))
   461  													Expect(testUI.Err).To(Say("upload app archive warning"))
   462  
   463  													Expect(testUI.Out).To(Say("Retrying upload due to an error..."))
   464  													Expect(testUI.Err).To(Say("retry upload warning"))
   465  
   466  													Expect(testUI.Out).To(Say("Waiting for API to complete processing files..."))
   467  
   468  													Expect(testUI.Out).To(Say("Waiting for app second-app to start..."))
   469  
   470  													Expect(testUI.Out).To(Say("Starting deployment for app second-app..."))
   471  
   472  													Expect(testUI.Out).To(Say("Waiting for app to deploy..."))
   473  												})
   474  											})
   475  
   476  											Describe("staging logs", func() {
   477  												BeforeEach(func() {
   478  													fakeActor.ActualizeStub = func(pushPlan v7pushaction.PushPlan, _ v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent {
   479  														return FillInEvents([]Step{
   480  															{Plan: pushPlan, Event: v7pushaction.StartingStaging},
   481  														})
   482  													}
   483  												})
   484  
   485  												When("there are no logging errors", func() {
   486  													BeforeEach(func() {
   487  														fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceStub = ReturnLogs(
   488  															[]LogEvent{
   489  																{Log: sharedaction.NewLogMessage("log-message-1", "OUT", time.Now(), sharedaction.StagingLog, "source-instance")},
   490  																{Log: sharedaction.NewLogMessage("log-message-2", "OUT", time.Now(), sharedaction.StagingLog, "source-instance")},
   491  																{Log: sharedaction.NewLogMessage("log-message-3", "OUT", time.Now(), "potato", "source-instance")},
   492  															},
   493  															v7action.Warnings{"log-warning-1", "log-warning-2"},
   494  															nil,
   495  														)
   496  													})
   497  
   498  													It("displays the staging logs and warnings", func() {
   499  														Expect(testUI.Out).To(Say("Staging app and tracing logs..."))
   500  
   501  														Expect(testUI.Err).To(Say("log-warning-1"))
   502  														Expect(testUI.Err).To(Say("log-warning-2"))
   503  
   504  														Eventually(testUI.Out).Should(Say("log-message-1"))
   505  														Eventually(testUI.Out).Should(Say("log-message-2"))
   506  														Eventually(testUI.Out).ShouldNot(Say("log-message-3"))
   507  
   508  														Expect(fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(2))
   509  														passedAppName, spaceGUID, _ := fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceArgsForCall(0)
   510  														Expect(passedAppName).To(Equal(appName1))
   511  														Expect(spaceGUID).To(Equal("some-space-guid"))
   512  														passedAppName, spaceGUID, _ = fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceArgsForCall(1)
   513  														Expect(passedAppName).To(Equal(appName2))
   514  														Expect(spaceGUID).To(Equal("some-space-guid"))
   515  
   516  													})
   517  												})
   518  
   519  												When("there are logging errors", func() {
   520  													BeforeEach(func() {
   521  														fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceStub = ReturnLogs(
   522  															[]LogEvent{
   523  																{Error: errors.New("some-random-err")},
   524  																{Error: actionerror.LogCacheTimeoutError{}},
   525  																{Log: sharedaction.NewLogMessage("log-message-1", "OUT", time.Now(), sharedaction.StagingLog, "source-instance")},
   526  															},
   527  															v7action.Warnings{"log-warning-1", "log-warning-2"},
   528  															nil,
   529  														)
   530  													})
   531  
   532  													It("displays the errors as warnings", func() {
   533  														Expect(testUI.Out).To(Say("Staging app and tracing logs..."))
   534  
   535  														Expect(testUI.Err).To(Say("log-warning-1"))
   536  														Expect(testUI.Err).To(Say("log-warning-2"))
   537  														Eventually(testUI.Err).Should(Say("Failed to retrieve logs from Log Cache: some-random-err"))
   538  														Eventually(testUI.Err).Should(Say("timeout connecting to log server, no log will be shown"))
   539  
   540  														Eventually(testUI.Out).Should(Say("log-message-1"))
   541  													})
   542  												})
   543  											})
   544  
   545  											When("when getting the application summary succeeds", func() {
   546  												BeforeEach(func() {
   547  													summary := v7action.DetailedApplicationSummary{
   548  														ApplicationSummary: v7action.ApplicationSummary{
   549  															Application:      resources.Application{},
   550  															ProcessSummaries: v7action.ProcessSummaries{},
   551  														},
   552  														CurrentDroplet: resources.Droplet{},
   553  													}
   554  													fakeVersionActor.GetDetailedAppSummaryReturnsOnCall(0, summary, v7action.Warnings{"app-1-summary-warning-1", "app-1-summary-warning-2"}, nil)
   555  													fakeVersionActor.GetDetailedAppSummaryReturnsOnCall(1, summary, v7action.Warnings{"app-2-summary-warning-1", "app-2-summary-warning-2"}, nil)
   556  												})
   557  
   558  												// TODO: Don't test the shared.AppSummaryDisplayer.AppDisplay method.
   559  												// Use DI to pass in a new AppSummaryDisplayer to the Command instead.
   560  												It("displays the app summary", func() {
   561  													Expect(executeErr).ToNot(HaveOccurred())
   562  													Expect(fakeVersionActor.GetDetailedAppSummaryCallCount()).To(Equal(2))
   563  												})
   564  											})
   565  
   566  											When("getting the application summary fails", func() {
   567  												BeforeEach(func() {
   568  													fakeVersionActor.GetDetailedAppSummaryReturns(
   569  														v7action.DetailedApplicationSummary{},
   570  														v7action.Warnings{"get-application-summary-warnings"},
   571  														errors.New("get-application-summary-error"),
   572  													)
   573  												})
   574  
   575  												It("does not display the app summary", func() {
   576  													Expect(testUI.Out).ToNot(Say(`requested state:`))
   577  												})
   578  
   579  												It("returns the error from GetDetailedAppSummary", func() {
   580  													Expect(executeErr).To(MatchError("get-application-summary-error"))
   581  												})
   582  
   583  												It("prints the warnings", func() {
   584  													Expect(testUI.Err).To(Say("get-application-summary-warnings"))
   585  												})
   586  											})
   587  
   588  										})
   589  
   590  										When("actualize returns an error", func() {
   591  											When("the error is generic", func() {
   592  												BeforeEach(func() {
   593  													fakeActor.ActualizeStub = func(v7pushaction.PushPlan, v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent {
   594  														return FillInEvents([]Step{
   595  															{Error: errors.New("anti avant garde naming")},
   596  														})
   597  													}
   598  												})
   599  
   600  												It("returns the error", func() {
   601  													Expect(executeErr).To(MatchError("anti avant garde naming"))
   602  												})
   603  											})
   604  
   605  											When("the error is a startup timeout error", func() {
   606  												BeforeEach(func() {
   607  													fakeActor.ActualizeStub = func(v7pushaction.PushPlan, v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent {
   608  														return FillInEvents([]Step{
   609  															{Error: actionerror.StartupTimeoutError{}},
   610  														})
   611  													}
   612  												})
   613  
   614  												It("returns the StartupTimeoutError and prints warnings", func() {
   615  													Expect(executeErr).To(MatchError(translatableerror.StartupTimeoutError{
   616  														AppName:    "first-app",
   617  														BinaryName: binaryName,
   618  													}))
   619  												})
   620  											})
   621  
   622  											When("the error is a process crashed error", func() {
   623  												BeforeEach(func() {
   624  													fakeActor.ActualizeStub = func(v7pushaction.PushPlan, v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent {
   625  														return FillInEvents([]Step{
   626  															{Error: actionerror.AllInstancesCrashedError{}},
   627  														})
   628  													}
   629  												})
   630  
   631  												It("returns the ApplicationUnableToStartError", func() {
   632  													Expect(executeErr).To(MatchError(translatableerror.ApplicationUnableToStartError{
   633  														AppName:    "first-app",
   634  														BinaryName: binaryName,
   635  													}))
   636  												})
   637  
   638  												It("displays the app summary", func() {
   639  													Expect(executeErr).To(HaveOccurred())
   640  													Expect(fakeVersionActor.GetDetailedAppSummaryCallCount()).To(Equal(1))
   641  												})
   642  											})
   643  										})
   644  									})
   645  								})
   646  							})
   647  						})
   648  					})
   649  				})
   650  			})
   651  		})
   652  	})
   653  
   654  	Describe("GetDockerPassword", func() {
   655  		var (
   656  			cmd        PushCommand
   657  			fakeConfig *commandfakes.FakeConfig
   658  			testUI     *ui.UI
   659  
   660  			dockerUsername        string
   661  			containsPrivateDocker bool
   662  
   663  			executeErr     error
   664  			dockerPassword string
   665  
   666  			input *Buffer
   667  		)
   668  
   669  		BeforeEach(func() {
   670  			input = NewBuffer()
   671  			testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer())
   672  			fakeConfig = new(commandfakes.FakeConfig)
   673  
   674  			cmd = PushCommand{
   675  				BaseCommand: BaseCommand{
   676  					Config: fakeConfig,
   677  					UI:     testUI,
   678  				},
   679  			}
   680  		})
   681  
   682  		Describe("Get", func() {
   683  			JustBeforeEach(func() {
   684  				dockerPassword, executeErr = cmd.GetDockerPassword(dockerUsername, containsPrivateDocker)
   685  			})
   686  
   687  			When("docker image is private", func() {
   688  				When("there is a manifest", func() {
   689  					BeforeEach(func() {
   690  						dockerUsername = ""
   691  						containsPrivateDocker = true
   692  					})
   693  
   694  					When("a password is provided via environment variable", func() {
   695  						BeforeEach(func() {
   696  							fakeConfig.DockerPasswordReturns("some-docker-password")
   697  						})
   698  
   699  						It("takes the password from the environment", func() {
   700  							Expect(executeErr).ToNot(HaveOccurred())
   701  
   702  							Expect(testUI.Out).ToNot(Say("Environment variable CF_DOCKER_PASSWORD not set."))
   703  							Expect(testUI.Out).ToNot(Say("Docker password"))
   704  
   705  							Expect(testUI.Out).To(Say("Using docker repository password from environment variable CF_DOCKER_PASSWORD."))
   706  
   707  							Expect(dockerPassword).To(Equal("some-docker-password"))
   708  						})
   709  					})
   710  
   711  					When("no password is provided", func() {
   712  						BeforeEach(func() {
   713  							_, err := input.Write([]byte("some-docker-password\n"))
   714  							Expect(err).ToNot(HaveOccurred())
   715  						})
   716  
   717  						It("prompts for a password", func() {
   718  							Expect(executeErr).ToNot(HaveOccurred())
   719  
   720  							Expect(testUI.Out).To(Say("Environment variable CF_DOCKER_PASSWORD not set."))
   721  							Expect(testUI.Out).To(Say("Docker password"))
   722  
   723  							Expect(dockerPassword).To(Equal("some-docker-password"))
   724  						})
   725  					})
   726  				})
   727  
   728  				When("there is no manifest", func() {
   729  					BeforeEach(func() {
   730  						dockerUsername = "some-docker-username"
   731  						containsPrivateDocker = false
   732  					})
   733  
   734  					When("a password is provided via environment variable", func() {
   735  						BeforeEach(func() {
   736  							fakeConfig.DockerPasswordReturns("some-docker-password")
   737  						})
   738  
   739  						It("takes the password from the environment", func() {
   740  							Expect(executeErr).ToNot(HaveOccurred())
   741  
   742  							Expect(testUI.Out).ToNot(Say("Environment variable CF_DOCKER_PASSWORD not set."))
   743  							Expect(testUI.Out).ToNot(Say("Docker password"))
   744  
   745  							Expect(testUI.Out).To(Say("Using docker repository password from environment variable CF_DOCKER_PASSWORD."))
   746  
   747  							Expect(dockerPassword).To(Equal("some-docker-password"))
   748  						})
   749  					})
   750  
   751  					When("no password is provided", func() {
   752  						BeforeEach(func() {
   753  							_, err := input.Write([]byte("some-docker-password\n"))
   754  							Expect(err).ToNot(HaveOccurred())
   755  						})
   756  
   757  						It("prompts for a password", func() {
   758  							Expect(executeErr).ToNot(HaveOccurred())
   759  
   760  							Expect(testUI.Out).To(Say("Environment variable CF_DOCKER_PASSWORD not set."))
   761  							Expect(testUI.Out).To(Say("Docker password"))
   762  
   763  							Expect(dockerPassword).To(Equal("some-docker-password"))
   764  						})
   765  					})
   766  				})
   767  			})
   768  			When("docker image is public", func() {
   769  				BeforeEach(func() {
   770  					dockerUsername = ""
   771  					containsPrivateDocker = false
   772  				})
   773  
   774  				It("does not prompt for a password", func() {
   775  					Expect(testUI.Out).ToNot(Say("Environment variable CF_DOCKER_PASSWORD not set."))
   776  					Expect(testUI.Out).ToNot(Say("Docker password"))
   777  					Expect(testUI.Out).ToNot(Say("Using docker repository password from environment variable CF_DOCKER_PASSWORD."))
   778  				})
   779  
   780  				It("returns an empty password", func() {
   781  					Expect(executeErr).ToNot(HaveOccurred())
   782  					Expect(dockerPassword).To(Equal(""))
   783  				})
   784  			})
   785  		})
   786  	})
   787  
   788  	Describe("GetBaseManifest", func() {
   789  		var (
   790  			somePath      string
   791  			flagOverrides v7pushaction.FlagOverrides
   792  			manifest      manifestparser.Manifest
   793  			executeErr    error
   794  		)
   795  
   796  		JustBeforeEach(func() {
   797  			manifest, executeErr = cmd.GetBaseManifest(flagOverrides)
   798  		})
   799  
   800  		When("no flags are specified", func() {
   801  			BeforeEach(func() {
   802  				cmd.CWD = somePath
   803  			})
   804  
   805  			When("a manifest exists in the current dir", func() {
   806  				BeforeEach(func() {
   807  					fakeManifestLocator.PathReturns("/manifest/path", true, nil)
   808  					fakeManifestParser.InterpolateAndParseReturns(
   809  						manifestparser.Manifest{
   810  							Applications: []manifestparser.Application{
   811  								{Name: "new-app"},
   812  							},
   813  						},
   814  						nil,
   815  					)
   816  				})
   817  
   818  				It("uses the manifest in the current directory", func() {
   819  					Expect(executeErr).ToNot(HaveOccurred())
   820  					Expect(manifest).To(Equal(
   821  						manifestparser.Manifest{
   822  							Applications: []manifestparser.Application{
   823  								{Name: "new-app"},
   824  							},
   825  						}),
   826  					)
   827  
   828  					Expect(fakeManifestLocator.PathCallCount()).To(Equal(1))
   829  					Expect(fakeManifestLocator.PathArgsForCall(0)).To(Equal(cmd.CWD))
   830  
   831  					Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1))
   832  					actualManifestPath, _, _ := fakeManifestParser.InterpolateAndParseArgsForCall(0)
   833  					Expect(actualManifestPath).To(Equal("/manifest/path"))
   834  				})
   835  			})
   836  
   837  			When("there is not a manifest in the current dir", func() {
   838  				BeforeEach(func() {
   839  					flagOverrides.AppName = "new-app"
   840  					fakeManifestLocator.PathReturns("", false, nil)
   841  				})
   842  
   843  				It("ignores the file not found error", func() {
   844  					Expect(executeErr).ToNot(HaveOccurred())
   845  					Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(0))
   846  				})
   847  
   848  				It("returns a default empty manifest", func() {
   849  					Expect(manifest).To(Equal(
   850  						manifestparser.Manifest{
   851  							Applications: []manifestparser.Application{
   852  								{Name: "new-app"},
   853  							},
   854  						}),
   855  					)
   856  				})
   857  			})
   858  
   859  			When("when there is an error locating the manifest in the current directory", func() {
   860  				BeforeEach(func() {
   861  					fakeManifestLocator.PathReturns("", false, errors.New("err-location"))
   862  				})
   863  
   864  				It("returns the error", func() {
   865  					Expect(executeErr).To(MatchError("err-location"))
   866  					Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(0))
   867  				})
   868  			})
   869  
   870  			When("parsing the manifest fails", func() {
   871  				When("parsing the manifest yields a yaml TypeError", func() {
   872  					BeforeEach(func() {
   873  						fakeManifestLocator.PathReturns("/manifest/path", true, nil)
   874  						fakeManifestParser.InterpolateAndParseReturns(
   875  							manifestparser.Manifest{},
   876  							&yaml.TypeError{},
   877  						)
   878  					})
   879  
   880  					It("returns a special error", func() {
   881  						Expect(executeErr).To(MatchError("Unable to push app because manifest /manifest/path is not valid yaml."))
   882  						Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1))
   883  					})
   884  				})
   885  
   886  				When("parsing the manifest yields a generic error", func() {
   887  					BeforeEach(func() {
   888  						fakeManifestLocator.PathReturns("/manifest/path", true, nil)
   889  						fakeManifestParser.InterpolateAndParseReturns(
   890  							manifestparser.Manifest{},
   891  							errors.New("bad yaml"),
   892  						)
   893  					})
   894  
   895  					It("returns the error", func() {
   896  						Expect(executeErr).To(MatchError("bad yaml"))
   897  						Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1))
   898  					})
   899  				})
   900  			})
   901  		})
   902  
   903  		When("The -f flag is specified", func() {
   904  			BeforeEach(func() {
   905  				somePath = "some-path"
   906  				flagOverrides.ManifestPath = somePath
   907  				fakeManifestLocator.PathReturns("/manifest/path", true, nil)
   908  				fakeManifestParser.InterpolateAndParseReturns(
   909  					manifestparser.Manifest{
   910  						Applications: []manifestparser.Application{
   911  							{Name: "new-app"},
   912  						},
   913  					},
   914  					nil,
   915  				)
   916  			})
   917  
   918  			It("parses the specified manifest", func() {
   919  				Expect(executeErr).ToNot(HaveOccurred())
   920  
   921  				Expect(fakeManifestLocator.PathCallCount()).To(Equal(1))
   922  				Expect(fakeManifestLocator.PathArgsForCall(0)).To(Equal(somePath))
   923  
   924  				Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1))
   925  				actualManifestPath, _, _ := fakeManifestParser.InterpolateAndParseArgsForCall(0)
   926  				Expect(actualManifestPath).To(Equal("/manifest/path"))
   927  				Expect(manifest).To(Equal(
   928  					manifestparser.Manifest{
   929  						Applications: []manifestparser.Application{
   930  							{Name: "new-app"},
   931  						},
   932  					}),
   933  				)
   934  			})
   935  		})
   936  
   937  		When("--vars-files are specified", func() {
   938  			var varsFiles []string
   939  
   940  			BeforeEach(func() {
   941  				fakeManifestLocator.PathReturns("/manifest/path", true, nil)
   942  				varsFiles = []string{"path1", "path2"}
   943  				flagOverrides.PathsToVarsFiles = append(flagOverrides.PathsToVarsFiles, varsFiles...)
   944  			})
   945  
   946  			It("passes vars files to the manifest parser", func() {
   947  				Expect(executeErr).ToNot(HaveOccurred())
   948  
   949  				Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1))
   950  				_, actualVarsFiles, _ := fakeManifestParser.InterpolateAndParseArgsForCall(0)
   951  				Expect(actualVarsFiles).To(Equal(varsFiles))
   952  			})
   953  		})
   954  
   955  		When("The --var flag is provided", func() {
   956  			var vars []template.VarKV
   957  
   958  			BeforeEach(func() {
   959  				fakeManifestLocator.PathReturns("/manifest/path", true, nil)
   960  				vars = []template.VarKV{
   961  					{Name: "put-var-here", Value: "turtle"},
   962  				}
   963  				flagOverrides.Vars = vars
   964  			})
   965  
   966  			It("passes vars files to the manifest parser", func() {
   967  				Expect(executeErr).ToNot(HaveOccurred())
   968  
   969  				Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1))
   970  				_, _, actualVars := fakeManifestParser.InterpolateAndParseArgsForCall(0)
   971  				Expect(actualVars).To(Equal(vars))
   972  			})
   973  		})
   974  	})
   975  
   976  	Describe("GetFlagOverrides", func() {
   977  		var (
   978  			overrides    v7pushaction.FlagOverrides
   979  			overridesErr error
   980  		)
   981  
   982  		BeforeEach(func() {
   983  			cmd.Buildpacks = []string{"buildpack-1", "buildpack-2"}
   984  			cmd.Stack = "validStack"
   985  			cmd.HealthCheckType = flag.HealthCheckType{Type: constant.Port}
   986  			cmd.HealthCheckHTTPEndpoint = "/health-check-http-endpoint"
   987  			cmd.HealthCheckTimeout = flag.PositiveInteger{Value: 7}
   988  			cmd.Memory = "64M"
   989  			cmd.Disk = "256M"
   990  			cmd.DropletPath = flag.PathWithExistenceCheck("some-droplet.tgz")
   991  			cmd.StartCommand = flag.Command{FilteredString: types.FilteredString{IsSet: true, Value: "some-start-command"}}
   992  			cmd.NoRoute = true
   993  			cmd.RandomRoute = false
   994  			cmd.NoStart = true
   995  			cmd.NoWait = true
   996  			cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyRolling}
   997  			cmd.Instances = flag.Instances{NullInt: types.NullInt{Value: 10, IsSet: true}}
   998  			cmd.PathToManifest = "/manifest/path"
   999  			cmd.PathsToVarsFiles = []flag.PathWithExistenceCheck{"/vars1", "/vars2"}
  1000  			cmd.Vars = []template.VarKV{{Name: "key", Value: "val"}}
  1001  			cmd.Task = true
  1002  		})
  1003  
  1004  		JustBeforeEach(func() {
  1005  			overrides, overridesErr = cmd.GetFlagOverrides()
  1006  			Expect(overridesErr).ToNot(HaveOccurred())
  1007  		})
  1008  
  1009  		It("sets them on the flag overrides", func() {
  1010  			Expect(overridesErr).ToNot(HaveOccurred())
  1011  			Expect(overrides.Buildpacks).To(ConsistOf("buildpack-1", "buildpack-2"))
  1012  			Expect(overrides.DropletPath).To(Equal("some-droplet.tgz"))
  1013  			Expect(overrides.Stack).To(Equal("validStack"))
  1014  			Expect(overrides.HealthCheckType).To(Equal(constant.Port))
  1015  			Expect(overrides.HealthCheckEndpoint).To(Equal("/health-check-http-endpoint"))
  1016  			Expect(overrides.HealthCheckTimeout).To(BeEquivalentTo(7))
  1017  			Expect(overrides.Memory).To(Equal("64M"))
  1018  			Expect(overrides.Disk).To(Equal("256M"))
  1019  			Expect(overrides.StartCommand).To(Equal(types.FilteredString{IsSet: true, Value: "some-start-command"}))
  1020  			Expect(overrides.NoRoute).To(BeTrue())
  1021  			Expect(overrides.NoStart).To(BeTrue())
  1022  			Expect(overrides.NoWait).To(BeTrue())
  1023  			Expect(overrides.RandomRoute).To(BeFalse())
  1024  			Expect(overrides.Strategy).To(Equal(constant.DeploymentStrategyRolling))
  1025  			Expect(overrides.Instances).To(Equal(types.NullInt{Value: 10, IsSet: true}))
  1026  			Expect(overrides.ManifestPath).To(Equal("/manifest/path"))
  1027  			Expect(overrides.PathsToVarsFiles).To(Equal([]string{"/vars1", "/vars2"}))
  1028  			Expect(overrides.Vars).To(Equal([]template.VarKV{{Name: "key", Value: "val"}}))
  1029  			Expect(overrides.Task).To(BeTrue())
  1030  		})
  1031  
  1032  		When("a docker image is provided", func() {
  1033  			BeforeEach(func() {
  1034  				cmd.DockerImage = flag.DockerImage{Path: "some-docker-image"}
  1035  			})
  1036  
  1037  			It("sets docker image on the flag overrides", func() {
  1038  				Expect(overridesErr).ToNot(HaveOccurred())
  1039  				Expect(overrides.DockerImage).To(Equal("some-docker-image"))
  1040  			})
  1041  		})
  1042  	})
  1043  
  1044  	DescribeTable("ValidateFlags returns an error",
  1045  		func(setup func(), expectedErr error) {
  1046  			setup()
  1047  			err := cmd.ValidateFlags()
  1048  			if expectedErr == nil {
  1049  				Expect(err).To(BeNil())
  1050  			} else {
  1051  				Expect(err).To(MatchError(expectedErr))
  1052  			}
  1053  		},
  1054  
  1055  		Entry("when docker username flag is passed *without* docker flag",
  1056  			func() {
  1057  				cmd.DockerUsername = "some-docker-username"
  1058  			},
  1059  			translatableerror.RequiredFlagsError{Arg1: "--docker-image, -o", Arg2: "--docker-username"}),
  1060  
  1061  		Entry("when docker and buildpacks flags are passed",
  1062  			func() {
  1063  				cmd.DockerImage.Path = "some-docker-image"
  1064  				cmd.Buildpacks = []string{"some-buildpack"}
  1065  			},
  1066  			translatableerror.ArgumentCombinationError{Args: []string{"--buildpack, -b", "--docker-image, -o"}}),
  1067  
  1068  		Entry("when docker and stack flags are passed",
  1069  			func() {
  1070  				cmd.DockerImage.Path = "some-docker-image"
  1071  				cmd.Stack = "validStack"
  1072  			},
  1073  			translatableerror.ArgumentCombinationError{Args: []string{"--stack, -s", "--docker-image, -o"}}),
  1074  
  1075  		Entry("when docker and path flags are passed",
  1076  			func() {
  1077  				cmd.DockerImage.Path = "some-docker-image"
  1078  				cmd.AppPath = "some-directory-path"
  1079  			},
  1080  			translatableerror.ArgumentCombinationError{Args: []string{"--docker-image, -o", "--path, -p"}}),
  1081  
  1082  		Entry("when -u http does not have a matching --endpoint",
  1083  			func() {
  1084  				cmd.HealthCheckType.Type = constant.HTTP
  1085  			},
  1086  			translatableerror.RequiredFlagsError{Arg1: "--endpoint", Arg2: "--health-check-type=http, -u=http"}),
  1087  
  1088  		Entry("when -u http does have a matching --endpoint",
  1089  			func() {
  1090  				cmd.HealthCheckType.Type = constant.HTTP
  1091  				cmd.HealthCheckHTTPEndpoint = "/health"
  1092  			},
  1093  			nil),
  1094  
  1095  		Entry("when droplet and path flags are passed",
  1096  			func() {
  1097  				cmd.DropletPath = "some-droplet.tgz"
  1098  				cmd.AppPath = "/my/app"
  1099  			},
  1100  			translatableerror.ArgumentCombinationError{
  1101  				Args: []string{
  1102  					"--droplet", "--docker-image, -o", "--docker-username", "-p",
  1103  				},
  1104  			}),
  1105  
  1106  		Entry("when droplet and docker image flags are passed",
  1107  			func() {
  1108  				cmd.DropletPath = "some-droplet.tgz"
  1109  				cmd.DockerImage.Path = "docker-image"
  1110  			},
  1111  			translatableerror.ArgumentCombinationError{
  1112  				Args: []string{
  1113  					"--droplet", "--docker-image, -o", "--docker-username", "-p",
  1114  				},
  1115  			}),
  1116  
  1117  		Entry("when droplet, docker image, and docker username flags are passed",
  1118  			func() {
  1119  				cmd.DropletPath = "some-droplet.tgz"
  1120  				cmd.DockerImage.Path = "docker-image"
  1121  				cmd.DockerUsername = "docker-username"
  1122  			},
  1123  			translatableerror.ArgumentCombinationError{
  1124  				Args: []string{
  1125  					"--droplet", "--docker-image, -o", "--docker-username", "-p",
  1126  				},
  1127  			}),
  1128  
  1129  		Entry("when strategy 'rolling' and no-start flags are passed",
  1130  			func() {
  1131  				cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyRolling}
  1132  				cmd.NoStart = true
  1133  			},
  1134  			translatableerror.ArgumentCombinationError{
  1135  				Args: []string{
  1136  					"--no-start", "--strategy=rolling",
  1137  				},
  1138  			}),
  1139  
  1140  		Entry("when strategy is not set and no-start flags are passed",
  1141  			func() {
  1142  				cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyDefault}
  1143  				cmd.NoStart = true
  1144  			},
  1145  			nil),
  1146  
  1147  		Entry("when no-start and no-wait flags are passed",
  1148  			func() {
  1149  				cmd.NoStart = true
  1150  				cmd.NoWait = true
  1151  			},
  1152  			translatableerror.ArgumentCombinationError{
  1153  				Args: []string{
  1154  					"--no-start", "--no-wait",
  1155  				},
  1156  			}),
  1157  		Entry("when no-route and random-route flags are passed",
  1158  			func() {
  1159  				cmd.NoRoute = true
  1160  				cmd.RandomRoute = true
  1161  			},
  1162  			translatableerror.ArgumentCombinationError{
  1163  				Args: []string{
  1164  					"--no-route", "--random-route",
  1165  				},
  1166  			}),
  1167  
  1168  		Entry("default is combined with non default buildpacks",
  1169  			func() {
  1170  				cmd.Buildpacks = []string{"some-docker-username", "default"}
  1171  			},
  1172  			translatableerror.InvalidBuildpacksError{}),
  1173  
  1174  		Entry("default is combined with non default buildpacks",
  1175  			func() {
  1176  				cmd.Buildpacks = []string{"some-docker-username", "null"}
  1177  			},
  1178  			translatableerror.InvalidBuildpacksError{}),
  1179  
  1180  		Entry("task and strategy flags are passed",
  1181  			func() {
  1182  				cmd.Task = true
  1183  				cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyRolling}
  1184  			},
  1185  			translatableerror.ArgumentCombinationError{
  1186  				Args: []string{
  1187  					"--task", "--strategy=rolling",
  1188  				},
  1189  			}),
  1190  	)
  1191  })