github.com/cloudfoundry-community/cloudfoundry-cli@v6.44.1-0.20240130060226-cda5ed8e89a5+incompatible/command/v7/push_command_test.go (about)

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