github.com/pbthorste/terraform@v0.8.6-0.20170127005045-deb56bd93da2/terraform/state_test.go (about)

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