github.com/ggriffiths/terraform@v0.9.0-beta1.0.20170222213024-79c4935604cb/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  						Primary: &InstanceState{
   328  							ID:      "bar",
   329  							Tainted: true,
   330  						},
   331  					},
   332  				},
   333  			},
   334  
   335  			&ModuleState{
   336  				Path: []string{"root", "child"},
   337  				Resources: map[string]*ResourceState{
   338  					"aws_instance.web": &ResourceState{
   339  						Type: "aws_instance",
   340  						Primary: &InstanceState{
   341  							ID: "baz",
   342  						},
   343  					},
   344  				},
   345  			},
   346  		},
   347  	}
   348  	ctx := testContext2(t, &ContextOpts{
   349  		Module: m,
   350  		Providers: map[string]ResourceProviderFactory{
   351  			"aws": testProviderFuncFixed(p),
   352  		},
   353  		State: state,
   354  	})
   355  
   356  	p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
   357  		if s.ID != "baz" {
   358  			return s, nil
   359  		}
   360  
   361  		s.ID = "new"
   362  		return s, nil
   363  	}
   364  
   365  	s, err := ctx.Refresh()
   366  	if err != nil {
   367  		t.Fatalf("err: %s", err)
   368  	}
   369  
   370  	actual := strings.TrimSpace(s.String())
   371  	expected := strings.TrimSpace(testContextRefreshModuleStr)
   372  	if actual != expected {
   373  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   374  	}
   375  }
   376  
   377  func TestContext2Refresh_moduleInputComputedOutput(t *testing.T) {
   378  	m := testModule(t, "refresh-module-input-computed-output")
   379  	p := testProvider("aws")
   380  	p.DiffFn = testDiffFn
   381  	ctx := testContext2(t, &ContextOpts{
   382  		Module: m,
   383  		Providers: map[string]ResourceProviderFactory{
   384  			"aws": testProviderFuncFixed(p),
   385  		},
   386  	})
   387  
   388  	if _, err := ctx.Refresh(); err != nil {
   389  		t.Fatalf("err: %s", err)
   390  	}
   391  }
   392  
   393  func TestContext2Refresh_moduleVarModule(t *testing.T) {
   394  	m := testModule(t, "refresh-module-var-module")
   395  	p := testProvider("aws")
   396  	p.DiffFn = testDiffFn
   397  	ctx := testContext2(t, &ContextOpts{
   398  		Module: m,
   399  		Providers: map[string]ResourceProviderFactory{
   400  			"aws": testProviderFuncFixed(p),
   401  		},
   402  	})
   403  
   404  	if _, err := ctx.Refresh(); err != nil {
   405  		t.Fatalf("err: %s", err)
   406  	}
   407  }
   408  
   409  // GH-70
   410  func TestContext2Refresh_noState(t *testing.T) {
   411  	p := testProvider("aws")
   412  	m := testModule(t, "refresh-no-state")
   413  	ctx := testContext2(t, &ContextOpts{
   414  		Module: m,
   415  		Providers: map[string]ResourceProviderFactory{
   416  			"aws": testProviderFuncFixed(p),
   417  		},
   418  	})
   419  
   420  	p.RefreshFn = nil
   421  	p.RefreshReturn = &InstanceState{
   422  		ID: "foo",
   423  	}
   424  
   425  	if _, err := ctx.Refresh(); err != nil {
   426  		t.Fatalf("err: %s", err)
   427  	}
   428  }
   429  
   430  func TestContext2Refresh_output(t *testing.T) {
   431  	p := testProvider("aws")
   432  	m := testModule(t, "refresh-output")
   433  	ctx := testContext2(t, &ContextOpts{
   434  		Module: m,
   435  		Providers: map[string]ResourceProviderFactory{
   436  			"aws": testProviderFuncFixed(p),
   437  		},
   438  		State: &State{
   439  			Modules: []*ModuleState{
   440  				&ModuleState{
   441  					Path: rootModulePath,
   442  					Resources: map[string]*ResourceState{
   443  						"aws_instance.web": &ResourceState{
   444  							Type: "aws_instance",
   445  							Primary: &InstanceState{
   446  								ID: "foo",
   447  								Attributes: map[string]string{
   448  									"foo": "bar",
   449  								},
   450  							},
   451  						},
   452  					},
   453  
   454  					Outputs: map[string]*OutputState{
   455  						"foo": &OutputState{
   456  							Type:      "string",
   457  							Sensitive: false,
   458  							Value:     "foo",
   459  						},
   460  					},
   461  				},
   462  			},
   463  		},
   464  	})
   465  
   466  	p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
   467  		return s, nil
   468  	}
   469  
   470  	s, err := ctx.Refresh()
   471  	if err != nil {
   472  		t.Fatalf("err: %s", err)
   473  	}
   474  
   475  	actual := strings.TrimSpace(s.String())
   476  	expected := strings.TrimSpace(testContextRefreshOutputStr)
   477  	if actual != expected {
   478  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   479  	}
   480  }
   481  
   482  func TestContext2Refresh_outputPartial(t *testing.T) {
   483  	p := testProvider("aws")
   484  	m := testModule(t, "refresh-output-partial")
   485  	ctx := testContext2(t, &ContextOpts{
   486  		Module: m,
   487  		Providers: map[string]ResourceProviderFactory{
   488  			"aws": testProviderFuncFixed(p),
   489  		},
   490  		State: &State{
   491  			Modules: []*ModuleState{
   492  				&ModuleState{
   493  					Path: rootModulePath,
   494  					Resources: map[string]*ResourceState{
   495  						"aws_instance.foo": &ResourceState{
   496  							Type: "aws_instance",
   497  							Primary: &InstanceState{
   498  								ID: "foo",
   499  							},
   500  						},
   501  					},
   502  					Outputs: map[string]*OutputState{},
   503  				},
   504  			},
   505  		},
   506  	})
   507  
   508  	p.RefreshFn = nil
   509  	p.RefreshReturn = nil
   510  
   511  	s, err := ctx.Refresh()
   512  	if err != nil {
   513  		t.Fatalf("err: %s", err)
   514  	}
   515  
   516  	actual := strings.TrimSpace(s.String())
   517  	expected := strings.TrimSpace(testContextRefreshOutputPartialStr)
   518  	if actual != expected {
   519  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   520  	}
   521  }
   522  
   523  func TestContext2Refresh_stateBasic(t *testing.T) {
   524  	p := testProvider("aws")
   525  	m := testModule(t, "refresh-basic")
   526  	state := &State{
   527  		Modules: []*ModuleState{
   528  			&ModuleState{
   529  				Path: rootModulePath,
   530  				Resources: map[string]*ResourceState{
   531  					"aws_instance.web": &ResourceState{
   532  						Type: "aws_instance",
   533  						Primary: &InstanceState{
   534  							ID: "bar",
   535  						},
   536  					},
   537  				},
   538  			},
   539  		},
   540  	}
   541  	ctx := testContext2(t, &ContextOpts{
   542  		Module: m,
   543  		Providers: map[string]ResourceProviderFactory{
   544  			"aws": testProviderFuncFixed(p),
   545  		},
   546  		State: state,
   547  	})
   548  
   549  	p.RefreshFn = nil
   550  	p.RefreshReturn = &InstanceState{
   551  		ID: "foo",
   552  	}
   553  
   554  	s, err := ctx.Refresh()
   555  	if err != nil {
   556  		t.Fatalf("err: %s", err)
   557  	}
   558  	originalMod := state.RootModule()
   559  	mod := s.RootModule()
   560  	if !p.RefreshCalled {
   561  		t.Fatal("refresh should be called")
   562  	}
   563  	if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Primary) {
   564  		t.Fatalf(
   565  			"bad:\n\n%#v\n\n%#v",
   566  			p.RefreshState,
   567  			originalMod.Resources["aws_instance.web"].Primary)
   568  	}
   569  	if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
   570  		t.Fatalf("bad: %#v", mod.Resources)
   571  	}
   572  }
   573  
   574  func TestContext2Refresh_dataOrphan(t *testing.T) {
   575  	p := testProvider("null")
   576  	state := &State{
   577  		Modules: []*ModuleState{
   578  			&ModuleState{
   579  				Path: rootModulePath,
   580  				Resources: map[string]*ResourceState{
   581  					"data.null_data_source.bar": &ResourceState{
   582  						Type: "foo",
   583  						Primary: &InstanceState{
   584  							ID: "foo",
   585  						},
   586  					},
   587  				},
   588  			},
   589  		},
   590  	}
   591  	ctx := testContext2(t, &ContextOpts{
   592  		Providers: map[string]ResourceProviderFactory{
   593  			"null": testProviderFuncFixed(p),
   594  		},
   595  		State: state,
   596  	})
   597  
   598  	s, err := ctx.Refresh()
   599  	if err != nil {
   600  		t.Fatalf("err: %s", err)
   601  	}
   602  
   603  	checkStateString(t, s, `<no state>`)
   604  }
   605  
   606  func TestContext2Refresh_dataState(t *testing.T) {
   607  	p := testProvider("null")
   608  	m := testModule(t, "refresh-data-resource-basic")
   609  	state := &State{
   610  		Modules: []*ModuleState{
   611  			&ModuleState{
   612  				Path: rootModulePath,
   613  				// Intentionally no resources since data resources are
   614  				// supposed to refresh themselves even if they didn't
   615  				// already exist.
   616  				Resources: map[string]*ResourceState{},
   617  			},
   618  		},
   619  	}
   620  	ctx := testContext2(t, &ContextOpts{
   621  		Module: m,
   622  		Providers: map[string]ResourceProviderFactory{
   623  			"null": testProviderFuncFixed(p),
   624  		},
   625  		State: state,
   626  	})
   627  
   628  	p.ReadDataDiffFn = nil
   629  	p.ReadDataDiffReturn = &InstanceDiff{
   630  		Attributes: map[string]*ResourceAttrDiff{
   631  			"inputs.#": {
   632  				Old:  "0",
   633  				New:  "1",
   634  				Type: DiffAttrInput,
   635  			},
   636  			"inputs.test": {
   637  				Old:  "",
   638  				New:  "yes",
   639  				Type: DiffAttrInput,
   640  			},
   641  			"outputs.#": {
   642  				Old:         "",
   643  				New:         "",
   644  				NewComputed: true,
   645  				Type:        DiffAttrOutput,
   646  			},
   647  		},
   648  	}
   649  
   650  	p.ReadDataApplyFn = nil
   651  	p.ReadDataApplyReturn = &InstanceState{
   652  		ID: "-",
   653  	}
   654  
   655  	s, err := ctx.Refresh()
   656  	if err != nil {
   657  		t.Fatalf("err: %s", err)
   658  	}
   659  
   660  	if !p.ReadDataDiffCalled {
   661  		t.Fatal("ReadDataDiff should have been called")
   662  	}
   663  	if !p.ReadDataApplyCalled {
   664  		t.Fatal("ReadDataApply should have been called")
   665  	}
   666  
   667  	mod := s.RootModule()
   668  	if got := mod.Resources["data.null_data_source.testing"].Primary.ID; got != "-" {
   669  		t.Fatalf("resource id is %q; want %s", got, "-")
   670  	}
   671  	if !reflect.DeepEqual(mod.Resources["data.null_data_source.testing"].Primary, p.ReadDataApplyReturn) {
   672  		t.Fatalf("bad: %#v", mod.Resources)
   673  	}
   674  }
   675  
   676  func TestContext2Refresh_dataStateRefData(t *testing.T) {
   677  	p := testProvider("null")
   678  	m := testModule(t, "refresh-data-ref-data")
   679  	state := &State{
   680  		Modules: []*ModuleState{
   681  			&ModuleState{
   682  				Path: rootModulePath,
   683  				// Intentionally no resources since data resources are
   684  				// supposed to refresh themselves even if they didn't
   685  				// already exist.
   686  				Resources: map[string]*ResourceState{},
   687  			},
   688  		},
   689  	}
   690  	ctx := testContext2(t, &ContextOpts{
   691  		Module: m,
   692  		Providers: map[string]ResourceProviderFactory{
   693  			"null": testProviderFuncFixed(p),
   694  		},
   695  		State: state,
   696  	})
   697  
   698  	p.ReadDataDiffFn = testDataDiffFn
   699  	p.ReadDataApplyFn = testDataApplyFn
   700  
   701  	s, err := ctx.Refresh()
   702  	if err != nil {
   703  		t.Fatalf("err: %s", err)
   704  	}
   705  
   706  	actual := strings.TrimSpace(s.String())
   707  	expected := strings.TrimSpace(testTerraformRefreshDataRefDataStr)
   708  	if actual != expected {
   709  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   710  	}
   711  }
   712  
   713  func TestContext2Refresh_tainted(t *testing.T) {
   714  	p := testProvider("aws")
   715  	m := testModule(t, "refresh-basic")
   716  	state := &State{
   717  		Modules: []*ModuleState{
   718  			&ModuleState{
   719  				Path: rootModulePath,
   720  				Resources: map[string]*ResourceState{
   721  					"aws_instance.web": &ResourceState{
   722  						Type: "aws_instance",
   723  						Primary: &InstanceState{
   724  							ID:      "bar",
   725  							Tainted: true,
   726  						},
   727  					},
   728  				},
   729  			},
   730  		},
   731  	}
   732  	ctx := testContext2(t, &ContextOpts{
   733  		Module: m,
   734  		Providers: map[string]ResourceProviderFactory{
   735  			"aws": testProviderFuncFixed(p),
   736  		},
   737  		State: state,
   738  	})
   739  
   740  	p.RefreshFn = nil
   741  	p.RefreshReturn = &InstanceState{
   742  		ID:      "foo",
   743  		Tainted: true,
   744  	}
   745  
   746  	s, err := ctx.Refresh()
   747  	if err != nil {
   748  		t.Fatalf("err: %s", err)
   749  	}
   750  	if !p.RefreshCalled {
   751  		t.Fatal("refresh should be called")
   752  	}
   753  
   754  	actual := strings.TrimSpace(s.String())
   755  	expected := strings.TrimSpace(testContextRefreshTaintedStr)
   756  	if actual != expected {
   757  		t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
   758  	}
   759  }
   760  
   761  // Doing a Refresh (or any operation really, but Refresh usually
   762  // happens first) with a config with an unknown provider should result in
   763  // an error. The key bug this found was that this wasn't happening if
   764  // Providers was _empty_.
   765  func TestContext2Refresh_unknownProvider(t *testing.T) {
   766  	m := testModule(t, "refresh-unknown-provider")
   767  	p := testProvider("aws")
   768  	p.ApplyFn = testApplyFn
   769  	p.DiffFn = testDiffFn
   770  	ctx := testContext2(t, &ContextOpts{
   771  		Module:    m,
   772  		Providers: map[string]ResourceProviderFactory{},
   773  		State: &State{
   774  			Modules: []*ModuleState{
   775  				&ModuleState{
   776  					Path: rootModulePath,
   777  					Resources: map[string]*ResourceState{
   778  						"aws_instance.web": &ResourceState{
   779  							Type: "aws_instance",
   780  							Primary: &InstanceState{
   781  								ID: "foo",
   782  							},
   783  						},
   784  					},
   785  				},
   786  			},
   787  		},
   788  	})
   789  
   790  	if _, err := ctx.Refresh(); err == nil {
   791  		t.Fatal("should error")
   792  	}
   793  }
   794  
   795  func TestContext2Refresh_vars(t *testing.T) {
   796  	p := testProvider("aws")
   797  	m := testModule(t, "refresh-vars")
   798  	ctx := testContext2(t, &ContextOpts{
   799  		Module: m,
   800  		Providers: map[string]ResourceProviderFactory{
   801  			"aws": testProviderFuncFixed(p),
   802  		},
   803  		State: &State{
   804  
   805  			Modules: []*ModuleState{
   806  				&ModuleState{
   807  					Path: rootModulePath,
   808  					Resources: map[string]*ResourceState{
   809  						"aws_instance.web": &ResourceState{
   810  							Type: "aws_instance",
   811  							Primary: &InstanceState{
   812  								ID: "foo",
   813  							},
   814  						},
   815  					},
   816  				},
   817  			},
   818  		},
   819  	})
   820  
   821  	p.RefreshFn = nil
   822  	p.RefreshReturn = &InstanceState{
   823  		ID: "foo",
   824  	}
   825  
   826  	s, err := ctx.Refresh()
   827  	if err != nil {
   828  		t.Fatalf("err: %s", err)
   829  	}
   830  	mod := s.RootModule()
   831  	if !p.RefreshCalled {
   832  		t.Fatal("refresh should be called")
   833  	}
   834  	if p.RefreshState.ID != "foo" {
   835  		t.Fatalf("bad: %#v", p.RefreshState)
   836  	}
   837  	if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
   838  		t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"])
   839  	}
   840  
   841  	for _, r := range mod.Resources {
   842  		if r.Type == "" {
   843  			t.Fatalf("no type: %#v", r)
   844  		}
   845  	}
   846  }
   847  
   848  func TestContext2Refresh_orphanModule(t *testing.T) {
   849  	p := testProvider("aws")
   850  	m := testModule(t, "refresh-module-orphan")
   851  
   852  	// Create a custom refresh function to track the order they were visited
   853  	var order []string
   854  	var orderLock sync.Mutex
   855  	p.RefreshFn = func(
   856  		info *InstanceInfo,
   857  		is *InstanceState) (*InstanceState, error) {
   858  		orderLock.Lock()
   859  		defer orderLock.Unlock()
   860  
   861  		order = append(order, is.ID)
   862  		return is, nil
   863  	}
   864  
   865  	state := &State{
   866  		Modules: []*ModuleState{
   867  			&ModuleState{
   868  				Path: rootModulePath,
   869  				Resources: map[string]*ResourceState{
   870  					"aws_instance.foo": &ResourceState{
   871  						Primary: &InstanceState{
   872  							ID: "i-abc123",
   873  							Attributes: map[string]string{
   874  								"childid":      "i-bcd234",
   875  								"grandchildid": "i-cde345",
   876  							},
   877  						},
   878  						Dependencies: []string{
   879  							"module.child",
   880  							"module.child",
   881  						},
   882  					},
   883  				},
   884  			},
   885  			&ModuleState{
   886  				Path: append(rootModulePath, "child"),
   887  				Resources: map[string]*ResourceState{
   888  					"aws_instance.bar": &ResourceState{
   889  						Primary: &InstanceState{
   890  							ID: "i-bcd234",
   891  							Attributes: map[string]string{
   892  								"grandchildid": "i-cde345",
   893  							},
   894  						},
   895  						Dependencies: []string{
   896  							"module.grandchild",
   897  						},
   898  					},
   899  				},
   900  				Outputs: map[string]*OutputState{
   901  					"id": &OutputState{
   902  						Value: "i-bcd234",
   903  						Type:  "string",
   904  					},
   905  					"grandchild_id": &OutputState{
   906  						Value: "i-cde345",
   907  						Type:  "string",
   908  					},
   909  				},
   910  			},
   911  			&ModuleState{
   912  				Path: append(rootModulePath, "child", "grandchild"),
   913  				Resources: map[string]*ResourceState{
   914  					"aws_instance.baz": &ResourceState{
   915  						Primary: &InstanceState{
   916  							ID: "i-cde345",
   917  						},
   918  					},
   919  				},
   920  				Outputs: map[string]*OutputState{
   921  					"id": &OutputState{
   922  						Value: "i-cde345",
   923  						Type:  "string",
   924  					},
   925  				},
   926  			},
   927  		},
   928  	}
   929  	ctx := testContext2(t, &ContextOpts{
   930  		Module: m,
   931  		Providers: map[string]ResourceProviderFactory{
   932  			"aws": testProviderFuncFixed(p),
   933  		},
   934  		State: state,
   935  	})
   936  
   937  	testCheckDeadlock(t, func() {
   938  		_, err := ctx.Refresh()
   939  		if err != nil {
   940  			t.Fatalf("err: %s", err)
   941  		}
   942  
   943  		// TODO: handle order properly for orphaned modules / resources
   944  		// expected := []string{"i-abc123", "i-bcd234", "i-cde345"}
   945  		// if !reflect.DeepEqual(order, expected) {
   946  		// 	t.Fatalf("expected: %#v, got: %#v", expected, order)
   947  		// }
   948  	})
   949  }
   950  
   951  func TestContext2Validate(t *testing.T) {
   952  	p := testProvider("aws")
   953  	m := testModule(t, "validate-good")
   954  	c := testContext2(t, &ContextOpts{
   955  		Module: m,
   956  		Providers: map[string]ResourceProviderFactory{
   957  			"aws": testProviderFuncFixed(p),
   958  		},
   959  	})
   960  
   961  	w, e := c.Validate()
   962  	if len(w) > 0 {
   963  		t.Fatalf("bad: %#v", w)
   964  	}
   965  	if len(e) > 0 {
   966  		t.Fatalf("bad: %s", e)
   967  	}
   968  }