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