github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/terraform/state_test.go (about)

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