github.com/ticketmaster/terraform@v0.10.0-beta2.0.20170711045249-a12daf5aba4f/terraform/state_test.go (about)

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