github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/terraform/context_refresh_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"reflect"
     5  	"sort"
     6  	"strings"
     7  	"sync"
     8  	"testing"
     9  )
    10  
    11  func TestContext2Refresh(t *testing.T) {
    12  	p := testProvider("aws")
    13  	m := testModule(t, "refresh-basic")
    14  	ctx := testContext2(t, &ContextOpts{
    15  		Module: m,
    16  		Providers: map[string]ResourceProviderFactory{
    17  			"aws": testProviderFuncFixed(p),
    18  		},
    19  		State: &State{
    20  			Modules: []*ModuleState{
    21  				&ModuleState{
    22  					Path: rootModulePath,
    23  					Resources: map[string]*ResourceState{
    24  						"aws_instance.web": &ResourceState{
    25  							Type: "aws_instance",
    26  							Primary: &InstanceState{
    27  								ID: "foo",
    28  							},
    29  						},
    30  					},
    31  				},
    32  			},
    33  		},
    34  	})
    35  
    36  	p.RefreshFn = nil
    37  	p.RefreshReturn = &InstanceState{
    38  		ID: "foo",
    39  	}
    40  
    41  	s, err := ctx.Refresh()
    42  	mod := s.RootModule()
    43  	if err != nil {
    44  		t.Fatalf("err: %s", err)
    45  	}
    46  	if !p.RefreshCalled {
    47  		t.Fatal("refresh should be called")
    48  	}
    49  	if p.RefreshState.ID != "foo" {
    50  		t.Fatalf("bad: %#v", p.RefreshState)
    51  	}
    52  	if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
    53  		t.Fatalf("bad: %#v %#v", mod.Resources["aws_instance.web"], p.RefreshReturn)
    54  	}
    55  
    56  	for _, r := range mod.Resources {
    57  		if r.Type == "" {
    58  			t.Fatalf("no type: %#v", r)
    59  		}
    60  	}
    61  }
    62  
    63  func TestContext2Refresh_targeted(t *testing.T) {
    64  	p := testProvider("aws")
    65  	m := testModule(t, "refresh-targeted")
    66  	ctx := testContext2(t, &ContextOpts{
    67  		Module: m,
    68  		Providers: map[string]ResourceProviderFactory{
    69  			"aws": testProviderFuncFixed(p),
    70  		},
    71  		State: &State{
    72  			Modules: []*ModuleState{
    73  				&ModuleState{
    74  					Path: rootModulePath,
    75  					Resources: map[string]*ResourceState{
    76  						"aws_vpc.metoo":      resourceState("aws_vpc", "vpc-abc123"),
    77  						"aws_instance.notme": resourceState("aws_instance", "i-bcd345"),
    78  						"aws_instance.me":    resourceState("aws_instance", "i-abc123"),
    79  						"aws_elb.meneither":  resourceState("aws_elb", "lb-abc123"),
    80  					},
    81  				},
    82  			},
    83  		},
    84  		Targets: []string{"aws_instance.me"},
    85  	})
    86  
    87  	refreshedResources := make([]string, 0, 2)
    88  	p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
    89  		refreshedResources = append(refreshedResources, i.Id)
    90  		return is, nil
    91  	}
    92  
    93  	_, err := ctx.Refresh()
    94  	if err != nil {
    95  		t.Fatalf("err: %s", err)
    96  	}
    97  
    98  	expected := []string{"aws_vpc.metoo", "aws_instance.me"}
    99  	if !reflect.DeepEqual(refreshedResources, expected) {
   100  		t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
   101  	}
   102  }
   103  
   104  func TestContext2Refresh_targetedCount(t *testing.T) {
   105  	p := testProvider("aws")
   106  	m := testModule(t, "refresh-targeted-count")
   107  	ctx := testContext2(t, &ContextOpts{
   108  		Module: m,
   109  		Providers: map[string]ResourceProviderFactory{
   110  			"aws": testProviderFuncFixed(p),
   111  		},
   112  		State: &State{
   113  			Modules: []*ModuleState{
   114  				&ModuleState{
   115  					Path: rootModulePath,
   116  					Resources: map[string]*ResourceState{
   117  						"aws_vpc.metoo":      resourceState("aws_vpc", "vpc-abc123"),
   118  						"aws_instance.notme": resourceState("aws_instance", "i-bcd345"),
   119  						"aws_instance.me.0":  resourceState("aws_instance", "i-abc123"),
   120  						"aws_instance.me.1":  resourceState("aws_instance", "i-cde567"),
   121  						"aws_instance.me.2":  resourceState("aws_instance", "i-cde789"),
   122  						"aws_elb.meneither":  resourceState("aws_elb", "lb-abc123"),
   123  					},
   124  				},
   125  			},
   126  		},
   127  		Targets: []string{"aws_instance.me"},
   128  	})
   129  
   130  	refreshedResources := make([]string, 0, 2)
   131  	p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
   132  		refreshedResources = append(refreshedResources, i.Id)
   133  		return is, nil
   134  	}
   135  
   136  	_, err := ctx.Refresh()
   137  	if err != nil {
   138  		t.Fatalf("err: %s", err)
   139  	}
   140  
   141  	// Target didn't specify index, so we should get all our instances
   142  	expected := []string{
   143  		"aws_vpc.metoo",
   144  		"aws_instance.me.0",
   145  		"aws_instance.me.1",
   146  		"aws_instance.me.2",
   147  	}
   148  	sort.Strings(expected)
   149  	sort.Strings(refreshedResources)
   150  	if !reflect.DeepEqual(refreshedResources, expected) {
   151  		t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
   152  	}
   153  }
   154  
   155  func TestContext2Refresh_targetedCountIndex(t *testing.T) {
   156  	p := testProvider("aws")
   157  	m := testModule(t, "refresh-targeted-count")
   158  	ctx := testContext2(t, &ContextOpts{
   159  		Module: m,
   160  		Providers: map[string]ResourceProviderFactory{
   161  			"aws": testProviderFuncFixed(p),
   162  		},
   163  		State: &State{
   164  			Modules: []*ModuleState{
   165  				&ModuleState{
   166  					Path: rootModulePath,
   167  					Resources: map[string]*ResourceState{
   168  						"aws_vpc.metoo":      resourceState("aws_vpc", "vpc-abc123"),
   169  						"aws_instance.notme": resourceState("aws_instance", "i-bcd345"),
   170  						"aws_instance.me.0":  resourceState("aws_instance", "i-abc123"),
   171  						"aws_instance.me.1":  resourceState("aws_instance", "i-cde567"),
   172  						"aws_instance.me.2":  resourceState("aws_instance", "i-cde789"),
   173  						"aws_elb.meneither":  resourceState("aws_elb", "lb-abc123"),
   174  					},
   175  				},
   176  			},
   177  		},
   178  		Targets: []string{"aws_instance.me[0]"},
   179  	})
   180  
   181  	refreshedResources := make([]string, 0, 2)
   182  	p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
   183  		refreshedResources = append(refreshedResources, i.Id)
   184  		return is, nil
   185  	}
   186  
   187  	_, err := ctx.Refresh()
   188  	if err != nil {
   189  		t.Fatalf("err: %s", err)
   190  	}
   191  
   192  	expected := []string{"aws_vpc.metoo", "aws_instance.me.0"}
   193  	if !reflect.DeepEqual(refreshedResources, expected) {
   194  		t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
   195  	}
   196  }
   197  
   198  func TestContext2Refresh_moduleComputedVar(t *testing.T) {
   199  	p := testProvider("aws")
   200  	m := testModule(t, "refresh-module-computed-var")
   201  	ctx := testContext2(t, &ContextOpts{
   202  		Module: m,
   203  		Providers: map[string]ResourceProviderFactory{
   204  			"aws": testProviderFuncFixed(p),
   205  		},
   206  	})
   207  
   208  	// This was failing (see GH-2188) at some point, so this test just
   209  	// verifies that the failure goes away.
   210  	if _, err := ctx.Refresh(); err != nil {
   211  		t.Fatalf("err: %s", err)
   212  	}
   213  }
   214  
   215  func TestContext2Refresh_delete(t *testing.T) {
   216  	p := testProvider("aws")
   217  	m := testModule(t, "refresh-basic")
   218  	ctx := testContext2(t, &ContextOpts{
   219  		Module: m,
   220  		Providers: map[string]ResourceProviderFactory{
   221  			"aws": testProviderFuncFixed(p),
   222  		},
   223  		State: &State{
   224  			Modules: []*ModuleState{
   225  				&ModuleState{
   226  					Path: rootModulePath,
   227  					Resources: map[string]*ResourceState{
   228  						"aws_instance.web": &ResourceState{
   229  							Type: "aws_instance",
   230  							Primary: &InstanceState{
   231  								ID: "foo",
   232  							},
   233  						},
   234  					},
   235  				},
   236  			},
   237  		},
   238  	})
   239  
   240  	p.RefreshFn = nil
   241  	p.RefreshReturn = nil
   242  
   243  	s, err := ctx.Refresh()
   244  	if err != nil {
   245  		t.Fatalf("err: %s", err)
   246  	}
   247  
   248  	mod := s.RootModule()
   249  	if len(mod.Resources) > 0 {
   250  		t.Fatal("resources should be empty")
   251  	}
   252  }
   253  
   254  func TestContext2Refresh_ignoreUncreated(t *testing.T) {
   255  	p := testProvider("aws")
   256  	m := testModule(t, "refresh-basic")
   257  	ctx := testContext2(t, &ContextOpts{
   258  		Module: m,
   259  		Providers: map[string]ResourceProviderFactory{
   260  			"aws": testProviderFuncFixed(p),
   261  		},
   262  		State: nil,
   263  	})
   264  
   265  	p.RefreshFn = nil
   266  	p.RefreshReturn = &InstanceState{
   267  		ID: "foo",
   268  	}
   269  
   270  	_, err := ctx.Refresh()
   271  	if err != nil {
   272  		t.Fatalf("err: %s", err)
   273  	}
   274  	if p.RefreshCalled {
   275  		t.Fatal("refresh should not be called")
   276  	}
   277  }
   278  
   279  func TestContext2Refresh_hook(t *testing.T) {
   280  	h := new(MockHook)
   281  	p := testProvider("aws")
   282  	m := testModule(t, "refresh-basic")
   283  	ctx := testContext2(t, &ContextOpts{
   284  		Module: m,
   285  		Hooks:  []Hook{h},
   286  		Providers: map[string]ResourceProviderFactory{
   287  			"aws": testProviderFuncFixed(p),
   288  		},
   289  		State: &State{
   290  			Modules: []*ModuleState{
   291  				&ModuleState{
   292  					Path: rootModulePath,
   293  					Resources: map[string]*ResourceState{
   294  						"aws_instance.web": &ResourceState{
   295  							Type: "aws_instance",
   296  							Primary: &InstanceState{
   297  								ID: "foo",
   298  							},
   299  						},
   300  					},
   301  				},
   302  			},
   303  		},
   304  	})
   305  
   306  	if _, err := ctx.Refresh(); err != nil {
   307  		t.Fatalf("err: %s", err)
   308  	}
   309  	if !h.PreRefreshCalled {
   310  		t.Fatal("should be called")
   311  	}
   312  	if !h.PostRefreshCalled {
   313  		t.Fatal("should be called")
   314  	}
   315  }
   316  
   317  func TestContext2Refresh_modules(t *testing.T) {
   318  	p := testProvider("aws")
   319  	m := testModule(t, "refresh-modules")
   320  	state := &State{
   321  		Modules: []*ModuleState{
   322  			&ModuleState{
   323  				Path: rootModulePath,
   324  				Resources: map[string]*ResourceState{
   325  					"aws_instance.web": &ResourceState{
   326  						Type: "aws_instance",
   327  						Tainted: []*InstanceState{
   328  							&InstanceState{
   329  								ID: "bar",
   330  							},
   331  						},
   332  					},
   333  				},
   334  			},
   335  
   336  			&ModuleState{
   337  				Path: []string{"root", "child"},
   338  				Resources: map[string]*ResourceState{
   339  					"aws_instance.web": &ResourceState{
   340  						Type: "aws_instance",
   341  						Primary: &InstanceState{
   342  							ID: "baz",
   343  						},
   344  					},
   345  				},
   346  			},
   347  		},
   348  	}
   349  	ctx := testContext2(t, &ContextOpts{
   350  		Module: m,
   351  		Providers: map[string]ResourceProviderFactory{
   352  			"aws": testProviderFuncFixed(p),
   353  		},
   354  		State: state,
   355  	})
   356  
   357  	p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
   358  		if s.ID != "baz" {
   359  			return s, nil
   360  		}
   361  
   362  		s.ID = "new"
   363  		return s, nil
   364  	}
   365  
   366  	s, err := ctx.Refresh()
   367  	if err != nil {
   368  		t.Fatalf("err: %s", err)
   369  	}
   370  
   371  	actual := strings.TrimSpace(s.String())
   372  	expected := strings.TrimSpace(testContextRefreshModuleStr)
   373  	if actual != expected {
   374  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   375  	}
   376  }
   377  
   378  func TestContext2Refresh_moduleInputComputedOutput(t *testing.T) {
   379  	m := testModule(t, "refresh-module-input-computed-output")
   380  	p := testProvider("aws")
   381  	p.DiffFn = testDiffFn
   382  	ctx := testContext2(t, &ContextOpts{
   383  		Module: m,
   384  		Providers: map[string]ResourceProviderFactory{
   385  			"aws": testProviderFuncFixed(p),
   386  		},
   387  	})
   388  
   389  	if _, err := ctx.Refresh(); err != nil {
   390  		t.Fatalf("err: %s", err)
   391  	}
   392  }
   393  
   394  func TestContext2Refresh_moduleVarModule(t *testing.T) {
   395  	m := testModule(t, "refresh-module-var-module")
   396  	p := testProvider("aws")
   397  	p.DiffFn = testDiffFn
   398  	ctx := testContext2(t, &ContextOpts{
   399  		Module: m,
   400  		Providers: map[string]ResourceProviderFactory{
   401  			"aws": testProviderFuncFixed(p),
   402  		},
   403  	})
   404  
   405  	if _, err := ctx.Refresh(); err != nil {
   406  		t.Fatalf("err: %s", err)
   407  	}
   408  }
   409  
   410  // GH-70
   411  func TestContext2Refresh_noState(t *testing.T) {
   412  	p := testProvider("aws")
   413  	m := testModule(t, "refresh-no-state")
   414  	ctx := testContext2(t, &ContextOpts{
   415  		Module: m,
   416  		Providers: map[string]ResourceProviderFactory{
   417  			"aws": testProviderFuncFixed(p),
   418  		},
   419  	})
   420  
   421  	p.RefreshFn = nil
   422  	p.RefreshReturn = &InstanceState{
   423  		ID: "foo",
   424  	}
   425  
   426  	if _, err := ctx.Refresh(); err != nil {
   427  		t.Fatalf("err: %s", err)
   428  	}
   429  }
   430  
   431  func TestContext2Refresh_output(t *testing.T) {
   432  	p := testProvider("aws")
   433  	m := testModule(t, "refresh-output")
   434  	ctx := testContext2(t, &ContextOpts{
   435  		Module: m,
   436  		Providers: map[string]ResourceProviderFactory{
   437  			"aws": testProviderFuncFixed(p),
   438  		},
   439  		State: &State{
   440  			Modules: []*ModuleState{
   441  				&ModuleState{
   442  					Path: rootModulePath,
   443  					Resources: map[string]*ResourceState{
   444  						"aws_instance.web": &ResourceState{
   445  							Type: "aws_instance",
   446  							Primary: &InstanceState{
   447  								ID: "foo",
   448  								Attributes: map[string]string{
   449  									"foo": "bar",
   450  								},
   451  							},
   452  						},
   453  					},
   454  
   455  					Outputs: map[string]string{
   456  						"foo": "foo",
   457  					},
   458  				},
   459  			},
   460  		},
   461  	})
   462  
   463  	p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
   464  		return s, nil
   465  	}
   466  
   467  	s, err := ctx.Refresh()
   468  	if err != nil {
   469  		t.Fatalf("err: %s", err)
   470  	}
   471  
   472  	actual := strings.TrimSpace(s.String())
   473  	expected := strings.TrimSpace(testContextRefreshOutputStr)
   474  	if actual != expected {
   475  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   476  	}
   477  }
   478  
   479  func TestContext2Refresh_outputPartial(t *testing.T) {
   480  	p := testProvider("aws")
   481  	m := testModule(t, "refresh-output-partial")
   482  	ctx := testContext2(t, &ContextOpts{
   483  		Module: m,
   484  		Providers: map[string]ResourceProviderFactory{
   485  			"aws": testProviderFuncFixed(p),
   486  		},
   487  		State: &State{
   488  			Modules: []*ModuleState{
   489  				&ModuleState{
   490  					Path: rootModulePath,
   491  					Resources: map[string]*ResourceState{
   492  						"aws_instance.foo": &ResourceState{
   493  							Type: "aws_instance",
   494  							Primary: &InstanceState{
   495  								ID: "foo",
   496  							},
   497  						},
   498  					},
   499  				},
   500  			},
   501  		},
   502  	})
   503  
   504  	p.RefreshFn = nil
   505  	p.RefreshReturn = nil
   506  
   507  	s, err := ctx.Refresh()
   508  	if err != nil {
   509  		t.Fatalf("err: %s", err)
   510  	}
   511  
   512  	actual := strings.TrimSpace(s.String())
   513  	expected := strings.TrimSpace(testContextRefreshOutputPartialStr)
   514  	if actual != expected {
   515  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   516  	}
   517  }
   518  
   519  func TestContext2Refresh_state(t *testing.T) {
   520  	p := testProvider("aws")
   521  	m := testModule(t, "refresh-basic")
   522  	state := &State{
   523  		Modules: []*ModuleState{
   524  			&ModuleState{
   525  				Path: rootModulePath,
   526  				Resources: map[string]*ResourceState{
   527  					"aws_instance.web": &ResourceState{
   528  						Primary: &InstanceState{
   529  							ID: "bar",
   530  						},
   531  					},
   532  				},
   533  			},
   534  		},
   535  	}
   536  	ctx := testContext2(t, &ContextOpts{
   537  		Module: m,
   538  		Providers: map[string]ResourceProviderFactory{
   539  			"aws": testProviderFuncFixed(p),
   540  		},
   541  		State: state,
   542  	})
   543  
   544  	p.RefreshFn = nil
   545  	p.RefreshReturn = &InstanceState{
   546  		ID: "foo",
   547  	}
   548  
   549  	s, err := ctx.Refresh()
   550  	if err != nil {
   551  		t.Fatalf("err: %s", err)
   552  	}
   553  	originalMod := state.RootModule()
   554  	mod := s.RootModule()
   555  	if !p.RefreshCalled {
   556  		t.Fatal("refresh should be called")
   557  	}
   558  	if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Primary) {
   559  		t.Fatalf(
   560  			"bad:\n\n%#v\n\n%#v",
   561  			p.RefreshState,
   562  			originalMod.Resources["aws_instance.web"].Primary)
   563  	}
   564  	if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
   565  		t.Fatalf("bad: %#v", mod.Resources)
   566  	}
   567  }
   568  
   569  func TestContext2Refresh_tainted(t *testing.T) {
   570  	p := testProvider("aws")
   571  	m := testModule(t, "refresh-basic")
   572  	state := &State{
   573  		Modules: []*ModuleState{
   574  			&ModuleState{
   575  				Path: rootModulePath,
   576  				Resources: map[string]*ResourceState{
   577  					"aws_instance.web": &ResourceState{
   578  						Type: "aws_instance",
   579  						Tainted: []*InstanceState{
   580  							&InstanceState{
   581  								ID: "bar",
   582  							},
   583  						},
   584  					},
   585  				},
   586  			},
   587  		},
   588  	}
   589  	ctx := testContext2(t, &ContextOpts{
   590  		Module: m,
   591  		Providers: map[string]ResourceProviderFactory{
   592  			"aws": testProviderFuncFixed(p),
   593  		},
   594  		State: state,
   595  	})
   596  
   597  	p.RefreshFn = nil
   598  	p.RefreshReturn = &InstanceState{
   599  		ID: "foo",
   600  	}
   601  
   602  	s, err := ctx.Refresh()
   603  	if err != nil {
   604  		t.Fatalf("err: %s", err)
   605  	}
   606  	if !p.RefreshCalled {
   607  		t.Fatal("refresh should be called")
   608  	}
   609  
   610  	actual := strings.TrimSpace(s.String())
   611  	expected := strings.TrimSpace(testContextRefreshTaintedStr)
   612  	if actual != expected {
   613  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   614  	}
   615  }
   616  
   617  // Doing a Refresh (or any operation really, but Refresh usually
   618  // happens first) with a config with an unknown provider should result in
   619  // an error. The key bug this found was that this wasn't happening if
   620  // Providers was _empty_.
   621  func TestContext2Refresh_unknownProvider(t *testing.T) {
   622  	m := testModule(t, "refresh-unknown-provider")
   623  	p := testProvider("aws")
   624  	p.ApplyFn = testApplyFn
   625  	p.DiffFn = testDiffFn
   626  	ctx := testContext2(t, &ContextOpts{
   627  		Module:    m,
   628  		Providers: map[string]ResourceProviderFactory{},
   629  	})
   630  
   631  	if _, err := ctx.Refresh(); err == nil {
   632  		t.Fatal("should error")
   633  	}
   634  }
   635  
   636  func TestContext2Refresh_vars(t *testing.T) {
   637  	p := testProvider("aws")
   638  	m := testModule(t, "refresh-vars")
   639  	ctx := testContext2(t, &ContextOpts{
   640  		Module: m,
   641  		Providers: map[string]ResourceProviderFactory{
   642  			"aws": testProviderFuncFixed(p),
   643  		},
   644  		State: &State{
   645  
   646  			Modules: []*ModuleState{
   647  				&ModuleState{
   648  					Path: rootModulePath,
   649  					Resources: map[string]*ResourceState{
   650  						"aws_instance.web": &ResourceState{
   651  							Type: "aws_instance",
   652  							Primary: &InstanceState{
   653  								ID: "foo",
   654  							},
   655  						},
   656  					},
   657  				},
   658  			},
   659  		},
   660  	})
   661  
   662  	p.RefreshFn = nil
   663  	p.RefreshReturn = &InstanceState{
   664  		ID: "foo",
   665  	}
   666  
   667  	s, err := ctx.Refresh()
   668  	if err != nil {
   669  		t.Fatalf("err: %s", err)
   670  	}
   671  	mod := s.RootModule()
   672  	if !p.RefreshCalled {
   673  		t.Fatal("refresh should be called")
   674  	}
   675  	if p.RefreshState.ID != "foo" {
   676  		t.Fatalf("bad: %#v", p.RefreshState)
   677  	}
   678  	if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
   679  		t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"])
   680  	}
   681  
   682  	for _, r := range mod.Resources {
   683  		if r.Type == "" {
   684  			t.Fatalf("no type: %#v", r)
   685  		}
   686  	}
   687  }
   688  
   689  func TestContext2Refresh_orphanModule(t *testing.T) {
   690  	p := testProvider("aws")
   691  	m := testModule(t, "refresh-module-orphan")
   692  
   693  	// Create a custom refresh function to track the order they were visited
   694  	var order []string
   695  	var orderLock sync.Mutex
   696  	p.RefreshFn = func(
   697  		info *InstanceInfo,
   698  		is *InstanceState) (*InstanceState, error) {
   699  		orderLock.Lock()
   700  		defer orderLock.Unlock()
   701  
   702  		order = append(order, is.ID)
   703  		return is, nil
   704  	}
   705  
   706  	state := &State{
   707  		Modules: []*ModuleState{
   708  			&ModuleState{
   709  				Path: rootModulePath,
   710  				Resources: map[string]*ResourceState{
   711  					"aws_instance.foo": &ResourceState{
   712  						Primary: &InstanceState{
   713  							ID: "i-abc123",
   714  							Attributes: map[string]string{
   715  								"childid":      "i-bcd234",
   716  								"grandchildid": "i-cde345",
   717  							},
   718  						},
   719  						Dependencies: []string{
   720  							"module.child",
   721  							"module.child",
   722  						},
   723  					},
   724  				},
   725  			},
   726  			&ModuleState{
   727  				Path: append(rootModulePath, "child"),
   728  				Resources: map[string]*ResourceState{
   729  					"aws_instance.bar": &ResourceState{
   730  						Primary: &InstanceState{
   731  							ID: "i-bcd234",
   732  							Attributes: map[string]string{
   733  								"grandchildid": "i-cde345",
   734  							},
   735  						},
   736  						Dependencies: []string{
   737  							"module.grandchild",
   738  						},
   739  					},
   740  				},
   741  				Outputs: map[string]string{
   742  					"id":            "i-bcd234",
   743  					"grandchild_id": "i-cde345",
   744  				},
   745  			},
   746  			&ModuleState{
   747  				Path: append(rootModulePath, "child", "grandchild"),
   748  				Resources: map[string]*ResourceState{
   749  					"aws_instance.baz": &ResourceState{
   750  						Primary: &InstanceState{
   751  							ID: "i-cde345",
   752  						},
   753  					},
   754  				},
   755  				Outputs: map[string]string{
   756  					"id": "i-cde345",
   757  				},
   758  			},
   759  		},
   760  	}
   761  	ctx := testContext2(t, &ContextOpts{
   762  		Module: m,
   763  		Providers: map[string]ResourceProviderFactory{
   764  			"aws": testProviderFuncFixed(p),
   765  		},
   766  		State: state,
   767  	})
   768  
   769  	testCheckDeadlock(t, func() {
   770  		_, err := ctx.Refresh()
   771  		if err != nil {
   772  			t.Fatalf("err: %s", err)
   773  		}
   774  
   775  		// TODO: handle order properly for orphaned modules / resources
   776  		// expected := []string{"i-abc123", "i-bcd234", "i-cde345"}
   777  		// if !reflect.DeepEqual(order, expected) {
   778  		// 	t.Fatalf("expected: %#v, got: %#v", expected, order)
   779  		// }
   780  	})
   781  }
   782  
   783  func TestContext2Validate(t *testing.T) {
   784  	p := testProvider("aws")
   785  	m := testModule(t, "validate-good")
   786  	c := testContext2(t, &ContextOpts{
   787  		Module: m,
   788  		Providers: map[string]ResourceProviderFactory{
   789  			"aws": testProviderFuncFixed(p),
   790  		},
   791  	})
   792  
   793  	w, e := c.Validate()
   794  	if len(w) > 0 {
   795  		t.Fatalf("bad: %#v", w)
   796  	}
   797  	if len(e) > 0 {
   798  		t.Fatalf("bad: %s", e)
   799  	}
   800  }