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

     1  package v6_test
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"regexp"
     9  	"time"
    10  
    11  	"code.cloudfoundry.org/cli/actor/actionerror"
    12  	"code.cloudfoundry.org/cli/actor/pushaction"
    13  	"code.cloudfoundry.org/cli/actor/v2action"
    14  	"code.cloudfoundry.org/cli/actor/v2v3action"
    15  	"code.cloudfoundry.org/cli/actor/v3action"
    16  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant"
    17  	v3constant "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    18  	"code.cloudfoundry.org/cli/command/commandfakes"
    19  	"code.cloudfoundry.org/cli/command/flag"
    20  	"code.cloudfoundry.org/cli/command/translatableerror"
    21  	. "code.cloudfoundry.org/cli/command/v6"
    22  	"code.cloudfoundry.org/cli/command/v6/shared/sharedfakes"
    23  	"code.cloudfoundry.org/cli/command/v6/v6fakes"
    24  	"code.cloudfoundry.org/cli/types"
    25  	"code.cloudfoundry.org/cli/util/configv3"
    26  	"code.cloudfoundry.org/cli/util/manifest"
    27  	"code.cloudfoundry.org/cli/util/ui"
    28  	"github.com/cloudfoundry/bosh-cli/director/template"
    29  	. "github.com/onsi/ginkgo"
    30  	. "github.com/onsi/ginkgo/extensions/table"
    31  	. "github.com/onsi/gomega"
    32  	. "github.com/onsi/gomega/gbytes"
    33  )
    34  
    35  var _ = Describe("push Command", func() {
    36  	var (
    37  		cmd                         PushCommand
    38  		testUI                      *ui.UI
    39  		fakeConfig                  *commandfakes.FakeConfig
    40  		fakeSharedActor             *commandfakes.FakeSharedActor
    41  		fakeActor                   *v6fakes.FakeV2PushActor
    42  		fakeRestartActor            *v6fakes.FakeRestartActor
    43  		fakeApplicationSummaryActor *sharedfakes.FakeApplicationSummaryActor
    44  		fakeProgressBar             *v6fakes.FakeProgressBar
    45  		input                       *Buffer
    46  		binaryName                  string
    47  
    48  		appName    string
    49  		executeErr error
    50  		pwd        string
    51  	)
    52  
    53  	BeforeEach(func() {
    54  		input = NewBuffer()
    55  		testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer())
    56  		fakeConfig = new(commandfakes.FakeConfig)
    57  		fakeSharedActor = new(commandfakes.FakeSharedActor)
    58  		fakeActor = new(v6fakes.FakeV2PushActor)
    59  		fakeRestartActor = new(v6fakes.FakeRestartActor)
    60  		fakeApplicationSummaryActor = new(sharedfakes.FakeApplicationSummaryActor)
    61  		fakeProgressBar = new(v6fakes.FakeProgressBar)
    62  
    63  		cmd = PushCommand{
    64  			UI:                      testUI,
    65  			Config:                  fakeConfig,
    66  			SharedActor:             fakeSharedActor,
    67  			Actor:                   fakeActor,
    68  			RestartActor:            fakeRestartActor,
    69  			ApplicationSummaryActor: fakeApplicationSummaryActor,
    70  			ProgressBar:             fakeProgressBar,
    71  		}
    72  
    73  		appName = "some-app"
    74  		cmd.OptionalArgs.AppName = appName
    75  		binaryName = "faceman"
    76  		fakeConfig.BinaryNameReturns(binaryName)
    77  
    78  		var err error
    79  		pwd, err = os.Getwd()
    80  		Expect(err).ToNot(HaveOccurred())
    81  	})
    82  
    83  	Context("Execute", func() {
    84  		JustBeforeEach(func() {
    85  			executeErr = cmd.Execute(nil)
    86  		})
    87  
    88  		When("checking target fails", func() {
    89  			BeforeEach(func() {
    90  				fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName})
    91  			})
    92  
    93  			It("returns an error", func() {
    94  				Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: binaryName}))
    95  
    96  				Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1))
    97  				checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0)
    98  				Expect(checkTargetedOrg).To(BeTrue())
    99  				Expect(checkTargetedSpace).To(BeTrue())
   100  			})
   101  		})
   102  
   103  		When("the user is logged in, and org and space are targeted", func() {
   104  			BeforeEach(func() {
   105  				fakeConfig.HasTargetedOrganizationReturns(true)
   106  				fakeConfig.TargetedOrganizationReturns(configv3.Organization{GUID: "some-org-guid", Name: "some-org"})
   107  				fakeConfig.HasTargetedSpaceReturns(true)
   108  				fakeConfig.TargetedSpaceReturns(configv3.Space{GUID: "some-space-guid", Name: "some-space"})
   109  				fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil)
   110  			})
   111  
   112  			When("the push settings are valid", func() {
   113  				var appManifests []manifest.Application
   114  
   115  				BeforeEach(func() {
   116  					appManifests = []manifest.Application{
   117  						{
   118  							Name: appName,
   119  							Path: pwd,
   120  						},
   121  					}
   122  					fakeActor.MergeAndValidateSettingsAndManifestsReturns(appManifests, nil)
   123  				})
   124  
   125  				When("the settings can be converted to a valid config", func() {
   126  					var appConfigs []pushaction.ApplicationConfig
   127  
   128  					BeforeEach(func() {
   129  						appConfigs = []pushaction.ApplicationConfig{
   130  							{
   131  								CurrentApplication: pushaction.Application{Application: v2action.Application{Name: appName, State: constant.ApplicationStarted}},
   132  								DesiredApplication: pushaction.Application{Application: v2action.Application{Name: appName}},
   133  								CurrentRoutes: []v2action.Route{
   134  									{Host: "route1", Domain: v2action.Domain{Name: "example.com"}},
   135  									{Host: "route2", Domain: v2action.Domain{Name: "example.com"}},
   136  								},
   137  								DesiredRoutes: []v2action.Route{
   138  									{Host: "route3", Domain: v2action.Domain{Name: "example.com"}},
   139  									{Host: "route4", Domain: v2action.Domain{Name: "example.com"}},
   140  								},
   141  								Path: pwd,
   142  							},
   143  						}
   144  						fakeActor.ConvertToApplicationConfigsReturns(appConfigs, pushaction.Warnings{"some-config-warnings"}, nil)
   145  					})
   146  
   147  					When("the apply is successful", func() {
   148  						var updatedConfig pushaction.ApplicationConfig
   149  
   150  						BeforeEach(func() {
   151  							fakeActor.ApplyStub = func(_ pushaction.ApplicationConfig, _ pushaction.ProgressBar) (<-chan pushaction.ApplicationConfig, <-chan pushaction.Event, <-chan pushaction.Warnings, <-chan error) {
   152  								configStream := make(chan pushaction.ApplicationConfig, 1)
   153  								eventStream := make(chan pushaction.Event)
   154  								warningsStream := make(chan pushaction.Warnings)
   155  								errorStream := make(chan error)
   156  
   157  								updatedConfig = pushaction.ApplicationConfig{
   158  									CurrentApplication: pushaction.Application{Application: v2action.Application{Name: appName, GUID: "some-app-guid"}},
   159  									DesiredApplication: pushaction.Application{Application: v2action.Application{Name: appName, GUID: "some-app-guid"}},
   160  									Path:               pwd,
   161  								}
   162  
   163  								go func() {
   164  									defer GinkgoRecover()
   165  
   166  									Eventually(eventStream).Should(BeSent(pushaction.SettingUpApplication))
   167  									Eventually(eventStream).Should(BeSent(pushaction.CreatedApplication))
   168  									Eventually(eventStream).Should(BeSent(pushaction.UpdatedApplication))
   169  									Eventually(eventStream).Should(BeSent(pushaction.CreatingAndMappingRoutes))
   170  									Eventually(eventStream).Should(BeSent(pushaction.CreatedRoutes))
   171  									Eventually(eventStream).Should(BeSent(pushaction.BoundRoutes))
   172  									Eventually(eventStream).Should(BeSent(pushaction.UnmappingRoutes))
   173  									Eventually(eventStream).Should(BeSent(pushaction.ConfiguringServices))
   174  									Eventually(eventStream).Should(BeSent(pushaction.BoundServices))
   175  									Eventually(eventStream).Should(BeSent(pushaction.ResourceMatching))
   176  									Eventually(eventStream).Should(BeSent(pushaction.UploadingApplication))
   177  									Eventually(eventStream).Should(BeSent(pushaction.CreatingArchive))
   178  									Eventually(eventStream).Should(BeSent(pushaction.UploadingApplicationWithArchive))
   179  									Eventually(fakeProgressBar.ReadyCallCount).Should(Equal(1))
   180  									Eventually(eventStream).Should(BeSent(pushaction.RetryUpload))
   181  									Eventually(eventStream).Should(BeSent(pushaction.UploadWithArchiveComplete))
   182  									Eventually(fakeProgressBar.CompleteCallCount).Should(Equal(1))
   183  									Eventually(configStream).Should(BeSent(updatedConfig))
   184  									Eventually(eventStream).Should(BeSent(pushaction.Complete))
   185  									Eventually(warningsStream).Should(BeSent(pushaction.Warnings{"apply-1", "apply-2"}))
   186  									close(configStream)
   187  									close(eventStream)
   188  									close(warningsStream)
   189  									close(errorStream)
   190  								}()
   191  
   192  								return configStream, eventStream, warningsStream, errorStream
   193  							}
   194  
   195  							fakeRestartActor.RestartApplicationStub = func(app v2action.Application, client v2action.NOAAClient) (<-chan *v2action.LogMessage, <-chan error, <-chan v2action.ApplicationStateChange, <-chan string, <-chan error) {
   196  								messages := make(chan *v2action.LogMessage)
   197  								logErrs := make(chan error)
   198  								appState := make(chan v2action.ApplicationStateChange)
   199  								warnings := make(chan string)
   200  								errs := make(chan error)
   201  
   202  								go func() {
   203  									messages <- v2action.NewLogMessage("log message 1", 1, time.Unix(0, 0), "STG", "1")
   204  									messages <- v2action.NewLogMessage("log message 2", 1, time.Unix(0, 0), "STG", "1")
   205  									appState <- v2action.ApplicationStateStopping
   206  									appState <- v2action.ApplicationStateStaging
   207  									appState <- v2action.ApplicationStateStarting
   208  									close(messages)
   209  									close(logErrs)
   210  									close(appState)
   211  									close(warnings)
   212  									close(errs)
   213  								}()
   214  
   215  								return messages, logErrs, appState, warnings, errs
   216  							}
   217  
   218  							applicationSummary := v2action.ApplicationSummary{
   219  								Application: v2action.Application{
   220  									DetectedBuildpack:    types.FilteredString{IsSet: true, Value: "some-buildpack"},
   221  									DetectedStartCommand: types.FilteredString{IsSet: true, Value: "some start command"},
   222  									GUID:                 "some-app-guid",
   223  									Instances:            types.NullInt{Value: 3, IsSet: true},
   224  									Memory:               types.NullByteSizeInMb{IsSet: true, Value: 128},
   225  									Name:                 appName,
   226  									PackageUpdatedAt:     time.Unix(0, 0),
   227  									State:                "STARTED",
   228  								},
   229  								Stack: v2action.Stack{
   230  									Name: "potatos",
   231  								},
   232  								Routes: []v2action.Route{
   233  									{
   234  										Host: "banana",
   235  										Domain: v2action.Domain{
   236  											Name: "fruit.com",
   237  										},
   238  										Path: "/hi",
   239  									},
   240  									{
   241  										Domain: v2action.Domain{
   242  											Name: "foobar.com",
   243  										},
   244  										Port: types.NullInt{IsSet: true, Value: 13},
   245  									},
   246  								},
   247  							}
   248  							warnings := []string{"app-summary-warning"}
   249  
   250  							applicationSummary.RunningInstances = []v2action.ApplicationInstanceWithStats{{State: "RUNNING"}}
   251  
   252  							fakeRestartActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil)
   253  						})
   254  
   255  						When("no manifest is provided", func() {
   256  							It("passes through the command line flags", func() {
   257  								Expect(executeErr).ToNot(HaveOccurred())
   258  
   259  								Expect(fakeActor.MergeAndValidateSettingsAndManifestsCallCount()).To(Equal(1))
   260  								cmdSettings, _ := fakeActor.MergeAndValidateSettingsAndManifestsArgsForCall(0)
   261  								Expect(cmdSettings).To(Equal(pushaction.CommandLineSettings{
   262  									Name:             appName,
   263  									CurrentDirectory: pwd,
   264  								}))
   265  							})
   266  						})
   267  
   268  						When("a manifest is provided", func() {
   269  							var (
   270  								tmpDir       string
   271  								providedPath string
   272  
   273  								originalDir string
   274  							)
   275  
   276  							BeforeEach(func() {
   277  								var err error
   278  								tmpDir, err = ioutil.TempDir("", "push-command-test")
   279  								Expect(err).ToNot(HaveOccurred())
   280  
   281  								// OS X uses weird symlinks that causes problems for some tests
   282  								tmpDir, err = filepath.EvalSymlinks(tmpDir)
   283  								Expect(err).ToNot(HaveOccurred())
   284  
   285  								originalDir, err = os.Getwd()
   286  								Expect(err).ToNot(HaveOccurred())
   287  
   288  								cmd.OptionalArgs.AppName = ""
   289  							})
   290  
   291  							AfterEach(func() {
   292  								Expect(os.Chdir(originalDir)).ToNot(HaveOccurred())
   293  								Expect(os.RemoveAll(tmpDir)).ToNot(HaveOccurred())
   294  							})
   295  
   296  							Context("via a manifest.yml in the current directory", func() {
   297  								var expectedApps []manifest.Application
   298  
   299  								BeforeEach(func() {
   300  									err := os.Chdir(tmpDir)
   301  									Expect(err).ToNot(HaveOccurred())
   302  
   303  									providedPath = filepath.Join(tmpDir, "manifest.yml")
   304  									err = ioutil.WriteFile(providedPath, []byte("some manifest file"), 0666)
   305  									Expect(err).ToNot(HaveOccurred())
   306  
   307  									expectedApps = []manifest.Application{{Name: "some-app"}, {Name: "some-other-app"}}
   308  									fakeActor.ReadManifestReturns(expectedApps, nil, nil)
   309  								})
   310  
   311  								When("reading the manifest file is successful", func() {
   312  									It("merges app manifest and flags", func() {
   313  										Expect(executeErr).ToNot(HaveOccurred())
   314  
   315  										Expect(fakeActor.ReadManifestCallCount()).To(Equal(1))
   316  										Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(providedPath))
   317  
   318  										Expect(fakeActor.MergeAndValidateSettingsAndManifestsCallCount()).To(Equal(1))
   319  										cmdSettings, manifestApps := fakeActor.MergeAndValidateSettingsAndManifestsArgsForCall(0)
   320  										Expect(cmdSettings).To(Equal(pushaction.CommandLineSettings{
   321  											CurrentDirectory: tmpDir,
   322  										}))
   323  										Expect(manifestApps).To(Equal(expectedApps))
   324  									})
   325  
   326  									It("outputs corresponding flavor text", func() {
   327  										Expect(executeErr).ToNot(HaveOccurred())
   328  
   329  										Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`))
   330  										Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(providedPath)))
   331  									})
   332  								})
   333  
   334  								When("reading manifest file errors", func() {
   335  									var expectedErr error
   336  
   337  									BeforeEach(func() {
   338  										expectedErr = errors.New("I am an error!!!")
   339  
   340  										fakeActor.ReadManifestReturns(nil, nil, expectedErr)
   341  									})
   342  
   343  									It("returns the error", func() {
   344  										Expect(executeErr).To(MatchError(expectedErr))
   345  									})
   346  								})
   347  
   348  								When("--no-manifest is specified", func() {
   349  									BeforeEach(func() {
   350  										cmd.NoManifest = true
   351  									})
   352  
   353  									It("ignores the manifest file", func() {
   354  										Expect(executeErr).ToNot(HaveOccurred())
   355  
   356  										Expect(fakeActor.MergeAndValidateSettingsAndManifestsCallCount()).To(Equal(1))
   357  										cmdSettings, manifestApps := fakeActor.MergeAndValidateSettingsAndManifestsArgsForCall(0)
   358  										Expect(cmdSettings).To(Equal(pushaction.CommandLineSettings{
   359  											CurrentDirectory: tmpDir,
   360  										}))
   361  										Expect(manifestApps).To(BeNil())
   362  									})
   363  								})
   364  							})
   365  
   366  							Context("via a manifest.yaml in the current directory", func() {
   367  								BeforeEach(func() {
   368  									err := os.Chdir(tmpDir)
   369  									Expect(err).ToNot(HaveOccurred())
   370  
   371  									providedPath = filepath.Join(tmpDir, "manifest.yaml")
   372  									err = ioutil.WriteFile(providedPath, []byte("some manifest file"), 0666)
   373  									Expect(err).ToNot(HaveOccurred())
   374  								})
   375  
   376  								It("should read the manifest.yml", func() {
   377  									Expect(executeErr).ToNot(HaveOccurred())
   378  
   379  									Expect(fakeActor.ReadManifestCallCount()).To(Equal(1))
   380  									Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(providedPath))
   381  								})
   382  							})
   383  
   384  							Context("via the -f flag", func() {
   385  								Context("given a path with filename 'manifest.yml'", func() {
   386  									BeforeEach(func() {
   387  										providedPath = filepath.Join(tmpDir, "manifest.yml")
   388  									})
   389  
   390  									When("the manifest.yml file does not exist", func() {
   391  										BeforeEach(func() {
   392  											cmd.PathToManifest = flag.PathWithExistenceCheck(providedPath)
   393  										})
   394  
   395  										It("returns an error", func() {
   396  											Expect(os.IsNotExist(executeErr)).To(BeTrue())
   397  
   398  											Expect(testUI.Out).ToNot(Say("Pushing from manifest"))
   399  											Expect(testUI.Out).ToNot(Say("Using manifest file"))
   400  
   401  											Expect(fakeActor.ReadManifestCallCount()).To(Equal(0))
   402  										})
   403  									})
   404  
   405  									When("the manifest.yml file exists", func() {
   406  										BeforeEach(func() {
   407  											err := ioutil.WriteFile(providedPath, []byte(`key: "value"`), 0666)
   408  											Expect(err).ToNot(HaveOccurred())
   409  
   410  											cmd.PathToManifest = flag.PathWithExistenceCheck(providedPath)
   411  										})
   412  
   413  										It("should read the manifest.yml file and outputs corresponding flavor text", func() {
   414  											Expect(executeErr).ToNot(HaveOccurred())
   415  
   416  											Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`))
   417  											Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(providedPath)))
   418  
   419  											Expect(fakeActor.ReadManifestCallCount()).To(Equal(1))
   420  											Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(providedPath))
   421  										})
   422  
   423  										Context("variable interpolation", func() {
   424  											Context("vars file only", func() {
   425  												When("a vars file is also provided", func() {
   426  													var providedVarsFilePath string
   427  
   428  													BeforeEach(func() {
   429  														providedVarsFilePath = filepath.Join(tmpDir, "vars-file.yml")
   430  														cmd.VarsFilePaths = []flag.PathWithExistenceCheck{flag.PathWithExistenceCheck(providedVarsFilePath)}
   431  													})
   432  
   433  													It("should read the vars-file.yml file and replace the variables in the manifest.yml file", func() {
   434  														Expect(executeErr).ToNot(HaveOccurred())
   435  
   436  														Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`))
   437  														Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(providedPath)))
   438  
   439  														Expect(fakeActor.ReadManifestCallCount()).To(Equal(1))
   440  														manifest, varsFiles, vars := fakeActor.ReadManifestArgsForCall(0)
   441  														Expect(manifest).To(Equal(providedPath))
   442  														Expect(varsFiles).To(Equal([]string{providedVarsFilePath}))
   443  														Expect(vars).To(BeEmpty())
   444  													})
   445  												})
   446  
   447  												When("multiple vars files are provided", func() {
   448  													var (
   449  														firstProvidedVarsFilePath  string
   450  														secondProvidedVarsFilePath string
   451  													)
   452  
   453  													BeforeEach(func() {
   454  														firstProvidedVarsFilePath = filepath.Join(tmpDir, "vars-file-1.yml")
   455  														firstVarsFile := flag.PathWithExistenceCheck(firstProvidedVarsFilePath)
   456  
   457  														secondProvidedVarsFilePath = filepath.Join(tmpDir, "vars-file-2.yml")
   458  														secondVarsFile := flag.PathWithExistenceCheck(secondProvidedVarsFilePath)
   459  														cmd.VarsFilePaths = []flag.PathWithExistenceCheck{firstVarsFile, secondVarsFile}
   460  													})
   461  
   462  													It("should read the vars-file.yml file and replace the variables in the manifest.yml file", func() {
   463  														Expect(executeErr).ToNot(HaveOccurred())
   464  
   465  														Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`))
   466  														Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(providedPath)))
   467  
   468  														Expect(fakeActor.ReadManifestCallCount()).To(Equal(1))
   469  														manifest, varsFiles, vars := fakeActor.ReadManifestArgsForCall(0)
   470  														Expect(manifest).To(Equal(providedPath))
   471  														Expect(varsFiles).To(Equal([]string{firstProvidedVarsFilePath, secondProvidedVarsFilePath}))
   472  														Expect(vars).To(BeEmpty())
   473  													})
   474  												})
   475  											})
   476  
   477  											Context("vars flag only", func() {
   478  												var vars []template.VarKV
   479  
   480  												BeforeEach(func() {
   481  													vars = []template.VarKV{
   482  														{Name: "some-var", Value: "some-value"},
   483  														{Name: "another-var", Value: 1},
   484  													}
   485  
   486  													cmd.Vars = vars
   487  												})
   488  
   489  												It("should read the vars and pass only the vars array to ReadManifest", func() {
   490  													Expect(executeErr).ToNot(HaveOccurred())
   491  
   492  													Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`))
   493  													Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(providedPath)))
   494  
   495  													Expect(fakeActor.ReadManifestCallCount()).To(Equal(1))
   496  													manifest, varsFiles, vars := fakeActor.ReadManifestArgsForCall(0)
   497  													Expect(manifest).To(Equal(providedPath))
   498  													Expect(varsFiles).To(BeEmpty())
   499  													Expect(vars).To(ConsistOf([]template.VarKV{
   500  														{Name: "some-var", Value: "some-value"},
   501  														{Name: "another-var", Value: 1},
   502  													}))
   503  												})
   504  											})
   505  										})
   506  									})
   507  								})
   508  
   509  								Context("given a path that is a directory", func() {
   510  
   511  									var (
   512  										ymlFile  string
   513  										yamlFile string
   514  									)
   515  
   516  									BeforeEach(func() {
   517  										providedPath = tmpDir
   518  										cmd.PathToManifest = flag.PathWithExistenceCheck(providedPath)
   519  									})
   520  
   521  									When("the directory does not contain a 'manifest.y{a}ml' file", func() {
   522  										It("returns an error", func() {
   523  											Expect(executeErr).To(MatchError(translatableerror.ManifestFileNotFoundInDirectoryError{PathToManifest: providedPath}))
   524  											Expect(testUI.Out).ToNot(Say("Pushing from manifest"))
   525  											Expect(testUI.Out).ToNot(Say("Using manifest file"))
   526  
   527  											Expect(fakeActor.ReadManifestCallCount()).To(Equal(0))
   528  										})
   529  									})
   530  
   531  									When("the directory contains a 'manifest.yml' file", func() {
   532  										BeforeEach(func() {
   533  											ymlFile = filepath.Join(providedPath, "manifest.yml")
   534  											err := ioutil.WriteFile(ymlFile, []byte(`key: "value"`), 0666)
   535  											Expect(err).ToNot(HaveOccurred())
   536  										})
   537  
   538  										It("should read the manifest.yml file and outputs corresponding flavor text", func() {
   539  											Expect(executeErr).ToNot(HaveOccurred())
   540  
   541  											Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`))
   542  											Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(ymlFile)))
   543  
   544  											Expect(fakeActor.ReadManifestCallCount()).To(Equal(1))
   545  											Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(ymlFile))
   546  										})
   547  									})
   548  
   549  									When("the directory contains a 'manifest.yaml' file", func() {
   550  										BeforeEach(func() {
   551  											yamlFile = filepath.Join(providedPath, "manifest.yaml")
   552  											err := ioutil.WriteFile(yamlFile, []byte(`key: "value"`), 0666)
   553  											Expect(err).ToNot(HaveOccurred())
   554  										})
   555  
   556  										It("should read the manifest.yaml file and outputs corresponding flavor text", func() {
   557  											Expect(executeErr).ToNot(HaveOccurred())
   558  
   559  											Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`))
   560  											Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(yamlFile)))
   561  
   562  											Expect(fakeActor.ReadManifestCallCount()).To(Equal(1))
   563  											Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(yamlFile))
   564  										})
   565  									})
   566  
   567  									When("the directory contains both a 'manifest.yml' and 'manifest.yaml' file", func() {
   568  										BeforeEach(func() {
   569  											ymlFile = filepath.Join(providedPath, "manifest.yml")
   570  											err := ioutil.WriteFile(ymlFile, []byte(`key: "value"`), 0666)
   571  											Expect(err).ToNot(HaveOccurred())
   572  
   573  											yamlFile = filepath.Join(providedPath, "manifest.yaml")
   574  											err = ioutil.WriteFile(yamlFile, []byte(`key: "value"`), 0666)
   575  											Expect(err).ToNot(HaveOccurred())
   576  										})
   577  
   578  										It("should read the manifest.yml file and outputs corresponding flavor text", func() {
   579  											Expect(executeErr).ToNot(HaveOccurred())
   580  
   581  											Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`))
   582  											Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(ymlFile)))
   583  
   584  											Expect(fakeActor.ReadManifestCallCount()).To(Equal(1))
   585  											Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(ymlFile))
   586  										})
   587  									})
   588  								})
   589  							})
   590  
   591  							Context("via a legacy manifest.yml in the current directory", func() {
   592  								var expectedErr manifest.GlobalFieldsError
   593  
   594  								BeforeEach(func() {
   595  									err := os.Chdir(tmpDir)
   596  									Expect(err).ToNot(HaveOccurred())
   597  
   598  									providedPath = filepath.Join(tmpDir, "manifest.yml")
   599  									err = ioutil.WriteFile(providedPath, []byte("some manifest file"), 0666)
   600  									Expect(err).ToNot(HaveOccurred())
   601  									expectedErr = manifest.GlobalFieldsError{Fields: []string{"host"}}
   602  
   603  									fakeActor.ReadManifestReturns(nil, nil, expectedErr)
   604  								})
   605  
   606  								It("throws a legacy main error", func() {
   607  									Expect(executeErr).To(MatchError(expectedErr))
   608  
   609  									Expect(fakeActor.ReadManifestCallCount()).To(Equal(1))
   610  									Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(providedPath))
   611  
   612  									Expect(fakeActor.MergeAndValidateSettingsAndManifestsCallCount()).To(Equal(0))
   613  
   614  									translatedErr := translatableerror.ConvertToTranslatableError(executeErr)
   615  									_, ok := translatedErr.(translatableerror.TriggerLegacyPushError)
   616  									Expect(ok).To(BeTrue())
   617  								})
   618  							})
   619  						})
   620  
   621  						When("an app name and manifest are provided", func() {
   622  							var (
   623  								tmpDir         string
   624  								pathToManifest string
   625  
   626  								originalDir string
   627  							)
   628  
   629  							BeforeEach(func() {
   630  								var err error
   631  								tmpDir, err = ioutil.TempDir("", "push-command-test")
   632  								Expect(err).ToNot(HaveOccurred())
   633  
   634  								// OS X uses weird symlinks that causes problems for some tests
   635  								tmpDir, err = filepath.EvalSymlinks(tmpDir)
   636  								Expect(err).ToNot(HaveOccurred())
   637  
   638  								pathToManifest = filepath.Join(tmpDir, "manifest.yml")
   639  								err = ioutil.WriteFile(pathToManifest, []byte("some manfiest file"), 0666)
   640  								Expect(err).ToNot(HaveOccurred())
   641  
   642  								originalDir, err = os.Getwd()
   643  								Expect(err).ToNot(HaveOccurred())
   644  
   645  								err = os.Chdir(tmpDir)
   646  								Expect(err).ToNot(HaveOccurred())
   647  							})
   648  
   649  							AfterEach(func() {
   650  								Expect(os.Chdir(originalDir)).ToNot(HaveOccurred())
   651  								Expect(os.RemoveAll(tmpDir)).ToNot(HaveOccurred())
   652  							})
   653  
   654  							It("outputs corresponding flavor text", func() {
   655  								Expect(executeErr).ToNot(HaveOccurred())
   656  
   657  								Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`))
   658  								Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(pathToManifest)))
   659  							})
   660  						})
   661  
   662  						It("converts the manifests to app configs and outputs config warnings", func() {
   663  							Expect(executeErr).ToNot(HaveOccurred())
   664  
   665  							Expect(testUI.Err).To(Say("some-config-warnings"))
   666  
   667  							Expect(fakeActor.ConvertToApplicationConfigsCallCount()).To(Equal(1))
   668  							orgGUID, spaceGUID, noStart, manifests := fakeActor.ConvertToApplicationConfigsArgsForCall(0)
   669  							Expect(orgGUID).To(Equal("some-org-guid"))
   670  							Expect(spaceGUID).To(Equal("some-space-guid"))
   671  							Expect(noStart).To(BeFalse())
   672  							Expect(manifests).To(Equal(appManifests))
   673  						})
   674  
   675  						It("outputs flavor text prior to generating app configuration", func() {
   676  							Expect(executeErr).ToNot(HaveOccurred())
   677  							Expect(testUI.Out).To(Say("Pushing app %s to org some-org / space some-space as some-user", appName))
   678  							Expect(testUI.Out).To(Say(`Getting app info\.\.\.`))
   679  						})
   680  
   681  						It("applies each of the application configurations", func() {
   682  							Expect(executeErr).ToNot(HaveOccurred())
   683  
   684  							Expect(fakeActor.ApplyCallCount()).To(Equal(1))
   685  							config, progressBar := fakeActor.ApplyArgsForCall(0)
   686  							Expect(config).To(Equal(appConfigs[0]))
   687  							Expect(progressBar).To(Equal(fakeProgressBar))
   688  						})
   689  
   690  						It("display diff of changes", func() {
   691  							Expect(executeErr).ToNot(HaveOccurred())
   692  
   693  							Expect(testUI.Out).To(Say(`\s+name:\s+%s`, appName))
   694  							Expect(testUI.Out).To(Say(`\s+path:\s+%s`, regexp.QuoteMeta(appConfigs[0].Path)))
   695  							Expect(testUI.Out).To(Say(`\s+routes:`))
   696  							for _, route := range appConfigs[0].CurrentRoutes {
   697  								Expect(testUI.Out).To(Say(route.String()))
   698  							}
   699  							for _, route := range appConfigs[0].DesiredRoutes {
   700  								Expect(testUI.Out).To(Say(route.String()))
   701  							}
   702  						})
   703  
   704  						When("the app starts", func() {
   705  							It("displays app events and warnings", func() {
   706  								Expect(executeErr).ToNot(HaveOccurred())
   707  
   708  								Expect(testUI.Out).To(Say(`Creating app with these attributes\.\.\.`))
   709  								Expect(testUI.Out).To(Say(`Mapping routes\.\.\.`))
   710  								Expect(testUI.Out).To(Say(`Unmapping routes\.\.\.`))
   711  								Expect(testUI.Out).To(Say(`Binding services\.\.\.`))
   712  								Expect(testUI.Out).To(Say(`Comparing local files to remote cache\.\.\.`))
   713  								Expect(testUI.Out).To(Say("All files found in remote cache; nothing to upload."))
   714  								Expect(testUI.Out).To(Say(`Waiting for API to complete processing files\.\.\.`))
   715  								Expect(testUI.Out).To(Say(`Packaging files to upload\.\.\.`))
   716  								Expect(testUI.Out).To(Say(`Uploading files\.\.\.`))
   717  								Expect(testUI.Out).To(Say(`Retrying upload due to an error\.\.\.`))
   718  								Expect(testUI.Out).To(Say(`Waiting for API to complete processing files\.\.\.`))
   719  								Expect(testUI.Out).To(Say(`Stopping app\.\.\.`))
   720  
   721  								Expect(testUI.Err).To(Say("some-config-warnings"))
   722  								Expect(testUI.Err).To(Say("apply-1"))
   723  								Expect(testUI.Err).To(Say("apply-2"))
   724  							})
   725  
   726  							It("displays app staging logs", func() {
   727  								Expect(executeErr).ToNot(HaveOccurred())
   728  
   729  								Expect(testUI.Out).To(Say("log message 1"))
   730  								Expect(testUI.Out).To(Say("log message 2"))
   731  
   732  								Expect(fakeRestartActor.RestartApplicationCallCount()).To(Equal(1))
   733  								appConfig, _ := fakeRestartActor.RestartApplicationArgsForCall(0)
   734  								Expect(appConfig).To(Equal(updatedConfig.CurrentApplication.Application))
   735  							})
   736  
   737  							Context("Process Information", func() {
   738  								BeforeEach(func() {
   739  									fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceReturns(
   740  										v2v3action.ApplicationSummary{
   741  											ApplicationSummary: v3action.ApplicationSummary{
   742  												Application: v3action.Application{
   743  													Name: appName,
   744  												},
   745  												ProcessSummaries: v3action.ProcessSummaries{
   746  													{
   747  														Process: v3action.Process{
   748  															Type:       "aba",
   749  															Command:    *types.NewFilteredString("some-command-1"),
   750  															MemoryInMB: types.NullUint64{Value: 32, IsSet: true},
   751  															DiskInMB:   types.NullUint64{Value: 1024, IsSet: true},
   752  														},
   753  													},
   754  													{
   755  														Process: v3action.Process{
   756  															Type:       "console",
   757  															Command:    *types.NewFilteredString("some-command-2"),
   758  															MemoryInMB: types.NullUint64{Value: 16, IsSet: true},
   759  															DiskInMB:   types.NullUint64{Value: 512, IsSet: true},
   760  														},
   761  													},
   762  												},
   763  											},
   764  										},
   765  										v2v3action.Warnings{"combo-summary-warning"},
   766  										nil)
   767  								})
   768  
   769  								It("displays process information", func() {
   770  									Expect(executeErr).ToNot(HaveOccurred())
   771  
   772  									Expect(testUI.Out).To(Say(`name:\s+%s`, appName))
   773  									Expect(testUI.Out).To(Say(`type:\s+aba`))
   774  									Expect(testUI.Out).To(Say(`instances:\s+0/0`))
   775  									Expect(testUI.Out).To(Say(`memory usage:\s+32M`))
   776  									Expect(testUI.Out).To(Say(`start command:\s+some-command-1`))
   777  									Expect(testUI.Out).To(Say(`type:\s+console`))
   778  									Expect(testUI.Out).To(Say(`instances:\s+0/0`))
   779  									Expect(testUI.Out).To(Say(`memory usage:\s+16M`))
   780  									Expect(testUI.Out).To(Say(`start command:\s+some-command-2`))
   781  
   782  									Expect(testUI.Err).To(Say("combo-summary-warning"))
   783  
   784  									Expect(fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1))
   785  									passedAppName, spaceGUID, withObfuscatedValues := fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0)
   786  									Expect(passedAppName).To(Equal(appName))
   787  									Expect(spaceGUID).To(Equal("some-space-guid"))
   788  									Expect(withObfuscatedValues).To(BeTrue())
   789  								})
   790  							})
   791  
   792  							When("the start command is explicitly set", func() {
   793  								BeforeEach(func() {
   794  									v3ApplicationSummary := v3action.ApplicationSummary{
   795  										Application: v3action.Application{
   796  											Name: appName,
   797  										},
   798  										ProcessSummaries: v3action.ProcessSummaries{
   799  											{
   800  												Process: v3action.Process{
   801  													Type:       "aba",
   802  													Command:    *types.NewFilteredString("a-different-start-command"),
   803  													MemoryInMB: types.NullUint64{Value: 32, IsSet: true},
   804  													DiskInMB:   types.NullUint64{Value: 1024, IsSet: true},
   805  												},
   806  												InstanceDetails: []v3action.ProcessInstance{
   807  													v3action.ProcessInstance{
   808  														State: v3constant.ProcessInstanceRunning,
   809  													},
   810  												},
   811  											},
   812  										},
   813  									}
   814  
   815  									warnings := []string{"app-summary-warning"}
   816  									applicationSummary := v2v3action.ApplicationSummary{
   817  										ApplicationSummary: v3ApplicationSummary,
   818  									}
   819  
   820  									fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil)
   821  								})
   822  
   823  								It("displays the correct start command", func() {
   824  									Expect(executeErr).ToNot(HaveOccurred())
   825  									Expect(testUI.Out).To(Say(`name:\s+%s`, appName))
   826  									Expect(testUI.Out).To(Say(`start command:\s+a-different-start-command`))
   827  								})
   828  							})
   829  						})
   830  
   831  						When("no-start is set", func() {
   832  							BeforeEach(func() {
   833  								cmd.NoStart = true
   834  								v3ApplicationSummary := v3action.ApplicationSummary{
   835  									Application: v3action.Application{
   836  										Name:  appName,
   837  										State: v3constant.ApplicationStopped,
   838  									},
   839  									ProcessSummaries: v3action.ProcessSummaries{
   840  										{
   841  											Process: v3action.Process{
   842  												Type:       "aba",
   843  												Command:    *types.NewFilteredString("a-different-start-command"),
   844  												MemoryInMB: types.NullUint64{Value: 32, IsSet: true},
   845  												DiskInMB:   types.NullUint64{Value: 1024, IsSet: true},
   846  											},
   847  											InstanceDetails: []v3action.ProcessInstance{},
   848  										},
   849  									},
   850  								}
   851  
   852  								warnings := []string{"app-summary-warning"}
   853  								applicationSummary := v2v3action.ApplicationSummary{
   854  									ApplicationSummary: v3ApplicationSummary,
   855  								}
   856  
   857  								fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil)
   858  							})
   859  
   860  							When("the app is not running", func() {
   861  								It("does not start the app", func() {
   862  									Expect(executeErr).ToNot(HaveOccurred())
   863  									Expect(testUI.Out).To(Say(`Waiting for API to complete processing files\.\.\.`))
   864  									Expect(testUI.Out).To(Say(`name:\s+%s`, appName))
   865  									Expect(testUI.Out).To(Say(`requested state:\s+stopped`))
   866  
   867  									Expect(fakeRestartActor.RestartApplicationCallCount()).To(Equal(0))
   868  								})
   869  							})
   870  						})
   871  					})
   872  
   873  					When("the apply errors", func() {
   874  						var expectedErr error
   875  
   876  						BeforeEach(func() {
   877  							expectedErr = errors.New("no wayz dude")
   878  							fakeActor.ApplyStub = func(_ pushaction.ApplicationConfig, _ pushaction.ProgressBar) (<-chan pushaction.ApplicationConfig, <-chan pushaction.Event, <-chan pushaction.Warnings, <-chan error) {
   879  								configStream := make(chan pushaction.ApplicationConfig)
   880  								eventStream := make(chan pushaction.Event)
   881  								warningsStream := make(chan pushaction.Warnings)
   882  								errorStream := make(chan error)
   883  
   884  								go func() {
   885  									defer GinkgoRecover()
   886  
   887  									Eventually(warningsStream).Should(BeSent(pushaction.Warnings{"apply-1", "apply-2"}))
   888  									Eventually(errorStream).Should(BeSent(expectedErr))
   889  									close(configStream)
   890  									close(eventStream)
   891  									close(warningsStream)
   892  									close(errorStream)
   893  								}()
   894  
   895  								return configStream, eventStream, warningsStream, errorStream
   896  							}
   897  						})
   898  
   899  						It("outputs the warnings and returns the error", func() {
   900  							Expect(executeErr).To(MatchError(expectedErr))
   901  
   902  							Expect(testUI.Err).To(Say("some-config-warnings"))
   903  							Expect(testUI.Err).To(Say("apply-1"))
   904  							Expect(testUI.Err).To(Say("apply-2"))
   905  						})
   906  					})
   907  				})
   908  
   909  				When("there is an error converting the app setting into a config", func() {
   910  					var expectedErr error
   911  
   912  					BeforeEach(func() {
   913  						expectedErr = errors.New("no wayz dude")
   914  						fakeActor.ConvertToApplicationConfigsReturns(nil, pushaction.Warnings{"some-config-warnings"}, expectedErr)
   915  					})
   916  
   917  					It("outputs the warnings and returns the error", func() {
   918  						Expect(executeErr).To(MatchError(expectedErr))
   919  
   920  						Expect(testUI.Err).To(Say("some-config-warnings"))
   921  					})
   922  				})
   923  			})
   924  
   925  			When("the push settings are invalid", func() {
   926  				var expectedErr error
   927  
   928  				BeforeEach(func() {
   929  					expectedErr = errors.New("no wayz dude")
   930  					fakeActor.MergeAndValidateSettingsAndManifestsReturns(nil, expectedErr)
   931  				})
   932  
   933  				It("returns the error", func() {
   934  					Expect(executeErr).To(MatchError(expectedErr))
   935  				})
   936  			})
   937  		})
   938  	})
   939  
   940  	Describe("GetCommandLineSettings", func() {
   941  		Context("valid flag combinations", func() {
   942  			var (
   943  				settings               pushaction.CommandLineSettings
   944  				commandLineSettingsErr error
   945  			)
   946  
   947  			JustBeforeEach(func() {
   948  				settings, commandLineSettingsErr = cmd.GetCommandLineSettings()
   949  				Expect(commandLineSettingsErr).ToNot(HaveOccurred())
   950  			})
   951  
   952  			When("general app settings are given", func() {
   953  				BeforeEach(func() {
   954  					cmd.Buildpacks = []string{"some-buildpack"}
   955  					cmd.Command = flag.Command{FilteredString: types.FilteredString{IsSet: true, Value: "echo foo bar baz"}}
   956  					cmd.DiskQuota = flag.Megabytes{NullUint64: types.NullUint64{Value: 1024, IsSet: true}}
   957  					cmd.HealthCheckTimeout = 14
   958  					cmd.HealthCheckType = flag.HealthCheckTypeWithDeprecatedValue{Type: "http"}
   959  					cmd.Instances = flag.Instances{NullInt: types.NullInt{Value: 12, IsSet: true}}
   960  					cmd.Memory = flag.Megabytes{NullUint64: types.NullUint64{Value: 100, IsSet: true}}
   961  					cmd.StackName = "some-stack"
   962  				})
   963  
   964  				It("sets them on the command line settings", func() {
   965  					Expect(commandLineSettingsErr).ToNot(HaveOccurred())
   966  					Expect(settings.Buildpacks).To(ConsistOf("some-buildpack"))
   967  					Expect(settings.Command).To(Equal(types.FilteredString{IsSet: true, Value: "echo foo bar baz"}))
   968  					Expect(settings.DiskQuota).To(Equal(uint64(1024)))
   969  					Expect(settings.HealthCheckTimeout).To(BeEquivalentTo(14))
   970  					Expect(settings.HealthCheckType).To(Equal("http"))
   971  					Expect(settings.Instances).To(Equal(types.NullInt{Value: 12, IsSet: true}))
   972  					Expect(settings.Memory).To(Equal(uint64(100)))
   973  					Expect(settings.StackName).To(Equal("some-stack"))
   974  				})
   975  			})
   976  
   977  			Context("route related flags", func() {
   978  				When("given customed route settings", func() {
   979  					BeforeEach(func() {
   980  						cmd.Domain = "some-domain"
   981  					})
   982  
   983  					It("sets NoHostname on the command line settings", func() {
   984  						Expect(settings.DefaultRouteDomain).To(Equal("some-domain"))
   985  					})
   986  				})
   987  
   988  				When("--hostname is given", func() {
   989  					BeforeEach(func() {
   990  						cmd.Hostname = "some-hostname"
   991  					})
   992  
   993  					It("sets DefaultRouteHostname on the command line settings", func() {
   994  						Expect(settings.DefaultRouteHostname).To(Equal("some-hostname"))
   995  					})
   996  				})
   997  
   998  				When("--no-hostname is given", func() {
   999  					BeforeEach(func() {
  1000  						cmd.NoHostname = true
  1001  					})
  1002  
  1003  					It("sets NoHostname on the command line settings", func() {
  1004  						Expect(settings.NoHostname).To(BeTrue())
  1005  					})
  1006  				})
  1007  
  1008  				When("--random-route is given", func() {
  1009  					BeforeEach(func() {
  1010  						cmd.RandomRoute = true
  1011  					})
  1012  
  1013  					It("sets --random-route on the command line settings", func() {
  1014  						Expect(commandLineSettingsErr).ToNot(HaveOccurred())
  1015  						Expect(settings.RandomRoute).To(BeTrue())
  1016  					})
  1017  				})
  1018  
  1019  				When("--route-path is given", func() {
  1020  					BeforeEach(func() {
  1021  						cmd.RoutePath = flag.V6RoutePath{Path: "/some-path"}
  1022  					})
  1023  
  1024  					It("sets --route-path on the command line settings", func() {
  1025  						Expect(commandLineSettingsErr).ToNot(HaveOccurred())
  1026  						Expect(settings.RoutePath).To(Equal("/some-path"))
  1027  					})
  1028  				})
  1029  
  1030  				When("--no-route is given", func() {
  1031  					BeforeEach(func() {
  1032  						cmd.NoRoute = true
  1033  					})
  1034  
  1035  					It("sets NoRoute on the command line settings", func() {
  1036  						Expect(settings.NoRoute).To(BeTrue())
  1037  					})
  1038  				})
  1039  			})
  1040  
  1041  			Context("app bits", func() {
  1042  				When("-p flag is given", func() {
  1043  					BeforeEach(func() {
  1044  						cmd.AppPath = "some-directory-path"
  1045  					})
  1046  
  1047  					It("sets ProvidedAppPath", func() {
  1048  						Expect(settings.ProvidedAppPath).To(Equal("some-directory-path"))
  1049  					})
  1050  				})
  1051  
  1052  				When("the -o flag is given", func() {
  1053  					BeforeEach(func() {
  1054  						cmd.DockerImage.Path = "some-docker-image-path"
  1055  					})
  1056  
  1057  					It("creates command line setting from command line arguments", func() {
  1058  						Expect(settings.DockerImage).To(Equal("some-docker-image-path"))
  1059  					})
  1060  
  1061  					Context("--docker-username flags is given", func() {
  1062  						BeforeEach(func() {
  1063  							cmd.DockerUsername = "some-docker-username"
  1064  						})
  1065  
  1066  						Context("the docker password environment variable is set", func() {
  1067  							BeforeEach(func() {
  1068  								fakeConfig.DockerPasswordReturns("some-docker-password")
  1069  							})
  1070  
  1071  							It("creates command line setting from command line arguments and config", func() {
  1072  								Expect(testUI.Out).To(Say("Using docker repository password from environment variable CF_DOCKER_PASSWORD."))
  1073  
  1074  								Expect(settings.Name).To(Equal(appName))
  1075  								Expect(settings.DockerImage).To(Equal("some-docker-image-path"))
  1076  								Expect(settings.DockerUsername).To(Equal("some-docker-username"))
  1077  								Expect(settings.DockerPassword).To(Equal("some-docker-password"))
  1078  							})
  1079  						})
  1080  
  1081  						Context("the docker password environment variable is *not* set", func() {
  1082  							BeforeEach(func() {
  1083  								input.Write([]byte("some-docker-password\n"))
  1084  							})
  1085  
  1086  							It("prompts the user for a password", func() {
  1087  								Expect(testUI.Out).To(Say("Environment variable CF_DOCKER_PASSWORD not set."))
  1088  								Expect(testUI.Out).To(Say("Docker password"))
  1089  
  1090  								Expect(settings.Name).To(Equal(appName))
  1091  								Expect(settings.DockerImage).To(Equal("some-docker-image-path"))
  1092  								Expect(settings.DockerUsername).To(Equal("some-docker-username"))
  1093  								Expect(settings.DockerPassword).To(Equal("some-docker-password"))
  1094  							})
  1095  						})
  1096  					})
  1097  				})
  1098  			})
  1099  		})
  1100  
  1101  		DescribeTable("validation errors when flags are passed",
  1102  			func(setup func(), expectedErr error) {
  1103  				setup()
  1104  				_, commandLineSettingsErr := cmd.GetCommandLineSettings()
  1105  				Expect(commandLineSettingsErr).To(MatchError(expectedErr))
  1106  			},
  1107  
  1108  			Entry("--droplet and --docker-username",
  1109  				func() {
  1110  					cmd.DropletPath = "some-droplet-path"
  1111  					cmd.DockerUsername = "some-docker-username"
  1112  				},
  1113  				translatableerror.ArgumentCombinationError{Args: []string{"--droplet", "--docker-username", "-p"}}),
  1114  
  1115  			Entry("--droplet and --docker-image",
  1116  				func() {
  1117  					cmd.DropletPath = "some-droplet-path"
  1118  					cmd.DockerImage.Path = "some-docker-image"
  1119  				},
  1120  				translatableerror.ArgumentCombinationError{Args: []string{"--droplet", "--docker-image", "-o"}}),
  1121  
  1122  			Entry("--droplet and -p",
  1123  				func() {
  1124  					cmd.DropletPath = "some-droplet-path"
  1125  					cmd.AppPath = "some-directory-path"
  1126  				},
  1127  				translatableerror.ArgumentCombinationError{Args: []string{"--droplet", "-p"}}),
  1128  
  1129  			Entry("-o and -p",
  1130  				func() {
  1131  					cmd.DockerImage.Path = "some-docker-image"
  1132  					cmd.AppPath = "some-directory-path"
  1133  				},
  1134  				translatableerror.ArgumentCombinationError{Args: []string{"--docker-image, -o", "-p"}}),
  1135  
  1136  			Entry("-b and --docker-image",
  1137  				func() {
  1138  					cmd.DockerImage.Path = "some-docker-image"
  1139  					cmd.Buildpacks = []string{"some-buildpack"}
  1140  				},
  1141  				translatableerror.ArgumentCombinationError{Args: []string{"-b", "--docker-image, -o"}}),
  1142  
  1143  			Entry("--docker-username (without DOCKER_PASSWORD env set)",
  1144  				func() {
  1145  					cmd.DockerUsername = "some-docker-username"
  1146  				},
  1147  				translatableerror.RequiredFlagsError{Arg1: "--docker-image, -o", Arg2: "--docker-username"}),
  1148  
  1149  			Entry("-d and --no-route",
  1150  				func() {
  1151  					cmd.Domain = "some-domain"
  1152  					cmd.NoRoute = true
  1153  				},
  1154  				translatableerror.ArgumentCombinationError{Args: []string{"-d", "--no-route"}}),
  1155  
  1156  			Entry("--hostname and --no-hostname",
  1157  				func() {
  1158  					cmd.Hostname = "po-tate-toe"
  1159  					cmd.NoHostname = true
  1160  				},
  1161  				translatableerror.ArgumentCombinationError{Args: []string{"--hostname", "-n", "--no-hostname"}}),
  1162  
  1163  			Entry("--hostname and --no-route",
  1164  				func() {
  1165  					cmd.Hostname = "po-tate-toe"
  1166  					cmd.NoRoute = true
  1167  				},
  1168  				translatableerror.ArgumentCombinationError{Args: []string{"--hostname", "-n", "--no-route"}}),
  1169  
  1170  			Entry("--no-hostname and --no-route",
  1171  				func() {
  1172  					cmd.NoHostname = true
  1173  					cmd.NoRoute = true
  1174  				},
  1175  				translatableerror.ArgumentCombinationError{Args: []string{"--no-hostname", "--no-route"}}),
  1176  
  1177  			Entry("-f and --no-manifest",
  1178  				func() {
  1179  					cmd.PathToManifest = "/some/path.yml"
  1180  					cmd.NoManifest = true
  1181  				},
  1182  				translatableerror.ArgumentCombinationError{Args: []string{"-f", "--no-manifest"}}),
  1183  
  1184  			Entry("--random-route and --hostname",
  1185  				func() {
  1186  					cmd.Hostname = "po-tate-toe"
  1187  					cmd.RandomRoute = true
  1188  				},
  1189  				translatableerror.ArgumentCombinationError{Args: []string{"--hostname", "-n", "--random-route"}}),
  1190  
  1191  			Entry("--random-route and --no-hostname",
  1192  				func() {
  1193  					cmd.RandomRoute = true
  1194  					cmd.NoHostname = true
  1195  				},
  1196  				translatableerror.ArgumentCombinationError{Args: []string{"--no-hostname", "--random-route"}}),
  1197  
  1198  			Entry("--random-route and --no-route",
  1199  				func() {
  1200  					cmd.RandomRoute = true
  1201  					cmd.NoRoute = true
  1202  				},
  1203  				translatableerror.ArgumentCombinationError{Args: []string{"--no-route", "--random-route"}}),
  1204  
  1205  			Entry("--random-route and --route-path",
  1206  				func() {
  1207  					cmd.RoutePath = flag.V6RoutePath{Path: "/bananas"}
  1208  					cmd.RandomRoute = true
  1209  				},
  1210  				translatableerror.ArgumentCombinationError{Args: []string{"--random-route", "--route-path"}}),
  1211  
  1212  			Entry("--route-path and --no-route",
  1213  				func() {
  1214  					cmd.RoutePath = flag.V6RoutePath{Path: "/bananas"}
  1215  					cmd.NoRoute = true
  1216  				},
  1217  				translatableerror.ArgumentCombinationError{Args: []string{"--route-path", "--no-route"}}),
  1218  		)
  1219  	})
  1220  })