github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+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/util/testhelpers/configuration"
    18  	testterm "code.cloudfoundry.org/cli/util/testhelpers/terminal"
    19  
    20  	"os"
    21  
    22  	. "code.cloudfoundry.org/cli/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  			Context("when there are app ports specified", func() {
   193  				BeforeEach(func() {
   194  					application.AppPorts = []int{1111, 2222}
   195  					appSummaryRepo.GetSummaryReturns(application, nil)
   196  				})
   197  
   198  				It("sets app ports", func() {
   199  					Expect(runCLIErr).NotTo(HaveOccurred())
   200  					Expect(fakeManifest.AppPortsCallCount()).To(Equal(1))
   201  					name, appPorts := fakeManifest.AppPortsArgsForCall(0)
   202  					Expect(name).To(Equal("app-name"))
   203  					Expect(appPorts).To(Equal([]int{1111, 2222}))
   204  				})
   205  			})
   206  
   207  			Context("when app ports are not specified", func() {
   208  				It("does not set app ports", func() {
   209  					Expect(runCLIErr).NotTo(HaveOccurred())
   210  					Expect(fakeManifest.AppPortsCallCount()).To(Equal(0))
   211  				})
   212  			})
   213  
   214  			It("tries to get stacks", func() {
   215  				Expect(runCLIErr).NotTo(HaveOccurred())
   216  				Expect(stackRepo.FindByGUIDCallCount()).To(Equal(1))
   217  				Expect(stackRepo.FindByGUIDArgsForCall(0)).To(Equal("the-stack-guid"))
   218  			})
   219  
   220  			Context("when getting stacks succeeds", func() {
   221  				BeforeEach(func() {
   222  					stackRepo.FindByGUIDReturns(models.Stack{
   223  						GUID: "the-stack-guid",
   224  						Name: "the-stack-name",
   225  					}, nil)
   226  				})
   227  
   228  				It("sets the stacks", func() {
   229  					Expect(runCLIErr).NotTo(HaveOccurred())
   230  					Expect(fakeManifest.StackCallCount()).To(Equal(1))
   231  					name, stackName := fakeManifest.StackArgsForCall(0)
   232  					Expect(name).To(Equal("app-name"))
   233  					Expect(stackName).To(Equal("the-stack-name"))
   234  				})
   235  			})
   236  
   237  			Context("when getting stacks fails", func() {
   238  				BeforeEach(func() {
   239  					stackRepo.FindByGUIDReturns(models.Stack{}, errors.New("find-by-guid-err"))
   240  				})
   241  
   242  				It("fails with error", func() {
   243  					Expect(runCLIErr).To(HaveOccurred())
   244  					Expect(runCLIErr.Error()).To(Equal("Error retrieving stack: find-by-guid-err"))
   245  				})
   246  			})
   247  
   248  			It("tries to save the manifest", func() {
   249  				Expect(runCLIErr).NotTo(HaveOccurred())
   250  				Expect(fakeManifest.SaveCallCount()).To(Equal(1))
   251  			})
   252  
   253  			Context("when saving the manifest succeeds", func() {
   254  				BeforeEach(func() {
   255  					fakeManifest.SaveReturns(nil)
   256  				})
   257  
   258  				It("says OK", func() {
   259  					Expect(runCLIErr).NotTo(HaveOccurred())
   260  					Expect(ui.Outputs()).To(ContainSubstrings(
   261  						[]string{"OK"},
   262  						[]string{"Manifest file created successfully at ./app-name_manifest.yml"},
   263  					))
   264  				})
   265  			})
   266  
   267  			Context("when saving the manifest fails", func() {
   268  				BeforeEach(func() {
   269  					fakeManifest.SaveReturns(errors.New("save-err"))
   270  				})
   271  
   272  				It("fails with error", func() {
   273  					Expect(runCLIErr).To(HaveOccurred())
   274  					Expect(runCLIErr.Error()).To(Equal("Error creating manifest file: save-err"))
   275  				})
   276  			})
   277  
   278  			Context("when the app has a command", func() {
   279  				BeforeEach(func() {
   280  					application.Command = "app-command"
   281  					appSummaryRepo.GetSummaryReturns(application, nil)
   282  				})
   283  
   284  				It("sets the start command", func() {
   285  					Expect(runCLIErr).NotTo(HaveOccurred())
   286  					Expect(fakeManifest.StartCommandCallCount()).To(Equal(1))
   287  					name, command := fakeManifest.StartCommandArgsForCall(0)
   288  					Expect(name).To(Equal("app-name"))
   289  					Expect(command).To(Equal("app-command"))
   290  				})
   291  			})
   292  
   293  			Context("when the app has a buildpack", func() {
   294  				BeforeEach(func() {
   295  					application.BuildpackURL = "buildpack"
   296  					appSummaryRepo.GetSummaryReturns(application, nil)
   297  				})
   298  
   299  				It("sets the buildpack", func() {
   300  					Expect(runCLIErr).NotTo(HaveOccurred())
   301  					Expect(fakeManifest.BuildpackURLCallCount()).To(Equal(1))
   302  					name, buildpack := fakeManifest.BuildpackURLArgsForCall(0)
   303  					Expect(name).To(Equal("app-name"))
   304  					Expect(buildpack).To(Equal("buildpack"))
   305  				})
   306  			})
   307  
   308  			Context("when the app has services", func() {
   309  				BeforeEach(func() {
   310  					application.Services = []models.ServicePlanSummary{
   311  						{
   312  							Name: "sp1-name",
   313  						},
   314  						{
   315  							Name: "sp2-name",
   316  						},
   317  					}
   318  					appSummaryRepo.GetSummaryReturns(application, nil)
   319  				})
   320  
   321  				It("sets the services", func() {
   322  					Expect(runCLIErr).NotTo(HaveOccurred())
   323  					Expect(fakeManifest.ServiceCallCount()).To(Equal(2))
   324  
   325  					name, service := fakeManifest.ServiceArgsForCall(0)
   326  					Expect(name).To(Equal("app-name"))
   327  					Expect(service).To(Equal("sp1-name"))
   328  
   329  					name, service = fakeManifest.ServiceArgsForCall(1)
   330  					Expect(name).To(Equal("app-name"))
   331  					Expect(service).To(Equal("sp2-name"))
   332  				})
   333  			})
   334  
   335  			Context("when the app has a health check timeout", func() {
   336  				BeforeEach(func() {
   337  					application.HealthCheckTimeout = 5
   338  					appSummaryRepo.GetSummaryReturns(application, nil)
   339  				})
   340  
   341  				It("sets the health check timeout", func() {
   342  					Expect(runCLIErr).NotTo(HaveOccurred())
   343  					Expect(fakeManifest.HealthCheckTimeoutCallCount()).To(Equal(1))
   344  					name, timeout := fakeManifest.HealthCheckTimeoutArgsForCall(0)
   345  					Expect(name).To(Equal("app-name"))
   346  					Expect(timeout).To(Equal(5))
   347  				})
   348  			})
   349  
   350  			Context("when the app has environment vars", func() {
   351  				BeforeEach(func() {
   352  					application.EnvironmentVars = map[string]interface{}{
   353  						"float64-key": float64(5),
   354  						"bool-key":    true,
   355  						"string-key":  "string",
   356  					}
   357  					appSummaryRepo.GetSummaryReturns(application, nil)
   358  				})
   359  
   360  				It("sets the env vars", func() {
   361  					Expect(runCLIErr).NotTo(HaveOccurred())
   362  					Expect(fakeManifest.EnvironmentVarsCallCount()).To(Equal(3))
   363  					actuals := map[string]interface{}{}
   364  
   365  					for i := 0; i < 3; i++ {
   366  						name, k, v := fakeManifest.EnvironmentVarsArgsForCall(i)
   367  						Expect(name).To(Equal("app-name"))
   368  						actuals[k] = v
   369  					}
   370  
   371  					Expect(actuals["float64-key"]).To(Equal("5"))
   372  					Expect(actuals["bool-key"]).To(Equal("true"))
   373  					Expect(actuals["string-key"]).To(Equal("string"))
   374  				})
   375  			})
   376  
   377  			Context("when the app has an environment var of an unsupported type", func() {
   378  				BeforeEach(func() {
   379  					application.EnvironmentVars = map[string]interface{}{
   380  						"key": int(1),
   381  					}
   382  					appSummaryRepo.GetSummaryReturns(application, nil)
   383  				})
   384  
   385  				It("fails with error", func() {
   386  					Expect(runCLIErr).To(HaveOccurred())
   387  					Expect(runCLIErr.Error()).To(Equal("Failed to create manifest, unable to parse environment variable: key"))
   388  				})
   389  			})
   390  
   391  			Context("when the app has routes", func() {
   392  				BeforeEach(func() {
   393  					application.Routes = []models.RouteSummary{
   394  						{
   395  							Host: "route-1-host",
   396  							Domain: models.DomainFields{
   397  								Name: "http-domain",
   398  							},
   399  							Path: "path",
   400  							Port: 0,
   401  						},
   402  						{
   403  							Host: "",
   404  							Domain: models.DomainFields{
   405  								Name: "tcp-domain",
   406  							},
   407  							Path: "",
   408  							Port: 123,
   409  						},
   410  					}
   411  					appSummaryRepo.GetSummaryReturns(application, nil)
   412  				})
   413  
   414  				It("sets the domains", func() {
   415  					Expect(runCLIErr).NotTo(HaveOccurred())
   416  					Expect(fakeManifest.RouteCallCount()).To(Equal(2))
   417  
   418  					name, host, domainName, path, port := fakeManifest.RouteArgsForCall(0)
   419  					Expect(name).To(Equal("app-name"))
   420  					Expect(host).To(Equal("route-1-host"))
   421  					Expect(domainName).To(Equal("http-domain"))
   422  					Expect(path).To(Equal("path"))
   423  					Expect(port).To(Equal(0))
   424  
   425  					name, host, domainName, path, port = fakeManifest.RouteArgsForCall(1)
   426  					Expect(name).To(Equal("app-name"))
   427  					Expect(host).To(Equal(""))
   428  					Expect(domainName).To(Equal("tcp-domain"))
   429  					Expect(path).To(Equal(""))
   430  					Expect(port).To(Equal(123))
   431  				})
   432  			})
   433  
   434  			Context("when the app has a disk quota", func() {
   435  				BeforeEach(func() {
   436  					application.DiskQuota = 1024
   437  					appSummaryRepo.GetSummaryReturns(application, nil)
   438  				})
   439  
   440  				It("sets the disk quota", func() {
   441  					Expect(runCLIErr).NotTo(HaveOccurred())
   442  					Expect(fakeManifest.DiskQuotaCallCount()).To(Equal(1))
   443  					name, quota := fakeManifest.DiskQuotaArgsForCall(0)
   444  					Expect(name).To(Equal("app-name"))
   445  					Expect(quota).To(Equal(int64(1024)))
   446  				})
   447  			})
   448  
   449  			Context("when the app has health check type", func() {
   450  				Context("when the health check type is port", func() {
   451  					BeforeEach(func() {
   452  						application.HealthCheckType = "port"
   453  						appSummaryRepo.GetSummaryReturns(application, nil)
   454  					})
   455  
   456  					It("does not set the health check type nor the endpoint", func() {
   457  						Expect(runCLIErr).NotTo(HaveOccurred())
   458  
   459  						Expect(fakeManifest.HealthCheckTypeCallCount()).To(Equal(0))
   460  						Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(0))
   461  					})
   462  				})
   463  
   464  				Context("when the health check type is process", func() {
   465  					BeforeEach(func() {
   466  						application.HealthCheckType = "process"
   467  						appSummaryRepo.GetSummaryReturns(application, nil)
   468  					})
   469  
   470  					It("sets the health check type but not the endpoint", func() {
   471  						Expect(runCLIErr).NotTo(HaveOccurred())
   472  
   473  						Expect(fakeManifest.HealthCheckTypeCallCount()).To(Equal(1))
   474  						name, healthCheckType := fakeManifest.HealthCheckTypeArgsForCall(0)
   475  						Expect(name).To(Equal("app-name"))
   476  						Expect(healthCheckType).To(Equal("process"))
   477  						Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(0))
   478  					})
   479  				})
   480  
   481  				Context("when the health check type is none", func() {
   482  					BeforeEach(func() {
   483  						application.HealthCheckType = "none"
   484  						appSummaryRepo.GetSummaryReturns(application, nil)
   485  					})
   486  
   487  					It("sets the health check type but not the endpoint", func() {
   488  						Expect(runCLIErr).NotTo(HaveOccurred())
   489  
   490  						Expect(fakeManifest.HealthCheckTypeCallCount()).To(Equal(1))
   491  						name, healthCheckType := fakeManifest.HealthCheckTypeArgsForCall(0)
   492  						Expect(name).To(Equal("app-name"))
   493  						Expect(healthCheckType).To(Equal("none"))
   494  						Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(0))
   495  					})
   496  				})
   497  
   498  				Context("when the health check type is http", func() {
   499  					BeforeEach(func() {
   500  						application.HealthCheckType = "http"
   501  						appSummaryRepo.GetSummaryReturns(application, nil)
   502  					})
   503  
   504  					It("sets the health check type", func() {
   505  						Expect(runCLIErr).NotTo(HaveOccurred())
   506  
   507  						Expect(fakeManifest.HealthCheckTypeCallCount()).To(Equal(1))
   508  						name, healthCheckType := fakeManifest.HealthCheckTypeArgsForCall(0)
   509  						Expect(name).To(Equal("app-name"))
   510  						Expect(healthCheckType).To(Equal("http"))
   511  					})
   512  
   513  					Context("when the health check endpoint is the empty string", func() {
   514  						BeforeEach(func() {
   515  							application.HealthCheckHTTPEndpoint = ""
   516  							appSummaryRepo.GetSummaryReturns(application, nil)
   517  						})
   518  
   519  						It("does not set the health check endpoint", func() {
   520  							Expect(runCLIErr).NotTo(HaveOccurred())
   521  
   522  							Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(0))
   523  						})
   524  					})
   525  
   526  					Context("when the health check endpoint is /", func() {
   527  						BeforeEach(func() {
   528  							application.HealthCheckHTTPEndpoint = "/"
   529  							appSummaryRepo.GetSummaryReturns(application, nil)
   530  						})
   531  
   532  						It("does not set the health check endpoint", func() {
   533  							Expect(runCLIErr).NotTo(HaveOccurred())
   534  
   535  							Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(0))
   536  						})
   537  					})
   538  
   539  					Context("when the health check endpoint is not /", func() {
   540  						BeforeEach(func() {
   541  							application.HealthCheckHTTPEndpoint = "/some-endpoint"
   542  							appSummaryRepo.GetSummaryReturns(application, nil)
   543  						})
   544  
   545  						It("sets the health check endpoint", func() {
   546  							Expect(runCLIErr).NotTo(HaveOccurred())
   547  
   548  							Expect(fakeManifest.HealthCheckHTTPEndpointCallCount()).To(Equal(1))
   549  							name, healthCheckHTTPEndpoint := fakeManifest.HealthCheckHTTPEndpointArgsForCall(0)
   550  							Expect(name).To(Equal("app-name"))
   551  							Expect(healthCheckHTTPEndpoint).To(Equal("/some-endpoint"))
   552  						})
   553  					})
   554  				})
   555  			})
   556  		})
   557  	})
   558  })