github.com/opentofu/opentofu@v1.7.1/internal/legacy/tofu/state_test.go (about)

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