github.com/openshift-online/ocm-sdk-go@v0.1.420/configuration/object_test.go (about) 1 /* 2 Copyright (c) 2020 Red Hat, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // This file contains tests for the configuration object. 18 19 package configuration 20 21 import ( 22 "os" 23 "path/filepath" 24 "strings" 25 26 "gopkg.in/yaml.v3" 27 28 . "github.com/onsi/ginkgo/v2/dsl/core" // nolint 29 . "github.com/onsi/ginkgo/v2/dsl/table" // nolint 30 . "github.com/onsi/gomega" // nolint 31 ) 32 33 var _ = Describe("Object", func() { 34 Describe("Load", func() { 35 It("Can be loaded from bytes", func() { 36 // Load the configuration: 37 object, err := New(). 38 Load([]byte(`mykey: myvalue`)). 39 Build() 40 Expect(err).ToNot(HaveOccurred()) 41 Expect(object).ToNot(BeNil()) 42 43 // Populate the configuration: 44 var config struct { 45 MyKey string `yaml:"mykey"` 46 } 47 err = object.Populate(&config) 48 Expect(err).ToNot(HaveOccurred()) 49 Expect(config.MyKey).To(Equal("myvalue")) 50 }) 51 52 It("Can be loaded from string", func() { 53 // Load the configuration: 54 object, err := New(). 55 Load(`mykey: myvalue`). 56 Build() 57 Expect(err).ToNot(HaveOccurred()) 58 Expect(object).ToNot(BeNil()) 59 60 // Populate the configuration: 61 var config struct { 62 MyKey string `yaml:"mykey"` 63 } 64 err = object.Populate(&config) 65 Expect(err).ToNot(HaveOccurred()) 66 Expect(config.MyKey).To(Equal("myvalue")) 67 }) 68 69 It("Can be loaded from reader", func() { 70 // Load the configuration: 71 object, err := New(). 72 Load(strings.NewReader(`mykey: myvalue`)). 73 Build() 74 Expect(err).ToNot(HaveOccurred()) 75 Expect(object).ToNot(BeNil()) 76 77 // Populate the configuration: 78 var config struct { 79 MyKey string `yaml:"mykey"` 80 } 81 err = object.Populate(&config) 82 Expect(err).ToNot(HaveOccurred()) 83 Expect(config.MyKey).To(Equal("myvalue")) 84 }) 85 86 It("Can be loaded from file", func() { 87 // Create a temporary file containing the configuration: 88 tmp, err := os.CreateTemp("", "*.test.yaml") 89 Expect(err).ToNot(HaveOccurred()) 90 defer func() { 91 err = os.Remove(tmp.Name()) 92 Expect(err).ToNot(HaveOccurred()) 93 }() 94 _, err = tmp.Write([]byte(`mykey: myvalue`)) 95 Expect(err).ToNot(HaveOccurred()) 96 err = tmp.Close() 97 Expect(err).ToNot(HaveOccurred()) 98 99 // Load the configuration: 100 object, err := New(). 101 Load(tmp.Name()). 102 Build() 103 Expect(err).ToNot(HaveOccurred()) 104 Expect(object).ToNot(BeNil()) 105 106 // Populate the configuration: 107 var config struct { 108 MyKey string `yaml:"mykey"` 109 } 110 err = object.Populate(&config) 111 Expect(err).ToNot(HaveOccurred()) 112 Expect(config.MyKey).To(Equal("myvalue")) 113 }) 114 115 It("Can be loaded from struct", func() { 116 // Load the configuration: 117 type Source struct { 118 MyKey string `yaml:"mykey"` 119 } 120 object, err := New(). 121 Load(&Source{ 122 MyKey: "myvalue", 123 }). 124 Build() 125 Expect(err).ToNot(HaveOccurred()) 126 Expect(object).ToNot(BeNil()) 127 128 // Populate the configuration: 129 var config struct { 130 MyKey string `yaml:"mykey"` 131 } 132 err = object.Populate(&config) 133 Expect(err).ToNot(HaveOccurred()) 134 Expect(config.MyKey).To(Equal("myvalue")) 135 }) 136 137 It("Can be loaded from map", func() { 138 // Load the configuration: 139 object, err := New(). 140 Load(map[string]string{ 141 "mykey": "myvalue", 142 }). 143 Build() 144 Expect(err).ToNot(HaveOccurred()) 145 Expect(object).ToNot(BeNil()) 146 147 // Populate the configuration: 148 var config struct { 149 MyKey string `yaml:"mykey"` 150 } 151 err = object.Populate(&config) 152 Expect(err).ToNot(HaveOccurred()) 153 Expect(config.MyKey).To(Equal("myvalue")) 154 }) 155 156 It("Can be loaded from YAML node", func() { 157 // Create the YAML node: 158 var node yaml.Node 159 err := yaml.Unmarshal([]byte(`mykey: myvalue`), &node) 160 Expect(err).ToNot(HaveOccurred()) 161 162 // Load the configuration: 163 object, err := New(). 164 Load(node). 165 Build() 166 Expect(err).ToNot(HaveOccurred()) 167 Expect(object).ToNot(BeNil()) 168 169 // Populate the configuration: 170 var config struct { 171 MyKey string `yaml:"mykey"` 172 } 173 err = object.Populate(&config) 174 Expect(err).ToNot(HaveOccurred()) 175 Expect(config.MyKey).To(Equal("myvalue")) 176 }) 177 178 It("Can be loaded from configuration object", func() { 179 // Load the source configuration: 180 source, err := New(). 181 Load(`mykey: myvalue`). 182 Build() 183 Expect(err).ToNot(HaveOccurred()) 184 Expect(source).ToNot(BeNil()) 185 186 // Load the configuration: 187 object, err := New(). 188 Load(source). 189 Build() 190 Expect(err).ToNot(HaveOccurred()) 191 Expect(object).ToNot(BeNil()) 192 193 // Populate the configuration: 194 var config struct { 195 MyKey string `yaml:"mykey"` 196 } 197 err = object.Populate(&config) 198 Expect(err).ToNot(HaveOccurred()) 199 Expect(config.MyKey).To(Equal("myvalue")) 200 }) 201 202 It("Can be loaded from directory", func() { 203 // Create a temporary directory containing two configuration files: 204 tmp, err := os.MkdirTemp("", "*.test.d") 205 Expect(err).ToNot(HaveOccurred()) 206 defer func() { 207 err = os.RemoveAll(tmp) 208 Expect(err).ToNot(HaveOccurred()) 209 }() 210 first := filepath.Join(tmp, "my.yaml") 211 err = os.WriteFile(first, []byte("mykey: myvalue"), 0600) 212 Expect(err).ToNot(HaveOccurred()) 213 second := filepath.Join(tmp, "your.yaml") 214 err = os.WriteFile(second, []byte("yourkey: yourvalue"), 0600) 215 216 // Load the configuration: 217 object, err := New(). 218 Load(tmp). 219 Build() 220 Expect(err).ToNot(HaveOccurred()) 221 Expect(object).ToNot(BeNil()) 222 223 // Populate the configuration: 224 var config struct { 225 MyKey string `yaml:"mykey"` 226 YourKey string `yaml:"yourkey"` 227 } 228 err = object.Populate(&config) 229 Expect(err).ToNot(HaveOccurred()) 230 Expect(config.MyKey).To(Equal("myvalue")) 231 Expect(config.YourKey).To(Equal("yourvalue")) 232 }) 233 234 It("Honours order of files in directory", func() { 235 // Create a temporary directory containing two configuration files: 236 tmp, err := os.MkdirTemp("", "*.test.d") 237 Expect(err).ToNot(HaveOccurred()) 238 defer func() { 239 err = os.RemoveAll(tmp) 240 Expect(err).ToNot(HaveOccurred()) 241 }() 242 first := filepath.Join(tmp, "0.yaml") 243 err = os.WriteFile(first, []byte("mykey: firstvalue"), 0600) 244 Expect(err).ToNot(HaveOccurred()) 245 second := filepath.Join(tmp, "1.yaml") 246 err = os.WriteFile(second, []byte("mykey: secondvalue"), 0600) 247 248 // Load the configuration: 249 object, err := New(). 250 Load(tmp). 251 Build() 252 Expect(err).ToNot(HaveOccurred()) 253 Expect(object).ToNot(BeNil()) 254 255 // Populate the configuration: 256 var config struct { 257 MyKey string `yaml:"mykey"` 258 } 259 err = object.Populate(&config) 260 Expect(err).ToNot(HaveOccurred()) 261 Expect(config.MyKey).To(Equal("secondvalue")) 262 }) 263 264 It("Decodes binary data", func() { 265 // Load the configuration: 266 object, err := New(). 267 Load(`mykey: !!binary bXl2YWx1ZQ==`). 268 Build() 269 Expect(err).ToNot(HaveOccurred()) 270 Expect(object).ToNot(BeNil()) 271 272 // Populate the configuration: 273 var config struct { 274 MyKey string `yaml:"mykey"` 275 } 276 err = object.Populate(&config) 277 Expect(err).ToNot(HaveOccurred()) 278 Expect(config.MyKey).To(Equal("myvalue")) 279 }) 280 }) 281 282 Describe("Merge", func() { 283 It("Honours order of sources", func() { 284 // Load the configuration: 285 object, err := New(). 286 Load(`mykey: myvalue`). 287 Load(`mykey: yourvalue`). 288 Build() 289 Expect(err).ToNot(HaveOccurred()) 290 Expect(object).ToNot(BeNil()) 291 292 // Populate the configuration: 293 var config struct { 294 MyKey string `yaml:"mykey"` 295 } 296 err = object.Populate(&config) 297 Expect(err).ToNot(HaveOccurred()) 298 Expect(config.MyKey).To(Equal("yourvalue")) 299 }) 300 301 It("Adds item to slice", func() { 302 // Load the configuration: 303 object, err := New(). 304 Load(`"myslice": [ "firstvalue" ]`). 305 Load(`"myslice": [ "secondvalue" ]`). 306 Build() 307 Expect(err).ToNot(HaveOccurred()) 308 Expect(object).ToNot(BeNil()) 309 310 // Populate the configuration: 311 var config struct { 312 MySlice []string `yaml:"myslice"` 313 } 314 err = object.Populate(&config) 315 Expect(err).ToNot(HaveOccurred()) 316 Expect(config.MySlice).To(ConsistOf("firstvalue", "secondvalue")) 317 }) 318 319 It("Adds entry to map", func() { 320 // Load the configuration: 321 object, err := New(). 322 Load(`"mymap": { firstkey: firstvalue }`). 323 Load(`"mymap": { secondkey: secondvalue }`). 324 Build() 325 Expect(err).ToNot(HaveOccurred()) 326 Expect(object).ToNot(BeNil()) 327 328 // Populate the configuration: 329 var config struct { 330 MyMap map[string]string `yaml:"mymap"` 331 } 332 err = object.Populate(&config) 333 Expect(err).ToNot(HaveOccurred()) 334 Expect(config.MyMap).To(HaveLen(2)) 335 Expect(config.MyMap).To(HaveKeyWithValue("firstkey", "firstvalue")) 336 Expect(config.MyMap).To(HaveKeyWithValue("secondkey", "secondvalue")) 337 }) 338 }) 339 340 It("Can be used as a struct field", func() { 341 var top, sub func(*Object) 342 343 // This simulates a top level component that uses its own struct to decode the 344 // configuration but has no visibility of the struct used by the sub-component. 345 top = func(object *Object) { 346 // Populate and verify the configuration: 347 var config struct { 348 TopKey string `yaml:"topkey"` 349 Sub *Object `yaml:"sub"` 350 } 351 err := object.Populate(&config) 352 Expect(err).ToNot(HaveOccurred()) 353 Expect(config.TopKey).To(Equal("topvalue")) 354 Expect(config.Sub).ToNot(BeNil()) 355 356 // Call the sub-component: 357 sub(config.Sub) 358 } 359 360 // This simulates a sub-component that uses its own private struct to decode the 361 // configuration. 362 sub = func(object *Object) { 363 // Populate and verify the configuration: 364 var config struct { 365 SubKey string `yaml:"subkey"` 366 } 367 err := object.Populate(&config) 368 Expect(err).ToNot(HaveOccurred()) 369 Expect(config.SubKey).To(Equal("subvalue")) 370 } 371 372 // Load the configuration: 373 object, err := New(). 374 Load(` 375 topkey: topvalue 376 sub: 377 subkey: subvalue 378 `). 379 Build() 380 Expect(err).ToNot(HaveOccurred()) 381 Expect(object).ToNot(BeNil()) 382 383 // Call the top level components: 384 top(object) 385 }) 386 387 Describe("Tags", func() { 388 // This type will be used to check values of fields pupulated using the tags in the 389 // tests below: 390 type Config struct { 391 User string `yaml:"user"` 392 Password string `yaml:"password"` 393 ID int `yaml:"id"` 394 Enabled bool `yaml:"enabled"` 395 } 396 397 DescribeTable( 398 "Successful processing", 399 func(source string, variables, files map[string]string, expected Config) { 400 var err error 401 402 // Set the environment variables: 403 var names []string 404 for name, value := range variables { 405 err = os.Setenv(name, value) 406 Expect(err).ToNot(HaveOccurred()) 407 names = append(names, name) 408 } 409 defer func() { 410 for _, name := range names { 411 err = os.Unsetenv(name) 412 Expect(err).ToNot(HaveOccurred()) 413 } 414 }() 415 416 // Create a temporary directory to contain the temporary files: 417 var tmp string 418 tmp, err = os.MkdirTemp("", "*.test") 419 Expect(err).ToNot(HaveOccurred()) 420 defer func() { 421 err = os.RemoveAll(tmp) 422 Expect(err).ToNot(HaveOccurred()) 423 }() 424 425 // Create the files into the temporary directory: 426 for name, content := range files { 427 path := filepath.Join(tmp, name) 428 err = os.WriteFile(path, []byte(content), 0600) 429 Expect(err).ToNot(HaveOccurred()) 430 } 431 432 // Change into the temporary directory: 433 var wd string 434 wd, err = os.Getwd() 435 Expect(err).ToNot(HaveOccurred()) 436 err = os.Chdir(tmp) 437 Expect(err).ToNot(HaveOccurred()) 438 defer func() { 439 err = os.Chdir(wd) 440 Expect(err).ToNot(HaveOccurred()) 441 }() 442 443 // Do the check: 444 object, err := New().Load(source).Build() 445 Expect(err).ToNot(HaveOccurred()) 446 var config Config 447 err = object.Populate(&config) 448 Expect(err).ToNot(HaveOccurred()) 449 Expect(config).To(Equal(expected)) 450 }, 451 Entry( 452 "Empty", 453 "", 454 nil, 455 nil, 456 Config{}, 457 ), 458 Entry( 459 "One environment variable", 460 ` 461 user: !variable MYUSER 462 `, 463 map[string]string{ 464 "MYUSER": "myuser", 465 }, 466 nil, 467 Config{ 468 User: "myuser", 469 }, 470 ), 471 Entry( 472 "Two environment variables", 473 ` 474 user: !variable MYUSER 475 password: !variable MYPASSWORD 476 `, 477 map[string]string{ 478 "MYUSER": "myuser", 479 "MYPASSWORD": "mypassword", 480 }, 481 nil, 482 Config{ 483 User: "myuser", 484 Password: "mypassword", 485 }, 486 ), 487 Entry( 488 "Environment variable with `var`", 489 ` 490 user: !var MYUSER 491 `, 492 map[string]string{ 493 "MYUSER": "myuser", 494 }, 495 nil, 496 Config{ 497 User: "myuser", 498 }, 499 ), 500 Entry( 501 "Environment variable with `v`", 502 ` 503 user: !v MYUSER 504 `, 505 map[string]string{ 506 "MYUSER": "myuser", 507 }, 508 nil, 509 Config{ 510 User: "myuser", 511 }, 512 ), 513 Entry( 514 "Environment variable with leading space", 515 ` 516 password: !variable MYPASSWORD 517 `, 518 map[string]string{ 519 "MYPASSWORD": " mypassword", 520 }, 521 nil, 522 Config{ 523 Password: " mypassword", 524 }, 525 ), 526 Entry( 527 "Environment variable with trailing space", 528 ` 529 password: !variable MYPASSWORD 530 `, 531 map[string]string{ 532 "MYPASSWORD": "mypassword ", 533 }, 534 nil, 535 Config{ 536 Password: "mypassword ", 537 }, 538 ), 539 Entry( 540 "Environment variable with quotes", 541 ` 542 password: !variable MYPASSWORD 543 `, 544 map[string]string{ 545 "MYPASSWORD": "my\"pass\"word", 546 }, 547 nil, 548 Config{ 549 Password: "my\"pass\"word", 550 }, 551 ), 552 Entry( 553 "Numeric environment variable", 554 ` 555 id: !variable/integer MYID 556 `, 557 map[string]string{ 558 "MYID": "123", 559 }, 560 nil, 561 Config{ 562 ID: 123, 563 }, 564 ), 565 Entry( 566 "Boolean environment variable", 567 ` 568 enabled: !variable/boolean MYENABLED 569 `, 570 map[string]string{ 571 "MYENABLED": "true", 572 }, 573 nil, 574 Config{ 575 Enabled: true, 576 }, 577 ), 578 Entry( 579 "One file", 580 ` 581 user: !file myuser.txt 582 `, 583 nil, 584 map[string]string{ 585 "myuser.txt": "myuser", 586 }, 587 Config{ 588 User: "myuser", 589 }, 590 ), 591 Entry( 592 "Two files", 593 ` 594 user: !file myuser.txt 595 password: !file mypassword.txt 596 `, 597 nil, 598 map[string]string{ 599 "myuser.txt": "myuser", 600 "mypassword.txt": "mypassword", 601 }, 602 Config{ 603 User: "myuser", 604 Password: "mypassword", 605 }, 606 ), 607 Entry( 608 "File with `f`", 609 ` 610 user: !f myuser.txt 611 `, 612 nil, 613 map[string]string{ 614 "myuser.txt": "myuser", 615 }, 616 Config{ 617 User: "myuser", 618 }, 619 ), 620 Entry( 621 "File with leading space preserved", 622 ` 623 user: !file myuser.txt 624 `, 625 nil, 626 map[string]string{ 627 "myuser.txt": " myuser", 628 }, 629 Config{ 630 User: " myuser", 631 }, 632 ), 633 Entry( 634 "File with leading space trimmed", 635 ` 636 user: !file/trim myuser.txt 637 `, 638 nil, 639 map[string]string{ 640 "myuser.txt": "myuser", 641 }, 642 Config{ 643 User: "myuser", 644 }, 645 ), 646 Entry( 647 "File with trailing space preserved", 648 ` 649 user: !file myuser.txt 650 `, 651 nil, 652 map[string]string{ 653 "myuser.txt": "myuser ", 654 }, 655 Config{ 656 User: "myuser ", 657 }, 658 ), 659 Entry( 660 "File with trailing space trimmed", 661 ` 662 user: !file/trim myuser.txt 663 `, 664 nil, 665 map[string]string{ 666 "myuser.txt": "myuser ", 667 }, 668 Config{ 669 User: "myuser", 670 }, 671 ), 672 Entry( 673 "File with trailing line break preserved", 674 ` 675 user: !file myuser.txt 676 `, 677 nil, 678 map[string]string{ 679 "myuser.txt": "myuser\n", 680 }, 681 Config{ 682 User: "myuser\n", 683 }, 684 ), 685 Entry( 686 "File with trailing line break trimmed", 687 ` 688 user: !file/trim myuser.txt 689 `, 690 nil, 691 map[string]string{ 692 "myuser.txt": "myuser\n", 693 }, 694 Config{ 695 User: "myuser", 696 }, 697 ), 698 Entry( 699 "Variable and file", 700 ` 701 user: !variable MYUSER 702 password: !file mypassword.txt 703 `, 704 map[string]string{ 705 "MYUSER": "myuser", 706 }, 707 map[string]string{ 708 "mypassword.txt": "mypassword", 709 }, 710 Config{ 711 User: "myuser", 712 Password: "mypassword", 713 }, 714 ), 715 Entry( 716 "File with quotes", 717 ` 718 user: myuser 719 password: !file mypassword.txt 720 `, 721 nil, 722 map[string]string{ 723 "mypassword.txt": "my\"pass\"word", 724 }, 725 Config{ 726 User: "myuser", 727 Password: "my\"pass\"word", 728 }, 729 ), 730 Entry( 731 "Numeric file", 732 ` 733 id: !file/integer myid.txt 734 `, 735 nil, 736 map[string]string{ 737 "myid.txt": "123", 738 }, 739 Config{ 740 ID: 123, 741 }, 742 ), 743 Entry( 744 "Boolean file", 745 ` 746 enabled: !file/boolean myenabled.txt 747 `, 748 nil, 749 map[string]string{ 750 "myenabled.txt": "true", 751 }, 752 Config{ 753 Enabled: true, 754 }, 755 ), 756 Entry( 757 "Script echo variable", 758 ` 759 user: !script echo -n ${MYUSER} 760 `, 761 map[string]string{ 762 "MYUSER": "myuser", 763 }, 764 nil, 765 Config{ 766 User: "myuser", 767 }, 768 ), 769 Entry( 770 "Script cat file", 771 ` 772 user: !script cat myuser.txt 773 `, 774 nil, 775 map[string]string{ 776 "myuser.txt": "myuser", 777 }, 778 Config{ 779 User: "myuser", 780 }, 781 ), 782 Entry( 783 "Include string", 784 ` 785 user: !file/yaml myuser.yaml 786 `, 787 nil, 788 map[string]string{ 789 "myuser.yaml": "myuser", 790 }, 791 Config{ 792 User: "myuser", 793 }, 794 ), 795 Entry( 796 "Include boolean", 797 ` 798 enabled: !file/yaml myenabled.yaml 799 `, 800 nil, 801 map[string]string{ 802 "myenabled.yaml": "true", 803 }, 804 Config{ 805 Enabled: true, 806 }, 807 ), 808 Entry( 809 "Include int", 810 ` 811 id: !file/yaml myid.yaml 812 `, 813 nil, 814 map[string]string{ 815 "myid.yaml": "123", 816 }, 817 Config{ 818 ID: 123, 819 }, 820 ), 821 Entry( 822 "Include map", 823 ` 824 !file/yaml mymap.yaml 825 `, 826 nil, 827 map[string]string{ 828 "mymap.yaml": "{ user: myuser, id: 123 }", 829 }, 830 Config{ 831 User: "myuser", 832 ID: 123, 833 }, 834 ), 835 Entry( 836 "Include chain", 837 ` 838 user: !file/yaml first.yaml 839 `, 840 nil, 841 map[string]string{ 842 "first.yaml": "!file/yaml second.yaml", 843 "second.yaml": "myuser", 844 }, 845 Config{ 846 User: "myuser", 847 }, 848 ), 849 Entry( 850 "Include chain and variable", 851 ` 852 user: !file/yaml first.yaml 853 `, 854 map[string]string{ 855 "MYUSER": "myuser", 856 }, 857 map[string]string{ 858 "first.yaml": "!file/yaml second.yaml", 859 "second.yaml": "!variable MYUSER", 860 }, 861 Config{ 862 User: "myuser", 863 }, 864 ), 865 Entry( 866 "Include chain and file", 867 ` 868 user: !file/yaml first.yaml 869 `, 870 nil, 871 map[string]string{ 872 "first.yaml": "!file/yaml second.yaml", 873 "second.yaml": "!file myuser.txt", 874 "myuser.txt": "myuser", 875 }, 876 Config{ 877 User: "myuser", 878 }, 879 ), 880 Entry( 881 "Include chain and script", 882 ` 883 user: !file/yaml first.yaml 884 `, 885 map[string]string{ 886 "MYUSER": "myuser", 887 }, 888 map[string]string{ 889 "first.yaml": "!file/yaml second.yaml", 890 "second.yaml": "!script echo -n ${MYUSER}", 891 }, 892 Config{ 893 User: "myuser", 894 }, 895 ), 896 Entry( 897 "Parse results of running script", 898 `!script/yaml echo user: myuser`, 899 nil, 900 nil, 901 Config{ 902 User: "myuser", 903 }, 904 ), 905 ) 906 907 It("Fails if first tag isn't supported", func() { 908 _, err := New(). 909 Load(`mykey: !wrong junk`). 910 Build() 911 Expect(err).To(HaveOccurred()) 912 message := err.Error() 913 Expect(message).To(ContainSubstring("wrong")) 914 }) 915 916 It("Fails if second tag isn't supported", func() { 917 _, err := New(). 918 Load(`mykey: !script/wrong echo -n junk`). 919 Build() 920 Expect(err).To(HaveOccurred()) 921 message := err.Error() 922 Expect(message).To(ContainSubstring("wrong")) 923 }) 924 925 It("Fails if environment variable doesn't exist", func() { 926 _, err := New(). 927 Load(`mykey: !variable DOESNOTEXIST`). 928 Build() 929 Expect(err).To(HaveOccurred()) 930 }) 931 932 It("Reports location of error for known source name", func() { 933 // Create a temporary file containing the configuration: 934 tmp, err := os.CreateTemp("", "*.test.yaml") 935 Expect(err).ToNot(HaveOccurred()) 936 name := tmp.Name() 937 defer func() { 938 err = os.Remove(name) 939 Expect(err).ToNot(HaveOccurred()) 940 }() 941 _, err = tmp.Write([]byte(`mykey: !file /doesnotexist`)) 942 Expect(err).ToNot(HaveOccurred()) 943 err = tmp.Close() 944 Expect(err).ToNot(HaveOccurred()) 945 946 // Check that loading fails and that the error message contains the name of 947 // the source file: 948 _, err = New(). 949 Load(name). 950 Build() 951 Expect(err).To(HaveOccurred()) 952 message := err.Error() 953 Expect(message).To(ContainSubstring(name + ":1:8")) 954 }) 955 956 It("Reports location of error for included file", func() { 957 // Create the a temporary file containing the text to be included: 958 tmp, err := os.CreateTemp("", "*.test.yaml") 959 Expect(err).ToNot(HaveOccurred()) 960 name := tmp.Name() 961 defer func() { 962 err = os.Remove(name) 963 Expect(err).ToNot(HaveOccurred()) 964 }() 965 _, err = tmp.Write([]byte(`yourkey: !file /doesnotexist`)) 966 Expect(err).ToNot(HaveOccurred()) 967 err = tmp.Close() 968 Expect(err).ToNot(HaveOccurred()) 969 970 // Check that loading fails and that the error message contains the name of 971 // the included file: 972 _, err = New(). 973 Load(`mykey: !file/yaml "` + name + `"`). 974 Build() 975 Expect(err).To(HaveOccurred()) 976 message := err.Error() 977 Expect(message).To(ContainSubstring(name + ":1:10:")) 978 }) 979 980 It("Reports location of error for unknown source name", func() { 981 _, err := New(). 982 Load(`mykey: !file /doesnotexist.txt`). 983 Build() 984 Expect(err).To(HaveOccurred()) 985 message := err.Error() 986 Expect(message).To(ContainSubstring("unknown:1:8:")) 987 }) 988 989 It("Fails if script writes to stderr", func() { 990 _, err := New(). 991 Load(`mykey: !script echo myerror 1>&2`). 992 Build() 993 Expect(err).To(HaveOccurred()) 994 }) 995 996 It("Script error contains stdout and stderr", func() { 997 _, err := New(). 998 Load(`mykey: !script echo myoutput; echo myerror 1>&2; exit 1`). 999 Build() 1000 Expect(err).To(HaveOccurred()) 1001 message := err.Error() 1002 Expect(message).To(ContainSubstring("myoutput")) 1003 Expect(message).To(ContainSubstring("myerror")) 1004 }) 1005 1006 It("Fails if script command doesn't exist", func() { 1007 _, err := New(). 1008 Load(`mykey: !script doesnotexist`). 1009 Build() 1010 Expect(err).To(HaveOccurred()) 1011 message := err.Error() 1012 Expect(message).To(ContainSubstring("doesnotexist")) 1013 }) 1014 1015 It("Fails if finds sequence when expecting scalar", func() { 1016 _, err := New(). 1017 Load(`mykey: !variable []`). 1018 Build() 1019 Expect(err).To(HaveOccurred()) 1020 message := err.Error() 1021 Expect(message).To(ContainSubstring("variable")) 1022 Expect(message).To(ContainSubstring("scalar")) 1023 Expect(message).To(ContainSubstring("sequence")) 1024 }) 1025 1026 It("Fails if finds mapping when expecting scalar", func() { 1027 _, err := New(). 1028 Load(`mykey: !file {}`). 1029 Build() 1030 Expect(err).To(HaveOccurred()) 1031 message := err.Error() 1032 Expect(message).To(ContainSubstring("file")) 1033 Expect(message).To(ContainSubstring("scalar")) 1034 Expect(message).To(ContainSubstring("mapping")) 1035 }) 1036 }) 1037 })