github.com/sarguru/terraform@v0.6.17-0.20160525232901-8fcdfd7e3dc9/terraform/state_test.go (about)

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