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 })