github.com/chalford/terraform@v0.3.7-0.20150113080010-a78c69a8c81f/helper/schema/resource_data_test.go (about) 1 package schema 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/hashicorp/terraform/terraform" 8 ) 9 10 func TestResourceDataGet(t *testing.T) { 11 cases := []struct { 12 Schema map[string]*Schema 13 State *terraform.InstanceState 14 Diff *terraform.InstanceDiff 15 Key string 16 Value interface{} 17 }{ 18 // #0 19 { 20 Schema: map[string]*Schema{ 21 "availability_zone": &Schema{ 22 Type: TypeString, 23 Optional: true, 24 Computed: true, 25 ForceNew: true, 26 }, 27 }, 28 29 State: nil, 30 31 Diff: &terraform.InstanceDiff{ 32 Attributes: map[string]*terraform.ResourceAttrDiff{ 33 "availability_zone": &terraform.ResourceAttrDiff{ 34 Old: "foo", 35 New: "bar", 36 NewComputed: true, 37 }, 38 }, 39 }, 40 41 Key: "availability_zone", 42 Value: "", 43 }, 44 45 // #1 46 { 47 Schema: map[string]*Schema{ 48 "availability_zone": &Schema{ 49 Type: TypeString, 50 Optional: true, 51 Computed: true, 52 ForceNew: true, 53 }, 54 }, 55 56 State: nil, 57 58 Diff: &terraform.InstanceDiff{ 59 Attributes: map[string]*terraform.ResourceAttrDiff{ 60 "availability_zone": &terraform.ResourceAttrDiff{ 61 Old: "", 62 New: "foo", 63 RequiresNew: true, 64 }, 65 }, 66 }, 67 68 Key: "availability_zone", 69 70 Value: "foo", 71 }, 72 73 // #2 74 { 75 Schema: map[string]*Schema{ 76 "availability_zone": &Schema{ 77 Type: TypeString, 78 Optional: true, 79 Computed: true, 80 ForceNew: true, 81 }, 82 }, 83 84 State: nil, 85 86 Diff: &terraform.InstanceDiff{ 87 Attributes: map[string]*terraform.ResourceAttrDiff{ 88 "availability_zone": &terraform.ResourceAttrDiff{ 89 Old: "", 90 New: "foo!", 91 NewExtra: "foo", 92 }, 93 }, 94 }, 95 96 Key: "availability_zone", 97 Value: "foo", 98 }, 99 100 // #3 101 { 102 Schema: map[string]*Schema{ 103 "availability_zone": &Schema{ 104 Type: TypeString, 105 Optional: true, 106 Computed: true, 107 ForceNew: true, 108 }, 109 }, 110 111 State: &terraform.InstanceState{ 112 Attributes: map[string]string{ 113 "availability_zone": "bar", 114 }, 115 }, 116 117 Diff: nil, 118 119 Key: "availability_zone", 120 121 Value: "bar", 122 }, 123 124 // #4 125 { 126 Schema: map[string]*Schema{ 127 "availability_zone": &Schema{ 128 Type: TypeString, 129 Optional: true, 130 Computed: true, 131 ForceNew: true, 132 }, 133 }, 134 135 State: &terraform.InstanceState{ 136 Attributes: map[string]string{ 137 "availability_zone": "foo", 138 }, 139 }, 140 141 Diff: &terraform.InstanceDiff{ 142 Attributes: map[string]*terraform.ResourceAttrDiff{ 143 "availability_zone": &terraform.ResourceAttrDiff{ 144 Old: "foo", 145 New: "bar", 146 NewComputed: true, 147 }, 148 }, 149 }, 150 151 Key: "availability_zone", 152 Value: "", 153 }, 154 155 // #5 156 { 157 Schema: map[string]*Schema{ 158 "port": &Schema{ 159 Type: TypeInt, 160 Optional: true, 161 Computed: true, 162 ForceNew: true, 163 }, 164 }, 165 166 State: &terraform.InstanceState{ 167 Attributes: map[string]string{ 168 "port": "80", 169 }, 170 }, 171 172 Diff: nil, 173 174 Key: "port", 175 176 Value: 80, 177 }, 178 179 // #6 180 { 181 Schema: map[string]*Schema{ 182 "ports": &Schema{ 183 Type: TypeList, 184 Required: true, 185 Elem: &Schema{Type: TypeInt}, 186 }, 187 }, 188 189 State: &terraform.InstanceState{ 190 Attributes: map[string]string{ 191 "ports.#": "3", 192 "ports.0": "1", 193 "ports.1": "2", 194 "ports.2": "5", 195 }, 196 }, 197 198 Key: "ports.1", 199 200 Value: 2, 201 }, 202 203 // #7 204 { 205 Schema: map[string]*Schema{ 206 "ports": &Schema{ 207 Type: TypeList, 208 Required: true, 209 Elem: &Schema{Type: TypeInt}, 210 }, 211 }, 212 213 State: &terraform.InstanceState{ 214 Attributes: map[string]string{ 215 "ports.#": "3", 216 "ports.0": "1", 217 "ports.1": "2", 218 "ports.2": "5", 219 }, 220 }, 221 222 Key: "ports.#", 223 224 Value: 3, 225 }, 226 227 // #8 228 { 229 Schema: map[string]*Schema{ 230 "ports": &Schema{ 231 Type: TypeList, 232 Required: true, 233 Elem: &Schema{Type: TypeInt}, 234 }, 235 }, 236 237 State: nil, 238 239 Key: "ports.#", 240 241 Value: 0, 242 }, 243 244 // #9 245 { 246 Schema: map[string]*Schema{ 247 "ports": &Schema{ 248 Type: TypeList, 249 Required: true, 250 Elem: &Schema{Type: TypeInt}, 251 }, 252 }, 253 254 State: &terraform.InstanceState{ 255 Attributes: map[string]string{ 256 "ports.#": "3", 257 "ports.0": "1", 258 "ports.1": "2", 259 "ports.2": "5", 260 }, 261 }, 262 263 Key: "ports", 264 265 Value: []interface{}{1, 2, 5}, 266 }, 267 268 // #10 269 { 270 Schema: map[string]*Schema{ 271 "ingress": &Schema{ 272 Type: TypeList, 273 Required: true, 274 Elem: &Resource{ 275 Schema: map[string]*Schema{ 276 "from": &Schema{ 277 Type: TypeInt, 278 Required: true, 279 }, 280 }, 281 }, 282 }, 283 }, 284 285 State: nil, 286 287 Diff: &terraform.InstanceDiff{ 288 Attributes: map[string]*terraform.ResourceAttrDiff{ 289 "ingress.#": &terraform.ResourceAttrDiff{ 290 Old: "", 291 New: "1", 292 }, 293 "ingress.0.from": &terraform.ResourceAttrDiff{ 294 Old: "", 295 New: "8080", 296 }, 297 }, 298 }, 299 300 Key: "ingress.0", 301 302 Value: map[string]interface{}{ 303 "from": 8080, 304 }, 305 }, 306 307 // #11 308 { 309 Schema: map[string]*Schema{ 310 "ingress": &Schema{ 311 Type: TypeList, 312 Required: true, 313 Elem: &Resource{ 314 Schema: map[string]*Schema{ 315 "from": &Schema{ 316 Type: TypeInt, 317 Required: true, 318 }, 319 }, 320 }, 321 }, 322 }, 323 324 State: nil, 325 326 Diff: &terraform.InstanceDiff{ 327 Attributes: map[string]*terraform.ResourceAttrDiff{ 328 "ingress.#": &terraform.ResourceAttrDiff{ 329 Old: "", 330 New: "1", 331 }, 332 "ingress.0.from": &terraform.ResourceAttrDiff{ 333 Old: "", 334 New: "8080", 335 }, 336 }, 337 }, 338 339 Key: "ingress", 340 341 Value: []interface{}{ 342 map[string]interface{}{ 343 "from": 8080, 344 }, 345 }, 346 }, 347 348 // #12 Computed get 349 { 350 Schema: map[string]*Schema{ 351 "availability_zone": &Schema{ 352 Type: TypeString, 353 Computed: true, 354 }, 355 }, 356 357 State: &terraform.InstanceState{ 358 Attributes: map[string]string{ 359 "availability_zone": "foo", 360 }, 361 }, 362 363 Key: "availability_zone", 364 365 Value: "foo", 366 }, 367 368 // #13 Full object 369 { 370 Schema: map[string]*Schema{ 371 "availability_zone": &Schema{ 372 Type: TypeString, 373 Optional: true, 374 Computed: true, 375 ForceNew: true, 376 }, 377 }, 378 379 State: nil, 380 381 Diff: &terraform.InstanceDiff{ 382 Attributes: map[string]*terraform.ResourceAttrDiff{ 383 "availability_zone": &terraform.ResourceAttrDiff{ 384 Old: "", 385 New: "foo", 386 RequiresNew: true, 387 }, 388 }, 389 }, 390 391 Key: "", 392 393 Value: map[string]interface{}{ 394 "availability_zone": "foo", 395 }, 396 }, 397 398 // #14 List of maps 399 { 400 Schema: map[string]*Schema{ 401 "config_vars": &Schema{ 402 Type: TypeList, 403 Optional: true, 404 Computed: true, 405 Elem: &Schema{ 406 Type: TypeMap, 407 }, 408 }, 409 }, 410 411 State: nil, 412 413 Diff: &terraform.InstanceDiff{ 414 Attributes: map[string]*terraform.ResourceAttrDiff{ 415 "config_vars.#": &terraform.ResourceAttrDiff{ 416 Old: "0", 417 New: "2", 418 }, 419 "config_vars.0.foo": &terraform.ResourceAttrDiff{ 420 Old: "", 421 New: "bar", 422 }, 423 "config_vars.1.bar": &terraform.ResourceAttrDiff{ 424 Old: "", 425 New: "baz", 426 }, 427 }, 428 }, 429 430 Key: "config_vars", 431 432 Value: []interface{}{ 433 map[string]interface{}{ 434 "foo": "bar", 435 }, 436 map[string]interface{}{ 437 "bar": "baz", 438 }, 439 }, 440 }, 441 442 // #15 List of maps in state 443 { 444 Schema: map[string]*Schema{ 445 "config_vars": &Schema{ 446 Type: TypeList, 447 Optional: true, 448 Computed: true, 449 Elem: &Schema{ 450 Type: TypeMap, 451 }, 452 }, 453 }, 454 455 State: &terraform.InstanceState{ 456 Attributes: map[string]string{ 457 "config_vars.#": "2", 458 "config_vars.0.foo": "baz", 459 "config_vars.1.bar": "bar", 460 }, 461 }, 462 463 Diff: nil, 464 465 Key: "config_vars", 466 467 Value: []interface{}{ 468 map[string]interface{}{ 469 "foo": "baz", 470 }, 471 map[string]interface{}{ 472 "bar": "bar", 473 }, 474 }, 475 }, 476 477 // #16 List of maps with removal in diff 478 { 479 Schema: map[string]*Schema{ 480 "config_vars": &Schema{ 481 Type: TypeList, 482 Optional: true, 483 Computed: true, 484 Elem: &Schema{ 485 Type: TypeMap, 486 }, 487 }, 488 }, 489 490 State: &terraform.InstanceState{ 491 Attributes: map[string]string{ 492 "config_vars.#": "1", 493 "config_vars.0.FOO": "bar", 494 }, 495 }, 496 497 Diff: &terraform.InstanceDiff{ 498 Attributes: map[string]*terraform.ResourceAttrDiff{ 499 "config_vars.#": &terraform.ResourceAttrDiff{ 500 Old: "1", 501 New: "0", 502 }, 503 "config_vars.0.FOO": &terraform.ResourceAttrDiff{ 504 Old: "bar", 505 NewRemoved: true, 506 }, 507 }, 508 }, 509 510 Key: "config_vars", 511 512 Value: []interface{}{}, 513 }, 514 515 // #17 Sets 516 { 517 Schema: map[string]*Schema{ 518 "ports": &Schema{ 519 Type: TypeSet, 520 Optional: true, 521 Computed: true, 522 Elem: &Schema{Type: TypeInt}, 523 Set: func(a interface{}) int { 524 return a.(int) 525 }, 526 }, 527 }, 528 529 State: &terraform.InstanceState{ 530 Attributes: map[string]string{ 531 "ports.#": "1", 532 "ports.80": "80", 533 }, 534 }, 535 536 Diff: nil, 537 538 Key: "ports", 539 540 Value: []interface{}{80}, 541 }, 542 543 // #18 544 { 545 Schema: map[string]*Schema{ 546 "data": &Schema{ 547 Type: TypeSet, 548 Optional: true, 549 Elem: &Resource{ 550 Schema: map[string]*Schema{ 551 "index": &Schema{ 552 Type: TypeInt, 553 Required: true, 554 }, 555 556 "value": &Schema{ 557 Type: TypeString, 558 Required: true, 559 }, 560 }, 561 }, 562 Set: func(a interface{}) int { 563 m := a.(map[string]interface{}) 564 return m["index"].(int) 565 }, 566 }, 567 }, 568 569 State: &terraform.InstanceState{ 570 Attributes: map[string]string{ 571 "data.#": "1", 572 "data.10.index": "10", 573 "data.10.value": "50", 574 }, 575 }, 576 577 Diff: &terraform.InstanceDiff{ 578 Attributes: map[string]*terraform.ResourceAttrDiff{ 579 "data.10.value": &terraform.ResourceAttrDiff{ 580 Old: "50", 581 New: "80", 582 }, 583 }, 584 }, 585 586 Key: "data", 587 588 Value: []interface{}{ 589 map[string]interface{}{ 590 "index": 10, 591 "value": "80", 592 }, 593 }, 594 }, 595 596 // #19 Empty Set 597 { 598 Schema: map[string]*Schema{ 599 "ports": &Schema{ 600 Type: TypeSet, 601 Optional: true, 602 Computed: true, 603 Elem: &Schema{Type: TypeInt}, 604 Set: func(a interface{}) int { 605 return a.(int) 606 }, 607 }, 608 }, 609 610 State: nil, 611 612 Diff: nil, 613 614 Key: "ports", 615 616 Value: []interface{}{}, 617 }, 618 } 619 620 for i, tc := range cases { 621 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 622 if err != nil { 623 t.Fatalf("err: %s", err) 624 } 625 626 v := d.Get(tc.Key) 627 if s, ok := v.(*Set); ok { 628 v = s.List() 629 } 630 631 if !reflect.DeepEqual(v, tc.Value) { 632 t.Fatalf("Bad: %d\n\n%#v\n\nExpected: %#v", i, v, tc.Value) 633 } 634 } 635 } 636 637 func TestResourceDataGetChange(t *testing.T) { 638 cases := []struct { 639 Schema map[string]*Schema 640 State *terraform.InstanceState 641 Diff *terraform.InstanceDiff 642 Key string 643 OldValue interface{} 644 NewValue interface{} 645 }{ 646 { 647 Schema: map[string]*Schema{ 648 "availability_zone": &Schema{ 649 Type: TypeString, 650 Optional: true, 651 Computed: true, 652 ForceNew: true, 653 }, 654 }, 655 656 State: nil, 657 658 Diff: &terraform.InstanceDiff{ 659 Attributes: map[string]*terraform.ResourceAttrDiff{ 660 "availability_zone": &terraform.ResourceAttrDiff{ 661 Old: "", 662 New: "foo", 663 RequiresNew: true, 664 }, 665 }, 666 }, 667 668 Key: "availability_zone", 669 670 OldValue: "", 671 NewValue: "foo", 672 }, 673 674 { 675 Schema: map[string]*Schema{ 676 "availability_zone": &Schema{ 677 Type: TypeString, 678 Optional: true, 679 Computed: true, 680 ForceNew: true, 681 }, 682 }, 683 684 State: &terraform.InstanceState{ 685 Attributes: map[string]string{ 686 "availability_zone": "foo", 687 }, 688 }, 689 690 Diff: &terraform.InstanceDiff{ 691 Attributes: map[string]*terraform.ResourceAttrDiff{ 692 "availability_zone": &terraform.ResourceAttrDiff{ 693 Old: "", 694 New: "foo", 695 RequiresNew: true, 696 }, 697 }, 698 }, 699 700 Key: "availability_zone", 701 702 OldValue: "foo", 703 NewValue: "foo", 704 }, 705 } 706 707 for i, tc := range cases { 708 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 709 if err != nil { 710 t.Fatalf("err: %s", err) 711 } 712 713 o, n := d.GetChange(tc.Key) 714 if !reflect.DeepEqual(o, tc.OldValue) { 715 t.Fatalf("Old Bad: %d\n\n%#v", i, o) 716 } 717 if !reflect.DeepEqual(n, tc.NewValue) { 718 t.Fatalf("New Bad: %d\n\n%#v", i, n) 719 } 720 } 721 } 722 723 func TestResourceDataGetOk(t *testing.T) { 724 cases := []struct { 725 Schema map[string]*Schema 726 State *terraform.InstanceState 727 Diff *terraform.InstanceDiff 728 Key string 729 Value interface{} 730 Ok bool 731 }{ 732 /* 733 * Primitives 734 */ 735 { 736 Schema: map[string]*Schema{ 737 "availability_zone": &Schema{ 738 Type: TypeString, 739 Optional: true, 740 Computed: true, 741 ForceNew: true, 742 }, 743 }, 744 745 State: nil, 746 747 Diff: &terraform.InstanceDiff{ 748 Attributes: map[string]*terraform.ResourceAttrDiff{ 749 "availability_zone": &terraform.ResourceAttrDiff{ 750 Old: "", 751 New: "", 752 }, 753 }, 754 }, 755 756 Key: "availability_zone", 757 Value: "", 758 Ok: true, 759 }, 760 761 { 762 Schema: map[string]*Schema{ 763 "availability_zone": &Schema{ 764 Type: TypeString, 765 Optional: true, 766 Computed: true, 767 ForceNew: true, 768 }, 769 }, 770 771 State: nil, 772 773 Diff: nil, 774 775 Key: "availability_zone", 776 Value: "", 777 Ok: false, 778 }, 779 780 /* 781 * Lists 782 */ 783 784 { 785 Schema: map[string]*Schema{ 786 "ports": &Schema{ 787 Type: TypeList, 788 Optional: true, 789 Elem: &Schema{Type: TypeInt}, 790 }, 791 }, 792 793 State: nil, 794 795 Diff: nil, 796 797 Key: "ports", 798 Value: []interface{}{}, 799 Ok: false, 800 }, 801 802 /* 803 * Map 804 */ 805 806 { 807 Schema: map[string]*Schema{ 808 "ports": &Schema{ 809 Type: TypeMap, 810 Optional: true, 811 }, 812 }, 813 814 State: nil, 815 816 Diff: nil, 817 818 Key: "ports", 819 Value: map[string]interface{}{}, 820 Ok: false, 821 }, 822 823 /* 824 * Set 825 */ 826 827 { 828 Schema: map[string]*Schema{ 829 "ports": &Schema{ 830 Type: TypeSet, 831 Optional: true, 832 Elem: &Schema{Type: TypeInt}, 833 Set: func(a interface{}) int { return a.(int) }, 834 }, 835 }, 836 837 State: nil, 838 839 Diff: nil, 840 841 Key: "ports", 842 Value: []interface{}{}, 843 Ok: false, 844 }, 845 846 { 847 Schema: map[string]*Schema{ 848 "ports": &Schema{ 849 Type: TypeSet, 850 Optional: true, 851 Elem: &Schema{Type: TypeInt}, 852 Set: func(a interface{}) int { return a.(int) }, 853 }, 854 }, 855 856 State: nil, 857 858 Diff: nil, 859 860 Key: "ports.0", 861 Value: 0, 862 Ok: false, 863 }, 864 } 865 866 for i, tc := range cases { 867 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 868 if err != nil { 869 t.Fatalf("err: %s", err) 870 } 871 872 v, ok := d.GetOk(tc.Key) 873 if s, ok := v.(*Set); ok { 874 v = s.List() 875 } 876 877 if !reflect.DeepEqual(v, tc.Value) { 878 t.Fatalf("Bad: %d\n\n%#v", i, v) 879 } 880 if ok != tc.Ok { 881 t.Fatalf("Bad: %d\n\n%#v", i, ok) 882 } 883 } 884 } 885 886 func TestResourceDataHasChange(t *testing.T) { 887 cases := []struct { 888 Schema map[string]*Schema 889 State *terraform.InstanceState 890 Diff *terraform.InstanceDiff 891 Key string 892 Change bool 893 }{ 894 { 895 Schema: map[string]*Schema{ 896 "availability_zone": &Schema{ 897 Type: TypeString, 898 Optional: true, 899 Computed: true, 900 ForceNew: true, 901 }, 902 }, 903 904 State: nil, 905 906 Diff: &terraform.InstanceDiff{ 907 Attributes: map[string]*terraform.ResourceAttrDiff{ 908 "availability_zone": &terraform.ResourceAttrDiff{ 909 Old: "", 910 New: "foo", 911 RequiresNew: true, 912 }, 913 }, 914 }, 915 916 Key: "availability_zone", 917 918 Change: true, 919 }, 920 921 { 922 Schema: map[string]*Schema{ 923 "availability_zone": &Schema{ 924 Type: TypeString, 925 Optional: true, 926 Computed: true, 927 ForceNew: true, 928 }, 929 }, 930 931 State: &terraform.InstanceState{ 932 Attributes: map[string]string{ 933 "availability_zone": "foo", 934 }, 935 }, 936 937 Diff: &terraform.InstanceDiff{ 938 Attributes: map[string]*terraform.ResourceAttrDiff{ 939 "availability_zone": &terraform.ResourceAttrDiff{ 940 Old: "", 941 New: "foo", 942 RequiresNew: true, 943 }, 944 }, 945 }, 946 947 Key: "availability_zone", 948 949 Change: false, 950 }, 951 952 { 953 Schema: map[string]*Schema{ 954 "tags": &Schema{ 955 Type: TypeMap, 956 Optional: true, 957 Computed: true, 958 }, 959 }, 960 961 State: nil, 962 963 Diff: &terraform.InstanceDiff{ 964 Attributes: map[string]*terraform.ResourceAttrDiff{ 965 "tags.Name": &terraform.ResourceAttrDiff{ 966 Old: "foo", 967 New: "foo", 968 }, 969 }, 970 }, 971 972 Key: "tags", 973 974 Change: true, 975 }, 976 } 977 978 for i, tc := range cases { 979 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 980 if err != nil { 981 t.Fatalf("err: %s", err) 982 } 983 984 actual := d.HasChange(tc.Key) 985 if actual != tc.Change { 986 t.Fatalf("Bad: %d %#v", i, actual) 987 } 988 } 989 } 990 991 func TestResourceDataSet(t *testing.T) { 992 cases := []struct { 993 Schema map[string]*Schema 994 State *terraform.InstanceState 995 Diff *terraform.InstanceDiff 996 Key string 997 Value interface{} 998 Err bool 999 GetKey string 1000 GetValue interface{} 1001 1002 // GetPreProcess can be set to munge the return value before being 1003 // compared to GetValue 1004 GetPreProcess func(interface{}) interface{} 1005 }{ 1006 // #0: Basic good 1007 { 1008 Schema: map[string]*Schema{ 1009 "availability_zone": &Schema{ 1010 Type: TypeString, 1011 Optional: true, 1012 Computed: true, 1013 ForceNew: true, 1014 }, 1015 }, 1016 1017 State: nil, 1018 1019 Diff: nil, 1020 1021 Key: "availability_zone", 1022 Value: "foo", 1023 1024 GetKey: "availability_zone", 1025 GetValue: "foo", 1026 }, 1027 1028 // #1: Basic int 1029 { 1030 Schema: map[string]*Schema{ 1031 "port": &Schema{ 1032 Type: TypeInt, 1033 Optional: true, 1034 Computed: true, 1035 ForceNew: true, 1036 }, 1037 }, 1038 1039 State: nil, 1040 1041 Diff: nil, 1042 1043 Key: "port", 1044 Value: 80, 1045 1046 GetKey: "port", 1047 GetValue: 80, 1048 }, 1049 1050 // #2: Basic bool 1051 { 1052 Schema: map[string]*Schema{ 1053 "vpc": &Schema{ 1054 Type: TypeBool, 1055 Optional: true, 1056 }, 1057 }, 1058 1059 State: nil, 1060 1061 Diff: nil, 1062 1063 Key: "vpc", 1064 Value: true, 1065 1066 GetKey: "vpc", 1067 GetValue: true, 1068 }, 1069 1070 // #3 1071 { 1072 Schema: map[string]*Schema{ 1073 "vpc": &Schema{ 1074 Type: TypeBool, 1075 Optional: true, 1076 }, 1077 }, 1078 1079 State: nil, 1080 1081 Diff: nil, 1082 1083 Key: "vpc", 1084 Value: false, 1085 1086 GetKey: "vpc", 1087 GetValue: false, 1088 }, 1089 1090 // #4: Invalid type 1091 { 1092 Schema: map[string]*Schema{ 1093 "availability_zone": &Schema{ 1094 Type: TypeString, 1095 Optional: true, 1096 Computed: true, 1097 ForceNew: true, 1098 }, 1099 }, 1100 1101 State: nil, 1102 1103 Diff: nil, 1104 1105 Key: "availability_zone", 1106 Value: 80, 1107 Err: true, 1108 1109 GetKey: "availability_zone", 1110 GetValue: "", 1111 }, 1112 1113 // #5: List of primitives, set list 1114 { 1115 Schema: map[string]*Schema{ 1116 "ports": &Schema{ 1117 Type: TypeList, 1118 Computed: true, 1119 Elem: &Schema{Type: TypeInt}, 1120 }, 1121 }, 1122 1123 State: nil, 1124 1125 Diff: nil, 1126 1127 Key: "ports", 1128 Value: []int{1, 2, 5}, 1129 1130 GetKey: "ports", 1131 GetValue: []interface{}{1, 2, 5}, 1132 }, 1133 1134 // #6: List of primitives, set list with error 1135 { 1136 Schema: map[string]*Schema{ 1137 "ports": &Schema{ 1138 Type: TypeList, 1139 Computed: true, 1140 Elem: &Schema{Type: TypeInt}, 1141 }, 1142 }, 1143 1144 State: nil, 1145 1146 Diff: nil, 1147 1148 Key: "ports", 1149 Value: []interface{}{1, "NOPE", 5}, 1150 Err: true, 1151 1152 GetKey: "ports", 1153 GetValue: []interface{}{}, 1154 }, 1155 1156 // #7: Set a list of maps 1157 { 1158 Schema: map[string]*Schema{ 1159 "config_vars": &Schema{ 1160 Type: TypeList, 1161 Optional: true, 1162 Computed: true, 1163 Elem: &Schema{ 1164 Type: TypeMap, 1165 }, 1166 }, 1167 }, 1168 1169 State: nil, 1170 1171 Diff: nil, 1172 1173 Key: "config_vars", 1174 Value: []interface{}{ 1175 map[string]interface{}{ 1176 "foo": "bar", 1177 }, 1178 map[string]interface{}{ 1179 "bar": "baz", 1180 }, 1181 }, 1182 Err: false, 1183 1184 GetKey: "config_vars", 1185 GetValue: []interface{}{ 1186 map[string]interface{}{ 1187 "foo": "bar", 1188 }, 1189 map[string]interface{}{ 1190 "bar": "baz", 1191 }, 1192 }, 1193 }, 1194 1195 // #8: Set, with list 1196 { 1197 Schema: map[string]*Schema{ 1198 "ports": &Schema{ 1199 Type: TypeSet, 1200 Optional: true, 1201 Computed: true, 1202 Elem: &Schema{Type: TypeInt}, 1203 Set: func(a interface{}) int { 1204 return a.(int) 1205 }, 1206 }, 1207 }, 1208 1209 State: &terraform.InstanceState{ 1210 Attributes: map[string]string{ 1211 "ports.#": "3", 1212 "ports.0": "100", 1213 "ports.1": "80", 1214 "ports.2": "80", 1215 }, 1216 }, 1217 1218 Key: "ports", 1219 Value: []interface{}{100, 125, 125}, 1220 1221 GetKey: "ports", 1222 GetValue: []interface{}{100, 125}, 1223 }, 1224 1225 // #9: Set, with Set 1226 { 1227 Schema: map[string]*Schema{ 1228 "ports": &Schema{ 1229 Type: TypeSet, 1230 Optional: true, 1231 Computed: true, 1232 Elem: &Schema{Type: TypeInt}, 1233 Set: func(a interface{}) int { 1234 return a.(int) 1235 }, 1236 }, 1237 }, 1238 1239 State: &terraform.InstanceState{ 1240 Attributes: map[string]string{ 1241 "ports.#": "3", 1242 "ports.100": "100", 1243 "ports.80": "80", 1244 "ports.81": "81", 1245 }, 1246 }, 1247 1248 Key: "ports", 1249 Value: &Set{ 1250 m: map[int]interface{}{ 1251 1: 1, 1252 2: 2, 1253 }, 1254 }, 1255 1256 GetKey: "ports", 1257 GetValue: []interface{}{1, 2}, 1258 }, 1259 1260 // #10: Set single item 1261 { 1262 Schema: map[string]*Schema{ 1263 "ports": &Schema{ 1264 Type: TypeSet, 1265 Optional: true, 1266 Computed: true, 1267 Elem: &Schema{Type: TypeInt}, 1268 Set: func(a interface{}) int { 1269 return a.(int) 1270 }, 1271 }, 1272 }, 1273 1274 State: &terraform.InstanceState{ 1275 Attributes: map[string]string{ 1276 "ports.#": "2", 1277 "ports.100": "100", 1278 "ports.80": "80", 1279 }, 1280 }, 1281 1282 Key: "ports.100", 1283 Value: 256, 1284 Err: true, 1285 1286 GetKey: "ports", 1287 GetValue: []interface{}{80, 100}, 1288 }, 1289 1290 // #11: Set with nested set 1291 { 1292 Schema: map[string]*Schema{ 1293 "ports": &Schema{ 1294 Type: TypeSet, 1295 Elem: &Resource{ 1296 Schema: map[string]*Schema{ 1297 "port": &Schema{ 1298 Type: TypeInt, 1299 }, 1300 1301 "set": &Schema{ 1302 Type: TypeSet, 1303 Elem: &Schema{Type: TypeInt}, 1304 Set: func(a interface{}) int { 1305 return a.(int) 1306 }, 1307 }, 1308 }, 1309 }, 1310 Set: func(a interface{}) int { 1311 return a.(map[string]interface{})["port"].(int) 1312 }, 1313 }, 1314 }, 1315 1316 State: nil, 1317 1318 Key: "ports", 1319 Value: []interface{}{ 1320 map[string]interface{}{ 1321 "port": 80, 1322 }, 1323 }, 1324 1325 GetKey: "ports", 1326 GetValue: []interface{}{ 1327 map[string]interface{}{ 1328 "port": 80, 1329 "set": []interface{}{}, 1330 }, 1331 }, 1332 1333 GetPreProcess: func(v interface{}) interface{} { 1334 if v == nil { 1335 return v 1336 } 1337 s, ok := v.([]interface{}) 1338 if !ok { 1339 return v 1340 } 1341 for _, v := range s { 1342 m, ok := v.(map[string]interface{}) 1343 if !ok { 1344 continue 1345 } 1346 if m["set"] == nil { 1347 continue 1348 } 1349 if s, ok := m["set"].(*Set); ok { 1350 m["set"] = s.List() 1351 } 1352 } 1353 1354 return v 1355 }, 1356 }, 1357 } 1358 1359 for i, tc := range cases { 1360 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 1361 if err != nil { 1362 t.Fatalf("err: %s", err) 1363 } 1364 1365 err = d.Set(tc.Key, tc.Value) 1366 if (err != nil) != tc.Err { 1367 t.Fatalf("%d err: %s", i, err) 1368 } 1369 1370 v := d.Get(tc.GetKey) 1371 if s, ok := v.(*Set); ok { 1372 v = s.List() 1373 } 1374 1375 if tc.GetPreProcess != nil { 1376 v = tc.GetPreProcess(v) 1377 } 1378 1379 if !reflect.DeepEqual(v, tc.GetValue) { 1380 t.Fatalf("Get Bad: %d\n\n%#v", i, v) 1381 } 1382 } 1383 } 1384 1385 func TestResourceDataState(t *testing.T) { 1386 cases := []struct { 1387 Schema map[string]*Schema 1388 State *terraform.InstanceState 1389 Diff *terraform.InstanceDiff 1390 Set map[string]interface{} 1391 Result *terraform.InstanceState 1392 Partial []string 1393 }{ 1394 // #0 Basic primitive in diff 1395 { 1396 Schema: map[string]*Schema{ 1397 "availability_zone": &Schema{ 1398 Type: TypeString, 1399 Optional: true, 1400 Computed: true, 1401 ForceNew: true, 1402 }, 1403 }, 1404 1405 State: nil, 1406 1407 Diff: &terraform.InstanceDiff{ 1408 Attributes: map[string]*terraform.ResourceAttrDiff{ 1409 "availability_zone": &terraform.ResourceAttrDiff{ 1410 Old: "", 1411 New: "foo", 1412 RequiresNew: true, 1413 }, 1414 }, 1415 }, 1416 1417 Result: &terraform.InstanceState{ 1418 Attributes: map[string]string{ 1419 "availability_zone": "foo", 1420 }, 1421 }, 1422 }, 1423 1424 // #1 Basic primitive set override 1425 { 1426 Schema: map[string]*Schema{ 1427 "availability_zone": &Schema{ 1428 Type: TypeString, 1429 Optional: true, 1430 Computed: true, 1431 ForceNew: true, 1432 }, 1433 }, 1434 1435 State: nil, 1436 1437 Diff: &terraform.InstanceDiff{ 1438 Attributes: map[string]*terraform.ResourceAttrDiff{ 1439 "availability_zone": &terraform.ResourceAttrDiff{ 1440 Old: "", 1441 New: "foo", 1442 RequiresNew: true, 1443 }, 1444 }, 1445 }, 1446 1447 Set: map[string]interface{}{ 1448 "availability_zone": "bar", 1449 }, 1450 1451 Result: &terraform.InstanceState{ 1452 Attributes: map[string]string{ 1453 "availability_zone": "bar", 1454 }, 1455 }, 1456 }, 1457 1458 // #2 1459 { 1460 Schema: map[string]*Schema{ 1461 "vpc": &Schema{ 1462 Type: TypeBool, 1463 Optional: true, 1464 }, 1465 }, 1466 1467 State: nil, 1468 1469 Diff: nil, 1470 1471 Set: map[string]interface{}{ 1472 "vpc": true, 1473 }, 1474 1475 Result: &terraform.InstanceState{ 1476 Attributes: map[string]string{ 1477 "vpc": "true", 1478 }, 1479 }, 1480 }, 1481 1482 // #3 Basic primitive with StateFunc set 1483 { 1484 Schema: map[string]*Schema{ 1485 "availability_zone": &Schema{ 1486 Type: TypeString, 1487 Optional: true, 1488 Computed: true, 1489 StateFunc: func(interface{}) string { return "" }, 1490 }, 1491 }, 1492 1493 State: nil, 1494 1495 Diff: &terraform.InstanceDiff{ 1496 Attributes: map[string]*terraform.ResourceAttrDiff{ 1497 "availability_zone": &terraform.ResourceAttrDiff{ 1498 Old: "", 1499 New: "foo", 1500 NewExtra: "foo!", 1501 }, 1502 }, 1503 }, 1504 1505 Result: &terraform.InstanceState{ 1506 Attributes: map[string]string{ 1507 "availability_zone": "foo", 1508 }, 1509 }, 1510 }, 1511 1512 // #4 List 1513 { 1514 Schema: map[string]*Schema{ 1515 "ports": &Schema{ 1516 Type: TypeList, 1517 Required: true, 1518 Elem: &Schema{Type: TypeInt}, 1519 }, 1520 }, 1521 1522 State: &terraform.InstanceState{ 1523 Attributes: map[string]string{ 1524 "ports.#": "1", 1525 "ports.0": "80", 1526 }, 1527 }, 1528 1529 Diff: &terraform.InstanceDiff{ 1530 Attributes: map[string]*terraform.ResourceAttrDiff{ 1531 "ports.#": &terraform.ResourceAttrDiff{ 1532 Old: "1", 1533 New: "2", 1534 }, 1535 "ports.1": &terraform.ResourceAttrDiff{ 1536 Old: "", 1537 New: "100", 1538 }, 1539 }, 1540 }, 1541 1542 Result: &terraform.InstanceState{ 1543 Attributes: map[string]string{ 1544 "ports.#": "2", 1545 "ports.0": "80", 1546 "ports.1": "100", 1547 }, 1548 }, 1549 }, 1550 1551 // #5 List of resources 1552 { 1553 Schema: map[string]*Schema{ 1554 "ingress": &Schema{ 1555 Type: TypeList, 1556 Required: true, 1557 Elem: &Resource{ 1558 Schema: map[string]*Schema{ 1559 "from": &Schema{ 1560 Type: TypeInt, 1561 Required: true, 1562 }, 1563 }, 1564 }, 1565 }, 1566 }, 1567 1568 State: &terraform.InstanceState{ 1569 Attributes: map[string]string{ 1570 "ingress.#": "1", 1571 "ingress.0.from": "80", 1572 }, 1573 }, 1574 1575 Diff: &terraform.InstanceDiff{ 1576 Attributes: map[string]*terraform.ResourceAttrDiff{ 1577 "ingress.#": &terraform.ResourceAttrDiff{ 1578 Old: "1", 1579 New: "2", 1580 }, 1581 "ingress.0.from": &terraform.ResourceAttrDiff{ 1582 Old: "80", 1583 New: "150", 1584 }, 1585 "ingress.1.from": &terraform.ResourceAttrDiff{ 1586 Old: "", 1587 New: "100", 1588 }, 1589 }, 1590 }, 1591 1592 Result: &terraform.InstanceState{ 1593 Attributes: map[string]string{ 1594 "ingress.#": "2", 1595 "ingress.0.from": "150", 1596 "ingress.1.from": "100", 1597 }, 1598 }, 1599 }, 1600 1601 // #6 List of maps 1602 { 1603 Schema: map[string]*Schema{ 1604 "config_vars": &Schema{ 1605 Type: TypeList, 1606 Optional: true, 1607 Computed: true, 1608 Elem: &Schema{ 1609 Type: TypeMap, 1610 }, 1611 }, 1612 }, 1613 1614 State: &terraform.InstanceState{ 1615 Attributes: map[string]string{ 1616 "config_vars.#": "2", 1617 "config_vars.0.foo": "bar", 1618 "config_vars.0.bar": "bar", 1619 "config_vars.1.bar": "baz", 1620 }, 1621 }, 1622 1623 Diff: &terraform.InstanceDiff{ 1624 Attributes: map[string]*terraform.ResourceAttrDiff{ 1625 "config_vars.0.bar": &terraform.ResourceAttrDiff{ 1626 NewRemoved: true, 1627 }, 1628 }, 1629 }, 1630 1631 Set: map[string]interface{}{ 1632 "config_vars": []map[string]interface{}{ 1633 map[string]interface{}{ 1634 "foo": "bar", 1635 }, 1636 map[string]interface{}{ 1637 "baz": "bang", 1638 }, 1639 }, 1640 }, 1641 1642 Result: &terraform.InstanceState{ 1643 Attributes: map[string]string{ 1644 "config_vars.#": "2", 1645 "config_vars.0.foo": "bar", 1646 "config_vars.1.baz": "bang", 1647 }, 1648 }, 1649 }, 1650 1651 // #7 List of maps with removal in diff 1652 { 1653 Schema: map[string]*Schema{ 1654 "config_vars": &Schema{ 1655 Type: TypeList, 1656 Optional: true, 1657 Computed: true, 1658 Elem: &Schema{ 1659 Type: TypeMap, 1660 }, 1661 }, 1662 }, 1663 1664 State: &terraform.InstanceState{ 1665 Attributes: map[string]string{ 1666 "config_vars.#": "1", 1667 "config_vars.0.FOO": "bar", 1668 }, 1669 }, 1670 1671 Diff: &terraform.InstanceDiff{ 1672 Attributes: map[string]*terraform.ResourceAttrDiff{ 1673 "config_vars.#": &terraform.ResourceAttrDiff{ 1674 Old: "1", 1675 New: "0", 1676 }, 1677 "config_vars.0.FOO": &terraform.ResourceAttrDiff{ 1678 Old: "bar", 1679 NewRemoved: true, 1680 }, 1681 }, 1682 }, 1683 1684 Result: &terraform.InstanceState{ 1685 Attributes: map[string]string{ 1686 "config_vars.#": "0", 1687 }, 1688 }, 1689 }, 1690 1691 // #8 Basic state with other keys 1692 { 1693 Schema: map[string]*Schema{ 1694 "availability_zone": &Schema{ 1695 Type: TypeString, 1696 Optional: true, 1697 Computed: true, 1698 ForceNew: true, 1699 }, 1700 }, 1701 1702 State: &terraform.InstanceState{ 1703 ID: "bar", 1704 Attributes: map[string]string{ 1705 "id": "bar", 1706 }, 1707 }, 1708 1709 Diff: &terraform.InstanceDiff{ 1710 Attributes: map[string]*terraform.ResourceAttrDiff{ 1711 "availability_zone": &terraform.ResourceAttrDiff{ 1712 Old: "", 1713 New: "foo", 1714 RequiresNew: true, 1715 }, 1716 }, 1717 }, 1718 1719 Result: &terraform.InstanceState{ 1720 ID: "bar", 1721 Attributes: map[string]string{ 1722 "id": "bar", 1723 "availability_zone": "foo", 1724 }, 1725 }, 1726 }, 1727 1728 // #9 Sets 1729 { 1730 Schema: map[string]*Schema{ 1731 "ports": &Schema{ 1732 Type: TypeSet, 1733 Optional: true, 1734 Computed: true, 1735 Elem: &Schema{Type: TypeInt}, 1736 Set: func(a interface{}) int { 1737 return a.(int) 1738 }, 1739 }, 1740 }, 1741 1742 State: &terraform.InstanceState{ 1743 Attributes: map[string]string{ 1744 "ports.#": "3", 1745 "ports.100": "100", 1746 "ports.80": "80", 1747 "ports.81": "81", 1748 }, 1749 }, 1750 1751 Diff: nil, 1752 1753 Result: &terraform.InstanceState{ 1754 Attributes: map[string]string{ 1755 "ports.#": "3", 1756 "ports.80": "80", 1757 "ports.81": "81", 1758 "ports.100": "100", 1759 }, 1760 }, 1761 }, 1762 1763 // #10 1764 { 1765 Schema: map[string]*Schema{ 1766 "ports": &Schema{ 1767 Type: TypeSet, 1768 Optional: true, 1769 Computed: true, 1770 Elem: &Schema{Type: TypeInt}, 1771 Set: func(a interface{}) int { 1772 return a.(int) 1773 }, 1774 }, 1775 }, 1776 1777 State: nil, 1778 1779 Diff: nil, 1780 1781 Set: map[string]interface{}{ 1782 "ports": []interface{}{100, 80}, 1783 }, 1784 1785 Result: &terraform.InstanceState{ 1786 Attributes: map[string]string{ 1787 "ports.#": "2", 1788 "ports.80": "80", 1789 "ports.100": "100", 1790 }, 1791 }, 1792 }, 1793 1794 // #11 1795 { 1796 Schema: map[string]*Schema{ 1797 "ports": &Schema{ 1798 Type: TypeSet, 1799 Optional: true, 1800 Computed: true, 1801 Elem: &Resource{ 1802 Schema: map[string]*Schema{ 1803 "order": &Schema{ 1804 Type: TypeInt, 1805 }, 1806 1807 "a": &Schema{ 1808 Type: TypeList, 1809 Elem: &Schema{Type: TypeInt}, 1810 }, 1811 1812 "b": &Schema{ 1813 Type: TypeList, 1814 Elem: &Schema{Type: TypeInt}, 1815 }, 1816 }, 1817 }, 1818 Set: func(a interface{}) int { 1819 m := a.(map[string]interface{}) 1820 return m["order"].(int) 1821 }, 1822 }, 1823 }, 1824 1825 State: &terraform.InstanceState{ 1826 Attributes: map[string]string{ 1827 "ports.#": "2", 1828 "ports.10.order": "10", 1829 "ports.10.a.#": "1", 1830 "ports.10.a.0": "80", 1831 "ports.20.order": "20", 1832 "ports.20.b.#": "1", 1833 "ports.20.b.0": "100", 1834 }, 1835 }, 1836 1837 Set: map[string]interface{}{ 1838 "ports": []interface{}{ 1839 map[string]interface{}{ 1840 "order": 20, 1841 "b": []interface{}{100}, 1842 }, 1843 map[string]interface{}{ 1844 "order": 10, 1845 "a": []interface{}{80}, 1846 }, 1847 }, 1848 }, 1849 1850 Result: &terraform.InstanceState{ 1851 Attributes: map[string]string{ 1852 "ports.#": "2", 1853 "ports.10.order": "10", 1854 "ports.10.a.#": "1", 1855 "ports.10.a.0": "80", 1856 "ports.10.b.#": "0", 1857 "ports.20.order": "20", 1858 "ports.20.a.#": "0", 1859 "ports.20.b.#": "1", 1860 "ports.20.b.0": "100", 1861 }, 1862 }, 1863 }, 1864 1865 /* 1866 * PARTIAL STATES 1867 */ 1868 1869 // #12 Basic primitive 1870 { 1871 Schema: map[string]*Schema{ 1872 "availability_zone": &Schema{ 1873 Type: TypeString, 1874 Optional: true, 1875 Computed: true, 1876 ForceNew: true, 1877 }, 1878 }, 1879 1880 State: nil, 1881 1882 Diff: &terraform.InstanceDiff{ 1883 Attributes: map[string]*terraform.ResourceAttrDiff{ 1884 "availability_zone": &terraform.ResourceAttrDiff{ 1885 Old: "", 1886 New: "foo", 1887 RequiresNew: true, 1888 }, 1889 }, 1890 }, 1891 1892 Partial: []string{}, 1893 1894 Result: &terraform.InstanceState{ 1895 Attributes: map[string]string{ 1896 "availability_zone": "", 1897 }, 1898 }, 1899 }, 1900 1901 // #13 List 1902 { 1903 Schema: map[string]*Schema{ 1904 "ports": &Schema{ 1905 Type: TypeList, 1906 Required: true, 1907 Elem: &Schema{Type: TypeInt}, 1908 }, 1909 }, 1910 1911 State: &terraform.InstanceState{ 1912 Attributes: map[string]string{ 1913 "ports.#": "1", 1914 "ports.0": "80", 1915 }, 1916 }, 1917 1918 Diff: &terraform.InstanceDiff{ 1919 Attributes: map[string]*terraform.ResourceAttrDiff{ 1920 "ports.#": &terraform.ResourceAttrDiff{ 1921 Old: "1", 1922 New: "2", 1923 }, 1924 "ports.1": &terraform.ResourceAttrDiff{ 1925 Old: "", 1926 New: "100", 1927 }, 1928 }, 1929 }, 1930 1931 Partial: []string{}, 1932 1933 Result: &terraform.InstanceState{ 1934 Attributes: map[string]string{ 1935 "ports.#": "1", 1936 "ports.0": "80", 1937 }, 1938 }, 1939 }, 1940 1941 // #14 1942 { 1943 Schema: map[string]*Schema{ 1944 "ports": &Schema{ 1945 Type: TypeList, 1946 Optional: true, 1947 Computed: true, 1948 Elem: &Schema{Type: TypeInt}, 1949 }, 1950 }, 1951 1952 State: nil, 1953 1954 Diff: &terraform.InstanceDiff{ 1955 Attributes: map[string]*terraform.ResourceAttrDiff{ 1956 "ports.#": &terraform.ResourceAttrDiff{ 1957 Old: "", 1958 NewComputed: true, 1959 }, 1960 }, 1961 }, 1962 1963 Partial: []string{}, 1964 1965 Set: map[string]interface{}{ 1966 "ports": []interface{}{}, 1967 }, 1968 1969 Result: &terraform.InstanceState{ 1970 Attributes: map[string]string{ 1971 "ports.#": "0", 1972 }, 1973 }, 1974 }, 1975 1976 // #15 List of resources 1977 { 1978 Schema: map[string]*Schema{ 1979 "ingress": &Schema{ 1980 Type: TypeList, 1981 Required: true, 1982 Elem: &Resource{ 1983 Schema: map[string]*Schema{ 1984 "from": &Schema{ 1985 Type: TypeInt, 1986 Required: true, 1987 }, 1988 }, 1989 }, 1990 }, 1991 }, 1992 1993 State: &terraform.InstanceState{ 1994 Attributes: map[string]string{ 1995 "ingress.#": "1", 1996 "ingress.0.from": "80", 1997 }, 1998 }, 1999 2000 Diff: &terraform.InstanceDiff{ 2001 Attributes: map[string]*terraform.ResourceAttrDiff{ 2002 "ingress.#": &terraform.ResourceAttrDiff{ 2003 Old: "1", 2004 New: "2", 2005 }, 2006 "ingress.0.from": &terraform.ResourceAttrDiff{ 2007 Old: "80", 2008 New: "150", 2009 }, 2010 "ingress.1.from": &terraform.ResourceAttrDiff{ 2011 Old: "", 2012 New: "100", 2013 }, 2014 }, 2015 }, 2016 2017 Partial: []string{}, 2018 2019 Result: &terraform.InstanceState{ 2020 Attributes: map[string]string{ 2021 "ingress.#": "1", 2022 "ingress.0.from": "80", 2023 }, 2024 }, 2025 }, 2026 2027 // #16 List of maps 2028 { 2029 Schema: map[string]*Schema{ 2030 "config_vars": &Schema{ 2031 Type: TypeList, 2032 Optional: true, 2033 Computed: true, 2034 Elem: &Schema{ 2035 Type: TypeMap, 2036 }, 2037 }, 2038 }, 2039 2040 State: &terraform.InstanceState{ 2041 Attributes: map[string]string{ 2042 "config_vars.#": "2", 2043 "config_vars.0.foo": "bar", 2044 "config_vars.0.bar": "bar", 2045 "config_vars.1.bar": "baz", 2046 }, 2047 }, 2048 2049 Diff: &terraform.InstanceDiff{ 2050 Attributes: map[string]*terraform.ResourceAttrDiff{ 2051 "config_vars.0.bar": &terraform.ResourceAttrDiff{ 2052 NewRemoved: true, 2053 }, 2054 }, 2055 }, 2056 2057 Set: map[string]interface{}{ 2058 "config_vars": []map[string]interface{}{ 2059 map[string]interface{}{ 2060 "foo": "bar", 2061 }, 2062 map[string]interface{}{ 2063 "baz": "bang", 2064 }, 2065 }, 2066 }, 2067 2068 Partial: []string{}, 2069 2070 Result: &terraform.InstanceState{ 2071 Attributes: map[string]string{ 2072 // TODO: broken, shouldn't bar be removed? 2073 "config_vars.#": "2", 2074 "config_vars.0.foo": "bar", 2075 "config_vars.0.bar": "bar", 2076 "config_vars.1.bar": "baz", 2077 }, 2078 }, 2079 }, 2080 2081 // #17 Sets 2082 { 2083 Schema: map[string]*Schema{ 2084 "ports": &Schema{ 2085 Type: TypeSet, 2086 Optional: true, 2087 Computed: true, 2088 Elem: &Schema{Type: TypeInt}, 2089 Set: func(a interface{}) int { 2090 return a.(int) 2091 }, 2092 }, 2093 }, 2094 2095 State: &terraform.InstanceState{ 2096 Attributes: map[string]string{ 2097 "ports.#": "3", 2098 "ports.100": "100", 2099 "ports.80": "80", 2100 "ports.81": "81", 2101 }, 2102 }, 2103 2104 Diff: &terraform.InstanceDiff{ 2105 Attributes: map[string]*terraform.ResourceAttrDiff{ 2106 "ports.120": &terraform.ResourceAttrDiff{ 2107 New: "120", 2108 }, 2109 }, 2110 }, 2111 2112 Partial: []string{}, 2113 2114 Result: &terraform.InstanceState{ 2115 Attributes: map[string]string{ 2116 "ports.#": "3", 2117 "ports.80": "80", 2118 "ports.81": "81", 2119 "ports.100": "100", 2120 }, 2121 }, 2122 }, 2123 2124 // #18 2125 { 2126 Schema: map[string]*Schema{ 2127 "ports": &Schema{ 2128 Type: TypeSet, 2129 Optional: true, 2130 Computed: true, 2131 Elem: &Schema{Type: TypeInt}, 2132 Set: func(a interface{}) int { 2133 return a.(int) 2134 }, 2135 }, 2136 }, 2137 2138 State: nil, 2139 2140 Diff: &terraform.InstanceDiff{ 2141 Attributes: map[string]*terraform.ResourceAttrDiff{ 2142 "ports.#": &terraform.ResourceAttrDiff{ 2143 Old: "", 2144 NewComputed: true, 2145 }, 2146 }, 2147 }, 2148 2149 Partial: []string{}, 2150 2151 Result: &terraform.InstanceState{ 2152 Attributes: map[string]string{ 2153 "ports.#": "0", 2154 }, 2155 }, 2156 }, 2157 2158 // #19 Maps 2159 { 2160 Schema: map[string]*Schema{ 2161 "tags": &Schema{ 2162 Type: TypeMap, 2163 Optional: true, 2164 Computed: true, 2165 }, 2166 }, 2167 2168 State: nil, 2169 2170 Diff: &terraform.InstanceDiff{ 2171 Attributes: map[string]*terraform.ResourceAttrDiff{ 2172 "tags.Name": &terraform.ResourceAttrDiff{ 2173 Old: "", 2174 New: "foo", 2175 }, 2176 }, 2177 }, 2178 2179 Result: &terraform.InstanceState{ 2180 Attributes: map[string]string{ 2181 "tags.Name": "foo", 2182 }, 2183 }, 2184 }, 2185 2186 // #20 2187 { 2188 Schema: map[string]*Schema{ 2189 "tags": &Schema{ 2190 Type: TypeMap, 2191 Optional: true, 2192 Computed: true, 2193 }, 2194 }, 2195 2196 State: nil, 2197 2198 Diff: &terraform.InstanceDiff{ 2199 Attributes: map[string]*terraform.ResourceAttrDiff{ 2200 "tags.Name": &terraform.ResourceAttrDiff{ 2201 Old: "", 2202 New: "foo", 2203 }, 2204 }, 2205 }, 2206 2207 Set: map[string]interface{}{ 2208 "tags": map[string]string{}, 2209 }, 2210 2211 Result: &terraform.InstanceState{ 2212 Attributes: map[string]string{}, 2213 }, 2214 }, 2215 } 2216 2217 for i, tc := range cases { 2218 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 2219 if err != nil { 2220 t.Fatalf("err: %s", err) 2221 } 2222 2223 for k, v := range tc.Set { 2224 if err := d.Set(k, v); err != nil { 2225 t.Fatalf("%d err: %s", i, err) 2226 } 2227 } 2228 2229 // Set an ID so that the state returned is not nil 2230 idSet := false 2231 if d.Id() == "" { 2232 idSet = true 2233 d.SetId("foo") 2234 } 2235 2236 // If we have partial, then enable partial state mode. 2237 if tc.Partial != nil { 2238 d.Partial(true) 2239 for _, k := range tc.Partial { 2240 d.SetPartial(k) 2241 } 2242 } 2243 2244 actual := d.State() 2245 2246 // If we set an ID, then undo what we did so the comparison works 2247 if actual != nil && idSet { 2248 actual.ID = "" 2249 delete(actual.Attributes, "id") 2250 } 2251 2252 if !reflect.DeepEqual(actual, tc.Result) { 2253 t.Fatalf("Bad: %d\n\n%#v\n\nExpected:\n\n%#v", i, actual, tc.Result) 2254 } 2255 } 2256 } 2257 2258 func TestResourceDataSetConnInfo(t *testing.T) { 2259 d := &ResourceData{} 2260 d.SetId("foo") 2261 d.SetConnInfo(map[string]string{ 2262 "foo": "bar", 2263 }) 2264 2265 expected := map[string]string{ 2266 "foo": "bar", 2267 } 2268 2269 actual := d.State() 2270 if !reflect.DeepEqual(actual.Ephemeral.ConnInfo, expected) { 2271 t.Fatalf("bad: %#v", actual) 2272 } 2273 } 2274 2275 func TestResourceDataSetId(t *testing.T) { 2276 d := &ResourceData{} 2277 d.SetId("foo") 2278 2279 actual := d.State() 2280 if actual.ID != "foo" { 2281 t.Fatalf("bad: %#v", actual) 2282 } 2283 } 2284 2285 func TestResourceDataSetId_clear(t *testing.T) { 2286 d := &ResourceData{ 2287 state: &terraform.InstanceState{ID: "bar"}, 2288 } 2289 d.SetId("") 2290 2291 actual := d.State() 2292 if actual != nil { 2293 t.Fatalf("bad: %#v", actual) 2294 } 2295 } 2296 2297 func TestResourceDataSetId_override(t *testing.T) { 2298 d := &ResourceData{ 2299 state: &terraform.InstanceState{ID: "bar"}, 2300 } 2301 d.SetId("foo") 2302 2303 actual := d.State() 2304 if actual.ID != "foo" { 2305 t.Fatalf("bad: %#v", actual) 2306 } 2307 }