github.com/ticketmaster/terraform@v0.10.0-beta2.0.20170711045249-a12daf5aba4f/terraform/state_test.go (about) 1 package terraform 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "os" 8 "reflect" 9 "sort" 10 "strings" 11 "testing" 12 13 "github.com/hashicorp/terraform/config" 14 ) 15 16 func TestStateValidate(t *testing.T) { 17 cases := map[string]struct { 18 In *State 19 Err bool 20 }{ 21 "empty state": { 22 &State{}, 23 false, 24 }, 25 26 "multiple modules": { 27 &State{ 28 Modules: []*ModuleState{ 29 &ModuleState{ 30 Path: []string{"root", "foo"}, 31 }, 32 &ModuleState{ 33 Path: []string{"root", "foo"}, 34 }, 35 }, 36 }, 37 true, 38 }, 39 } 40 41 for name, tc := range cases { 42 // Init the state 43 tc.In.init() 44 45 err := tc.In.Validate() 46 if (err != nil) != tc.Err { 47 t.Fatalf("%s: err: %s", name, err) 48 } 49 } 50 } 51 52 func TestStateAddModule(t *testing.T) { 53 cases := []struct { 54 In [][]string 55 Out [][]string 56 }{ 57 { 58 [][]string{ 59 []string{"root"}, 60 []string{"root", "child"}, 61 }, 62 [][]string{ 63 []string{"root"}, 64 []string{"root", "child"}, 65 }, 66 }, 67 68 { 69 [][]string{ 70 []string{"root", "foo", "bar"}, 71 []string{"root", "foo"}, 72 []string{"root"}, 73 []string{"root", "bar"}, 74 }, 75 [][]string{ 76 []string{"root"}, 77 []string{"root", "bar"}, 78 []string{"root", "foo"}, 79 []string{"root", "foo", "bar"}, 80 }, 81 }, 82 // Same last element, different middle element 83 { 84 [][]string{ 85 []string{"root", "foo", "bar"}, // This one should sort after... 86 []string{"root", "foo"}, 87 []string{"root"}, 88 []string{"root", "bar", "bar"}, // ...this one. 89 []string{"root", "bar"}, 90 }, 91 [][]string{ 92 []string{"root"}, 93 []string{"root", "bar"}, 94 []string{"root", "foo"}, 95 []string{"root", "bar", "bar"}, 96 []string{"root", "foo", "bar"}, 97 }, 98 }, 99 } 100 101 for _, tc := range cases { 102 s := new(State) 103 for _, p := range tc.In { 104 s.AddModule(p) 105 } 106 107 actual := make([][]string, 0, len(tc.In)) 108 for _, m := range s.Modules { 109 actual = append(actual, m.Path) 110 } 111 112 if !reflect.DeepEqual(actual, tc.Out) { 113 t.Fatalf("In: %#v\n\nOut: %#v", tc.In, actual) 114 } 115 } 116 } 117 118 func TestStateOutputTypeRoundTrip(t *testing.T) { 119 state := &State{ 120 Modules: []*ModuleState{ 121 &ModuleState{ 122 Path: RootModulePath, 123 Outputs: map[string]*OutputState{ 124 "string_output": &OutputState{ 125 Value: "String Value", 126 Type: "string", 127 }, 128 }, 129 }, 130 }, 131 } 132 state.init() 133 134 buf := new(bytes.Buffer) 135 if err := WriteState(state, buf); err != nil { 136 t.Fatalf("err: %s", err) 137 } 138 139 roundTripped, err := ReadState(buf) 140 if err != nil { 141 t.Fatalf("err: %s", err) 142 } 143 144 if !reflect.DeepEqual(state, roundTripped) { 145 t.Logf("expected:\n%#v", state) 146 t.Fatalf("got:\n%#v", roundTripped) 147 } 148 } 149 150 func TestStateModuleOrphans(t *testing.T) { 151 state := &State{ 152 Modules: []*ModuleState{ 153 &ModuleState{ 154 Path: RootModulePath, 155 }, 156 &ModuleState{ 157 Path: []string{RootModuleName, "foo"}, 158 }, 159 &ModuleState{ 160 Path: []string{RootModuleName, "bar"}, 161 }, 162 }, 163 } 164 165 state.init() 166 167 config := testModule(t, "state-module-orphans").Config() 168 actual := state.ModuleOrphans(RootModulePath, config) 169 expected := [][]string{ 170 []string{RootModuleName, "foo"}, 171 } 172 173 if !reflect.DeepEqual(actual, expected) { 174 t.Fatalf("bad: %#v", actual) 175 } 176 } 177 178 func TestStateModuleOrphans_nested(t *testing.T) { 179 state := &State{ 180 Modules: []*ModuleState{ 181 &ModuleState{ 182 Path: RootModulePath, 183 }, 184 &ModuleState{ 185 Path: []string{RootModuleName, "foo", "bar"}, 186 }, 187 }, 188 } 189 190 state.init() 191 192 actual := state.ModuleOrphans(RootModulePath, nil) 193 expected := [][]string{ 194 []string{RootModuleName, "foo"}, 195 } 196 197 if !reflect.DeepEqual(actual, expected) { 198 t.Fatalf("bad: %#v", actual) 199 } 200 } 201 202 func TestStateModuleOrphans_nilConfig(t *testing.T) { 203 state := &State{ 204 Modules: []*ModuleState{ 205 &ModuleState{ 206 Path: RootModulePath, 207 }, 208 &ModuleState{ 209 Path: []string{RootModuleName, "foo"}, 210 }, 211 &ModuleState{ 212 Path: []string{RootModuleName, "bar"}, 213 }, 214 }, 215 } 216 217 state.init() 218 219 actual := state.ModuleOrphans(RootModulePath, nil) 220 expected := [][]string{ 221 []string{RootModuleName, "foo"}, 222 []string{RootModuleName, "bar"}, 223 } 224 225 if !reflect.DeepEqual(actual, expected) { 226 t.Fatalf("bad: %#v", actual) 227 } 228 } 229 230 func TestStateModuleOrphans_deepNestedNilConfig(t *testing.T) { 231 state := &State{ 232 Modules: []*ModuleState{ 233 &ModuleState{ 234 Path: RootModulePath, 235 }, 236 &ModuleState{ 237 Path: []string{RootModuleName, "parent", "childfoo"}, 238 }, 239 &ModuleState{ 240 Path: []string{RootModuleName, "parent", "childbar"}, 241 }, 242 }, 243 } 244 245 state.init() 246 247 actual := state.ModuleOrphans(RootModulePath, nil) 248 expected := [][]string{ 249 []string{RootModuleName, "parent"}, 250 } 251 252 if !reflect.DeepEqual(actual, expected) { 253 t.Fatalf("bad: %#v", actual) 254 } 255 } 256 257 func TestStateDeepCopy(t *testing.T) { 258 cases := []struct { 259 State *State 260 }{ 261 // Nil 262 {nil}, 263 264 // Version 265 { 266 &State{Version: 5}, 267 }, 268 // TFVersion 269 { 270 &State{TFVersion: "5"}, 271 }, 272 // Modules 273 { 274 &State{ 275 Version: 6, 276 Modules: []*ModuleState{ 277 &ModuleState{ 278 Path: rootModulePath, 279 Resources: map[string]*ResourceState{ 280 "test_instance.foo": &ResourceState{ 281 Primary: &InstanceState{ 282 Meta: map[string]interface{}{}, 283 }, 284 }, 285 }, 286 }, 287 }, 288 }, 289 }, 290 // Deposed 291 // The nil values shouldn't be there if the State was properly init'ed, 292 // but the Copy should still work anyway. 293 { 294 &State{ 295 Version: 6, 296 Modules: []*ModuleState{ 297 &ModuleState{ 298 Path: rootModulePath, 299 Resources: map[string]*ResourceState{ 300 "test_instance.foo": &ResourceState{ 301 Primary: &InstanceState{ 302 Meta: map[string]interface{}{}, 303 }, 304 Deposed: []*InstanceState{ 305 {ID: "test"}, 306 nil, 307 }, 308 }, 309 }, 310 }, 311 }, 312 }, 313 }, 314 } 315 316 for i, tc := range cases { 317 t.Run(fmt.Sprintf("copy-%d", i), func(t *testing.T) { 318 actual := tc.State.DeepCopy() 319 expected := tc.State 320 if !reflect.DeepEqual(actual, expected) { 321 t.Fatalf("Expected: %#v\nRecevied: %#v\n", expected, actual) 322 } 323 }) 324 } 325 } 326 327 func TestStateEqual(t *testing.T) { 328 cases := []struct { 329 Name string 330 Result bool 331 One, Two *State 332 }{ 333 // Nils 334 { 335 "one nil", 336 false, 337 nil, 338 &State{Version: 2}, 339 }, 340 341 { 342 "both nil", 343 true, 344 nil, 345 nil, 346 }, 347 348 // Different versions 349 { 350 "different state versions", 351 false, 352 &State{Version: 5}, 353 &State{Version: 2}, 354 }, 355 356 // Different modules 357 { 358 "different module states", 359 false, 360 &State{ 361 Modules: []*ModuleState{ 362 &ModuleState{ 363 Path: RootModulePath, 364 }, 365 }, 366 }, 367 &State{}, 368 }, 369 370 { 371 "same module states", 372 true, 373 &State{ 374 Modules: []*ModuleState{ 375 &ModuleState{ 376 Path: RootModulePath, 377 }, 378 }, 379 }, 380 &State{ 381 Modules: []*ModuleState{ 382 &ModuleState{ 383 Path: RootModulePath, 384 }, 385 }, 386 }, 387 }, 388 389 // Meta differs 390 { 391 "differing meta values with primitives", 392 false, 393 &State{ 394 Modules: []*ModuleState{ 395 &ModuleState{ 396 Path: rootModulePath, 397 Resources: map[string]*ResourceState{ 398 "test_instance.foo": &ResourceState{ 399 Primary: &InstanceState{ 400 Meta: map[string]interface{}{ 401 "schema_version": "1", 402 }, 403 }, 404 }, 405 }, 406 }, 407 }, 408 }, 409 &State{ 410 Modules: []*ModuleState{ 411 &ModuleState{ 412 Path: rootModulePath, 413 Resources: map[string]*ResourceState{ 414 "test_instance.foo": &ResourceState{ 415 Primary: &InstanceState{ 416 Meta: map[string]interface{}{ 417 "schema_version": "2", 418 }, 419 }, 420 }, 421 }, 422 }, 423 }, 424 }, 425 }, 426 427 // Meta with complex types 428 { 429 "same meta with complex types", 430 true, 431 &State{ 432 Modules: []*ModuleState{ 433 &ModuleState{ 434 Path: rootModulePath, 435 Resources: map[string]*ResourceState{ 436 "test_instance.foo": &ResourceState{ 437 Primary: &InstanceState{ 438 Meta: map[string]interface{}{ 439 "timeouts": map[string]interface{}{ 440 "create": 42, 441 "read": "27", 442 }, 443 }, 444 }, 445 }, 446 }, 447 }, 448 }, 449 }, 450 &State{ 451 Modules: []*ModuleState{ 452 &ModuleState{ 453 Path: rootModulePath, 454 Resources: map[string]*ResourceState{ 455 "test_instance.foo": &ResourceState{ 456 Primary: &InstanceState{ 457 Meta: map[string]interface{}{ 458 "timeouts": map[string]interface{}{ 459 "create": 42, 460 "read": "27", 461 }, 462 }, 463 }, 464 }, 465 }, 466 }, 467 }, 468 }, 469 }, 470 } 471 472 for i, tc := range cases { 473 t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) { 474 if tc.One.Equal(tc.Two) != tc.Result { 475 t.Fatalf("Bad: %d\n\n%s\n\n%s", i, tc.One.String(), tc.Two.String()) 476 } 477 if tc.Two.Equal(tc.One) != tc.Result { 478 t.Fatalf("Bad: %d\n\n%s\n\n%s", i, tc.One.String(), tc.Two.String()) 479 } 480 }) 481 } 482 } 483 484 func TestStateCompareAges(t *testing.T) { 485 cases := []struct { 486 Result StateAgeComparison 487 Err bool 488 One, Two *State 489 }{ 490 { 491 StateAgeEqual, false, 492 &State{ 493 Lineage: "1", 494 Serial: 2, 495 }, 496 &State{ 497 Lineage: "1", 498 Serial: 2, 499 }, 500 }, 501 { 502 StateAgeReceiverOlder, false, 503 &State{ 504 Lineage: "1", 505 Serial: 2, 506 }, 507 &State{ 508 Lineage: "1", 509 Serial: 3, 510 }, 511 }, 512 { 513 StateAgeReceiverNewer, false, 514 &State{ 515 Lineage: "1", 516 Serial: 3, 517 }, 518 &State{ 519 Lineage: "1", 520 Serial: 2, 521 }, 522 }, 523 { 524 StateAgeEqual, true, 525 &State{ 526 Lineage: "1", 527 Serial: 2, 528 }, 529 &State{ 530 Lineage: "2", 531 Serial: 2, 532 }, 533 }, 534 { 535 StateAgeEqual, true, 536 &State{ 537 Lineage: "1", 538 Serial: 3, 539 }, 540 &State{ 541 Lineage: "2", 542 Serial: 2, 543 }, 544 }, 545 } 546 547 for i, tc := range cases { 548 result, err := tc.One.CompareAges(tc.Two) 549 550 if err != nil && !tc.Err { 551 t.Errorf( 552 "%d: got error, but want success\n\n%s\n\n%s", 553 i, tc.One, tc.Two, 554 ) 555 continue 556 } 557 558 if err == nil && tc.Err { 559 t.Errorf( 560 "%d: got success, but want error\n\n%s\n\n%s", 561 i, tc.One, tc.Two, 562 ) 563 continue 564 } 565 566 if result != tc.Result { 567 t.Errorf( 568 "%d: got result %d, but want %d\n\n%s\n\n%s", 569 i, result, tc.Result, tc.One, tc.Two, 570 ) 571 continue 572 } 573 } 574 } 575 576 func TestStateSameLineage(t *testing.T) { 577 cases := []struct { 578 Result bool 579 One, Two *State 580 }{ 581 { 582 true, 583 &State{ 584 Lineage: "1", 585 }, 586 &State{ 587 Lineage: "1", 588 }, 589 }, 590 { 591 // Empty lineage is compatible with all 592 true, 593 &State{ 594 Lineage: "", 595 }, 596 &State{ 597 Lineage: "1", 598 }, 599 }, 600 { 601 // Empty lineage is compatible with all 602 true, 603 &State{ 604 Lineage: "1", 605 }, 606 &State{ 607 Lineage: "", 608 }, 609 }, 610 { 611 false, 612 &State{ 613 Lineage: "1", 614 }, 615 &State{ 616 Lineage: "2", 617 }, 618 }, 619 } 620 621 for i, tc := range cases { 622 result := tc.One.SameLineage(tc.Two) 623 624 if result != tc.Result { 625 t.Errorf( 626 "%d: got %v, but want %v\n\n%s\n\n%s", 627 i, result, tc.Result, tc.One, tc.Two, 628 ) 629 continue 630 } 631 } 632 } 633 634 func TestStateMarshalEqual(t *testing.T) { 635 tests := map[string]struct { 636 S1, S2 *State 637 Want bool 638 }{ 639 "both nil": { 640 nil, 641 nil, 642 true, 643 }, 644 "first zero, second nil": { 645 &State{}, 646 nil, 647 false, 648 }, 649 "first nil, second zero": { 650 nil, 651 &State{}, 652 false, 653 }, 654 "both zero": { 655 // These are not equal because they both implicitly init with 656 // different lineage. 657 &State{}, 658 &State{}, 659 false, 660 }, 661 "both set, same lineage": { 662 &State{ 663 Lineage: "abc123", 664 }, 665 &State{ 666 Lineage: "abc123", 667 }, 668 true, 669 }, 670 "both set, same lineage, different serial": { 671 &State{ 672 Lineage: "abc123", 673 Serial: 1, 674 }, 675 &State{ 676 Lineage: "abc123", 677 Serial: 2, 678 }, 679 false, 680 }, 681 "both set, same lineage, same serial, same resources": { 682 &State{ 683 Lineage: "abc123", 684 Serial: 1, 685 Modules: []*ModuleState{ 686 { 687 Path: []string{"root"}, 688 Resources: map[string]*ResourceState{ 689 "foo_bar.baz": {}, 690 }, 691 }, 692 }, 693 }, 694 &State{ 695 Lineage: "abc123", 696 Serial: 1, 697 Modules: []*ModuleState{ 698 { 699 Path: []string{"root"}, 700 Resources: map[string]*ResourceState{ 701 "foo_bar.baz": {}, 702 }, 703 }, 704 }, 705 }, 706 true, 707 }, 708 "both set, same lineage, same serial, different resources": { 709 &State{ 710 Lineage: "abc123", 711 Serial: 1, 712 Modules: []*ModuleState{ 713 { 714 Path: []string{"root"}, 715 Resources: map[string]*ResourceState{ 716 "foo_bar.baz": {}, 717 }, 718 }, 719 }, 720 }, 721 &State{ 722 Lineage: "abc123", 723 Serial: 1, 724 Modules: []*ModuleState{ 725 { 726 Path: []string{"root"}, 727 Resources: map[string]*ResourceState{ 728 "pizza_crust.tasty": {}, 729 }, 730 }, 731 }, 732 }, 733 false, 734 }, 735 } 736 737 for name, test := range tests { 738 t.Run(name, func(t *testing.T) { 739 got := test.S1.MarshalEqual(test.S2) 740 if got != test.Want { 741 t.Errorf("wrong result %#v; want %#v", got, test.Want) 742 s1Buf := &bytes.Buffer{} 743 s2Buf := &bytes.Buffer{} 744 _ = WriteState(test.S1, s1Buf) 745 _ = WriteState(test.S2, s2Buf) 746 t.Logf("\nState 1: %s\nState 2: %s", s1Buf.Bytes(), s2Buf.Bytes()) 747 } 748 }) 749 } 750 } 751 752 func TestStateRemove(t *testing.T) { 753 cases := map[string]struct { 754 Address string 755 One, Two *State 756 }{ 757 "simple resource": { 758 "test_instance.foo", 759 &State{ 760 Modules: []*ModuleState{ 761 &ModuleState{ 762 Path: rootModulePath, 763 Resources: map[string]*ResourceState{ 764 "test_instance.foo": &ResourceState{ 765 Type: "test_instance", 766 Primary: &InstanceState{ 767 ID: "foo", 768 }, 769 }, 770 771 "test_instance.bar": &ResourceState{ 772 Type: "test_instance", 773 Primary: &InstanceState{ 774 ID: "foo", 775 }, 776 }, 777 }, 778 }, 779 }, 780 }, 781 &State{ 782 Modules: []*ModuleState{ 783 &ModuleState{ 784 Path: rootModulePath, 785 Resources: map[string]*ResourceState{ 786 "test_instance.bar": &ResourceState{ 787 Type: "test_instance", 788 Primary: &InstanceState{ 789 ID: "foo", 790 }, 791 }, 792 }, 793 }, 794 }, 795 }, 796 }, 797 798 "single instance": { 799 "test_instance.foo.primary", 800 &State{ 801 Modules: []*ModuleState{ 802 &ModuleState{ 803 Path: rootModulePath, 804 Resources: map[string]*ResourceState{ 805 "test_instance.foo": &ResourceState{ 806 Type: "test_instance", 807 Primary: &InstanceState{ 808 ID: "foo", 809 }, 810 }, 811 }, 812 }, 813 }, 814 }, 815 &State{ 816 Modules: []*ModuleState{ 817 &ModuleState{ 818 Path: rootModulePath, 819 Resources: map[string]*ResourceState{}, 820 }, 821 }, 822 }, 823 }, 824 825 "single instance in multi-count": { 826 "test_instance.foo[0]", 827 &State{ 828 Modules: []*ModuleState{ 829 &ModuleState{ 830 Path: rootModulePath, 831 Resources: map[string]*ResourceState{ 832 "test_instance.foo.0": &ResourceState{ 833 Type: "test_instance", 834 Primary: &InstanceState{ 835 ID: "foo", 836 }, 837 }, 838 839 "test_instance.foo.1": &ResourceState{ 840 Type: "test_instance", 841 Primary: &InstanceState{ 842 ID: "foo", 843 }, 844 }, 845 }, 846 }, 847 }, 848 }, 849 &State{ 850 Modules: []*ModuleState{ 851 &ModuleState{ 852 Path: rootModulePath, 853 Resources: map[string]*ResourceState{ 854 "test_instance.foo.1": &ResourceState{ 855 Type: "test_instance", 856 Primary: &InstanceState{ 857 ID: "foo", 858 }, 859 }, 860 }, 861 }, 862 }, 863 }, 864 }, 865 866 "single resource, multi-count": { 867 "test_instance.foo", 868 &State{ 869 Modules: []*ModuleState{ 870 &ModuleState{ 871 Path: rootModulePath, 872 Resources: map[string]*ResourceState{ 873 "test_instance.foo.0": &ResourceState{ 874 Type: "test_instance", 875 Primary: &InstanceState{ 876 ID: "foo", 877 }, 878 }, 879 880 "test_instance.foo.1": &ResourceState{ 881 Type: "test_instance", 882 Primary: &InstanceState{ 883 ID: "foo", 884 }, 885 }, 886 }, 887 }, 888 }, 889 }, 890 &State{ 891 Modules: []*ModuleState{ 892 &ModuleState{ 893 Path: rootModulePath, 894 Resources: map[string]*ResourceState{}, 895 }, 896 }, 897 }, 898 }, 899 900 "full module": { 901 "module.foo", 902 &State{ 903 Modules: []*ModuleState{ 904 &ModuleState{ 905 Path: rootModulePath, 906 Resources: map[string]*ResourceState{ 907 "test_instance.foo": &ResourceState{ 908 Type: "test_instance", 909 Primary: &InstanceState{ 910 ID: "foo", 911 }, 912 }, 913 }, 914 }, 915 916 &ModuleState{ 917 Path: []string{"root", "foo"}, 918 Resources: map[string]*ResourceState{ 919 "test_instance.foo": &ResourceState{ 920 Type: "test_instance", 921 Primary: &InstanceState{ 922 ID: "foo", 923 }, 924 }, 925 926 "test_instance.bar": &ResourceState{ 927 Type: "test_instance", 928 Primary: &InstanceState{ 929 ID: "foo", 930 }, 931 }, 932 }, 933 }, 934 }, 935 }, 936 &State{ 937 Modules: []*ModuleState{ 938 &ModuleState{ 939 Path: rootModulePath, 940 Resources: map[string]*ResourceState{ 941 "test_instance.foo": &ResourceState{ 942 Type: "test_instance", 943 Primary: &InstanceState{ 944 ID: "foo", 945 }, 946 }, 947 }, 948 }, 949 }, 950 }, 951 }, 952 953 "module and children": { 954 "module.foo", 955 &State{ 956 Modules: []*ModuleState{ 957 &ModuleState{ 958 Path: rootModulePath, 959 Resources: map[string]*ResourceState{ 960 "test_instance.foo": &ResourceState{ 961 Type: "test_instance", 962 Primary: &InstanceState{ 963 ID: "foo", 964 }, 965 }, 966 }, 967 }, 968 969 &ModuleState{ 970 Path: []string{"root", "foo"}, 971 Resources: map[string]*ResourceState{ 972 "test_instance.foo": &ResourceState{ 973 Type: "test_instance", 974 Primary: &InstanceState{ 975 ID: "foo", 976 }, 977 }, 978 979 "test_instance.bar": &ResourceState{ 980 Type: "test_instance", 981 Primary: &InstanceState{ 982 ID: "foo", 983 }, 984 }, 985 }, 986 }, 987 988 &ModuleState{ 989 Path: []string{"root", "foo", "bar"}, 990 Resources: map[string]*ResourceState{ 991 "test_instance.foo": &ResourceState{ 992 Type: "test_instance", 993 Primary: &InstanceState{ 994 ID: "foo", 995 }, 996 }, 997 998 "test_instance.bar": &ResourceState{ 999 Type: "test_instance", 1000 Primary: &InstanceState{ 1001 ID: "foo", 1002 }, 1003 }, 1004 }, 1005 }, 1006 }, 1007 }, 1008 &State{ 1009 Modules: []*ModuleState{ 1010 &ModuleState{ 1011 Path: rootModulePath, 1012 Resources: map[string]*ResourceState{ 1013 "test_instance.foo": &ResourceState{ 1014 Type: "test_instance", 1015 Primary: &InstanceState{ 1016 ID: "foo", 1017 }, 1018 }, 1019 }, 1020 }, 1021 }, 1022 }, 1023 }, 1024 } 1025 1026 for k, tc := range cases { 1027 if err := tc.One.Remove(tc.Address); err != nil { 1028 t.Fatalf("bad: %s\n\n%s", k, err) 1029 } 1030 1031 if !tc.One.Equal(tc.Two) { 1032 t.Fatalf("Bad: %s\n\n%s\n\n%s", k, tc.One.String(), tc.Two.String()) 1033 } 1034 } 1035 } 1036 1037 func TestResourceStateEqual(t *testing.T) { 1038 cases := []struct { 1039 Result bool 1040 One, Two *ResourceState 1041 }{ 1042 // Different types 1043 { 1044 false, 1045 &ResourceState{Type: "foo"}, 1046 &ResourceState{Type: "bar"}, 1047 }, 1048 1049 // Different dependencies 1050 { 1051 false, 1052 &ResourceState{Dependencies: []string{"foo"}}, 1053 &ResourceState{Dependencies: []string{"bar"}}, 1054 }, 1055 1056 { 1057 false, 1058 &ResourceState{Dependencies: []string{"foo", "bar"}}, 1059 &ResourceState{Dependencies: []string{"foo"}}, 1060 }, 1061 1062 { 1063 true, 1064 &ResourceState{Dependencies: []string{"bar", "foo"}}, 1065 &ResourceState{Dependencies: []string{"foo", "bar"}}, 1066 }, 1067 1068 // Different primaries 1069 { 1070 false, 1071 &ResourceState{Primary: nil}, 1072 &ResourceState{Primary: &InstanceState{ID: "foo"}}, 1073 }, 1074 1075 { 1076 true, 1077 &ResourceState{Primary: &InstanceState{ID: "foo"}}, 1078 &ResourceState{Primary: &InstanceState{ID: "foo"}}, 1079 }, 1080 1081 // Different tainted 1082 { 1083 false, 1084 &ResourceState{ 1085 Primary: &InstanceState{ 1086 ID: "foo", 1087 }, 1088 }, 1089 &ResourceState{ 1090 Primary: &InstanceState{ 1091 ID: "foo", 1092 Tainted: true, 1093 }, 1094 }, 1095 }, 1096 1097 { 1098 true, 1099 &ResourceState{ 1100 Primary: &InstanceState{ 1101 ID: "foo", 1102 Tainted: true, 1103 }, 1104 }, 1105 &ResourceState{ 1106 Primary: &InstanceState{ 1107 ID: "foo", 1108 Tainted: true, 1109 }, 1110 }, 1111 }, 1112 } 1113 1114 for i, tc := range cases { 1115 if tc.One.Equal(tc.Two) != tc.Result { 1116 t.Fatalf("Bad: %d\n\n%s\n\n%s", i, tc.One.String(), tc.Two.String()) 1117 } 1118 if tc.Two.Equal(tc.One) != tc.Result { 1119 t.Fatalf("Bad: %d\n\n%s\n\n%s", i, tc.One.String(), tc.Two.String()) 1120 } 1121 } 1122 } 1123 1124 func TestResourceStateTaint(t *testing.T) { 1125 cases := map[string]struct { 1126 Input *ResourceState 1127 Output *ResourceState 1128 }{ 1129 "no primary": { 1130 &ResourceState{}, 1131 &ResourceState{}, 1132 }, 1133 1134 "primary, not tainted": { 1135 &ResourceState{ 1136 Primary: &InstanceState{ID: "foo"}, 1137 }, 1138 &ResourceState{ 1139 Primary: &InstanceState{ 1140 ID: "foo", 1141 Tainted: true, 1142 }, 1143 }, 1144 }, 1145 1146 "primary, tainted": { 1147 &ResourceState{ 1148 Primary: &InstanceState{ 1149 ID: "foo", 1150 Tainted: true, 1151 }, 1152 }, 1153 &ResourceState{ 1154 Primary: &InstanceState{ 1155 ID: "foo", 1156 Tainted: true, 1157 }, 1158 }, 1159 }, 1160 } 1161 1162 for k, tc := range cases { 1163 tc.Input.Taint() 1164 if !reflect.DeepEqual(tc.Input, tc.Output) { 1165 t.Fatalf( 1166 "Failure: %s\n\nExpected: %#v\n\nGot: %#v", 1167 k, tc.Output, tc.Input) 1168 } 1169 } 1170 } 1171 1172 func TestResourceStateUntaint(t *testing.T) { 1173 cases := map[string]struct { 1174 Input *ResourceState 1175 ExpectedOutput *ResourceState 1176 }{ 1177 "no primary, err": { 1178 Input: &ResourceState{}, 1179 ExpectedOutput: &ResourceState{}, 1180 }, 1181 1182 "primary, not tainted": { 1183 Input: &ResourceState{ 1184 Primary: &InstanceState{ID: "foo"}, 1185 }, 1186 ExpectedOutput: &ResourceState{ 1187 Primary: &InstanceState{ID: "foo"}, 1188 }, 1189 }, 1190 "primary, tainted": { 1191 Input: &ResourceState{ 1192 Primary: &InstanceState{ 1193 ID: "foo", 1194 Tainted: true, 1195 }, 1196 }, 1197 ExpectedOutput: &ResourceState{ 1198 Primary: &InstanceState{ID: "foo"}, 1199 }, 1200 }, 1201 } 1202 1203 for k, tc := range cases { 1204 tc.Input.Untaint() 1205 if !reflect.DeepEqual(tc.Input, tc.ExpectedOutput) { 1206 t.Fatalf( 1207 "Failure: %s\n\nExpected: %#v\n\nGot: %#v", 1208 k, tc.ExpectedOutput, tc.Input) 1209 } 1210 } 1211 } 1212 1213 func TestInstanceStateEmpty(t *testing.T) { 1214 cases := map[string]struct { 1215 In *InstanceState 1216 Result bool 1217 }{ 1218 "nil is empty": { 1219 nil, 1220 true, 1221 }, 1222 "non-nil but without ID is empty": { 1223 &InstanceState{}, 1224 true, 1225 }, 1226 "with ID is not empty": { 1227 &InstanceState{ 1228 ID: "i-abc123", 1229 }, 1230 false, 1231 }, 1232 } 1233 1234 for tn, tc := range cases { 1235 if tc.In.Empty() != tc.Result { 1236 t.Fatalf("%q expected %#v to be empty: %#v", tn, tc.In, tc.Result) 1237 } 1238 } 1239 } 1240 1241 func TestInstanceStateEqual(t *testing.T) { 1242 cases := []struct { 1243 Result bool 1244 One, Two *InstanceState 1245 }{ 1246 // Nils 1247 { 1248 false, 1249 nil, 1250 &InstanceState{}, 1251 }, 1252 1253 { 1254 false, 1255 &InstanceState{}, 1256 nil, 1257 }, 1258 1259 // Different IDs 1260 { 1261 false, 1262 &InstanceState{ID: "foo"}, 1263 &InstanceState{ID: "bar"}, 1264 }, 1265 1266 // Different Attributes 1267 { 1268 false, 1269 &InstanceState{Attributes: map[string]string{"foo": "bar"}}, 1270 &InstanceState{Attributes: map[string]string{"foo": "baz"}}, 1271 }, 1272 1273 // Different Attribute keys 1274 { 1275 false, 1276 &InstanceState{Attributes: map[string]string{"foo": "bar"}}, 1277 &InstanceState{Attributes: map[string]string{"bar": "baz"}}, 1278 }, 1279 1280 { 1281 false, 1282 &InstanceState{Attributes: map[string]string{"bar": "baz"}}, 1283 &InstanceState{Attributes: map[string]string{"foo": "bar"}}, 1284 }, 1285 } 1286 1287 for i, tc := range cases { 1288 if tc.One.Equal(tc.Two) != tc.Result { 1289 t.Fatalf("Bad: %d\n\n%s\n\n%s", i, tc.One.String(), tc.Two.String()) 1290 } 1291 } 1292 } 1293 1294 func TestStateEmpty(t *testing.T) { 1295 cases := []struct { 1296 In *State 1297 Result bool 1298 }{ 1299 { 1300 nil, 1301 true, 1302 }, 1303 { 1304 &State{}, 1305 true, 1306 }, 1307 { 1308 &State{ 1309 Remote: &RemoteState{Type: "foo"}, 1310 }, 1311 true, 1312 }, 1313 { 1314 &State{ 1315 Modules: []*ModuleState{ 1316 &ModuleState{}, 1317 }, 1318 }, 1319 false, 1320 }, 1321 } 1322 1323 for i, tc := range cases { 1324 if tc.In.Empty() != tc.Result { 1325 t.Fatalf("bad %d %#v:\n\n%#v", i, tc.Result, tc.In) 1326 } 1327 } 1328 } 1329 1330 func TestStateHasResources(t *testing.T) { 1331 cases := []struct { 1332 In *State 1333 Result bool 1334 }{ 1335 { 1336 nil, 1337 false, 1338 }, 1339 { 1340 &State{}, 1341 false, 1342 }, 1343 { 1344 &State{ 1345 Remote: &RemoteState{Type: "foo"}, 1346 }, 1347 false, 1348 }, 1349 { 1350 &State{ 1351 Modules: []*ModuleState{ 1352 &ModuleState{}, 1353 }, 1354 }, 1355 false, 1356 }, 1357 { 1358 &State{ 1359 Modules: []*ModuleState{ 1360 &ModuleState{}, 1361 &ModuleState{}, 1362 }, 1363 }, 1364 false, 1365 }, 1366 { 1367 &State{ 1368 Modules: []*ModuleState{ 1369 &ModuleState{}, 1370 &ModuleState{ 1371 Resources: map[string]*ResourceState{ 1372 "foo.foo": &ResourceState{}, 1373 }, 1374 }, 1375 }, 1376 }, 1377 true, 1378 }, 1379 } 1380 1381 for i, tc := range cases { 1382 if tc.In.HasResources() != tc.Result { 1383 t.Fatalf("bad %d %#v:\n\n%#v", i, tc.Result, tc.In) 1384 } 1385 } 1386 } 1387 1388 func TestStateFromFutureTerraform(t *testing.T) { 1389 cases := []struct { 1390 In string 1391 Result bool 1392 }{ 1393 { 1394 "", 1395 false, 1396 }, 1397 { 1398 "0.1", 1399 false, 1400 }, 1401 { 1402 "999.15.1", 1403 true, 1404 }, 1405 } 1406 1407 for _, tc := range cases { 1408 state := &State{TFVersion: tc.In} 1409 actual := state.FromFutureTerraform() 1410 if actual != tc.Result { 1411 t.Fatalf("%s: bad: %v", tc.In, actual) 1412 } 1413 } 1414 } 1415 1416 func TestStateIsRemote(t *testing.T) { 1417 cases := []struct { 1418 In *State 1419 Result bool 1420 }{ 1421 { 1422 nil, 1423 false, 1424 }, 1425 { 1426 &State{}, 1427 false, 1428 }, 1429 { 1430 &State{ 1431 Remote: &RemoteState{Type: "foo"}, 1432 }, 1433 true, 1434 }, 1435 } 1436 1437 for i, tc := range cases { 1438 if tc.In.IsRemote() != tc.Result { 1439 t.Fatalf("bad %d %#v:\n\n%#v", i, tc.Result, tc.In) 1440 } 1441 } 1442 } 1443 1444 func TestInstanceState_MergeDiff(t *testing.T) { 1445 is := InstanceState{ 1446 ID: "foo", 1447 Attributes: map[string]string{ 1448 "foo": "bar", 1449 "port": "8000", 1450 }, 1451 } 1452 1453 diff := &InstanceDiff{ 1454 Attributes: map[string]*ResourceAttrDiff{ 1455 "foo": &ResourceAttrDiff{ 1456 Old: "bar", 1457 New: "baz", 1458 }, 1459 "bar": &ResourceAttrDiff{ 1460 Old: "", 1461 New: "foo", 1462 }, 1463 "baz": &ResourceAttrDiff{ 1464 Old: "", 1465 New: "foo", 1466 NewComputed: true, 1467 }, 1468 "port": &ResourceAttrDiff{ 1469 NewRemoved: true, 1470 }, 1471 }, 1472 } 1473 1474 is2 := is.MergeDiff(diff) 1475 1476 expected := map[string]string{ 1477 "foo": "baz", 1478 "bar": "foo", 1479 "baz": config.UnknownVariableValue, 1480 } 1481 1482 if !reflect.DeepEqual(expected, is2.Attributes) { 1483 t.Fatalf("bad: %#v", is2.Attributes) 1484 } 1485 } 1486 1487 // GH-12183. This tests that a list with a computed set generates the 1488 // right partial state. This never failed but is put here for completion 1489 // of the test case for GH-12183. 1490 func TestInstanceState_MergeDiff_computedSet(t *testing.T) { 1491 is := InstanceState{} 1492 1493 diff := &InstanceDiff{ 1494 Attributes: map[string]*ResourceAttrDiff{ 1495 "config.#": &ResourceAttrDiff{ 1496 Old: "0", 1497 New: "1", 1498 RequiresNew: true, 1499 }, 1500 1501 "config.0.name": &ResourceAttrDiff{ 1502 Old: "", 1503 New: "hello", 1504 }, 1505 1506 "config.0.rules.#": &ResourceAttrDiff{ 1507 Old: "", 1508 NewComputed: true, 1509 }, 1510 }, 1511 } 1512 1513 is2 := is.MergeDiff(diff) 1514 1515 expected := map[string]string{ 1516 "config.#": "1", 1517 "config.0.name": "hello", 1518 "config.0.rules.#": config.UnknownVariableValue, 1519 } 1520 1521 if !reflect.DeepEqual(expected, is2.Attributes) { 1522 t.Fatalf("bad: %#v", is2.Attributes) 1523 } 1524 } 1525 1526 func TestInstanceState_MergeDiff_nil(t *testing.T) { 1527 var is *InstanceState 1528 1529 diff := &InstanceDiff{ 1530 Attributes: map[string]*ResourceAttrDiff{ 1531 "foo": &ResourceAttrDiff{ 1532 Old: "", 1533 New: "baz", 1534 }, 1535 }, 1536 } 1537 1538 is2 := is.MergeDiff(diff) 1539 1540 expected := map[string]string{ 1541 "foo": "baz", 1542 } 1543 1544 if !reflect.DeepEqual(expected, is2.Attributes) { 1545 t.Fatalf("bad: %#v", is2.Attributes) 1546 } 1547 } 1548 1549 func TestInstanceState_MergeDiff_nilDiff(t *testing.T) { 1550 is := InstanceState{ 1551 ID: "foo", 1552 Attributes: map[string]string{ 1553 "foo": "bar", 1554 }, 1555 } 1556 1557 is2 := is.MergeDiff(nil) 1558 1559 expected := map[string]string{ 1560 "foo": "bar", 1561 } 1562 1563 if !reflect.DeepEqual(expected, is2.Attributes) { 1564 t.Fatalf("bad: %#v", is2.Attributes) 1565 } 1566 } 1567 1568 func TestReadWriteState(t *testing.T) { 1569 state := &State{ 1570 Serial: 9, 1571 Lineage: "5d1ad1a1-4027-4665-a908-dbe6adff11d8", 1572 Remote: &RemoteState{ 1573 Type: "http", 1574 Config: map[string]string{ 1575 "url": "http://my-cool-server.com/", 1576 }, 1577 }, 1578 Modules: []*ModuleState{ 1579 &ModuleState{ 1580 Path: rootModulePath, 1581 Dependencies: []string{ 1582 "aws_instance.bar", 1583 }, 1584 Resources: map[string]*ResourceState{ 1585 "foo": &ResourceState{ 1586 Primary: &InstanceState{ 1587 ID: "bar", 1588 Ephemeral: EphemeralState{ 1589 ConnInfo: map[string]string{ 1590 "type": "ssh", 1591 "user": "root", 1592 "password": "supersecret", 1593 }, 1594 }, 1595 }, 1596 }, 1597 }, 1598 }, 1599 }, 1600 } 1601 state.init() 1602 1603 buf := new(bytes.Buffer) 1604 if err := WriteState(state, buf); err != nil { 1605 t.Fatalf("err: %s", err) 1606 } 1607 1608 // Verify that the version and serial are set 1609 if state.Version != StateVersion { 1610 t.Fatalf("bad version number: %d", state.Version) 1611 } 1612 1613 actual, err := ReadState(buf) 1614 if err != nil { 1615 t.Fatalf("err: %s", err) 1616 } 1617 1618 // ReadState should not restore sensitive information! 1619 mod := state.RootModule() 1620 mod.Resources["foo"].Primary.Ephemeral = EphemeralState{} 1621 mod.Resources["foo"].Primary.Ephemeral.init() 1622 1623 if !reflect.DeepEqual(actual, state) { 1624 t.Logf("expected:\n%#v", state) 1625 t.Fatalf("got:\n%#v", actual) 1626 } 1627 } 1628 1629 func TestReadStateNewVersion(t *testing.T) { 1630 type out struct { 1631 Version int 1632 } 1633 1634 buf, err := json.Marshal(&out{StateVersion + 1}) 1635 if err != nil { 1636 t.Fatalf("err: %v", err) 1637 } 1638 1639 s, err := ReadState(bytes.NewReader(buf)) 1640 if s != nil { 1641 t.Fatalf("unexpected: %#v", s) 1642 } 1643 if !strings.Contains(err.Error(), "does not support state version") { 1644 t.Fatalf("err: %v", err) 1645 } 1646 } 1647 1648 func TestReadStateEmptyOrNilFile(t *testing.T) { 1649 var emptyState bytes.Buffer 1650 _, err := ReadState(&emptyState) 1651 if err != ErrNoState { 1652 t.Fatal("expected ErrNostate, got", err) 1653 } 1654 1655 var nilFile *os.File 1656 _, err = ReadState(nilFile) 1657 if err != ErrNoState { 1658 t.Fatal("expected ErrNostate, got", err) 1659 } 1660 } 1661 1662 func TestReadStateTFVersion(t *testing.T) { 1663 type tfVersion struct { 1664 Version int `json:"version"` 1665 TFVersion string `json:"terraform_version"` 1666 } 1667 1668 cases := []struct { 1669 Written string 1670 Read string 1671 Err bool 1672 }{ 1673 { 1674 "0.0.0", 1675 "0.0.0", 1676 false, 1677 }, 1678 { 1679 "", 1680 "", 1681 false, 1682 }, 1683 { 1684 "bad", 1685 "", 1686 true, 1687 }, 1688 } 1689 1690 for _, tc := range cases { 1691 buf, err := json.Marshal(&tfVersion{ 1692 Version: 2, 1693 TFVersion: tc.Written, 1694 }) 1695 if err != nil { 1696 t.Fatalf("err: %v", err) 1697 } 1698 1699 s, err := ReadState(bytes.NewReader(buf)) 1700 if (err != nil) != tc.Err { 1701 t.Fatalf("%s: err: %s", tc.Written, err) 1702 } 1703 if err != nil { 1704 continue 1705 } 1706 1707 if s.TFVersion != tc.Read { 1708 t.Fatalf("%s: bad: %s", tc.Written, s.TFVersion) 1709 } 1710 } 1711 } 1712 1713 func TestWriteStateTFVersion(t *testing.T) { 1714 cases := []struct { 1715 Write string 1716 Read string 1717 Err bool 1718 }{ 1719 { 1720 "0.0.0", 1721 "0.0.0", 1722 false, 1723 }, 1724 { 1725 "", 1726 "", 1727 false, 1728 }, 1729 { 1730 "bad", 1731 "", 1732 true, 1733 }, 1734 } 1735 1736 for _, tc := range cases { 1737 var buf bytes.Buffer 1738 err := WriteState(&State{TFVersion: tc.Write}, &buf) 1739 if (err != nil) != tc.Err { 1740 t.Fatalf("%s: err: %s", tc.Write, err) 1741 } 1742 if err != nil { 1743 continue 1744 } 1745 1746 s, err := ReadState(&buf) 1747 if err != nil { 1748 t.Fatalf("%s: err: %s", tc.Write, err) 1749 } 1750 1751 if s.TFVersion != tc.Read { 1752 t.Fatalf("%s: bad: %s", tc.Write, s.TFVersion) 1753 } 1754 } 1755 } 1756 1757 func TestParseResourceStateKey(t *testing.T) { 1758 cases := []struct { 1759 Input string 1760 Expected *ResourceStateKey 1761 ExpectedErr bool 1762 }{ 1763 { 1764 Input: "aws_instance.foo.3", 1765 Expected: &ResourceStateKey{ 1766 Mode: config.ManagedResourceMode, 1767 Type: "aws_instance", 1768 Name: "foo", 1769 Index: 3, 1770 }, 1771 }, 1772 { 1773 Input: "aws_instance.foo.0", 1774 Expected: &ResourceStateKey{ 1775 Mode: config.ManagedResourceMode, 1776 Type: "aws_instance", 1777 Name: "foo", 1778 Index: 0, 1779 }, 1780 }, 1781 { 1782 Input: "aws_instance.foo", 1783 Expected: &ResourceStateKey{ 1784 Mode: config.ManagedResourceMode, 1785 Type: "aws_instance", 1786 Name: "foo", 1787 Index: -1, 1788 }, 1789 }, 1790 { 1791 Input: "data.aws_ami.foo", 1792 Expected: &ResourceStateKey{ 1793 Mode: config.DataResourceMode, 1794 Type: "aws_ami", 1795 Name: "foo", 1796 Index: -1, 1797 }, 1798 }, 1799 { 1800 Input: "aws_instance.foo.malformed", 1801 ExpectedErr: true, 1802 }, 1803 { 1804 Input: "aws_instance.foo.malformedwithnumber.123", 1805 ExpectedErr: true, 1806 }, 1807 { 1808 Input: "malformed", 1809 ExpectedErr: true, 1810 }, 1811 } 1812 for _, tc := range cases { 1813 rsk, err := ParseResourceStateKey(tc.Input) 1814 if rsk != nil && tc.Expected != nil && !rsk.Equal(tc.Expected) { 1815 t.Fatalf("%s: expected %s, got %s", tc.Input, tc.Expected, rsk) 1816 } 1817 if (err != nil) != tc.ExpectedErr { 1818 t.Fatalf("%s: expected err: %t, got %s", tc.Input, tc.ExpectedErr, err) 1819 } 1820 } 1821 } 1822 1823 func TestStateModuleOrphans_empty(t *testing.T) { 1824 state := &State{ 1825 Modules: []*ModuleState{ 1826 &ModuleState{ 1827 Path: RootModulePath, 1828 }, 1829 &ModuleState{ 1830 Path: []string{RootModuleName, "foo", "bar"}, 1831 }, 1832 &ModuleState{ 1833 Path: []string{}, 1834 }, 1835 nil, 1836 }, 1837 } 1838 1839 state.init() 1840 1841 // just calling this to check for panic 1842 state.ModuleOrphans(RootModulePath, nil) 1843 } 1844 1845 func TestReadState_prune(t *testing.T) { 1846 state := &State{ 1847 Modules: []*ModuleState{ 1848 &ModuleState{Path: rootModulePath}, 1849 nil, 1850 }, 1851 } 1852 state.init() 1853 1854 buf := new(bytes.Buffer) 1855 if err := WriteState(state, buf); err != nil { 1856 t.Fatalf("err: %s", err) 1857 } 1858 1859 actual, err := ReadState(buf) 1860 if err != nil { 1861 t.Fatalf("err: %s", err) 1862 } 1863 1864 expected := &State{ 1865 Version: state.Version, 1866 Lineage: state.Lineage, 1867 } 1868 expected.init() 1869 1870 if !reflect.DeepEqual(actual, expected) { 1871 t.Fatalf("got:\n%#v", actual) 1872 } 1873 } 1874 1875 func TestReadState_pruneDependencies(t *testing.T) { 1876 state := &State{ 1877 Serial: 9, 1878 Lineage: "5d1ad1a1-4027-4665-a908-dbe6adff11d8", 1879 Remote: &RemoteState{ 1880 Type: "http", 1881 Config: map[string]string{ 1882 "url": "http://my-cool-server.com/", 1883 }, 1884 }, 1885 Modules: []*ModuleState{ 1886 &ModuleState{ 1887 Path: rootModulePath, 1888 Dependencies: []string{ 1889 "aws_instance.bar", 1890 "aws_instance.bar", 1891 }, 1892 Resources: map[string]*ResourceState{ 1893 "foo": &ResourceState{ 1894 Dependencies: []string{ 1895 "aws_instance.baz", 1896 "aws_instance.baz", 1897 }, 1898 Primary: &InstanceState{ 1899 ID: "bar", 1900 }, 1901 }, 1902 }, 1903 }, 1904 }, 1905 } 1906 state.init() 1907 1908 buf := new(bytes.Buffer) 1909 if err := WriteState(state, buf); err != nil { 1910 t.Fatalf("err: %s", err) 1911 } 1912 1913 actual, err := ReadState(buf) 1914 if err != nil { 1915 t.Fatalf("err: %s", err) 1916 } 1917 1918 // make sure the duplicate Dependencies are filtered 1919 modDeps := actual.Modules[0].Dependencies 1920 resourceDeps := actual.Modules[0].Resources["foo"].Dependencies 1921 1922 if len(modDeps) > 1 || modDeps[0] != "aws_instance.bar" { 1923 t.Fatalf("expected 1 module depends_on entry, got %q", modDeps) 1924 } 1925 1926 if len(resourceDeps) > 1 || resourceDeps[0] != "aws_instance.baz" { 1927 t.Fatalf("expected 1 resource depends_on entry, got %q", resourceDeps) 1928 } 1929 } 1930 1931 func TestResourceNameSort(t *testing.T) { 1932 names := []string{ 1933 "a", 1934 "b", 1935 "a.0", 1936 "a.c", 1937 "a.d", 1938 "c", 1939 "a.b.0", 1940 "a.b.1", 1941 "a.b.10", 1942 "a.b.2", 1943 } 1944 1945 sort.Sort(resourceNameSort(names)) 1946 1947 expected := []string{ 1948 "a", 1949 "a.0", 1950 "a.b.0", 1951 "a.b.1", 1952 "a.b.2", 1953 "a.b.10", 1954 "a.c", 1955 "a.d", 1956 "b", 1957 "c", 1958 } 1959 1960 if !reflect.DeepEqual(names, expected) { 1961 t.Fatalf("got: %q\nexpected: %q\n", names, expected) 1962 } 1963 }