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