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