github.com/swisscom/cloudfoundry-cli@v7.1.0+incompatible/cf/commands/create_app_manifest_test.go (about)

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