github.com/rjeczalik/terraform@v0.6.7-0.20160812060014-e251d5c7bd39/helper/schema/resource_data_test.go (about) 1 package schema 2 3 import ( 4 "math" 5 "reflect" 6 "testing" 7 8 "github.com/hashicorp/terraform/terraform" 9 ) 10 11 func TestResourceDataGet(t *testing.T) { 12 cases := []struct { 13 Schema map[string]*Schema 14 State *terraform.InstanceState 15 Diff *terraform.InstanceDiff 16 Key string 17 Value interface{} 18 }{ 19 // #0 20 { 21 Schema: map[string]*Schema{ 22 "availability_zone": &Schema{ 23 Type: TypeString, 24 Optional: true, 25 Computed: true, 26 ForceNew: true, 27 }, 28 }, 29 30 State: nil, 31 32 Diff: &terraform.InstanceDiff{ 33 Attributes: map[string]*terraform.ResourceAttrDiff{ 34 "availability_zone": &terraform.ResourceAttrDiff{ 35 Old: "foo", 36 New: "bar", 37 NewComputed: true, 38 }, 39 }, 40 }, 41 42 Key: "availability_zone", 43 Value: "", 44 }, 45 46 // #1 47 { 48 Schema: map[string]*Schema{ 49 "availability_zone": &Schema{ 50 Type: TypeString, 51 Optional: true, 52 Computed: true, 53 ForceNew: true, 54 }, 55 }, 56 57 State: nil, 58 59 Diff: &terraform.InstanceDiff{ 60 Attributes: map[string]*terraform.ResourceAttrDiff{ 61 "availability_zone": &terraform.ResourceAttrDiff{ 62 Old: "", 63 New: "foo", 64 RequiresNew: true, 65 }, 66 }, 67 }, 68 69 Key: "availability_zone", 70 71 Value: "foo", 72 }, 73 74 // #2 75 { 76 Schema: map[string]*Schema{ 77 "availability_zone": &Schema{ 78 Type: TypeString, 79 Optional: true, 80 Computed: true, 81 ForceNew: true, 82 }, 83 }, 84 85 State: nil, 86 87 Diff: &terraform.InstanceDiff{ 88 Attributes: map[string]*terraform.ResourceAttrDiff{ 89 "availability_zone": &terraform.ResourceAttrDiff{ 90 Old: "", 91 New: "foo!", 92 NewExtra: "foo", 93 }, 94 }, 95 }, 96 97 Key: "availability_zone", 98 Value: "foo", 99 }, 100 101 // #3 102 { 103 Schema: map[string]*Schema{ 104 "availability_zone": &Schema{ 105 Type: TypeString, 106 Optional: true, 107 Computed: true, 108 ForceNew: true, 109 }, 110 }, 111 112 State: &terraform.InstanceState{ 113 Attributes: map[string]string{ 114 "availability_zone": "bar", 115 }, 116 }, 117 118 Diff: nil, 119 120 Key: "availability_zone", 121 122 Value: "bar", 123 }, 124 125 // #4 126 { 127 Schema: map[string]*Schema{ 128 "availability_zone": &Schema{ 129 Type: TypeString, 130 Optional: true, 131 Computed: true, 132 ForceNew: true, 133 }, 134 }, 135 136 State: &terraform.InstanceState{ 137 Attributes: map[string]string{ 138 "availability_zone": "foo", 139 }, 140 }, 141 142 Diff: &terraform.InstanceDiff{ 143 Attributes: map[string]*terraform.ResourceAttrDiff{ 144 "availability_zone": &terraform.ResourceAttrDiff{ 145 Old: "foo", 146 New: "bar", 147 NewComputed: true, 148 }, 149 }, 150 }, 151 152 Key: "availability_zone", 153 Value: "", 154 }, 155 156 // #5 157 { 158 Schema: map[string]*Schema{ 159 "port": &Schema{ 160 Type: TypeInt, 161 Optional: true, 162 Computed: true, 163 ForceNew: true, 164 }, 165 }, 166 167 State: &terraform.InstanceState{ 168 Attributes: map[string]string{ 169 "port": "80", 170 }, 171 }, 172 173 Diff: nil, 174 175 Key: "port", 176 177 Value: 80, 178 }, 179 180 // #6 181 { 182 Schema: map[string]*Schema{ 183 "ports": &Schema{ 184 Type: TypeList, 185 Required: true, 186 Elem: &Schema{Type: TypeInt}, 187 }, 188 }, 189 190 State: &terraform.InstanceState{ 191 Attributes: map[string]string{ 192 "ports.#": "3", 193 "ports.0": "1", 194 "ports.1": "2", 195 "ports.2": "5", 196 }, 197 }, 198 199 Key: "ports.1", 200 201 Value: 2, 202 }, 203 204 // #7 205 { 206 Schema: map[string]*Schema{ 207 "ports": &Schema{ 208 Type: TypeList, 209 Required: true, 210 Elem: &Schema{Type: TypeInt}, 211 }, 212 }, 213 214 State: &terraform.InstanceState{ 215 Attributes: map[string]string{ 216 "ports.#": "3", 217 "ports.0": "1", 218 "ports.1": "2", 219 "ports.2": "5", 220 }, 221 }, 222 223 Key: "ports.#", 224 225 Value: 3, 226 }, 227 228 // #8 229 { 230 Schema: map[string]*Schema{ 231 "ports": &Schema{ 232 Type: TypeList, 233 Required: true, 234 Elem: &Schema{Type: TypeInt}, 235 }, 236 }, 237 238 State: nil, 239 240 Key: "ports.#", 241 242 Value: 0, 243 }, 244 245 // #9 246 { 247 Schema: map[string]*Schema{ 248 "ports": &Schema{ 249 Type: TypeList, 250 Required: true, 251 Elem: &Schema{Type: TypeInt}, 252 }, 253 }, 254 255 State: &terraform.InstanceState{ 256 Attributes: map[string]string{ 257 "ports.#": "3", 258 "ports.0": "1", 259 "ports.1": "2", 260 "ports.2": "5", 261 }, 262 }, 263 264 Key: "ports", 265 266 Value: []interface{}{1, 2, 5}, 267 }, 268 269 // #10 270 { 271 Schema: map[string]*Schema{ 272 "ingress": &Schema{ 273 Type: TypeList, 274 Required: true, 275 Elem: &Resource{ 276 Schema: map[string]*Schema{ 277 "from": &Schema{ 278 Type: TypeInt, 279 Required: true, 280 }, 281 }, 282 }, 283 }, 284 }, 285 286 State: nil, 287 288 Diff: &terraform.InstanceDiff{ 289 Attributes: map[string]*terraform.ResourceAttrDiff{ 290 "ingress.#": &terraform.ResourceAttrDiff{ 291 Old: "", 292 New: "1", 293 }, 294 "ingress.0.from": &terraform.ResourceAttrDiff{ 295 Old: "", 296 New: "8080", 297 }, 298 }, 299 }, 300 301 Key: "ingress.0", 302 303 Value: map[string]interface{}{ 304 "from": 8080, 305 }, 306 }, 307 308 // #11 309 { 310 Schema: map[string]*Schema{ 311 "ingress": &Schema{ 312 Type: TypeList, 313 Required: true, 314 Elem: &Resource{ 315 Schema: map[string]*Schema{ 316 "from": &Schema{ 317 Type: TypeInt, 318 Required: true, 319 }, 320 }, 321 }, 322 }, 323 }, 324 325 State: nil, 326 327 Diff: &terraform.InstanceDiff{ 328 Attributes: map[string]*terraform.ResourceAttrDiff{ 329 "ingress.#": &terraform.ResourceAttrDiff{ 330 Old: "", 331 New: "1", 332 }, 333 "ingress.0.from": &terraform.ResourceAttrDiff{ 334 Old: "", 335 New: "8080", 336 }, 337 }, 338 }, 339 340 Key: "ingress", 341 342 Value: []interface{}{ 343 map[string]interface{}{ 344 "from": 8080, 345 }, 346 }, 347 }, 348 349 // #12 Computed get 350 { 351 Schema: map[string]*Schema{ 352 "availability_zone": &Schema{ 353 Type: TypeString, 354 Computed: true, 355 }, 356 }, 357 358 State: &terraform.InstanceState{ 359 Attributes: map[string]string{ 360 "availability_zone": "foo", 361 }, 362 }, 363 364 Key: "availability_zone", 365 366 Value: "foo", 367 }, 368 369 // #13 Full object 370 { 371 Schema: map[string]*Schema{ 372 "availability_zone": &Schema{ 373 Type: TypeString, 374 Optional: true, 375 Computed: true, 376 ForceNew: true, 377 }, 378 }, 379 380 State: nil, 381 382 Diff: &terraform.InstanceDiff{ 383 Attributes: map[string]*terraform.ResourceAttrDiff{ 384 "availability_zone": &terraform.ResourceAttrDiff{ 385 Old: "", 386 New: "foo", 387 RequiresNew: true, 388 }, 389 }, 390 }, 391 392 Key: "", 393 394 Value: map[string]interface{}{ 395 "availability_zone": "foo", 396 }, 397 }, 398 399 // #14 List of maps 400 { 401 Schema: map[string]*Schema{ 402 "config_vars": &Schema{ 403 Type: TypeList, 404 Optional: true, 405 Computed: true, 406 Elem: &Schema{ 407 Type: TypeMap, 408 }, 409 }, 410 }, 411 412 State: nil, 413 414 Diff: &terraform.InstanceDiff{ 415 Attributes: map[string]*terraform.ResourceAttrDiff{ 416 "config_vars.#": &terraform.ResourceAttrDiff{ 417 Old: "0", 418 New: "2", 419 }, 420 "config_vars.0.foo": &terraform.ResourceAttrDiff{ 421 Old: "", 422 New: "bar", 423 }, 424 "config_vars.1.bar": &terraform.ResourceAttrDiff{ 425 Old: "", 426 New: "baz", 427 }, 428 }, 429 }, 430 431 Key: "config_vars", 432 433 Value: []interface{}{ 434 map[string]interface{}{ 435 "foo": "bar", 436 }, 437 map[string]interface{}{ 438 "bar": "baz", 439 }, 440 }, 441 }, 442 443 // #15 List of maps in state 444 { 445 Schema: map[string]*Schema{ 446 "config_vars": &Schema{ 447 Type: TypeList, 448 Optional: true, 449 Computed: true, 450 Elem: &Schema{ 451 Type: TypeMap, 452 }, 453 }, 454 }, 455 456 State: &terraform.InstanceState{ 457 Attributes: map[string]string{ 458 "config_vars.#": "2", 459 "config_vars.0.foo": "baz", 460 "config_vars.1.bar": "bar", 461 }, 462 }, 463 464 Diff: nil, 465 466 Key: "config_vars", 467 468 Value: []interface{}{ 469 map[string]interface{}{ 470 "foo": "baz", 471 }, 472 map[string]interface{}{ 473 "bar": "bar", 474 }, 475 }, 476 }, 477 478 // #16 List of maps with removal in diff 479 { 480 Schema: map[string]*Schema{ 481 "config_vars": &Schema{ 482 Type: TypeList, 483 Optional: true, 484 Computed: true, 485 Elem: &Schema{ 486 Type: TypeMap, 487 }, 488 }, 489 }, 490 491 State: &terraform.InstanceState{ 492 Attributes: map[string]string{ 493 "config_vars.#": "1", 494 "config_vars.0.FOO": "bar", 495 }, 496 }, 497 498 Diff: &terraform.InstanceDiff{ 499 Attributes: map[string]*terraform.ResourceAttrDiff{ 500 "config_vars.#": &terraform.ResourceAttrDiff{ 501 Old: "1", 502 New: "0", 503 }, 504 "config_vars.0.FOO": &terraform.ResourceAttrDiff{ 505 Old: "bar", 506 NewRemoved: true, 507 }, 508 }, 509 }, 510 511 Key: "config_vars", 512 513 Value: []interface{}{}, 514 }, 515 516 // #17 Sets 517 { 518 Schema: map[string]*Schema{ 519 "ports": &Schema{ 520 Type: TypeSet, 521 Optional: true, 522 Computed: true, 523 Elem: &Schema{Type: TypeInt}, 524 Set: func(a interface{}) int { 525 return a.(int) 526 }, 527 }, 528 }, 529 530 State: &terraform.InstanceState{ 531 Attributes: map[string]string{ 532 "ports.#": "1", 533 "ports.80": "80", 534 }, 535 }, 536 537 Diff: nil, 538 539 Key: "ports", 540 541 Value: []interface{}{80}, 542 }, 543 544 // #18 545 { 546 Schema: map[string]*Schema{ 547 "data": &Schema{ 548 Type: TypeSet, 549 Optional: true, 550 Elem: &Resource{ 551 Schema: map[string]*Schema{ 552 "index": &Schema{ 553 Type: TypeInt, 554 Required: true, 555 }, 556 557 "value": &Schema{ 558 Type: TypeString, 559 Required: true, 560 }, 561 }, 562 }, 563 Set: func(a interface{}) int { 564 m := a.(map[string]interface{}) 565 return m["index"].(int) 566 }, 567 }, 568 }, 569 570 State: &terraform.InstanceState{ 571 Attributes: map[string]string{ 572 "data.#": "1", 573 "data.10.index": "10", 574 "data.10.value": "50", 575 }, 576 }, 577 578 Diff: &terraform.InstanceDiff{ 579 Attributes: map[string]*terraform.ResourceAttrDiff{ 580 "data.10.value": &terraform.ResourceAttrDiff{ 581 Old: "50", 582 New: "80", 583 }, 584 }, 585 }, 586 587 Key: "data", 588 589 Value: []interface{}{ 590 map[string]interface{}{ 591 "index": 10, 592 "value": "80", 593 }, 594 }, 595 }, 596 597 // #19 Empty Set 598 { 599 Schema: map[string]*Schema{ 600 "ports": &Schema{ 601 Type: TypeSet, 602 Optional: true, 603 Computed: true, 604 Elem: &Schema{Type: TypeInt}, 605 Set: func(a interface{}) int { 606 return a.(int) 607 }, 608 }, 609 }, 610 611 State: nil, 612 613 Diff: nil, 614 615 Key: "ports", 616 617 Value: []interface{}{}, 618 }, 619 620 // #20 Float zero 621 { 622 Schema: map[string]*Schema{ 623 "ratio": &Schema{ 624 Type: TypeFloat, 625 Optional: true, 626 Computed: true, 627 }, 628 }, 629 630 State: nil, 631 632 Diff: nil, 633 634 Key: "ratio", 635 636 Value: 0.0, 637 }, 638 639 // #21 Float given 640 { 641 Schema: map[string]*Schema{ 642 "ratio": &Schema{ 643 Type: TypeFloat, 644 Optional: true, 645 Computed: true, 646 }, 647 }, 648 649 State: &terraform.InstanceState{ 650 Attributes: map[string]string{ 651 "ratio": "0.5", 652 }, 653 }, 654 655 Diff: nil, 656 657 Key: "ratio", 658 659 Value: 0.5, 660 }, 661 662 // #22 Float diff 663 { 664 Schema: map[string]*Schema{ 665 "ratio": &Schema{ 666 Type: TypeFloat, 667 Optional: true, 668 Computed: true, 669 }, 670 }, 671 672 State: &terraform.InstanceState{ 673 Attributes: map[string]string{ 674 "ratio": "-0.5", 675 }, 676 }, 677 678 Diff: &terraform.InstanceDiff{ 679 Attributes: map[string]*terraform.ResourceAttrDiff{ 680 "ratio": &terraform.ResourceAttrDiff{ 681 Old: "-0.5", 682 New: "33.0", 683 }, 684 }, 685 }, 686 687 Key: "ratio", 688 689 Value: 33.0, 690 }, 691 692 // #23 Sets with removed elements 693 { 694 Schema: map[string]*Schema{ 695 "ports": &Schema{ 696 Type: TypeSet, 697 Optional: true, 698 Computed: true, 699 Elem: &Schema{Type: TypeInt}, 700 Set: func(a interface{}) int { 701 return a.(int) 702 }, 703 }, 704 }, 705 706 State: &terraform.InstanceState{ 707 Attributes: map[string]string{ 708 "ports.#": "1", 709 "ports.80": "80", 710 }, 711 }, 712 713 Diff: &terraform.InstanceDiff{ 714 Attributes: map[string]*terraform.ResourceAttrDiff{ 715 "ports.#": &terraform.ResourceAttrDiff{ 716 Old: "2", 717 New: "1", 718 }, 719 "ports.80": &terraform.ResourceAttrDiff{ 720 Old: "80", 721 New: "80", 722 }, 723 "ports.8080": &terraform.ResourceAttrDiff{ 724 Old: "8080", 725 New: "0", 726 NewRemoved: true, 727 }, 728 }, 729 }, 730 731 Key: "ports", 732 733 Value: []interface{}{80}, 734 }, 735 } 736 737 for i, tc := range cases { 738 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 739 if err != nil { 740 t.Fatalf("err: %s", err) 741 } 742 743 v := d.Get(tc.Key) 744 if s, ok := v.(*Set); ok { 745 v = s.List() 746 } 747 748 if !reflect.DeepEqual(v, tc.Value) { 749 t.Fatalf("Bad: %d\n\n%#v\n\nExpected: %#v", i, v, tc.Value) 750 } 751 } 752 } 753 754 func TestResourceDataGetChange(t *testing.T) { 755 cases := []struct { 756 Schema map[string]*Schema 757 State *terraform.InstanceState 758 Diff *terraform.InstanceDiff 759 Key string 760 OldValue interface{} 761 NewValue interface{} 762 }{ 763 { 764 Schema: map[string]*Schema{ 765 "availability_zone": &Schema{ 766 Type: TypeString, 767 Optional: true, 768 Computed: true, 769 ForceNew: true, 770 }, 771 }, 772 773 State: nil, 774 775 Diff: &terraform.InstanceDiff{ 776 Attributes: map[string]*terraform.ResourceAttrDiff{ 777 "availability_zone": &terraform.ResourceAttrDiff{ 778 Old: "", 779 New: "foo", 780 RequiresNew: true, 781 }, 782 }, 783 }, 784 785 Key: "availability_zone", 786 787 OldValue: "", 788 NewValue: "foo", 789 }, 790 791 { 792 Schema: map[string]*Schema{ 793 "availability_zone": &Schema{ 794 Type: TypeString, 795 Optional: true, 796 Computed: true, 797 ForceNew: true, 798 }, 799 }, 800 801 State: &terraform.InstanceState{ 802 Attributes: map[string]string{ 803 "availability_zone": "foo", 804 }, 805 }, 806 807 Diff: &terraform.InstanceDiff{ 808 Attributes: map[string]*terraform.ResourceAttrDiff{ 809 "availability_zone": &terraform.ResourceAttrDiff{ 810 Old: "", 811 New: "foo", 812 RequiresNew: true, 813 }, 814 }, 815 }, 816 817 Key: "availability_zone", 818 819 OldValue: "foo", 820 NewValue: "foo", 821 }, 822 } 823 824 for i, tc := range cases { 825 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 826 if err != nil { 827 t.Fatalf("err: %s", err) 828 } 829 830 o, n := d.GetChange(tc.Key) 831 if !reflect.DeepEqual(o, tc.OldValue) { 832 t.Fatalf("Old Bad: %d\n\n%#v", i, o) 833 } 834 if !reflect.DeepEqual(n, tc.NewValue) { 835 t.Fatalf("New Bad: %d\n\n%#v", i, n) 836 } 837 } 838 } 839 840 func TestResourceDataGetOk(t *testing.T) { 841 cases := []struct { 842 Schema map[string]*Schema 843 State *terraform.InstanceState 844 Diff *terraform.InstanceDiff 845 Key string 846 Value interface{} 847 Ok bool 848 }{ 849 /* 850 * Primitives 851 */ 852 { 853 Schema: map[string]*Schema{ 854 "availability_zone": &Schema{ 855 Type: TypeString, 856 Optional: true, 857 Computed: true, 858 ForceNew: true, 859 }, 860 }, 861 862 State: nil, 863 864 Diff: &terraform.InstanceDiff{ 865 Attributes: map[string]*terraform.ResourceAttrDiff{ 866 "availability_zone": &terraform.ResourceAttrDiff{ 867 Old: "", 868 New: "", 869 }, 870 }, 871 }, 872 873 Key: "availability_zone", 874 Value: "", 875 Ok: false, 876 }, 877 878 { 879 Schema: map[string]*Schema{ 880 "availability_zone": &Schema{ 881 Type: TypeString, 882 Optional: true, 883 Computed: true, 884 ForceNew: true, 885 }, 886 }, 887 888 State: nil, 889 890 Diff: &terraform.InstanceDiff{ 891 Attributes: map[string]*terraform.ResourceAttrDiff{ 892 "availability_zone": &terraform.ResourceAttrDiff{ 893 Old: "", 894 New: "", 895 NewComputed: true, 896 }, 897 }, 898 }, 899 900 Key: "availability_zone", 901 Value: "", 902 Ok: false, 903 }, 904 905 { 906 Schema: map[string]*Schema{ 907 "availability_zone": &Schema{ 908 Type: TypeString, 909 Optional: true, 910 Computed: true, 911 ForceNew: true, 912 }, 913 }, 914 915 State: nil, 916 917 Diff: nil, 918 919 Key: "availability_zone", 920 Value: "", 921 Ok: false, 922 }, 923 924 /* 925 * Lists 926 */ 927 928 { 929 Schema: map[string]*Schema{ 930 "ports": &Schema{ 931 Type: TypeList, 932 Optional: true, 933 Elem: &Schema{Type: TypeInt}, 934 }, 935 }, 936 937 State: nil, 938 939 Diff: nil, 940 941 Key: "ports", 942 Value: []interface{}{}, 943 Ok: false, 944 }, 945 946 /* 947 * Map 948 */ 949 950 { 951 Schema: map[string]*Schema{ 952 "ports": &Schema{ 953 Type: TypeMap, 954 Optional: true, 955 }, 956 }, 957 958 State: nil, 959 960 Diff: nil, 961 962 Key: "ports", 963 Value: map[string]interface{}{}, 964 Ok: false, 965 }, 966 967 /* 968 * Set 969 */ 970 971 { 972 Schema: map[string]*Schema{ 973 "ports": &Schema{ 974 Type: TypeSet, 975 Optional: true, 976 Elem: &Schema{Type: TypeInt}, 977 Set: func(a interface{}) int { return a.(int) }, 978 }, 979 }, 980 981 State: nil, 982 983 Diff: nil, 984 985 Key: "ports", 986 Value: []interface{}{}, 987 Ok: false, 988 }, 989 990 { 991 Schema: map[string]*Schema{ 992 "ports": &Schema{ 993 Type: TypeSet, 994 Optional: true, 995 Elem: &Schema{Type: TypeInt}, 996 Set: func(a interface{}) int { return a.(int) }, 997 }, 998 }, 999 1000 State: nil, 1001 1002 Diff: nil, 1003 1004 Key: "ports.0", 1005 Value: 0, 1006 Ok: false, 1007 }, 1008 1009 { 1010 Schema: map[string]*Schema{ 1011 "ports": &Schema{ 1012 Type: TypeSet, 1013 Optional: true, 1014 Elem: &Schema{Type: TypeInt}, 1015 Set: func(a interface{}) int { return a.(int) }, 1016 }, 1017 }, 1018 1019 State: nil, 1020 1021 Diff: &terraform.InstanceDiff{ 1022 Attributes: map[string]*terraform.ResourceAttrDiff{ 1023 "ports.#": &terraform.ResourceAttrDiff{ 1024 Old: "0", 1025 New: "0", 1026 }, 1027 }, 1028 }, 1029 1030 Key: "ports", 1031 Value: []interface{}{}, 1032 Ok: false, 1033 }, 1034 1035 // Further illustrates and clarifiies the GetOk semantics from #933, and 1036 // highlights the limitation that zero-value config is currently 1037 // indistinguishable from unset config. 1038 { 1039 Schema: map[string]*Schema{ 1040 "from_port": &Schema{ 1041 Type: TypeInt, 1042 Optional: true, 1043 }, 1044 }, 1045 1046 State: nil, 1047 1048 Diff: &terraform.InstanceDiff{ 1049 Attributes: map[string]*terraform.ResourceAttrDiff{ 1050 "from_port": &terraform.ResourceAttrDiff{ 1051 Old: "", 1052 New: "0", 1053 }, 1054 }, 1055 }, 1056 1057 Key: "from_port", 1058 Value: 0, 1059 Ok: false, 1060 }, 1061 } 1062 1063 for i, tc := range cases { 1064 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 1065 if err != nil { 1066 t.Fatalf("err: %s", err) 1067 } 1068 1069 v, ok := d.GetOk(tc.Key) 1070 if s, ok := v.(*Set); ok { 1071 v = s.List() 1072 } 1073 1074 if !reflect.DeepEqual(v, tc.Value) { 1075 t.Fatalf("Bad: %d\n\n%#v", i, v) 1076 } 1077 if ok != tc.Ok { 1078 t.Fatalf("%d: expected ok: %t, got: %t", i, tc.Ok, ok) 1079 } 1080 } 1081 } 1082 1083 func TestResourceDataHasChange(t *testing.T) { 1084 cases := []struct { 1085 Schema map[string]*Schema 1086 State *terraform.InstanceState 1087 Diff *terraform.InstanceDiff 1088 Key string 1089 Change bool 1090 }{ 1091 { 1092 Schema: map[string]*Schema{ 1093 "availability_zone": &Schema{ 1094 Type: TypeString, 1095 Optional: true, 1096 Computed: true, 1097 ForceNew: true, 1098 }, 1099 }, 1100 1101 State: nil, 1102 1103 Diff: &terraform.InstanceDiff{ 1104 Attributes: map[string]*terraform.ResourceAttrDiff{ 1105 "availability_zone": &terraform.ResourceAttrDiff{ 1106 Old: "", 1107 New: "foo", 1108 RequiresNew: true, 1109 }, 1110 }, 1111 }, 1112 1113 Key: "availability_zone", 1114 1115 Change: true, 1116 }, 1117 1118 { 1119 Schema: map[string]*Schema{ 1120 "availability_zone": &Schema{ 1121 Type: TypeString, 1122 Optional: true, 1123 Computed: true, 1124 ForceNew: true, 1125 }, 1126 }, 1127 1128 State: &terraform.InstanceState{ 1129 Attributes: map[string]string{ 1130 "availability_zone": "foo", 1131 }, 1132 }, 1133 1134 Diff: &terraform.InstanceDiff{ 1135 Attributes: map[string]*terraform.ResourceAttrDiff{ 1136 "availability_zone": &terraform.ResourceAttrDiff{ 1137 Old: "", 1138 New: "foo", 1139 RequiresNew: true, 1140 }, 1141 }, 1142 }, 1143 1144 Key: "availability_zone", 1145 1146 Change: false, 1147 }, 1148 1149 { 1150 Schema: map[string]*Schema{ 1151 "tags": &Schema{ 1152 Type: TypeMap, 1153 Optional: true, 1154 Computed: true, 1155 }, 1156 }, 1157 1158 State: nil, 1159 1160 Diff: &terraform.InstanceDiff{ 1161 Attributes: map[string]*terraform.ResourceAttrDiff{ 1162 "tags.Name": &terraform.ResourceAttrDiff{ 1163 Old: "foo", 1164 New: "foo", 1165 }, 1166 }, 1167 }, 1168 1169 Key: "tags", 1170 1171 Change: true, 1172 }, 1173 1174 { 1175 Schema: map[string]*Schema{ 1176 "ports": &Schema{ 1177 Type: TypeSet, 1178 Optional: true, 1179 Elem: &Schema{Type: TypeInt}, 1180 Set: func(a interface{}) int { return a.(int) }, 1181 }, 1182 }, 1183 1184 State: &terraform.InstanceState{ 1185 Attributes: map[string]string{ 1186 "ports.#": "1", 1187 "ports.80": "80", 1188 }, 1189 }, 1190 1191 Diff: &terraform.InstanceDiff{ 1192 Attributes: map[string]*terraform.ResourceAttrDiff{ 1193 "ports.#": &terraform.ResourceAttrDiff{ 1194 Old: "1", 1195 New: "0", 1196 }, 1197 }, 1198 }, 1199 1200 Key: "ports", 1201 1202 Change: true, 1203 }, 1204 1205 // https://github.com/hashicorp/terraform/issues/927 1206 { 1207 Schema: map[string]*Schema{ 1208 "ports": &Schema{ 1209 Type: TypeSet, 1210 Optional: true, 1211 Elem: &Schema{Type: TypeInt}, 1212 Set: func(a interface{}) int { return a.(int) }, 1213 }, 1214 }, 1215 1216 State: &terraform.InstanceState{ 1217 Attributes: map[string]string{ 1218 "ports.#": "1", 1219 "ports.80": "80", 1220 }, 1221 }, 1222 1223 Diff: &terraform.InstanceDiff{ 1224 Attributes: map[string]*terraform.ResourceAttrDiff{ 1225 "tags.foo": &terraform.ResourceAttrDiff{ 1226 Old: "", 1227 New: "bar", 1228 }, 1229 }, 1230 }, 1231 1232 Key: "ports", 1233 1234 Change: false, 1235 }, 1236 } 1237 1238 for i, tc := range cases { 1239 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 1240 if err != nil { 1241 t.Fatalf("err: %s", err) 1242 } 1243 1244 actual := d.HasChange(tc.Key) 1245 if actual != tc.Change { 1246 t.Fatalf("Bad: %d %#v", i, actual) 1247 } 1248 } 1249 } 1250 1251 func TestResourceDataSet(t *testing.T) { 1252 var testNilPtr *string 1253 1254 cases := []struct { 1255 Schema map[string]*Schema 1256 State *terraform.InstanceState 1257 Diff *terraform.InstanceDiff 1258 Key string 1259 Value interface{} 1260 Err bool 1261 GetKey string 1262 GetValue interface{} 1263 1264 // GetPreProcess can be set to munge the return value before being 1265 // compared to GetValue 1266 GetPreProcess func(interface{}) interface{} 1267 }{ 1268 // #0: Basic good 1269 { 1270 Schema: map[string]*Schema{ 1271 "availability_zone": &Schema{ 1272 Type: TypeString, 1273 Optional: true, 1274 Computed: true, 1275 ForceNew: true, 1276 }, 1277 }, 1278 1279 State: nil, 1280 1281 Diff: nil, 1282 1283 Key: "availability_zone", 1284 Value: "foo", 1285 1286 GetKey: "availability_zone", 1287 GetValue: "foo", 1288 }, 1289 1290 // #1: Basic int 1291 { 1292 Schema: map[string]*Schema{ 1293 "port": &Schema{ 1294 Type: TypeInt, 1295 Optional: true, 1296 Computed: true, 1297 ForceNew: true, 1298 }, 1299 }, 1300 1301 State: nil, 1302 1303 Diff: nil, 1304 1305 Key: "port", 1306 Value: 80, 1307 1308 GetKey: "port", 1309 GetValue: 80, 1310 }, 1311 1312 // #2: Basic bool 1313 { 1314 Schema: map[string]*Schema{ 1315 "vpc": &Schema{ 1316 Type: TypeBool, 1317 Optional: true, 1318 }, 1319 }, 1320 1321 State: nil, 1322 1323 Diff: nil, 1324 1325 Key: "vpc", 1326 Value: true, 1327 1328 GetKey: "vpc", 1329 GetValue: true, 1330 }, 1331 1332 // #3 1333 { 1334 Schema: map[string]*Schema{ 1335 "vpc": &Schema{ 1336 Type: TypeBool, 1337 Optional: true, 1338 }, 1339 }, 1340 1341 State: nil, 1342 1343 Diff: nil, 1344 1345 Key: "vpc", 1346 Value: false, 1347 1348 GetKey: "vpc", 1349 GetValue: false, 1350 }, 1351 1352 // #4: Invalid type 1353 { 1354 Schema: map[string]*Schema{ 1355 "availability_zone": &Schema{ 1356 Type: TypeString, 1357 Optional: true, 1358 Computed: true, 1359 ForceNew: true, 1360 }, 1361 }, 1362 1363 State: nil, 1364 1365 Diff: nil, 1366 1367 Key: "availability_zone", 1368 Value: 80, 1369 Err: true, 1370 1371 GetKey: "availability_zone", 1372 GetValue: "", 1373 }, 1374 1375 // #5: List of primitives, set list 1376 { 1377 Schema: map[string]*Schema{ 1378 "ports": &Schema{ 1379 Type: TypeList, 1380 Computed: true, 1381 Elem: &Schema{Type: TypeInt}, 1382 }, 1383 }, 1384 1385 State: nil, 1386 1387 Diff: nil, 1388 1389 Key: "ports", 1390 Value: []int{1, 2, 5}, 1391 1392 GetKey: "ports", 1393 GetValue: []interface{}{1, 2, 5}, 1394 }, 1395 1396 // #6: List of primitives, set list with error 1397 { 1398 Schema: map[string]*Schema{ 1399 "ports": &Schema{ 1400 Type: TypeList, 1401 Computed: true, 1402 Elem: &Schema{Type: TypeInt}, 1403 }, 1404 }, 1405 1406 State: nil, 1407 1408 Diff: nil, 1409 1410 Key: "ports", 1411 Value: []interface{}{1, "NOPE", 5}, 1412 Err: true, 1413 1414 GetKey: "ports", 1415 GetValue: []interface{}{}, 1416 }, 1417 1418 // #7: Set a list of maps 1419 { 1420 Schema: map[string]*Schema{ 1421 "config_vars": &Schema{ 1422 Type: TypeList, 1423 Optional: true, 1424 Computed: true, 1425 Elem: &Schema{ 1426 Type: TypeMap, 1427 }, 1428 }, 1429 }, 1430 1431 State: nil, 1432 1433 Diff: nil, 1434 1435 Key: "config_vars", 1436 Value: []interface{}{ 1437 map[string]interface{}{ 1438 "foo": "bar", 1439 }, 1440 map[string]interface{}{ 1441 "bar": "baz", 1442 }, 1443 }, 1444 Err: false, 1445 1446 GetKey: "config_vars", 1447 GetValue: []interface{}{ 1448 map[string]interface{}{ 1449 "foo": "bar", 1450 }, 1451 map[string]interface{}{ 1452 "bar": "baz", 1453 }, 1454 }, 1455 }, 1456 1457 // #8: Set, with list 1458 { 1459 Schema: map[string]*Schema{ 1460 "ports": &Schema{ 1461 Type: TypeSet, 1462 Optional: true, 1463 Computed: true, 1464 Elem: &Schema{Type: TypeInt}, 1465 Set: func(a interface{}) int { 1466 return a.(int) 1467 }, 1468 }, 1469 }, 1470 1471 State: &terraform.InstanceState{ 1472 Attributes: map[string]string{ 1473 "ports.#": "3", 1474 "ports.0": "100", 1475 "ports.1": "80", 1476 "ports.2": "80", 1477 }, 1478 }, 1479 1480 Key: "ports", 1481 Value: []interface{}{100, 125, 125}, 1482 1483 GetKey: "ports", 1484 GetValue: []interface{}{100, 125}, 1485 }, 1486 1487 // #9: Set, with Set 1488 { 1489 Schema: map[string]*Schema{ 1490 "ports": &Schema{ 1491 Type: TypeSet, 1492 Optional: true, 1493 Computed: true, 1494 Elem: &Schema{Type: TypeInt}, 1495 Set: func(a interface{}) int { 1496 return a.(int) 1497 }, 1498 }, 1499 }, 1500 1501 State: &terraform.InstanceState{ 1502 Attributes: map[string]string{ 1503 "ports.#": "3", 1504 "ports.100": "100", 1505 "ports.80": "80", 1506 "ports.81": "81", 1507 }, 1508 }, 1509 1510 Key: "ports", 1511 Value: &Set{ 1512 m: map[string]interface{}{ 1513 "1": 1, 1514 "2": 2, 1515 }, 1516 }, 1517 1518 GetKey: "ports", 1519 GetValue: []interface{}{1, 2}, 1520 }, 1521 1522 // #10: Set single item 1523 { 1524 Schema: map[string]*Schema{ 1525 "ports": &Schema{ 1526 Type: TypeSet, 1527 Optional: true, 1528 Computed: true, 1529 Elem: &Schema{Type: TypeInt}, 1530 Set: func(a interface{}) int { 1531 return a.(int) 1532 }, 1533 }, 1534 }, 1535 1536 State: &terraform.InstanceState{ 1537 Attributes: map[string]string{ 1538 "ports.#": "2", 1539 "ports.100": "100", 1540 "ports.80": "80", 1541 }, 1542 }, 1543 1544 Key: "ports.100", 1545 Value: 256, 1546 Err: true, 1547 1548 GetKey: "ports", 1549 GetValue: []interface{}{100, 80}, 1550 }, 1551 1552 // #11: Set with nested set 1553 { 1554 Schema: map[string]*Schema{ 1555 "ports": &Schema{ 1556 Type: TypeSet, 1557 Elem: &Resource{ 1558 Schema: map[string]*Schema{ 1559 "port": &Schema{ 1560 Type: TypeInt, 1561 }, 1562 1563 "set": &Schema{ 1564 Type: TypeSet, 1565 Elem: &Schema{Type: TypeInt}, 1566 Set: func(a interface{}) int { 1567 return a.(int) 1568 }, 1569 }, 1570 }, 1571 }, 1572 Set: func(a interface{}) int { 1573 return a.(map[string]interface{})["port"].(int) 1574 }, 1575 }, 1576 }, 1577 1578 State: nil, 1579 1580 Key: "ports", 1581 Value: []interface{}{ 1582 map[string]interface{}{ 1583 "port": 80, 1584 }, 1585 }, 1586 1587 GetKey: "ports", 1588 GetValue: []interface{}{ 1589 map[string]interface{}{ 1590 "port": 80, 1591 "set": []interface{}{}, 1592 }, 1593 }, 1594 1595 GetPreProcess: func(v interface{}) interface{} { 1596 if v == nil { 1597 return v 1598 } 1599 s, ok := v.([]interface{}) 1600 if !ok { 1601 return v 1602 } 1603 for _, v := range s { 1604 m, ok := v.(map[string]interface{}) 1605 if !ok { 1606 continue 1607 } 1608 if m["set"] == nil { 1609 continue 1610 } 1611 if s, ok := m["set"].(*Set); ok { 1612 m["set"] = s.List() 1613 } 1614 } 1615 1616 return v 1617 }, 1618 }, 1619 1620 // #12: List of floats, set list 1621 { 1622 Schema: map[string]*Schema{ 1623 "ratios": &Schema{ 1624 Type: TypeList, 1625 Computed: true, 1626 Elem: &Schema{Type: TypeFloat}, 1627 }, 1628 }, 1629 1630 State: nil, 1631 1632 Diff: nil, 1633 1634 Key: "ratios", 1635 Value: []float64{1.0, 2.2, 5.5}, 1636 1637 GetKey: "ratios", 1638 GetValue: []interface{}{1.0, 2.2, 5.5}, 1639 }, 1640 1641 // #12: Set of floats, set list 1642 { 1643 Schema: map[string]*Schema{ 1644 "ratios": &Schema{ 1645 Type: TypeSet, 1646 Computed: true, 1647 Elem: &Schema{Type: TypeFloat}, 1648 Set: func(a interface{}) int { 1649 return int(math.Float64bits(a.(float64))) 1650 }, 1651 }, 1652 }, 1653 1654 State: nil, 1655 1656 Diff: nil, 1657 1658 Key: "ratios", 1659 Value: []float64{1.0, 2.2, 5.5}, 1660 1661 GetKey: "ratios", 1662 GetValue: []interface{}{1.0, 2.2, 5.5}, 1663 }, 1664 1665 // #13: Basic pointer 1666 { 1667 Schema: map[string]*Schema{ 1668 "availability_zone": &Schema{ 1669 Type: TypeString, 1670 Optional: true, 1671 Computed: true, 1672 ForceNew: true, 1673 }, 1674 }, 1675 1676 State: nil, 1677 1678 Diff: nil, 1679 1680 Key: "availability_zone", 1681 Value: testPtrTo("foo"), 1682 1683 GetKey: "availability_zone", 1684 GetValue: "foo", 1685 }, 1686 1687 // #14: Basic nil value 1688 { 1689 Schema: map[string]*Schema{ 1690 "availability_zone": &Schema{ 1691 Type: TypeString, 1692 Optional: true, 1693 Computed: true, 1694 ForceNew: true, 1695 }, 1696 }, 1697 1698 State: nil, 1699 1700 Diff: nil, 1701 1702 Key: "availability_zone", 1703 Value: testPtrTo(nil), 1704 1705 GetKey: "availability_zone", 1706 GetValue: "", 1707 }, 1708 1709 // #15: Basic nil pointer 1710 { 1711 Schema: map[string]*Schema{ 1712 "availability_zone": &Schema{ 1713 Type: TypeString, 1714 Optional: true, 1715 Computed: true, 1716 ForceNew: true, 1717 }, 1718 }, 1719 1720 State: nil, 1721 1722 Diff: nil, 1723 1724 Key: "availability_zone", 1725 Value: testNilPtr, 1726 1727 GetKey: "availability_zone", 1728 GetValue: "", 1729 }, 1730 } 1731 1732 for i, tc := range cases { 1733 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 1734 if err != nil { 1735 t.Fatalf("err: %s", err) 1736 } 1737 1738 err = d.Set(tc.Key, tc.Value) 1739 if err != nil != tc.Err { 1740 t.Fatalf("%d err: %s", i, err) 1741 } 1742 1743 v := d.Get(tc.GetKey) 1744 if s, ok := v.(*Set); ok { 1745 v = s.List() 1746 } 1747 1748 if tc.GetPreProcess != nil { 1749 v = tc.GetPreProcess(v) 1750 } 1751 1752 if !reflect.DeepEqual(v, tc.GetValue) { 1753 t.Fatalf("Get Bad: %d\n\n%#v", i, v) 1754 } 1755 } 1756 } 1757 1758 func TestResourceDataState_dynamicAttributes(t *testing.T) { 1759 cases := []struct { 1760 Schema map[string]*Schema 1761 State *terraform.InstanceState 1762 Diff *terraform.InstanceDiff 1763 Set map[string]interface{} 1764 UnsafeSet map[string]string 1765 Result *terraform.InstanceState 1766 }{ 1767 { 1768 Schema: map[string]*Schema{ 1769 "__has_dynamic_attributes": { 1770 Type: TypeString, 1771 Optional: true, 1772 }, 1773 1774 "schema_field": { 1775 Type: TypeString, 1776 Required: true, 1777 }, 1778 }, 1779 1780 State: nil, 1781 1782 Diff: nil, 1783 1784 Set: map[string]interface{}{ 1785 "schema_field": "present", 1786 }, 1787 1788 UnsafeSet: map[string]string{ 1789 "test1": "value", 1790 "test2": "value", 1791 }, 1792 1793 Result: &terraform.InstanceState{ 1794 Attributes: map[string]string{ 1795 "schema_field": "present", 1796 "test1": "value", 1797 "test2": "value", 1798 }, 1799 }, 1800 }, 1801 } 1802 1803 for i, tc := range cases { 1804 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 1805 if err != nil { 1806 t.Fatalf("err: %s", err) 1807 } 1808 1809 for k, v := range tc.Set { 1810 d.Set(k, v) 1811 } 1812 1813 for k, v := range tc.UnsafeSet { 1814 d.UnsafeSetFieldRaw(k, v) 1815 } 1816 1817 // Set an ID so that the state returned is not nil 1818 idSet := false 1819 if d.Id() == "" { 1820 idSet = true 1821 d.SetId("foo") 1822 } 1823 1824 actual := d.State() 1825 1826 // If we set an ID, then undo what we did so the comparison works 1827 if actual != nil && idSet { 1828 actual.ID = "" 1829 delete(actual.Attributes, "id") 1830 } 1831 1832 if !reflect.DeepEqual(actual, tc.Result) { 1833 t.Fatalf("Bad: %d\n\n%#v\n\nExpected:\n\n%#v", i, actual, tc.Result) 1834 } 1835 } 1836 } 1837 1838 func TestResourceDataState_schema(t *testing.T) { 1839 cases := []struct { 1840 Schema map[string]*Schema 1841 State *terraform.InstanceState 1842 Diff *terraform.InstanceDiff 1843 Set map[string]interface{} 1844 Result *terraform.InstanceState 1845 Partial []string 1846 }{ 1847 // #0 Basic primitive in diff 1848 { 1849 Schema: map[string]*Schema{ 1850 "availability_zone": &Schema{ 1851 Type: TypeString, 1852 Optional: true, 1853 Computed: true, 1854 ForceNew: true, 1855 }, 1856 }, 1857 1858 State: nil, 1859 1860 Diff: &terraform.InstanceDiff{ 1861 Attributes: map[string]*terraform.ResourceAttrDiff{ 1862 "availability_zone": &terraform.ResourceAttrDiff{ 1863 Old: "", 1864 New: "foo", 1865 RequiresNew: true, 1866 }, 1867 }, 1868 }, 1869 1870 Result: &terraform.InstanceState{ 1871 Attributes: map[string]string{ 1872 "availability_zone": "foo", 1873 }, 1874 }, 1875 }, 1876 1877 // #1 Basic primitive set override 1878 { 1879 Schema: map[string]*Schema{ 1880 "availability_zone": &Schema{ 1881 Type: TypeString, 1882 Optional: true, 1883 Computed: true, 1884 ForceNew: true, 1885 }, 1886 }, 1887 1888 State: nil, 1889 1890 Diff: &terraform.InstanceDiff{ 1891 Attributes: map[string]*terraform.ResourceAttrDiff{ 1892 "availability_zone": &terraform.ResourceAttrDiff{ 1893 Old: "", 1894 New: "foo", 1895 RequiresNew: true, 1896 }, 1897 }, 1898 }, 1899 1900 Set: map[string]interface{}{ 1901 "availability_zone": "bar", 1902 }, 1903 1904 Result: &terraform.InstanceState{ 1905 Attributes: map[string]string{ 1906 "availability_zone": "bar", 1907 }, 1908 }, 1909 }, 1910 1911 // #2 1912 { 1913 Schema: map[string]*Schema{ 1914 "vpc": &Schema{ 1915 Type: TypeBool, 1916 Optional: true, 1917 }, 1918 }, 1919 1920 State: nil, 1921 1922 Diff: nil, 1923 1924 Set: map[string]interface{}{ 1925 "vpc": true, 1926 }, 1927 1928 Result: &terraform.InstanceState{ 1929 Attributes: map[string]string{ 1930 "vpc": "true", 1931 }, 1932 }, 1933 }, 1934 1935 // #3 Basic primitive with StateFunc set 1936 { 1937 Schema: map[string]*Schema{ 1938 "availability_zone": &Schema{ 1939 Type: TypeString, 1940 Optional: true, 1941 Computed: true, 1942 StateFunc: func(interface{}) string { return "" }, 1943 }, 1944 }, 1945 1946 State: nil, 1947 1948 Diff: &terraform.InstanceDiff{ 1949 Attributes: map[string]*terraform.ResourceAttrDiff{ 1950 "availability_zone": &terraform.ResourceAttrDiff{ 1951 Old: "", 1952 New: "foo", 1953 NewExtra: "foo!", 1954 }, 1955 }, 1956 }, 1957 1958 Result: &terraform.InstanceState{ 1959 Attributes: map[string]string{ 1960 "availability_zone": "foo", 1961 }, 1962 }, 1963 }, 1964 1965 // #4 List 1966 { 1967 Schema: map[string]*Schema{ 1968 "ports": &Schema{ 1969 Type: TypeList, 1970 Required: true, 1971 Elem: &Schema{Type: TypeInt}, 1972 }, 1973 }, 1974 1975 State: &terraform.InstanceState{ 1976 Attributes: map[string]string{ 1977 "ports.#": "1", 1978 "ports.0": "80", 1979 }, 1980 }, 1981 1982 Diff: &terraform.InstanceDiff{ 1983 Attributes: map[string]*terraform.ResourceAttrDiff{ 1984 "ports.#": &terraform.ResourceAttrDiff{ 1985 Old: "1", 1986 New: "2", 1987 }, 1988 "ports.1": &terraform.ResourceAttrDiff{ 1989 Old: "", 1990 New: "100", 1991 }, 1992 }, 1993 }, 1994 1995 Result: &terraform.InstanceState{ 1996 Attributes: map[string]string{ 1997 "ports.#": "2", 1998 "ports.0": "80", 1999 "ports.1": "100", 2000 }, 2001 }, 2002 }, 2003 2004 // #5 List of resources 2005 { 2006 Schema: map[string]*Schema{ 2007 "ingress": &Schema{ 2008 Type: TypeList, 2009 Required: true, 2010 Elem: &Resource{ 2011 Schema: map[string]*Schema{ 2012 "from": &Schema{ 2013 Type: TypeInt, 2014 Required: true, 2015 }, 2016 }, 2017 }, 2018 }, 2019 }, 2020 2021 State: &terraform.InstanceState{ 2022 Attributes: map[string]string{ 2023 "ingress.#": "1", 2024 "ingress.0.from": "80", 2025 }, 2026 }, 2027 2028 Diff: &terraform.InstanceDiff{ 2029 Attributes: map[string]*terraform.ResourceAttrDiff{ 2030 "ingress.#": &terraform.ResourceAttrDiff{ 2031 Old: "1", 2032 New: "2", 2033 }, 2034 "ingress.0.from": &terraform.ResourceAttrDiff{ 2035 Old: "80", 2036 New: "150", 2037 }, 2038 "ingress.1.from": &terraform.ResourceAttrDiff{ 2039 Old: "", 2040 New: "100", 2041 }, 2042 }, 2043 }, 2044 2045 Result: &terraform.InstanceState{ 2046 Attributes: map[string]string{ 2047 "ingress.#": "2", 2048 "ingress.0.from": "150", 2049 "ingress.1.from": "100", 2050 }, 2051 }, 2052 }, 2053 2054 // #6 List of maps 2055 { 2056 Schema: map[string]*Schema{ 2057 "config_vars": &Schema{ 2058 Type: TypeList, 2059 Optional: true, 2060 Computed: true, 2061 Elem: &Schema{ 2062 Type: TypeMap, 2063 }, 2064 }, 2065 }, 2066 2067 State: &terraform.InstanceState{ 2068 Attributes: map[string]string{ 2069 "config_vars.#": "2", 2070 "config_vars.0.%": "2", 2071 "config_vars.0.foo": "bar", 2072 "config_vars.0.bar": "bar", 2073 "config_vars.1.%": "1", 2074 "config_vars.1.bar": "baz", 2075 }, 2076 }, 2077 2078 Diff: &terraform.InstanceDiff{ 2079 Attributes: map[string]*terraform.ResourceAttrDiff{ 2080 "config_vars.0.bar": &terraform.ResourceAttrDiff{ 2081 NewRemoved: true, 2082 }, 2083 }, 2084 }, 2085 2086 Set: map[string]interface{}{ 2087 "config_vars": []map[string]interface{}{ 2088 map[string]interface{}{ 2089 "foo": "bar", 2090 }, 2091 map[string]interface{}{ 2092 "baz": "bang", 2093 }, 2094 }, 2095 }, 2096 2097 Result: &terraform.InstanceState{ 2098 Attributes: map[string]string{ 2099 "config_vars.#": "2", 2100 "config_vars.0.%": "1", 2101 "config_vars.0.foo": "bar", 2102 "config_vars.1.%": "1", 2103 "config_vars.1.baz": "bang", 2104 }, 2105 }, 2106 }, 2107 2108 // #7 List of maps with removal in diff 2109 { 2110 Schema: map[string]*Schema{ 2111 "config_vars": &Schema{ 2112 Type: TypeList, 2113 Optional: true, 2114 Computed: true, 2115 Elem: &Schema{ 2116 Type: TypeMap, 2117 }, 2118 }, 2119 }, 2120 2121 State: &terraform.InstanceState{ 2122 Attributes: map[string]string{ 2123 "config_vars.#": "1", 2124 "config_vars.0.FOO": "bar", 2125 }, 2126 }, 2127 2128 Diff: &terraform.InstanceDiff{ 2129 Attributes: map[string]*terraform.ResourceAttrDiff{ 2130 "config_vars.#": &terraform.ResourceAttrDiff{ 2131 Old: "1", 2132 New: "0", 2133 }, 2134 "config_vars.0.FOO": &terraform.ResourceAttrDiff{ 2135 Old: "bar", 2136 NewRemoved: true, 2137 }, 2138 }, 2139 }, 2140 2141 Result: &terraform.InstanceState{ 2142 Attributes: map[string]string{ 2143 "config_vars.#": "0", 2144 }, 2145 }, 2146 }, 2147 2148 // #8 Basic state with other keys 2149 { 2150 Schema: map[string]*Schema{ 2151 "availability_zone": &Schema{ 2152 Type: TypeString, 2153 Optional: true, 2154 Computed: true, 2155 ForceNew: true, 2156 }, 2157 }, 2158 2159 State: &terraform.InstanceState{ 2160 ID: "bar", 2161 Attributes: map[string]string{ 2162 "id": "bar", 2163 }, 2164 }, 2165 2166 Diff: &terraform.InstanceDiff{ 2167 Attributes: map[string]*terraform.ResourceAttrDiff{ 2168 "availability_zone": &terraform.ResourceAttrDiff{ 2169 Old: "", 2170 New: "foo", 2171 RequiresNew: true, 2172 }, 2173 }, 2174 }, 2175 2176 Result: &terraform.InstanceState{ 2177 ID: "bar", 2178 Attributes: map[string]string{ 2179 "id": "bar", 2180 "availability_zone": "foo", 2181 }, 2182 }, 2183 }, 2184 2185 // #9 Sets 2186 { 2187 Schema: map[string]*Schema{ 2188 "ports": &Schema{ 2189 Type: TypeSet, 2190 Optional: true, 2191 Computed: true, 2192 Elem: &Schema{Type: TypeInt}, 2193 Set: func(a interface{}) int { 2194 return a.(int) 2195 }, 2196 }, 2197 }, 2198 2199 State: &terraform.InstanceState{ 2200 Attributes: map[string]string{ 2201 "ports.#": "3", 2202 "ports.100": "100", 2203 "ports.80": "80", 2204 "ports.81": "81", 2205 }, 2206 }, 2207 2208 Diff: nil, 2209 2210 Result: &terraform.InstanceState{ 2211 Attributes: map[string]string{ 2212 "ports.#": "3", 2213 "ports.80": "80", 2214 "ports.81": "81", 2215 "ports.100": "100", 2216 }, 2217 }, 2218 }, 2219 2220 // #10 2221 { 2222 Schema: map[string]*Schema{ 2223 "ports": &Schema{ 2224 Type: TypeSet, 2225 Optional: true, 2226 Computed: true, 2227 Elem: &Schema{Type: TypeInt}, 2228 Set: func(a interface{}) int { 2229 return a.(int) 2230 }, 2231 }, 2232 }, 2233 2234 State: nil, 2235 2236 Diff: nil, 2237 2238 Set: map[string]interface{}{ 2239 "ports": []interface{}{100, 80}, 2240 }, 2241 2242 Result: &terraform.InstanceState{ 2243 Attributes: map[string]string{ 2244 "ports.#": "2", 2245 "ports.80": "80", 2246 "ports.100": "100", 2247 }, 2248 }, 2249 }, 2250 2251 // #11 2252 { 2253 Schema: map[string]*Schema{ 2254 "ports": &Schema{ 2255 Type: TypeSet, 2256 Optional: true, 2257 Computed: true, 2258 Elem: &Resource{ 2259 Schema: map[string]*Schema{ 2260 "order": &Schema{ 2261 Type: TypeInt, 2262 }, 2263 2264 "a": &Schema{ 2265 Type: TypeList, 2266 Elem: &Schema{Type: TypeInt}, 2267 }, 2268 2269 "b": &Schema{ 2270 Type: TypeList, 2271 Elem: &Schema{Type: TypeInt}, 2272 }, 2273 }, 2274 }, 2275 Set: func(a interface{}) int { 2276 m := a.(map[string]interface{}) 2277 return m["order"].(int) 2278 }, 2279 }, 2280 }, 2281 2282 State: &terraform.InstanceState{ 2283 Attributes: map[string]string{ 2284 "ports.#": "2", 2285 "ports.10.order": "10", 2286 "ports.10.a.#": "1", 2287 "ports.10.a.0": "80", 2288 "ports.20.order": "20", 2289 "ports.20.b.#": "1", 2290 "ports.20.b.0": "100", 2291 }, 2292 }, 2293 2294 Set: map[string]interface{}{ 2295 "ports": []interface{}{ 2296 map[string]interface{}{ 2297 "order": 20, 2298 "b": []interface{}{100}, 2299 }, 2300 map[string]interface{}{ 2301 "order": 10, 2302 "a": []interface{}{80}, 2303 }, 2304 }, 2305 }, 2306 2307 Result: &terraform.InstanceState{ 2308 Attributes: map[string]string{ 2309 "ports.#": "2", 2310 "ports.10.order": "10", 2311 "ports.10.a.#": "1", 2312 "ports.10.a.0": "80", 2313 "ports.10.b.#": "0", 2314 "ports.20.order": "20", 2315 "ports.20.a.#": "0", 2316 "ports.20.b.#": "1", 2317 "ports.20.b.0": "100", 2318 }, 2319 }, 2320 }, 2321 2322 /* 2323 * PARTIAL STATES 2324 */ 2325 2326 // #12 Basic primitive 2327 { 2328 Schema: map[string]*Schema{ 2329 "availability_zone": &Schema{ 2330 Type: TypeString, 2331 Optional: true, 2332 Computed: true, 2333 ForceNew: true, 2334 }, 2335 }, 2336 2337 State: nil, 2338 2339 Diff: &terraform.InstanceDiff{ 2340 Attributes: map[string]*terraform.ResourceAttrDiff{ 2341 "availability_zone": &terraform.ResourceAttrDiff{ 2342 Old: "", 2343 New: "foo", 2344 RequiresNew: true, 2345 }, 2346 }, 2347 }, 2348 2349 Partial: []string{}, 2350 2351 Result: &terraform.InstanceState{ 2352 Attributes: map[string]string{}, 2353 }, 2354 }, 2355 2356 // #13 List 2357 { 2358 Schema: map[string]*Schema{ 2359 "ports": &Schema{ 2360 Type: TypeList, 2361 Required: true, 2362 Elem: &Schema{Type: TypeInt}, 2363 }, 2364 }, 2365 2366 State: &terraform.InstanceState{ 2367 Attributes: map[string]string{ 2368 "ports.#": "1", 2369 "ports.0": "80", 2370 }, 2371 }, 2372 2373 Diff: &terraform.InstanceDiff{ 2374 Attributes: map[string]*terraform.ResourceAttrDiff{ 2375 "ports.#": &terraform.ResourceAttrDiff{ 2376 Old: "1", 2377 New: "2", 2378 }, 2379 "ports.1": &terraform.ResourceAttrDiff{ 2380 Old: "", 2381 New: "100", 2382 }, 2383 }, 2384 }, 2385 2386 Partial: []string{}, 2387 2388 Result: &terraform.InstanceState{ 2389 Attributes: map[string]string{ 2390 "ports.#": "1", 2391 "ports.0": "80", 2392 }, 2393 }, 2394 }, 2395 2396 // #14 2397 { 2398 Schema: map[string]*Schema{ 2399 "ports": &Schema{ 2400 Type: TypeList, 2401 Optional: true, 2402 Computed: true, 2403 Elem: &Schema{Type: TypeInt}, 2404 }, 2405 }, 2406 2407 State: nil, 2408 2409 Diff: &terraform.InstanceDiff{ 2410 Attributes: map[string]*terraform.ResourceAttrDiff{ 2411 "ports.#": &terraform.ResourceAttrDiff{ 2412 Old: "", 2413 NewComputed: true, 2414 }, 2415 }, 2416 }, 2417 2418 Partial: []string{}, 2419 2420 Set: map[string]interface{}{ 2421 "ports": []interface{}{}, 2422 }, 2423 2424 Result: &terraform.InstanceState{ 2425 Attributes: map[string]string{}, 2426 }, 2427 }, 2428 2429 // #15 List of resources 2430 { 2431 Schema: map[string]*Schema{ 2432 "ingress": &Schema{ 2433 Type: TypeList, 2434 Required: true, 2435 Elem: &Resource{ 2436 Schema: map[string]*Schema{ 2437 "from": &Schema{ 2438 Type: TypeInt, 2439 Required: true, 2440 }, 2441 }, 2442 }, 2443 }, 2444 }, 2445 2446 State: &terraform.InstanceState{ 2447 Attributes: map[string]string{ 2448 "ingress.#": "1", 2449 "ingress.0.from": "80", 2450 }, 2451 }, 2452 2453 Diff: &terraform.InstanceDiff{ 2454 Attributes: map[string]*terraform.ResourceAttrDiff{ 2455 "ingress.#": &terraform.ResourceAttrDiff{ 2456 Old: "1", 2457 New: "2", 2458 }, 2459 "ingress.0.from": &terraform.ResourceAttrDiff{ 2460 Old: "80", 2461 New: "150", 2462 }, 2463 "ingress.1.from": &terraform.ResourceAttrDiff{ 2464 Old: "", 2465 New: "100", 2466 }, 2467 }, 2468 }, 2469 2470 Partial: []string{}, 2471 2472 Result: &terraform.InstanceState{ 2473 Attributes: map[string]string{ 2474 "ingress.#": "1", 2475 "ingress.0.from": "80", 2476 }, 2477 }, 2478 }, 2479 2480 // #16 List of maps 2481 { 2482 Schema: map[string]*Schema{ 2483 "config_vars": &Schema{ 2484 Type: TypeList, 2485 Optional: true, 2486 Computed: true, 2487 Elem: &Schema{ 2488 Type: TypeMap, 2489 }, 2490 }, 2491 }, 2492 2493 State: &terraform.InstanceState{ 2494 Attributes: map[string]string{ 2495 "config_vars.#": "2", 2496 "config_vars.0.foo": "bar", 2497 "config_vars.0.bar": "bar", 2498 "config_vars.1.bar": "baz", 2499 }, 2500 }, 2501 2502 Diff: &terraform.InstanceDiff{ 2503 Attributes: map[string]*terraform.ResourceAttrDiff{ 2504 "config_vars.0.bar": &terraform.ResourceAttrDiff{ 2505 NewRemoved: true, 2506 }, 2507 }, 2508 }, 2509 2510 Set: map[string]interface{}{ 2511 "config_vars": []map[string]interface{}{ 2512 map[string]interface{}{ 2513 "foo": "bar", 2514 }, 2515 map[string]interface{}{ 2516 "baz": "bang", 2517 }, 2518 }, 2519 }, 2520 2521 Partial: []string{}, 2522 2523 Result: &terraform.InstanceState{ 2524 Attributes: map[string]string{ 2525 // TODO: broken, shouldn't bar be removed? 2526 "config_vars.#": "2", 2527 "config_vars.0.%": "2", 2528 "config_vars.0.foo": "bar", 2529 "config_vars.0.bar": "bar", 2530 "config_vars.1.%": "1", 2531 "config_vars.1.bar": "baz", 2532 }, 2533 }, 2534 }, 2535 2536 // #17 Sets 2537 { 2538 Schema: map[string]*Schema{ 2539 "ports": &Schema{ 2540 Type: TypeSet, 2541 Optional: true, 2542 Computed: true, 2543 Elem: &Schema{Type: TypeInt}, 2544 Set: func(a interface{}) int { 2545 return a.(int) 2546 }, 2547 }, 2548 }, 2549 2550 State: &terraform.InstanceState{ 2551 Attributes: map[string]string{ 2552 "ports.#": "3", 2553 "ports.100": "100", 2554 "ports.80": "80", 2555 "ports.81": "81", 2556 }, 2557 }, 2558 2559 Diff: &terraform.InstanceDiff{ 2560 Attributes: map[string]*terraform.ResourceAttrDiff{ 2561 "ports.120": &terraform.ResourceAttrDiff{ 2562 New: "120", 2563 }, 2564 }, 2565 }, 2566 2567 Partial: []string{}, 2568 2569 Result: &terraform.InstanceState{ 2570 Attributes: map[string]string{ 2571 "ports.#": "3", 2572 "ports.80": "80", 2573 "ports.81": "81", 2574 "ports.100": "100", 2575 }, 2576 }, 2577 }, 2578 2579 // #18 2580 { 2581 Schema: map[string]*Schema{ 2582 "ports": &Schema{ 2583 Type: TypeSet, 2584 Optional: true, 2585 Computed: true, 2586 Elem: &Schema{Type: TypeInt}, 2587 Set: func(a interface{}) int { 2588 return a.(int) 2589 }, 2590 }, 2591 }, 2592 2593 State: nil, 2594 2595 Diff: &terraform.InstanceDiff{ 2596 Attributes: map[string]*terraform.ResourceAttrDiff{ 2597 "ports.#": &terraform.ResourceAttrDiff{ 2598 Old: "", 2599 NewComputed: true, 2600 }, 2601 }, 2602 }, 2603 2604 Partial: []string{}, 2605 2606 Result: &terraform.InstanceState{ 2607 Attributes: map[string]string{}, 2608 }, 2609 }, 2610 2611 // #19 Maps 2612 { 2613 Schema: map[string]*Schema{ 2614 "tags": &Schema{ 2615 Type: TypeMap, 2616 Optional: true, 2617 Computed: true, 2618 }, 2619 }, 2620 2621 State: nil, 2622 2623 Diff: &terraform.InstanceDiff{ 2624 Attributes: map[string]*terraform.ResourceAttrDiff{ 2625 "tags.Name": &terraform.ResourceAttrDiff{ 2626 Old: "", 2627 New: "foo", 2628 }, 2629 }, 2630 }, 2631 2632 Result: &terraform.InstanceState{ 2633 Attributes: map[string]string{ 2634 "tags.%": "1", 2635 "tags.Name": "foo", 2636 }, 2637 }, 2638 }, 2639 2640 // #20 empty computed map 2641 { 2642 Schema: map[string]*Schema{ 2643 "tags": &Schema{ 2644 Type: TypeMap, 2645 Optional: true, 2646 Computed: true, 2647 }, 2648 }, 2649 2650 State: nil, 2651 2652 Diff: &terraform.InstanceDiff{ 2653 Attributes: map[string]*terraform.ResourceAttrDiff{ 2654 "tags.Name": &terraform.ResourceAttrDiff{ 2655 Old: "", 2656 New: "foo", 2657 }, 2658 }, 2659 }, 2660 2661 Set: map[string]interface{}{ 2662 "tags": map[string]string{}, 2663 }, 2664 2665 Result: &terraform.InstanceState{ 2666 Attributes: map[string]string{ 2667 "tags.%": "0", 2668 }, 2669 }, 2670 }, 2671 2672 // #21 2673 { 2674 Schema: map[string]*Schema{ 2675 "foo": &Schema{ 2676 Type: TypeString, 2677 Optional: true, 2678 Computed: true, 2679 }, 2680 }, 2681 2682 State: nil, 2683 2684 Diff: &terraform.InstanceDiff{ 2685 Attributes: map[string]*terraform.ResourceAttrDiff{ 2686 "foo": &terraform.ResourceAttrDiff{ 2687 NewComputed: true, 2688 }, 2689 }, 2690 }, 2691 2692 Result: &terraform.InstanceState{ 2693 Attributes: map[string]string{}, 2694 }, 2695 }, 2696 2697 // #22 2698 { 2699 Schema: map[string]*Schema{ 2700 "foo": &Schema{ 2701 Type: TypeString, 2702 Optional: true, 2703 Computed: true, 2704 }, 2705 }, 2706 2707 State: nil, 2708 2709 Diff: &terraform.InstanceDiff{ 2710 Attributes: map[string]*terraform.ResourceAttrDiff{ 2711 "foo": &terraform.ResourceAttrDiff{ 2712 NewComputed: true, 2713 }, 2714 }, 2715 }, 2716 2717 Set: map[string]interface{}{ 2718 "foo": "bar", 2719 }, 2720 2721 Result: &terraform.InstanceState{ 2722 Attributes: map[string]string{ 2723 "foo": "bar", 2724 }, 2725 }, 2726 }, 2727 2728 // #23 Set of maps 2729 { 2730 Schema: map[string]*Schema{ 2731 "ports": &Schema{ 2732 Type: TypeSet, 2733 Optional: true, 2734 Computed: true, 2735 Elem: &Resource{ 2736 Schema: map[string]*Schema{ 2737 "index": &Schema{Type: TypeInt}, 2738 "uuids": &Schema{Type: TypeMap}, 2739 }, 2740 }, 2741 Set: func(a interface{}) int { 2742 m := a.(map[string]interface{}) 2743 return m["index"].(int) 2744 }, 2745 }, 2746 }, 2747 2748 State: nil, 2749 2750 Diff: &terraform.InstanceDiff{ 2751 Attributes: map[string]*terraform.ResourceAttrDiff{ 2752 "ports.10.uuids.#": &terraform.ResourceAttrDiff{ 2753 NewComputed: true, 2754 }, 2755 }, 2756 }, 2757 2758 Set: map[string]interface{}{ 2759 "ports": []interface{}{ 2760 map[string]interface{}{ 2761 "index": 10, 2762 "uuids": map[string]interface{}{ 2763 "80": "value", 2764 }, 2765 }, 2766 }, 2767 }, 2768 2769 Result: &terraform.InstanceState{ 2770 Attributes: map[string]string{ 2771 "ports.#": "1", 2772 "ports.10.index": "10", 2773 "ports.10.uuids.%": "1", 2774 "ports.10.uuids.80": "value", 2775 }, 2776 }, 2777 }, 2778 2779 // #24 2780 { 2781 Schema: map[string]*Schema{ 2782 "ports": &Schema{ 2783 Type: TypeSet, 2784 Optional: true, 2785 Computed: true, 2786 Elem: &Schema{Type: TypeInt}, 2787 Set: func(a interface{}) int { 2788 return a.(int) 2789 }, 2790 }, 2791 }, 2792 2793 State: &terraform.InstanceState{ 2794 Attributes: map[string]string{ 2795 "ports.#": "3", 2796 "ports.100": "100", 2797 "ports.80": "80", 2798 "ports.81": "81", 2799 }, 2800 }, 2801 2802 Diff: &terraform.InstanceDiff{ 2803 Attributes: map[string]*terraform.ResourceAttrDiff{ 2804 "ports.#": &terraform.ResourceAttrDiff{ 2805 Old: "3", 2806 New: "0", 2807 }, 2808 }, 2809 }, 2810 2811 Result: &terraform.InstanceState{ 2812 Attributes: map[string]string{ 2813 "ports.#": "0", 2814 }, 2815 }, 2816 }, 2817 2818 // #25 2819 { 2820 Schema: map[string]*Schema{ 2821 "ports": &Schema{ 2822 Type: TypeSet, 2823 Optional: true, 2824 Computed: true, 2825 Elem: &Schema{Type: TypeInt}, 2826 Set: func(a interface{}) int { 2827 return a.(int) 2828 }, 2829 }, 2830 }, 2831 2832 State: nil, 2833 2834 Diff: nil, 2835 2836 Set: map[string]interface{}{ 2837 "ports": []interface{}{}, 2838 }, 2839 2840 Result: &terraform.InstanceState{ 2841 Attributes: map[string]string{ 2842 "ports.#": "0", 2843 }, 2844 }, 2845 }, 2846 2847 // #26 2848 { 2849 Schema: map[string]*Schema{ 2850 "ports": &Schema{ 2851 Type: TypeList, 2852 Optional: true, 2853 Computed: true, 2854 Elem: &Schema{Type: TypeInt}, 2855 }, 2856 }, 2857 2858 State: nil, 2859 2860 Diff: nil, 2861 2862 Set: map[string]interface{}{ 2863 "ports": []interface{}{}, 2864 }, 2865 2866 Result: &terraform.InstanceState{ 2867 Attributes: map[string]string{ 2868 "ports.#": "0", 2869 }, 2870 }, 2871 }, 2872 2873 // #27 Set lists 2874 { 2875 Schema: map[string]*Schema{ 2876 "ports": &Schema{ 2877 Type: TypeList, 2878 Optional: true, 2879 Computed: true, 2880 Elem: &Resource{ 2881 Schema: map[string]*Schema{ 2882 "index": &Schema{Type: TypeInt}, 2883 "uuids": &Schema{Type: TypeMap}, 2884 }, 2885 }, 2886 }, 2887 }, 2888 2889 State: nil, 2890 2891 Diff: &terraform.InstanceDiff{ 2892 Attributes: map[string]*terraform.ResourceAttrDiff{ 2893 "ports.#": &terraform.ResourceAttrDiff{ 2894 NewComputed: true, 2895 }, 2896 }, 2897 }, 2898 2899 Set: map[string]interface{}{ 2900 "ports": []interface{}{ 2901 map[string]interface{}{ 2902 "index": 10, 2903 "uuids": map[string]interface{}{ 2904 "80": "value", 2905 }, 2906 }, 2907 }, 2908 }, 2909 2910 Result: &terraform.InstanceState{ 2911 Attributes: map[string]string{ 2912 "ports.#": "1", 2913 "ports.0.index": "10", 2914 "ports.0.uuids.%": "1", 2915 "ports.0.uuids.80": "value", 2916 }, 2917 }, 2918 }, 2919 } 2920 2921 for i, tc := range cases { 2922 d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff) 2923 if err != nil { 2924 t.Fatalf("err: %s", err) 2925 } 2926 2927 for k, v := range tc.Set { 2928 if err := d.Set(k, v); err != nil { 2929 t.Fatalf("%d err: %s", i, err) 2930 } 2931 } 2932 2933 // Set an ID so that the state returned is not nil 2934 idSet := false 2935 if d.Id() == "" { 2936 idSet = true 2937 d.SetId("foo") 2938 } 2939 2940 // If we have partial, then enable partial state mode. 2941 if tc.Partial != nil { 2942 d.Partial(true) 2943 for _, k := range tc.Partial { 2944 d.SetPartial(k) 2945 } 2946 } 2947 2948 actual := d.State() 2949 2950 // If we set an ID, then undo what we did so the comparison works 2951 if actual != nil && idSet { 2952 actual.ID = "" 2953 delete(actual.Attributes, "id") 2954 } 2955 2956 if !reflect.DeepEqual(actual, tc.Result) { 2957 t.Fatalf("Bad: %d\n\n%#v\n\nExpected:\n\n%#v", i, actual, tc.Result) 2958 } 2959 } 2960 } 2961 2962 func TestResourceDataSetConnInfo(t *testing.T) { 2963 d := &ResourceData{} 2964 d.SetId("foo") 2965 d.SetConnInfo(map[string]string{ 2966 "foo": "bar", 2967 }) 2968 2969 expected := map[string]string{ 2970 "foo": "bar", 2971 } 2972 2973 actual := d.State() 2974 if !reflect.DeepEqual(actual.Ephemeral.ConnInfo, expected) { 2975 t.Fatalf("bad: %#v", actual) 2976 } 2977 } 2978 2979 func TestResourceDataSetId(t *testing.T) { 2980 d := &ResourceData{} 2981 d.SetId("foo") 2982 2983 actual := d.State() 2984 if actual.ID != "foo" { 2985 t.Fatalf("bad: %#v", actual) 2986 } 2987 } 2988 2989 func TestResourceDataSetId_clear(t *testing.T) { 2990 d := &ResourceData{ 2991 state: &terraform.InstanceState{ID: "bar"}, 2992 } 2993 d.SetId("") 2994 2995 actual := d.State() 2996 if actual != nil { 2997 t.Fatalf("bad: %#v", actual) 2998 } 2999 } 3000 3001 func TestResourceDataSetId_override(t *testing.T) { 3002 d := &ResourceData{ 3003 state: &terraform.InstanceState{ID: "bar"}, 3004 } 3005 d.SetId("foo") 3006 3007 actual := d.State() 3008 if actual.ID != "foo" { 3009 t.Fatalf("bad: %#v", actual) 3010 } 3011 } 3012 3013 func TestResourceDataSetType(t *testing.T) { 3014 d := &ResourceData{} 3015 d.SetId("foo") 3016 d.SetType("bar") 3017 3018 actual := d.State() 3019 if v := actual.Ephemeral.Type; v != "bar" { 3020 t.Fatalf("bad: %#v", actual) 3021 } 3022 } 3023 3024 func testPtrTo(raw interface{}) interface{} { 3025 return &raw 3026 }