github.com/willmadison/cli@v6.40.1-0.20181018160101-29d5937903ff+incompatible/cf/commands/create_app_manifest_test.go (about)

     1  package commands_test
     2  
     3  import (
     4  	"errors"
     5  
     6  	"code.cloudfoundry.org/cli/cf/commandregistry"
     7  	"code.cloudfoundry.org/cli/cf/commands"
     8  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
     9  	"code.cloudfoundry.org/cli/cf/flags"
    10  	"code.cloudfoundry.org/cli/cf/manifest/manifestfakes"
    11  	"code.cloudfoundry.org/cli/cf/models"
    12  	"code.cloudfoundry.org/cli/cf/requirements"
    13  	"code.cloudfoundry.org/cli/cf/requirements/requirementsfakes"
    14  
    15  	"code.cloudfoundry.org/cli/cf/api/apifakes"
    16  	"code.cloudfoundry.org/cli/cf/api/stacks/stacksfakes"
    17  	testconfig "code.cloudfoundry.org/cli/cf/util/testhelpers/configuration"
    18  	testterm "code.cloudfoundry.org/cli/cf/util/testhelpers/terminal"
    19  
    20  	"os"
    21  
    22  	. "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers"
    23  	. "github.com/onsi/ginkgo"
    24  	. "github.com/onsi/gomega"
    25  )
    26  
    27  var _ = Describe("CreateAppManifest", func() {
    28  	var (
    29  		ui             *testterm.FakeUI
    30  		configRepo     coreconfig.Repository
    31  		appSummaryRepo *apifakes.FakeAppSummaryRepository
    32  		stackRepo      *stacksfakes.FakeStackRepository
    33  
    34  		cmd         commandregistry.Command
    35  		deps        commandregistry.Dependency
    36  		factory     *requirementsfakes.FakeFactory
    37  		flagContext flags.FlagContext
    38  
    39  		loginRequirement         requirements.Requirement
    40  		targetedSpaceRequirement requirements.Requirement
    41  		applicationRequirement   *requirementsfakes.FakeApplicationRequirement
    42  
    43  		fakeManifest *manifestfakes.FakeApp
    44  	)
    45  
    46  	BeforeEach(func() {
    47  		ui = &testterm.FakeUI{}
    48  		configRepo = testconfig.NewRepositoryWithDefaults()
    49  		appSummaryRepo = new(apifakes.FakeAppSummaryRepository)
    50  		repoLocator := deps.RepoLocator.SetAppSummaryRepository(appSummaryRepo)
    51  		stackRepo = new(stacksfakes.FakeStackRepository)
    52  		repoLocator = repoLocator.SetStackRepository(stackRepo)
    53  
    54  		fakeManifest = new(manifestfakes.FakeApp)
    55  
    56  		deps = commandregistry.Dependency{
    57  			UI:          ui,
    58  			Config:      configRepo,
    59  			RepoLocator: repoLocator,
    60  			AppManifest: fakeManifest,
    61  		}
    62  
    63  		cmd = &commands.CreateAppManifest{}
    64  		cmd.SetDependency(deps, false)
    65  
    66  		flagContext = flags.NewFlagContext(cmd.MetaData().Flags)
    67  		factory = new(requirementsfakes.FakeFactory)
    68  
    69  		loginRequirement = &passingRequirement{Name: "login-requirement"}
    70  		factory.NewLoginRequirementReturns(loginRequirement)
    71  
    72  		targetedSpaceRequirement = &passingRequirement{Name: "targeted-space-requirement"}
    73  		factory.NewTargetedSpaceRequirementReturns(targetedSpaceRequirement)
    74  
    75  		applicationRequirement = new(requirementsfakes.FakeApplicationRequirement)
    76  		application := models.Application{}
    77  		application.GUID = "app-guid"
    78  		applicationRequirement.GetApplicationReturns(application)
    79  		factory.NewApplicationRequirementReturns(applicationRequirement)
    80  	})
    81  
    82  	Describe("Requirements", func() {
    83  		Context("when not provided exactly one arg", func() {
    84  			BeforeEach(func() {
    85  				flagContext.Parse("app-name", "extra-arg")
    86  			})
    87  
    88  			It("fails with usage", func() {
    89  				_, err := cmd.Requirements(factory, flagContext)
    90  				Expect(err).To(HaveOccurred())
    91  				Expect(ui.Outputs()).To(ContainSubstrings(
    92  					[]string{"FAILED"},
    93  					[]string{"Incorrect Usage. Requires APP_NAME as argument"},
    94  				))
    95  			})
    96  		})
    97  
    98  		Context("when provided exactly one arg", func() {
    99  			BeforeEach(func() {
   100  				flagContext.Parse("app-name")
   101  			})
   102  
   103  			It("returns a LoginRequirement", func() {
   104  				actualRequirements, err := cmd.Requirements(factory, flagContext)
   105  				Expect(err).NotTo(HaveOccurred())
   106  				Expect(actualRequirements).To(ContainElement(loginRequirement))
   107  			})
   108  
   109  			It("returns an ApplicationRequirement", func() {
   110  				actualRequirements, err := cmd.Requirements(factory, flagContext)
   111  				Expect(err).NotTo(HaveOccurred())
   112  				Expect(actualRequirements).To(ContainElement(applicationRequirement))
   113  			})
   114  
   115  			It("returns a TargetedSpaceRequirement", func() {
   116  				actualRequirements, err := cmd.Requirements(factory, flagContext)
   117  				Expect(err).NotTo(HaveOccurred())
   118  				Expect(actualRequirements).To(ContainElement(targetedSpaceRequirement))
   119  			})
   120  		})
   121  	})
   122  
   123  	Describe("Execute", func() {
   124  		var (
   125  			application models.Application
   126  			runCLIErr   error
   127  		)
   128  
   129  		BeforeEach(func() {
   130  			err := flagContext.Parse("app-name")
   131  			Expect(err).NotTo(HaveOccurred())
   132  			cmd.Requirements(factory, flagContext)
   133  
   134  			application = models.Application{}
   135  			application.Name = "app-name"
   136  		})
   137  
   138  		JustBeforeEach(func() {
   139  			runCLIErr = cmd.Execute(flagContext)
   140  		})
   141  
   142  		AfterEach(func() {
   143  			os.Remove("app-name_manifest.yml")
   144  		})
   145  
   146  		Context("when there is an app summary", func() {
   147  			BeforeEach(func() {
   148  				appSummaryRepo.GetSummaryReturns(application, nil)
   149  			})
   150  
   151  			It("tries to get the app summary", func() {
   152  				Expect(runCLIErr).NotTo(HaveOccurred())
   153  				Expect(appSummaryRepo.GetSummaryCallCount()).To(Equal(1))
   154  			})
   155  		})
   156  
   157  		Context("when there is an error getting the app summary", func() {
   158  			BeforeEach(func() {
   159  				appSummaryRepo.GetSummaryReturns(models.Application{}, errors.New("get-summary-err"))
   160  			})
   161  
   162  			It("prints an error", func() {
   163  				Expect(runCLIErr).To(HaveOccurred())
   164  				Expect(runCLIErr.Error()).To(Equal("Error getting application summary: get-summary-err"))
   165  			})
   166  		})
   167  
   168  		Context("when getting the app summary succeeds", func() {
   169  			BeforeEach(func() {
   170  				application.Memory = 1024
   171  				application.InstanceCount = 2
   172  				application.StackGUID = "the-stack-guid"
   173  				appSummaryRepo.GetSummaryReturns(application, nil)
   174  			})
   175  
   176  			It("sets memory", func() {
   177  				Expect(runCLIErr).NotTo(HaveOccurred())
   178  				Expect(fakeManifest.MemoryCallCount()).To(Equal(1))
   179  				name, memory := fakeManifest.MemoryArgsForCall(0)
   180  				Expect(name).To(Equal("app-name"))
   181  				Expect(memory).To(Equal(int64(1024)))
   182  			})
   183  
   184  			It("sets instances", func() {
   185  				Expect(runCLIErr).NotTo(HaveOccurred())
   186  				Expect(fakeManifest.InstancesCallCount()).To(Equal(1))
   187  				name, instances := fakeManifest.InstancesArgsForCall(0)
   188  				Expect(name).To(Equal("app-name"))
   189  				Expect(instances).To(Equal(2))
   190  			})
   191  
   192  			It("tries to get stacks", func() {
   193  				Expect(runCLIErr).NotTo(HaveOccurred())
   194  				Expect(stackRepo.FindByGUIDCallCount()).To(Equal(1))
   195  				Expect(stackRepo.FindByGUIDArgsForCall(0)).To(Equal("the-stack-guid"))
   196  			})
   197  
   198  			Context("when getting stacks succeeds", func() {
   199  				BeforeEach(func() {
   200  					stackRepo.FindByGUIDReturns(models.Stack{
   201  						GUID: "the-stack-guid",
   202  						Name: "the-stack-name",
   203  					}, nil)
   204  				})
   205  
   206  				It("sets the stacks", func() {
   207  					Expect(runCLIErr).NotTo(HaveOccurred())
   208  					Expect(fakeManifest.StackCallCount()).To(Equal(1))
   209  					name, stackName := fakeManifest.StackArgsForCall(0)
   210  					Expect(name).To(Equal("app-name"))
   211  					Expect(stackName).To(Equal("the-stack-name"))
   212  				})
   213  			})
   214  
   215  			Context("when getting stacks fails", func() {
   216  				BeforeEach(func() {
   217  					stackRepo.FindByGUIDReturns(models.Stack{}, errors.New("find-by-guid-err"))
   218  				})
   219  
   220  				It("fails with error", func() {
   221  					Expect(runCLIErr).To(HaveOccurred())
   222  					Expect(runCLIErr.Error()).To(Equal("Error retrieving stack: find-by-guid-err"))
   223  				})
   224  			})
   225  
   226  			It("tries to save the manifest", func() {
   227  				Expect(runCLIErr).NotTo(HaveOccurred())
   228  				Expect(fakeManifest.SaveCallCount()).To(Equal(1))
   229  			})
   230  
   231  			Context("when saving the manifest succeeds", func() {
   232  				BeforeEach(func() {
   233  					fakeManifest.SaveReturns(nil)
   234  				})
   235  
   236  				It("says OK", func() {
   237  					Expect(runCLIErr).NotTo(HaveOccurred())
   238  					Expect(ui.Outputs()).To(ContainSubstrings(
   239  						[]string{"OK"},
   240  						[]string{"Manifest file created successfully at ./app-name_manifest.yml"},
   241  					))
   242  				})
   243  			})
   244  
   245  			Context("when saving the manifest fails", func() {
   246  				BeforeEach(func() {
   247  					fakeManifest.SaveReturns(errors.New("save-err"))
   248  				})
   249  
   250  				It("fails with error", func() {
   251  					Expect(runCLIErr).To(HaveOccurred())
   252  					Expect(runCLIErr.Error()).To(Equal("Error creating manifest file: save-err"))
   253  				})
   254  			})
   255  
   256  			Context("when the app has a command", func() {
   257  				BeforeEach(func() {
   258  					application.Command = "app-command"
   259  					appSummaryRepo.GetSummaryReturns(application, nil)
   260  				})
   261  
   262  				It("sets the start command", func() {
   263  					Expect(runCLIErr).NotTo(HaveOccurred())
   264  					Expect(fakeManifest.StartCommandCallCount()).To(Equal(1))
   265  					name, command := fakeManifest.StartCommandArgsForCall(0)
   266  					Expect(name).To(Equal("app-name"))
   267  					Expect(command).To(Equal("app-command"))
   268  				})
   269  			})
   270  
   271  			Context("when the app has a buildpack", func() {
   272  				BeforeEach(func() {
   273  					application.BuildpackURL = "buildpack"
   274  					appSummaryRepo.GetSummaryReturns(application, nil)
   275  				})
   276  
   277  				It("sets the buildpack", func() {
   278  					Expect(runCLIErr).NotTo(HaveOccurred())
   279  					Expect(fakeManifest.BuildpackURLCallCount()).To(Equal(1))
   280  					name, buildpack := fakeManifest.BuildpackURLArgsForCall(0)
   281  					Expect(name).To(Equal("app-name"))
   282  					Expect(buildpack).To(Equal("buildpack"))
   283  				})
   284  			})
   285  
   286  			Context("when the app has services", func() {
   287  				BeforeEach(func() {
   288  					application.Services = []models.ServicePlanSummary{
   289  						{
   290  							Name: "sp1-name",
   291  						},
   292  						{
   293  							Name: "sp2-name",
   294  						},
   295  					}
   296  					appSummaryRepo.GetSummaryReturns(application, nil)
   297  				})
   298  
   299  				It("sets the services", func() {
   300  					Expect(runCLIErr).NotTo(HaveOccurred())
   301  					Expect(fakeManifest.ServiceCallCount()).To(Equal(2))
   302  
   303  					name, service := fakeManifest.ServiceArgsForCall(0)
   304  					Expect(name).To(Equal("app-name"))
   305  					Expect(service).To(Equal("sp1-name"))
   306  
   307  					name, service = fakeManifest.ServiceArgsForCall(1)
   308  					Expect(name).To(Equal("app-name"))
   309  					Expect(service).To(Equal("sp2-name"))
   310  				})
   311  			})
   312  
   313  			Context("when the app has a health check timeout", func() {
   314  				BeforeEach(func() {
   315  					application.HealthCheckTimeout = 5
   316  					appSummaryRepo.GetSummaryReturns(application, nil)
   317  				})
   318  
   319  				It("sets the health check timeout", func() {
   320  					Expect(runCLIErr).NotTo(HaveOccurred())
   321  					Expect(fakeManifest.HealthCheckTimeoutCallCount()).To(Equal(1))
   322  					name, timeout := fakeManifest.HealthCheckTimeoutArgsForCall(0)
   323  					Expect(name).To(Equal("app-name"))
   324  					Expect(timeout).To(Equal(5))
   325  				})
   326  			})
   327  
   328  			Context("when the app has environment vars", func() {
   329  				BeforeEach(func() {
   330  					application.EnvironmentVars = map[string]interface{}{
   331  						"float64-key": float64(5),
   332  						"bool-key":    true,
   333  						"string-key":  "string",
   334  					}
   335  					appSummaryRepo.GetSummaryReturns(application, nil)
   336  				})
   337  
   338  				It("sets the env vars", func() {
   339  					Expect(runCLIErr).NotTo(HaveOccurred())
   340  					Expect(fakeManifest.EnvironmentVarsCallCount()).To(Equal(3))
   341  					actuals := map[string]interface{}{}
   342  
   343  					for i := 0; i < 3; i++ {
   344  						name, k, v := fakeManifest.EnvironmentVarsArgsForCall(i)
   345  						Expect(name).To(Equal("app-name"))
   346  						actuals[k] = v
   347  					}
   348  
   349  					Expect(actuals["float64-key"]).To(Equal("5"))
   350  					Expect(actuals["bool-key"]).To(Equal("true"))
   351  					Expect(actuals["string-key"]).To(Equal("string"))
   352  				})
   353  			})
   354  
   355  			Context("when the app has an environment var of an unsupported type", func() {
   356  				BeforeEach(func() {
   357  					application.EnvironmentVars = map[string]interface{}{
   358  						"key": int(1),
   359  					}
   360  					appSummaryRepo.GetSummaryReturns(application, nil)
   361  				})
   362  
   363  				It("fails with error", func() {
   364  					Expect(runCLIErr).To(HaveOccurred())
   365  					Expect(runCLIErr.Error()).To(Equal("Failed to create manifest, unable to parse environment variable: key"))
   366  				})
   367  			})
   368  
   369  			Context("when the app has routes", func() {
   370  				BeforeEach(func() {
   371  					application.Routes = []models.RouteSummary{
   372  						{
   373  							Host: "route-1-host",
   374  							Domain: models.DomainFields{
   375  								Name: "http-domain",
   376  							},
   377  							Path: "path",
   378  							Port: 0,
   379  						},
   380  						{
   381  							Host: "",
   382  							Domain: models.DomainFields{
   383  								Name: "tcp-domain",
   384  							},
   385  							Path: "",
   386  							Port: 123,
   387  						},
   388  					}
   389  					appSummaryRepo.GetSummaryReturns(application, nil)
   390  				})
   391  
   392  				It("sets the domains", func() {
   393  					Expect(runCLIErr).NotTo(HaveOccurred())
   394  					Expect(fakeManifest.RouteCallCount()).To(Equal(2))
   395  
   396  					name, host, domainName, path, port := fakeManifest.RouteArgsForCall(0)
   397  					Expect(name).To(Equal("app-name"))
   398  					Expect(host).To(Equal("route-1-host"))
   399  					Expect(domainName).To(Equal("http-domain"))
   400  					Expect(path).To(Equal("path"))
   401  					Expect(port).To(Equal(0))
   402  
   403  					name, host, domainName, path, port = fakeManifest.RouteArgsForCall(1)
   404  					Expect(name).To(Equal("app-name"))
   405  					Expect(host).To(Equal(""))
   406  					Expect(domainName).To(Equal("tcp-domain"))
   407  					Expect(path).To(Equal(""))
   408  					Expect(port).To(Equal(123))
   409  				})
   410  			})
   411  
   412  			Context("when the app has a disk quota", func() {
   413  				BeforeEach(func() {
   414  					application.DiskQuota = 1024
   415  					appSummaryRepo.GetSummaryReturns(application, nil)
   416  				})
   417  
   418  				It("sets the disk quota", func() {
   419  					Expect(runCLIErr).NotTo(HaveOccurred())
   420  					Expect(fakeManifest.DiskQuotaCallCount()).To(Equal(1))
   421  					name, quota := fakeManifest.DiskQuotaArgsForCall(0)
   422  					Expect(name).To(Equal("app-name"))
   423  					Expect(quota).To(Equal(int64(1024)))
   424  				})
   425  			})
   426  
   427  			Context("when the app has health check type", func() {
   428  				Context("when the health check type is port", func() {
   429  					BeforeEach(func() {
   430  						application.HealthCheckType = "port"
   431  						appSummaryRepo.GetSummaryReturns(application, nil)
   432  					})
   433  
   434  					It("does not set the health check type nor the endpoint", func() {
   435  						Expect(runCLIErr).NotTo(HaveOccurred())
   436  
   437  						Expect(fakeManifest.HealthCheckTypeCallCount()).To(Equal(0))
   438  						Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(0))
   439  					})
   440  				})
   441  
   442  				Context("when the health check type is process", func() {
   443  					BeforeEach(func() {
   444  						application.HealthCheckType = "process"
   445  						appSummaryRepo.GetSummaryReturns(application, nil)
   446  					})
   447  
   448  					It("sets the health check type but not the endpoint", func() {
   449  						Expect(runCLIErr).NotTo(HaveOccurred())
   450  
   451  						Expect(fakeManifest.HealthCheckTypeCallCount()).To(Equal(1))
   452  						name, healthCheckType := fakeManifest.HealthCheckTypeArgsForCall(0)
   453  						Expect(name).To(Equal("app-name"))
   454  						Expect(healthCheckType).To(Equal("process"))
   455  						Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(0))
   456  					})
   457  				})
   458  
   459  				Context("when the health check type is none", func() {
   460  					BeforeEach(func() {
   461  						application.HealthCheckType = "none"
   462  						appSummaryRepo.GetSummaryReturns(application, nil)
   463  					})
   464  
   465  					It("sets the health check type but not the endpoint", func() {
   466  						Expect(runCLIErr).NotTo(HaveOccurred())
   467  
   468  						Expect(fakeManifest.HealthCheckTypeCallCount()).To(Equal(1))
   469  						name, healthCheckType := fakeManifest.HealthCheckTypeArgsForCall(0)
   470  						Expect(name).To(Equal("app-name"))
   471  						Expect(healthCheckType).To(Equal("none"))
   472  						Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(0))
   473  					})
   474  				})
   475  
   476  				Context("when the health check type is http", func() {
   477  					BeforeEach(func() {
   478  						application.HealthCheckType = "http"
   479  						appSummaryRepo.GetSummaryReturns(application, nil)
   480  					})
   481  
   482  					It("sets the health check type", func() {
   483  						Expect(runCLIErr).NotTo(HaveOccurred())
   484  
   485  						Expect(fakeManifest.HealthCheckTypeCallCount()).To(Equal(1))
   486  						name, healthCheckType := fakeManifest.HealthCheckTypeArgsForCall(0)
   487  						Expect(name).To(Equal("app-name"))
   488  						Expect(healthCheckType).To(Equal("http"))
   489  					})
   490  
   491  					Context("when the health check endpoint is the empty string", func() {
   492  						BeforeEach(func() {
   493  							application.HealthCheckHTTPEndpoint = ""
   494  							appSummaryRepo.GetSummaryReturns(application, nil)
   495  						})
   496  
   497  						It("does not set the health check endpoint", func() {
   498  							Expect(runCLIErr).NotTo(HaveOccurred())
   499  
   500  							Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(0))
   501  						})
   502  					})
   503  
   504  					Context("when the health check endpoint is /", func() {
   505  						BeforeEach(func() {
   506  							application.HealthCheckHTTPEndpoint = "/"
   507  							appSummaryRepo.GetSummaryReturns(application, nil)
   508  						})
   509  
   510  						It("does not set the health check endpoint", func() {
   511  							Expect(runCLIErr).NotTo(HaveOccurred())
   512  
   513  							Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(0))
   514  						})
   515  					})
   516  
   517  					Context("when the health check endpoint is not /", func() {
   518  						BeforeEach(func() {
   519  							application.HealthCheckHTTPEndpoint = "/some-endpoint"
   520  							appSummaryRepo.GetSummaryReturns(application, nil)
   521  						})
   522  
   523  						It("sets the health check endpoint", func() {
   524  							Expect(runCLIErr).NotTo(HaveOccurred())
   525  
   526  							Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(1))
   527  							name, healthCheckHTTPEndpoint := fakeManifest.HealthCheckHTTPEndpointArgsForCall(0)
   528  							Expect(name).To(Equal("app-name"))
   529  							Expect(healthCheckHTTPEndpoint).To(Equal("/some-endpoint"))
   530  						})
   531  					})
   532  				})
   533  			})
   534  		})
   535  	})
   536  })