github.com/nalum/terraform@v0.3.2-0.20141223102918-aa2c22ffeff6/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 597 for i, tc := range cases { 598 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 599 if err != nil { 600 t.Fatalf("err: %s", err) 601 } 602 603 v := d.Get(tc.Key) 604 if s, ok := v.(*Set); ok { 605 v = s.List() 606 } 607 608 if !reflect.DeepEqual(v, tc.Value) { 609 t.Fatalf("Bad: %d\n\n%#v", i, v) 610 } 611 } 612 } 613 614 func TestResourceDataGetChange(t *testing.T) { 615 cases := []struct { 616 Schema map[string]*Schema 617 State *terraform.InstanceState 618 Diff *terraform.InstanceDiff 619 Key string 620 OldValue interface{} 621 NewValue interface{} 622 }{ 623 { 624 Schema: map[string]*Schema{ 625 "availability_zone": &Schema{ 626 Type: TypeString, 627 Optional: true, 628 Computed: true, 629 ForceNew: true, 630 }, 631 }, 632 633 State: nil, 634 635 Diff: &terraform.InstanceDiff{ 636 Attributes: map[string]*terraform.ResourceAttrDiff{ 637 "availability_zone": &terraform.ResourceAttrDiff{ 638 Old: "", 639 New: "foo", 640 RequiresNew: true, 641 }, 642 }, 643 }, 644 645 Key: "availability_zone", 646 647 OldValue: "", 648 NewValue: "foo", 649 }, 650 651 { 652 Schema: map[string]*Schema{ 653 "availability_zone": &Schema{ 654 Type: TypeString, 655 Optional: true, 656 Computed: true, 657 ForceNew: true, 658 }, 659 }, 660 661 State: &terraform.InstanceState{ 662 Attributes: map[string]string{ 663 "availability_zone": "foo", 664 }, 665 }, 666 667 Diff: &terraform.InstanceDiff{ 668 Attributes: map[string]*terraform.ResourceAttrDiff{ 669 "availability_zone": &terraform.ResourceAttrDiff{ 670 Old: "", 671 New: "foo", 672 RequiresNew: true, 673 }, 674 }, 675 }, 676 677 Key: "availability_zone", 678 679 OldValue: "foo", 680 NewValue: "foo", 681 }, 682 } 683 684 for i, tc := range cases { 685 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 686 if err != nil { 687 t.Fatalf("err: %s", err) 688 } 689 690 o, n := d.GetChange(tc.Key) 691 if !reflect.DeepEqual(o, tc.OldValue) { 692 t.Fatalf("Old Bad: %d\n\n%#v", i, o) 693 } 694 if !reflect.DeepEqual(n, tc.NewValue) { 695 t.Fatalf("New Bad: %d\n\n%#v", i, n) 696 } 697 } 698 } 699 700 func TestResourceDataGetOk(t *testing.T) { 701 cases := []struct { 702 Schema map[string]*Schema 703 State *terraform.InstanceState 704 Diff *terraform.InstanceDiff 705 Key string 706 Value interface{} 707 Ok bool 708 }{ 709 /* 710 * Primitives 711 */ 712 { 713 Schema: map[string]*Schema{ 714 "availability_zone": &Schema{ 715 Type: TypeString, 716 Optional: true, 717 Computed: true, 718 ForceNew: true, 719 }, 720 }, 721 722 State: nil, 723 724 Diff: &terraform.InstanceDiff{ 725 Attributes: map[string]*terraform.ResourceAttrDiff{ 726 "availability_zone": &terraform.ResourceAttrDiff{ 727 Old: "", 728 New: "", 729 }, 730 }, 731 }, 732 733 Key: "availability_zone", 734 Value: "", 735 Ok: true, 736 }, 737 738 { 739 Schema: map[string]*Schema{ 740 "availability_zone": &Schema{ 741 Type: TypeString, 742 Optional: true, 743 Computed: true, 744 ForceNew: true, 745 }, 746 }, 747 748 State: nil, 749 750 Diff: nil, 751 752 Key: "availability_zone", 753 Value: "", 754 Ok: false, 755 }, 756 757 /* 758 * Lists 759 */ 760 761 { 762 Schema: map[string]*Schema{ 763 "ports": &Schema{ 764 Type: TypeList, 765 Optional: true, 766 Elem: &Schema{Type: TypeInt}, 767 }, 768 }, 769 770 State: nil, 771 772 Diff: nil, 773 774 Key: "ports", 775 Value: []interface{}{}, 776 Ok: false, 777 }, 778 779 /* 780 * Map 781 */ 782 783 { 784 Schema: map[string]*Schema{ 785 "ports": &Schema{ 786 Type: TypeMap, 787 Optional: true, 788 }, 789 }, 790 791 State: nil, 792 793 Diff: nil, 794 795 Key: "ports", 796 Value: map[string]interface{}{}, 797 Ok: false, 798 }, 799 800 /* 801 * Set 802 */ 803 804 { 805 Schema: map[string]*Schema{ 806 "ports": &Schema{ 807 Type: TypeSet, 808 Optional: true, 809 Elem: &Schema{Type: TypeInt}, 810 Set: func(a interface{}) int { return a.(int) }, 811 }, 812 }, 813 814 State: nil, 815 816 Diff: nil, 817 818 Key: "ports", 819 Value: []interface{}{}, 820 Ok: false, 821 }, 822 823 { 824 Schema: map[string]*Schema{ 825 "ports": &Schema{ 826 Type: TypeSet, 827 Optional: true, 828 Elem: &Schema{Type: TypeInt}, 829 Set: func(a interface{}) int { return a.(int) }, 830 }, 831 }, 832 833 State: nil, 834 835 Diff: nil, 836 837 Key: "ports.0", 838 Value: 0, 839 Ok: false, 840 }, 841 } 842 843 for i, tc := range cases { 844 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 845 if err != nil { 846 t.Fatalf("err: %s", err) 847 } 848 849 v, ok := d.GetOk(tc.Key) 850 if s, ok := v.(*Set); ok { 851 v = s.List() 852 } 853 854 if !reflect.DeepEqual(v, tc.Value) { 855 t.Fatalf("Bad: %d\n\n%#v", i, v) 856 } 857 if ok != tc.Ok { 858 t.Fatalf("Bad: %d\n\n%#v", i, ok) 859 } 860 } 861 } 862 863 func TestResourceDataHasChange(t *testing.T) { 864 cases := []struct { 865 Schema map[string]*Schema 866 State *terraform.InstanceState 867 Diff *terraform.InstanceDiff 868 Key string 869 Change bool 870 }{ 871 { 872 Schema: map[string]*Schema{ 873 "availability_zone": &Schema{ 874 Type: TypeString, 875 Optional: true, 876 Computed: true, 877 ForceNew: true, 878 }, 879 }, 880 881 State: nil, 882 883 Diff: &terraform.InstanceDiff{ 884 Attributes: map[string]*terraform.ResourceAttrDiff{ 885 "availability_zone": &terraform.ResourceAttrDiff{ 886 Old: "", 887 New: "foo", 888 RequiresNew: true, 889 }, 890 }, 891 }, 892 893 Key: "availability_zone", 894 895 Change: true, 896 }, 897 898 { 899 Schema: map[string]*Schema{ 900 "availability_zone": &Schema{ 901 Type: TypeString, 902 Optional: true, 903 Computed: true, 904 ForceNew: true, 905 }, 906 }, 907 908 State: &terraform.InstanceState{ 909 Attributes: map[string]string{ 910 "availability_zone": "foo", 911 }, 912 }, 913 914 Diff: &terraform.InstanceDiff{ 915 Attributes: map[string]*terraform.ResourceAttrDiff{ 916 "availability_zone": &terraform.ResourceAttrDiff{ 917 Old: "", 918 New: "foo", 919 RequiresNew: true, 920 }, 921 }, 922 }, 923 924 Key: "availability_zone", 925 926 Change: false, 927 }, 928 929 { 930 Schema: map[string]*Schema{ 931 "tags": &Schema{ 932 Type: TypeMap, 933 Optional: true, 934 Computed: true, 935 }, 936 }, 937 938 State: nil, 939 940 Diff: &terraform.InstanceDiff{ 941 Attributes: map[string]*terraform.ResourceAttrDiff{ 942 "tags.Name": &terraform.ResourceAttrDiff{ 943 Old: "foo", 944 New: "foo", 945 }, 946 }, 947 }, 948 949 Key: "tags", 950 951 Change: true, 952 }, 953 } 954 955 for i, tc := range cases { 956 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 957 if err != nil { 958 t.Fatalf("err: %s", err) 959 } 960 961 actual := d.HasChange(tc.Key) 962 if actual != tc.Change { 963 t.Fatalf("Bad: %d %#v", i, actual) 964 } 965 } 966 } 967 968 func TestResourceDataSet(t *testing.T) { 969 cases := []struct { 970 Schema map[string]*Schema 971 State *terraform.InstanceState 972 Diff *terraform.InstanceDiff 973 Key string 974 Value interface{} 975 Err bool 976 GetKey string 977 GetValue interface{} 978 }{ 979 // Basic good 980 { 981 Schema: map[string]*Schema{ 982 "availability_zone": &Schema{ 983 Type: TypeString, 984 Optional: true, 985 Computed: true, 986 ForceNew: true, 987 }, 988 }, 989 990 State: nil, 991 992 Diff: nil, 993 994 Key: "availability_zone", 995 Value: "foo", 996 997 GetKey: "availability_zone", 998 GetValue: "foo", 999 }, 1000 1001 // Basic int 1002 { 1003 Schema: map[string]*Schema{ 1004 "port": &Schema{ 1005 Type: TypeInt, 1006 Optional: true, 1007 Computed: true, 1008 ForceNew: true, 1009 }, 1010 }, 1011 1012 State: nil, 1013 1014 Diff: nil, 1015 1016 Key: "port", 1017 Value: 80, 1018 1019 GetKey: "port", 1020 GetValue: 80, 1021 }, 1022 1023 // Basic bool 1024 { 1025 Schema: map[string]*Schema{ 1026 "vpc": &Schema{ 1027 Type: TypeBool, 1028 Optional: true, 1029 }, 1030 }, 1031 1032 State: nil, 1033 1034 Diff: nil, 1035 1036 Key: "vpc", 1037 Value: true, 1038 1039 GetKey: "vpc", 1040 GetValue: true, 1041 }, 1042 1043 { 1044 Schema: map[string]*Schema{ 1045 "vpc": &Schema{ 1046 Type: TypeBool, 1047 Optional: true, 1048 }, 1049 }, 1050 1051 State: nil, 1052 1053 Diff: nil, 1054 1055 Key: "vpc", 1056 Value: false, 1057 1058 GetKey: "vpc", 1059 GetValue: false, 1060 }, 1061 1062 // Invalid type 1063 { 1064 Schema: map[string]*Schema{ 1065 "availability_zone": &Schema{ 1066 Type: TypeString, 1067 Optional: true, 1068 Computed: true, 1069 ForceNew: true, 1070 }, 1071 }, 1072 1073 State: nil, 1074 1075 Diff: nil, 1076 1077 Key: "availability_zone", 1078 Value: 80, 1079 Err: true, 1080 1081 GetKey: "availability_zone", 1082 GetValue: "", 1083 }, 1084 1085 // List of primitives, set element 1086 { 1087 Schema: map[string]*Schema{ 1088 "ports": &Schema{ 1089 Type: TypeList, 1090 Computed: true, 1091 Elem: &Schema{Type: TypeInt}, 1092 }, 1093 }, 1094 1095 State: &terraform.InstanceState{ 1096 Attributes: map[string]string{ 1097 "ports.#": "3", 1098 "ports.0": "1", 1099 "ports.1": "2", 1100 "ports.2": "5", 1101 }, 1102 }, 1103 1104 Diff: nil, 1105 1106 Key: "ports.1", 1107 Value: 3, 1108 1109 GetKey: "ports", 1110 GetValue: []interface{}{1, 3, 5}, 1111 }, 1112 1113 // 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 // 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 // List of resource, set element 1157 { 1158 Schema: map[string]*Schema{ 1159 "ingress": &Schema{ 1160 Type: TypeList, 1161 Computed: true, 1162 Elem: &Resource{ 1163 Schema: map[string]*Schema{ 1164 "from": &Schema{ 1165 Type: TypeInt, 1166 }, 1167 }, 1168 }, 1169 }, 1170 }, 1171 1172 State: &terraform.InstanceState{ 1173 Attributes: map[string]string{ 1174 "ingress.#": "2", 1175 "ingress.0.from": "80", 1176 "ingress.1.from": "8080", 1177 }, 1178 }, 1179 1180 Diff: nil, 1181 1182 Key: "ingress.1.from", 1183 Value: 9000, 1184 1185 GetKey: "ingress", 1186 GetValue: []interface{}{ 1187 map[string]interface{}{ 1188 "from": 80, 1189 }, 1190 map[string]interface{}{ 1191 "from": 9000, 1192 }, 1193 }, 1194 }, 1195 1196 // List of resource, set full resource element 1197 { 1198 Schema: map[string]*Schema{ 1199 "ingress": &Schema{ 1200 Type: TypeList, 1201 Computed: true, 1202 Elem: &Resource{ 1203 Schema: map[string]*Schema{ 1204 "from": &Schema{ 1205 Type: TypeInt, 1206 }, 1207 }, 1208 }, 1209 }, 1210 }, 1211 1212 State: &terraform.InstanceState{ 1213 Attributes: map[string]string{ 1214 "ingress.#": "2", 1215 "ingress.0.from": "80", 1216 "ingress.1.from": "8080", 1217 }, 1218 }, 1219 1220 Diff: nil, 1221 1222 Key: "ingress.1", 1223 Value: map[string]interface{}{ 1224 "from": 9000, 1225 }, 1226 1227 GetKey: "ingress", 1228 GetValue: []interface{}{ 1229 map[string]interface{}{ 1230 "from": 80, 1231 }, 1232 map[string]interface{}{ 1233 "from": 9000, 1234 }, 1235 }, 1236 }, 1237 1238 // List of resource, set full resource element, with error 1239 { 1240 Schema: map[string]*Schema{ 1241 "ingress": &Schema{ 1242 Type: TypeList, 1243 Computed: true, 1244 Elem: &Resource{ 1245 Schema: map[string]*Schema{ 1246 "from": &Schema{ 1247 Type: TypeInt, 1248 }, 1249 "to": &Schema{ 1250 Type: TypeInt, 1251 }, 1252 }, 1253 }, 1254 }, 1255 }, 1256 1257 State: &terraform.InstanceState{ 1258 Attributes: map[string]string{ 1259 "ingress.#": "2", 1260 "ingress.0.from": "80", 1261 "ingress.0.to": "10", 1262 "ingress.1.from": "8080", 1263 "ingress.1.to": "8080", 1264 }, 1265 }, 1266 1267 Diff: nil, 1268 1269 Key: "ingress.1", 1270 Value: map[string]interface{}{ 1271 "from": 9000, 1272 "to": "bar", 1273 }, 1274 Err: true, 1275 1276 GetKey: "ingress", 1277 GetValue: []interface{}{ 1278 map[string]interface{}{ 1279 "from": 80, 1280 "to": 10, 1281 }, 1282 map[string]interface{}{ 1283 "from": 8080, 1284 "to": 8080, 1285 }, 1286 }, 1287 }, 1288 1289 // Set a list of maps 1290 { 1291 Schema: map[string]*Schema{ 1292 "config_vars": &Schema{ 1293 Type: TypeList, 1294 Optional: true, 1295 Computed: true, 1296 Elem: &Schema{ 1297 Type: TypeMap, 1298 }, 1299 }, 1300 }, 1301 1302 State: nil, 1303 1304 Diff: nil, 1305 1306 Key: "config_vars", 1307 Value: []interface{}{ 1308 map[string]interface{}{ 1309 "foo": "bar", 1310 }, 1311 map[string]interface{}{ 1312 "bar": "baz", 1313 }, 1314 }, 1315 Err: false, 1316 1317 GetKey: "config_vars", 1318 GetValue: []interface{}{ 1319 map[string]interface{}{ 1320 "foo": "bar", 1321 }, 1322 map[string]interface{}{ 1323 "bar": "baz", 1324 }, 1325 }, 1326 }, 1327 1328 // Set a list of maps 1329 { 1330 Schema: map[string]*Schema{ 1331 "config_vars": &Schema{ 1332 Type: TypeList, 1333 Optional: true, 1334 Computed: true, 1335 Elem: &Schema{ 1336 Type: TypeMap, 1337 }, 1338 }, 1339 }, 1340 1341 State: nil, 1342 1343 Diff: nil, 1344 1345 Key: "config_vars", 1346 Value: []interface{}{ 1347 map[string]string{ 1348 "foo": "bar", 1349 }, 1350 map[string]string{ 1351 "bar": "baz", 1352 }, 1353 }, 1354 Err: false, 1355 1356 GetKey: "config_vars", 1357 GetValue: []interface{}{ 1358 map[string]interface{}{ 1359 "foo": "bar", 1360 }, 1361 map[string]interface{}{ 1362 "bar": "baz", 1363 }, 1364 }, 1365 }, 1366 1367 // Set, with list 1368 { 1369 Schema: map[string]*Schema{ 1370 "ports": &Schema{ 1371 Type: TypeSet, 1372 Optional: true, 1373 Computed: true, 1374 Elem: &Schema{Type: TypeInt}, 1375 Set: func(a interface{}) int { 1376 return a.(int) 1377 }, 1378 }, 1379 }, 1380 1381 State: &terraform.InstanceState{ 1382 Attributes: map[string]string{ 1383 "ports.#": "3", 1384 "ports.0": "100", 1385 "ports.1": "80", 1386 "ports.2": "80", 1387 }, 1388 }, 1389 1390 Key: "ports", 1391 Value: []interface{}{100, 125, 125}, 1392 1393 GetKey: "ports", 1394 GetValue: []interface{}{100, 125}, 1395 }, 1396 1397 // Set, with Set 1398 { 1399 Schema: map[string]*Schema{ 1400 "ports": &Schema{ 1401 Type: TypeSet, 1402 Optional: true, 1403 Computed: true, 1404 Elem: &Schema{Type: TypeInt}, 1405 Set: func(a interface{}) int { 1406 return a.(int) 1407 }, 1408 }, 1409 }, 1410 1411 State: &terraform.InstanceState{ 1412 Attributes: map[string]string{ 1413 "ports.#": "3", 1414 "ports.100": "100", 1415 "ports.80": "80", 1416 "ports.81": "81", 1417 }, 1418 }, 1419 1420 Key: "ports", 1421 Value: &Set{ 1422 m: map[int]interface{}{ 1423 1: 1, 1424 2: 2, 1425 }, 1426 }, 1427 1428 GetKey: "ports", 1429 GetValue: []interface{}{1, 2}, 1430 }, 1431 1432 // Set single item 1433 { 1434 Schema: map[string]*Schema{ 1435 "ports": &Schema{ 1436 Type: TypeSet, 1437 Optional: true, 1438 Computed: true, 1439 Elem: &Schema{Type: TypeInt}, 1440 Set: func(a interface{}) int { 1441 return a.(int) 1442 }, 1443 }, 1444 }, 1445 1446 State: &terraform.InstanceState{ 1447 Attributes: map[string]string{ 1448 "ports.#": "2", 1449 "ports.100": "100", 1450 "ports.80": "80", 1451 }, 1452 }, 1453 1454 Key: "ports.100", 1455 Value: 256, 1456 Err: true, 1457 1458 GetKey: "ports", 1459 GetValue: []interface{}{80, 100}, 1460 }, 1461 } 1462 1463 for i, tc := range cases { 1464 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 1465 if err != nil { 1466 t.Fatalf("err: %s", err) 1467 } 1468 1469 err = d.Set(tc.Key, tc.Value) 1470 if (err != nil) != tc.Err { 1471 t.Fatalf("%d err: %s", i, err) 1472 } 1473 1474 v := d.Get(tc.GetKey) 1475 if s, ok := v.(*Set); ok { 1476 v = s.List() 1477 } 1478 if !reflect.DeepEqual(v, tc.GetValue) { 1479 t.Fatalf("Get Bad: %d\n\n%#v", i, v) 1480 } 1481 } 1482 } 1483 1484 func TestResourceDataState(t *testing.T) { 1485 cases := []struct { 1486 Schema map[string]*Schema 1487 State *terraform.InstanceState 1488 Diff *terraform.InstanceDiff 1489 Set map[string]interface{} 1490 Result *terraform.InstanceState 1491 Partial []string 1492 }{ 1493 // Basic primitive in diff 1494 { 1495 Schema: map[string]*Schema{ 1496 "availability_zone": &Schema{ 1497 Type: TypeString, 1498 Optional: true, 1499 Computed: true, 1500 ForceNew: true, 1501 }, 1502 }, 1503 1504 State: nil, 1505 1506 Diff: &terraform.InstanceDiff{ 1507 Attributes: map[string]*terraform.ResourceAttrDiff{ 1508 "availability_zone": &terraform.ResourceAttrDiff{ 1509 Old: "", 1510 New: "foo", 1511 RequiresNew: true, 1512 }, 1513 }, 1514 }, 1515 1516 Result: &terraform.InstanceState{ 1517 Attributes: map[string]string{ 1518 "availability_zone": "foo", 1519 }, 1520 }, 1521 }, 1522 1523 // Basic primitive set override 1524 { 1525 Schema: map[string]*Schema{ 1526 "availability_zone": &Schema{ 1527 Type: TypeString, 1528 Optional: true, 1529 Computed: true, 1530 ForceNew: true, 1531 }, 1532 }, 1533 1534 State: nil, 1535 1536 Diff: &terraform.InstanceDiff{ 1537 Attributes: map[string]*terraform.ResourceAttrDiff{ 1538 "availability_zone": &terraform.ResourceAttrDiff{ 1539 Old: "", 1540 New: "foo", 1541 RequiresNew: true, 1542 }, 1543 }, 1544 }, 1545 1546 Set: map[string]interface{}{ 1547 "availability_zone": "bar", 1548 }, 1549 1550 Result: &terraform.InstanceState{ 1551 Attributes: map[string]string{ 1552 "availability_zone": "bar", 1553 }, 1554 }, 1555 }, 1556 1557 { 1558 Schema: map[string]*Schema{ 1559 "vpc": &Schema{ 1560 Type: TypeBool, 1561 Optional: true, 1562 }, 1563 }, 1564 1565 State: nil, 1566 1567 Diff: nil, 1568 1569 Set: map[string]interface{}{ 1570 "vpc": true, 1571 }, 1572 1573 Result: &terraform.InstanceState{ 1574 Attributes: map[string]string{ 1575 "vpc": "true", 1576 }, 1577 }, 1578 }, 1579 1580 // Basic primitive with StateFunc set 1581 { 1582 Schema: map[string]*Schema{ 1583 "availability_zone": &Schema{ 1584 Type: TypeString, 1585 Optional: true, 1586 Computed: true, 1587 StateFunc: func(interface{}) string { return "" }, 1588 }, 1589 }, 1590 1591 State: nil, 1592 1593 Diff: &terraform.InstanceDiff{ 1594 Attributes: map[string]*terraform.ResourceAttrDiff{ 1595 "availability_zone": &terraform.ResourceAttrDiff{ 1596 Old: "", 1597 New: "foo", 1598 NewExtra: "foo!", 1599 }, 1600 }, 1601 }, 1602 1603 Result: &terraform.InstanceState{ 1604 Attributes: map[string]string{ 1605 "availability_zone": "foo", 1606 }, 1607 }, 1608 }, 1609 1610 // List 1611 { 1612 Schema: map[string]*Schema{ 1613 "ports": &Schema{ 1614 Type: TypeList, 1615 Required: true, 1616 Elem: &Schema{Type: TypeInt}, 1617 }, 1618 }, 1619 1620 State: &terraform.InstanceState{ 1621 Attributes: map[string]string{ 1622 "ports.#": "1", 1623 "ports.0": "80", 1624 }, 1625 }, 1626 1627 Diff: &terraform.InstanceDiff{ 1628 Attributes: map[string]*terraform.ResourceAttrDiff{ 1629 "ports.#": &terraform.ResourceAttrDiff{ 1630 Old: "1", 1631 New: "2", 1632 }, 1633 "ports.1": &terraform.ResourceAttrDiff{ 1634 Old: "", 1635 New: "100", 1636 }, 1637 }, 1638 }, 1639 1640 Result: &terraform.InstanceState{ 1641 Attributes: map[string]string{ 1642 "ports.#": "2", 1643 "ports.0": "80", 1644 "ports.1": "100", 1645 }, 1646 }, 1647 }, 1648 1649 // List of resources 1650 { 1651 Schema: map[string]*Schema{ 1652 "ingress": &Schema{ 1653 Type: TypeList, 1654 Required: true, 1655 Elem: &Resource{ 1656 Schema: map[string]*Schema{ 1657 "from": &Schema{ 1658 Type: TypeInt, 1659 Required: true, 1660 }, 1661 }, 1662 }, 1663 }, 1664 }, 1665 1666 State: &terraform.InstanceState{ 1667 Attributes: map[string]string{ 1668 "ingress.#": "1", 1669 "ingress.0.from": "80", 1670 }, 1671 }, 1672 1673 Diff: &terraform.InstanceDiff{ 1674 Attributes: map[string]*terraform.ResourceAttrDiff{ 1675 "ingress.#": &terraform.ResourceAttrDiff{ 1676 Old: "1", 1677 New: "2", 1678 }, 1679 "ingress.0.from": &terraform.ResourceAttrDiff{ 1680 Old: "80", 1681 New: "150", 1682 }, 1683 "ingress.1.from": &terraform.ResourceAttrDiff{ 1684 Old: "", 1685 New: "100", 1686 }, 1687 }, 1688 }, 1689 1690 Result: &terraform.InstanceState{ 1691 Attributes: map[string]string{ 1692 "ingress.#": "2", 1693 "ingress.0.from": "150", 1694 "ingress.1.from": "100", 1695 }, 1696 }, 1697 }, 1698 1699 // List of maps 1700 { 1701 Schema: map[string]*Schema{ 1702 "config_vars": &Schema{ 1703 Type: TypeList, 1704 Optional: true, 1705 Computed: true, 1706 Elem: &Schema{ 1707 Type: TypeMap, 1708 }, 1709 }, 1710 }, 1711 1712 State: &terraform.InstanceState{ 1713 Attributes: map[string]string{ 1714 "config_vars.#": "2", 1715 "config_vars.0.foo": "bar", 1716 "config_vars.0.bar": "bar", 1717 "config_vars.1.bar": "baz", 1718 }, 1719 }, 1720 1721 Diff: &terraform.InstanceDiff{ 1722 Attributes: map[string]*terraform.ResourceAttrDiff{ 1723 "config_vars.0.bar": &terraform.ResourceAttrDiff{ 1724 NewRemoved: true, 1725 }, 1726 }, 1727 }, 1728 1729 Set: map[string]interface{}{ 1730 "config_vars.1": map[string]interface{}{ 1731 "baz": "bang", 1732 }, 1733 }, 1734 1735 Result: &terraform.InstanceState{ 1736 Attributes: map[string]string{ 1737 "config_vars.#": "2", 1738 "config_vars.0.foo": "bar", 1739 "config_vars.1.baz": "bang", 1740 }, 1741 }, 1742 }, 1743 1744 // List of maps with removal in diff 1745 { 1746 Schema: map[string]*Schema{ 1747 "config_vars": &Schema{ 1748 Type: TypeList, 1749 Optional: true, 1750 Computed: true, 1751 Elem: &Schema{ 1752 Type: TypeMap, 1753 }, 1754 }, 1755 }, 1756 1757 State: &terraform.InstanceState{ 1758 Attributes: map[string]string{ 1759 "config_vars.#": "1", 1760 "config_vars.0.FOO": "bar", 1761 }, 1762 }, 1763 1764 Diff: &terraform.InstanceDiff{ 1765 Attributes: map[string]*terraform.ResourceAttrDiff{ 1766 "config_vars.#": &terraform.ResourceAttrDiff{ 1767 Old: "1", 1768 New: "0", 1769 }, 1770 "config_vars.0.FOO": &terraform.ResourceAttrDiff{ 1771 Old: "bar", 1772 NewRemoved: true, 1773 }, 1774 }, 1775 }, 1776 1777 Result: &terraform.InstanceState{ 1778 Attributes: map[string]string{ 1779 "config_vars.#": "0", 1780 }, 1781 }, 1782 }, 1783 1784 // Basic state with other keys 1785 { 1786 Schema: map[string]*Schema{ 1787 "availability_zone": &Schema{ 1788 Type: TypeString, 1789 Optional: true, 1790 Computed: true, 1791 ForceNew: true, 1792 }, 1793 }, 1794 1795 State: &terraform.InstanceState{ 1796 ID: "bar", 1797 Attributes: map[string]string{ 1798 "id": "bar", 1799 }, 1800 }, 1801 1802 Diff: &terraform.InstanceDiff{ 1803 Attributes: map[string]*terraform.ResourceAttrDiff{ 1804 "availability_zone": &terraform.ResourceAttrDiff{ 1805 Old: "", 1806 New: "foo", 1807 RequiresNew: true, 1808 }, 1809 }, 1810 }, 1811 1812 Result: &terraform.InstanceState{ 1813 ID: "bar", 1814 Attributes: map[string]string{ 1815 "id": "bar", 1816 "availability_zone": "foo", 1817 }, 1818 }, 1819 }, 1820 1821 // Sets 1822 { 1823 Schema: map[string]*Schema{ 1824 "ports": &Schema{ 1825 Type: TypeSet, 1826 Optional: true, 1827 Computed: true, 1828 Elem: &Schema{Type: TypeInt}, 1829 Set: func(a interface{}) int { 1830 return a.(int) 1831 }, 1832 }, 1833 }, 1834 1835 State: &terraform.InstanceState{ 1836 Attributes: map[string]string{ 1837 "ports.#": "3", 1838 "ports.100": "100", 1839 "ports.80": "80", 1840 "ports.81": "81", 1841 }, 1842 }, 1843 1844 Diff: nil, 1845 1846 Result: &terraform.InstanceState{ 1847 Attributes: map[string]string{ 1848 "ports.#": "3", 1849 "ports.80": "80", 1850 "ports.81": "81", 1851 "ports.100": "100", 1852 }, 1853 }, 1854 }, 1855 1856 { 1857 Schema: map[string]*Schema{ 1858 "ports": &Schema{ 1859 Type: TypeSet, 1860 Optional: true, 1861 Computed: true, 1862 Elem: &Schema{Type: TypeInt}, 1863 Set: func(a interface{}) int { 1864 return a.(int) 1865 }, 1866 }, 1867 }, 1868 1869 State: nil, 1870 1871 Diff: nil, 1872 1873 Set: map[string]interface{}{ 1874 "ports": []interface{}{100, 80}, 1875 }, 1876 1877 Result: &terraform.InstanceState{ 1878 Attributes: map[string]string{ 1879 "ports.#": "2", 1880 "ports.80": "80", 1881 "ports.100": "100", 1882 }, 1883 }, 1884 }, 1885 1886 { 1887 Schema: map[string]*Schema{ 1888 "ports": &Schema{ 1889 Type: TypeSet, 1890 Optional: true, 1891 Computed: true, 1892 Elem: &Resource{ 1893 Schema: map[string]*Schema{ 1894 "order": &Schema{ 1895 Type: TypeInt, 1896 }, 1897 1898 "a": &Schema{ 1899 Type: TypeList, 1900 Elem: &Schema{Type: TypeInt}, 1901 }, 1902 1903 "b": &Schema{ 1904 Type: TypeList, 1905 Elem: &Schema{Type: TypeInt}, 1906 }, 1907 }, 1908 }, 1909 Set: func(a interface{}) int { 1910 m := a.(map[string]interface{}) 1911 return m["order"].(int) 1912 }, 1913 }, 1914 }, 1915 1916 State: &terraform.InstanceState{ 1917 Attributes: map[string]string{ 1918 "ports.#": "2", 1919 "ports.10.order": "10", 1920 "ports.10.a.#": "1", 1921 "ports.10.a.0": "80", 1922 "ports.20.order": "20", 1923 "ports.20.b.#": "1", 1924 "ports.20.b.0": "100", 1925 }, 1926 }, 1927 1928 Set: map[string]interface{}{ 1929 "ports": []interface{}{ 1930 map[string]interface{}{ 1931 "order": 20, 1932 "b": []interface{}{100}, 1933 }, 1934 map[string]interface{}{ 1935 "order": 10, 1936 "a": []interface{}{80}, 1937 }, 1938 }, 1939 }, 1940 1941 Result: &terraform.InstanceState{ 1942 Attributes: map[string]string{ 1943 "ports.#": "2", 1944 "ports.10.order": "10", 1945 "ports.10.a.#": "1", 1946 "ports.10.a.0": "80", 1947 "ports.20.order": "20", 1948 "ports.20.b.#": "1", 1949 "ports.20.b.0": "100", 1950 }, 1951 }, 1952 }, 1953 1954 /* 1955 * PARTIAL STATES 1956 */ 1957 1958 // Basic primitive 1959 { 1960 Schema: map[string]*Schema{ 1961 "availability_zone": &Schema{ 1962 Type: TypeString, 1963 Optional: true, 1964 Computed: true, 1965 ForceNew: true, 1966 }, 1967 }, 1968 1969 State: nil, 1970 1971 Diff: &terraform.InstanceDiff{ 1972 Attributes: map[string]*terraform.ResourceAttrDiff{ 1973 "availability_zone": &terraform.ResourceAttrDiff{ 1974 Old: "", 1975 New: "foo", 1976 RequiresNew: true, 1977 }, 1978 }, 1979 }, 1980 1981 Partial: []string{}, 1982 1983 Result: &terraform.InstanceState{ 1984 Attributes: map[string]string{}, 1985 }, 1986 }, 1987 1988 // List 1989 { 1990 Schema: map[string]*Schema{ 1991 "ports": &Schema{ 1992 Type: TypeList, 1993 Required: true, 1994 Elem: &Schema{Type: TypeInt}, 1995 }, 1996 }, 1997 1998 State: &terraform.InstanceState{ 1999 Attributes: map[string]string{ 2000 "ports.#": "1", 2001 "ports.0": "80", 2002 }, 2003 }, 2004 2005 Diff: &terraform.InstanceDiff{ 2006 Attributes: map[string]*terraform.ResourceAttrDiff{ 2007 "ports.#": &terraform.ResourceAttrDiff{ 2008 Old: "1", 2009 New: "2", 2010 }, 2011 "ports.1": &terraform.ResourceAttrDiff{ 2012 Old: "", 2013 New: "100", 2014 }, 2015 }, 2016 }, 2017 2018 Partial: []string{}, 2019 2020 Result: &terraform.InstanceState{ 2021 Attributes: map[string]string{ 2022 "ports.#": "1", 2023 "ports.0": "80", 2024 }, 2025 }, 2026 }, 2027 2028 { 2029 Schema: map[string]*Schema{ 2030 "ports": &Schema{ 2031 Type: TypeList, 2032 Optional: true, 2033 Computed: true, 2034 Elem: &Schema{Type: TypeInt}, 2035 }, 2036 }, 2037 2038 State: nil, 2039 2040 Diff: &terraform.InstanceDiff{ 2041 Attributes: map[string]*terraform.ResourceAttrDiff{ 2042 "ports.#": &terraform.ResourceAttrDiff{ 2043 Old: "", 2044 NewComputed: true, 2045 }, 2046 }, 2047 }, 2048 2049 Partial: []string{}, 2050 2051 Set: map[string]interface{}{ 2052 "ports": []interface{}{}, 2053 }, 2054 2055 Result: &terraform.InstanceState{ 2056 Attributes: map[string]string{ 2057 "ports.#": "0", 2058 }, 2059 }, 2060 }, 2061 2062 // List of resources 2063 { 2064 Schema: map[string]*Schema{ 2065 "ingress": &Schema{ 2066 Type: TypeList, 2067 Required: true, 2068 Elem: &Resource{ 2069 Schema: map[string]*Schema{ 2070 "from": &Schema{ 2071 Type: TypeInt, 2072 Required: true, 2073 }, 2074 }, 2075 }, 2076 }, 2077 }, 2078 2079 State: &terraform.InstanceState{ 2080 Attributes: map[string]string{ 2081 "ingress.#": "1", 2082 "ingress.0.from": "80", 2083 }, 2084 }, 2085 2086 Diff: &terraform.InstanceDiff{ 2087 Attributes: map[string]*terraform.ResourceAttrDiff{ 2088 "ingress.#": &terraform.ResourceAttrDiff{ 2089 Old: "1", 2090 New: "2", 2091 }, 2092 "ingress.0.from": &terraform.ResourceAttrDiff{ 2093 Old: "80", 2094 New: "150", 2095 }, 2096 "ingress.1.from": &terraform.ResourceAttrDiff{ 2097 Old: "", 2098 New: "100", 2099 }, 2100 }, 2101 }, 2102 2103 Partial: []string{}, 2104 2105 Result: &terraform.InstanceState{ 2106 Attributes: map[string]string{ 2107 "ingress.#": "1", 2108 "ingress.0.from": "80", 2109 }, 2110 }, 2111 }, 2112 2113 // List of maps 2114 { 2115 Schema: map[string]*Schema{ 2116 "config_vars": &Schema{ 2117 Type: TypeList, 2118 Optional: true, 2119 Computed: true, 2120 Elem: &Schema{ 2121 Type: TypeMap, 2122 }, 2123 }, 2124 }, 2125 2126 State: &terraform.InstanceState{ 2127 Attributes: map[string]string{ 2128 "config_vars.#": "2", 2129 "config_vars.0.foo": "bar", 2130 "config_vars.0.bar": "bar", 2131 "config_vars.1.bar": "baz", 2132 }, 2133 }, 2134 2135 Diff: &terraform.InstanceDiff{ 2136 Attributes: map[string]*terraform.ResourceAttrDiff{ 2137 "config_vars.0.bar": &terraform.ResourceAttrDiff{ 2138 NewRemoved: true, 2139 }, 2140 }, 2141 }, 2142 2143 Set: map[string]interface{}{ 2144 "config_vars.1": map[string]interface{}{ 2145 "baz": "bang", 2146 }, 2147 }, 2148 2149 Partial: []string{}, 2150 2151 Result: &terraform.InstanceState{ 2152 Attributes: map[string]string{ 2153 "config_vars.#": "2", 2154 "config_vars.0.foo": "bar", 2155 "config_vars.0.bar": "bar", 2156 "config_vars.1.bar": "baz", 2157 }, 2158 }, 2159 }, 2160 2161 // Sets 2162 { 2163 Schema: map[string]*Schema{ 2164 "ports": &Schema{ 2165 Type: TypeSet, 2166 Optional: true, 2167 Computed: true, 2168 Elem: &Schema{Type: TypeInt}, 2169 Set: func(a interface{}) int { 2170 return a.(int) 2171 }, 2172 }, 2173 }, 2174 2175 State: &terraform.InstanceState{ 2176 Attributes: map[string]string{ 2177 "ports.#": "3", 2178 "ports.100": "100", 2179 "ports.80": "80", 2180 "ports.81": "81", 2181 }, 2182 }, 2183 2184 Diff: &terraform.InstanceDiff{ 2185 Attributes: map[string]*terraform.ResourceAttrDiff{ 2186 "ports.120": &terraform.ResourceAttrDiff{ 2187 New: "120", 2188 }, 2189 }, 2190 }, 2191 2192 Partial: []string{}, 2193 2194 Result: &terraform.InstanceState{ 2195 Attributes: map[string]string{ 2196 "ports.#": "3", 2197 "ports.80": "80", 2198 "ports.81": "81", 2199 "ports.100": "100", 2200 }, 2201 }, 2202 }, 2203 2204 { 2205 Schema: map[string]*Schema{ 2206 "ports": &Schema{ 2207 Type: TypeSet, 2208 Optional: true, 2209 Computed: true, 2210 Elem: &Schema{Type: TypeInt}, 2211 Set: func(a interface{}) int { 2212 return a.(int) 2213 }, 2214 }, 2215 }, 2216 2217 State: nil, 2218 2219 Diff: &terraform.InstanceDiff{ 2220 Attributes: map[string]*terraform.ResourceAttrDiff{ 2221 "ports.#": &terraform.ResourceAttrDiff{ 2222 Old: "", 2223 NewComputed: true, 2224 }, 2225 }, 2226 }, 2227 2228 Partial: []string{}, 2229 2230 Result: &terraform.InstanceState{ 2231 Attributes: map[string]string{ 2232 "ports.#": "0", 2233 }, 2234 }, 2235 }, 2236 2237 // Maps 2238 { 2239 Schema: map[string]*Schema{ 2240 "tags": &Schema{ 2241 Type: TypeMap, 2242 Optional: true, 2243 Computed: true, 2244 }, 2245 }, 2246 2247 State: nil, 2248 2249 Diff: &terraform.InstanceDiff{ 2250 Attributes: map[string]*terraform.ResourceAttrDiff{ 2251 "tags.Name": &terraform.ResourceAttrDiff{ 2252 Old: "", 2253 New: "foo", 2254 }, 2255 }, 2256 }, 2257 2258 Result: &terraform.InstanceState{ 2259 Attributes: map[string]string{ 2260 "tags.Name": "foo", 2261 }, 2262 }, 2263 }, 2264 2265 { 2266 Schema: map[string]*Schema{ 2267 "tags": &Schema{ 2268 Type: TypeMap, 2269 Optional: true, 2270 Computed: true, 2271 }, 2272 }, 2273 2274 State: nil, 2275 2276 Diff: &terraform.InstanceDiff{ 2277 Attributes: map[string]*terraform.ResourceAttrDiff{ 2278 "tags.Name": &terraform.ResourceAttrDiff{ 2279 Old: "", 2280 New: "foo", 2281 }, 2282 }, 2283 }, 2284 2285 Set: map[string]interface{}{ 2286 "tags": map[string]string{}, 2287 }, 2288 2289 Result: &terraform.InstanceState{ 2290 Attributes: map[string]string{}, 2291 }, 2292 }, 2293 } 2294 2295 for i, tc := range cases { 2296 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 2297 if err != nil { 2298 t.Fatalf("err: %s", err) 2299 } 2300 2301 for k, v := range tc.Set { 2302 if err := d.Set(k, v); err != nil { 2303 t.Fatalf("%d err: %s", i, err) 2304 } 2305 } 2306 2307 // Set an ID so that the state returned is not nil 2308 idSet := false 2309 if d.Id() == "" { 2310 idSet = true 2311 d.SetId("foo") 2312 } 2313 2314 // If we have partial, then enable partial state mode. 2315 if tc.Partial != nil { 2316 d.Partial(true) 2317 for _, k := range tc.Partial { 2318 d.SetPartial(k) 2319 } 2320 } 2321 2322 actual := d.State() 2323 2324 // If we set an ID, then undo what we did so the comparison works 2325 if actual != nil && idSet { 2326 actual.ID = "" 2327 delete(actual.Attributes, "id") 2328 } 2329 2330 if !reflect.DeepEqual(actual, tc.Result) { 2331 t.Fatalf("Bad: %d\n\n%#v\n\nExpected:\n\n%#v", i, actual, tc.Result) 2332 } 2333 } 2334 } 2335 2336 func TestResourceDataSetConnInfo(t *testing.T) { 2337 d := &ResourceData{} 2338 d.SetId("foo") 2339 d.SetConnInfo(map[string]string{ 2340 "foo": "bar", 2341 }) 2342 2343 expected := map[string]string{ 2344 "foo": "bar", 2345 } 2346 2347 actual := d.State() 2348 if !reflect.DeepEqual(actual.Ephemeral.ConnInfo, expected) { 2349 t.Fatalf("bad: %#v", actual) 2350 } 2351 } 2352 2353 func TestResourceDataSetId(t *testing.T) { 2354 d := &ResourceData{} 2355 d.SetId("foo") 2356 2357 actual := d.State() 2358 if actual.ID != "foo" { 2359 t.Fatalf("bad: %#v", actual) 2360 } 2361 } 2362 2363 func TestResourceDataSetId_clear(t *testing.T) { 2364 d := &ResourceData{ 2365 state: &terraform.InstanceState{ID: "bar"}, 2366 } 2367 d.SetId("") 2368 2369 actual := d.State() 2370 if actual != nil { 2371 t.Fatalf("bad: %#v", actual) 2372 } 2373 } 2374 2375 func TestResourceDataSetId_override(t *testing.T) { 2376 d := &ResourceData{ 2377 state: &terraform.InstanceState{ID: "bar"}, 2378 } 2379 d.SetId("foo") 2380 2381 actual := d.State() 2382 if actual.ID != "foo" { 2383 t.Fatalf("bad: %#v", actual) 2384 } 2385 }