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