github.com/LukasHeimann/cloudfoundrycli/v8@v8.4.4/command/v7/push_command_test.go (about)

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