github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/cf/manifest/manifest_test.go (about) 1 package manifest_test 2 3 import ( 4 "runtime" 5 "strings" 6 7 "code.cloudfoundry.org/cli/cf/manifest" 8 "code.cloudfoundry.org/cli/util/generic" 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 12 . "code.cloudfoundry.org/cli/util/testhelpers/matchers" 13 ) 14 15 func NewManifest(path string, data generic.Map) (m *manifest.Manifest) { 16 return &manifest.Manifest{Path: path, Data: data} 17 } 18 19 var _ = Describe("Manifests", func() { 20 It("merges global properties into each app's properties", func() { 21 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 22 "instances": "3", 23 "memory": "512M", 24 "applications": []interface{}{ 25 map[interface{}]interface{}{ 26 "name": "bitcoin-miner", 27 "no-route": true, 28 }, 29 }, 30 })) 31 32 apps, err := m.Applications() 33 Expect(err).NotTo(HaveOccurred()) 34 35 Expect(*apps[0].InstanceCount).To(Equal(3)) 36 Expect(*apps[0].Memory).To(Equal(int64(512))) 37 Expect(apps[0].NoRoute).To(BeTrue()) 38 }) 39 40 Context("when there is no applications block", func() { 41 It("returns a single application with the global properties", func() { 42 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 43 "instances": "3", 44 "memory": "512M", 45 })) 46 47 apps, err := m.Applications() 48 Expect(err).NotTo(HaveOccurred()) 49 50 Expect(len(apps)).To(Equal(1)) 51 Expect(*apps[0].InstanceCount).To(Equal(3)) 52 Expect(*apps[0].Memory).To(Equal(int64(512))) 53 }) 54 }) 55 56 It("returns an error when the memory limit doesn't have a unit", func() { 57 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 58 "instances": "3", 59 "memory": "512", 60 "applications": []interface{}{ 61 map[interface{}]interface{}{ 62 "name": "bitcoin-miner", 63 }, 64 }, 65 })) 66 67 _, err := m.Applications() 68 Expect(err).To(HaveOccurred()) 69 Expect(err.Error()).To(ContainSubstring("Invalid value for 'memory': 512")) 70 }) 71 72 It("returns an error when the memory limit is a non-string", func() { 73 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 74 "instances": "3", 75 "memory": 128, 76 "applications": []interface{}{ 77 map[interface{}]interface{}{ 78 "name": "bitcoin-miner", 79 }, 80 }, 81 })) 82 83 _, err := m.Applications() 84 Expect(err).To(HaveOccurred()) 85 Expect(err.Error()).To(ContainSubstring("Invalid value for 'memory': 128")) 86 }) 87 88 It("sets applications' health check timeouts", func() { 89 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 90 "applications": []interface{}{ 91 map[interface{}]interface{}{ 92 "name": "bitcoin-miner", 93 "timeout": "360", 94 }, 95 }, 96 })) 97 98 apps, err := m.Applications() 99 Expect(err).NotTo(HaveOccurred()) 100 Expect(*apps[0].HealthCheckTimeout).To(Equal(360)) 101 }) 102 103 It("allows boolean env var values", func() { 104 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 105 "env": generic.NewMap(map[interface{}]interface{}{ 106 "bar": true, 107 }), 108 })) 109 110 _, err := m.Applications() 111 Expect(err).ToNot(HaveOccurred()) 112 }) 113 114 It("allows nil value for global env if env is present in the app", func() { 115 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 116 "env": nil, 117 "applications": []interface{}{ 118 map[interface{}]interface{}{ 119 "name": "bad app", 120 "env": map[interface{}]interface{}{ 121 "foo": "bar", 122 }, 123 }, 124 }, 125 })) 126 127 apps, err := m.Applications() 128 Expect(err).NotTo(HaveOccurred()) 129 Expect(*apps[0].EnvironmentVars).To(Equal(map[string]interface{}{"foo": "bar"})) 130 }) 131 132 It("does not allow nil value for env in application", func() { 133 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 134 "env": generic.NewMap(map[interface{}]interface{}{ 135 "foo": "bar", 136 }), 137 "applications": []interface{}{ 138 map[interface{}]interface{}{ 139 "name": "bad app", 140 "env": nil, 141 }, 142 }, 143 })) 144 145 _, err := m.Applications() 146 Expect(err).To(HaveOccurred()) 147 Expect(err.Error()).To(ContainSubstring("env should not be null")) 148 }) 149 150 It("does not allow nil values for environment variables", func() { 151 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 152 "env": generic.NewMap(map[interface{}]interface{}{ 153 "bar": nil, 154 }), 155 "applications": []interface{}{ 156 map[interface{}]interface{}{ 157 "name": "bad app", 158 }, 159 }, 160 })) 161 162 _, err := m.Applications() 163 Expect(err).To(HaveOccurred()) 164 Expect(err.Error()).To(ContainSubstring("env var 'bar' should not be null")) 165 }) 166 167 It("returns an empty map when no env was present in the manifest", func() { 168 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 169 "applications": []interface{}{ 170 map[interface{}]interface{}{"name": "no-env-vars"}, 171 }, 172 })) 173 174 apps, err := m.Applications() 175 Expect(err).NotTo(HaveOccurred()) 176 Expect(*apps[0].EnvironmentVars).NotTo(BeNil()) 177 }) 178 179 It("allows applications to have absolute paths", func() { 180 if runtime.GOOS == "windows" { 181 m := NewManifest(`C:\some\path\manifest.yml`, generic.NewMap(map[interface{}]interface{}{ 182 "applications": []interface{}{ 183 map[interface{}]interface{}{ 184 "path": `C:\another\path`, 185 }, 186 }, 187 })) 188 189 apps, err := m.Applications() 190 Expect(err).NotTo(HaveOccurred()) 191 Expect(*apps[0].Path).To(Equal(`C:\another\path`)) 192 } else { 193 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 194 "applications": []interface{}{ 195 map[interface{}]interface{}{ 196 "path": "/another/path-segment", 197 }, 198 }, 199 })) 200 201 apps, err := m.Applications() 202 Expect(err).NotTo(HaveOccurred()) 203 Expect(*apps[0].Path).To(Equal("/another/path-segment")) 204 } 205 }) 206 207 It("expands relative app paths based on the manifest's path", func() { 208 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 209 "applications": []interface{}{ 210 map[interface{}]interface{}{ 211 "path": "../another/path-segment", 212 }, 213 }, 214 })) 215 216 apps, err := m.Applications() 217 Expect(err).NotTo(HaveOccurred()) 218 if runtime.GOOS == "windows" { 219 Expect(*apps[0].Path).To(Equal("\\some\\another\\path-segment")) 220 } else { 221 Expect(*apps[0].Path).To(Equal("/some/another/path-segment")) 222 } 223 }) 224 225 It("returns errors when there are null values", func() { 226 m := NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{ 227 "applications": []interface{}{ 228 map[interface{}]interface{}{ 229 "disk_quota": nil, 230 "domain": nil, 231 "host": nil, 232 "name": nil, 233 "path": nil, 234 "stack": nil, 235 "memory": nil, 236 "instances": nil, 237 "timeout": nil, 238 "no-route": nil, 239 "no-hostname": nil, 240 "services": nil, 241 "env": nil, 242 "random-route": nil, 243 }, 244 }, 245 })) 246 247 _, err := m.Applications() 248 Expect(err).To(HaveOccurred()) 249 errorSlice := strings.Split(err.Error(), "\n") 250 manifestKeys := []string{"disk_quota", "domain", "host", "name", "path", "stack", 251 "memory", "instances", "timeout", "no-route", "no-hostname", "services", "env", "random-route"} 252 253 for _, key := range manifestKeys { 254 Expect(errorSlice).To(ContainSubstrings([]string{key, "not be null"})) 255 } 256 }) 257 258 It("returns errors when hosts/domains is not valid slice", func() { 259 m := NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{ 260 "applications": []interface{}{ 261 map[interface{}]interface{}{ 262 "hosts": "bad-value", 263 "domains": []interface{}{"val1", "val2", false, true}, 264 }, 265 }, 266 })) 267 268 _, err := m.Applications() 269 Expect(err).To(HaveOccurred()) 270 errorSlice := strings.Split(err.Error(), "\n") 271 272 Expect(errorSlice).To(ContainSubstrings([]string{"hosts", "to be a list of strings"})) 273 Expect(errorSlice).To(ContainSubstrings([]string{"domains", "to be a list of strings"})) 274 }) 275 276 It("parses known manifest keys", func() { 277 m := NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{ 278 "applications": []interface{}{ 279 map[interface{}]interface{}{ 280 "buildpack": "my-buildpack", 281 "disk_quota": "512M", 282 "domain": "my-domain", 283 "domains": []interface{}{"domain1.test", "domain2.test"}, 284 "host": "my-hostname", 285 "hosts": []interface{}{"host-1", "host-2"}, 286 "name": "my-app-name", 287 "stack": "my-stack", 288 "memory": "256M", 289 "health-check-type": "none", 290 "instances": 1, 291 "timeout": 11, 292 "no-route": true, 293 "no-hostname": true, 294 "random-route": true, 295 "docker": map[interface{}]interface{}{ 296 "image": "docker.com:3333/docker/docker:some-tag", 297 }, 298 }, 299 }, 300 })) 301 302 apps, err := m.Applications() 303 Expect(err).NotTo(HaveOccurred()) 304 Expect(len(apps)).To(Equal(1)) 305 306 Expect(*apps[0].BuildpackURL).To(Equal("my-buildpack")) 307 Expect(*apps[0].DiskQuota).To(Equal(int64(512))) 308 Expect(apps[0].Domains).To(ConsistOf([]string{"domain1.test", "domain2.test", "my-domain"})) 309 Expect(apps[0].Hosts).To(ConsistOf([]string{"host-1", "host-2", "my-hostname"})) 310 Expect(*apps[0].Name).To(Equal("my-app-name")) 311 Expect(*apps[0].StackName).To(Equal("my-stack")) 312 Expect(*apps[0].HealthCheckType).To(Equal("none")) 313 Expect(*apps[0].Memory).To(Equal(int64(256))) 314 Expect(*apps[0].InstanceCount).To(Equal(1)) 315 Expect(*apps[0].HealthCheckTimeout).To(Equal(11)) 316 Expect(apps[0].NoRoute).To(BeTrue()) 317 Expect(*apps[0].NoHostname).To(BeTrue()) 318 Expect(apps[0].UseRandomRoute).To(BeTrue()) 319 Expect(*apps[0].DockerImage).To(Equal("docker.com:3333/docker/docker:some-tag")) 320 }) 321 322 Context("when the health-check-type is 'http'", func() { 323 Context("when health-check-http-endpoint IS provided", func() { 324 It("sets http-health-check-endpoint to the provided endpoint", func() { 325 m := NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{ 326 "applications": []interface{}{ 327 map[interface{}]interface{}{ 328 "health-check-type": "http", 329 "health-check-http-endpoint": "/some-endpoint", 330 }, 331 }, 332 })) 333 334 apps, err := m.Applications() 335 Expect(err).NotTo(HaveOccurred()) 336 Expect(len(apps)).To(Equal(1)) 337 338 Expect(*apps[0].HealthCheckType).To(Equal("http")) 339 Expect(*apps[0].HealthCheckHTTPEndpoint).To(Equal("/some-endpoint")) 340 }) 341 }) 342 }) 343 344 It("removes duplicated values in 'hosts' and 'domains'", func() { 345 m := NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{ 346 "applications": []interface{}{ 347 map[interface{}]interface{}{ 348 "domain": "my-domain", 349 "domains": []interface{}{"my-domain", "domain1.test", "domain1.test", "domain2.test"}, 350 "host": "my-hostname", 351 "hosts": []interface{}{"my-hostname", "host-1", "host-1", "host-2"}, 352 "name": "my-app-name", 353 }, 354 }, 355 })) 356 357 apps, err := m.Applications() 358 Expect(err).NotTo(HaveOccurred()) 359 Expect(len(apps)).To(Equal(1)) 360 361 Expect(len(apps[0].Domains)).To(Equal(3)) 362 Expect(apps[0].Domains).To(ConsistOf([]string{"my-domain", "domain1.test", "domain2.test"})) 363 Expect(len(apps[0].Hosts)).To(Equal(3)) 364 Expect(apps[0].Hosts).To(ConsistOf([]string{"my-hostname", "host-1", "host-2"})) 365 }) 366 367 It("sets the command and buildpack to blank when their values are null in the manifest", func() { 368 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 369 "applications": []interface{}{ 370 generic.NewMap(map[interface{}]interface{}{ 371 "buildpack": nil, 372 "command": nil, 373 }), 374 }, 375 })) 376 377 apps, err := m.Applications() 378 Expect(err).NotTo(HaveOccurred()) 379 Expect(*apps[0].Command).To(Equal("")) 380 Expect(*apps[0].BuildpackURL).To(Equal("")) 381 }) 382 383 It("sets the command and buildpack to blank when their values are 'default' in the manifest", func() { 384 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 385 "applications": []interface{}{ 386 generic.NewMap(map[interface{}]interface{}{ 387 "command": "default", 388 "buildpack": "default", 389 }), 390 }, 391 })) 392 393 apps, err := m.Applications() 394 Expect(err).NotTo(HaveOccurred()) 395 Expect(*apps[0].Command).To(Equal("")) 396 Expect(*apps[0].BuildpackURL).To(Equal("")) 397 }) 398 399 It("does not set the start command when the manifest doesn't have the 'command' key", func() { 400 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 401 "applications": []interface{}{ 402 map[interface{}]interface{}{}, 403 }, 404 })) 405 406 apps, err := m.Applications() 407 Expect(err).NotTo(HaveOccurred()) 408 Expect(apps[0].Command).To(BeNil()) 409 }) 410 411 It("can build the applications multiple times", func() { 412 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 413 "memory": "254m", 414 "applications": []interface{}{ 415 map[interface{}]interface{}{ 416 "name": "bitcoin-miner", 417 }, 418 map[interface{}]interface{}{ 419 "name": "bitcoin-miner", 420 }, 421 }, 422 })) 423 424 apps1, err := m.Applications() 425 Expect(err).NotTo(HaveOccurred()) 426 427 apps2, err := m.Applications() 428 Expect(err).NotTo(HaveOccurred()) 429 Expect(apps1).To(Equal(apps2)) 430 }) 431 432 Context("parsing app ports", func() { 433 It("parses app ports", func() { 434 m := NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{ 435 "applications": []interface{}{ 436 map[interface{}]interface{}{ 437 "app-ports": []interface{}{ 438 8080, 439 9090, 440 }, 441 }, 442 }, 443 })) 444 445 apps, err := m.Applications() 446 Expect(err).NotTo(HaveOccurred()) 447 448 Expect(apps[0].AppPorts).NotTo(BeNil()) 449 Expect(*(apps[0].AppPorts)).To(Equal([]int{8080, 9090})) 450 }) 451 452 It("handles omitted field", func() { 453 m := NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{ 454 "applications": []interface{}{ 455 map[interface{}]interface{}{}, 456 }, 457 })) 458 459 apps, err := m.Applications() 460 Expect(err).NotTo(HaveOccurred()) 461 462 Expect(apps[0].AppPorts).To(BeNil()) 463 }) 464 465 It("handles mixed arrays", func() { 466 m := NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{ 467 "applications": []interface{}{ 468 map[interface{}]interface{}{ 469 "app-ports": []interface{}{ 470 8080, 471 "potato", 472 }, 473 }, 474 }, 475 })) 476 477 _, err := m.Applications() 478 Expect(err).To(HaveOccurred()) 479 Expect(err.Error()).To(ContainSubstring("Expected app-ports to be a list of integers.")) 480 }) 481 482 It("handles non-array values", func() { 483 m := NewManifest("/some/path", generic.NewMap(map[interface{}]interface{}{ 484 "applications": []interface{}{ 485 map[interface{}]interface{}{ 486 "app-ports": "potato", 487 }, 488 }, 489 })) 490 491 _, err := m.Applications() 492 Expect(err).To(HaveOccurred()) 493 Expect(err.Error()).To(ContainSubstring("Expected app-ports to be a list of integers.")) 494 }) 495 }) 496 497 Context("parsing env vars", func() { 498 It("handles values that are not strings", func() { 499 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 500 "applications": []interface{}{ 501 generic.NewMap(map[interface{}]interface{}{ 502 "env": map[interface{}]interface{}{ 503 "string-key": "value", 504 "int-key": 1, 505 "float-key": 11.1, 506 "large-int-key": 123456789, 507 "large-float-key": 123456789.12345678, 508 "bool-key": false, 509 }, 510 }), 511 }, 512 })) 513 514 app, err := m.Applications() 515 Expect(err).NotTo(HaveOccurred()) 516 517 Expect((*app[0].EnvironmentVars)["string-key"]).To(Equal("value")) 518 Expect((*app[0].EnvironmentVars)["int-key"]).To(Equal("1")) 519 Expect((*app[0].EnvironmentVars)["float-key"]).To(Equal("11.1")) 520 Expect((*app[0].EnvironmentVars)["large-int-key"]).To(Equal("123456789")) 521 Expect((*app[0].EnvironmentVars)["large-float-key"]).To(Equal("123456789.12345678")) 522 Expect((*app[0].EnvironmentVars)["bool-key"]).To(Equal("false")) 523 }) 524 }) 525 526 Context("parsing services", func() { 527 It("can read a list of service instance names", func() { 528 m := NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 529 "services": []interface{}{"service-1", "service-2"}, 530 })) 531 532 app, err := m.Applications() 533 Expect(err).NotTo(HaveOccurred()) 534 535 Expect(app[0].ServicesToBind).To(Equal([]string{"service-1", "service-2"})) 536 }) 537 }) 538 539 Context("when routes are provided", func() { 540 var manifest *manifest.Manifest 541 542 Context("when passed 'routes'", func() { 543 Context("valid 'routes'", func() { 544 BeforeEach(func() { 545 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 546 "applications": []interface{}{ 547 generic.NewMap(map[interface{}]interface{}{ 548 "routes": []interface{}{ 549 map[interface{}]interface{}{"route": "route1.example.com"}, 550 map[interface{}]interface{}{"route": "route2.example.com"}, 551 }, 552 }), 553 }, 554 })) 555 }) 556 557 It("parses routes into app params", func() { 558 apps, err := manifest.Applications() 559 Expect(err).NotTo(HaveOccurred()) 560 Expect(apps).To(HaveLen(1)) 561 562 routes := apps[0].Routes 563 Expect(routes).To(HaveLen(2)) 564 Expect(routes[0].Route).To(Equal("route1.example.com")) 565 Expect(routes[1].Route).To(Equal("route2.example.com")) 566 }) 567 }) 568 569 Context("invalid 'routes'", func() { 570 Context("'routes' is formatted incorrectly", func() { 571 BeforeEach(func() { 572 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 573 "applications": []interface{}{ 574 generic.NewMap(map[interface{}]interface{}{ 575 "routes": []string{}, 576 }), 577 }, 578 })) 579 }) 580 581 It("errors out", func() { 582 _, err := manifest.Applications() 583 Expect(err).To(HaveOccurred()) 584 Expect(err.Error()).To(MatchRegexp("should be a list")) 585 }) 586 }) 587 588 Context("an individual 'route' is formatted incorrectly", func() { 589 BeforeEach(func() { 590 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 591 "applications": []interface{}{ 592 generic.NewMap(map[interface{}]interface{}{ 593 "routes": []interface{}{ 594 map[interface{}]interface{}{"routef": "route1.example.com"}, 595 }, 596 }), 597 }, 598 })) 599 }) 600 601 It("parses routes into app params", func() { 602 _, err := manifest.Applications() 603 Expect(err).To(HaveOccurred()) 604 Expect(err.Error()).To(MatchRegexp("each route in 'routes' must have a 'route' property")) 605 }) 606 }) 607 }) 608 }) 609 610 Context("when there are no routes", func() { 611 BeforeEach(func() { 612 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 613 "applications": []interface{}{ 614 generic.NewMap(map[interface{}]interface{}{ 615 "buildpack": nil, 616 "command": "echo banana", 617 }), 618 }, 619 })) 620 }) 621 622 It("sets routes to be nil", func() { 623 apps, err := manifest.Applications() 624 Expect(err).NotTo(HaveOccurred()) 625 Expect(apps).To(HaveLen(1)) 626 Expect(apps[0].Routes).To(BeNil()) 627 }) 628 }) 629 630 Context("when no-hostname is not specified in the manifest", func() { 631 BeforeEach(func() { 632 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 633 "applications": []interface{}{ 634 generic.NewMap(map[interface{}]interface{}{ 635 "buildpack": nil, 636 "command": "echo banana", 637 }), 638 }, 639 })) 640 }) 641 642 It("sets no-hostname to be nil", func() { 643 apps, err := manifest.Applications() 644 Expect(err).NotTo(HaveOccurred()) 645 Expect(apps).To(HaveLen(1)) 646 Expect(apps[0].NoHostname).To(BeNil()) 647 }) 648 }) 649 650 Context("when no-hostname is specified in the manifest", func() { 651 Context("and it is set to true", func() { 652 Context("and the value is a boolean", func() { 653 BeforeEach(func() { 654 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 655 "applications": []interface{}{ 656 generic.NewMap(map[interface{}]interface{}{ 657 "buildpack": nil, 658 "command": "echo banana", 659 "no-hostname": true, 660 }), 661 }, 662 })) 663 }) 664 665 It("sets no-hostname to be true", func() { 666 apps, err := manifest.Applications() 667 Expect(err).NotTo(HaveOccurred()) 668 Expect(apps).To(HaveLen(1)) 669 Expect(*apps[0].NoHostname).To(BeTrue()) 670 }) 671 }) 672 Context("and the value is a string", func() { 673 BeforeEach(func() { 674 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 675 "applications": []interface{}{ 676 generic.NewMap(map[interface{}]interface{}{ 677 "buildpack": nil, 678 "command": "echo banana", 679 "no-hostname": "true", 680 }), 681 }, 682 })) 683 }) 684 685 It("sets no-hostname to be true", func() { 686 apps, err := manifest.Applications() 687 Expect(err).NotTo(HaveOccurred()) 688 Expect(apps).To(HaveLen(1)) 689 Expect(*apps[0].NoHostname).To(BeTrue()) 690 }) 691 }) 692 }) 693 Context("and it is set to false", func() { 694 BeforeEach(func() { 695 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 696 "applications": []interface{}{ 697 generic.NewMap(map[interface{}]interface{}{ 698 "buildpack": nil, 699 "command": "echo banana", 700 "no-hostname": false, 701 }), 702 }, 703 })) 704 }) 705 It("sets no-hostname to be false", func() { 706 apps, err := manifest.Applications() 707 Expect(err).NotTo(HaveOccurred()) 708 Expect(apps).To(HaveLen(1)) 709 Expect(*apps[0].NoHostname).To(BeFalse()) 710 }) 711 }) 712 }) 713 }) 714 715 Context("when the 'docker' property is not specified", func() { 716 var manifest *manifest.Manifest 717 718 BeforeEach(func() { 719 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 720 "applications": []interface{}{ 721 generic.NewMap(map[interface{}]interface{}{}), 722 }, 723 })) 724 }) 725 726 It("returns a parsed manifest that does not contain any docker fields", func() { 727 apps, err := manifest.Applications() 728 Expect(err).NotTo(HaveOccurred()) 729 Expect(apps).To(HaveLen(1)) 730 Expect(apps[0].DockerImage).To(BeNil()) 731 Expect(apps[0].DockerUsername).To(BeNil()) 732 }) 733 }) 734 735 Context("when the 'docker' property is specified but contains no properties", func() { 736 var manifest *manifest.Manifest 737 738 BeforeEach(func() { 739 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 740 "applications": []interface{}{ 741 generic.NewMap(map[interface{}]interface{}{ 742 "docker": map[interface{}]interface{}{}, 743 }), 744 }, 745 })) 746 }) 747 748 It("returns a parsed manifest that does not contain any docker fields", func() { 749 apps, err := manifest.Applications() 750 Expect(err).NotTo(HaveOccurred()) 751 Expect(apps).To(HaveLen(1)) 752 Expect(apps[0].DockerImage).To(BeNil()) 753 Expect(apps[0].DockerUsername).To(BeNil()) 754 }) 755 }) 756 757 Context("when the 'docker' property is specified", func() { 758 var manifest *manifest.Manifest 759 760 Context("when 'docker' contains an 'image' property", func() { 761 Context("when the 'image' property is not a string", func() { 762 BeforeEach(func() { 763 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 764 "applications": []interface{}{ 765 generic.NewMap(map[interface{}]interface{}{ 766 "docker": map[interface{}]interface{}{ 767 "image": []interface{}{}, 768 }, 769 }), 770 }, 771 })) 772 }) 773 774 It("returns an error", func() { 775 _, err := manifest.Applications() 776 Expect(err.Error()).To(MatchRegexp("'docker.image' must be a string")) 777 }) 778 }) 779 780 Context("when the 'image' property is a string", func() { 781 BeforeEach(func() { 782 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 783 "applications": []interface{}{ 784 generic.NewMap(map[interface{}]interface{}{ 785 "docker": map[interface{}]interface{}{ 786 "image": "docker.com:3333/docker/docker:tag", 787 }, 788 }), 789 }, 790 })) 791 }) 792 793 It("sets DockerImage to the 'image' property value", func() { 794 apps, err := manifest.Applications() 795 Expect(err).NotTo(HaveOccurred()) 796 Expect(apps).To(HaveLen(1)) 797 Expect(*apps[0].DockerImage).To(Equal("docker.com:3333/docker/docker:tag")) 798 }) 799 }) 800 }) 801 802 Context("when 'docker' contains a 'username' property", func() { 803 Context("when 'username' is not a string", func() { 804 BeforeEach(func() { 805 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 806 "applications": []interface{}{ 807 generic.NewMap(map[interface{}]interface{}{ 808 "docker": map[interface{}]interface{}{ 809 "username": []interface{}{}, 810 }, 811 }), 812 }, 813 })) 814 }) 815 816 It("returns an error", func() { 817 _, err := manifest.Applications() 818 Expect(err.Error()).To(MatchRegexp("'docker.username' must be a string")) 819 }) 820 }) 821 822 Context("when 'username' is a string", func() { 823 BeforeEach(func() { 824 manifest = NewManifest("/some/path/manifest.yml", generic.NewMap(map[interface{}]interface{}{ 825 "applications": []interface{}{ 826 generic.NewMap(map[interface{}]interface{}{ 827 "docker": map[interface{}]interface{}{ 828 "username": "some-user", 829 }, 830 }), 831 }, 832 })) 833 }) 834 835 It("sets DockerUsername to the 'username' property value", func() { 836 apps, err := manifest.Applications() 837 Expect(err).NotTo(HaveOccurred()) 838 Expect(apps).To(HaveLen(1)) 839 Expect(*apps[0].DockerUsername).To(Equal("some-user")) 840 }) 841 }) 842 }) 843 }) 844 })