github.com/kevinklinger/open_terraform@v1.3.6/noninternal/terraform/context_refresh_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"reflect"
     5  	"sort"
     6  	"strings"
     7  	"sync"
     8  	"testing"
     9  
    10  	"github.com/google/go-cmp/cmp"
    11  	"github.com/zclconf/go-cty/cty"
    12  
    13  	"github.com/kevinklinger/open_terraform/noninternal/addrs"
    14  	"github.com/kevinklinger/open_terraform/noninternal/configs/configschema"
    15  	"github.com/kevinklinger/open_terraform/noninternal/configs/hcl2shim"
    16  	"github.com/kevinklinger/open_terraform/noninternal/plans"
    17  	"github.com/kevinklinger/open_terraform/noninternal/providers"
    18  	"github.com/kevinklinger/open_terraform/noninternal/states"
    19  )
    20  
    21  func TestContext2Refresh(t *testing.T) {
    22  	p := testProvider("aws")
    23  	m := testModule(t, "refresh-basic")
    24  
    25  	state := states.NewState()
    26  	root := state.EnsureModule(addrs.RootModuleInstance)
    27  	root.SetResourceInstanceCurrent(
    28  		mustResourceInstanceAddr("aws_instance.web").Resource,
    29  		&states.ResourceInstanceObjectSrc{
    30  			Status:    states.ObjectReady,
    31  			AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`),
    32  		},
    33  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
    34  	)
    35  
    36  	ctx := testContext2(t, &ContextOpts{
    37  		Providers: map[addrs.Provider]providers.Factory{
    38  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
    39  		},
    40  	})
    41  
    42  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
    43  	ty := schema.ImpliedType()
    44  	readState, err := hcl2shim.HCL2ValueFromFlatmap(map[string]string{"id": "foo", "foo": "baz"}, ty)
    45  	if err != nil {
    46  		t.Fatal(err)
    47  	}
    48  
    49  	p.ReadResourceResponse = &providers.ReadResourceResponse{
    50  		NewState: readState,
    51  	}
    52  
    53  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
    54  	if diags.HasErrors() {
    55  		t.Fatal(diags.Err())
    56  	}
    57  
    58  	if !p.ReadResourceCalled {
    59  		t.Fatal("ReadResource should be called")
    60  	}
    61  
    62  	mod := s.RootModule()
    63  	fromState, err := mod.Resources["aws_instance.web"].Instances[addrs.NoKey].Current.Decode(ty)
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  
    68  	newState, err := schema.CoerceValue(fromState.Value)
    69  	if err != nil {
    70  		t.Fatal(err)
    71  	}
    72  
    73  	if !cmp.Equal(readState, newState, valueComparer) {
    74  		t.Fatal(cmp.Diff(readState, newState, valueComparer, equateEmpty))
    75  	}
    76  }
    77  
    78  func TestContext2Refresh_dynamicAttr(t *testing.T) {
    79  	m := testModule(t, "refresh-dynamic")
    80  
    81  	startingState := states.BuildState(func(ss *states.SyncState) {
    82  		ss.SetResourceInstanceCurrent(
    83  			addrs.Resource{
    84  				Mode: addrs.ManagedResourceMode,
    85  				Type: "test_instance",
    86  				Name: "foo",
    87  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    88  			&states.ResourceInstanceObjectSrc{
    89  				Status:    states.ObjectReady,
    90  				AttrsJSON: []byte(`{"dynamic":{"type":"string","value":"hello"}}`),
    91  			},
    92  			addrs.AbsProviderConfig{
    93  				Provider: addrs.NewDefaultProvider("test"),
    94  				Module:   addrs.RootModule,
    95  			},
    96  		)
    97  	})
    98  
    99  	readStateVal := cty.ObjectVal(map[string]cty.Value{
   100  		"dynamic": cty.EmptyTupleVal,
   101  	})
   102  
   103  	p := testProvider("test")
   104  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   105  		ResourceTypes: map[string]*configschema.Block{
   106  			"test_instance": {
   107  				Attributes: map[string]*configschema.Attribute{
   108  					"dynamic": {Type: cty.DynamicPseudoType, Optional: true},
   109  				},
   110  			},
   111  		},
   112  	})
   113  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
   114  		return providers.ReadResourceResponse{
   115  			NewState: readStateVal,
   116  		}
   117  	}
   118  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
   119  		resp.PlannedState = req.ProposedNewState
   120  		return resp
   121  	}
   122  
   123  	ctx := testContext2(t, &ContextOpts{
   124  		Providers: map[addrs.Provider]providers.Factory{
   125  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
   126  		},
   127  	})
   128  
   129  	schema := p.GetProviderSchemaResponse.ResourceTypes["test_instance"].Block
   130  	ty := schema.ImpliedType()
   131  
   132  	s, diags := ctx.Refresh(m, startingState, &PlanOpts{Mode: plans.NormalMode})
   133  	if diags.HasErrors() {
   134  		t.Fatal(diags.Err())
   135  	}
   136  
   137  	if !p.ReadResourceCalled {
   138  		t.Fatal("ReadResource should be called")
   139  	}
   140  
   141  	mod := s.RootModule()
   142  	newState, err := mod.Resources["test_instance.foo"].Instances[addrs.NoKey].Current.Decode(ty)
   143  	if err != nil {
   144  		t.Fatal(err)
   145  	}
   146  
   147  	if !cmp.Equal(readStateVal, newState.Value, valueComparer) {
   148  		t.Error(cmp.Diff(newState.Value, readStateVal, valueComparer, equateEmpty))
   149  	}
   150  }
   151  
   152  func TestContext2Refresh_dataComputedModuleVar(t *testing.T) {
   153  	p := testProvider("aws")
   154  	m := testModule(t, "refresh-data-module-var")
   155  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
   156  		obj := req.ProposedNewState.AsValueMap()
   157  		obj["id"] = cty.UnknownVal(cty.String)
   158  		resp.PlannedState = cty.ObjectVal(obj)
   159  		return resp
   160  	}
   161  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
   162  		resp.State = req.Config
   163  		return resp
   164  	}
   165  
   166  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   167  		Provider: &configschema.Block{},
   168  		ResourceTypes: map[string]*configschema.Block{
   169  			"aws_instance": {
   170  				Attributes: map[string]*configschema.Attribute{
   171  					"foo": {
   172  						Type:     cty.String,
   173  						Optional: true,
   174  					},
   175  					"id": {
   176  						Type:     cty.String,
   177  						Computed: true,
   178  					},
   179  				},
   180  			},
   181  		},
   182  		DataSources: map[string]*configschema.Block{
   183  			"aws_data_source": {
   184  				Attributes: map[string]*configschema.Attribute{
   185  					"id": {
   186  						Type:     cty.String,
   187  						Optional: true,
   188  					},
   189  					"output": {
   190  						Type:     cty.String,
   191  						Computed: true,
   192  					},
   193  				},
   194  			},
   195  		},
   196  	})
   197  
   198  	ctx := testContext2(t, &ContextOpts{
   199  		Providers: map[addrs.Provider]providers.Factory{
   200  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   201  		},
   202  	})
   203  
   204  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{Mode: plans.RefreshOnlyMode})
   205  	if diags.HasErrors() {
   206  		t.Fatalf("refresh errors: %s", diags.Err())
   207  	}
   208  
   209  	checkStateString(t, plan.PriorState, `
   210  <no state>
   211  `)
   212  }
   213  
   214  func TestContext2Refresh_targeted(t *testing.T) {
   215  	p := testProvider("aws")
   216  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   217  		Provider: &configschema.Block{},
   218  		ResourceTypes: map[string]*configschema.Block{
   219  			"aws_elb": {
   220  				Attributes: map[string]*configschema.Attribute{
   221  					"id": {
   222  						Type:     cty.String,
   223  						Computed: true,
   224  					},
   225  					"instances": {
   226  						Type:     cty.Set(cty.String),
   227  						Optional: true,
   228  					},
   229  				},
   230  			},
   231  			"aws_instance": {
   232  				Attributes: map[string]*configschema.Attribute{
   233  					"id": {
   234  						Type:     cty.String,
   235  						Computed: true,
   236  					},
   237  					"vpc_id": {
   238  						Type:     cty.String,
   239  						Optional: true,
   240  					},
   241  				},
   242  			},
   243  			"aws_vpc": {
   244  				Attributes: map[string]*configschema.Attribute{
   245  					"id": {
   246  						Type:     cty.String,
   247  						Computed: true,
   248  					},
   249  				},
   250  			},
   251  		},
   252  	})
   253  
   254  	state := states.NewState()
   255  	root := state.EnsureModule(addrs.RootModuleInstance)
   256  	testSetResourceInstanceCurrent(root, "aws_vpc.metoo", `{"id":"vpc-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   257  	testSetResourceInstanceCurrent(root, "aws_instance.notme", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   258  	testSetResourceInstanceCurrent(root, "aws_instance.me", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   259  	testSetResourceInstanceCurrent(root, "aws_elb.meneither", `{"id":"lb-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   260  
   261  	m := testModule(t, "refresh-targeted")
   262  	ctx := testContext2(t, &ContextOpts{
   263  		Providers: map[addrs.Provider]providers.Factory{
   264  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   265  		},
   266  	})
   267  
   268  	refreshedResources := make([]string, 0, 2)
   269  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
   270  		refreshedResources = append(refreshedResources, req.PriorState.GetAttr("id").AsString())
   271  		return providers.ReadResourceResponse{
   272  			NewState: req.PriorState,
   273  		}
   274  	}
   275  
   276  	_, diags := ctx.Refresh(m, state, &PlanOpts{
   277  		Mode: plans.NormalMode,
   278  		Targets: []addrs.Targetable{
   279  			addrs.RootModuleInstance.Resource(
   280  				addrs.ManagedResourceMode, "aws_instance", "me",
   281  			),
   282  		},
   283  	})
   284  	if diags.HasErrors() {
   285  		t.Fatalf("refresh errors: %s", diags.Err())
   286  	}
   287  
   288  	expected := []string{"vpc-abc123", "i-abc123"}
   289  	if !reflect.DeepEqual(refreshedResources, expected) {
   290  		t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
   291  	}
   292  }
   293  
   294  func TestContext2Refresh_targetedCount(t *testing.T) {
   295  	p := testProvider("aws")
   296  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   297  		Provider: &configschema.Block{},
   298  		ResourceTypes: map[string]*configschema.Block{
   299  			"aws_elb": {
   300  				Attributes: map[string]*configschema.Attribute{
   301  					"id": {
   302  						Type:     cty.String,
   303  						Computed: true,
   304  					},
   305  					"instances": {
   306  						Type:     cty.Set(cty.String),
   307  						Optional: true,
   308  					},
   309  				},
   310  			},
   311  			"aws_instance": {
   312  				Attributes: map[string]*configschema.Attribute{
   313  					"id": {
   314  						Type:     cty.String,
   315  						Computed: true,
   316  					},
   317  					"vpc_id": {
   318  						Type:     cty.String,
   319  						Optional: true,
   320  					},
   321  				},
   322  			},
   323  			"aws_vpc": {
   324  				Attributes: map[string]*configschema.Attribute{
   325  					"id": {
   326  						Type:     cty.String,
   327  						Computed: true,
   328  					},
   329  				},
   330  			},
   331  		},
   332  	})
   333  
   334  	state := states.NewState()
   335  	root := state.EnsureModule(addrs.RootModuleInstance)
   336  	testSetResourceInstanceCurrent(root, "aws_vpc.metoo", `{"id":"vpc-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   337  	testSetResourceInstanceCurrent(root, "aws_instance.notme", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   338  	testSetResourceInstanceCurrent(root, "aws_instance.me[0]", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   339  	testSetResourceInstanceCurrent(root, "aws_instance.me[1]", `{"id":"i-cde567"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   340  	testSetResourceInstanceCurrent(root, "aws_instance.me[2]", `{"id":"i-cde789"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   341  	testSetResourceInstanceCurrent(root, "aws_elb.meneither", `{"id":"lb-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   342  
   343  	m := testModule(t, "refresh-targeted-count")
   344  	ctx := testContext2(t, &ContextOpts{
   345  		Providers: map[addrs.Provider]providers.Factory{
   346  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   347  		},
   348  	})
   349  
   350  	refreshedResources := make([]string, 0, 2)
   351  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
   352  		refreshedResources = append(refreshedResources, req.PriorState.GetAttr("id").AsString())
   353  		return providers.ReadResourceResponse{
   354  			NewState: req.PriorState,
   355  		}
   356  	}
   357  
   358  	_, diags := ctx.Refresh(m, state, &PlanOpts{
   359  		Mode: plans.NormalMode,
   360  		Targets: []addrs.Targetable{
   361  			addrs.RootModuleInstance.Resource(
   362  				addrs.ManagedResourceMode, "aws_instance", "me",
   363  			),
   364  		},
   365  	})
   366  	if diags.HasErrors() {
   367  		t.Fatalf("refresh errors: %s", diags.Err())
   368  	}
   369  
   370  	// Target didn't specify index, so we should get all our instances
   371  	expected := []string{
   372  		"vpc-abc123",
   373  		"i-abc123",
   374  		"i-cde567",
   375  		"i-cde789",
   376  	}
   377  	sort.Strings(expected)
   378  	sort.Strings(refreshedResources)
   379  	if !reflect.DeepEqual(refreshedResources, expected) {
   380  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", refreshedResources, expected)
   381  	}
   382  }
   383  
   384  func TestContext2Refresh_targetedCountIndex(t *testing.T) {
   385  	p := testProvider("aws")
   386  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   387  		Provider: &configschema.Block{},
   388  		ResourceTypes: map[string]*configschema.Block{
   389  			"aws_elb": {
   390  				Attributes: map[string]*configschema.Attribute{
   391  					"id": {
   392  						Type:     cty.String,
   393  						Computed: true,
   394  					},
   395  					"instances": {
   396  						Type:     cty.Set(cty.String),
   397  						Optional: true,
   398  					},
   399  				},
   400  			},
   401  			"aws_instance": {
   402  				Attributes: map[string]*configschema.Attribute{
   403  					"id": {
   404  						Type:     cty.String,
   405  						Computed: true,
   406  					},
   407  					"vpc_id": {
   408  						Type:     cty.String,
   409  						Optional: true,
   410  					},
   411  				},
   412  			},
   413  			"aws_vpc": {
   414  				Attributes: map[string]*configschema.Attribute{
   415  					"id": {
   416  						Type:     cty.String,
   417  						Computed: true,
   418  					},
   419  				},
   420  			},
   421  		},
   422  	})
   423  
   424  	state := states.NewState()
   425  	root := state.EnsureModule(addrs.RootModuleInstance)
   426  	testSetResourceInstanceCurrent(root, "aws_vpc.metoo", `{"id":"vpc-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   427  	testSetResourceInstanceCurrent(root, "aws_instance.notme", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   428  	testSetResourceInstanceCurrent(root, "aws_instance.me[0]", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   429  	testSetResourceInstanceCurrent(root, "aws_instance.me[1]", `{"id":"i-cde567"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   430  	testSetResourceInstanceCurrent(root, "aws_instance.me[2]", `{"id":"i-cde789"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   431  	testSetResourceInstanceCurrent(root, "aws_elb.meneither", `{"id":"lb-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   432  
   433  	m := testModule(t, "refresh-targeted-count")
   434  	ctx := testContext2(t, &ContextOpts{
   435  		Providers: map[addrs.Provider]providers.Factory{
   436  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   437  		},
   438  	})
   439  
   440  	refreshedResources := make([]string, 0, 2)
   441  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
   442  		refreshedResources = append(refreshedResources, req.PriorState.GetAttr("id").AsString())
   443  		return providers.ReadResourceResponse{
   444  			NewState: req.PriorState,
   445  		}
   446  	}
   447  
   448  	_, diags := ctx.Refresh(m, state, &PlanOpts{
   449  		Mode: plans.NormalMode,
   450  		Targets: []addrs.Targetable{
   451  			addrs.RootModuleInstance.ResourceInstance(
   452  				addrs.ManagedResourceMode, "aws_instance", "me", addrs.IntKey(0),
   453  			),
   454  		},
   455  	})
   456  	if diags.HasErrors() {
   457  		t.Fatalf("refresh errors: %s", diags.Err())
   458  	}
   459  
   460  	expected := []string{"vpc-abc123", "i-abc123"}
   461  	if !reflect.DeepEqual(refreshedResources, expected) {
   462  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", refreshedResources, expected)
   463  	}
   464  }
   465  
   466  func TestContext2Refresh_moduleComputedVar(t *testing.T) {
   467  	p := testProvider("aws")
   468  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   469  		Provider: &configschema.Block{},
   470  		ResourceTypes: map[string]*configschema.Block{
   471  			"aws_instance": {
   472  				Attributes: map[string]*configschema.Attribute{
   473  					"id": {
   474  						Type:     cty.String,
   475  						Computed: true,
   476  					},
   477  					"value": {
   478  						Type:     cty.String,
   479  						Optional: true,
   480  					},
   481  				},
   482  			},
   483  		},
   484  	})
   485  
   486  	m := testModule(t, "refresh-module-computed-var")
   487  	ctx := testContext2(t, &ContextOpts{
   488  		Providers: map[addrs.Provider]providers.Factory{
   489  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   490  		},
   491  	})
   492  
   493  	// This was failing (see GH-2188) at some point, so this test just
   494  	// verifies that the failure goes away.
   495  	if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
   496  		t.Fatalf("refresh errs: %s", diags.Err())
   497  	}
   498  }
   499  
   500  func TestContext2Refresh_delete(t *testing.T) {
   501  	p := testProvider("aws")
   502  	m := testModule(t, "refresh-basic")
   503  
   504  	state := states.NewState()
   505  	root := state.EnsureModule(addrs.RootModuleInstance)
   506  	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   507  
   508  	ctx := testContext2(t, &ContextOpts{
   509  		Providers: map[addrs.Provider]providers.Factory{
   510  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   511  		},
   512  	})
   513  
   514  	p.ReadResourceResponse = &providers.ReadResourceResponse{
   515  		NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block.ImpliedType()),
   516  	}
   517  
   518  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
   519  	if diags.HasErrors() {
   520  		t.Fatalf("refresh errors: %s", diags.Err())
   521  	}
   522  
   523  	mod := s.RootModule()
   524  	if len(mod.Resources) > 0 {
   525  		t.Fatal("resources should be empty")
   526  	}
   527  }
   528  
   529  func TestContext2Refresh_ignoreUncreated(t *testing.T) {
   530  	p := testProvider("aws")
   531  	m := testModule(t, "refresh-basic")
   532  	ctx := testContext2(t, &ContextOpts{
   533  		Providers: map[addrs.Provider]providers.Factory{
   534  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   535  		},
   536  	})
   537  
   538  	p.ReadResourceResponse = &providers.ReadResourceResponse{
   539  		NewState: cty.ObjectVal(map[string]cty.Value{
   540  			"id": cty.StringVal("foo"),
   541  		}),
   542  	}
   543  
   544  	_, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode})
   545  	if diags.HasErrors() {
   546  		t.Fatalf("refresh errors: %s", diags.Err())
   547  	}
   548  	if p.ReadResourceCalled {
   549  		t.Fatal("refresh should not be called")
   550  	}
   551  }
   552  
   553  func TestContext2Refresh_hook(t *testing.T) {
   554  	h := new(MockHook)
   555  	p := testProvider("aws")
   556  	m := testModule(t, "refresh-basic")
   557  
   558  	state := states.NewState()
   559  	root := state.EnsureModule(addrs.RootModuleInstance)
   560  	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   561  
   562  	ctx := testContext2(t, &ContextOpts{
   563  		Hooks: []Hook{h},
   564  		Providers: map[addrs.Provider]providers.Factory{
   565  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   566  		},
   567  	})
   568  
   569  	if _, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
   570  		t.Fatalf("refresh errs: %s", diags.Err())
   571  	}
   572  	if !h.PreRefreshCalled {
   573  		t.Fatal("should be called")
   574  	}
   575  	if !h.PostRefreshCalled {
   576  		t.Fatal("should be called")
   577  	}
   578  }
   579  
   580  func TestContext2Refresh_modules(t *testing.T) {
   581  	p := testProvider("aws")
   582  	m := testModule(t, "refresh-modules")
   583  
   584  	state := states.NewState()
   585  	root := state.EnsureModule(addrs.RootModuleInstance)
   586  	testSetResourceInstanceTainted(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   587  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
   588  	testSetResourceInstanceCurrent(child, "aws_instance.web", `{"id":"baz"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   589  
   590  	ctx := testContext2(t, &ContextOpts{
   591  		Providers: map[addrs.Provider]providers.Factory{
   592  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   593  		},
   594  	})
   595  
   596  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
   597  		if !req.PriorState.GetAttr("id").RawEquals(cty.StringVal("baz")) {
   598  			return providers.ReadResourceResponse{
   599  				NewState: req.PriorState,
   600  			}
   601  		}
   602  
   603  		new, _ := cty.Transform(req.PriorState, func(path cty.Path, v cty.Value) (cty.Value, error) {
   604  			if len(path) == 1 && path[0].(cty.GetAttrStep).Name == "id" {
   605  				return cty.StringVal("new"), nil
   606  			}
   607  			return v, nil
   608  		})
   609  		return providers.ReadResourceResponse{
   610  			NewState: new,
   611  		}
   612  	}
   613  
   614  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
   615  	if diags.HasErrors() {
   616  		t.Fatalf("refresh errors: %s", diags.Err())
   617  	}
   618  
   619  	actual := strings.TrimSpace(s.String())
   620  	expected := strings.TrimSpace(testContextRefreshModuleStr)
   621  	if actual != expected {
   622  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   623  	}
   624  }
   625  
   626  func TestContext2Refresh_moduleInputComputedOutput(t *testing.T) {
   627  	m := testModule(t, "refresh-module-input-computed-output")
   628  	p := testProvider("aws")
   629  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   630  		Provider: &configschema.Block{},
   631  		ResourceTypes: map[string]*configschema.Block{
   632  			"aws_instance": {
   633  				Attributes: map[string]*configschema.Attribute{
   634  					"foo": {
   635  						Type:     cty.String,
   636  						Optional: true,
   637  						Computed: true,
   638  					},
   639  					"compute": {
   640  						Type:     cty.String,
   641  						Optional: true,
   642  					},
   643  				},
   644  			},
   645  		},
   646  	})
   647  
   648  	ctx := testContext2(t, &ContextOpts{
   649  		Providers: map[addrs.Provider]providers.Factory{
   650  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   651  		},
   652  	})
   653  
   654  	if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
   655  		t.Fatalf("refresh errs: %s", diags.Err())
   656  	}
   657  }
   658  
   659  func TestContext2Refresh_moduleVarModule(t *testing.T) {
   660  	m := testModule(t, "refresh-module-var-module")
   661  	p := testProvider("aws")
   662  	ctx := testContext2(t, &ContextOpts{
   663  		Providers: map[addrs.Provider]providers.Factory{
   664  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   665  		},
   666  	})
   667  
   668  	if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
   669  		t.Fatalf("refresh errs: %s", diags.Err())
   670  	}
   671  }
   672  
   673  // GH-70
   674  func TestContext2Refresh_noState(t *testing.T) {
   675  	p := testProvider("aws")
   676  	m := testModule(t, "refresh-no-state")
   677  	ctx := testContext2(t, &ContextOpts{
   678  		Providers: map[addrs.Provider]providers.Factory{
   679  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   680  		},
   681  	})
   682  
   683  	p.ReadResourceResponse = &providers.ReadResourceResponse{
   684  		NewState: cty.ObjectVal(map[string]cty.Value{
   685  			"id": cty.StringVal("foo"),
   686  		}),
   687  	}
   688  
   689  	if _, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode}); diags.HasErrors() {
   690  		t.Fatalf("refresh errs: %s", diags.Err())
   691  	}
   692  }
   693  
   694  func TestContext2Refresh_output(t *testing.T) {
   695  	p := testProvider("aws")
   696  	p.PlanResourceChangeFn = testDiffFn
   697  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   698  		Provider: &configschema.Block{},
   699  		ResourceTypes: map[string]*configschema.Block{
   700  			"aws_instance": {
   701  				Attributes: map[string]*configschema.Attribute{
   702  					"id": {
   703  						Type:     cty.String,
   704  						Computed: true,
   705  					},
   706  					"foo": {
   707  						Type:     cty.String,
   708  						Optional: true,
   709  						Computed: true,
   710  					},
   711  				},
   712  			},
   713  		},
   714  	})
   715  
   716  	m := testModule(t, "refresh-output")
   717  
   718  	state := states.NewState()
   719  	root := state.EnsureModule(addrs.RootModuleInstance)
   720  	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo","foo":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   721  	root.SetOutputValue("foo", cty.StringVal("foo"), false)
   722  
   723  	ctx := testContext2(t, &ContextOpts{
   724  		Providers: map[addrs.Provider]providers.Factory{
   725  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   726  		},
   727  	})
   728  
   729  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
   730  	if diags.HasErrors() {
   731  		t.Fatalf("refresh errors: %s", diags.Err())
   732  	}
   733  
   734  	actual := strings.TrimSpace(s.String())
   735  	expected := strings.TrimSpace(testContextRefreshOutputStr)
   736  	if actual != expected {
   737  		t.Fatalf("wrong result\n\ngot:\n%q\n\nwant:\n%q", actual, expected)
   738  	}
   739  }
   740  
   741  func TestContext2Refresh_outputPartial(t *testing.T) {
   742  	p := testProvider("aws")
   743  	m := testModule(t, "refresh-output-partial")
   744  
   745  	// Refresh creates a partial plan for any instances that don't have
   746  	// remote objects yet, to get stub values for interpolation. Therefore
   747  	// we need to make DiffFn available to let that complete.
   748  
   749  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   750  		Provider: &configschema.Block{},
   751  		ResourceTypes: map[string]*configschema.Block{
   752  			"aws_instance": {
   753  				Attributes: map[string]*configschema.Attribute{
   754  					"foo": {
   755  						Type:     cty.String,
   756  						Computed: true,
   757  					},
   758  				},
   759  			},
   760  		},
   761  	})
   762  
   763  	p.ReadResourceResponse = &providers.ReadResourceResponse{
   764  		NewState: cty.NullVal(p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block.ImpliedType()),
   765  	}
   766  
   767  	state := states.NewState()
   768  	root := state.EnsureModule(addrs.RootModuleInstance)
   769  	testSetResourceInstanceCurrent(root, "aws_instance.foo", `{}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   770  
   771  	ctx := testContext2(t, &ContextOpts{
   772  		Providers: map[addrs.Provider]providers.Factory{
   773  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   774  		},
   775  	})
   776  
   777  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
   778  	if diags.HasErrors() {
   779  		t.Fatalf("refresh errors: %s", diags.Err())
   780  	}
   781  
   782  	actual := strings.TrimSpace(s.String())
   783  	expected := strings.TrimSpace(testContextRefreshOutputPartialStr)
   784  	if actual != expected {
   785  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   786  	}
   787  }
   788  
   789  func TestContext2Refresh_stateBasic(t *testing.T) {
   790  	p := testProvider("aws")
   791  	m := testModule(t, "refresh-basic")
   792  
   793  	state := states.NewState()
   794  	root := state.EnsureModule(addrs.RootModuleInstance)
   795  	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   796  
   797  	ctx := testContext2(t, &ContextOpts{
   798  		Providers: map[addrs.Provider]providers.Factory{
   799  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   800  		},
   801  	})
   802  
   803  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   804  	ty := schema.ImpliedType()
   805  
   806  	readStateVal, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
   807  		"id": cty.StringVal("foo"),
   808  	}))
   809  	if err != nil {
   810  		t.Fatal(err)
   811  	}
   812  
   813  	p.ReadResourceResponse = &providers.ReadResourceResponse{
   814  		NewState: readStateVal,
   815  	}
   816  
   817  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
   818  	if diags.HasErrors() {
   819  		t.Fatalf("refresh errors: %s", diags.Err())
   820  	}
   821  
   822  	if !p.ReadResourceCalled {
   823  		t.Fatal("read resource should be called")
   824  	}
   825  
   826  	mod := s.RootModule()
   827  	newState, err := mod.Resources["aws_instance.web"].Instances[addrs.NoKey].Current.Decode(ty)
   828  	if err != nil {
   829  		t.Fatal(err)
   830  	}
   831  
   832  	if !cmp.Equal(readStateVal, newState.Value, valueComparer, equateEmpty) {
   833  		t.Fatal(cmp.Diff(readStateVal, newState.Value, valueComparer, equateEmpty))
   834  	}
   835  }
   836  
   837  func TestContext2Refresh_dataCount(t *testing.T) {
   838  	p := testProvider("test")
   839  	m := testModule(t, "refresh-data-count")
   840  
   841  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
   842  		m := req.ProposedNewState.AsValueMap()
   843  		m["things"] = cty.ListVal([]cty.Value{cty.StringVal("foo")})
   844  		resp.PlannedState = cty.ObjectVal(m)
   845  		return resp
   846  	}
   847  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   848  		ResourceTypes: map[string]*configschema.Block{
   849  			"test": {
   850  				Attributes: map[string]*configschema.Attribute{
   851  					"id":     {Type: cty.String, Computed: true},
   852  					"things": {Type: cty.List(cty.String), Computed: true},
   853  				},
   854  			},
   855  		},
   856  		DataSources: map[string]*configschema.Block{
   857  			"test": {},
   858  		},
   859  	})
   860  
   861  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
   862  		return providers.ReadDataSourceResponse{
   863  			State: req.Config,
   864  		}
   865  	}
   866  
   867  	ctx := testContext2(t, &ContextOpts{
   868  		Providers: map[addrs.Provider]providers.Factory{
   869  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
   870  		},
   871  	})
   872  
   873  	s, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode})
   874  
   875  	if diags.HasErrors() {
   876  		t.Fatalf("refresh errors: %s", diags.Err())
   877  	}
   878  
   879  	checkStateString(t, s, `<no state>`)
   880  }
   881  
   882  func TestContext2Refresh_dataState(t *testing.T) {
   883  	m := testModule(t, "refresh-data-resource-basic")
   884  	state := states.NewState()
   885  	schema := &configschema.Block{
   886  		Attributes: map[string]*configschema.Attribute{
   887  			"inputs": {
   888  				Type:     cty.Map(cty.String),
   889  				Optional: true,
   890  			},
   891  		},
   892  	}
   893  
   894  	p := testProvider("null")
   895  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   896  		Provider: &configschema.Block{},
   897  		DataSources: map[string]*configschema.Block{
   898  			"null_data_source": schema,
   899  		},
   900  	})
   901  
   902  	ctx := testContext2(t, &ContextOpts{
   903  		Providers: map[addrs.Provider]providers.Factory{
   904  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   905  		},
   906  	})
   907  
   908  	var readStateVal cty.Value
   909  
   910  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
   911  		m := req.Config.AsValueMap()
   912  		readStateVal = cty.ObjectVal(m)
   913  
   914  		return providers.ReadDataSourceResponse{
   915  			State: readStateVal,
   916  		}
   917  	}
   918  
   919  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
   920  	if diags.HasErrors() {
   921  		t.Fatalf("refresh errors: %s", diags.Err())
   922  	}
   923  
   924  	if !p.ReadDataSourceCalled {
   925  		t.Fatal("ReadDataSource should have been called")
   926  	}
   927  
   928  	mod := s.RootModule()
   929  
   930  	newState, err := mod.Resources["data.null_data_source.testing"].Instances[addrs.NoKey].Current.Decode(schema.ImpliedType())
   931  	if err != nil {
   932  		t.Fatal(err)
   933  	}
   934  
   935  	if !cmp.Equal(readStateVal, newState.Value, valueComparer, equateEmpty) {
   936  		t.Fatal(cmp.Diff(readStateVal, newState.Value, valueComparer, equateEmpty))
   937  	}
   938  }
   939  
   940  func TestContext2Refresh_dataStateRefData(t *testing.T) {
   941  	p := testProvider("null")
   942  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   943  		Provider: &configschema.Block{},
   944  		DataSources: map[string]*configschema.Block{
   945  			"null_data_source": {
   946  				Attributes: map[string]*configschema.Attribute{
   947  					"id": {
   948  						Type:     cty.String,
   949  						Computed: true,
   950  					},
   951  					"foo": {
   952  						Type:     cty.String,
   953  						Optional: true,
   954  					},
   955  					"bar": {
   956  						Type:     cty.String,
   957  						Optional: true,
   958  					},
   959  				},
   960  			},
   961  		},
   962  	})
   963  
   964  	m := testModule(t, "refresh-data-ref-data")
   965  	state := states.NewState()
   966  	ctx := testContext2(t, &ContextOpts{
   967  		Providers: map[addrs.Provider]providers.Factory{
   968  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   969  		},
   970  	})
   971  
   972  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
   973  		// add the required id
   974  		m := req.Config.AsValueMap()
   975  		m["id"] = cty.StringVal("foo")
   976  
   977  		return providers.ReadDataSourceResponse{
   978  			State: cty.ObjectVal(m),
   979  		}
   980  	}
   981  
   982  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
   983  	if diags.HasErrors() {
   984  		t.Fatalf("refresh errors: %s", diags.Err())
   985  	}
   986  
   987  	actual := strings.TrimSpace(s.String())
   988  	expected := strings.TrimSpace(testTerraformRefreshDataRefDataStr)
   989  	if actual != expected {
   990  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   991  	}
   992  }
   993  
   994  func TestContext2Refresh_tainted(t *testing.T) {
   995  	p := testProvider("aws")
   996  	m := testModule(t, "refresh-basic")
   997  
   998  	state := states.NewState()
   999  	root := state.EnsureModule(addrs.RootModuleInstance)
  1000  	testSetResourceInstanceTainted(root, "aws_instance.web", `{"id":"bar"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
  1001  
  1002  	ctx := testContext2(t, &ContextOpts{
  1003  		Providers: map[addrs.Provider]providers.Factory{
  1004  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1005  		},
  1006  	})
  1007  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
  1008  		// add the required id
  1009  		m := req.PriorState.AsValueMap()
  1010  		m["id"] = cty.StringVal("foo")
  1011  
  1012  		return providers.ReadResourceResponse{
  1013  			NewState: cty.ObjectVal(m),
  1014  		}
  1015  	}
  1016  
  1017  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
  1018  	if diags.HasErrors() {
  1019  		t.Fatalf("refresh errors: %s", diags.Err())
  1020  	}
  1021  	if !p.ReadResourceCalled {
  1022  		t.Fatal("ReadResource was not called; should have been")
  1023  	}
  1024  
  1025  	actual := strings.TrimSpace(s.String())
  1026  	expected := strings.TrimSpace(testContextRefreshTaintedStr)
  1027  	if actual != expected {
  1028  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1029  	}
  1030  }
  1031  
  1032  // Doing a Refresh (or any operation really, but Refresh usually
  1033  // happens first) with a config with an unknown provider should result in
  1034  // an error. The key bug this found was that this wasn't happening if
  1035  // Providers was _empty_.
  1036  func TestContext2Refresh_unknownProvider(t *testing.T) {
  1037  	m := testModule(t, "refresh-unknown-provider")
  1038  
  1039  	state := states.NewState()
  1040  	root := state.EnsureModule(addrs.RootModuleInstance)
  1041  	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
  1042  
  1043  	c, diags := NewContext(&ContextOpts{
  1044  		Providers: map[addrs.Provider]providers.Factory{},
  1045  	})
  1046  	assertNoDiagnostics(t, diags)
  1047  
  1048  	_, diags = c.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode})
  1049  	if !diags.HasErrors() {
  1050  		t.Fatal("successfully refreshed; want error")
  1051  	}
  1052  
  1053  	if got, want := diags.Err().Error(), "Missing required provider"; !strings.Contains(got, want) {
  1054  		t.Errorf("missing expected error\nwant substring: %s\ngot:\n%s", want, got)
  1055  	}
  1056  }
  1057  
  1058  func TestContext2Refresh_vars(t *testing.T) {
  1059  	p := testProvider("aws")
  1060  
  1061  	schema := &configschema.Block{
  1062  		Attributes: map[string]*configschema.Attribute{
  1063  			"ami": {
  1064  				Type:     cty.String,
  1065  				Optional: true,
  1066  			},
  1067  			"id": {
  1068  				Type:     cty.String,
  1069  				Computed: true,
  1070  			},
  1071  		},
  1072  	}
  1073  
  1074  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1075  		Provider:      &configschema.Block{},
  1076  		ResourceTypes: map[string]*configschema.Block{"aws_instance": schema},
  1077  	})
  1078  
  1079  	m := testModule(t, "refresh-vars")
  1080  	state := states.NewState()
  1081  	root := state.EnsureModule(addrs.RootModuleInstance)
  1082  	testSetResourceInstanceCurrent(root, "aws_instance.web", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
  1083  
  1084  	ctx := testContext2(t, &ContextOpts{
  1085  		Providers: map[addrs.Provider]providers.Factory{
  1086  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1087  		},
  1088  	})
  1089  
  1090  	readStateVal, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
  1091  		"id": cty.StringVal("foo"),
  1092  	}))
  1093  	if err != nil {
  1094  		t.Fatal(err)
  1095  	}
  1096  
  1097  	p.ReadResourceResponse = &providers.ReadResourceResponse{
  1098  		NewState: readStateVal,
  1099  	}
  1100  
  1101  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  1102  		return providers.PlanResourceChangeResponse{
  1103  			PlannedState: req.ProposedNewState,
  1104  		}
  1105  	}
  1106  
  1107  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
  1108  	if diags.HasErrors() {
  1109  		t.Fatalf("refresh errors: %s", diags.Err())
  1110  	}
  1111  
  1112  	if !p.ReadResourceCalled {
  1113  		t.Fatal("read resource should be called")
  1114  	}
  1115  
  1116  	mod := s.RootModule()
  1117  
  1118  	newState, err := mod.Resources["aws_instance.web"].Instances[addrs.NoKey].Current.Decode(schema.ImpliedType())
  1119  	if err != nil {
  1120  		t.Fatal(err)
  1121  	}
  1122  
  1123  	if !cmp.Equal(readStateVal, newState.Value, valueComparer, equateEmpty) {
  1124  		t.Fatal(cmp.Diff(readStateVal, newState.Value, valueComparer, equateEmpty))
  1125  	}
  1126  
  1127  	for _, r := range mod.Resources {
  1128  		if r.Addr.Resource.Type == "" {
  1129  			t.Fatalf("no type: %#v", r)
  1130  		}
  1131  	}
  1132  }
  1133  
  1134  func TestContext2Refresh_orphanModule(t *testing.T) {
  1135  	p := testProvider("aws")
  1136  	m := testModule(t, "refresh-module-orphan")
  1137  
  1138  	// Create a custom refresh function to track the order they were visited
  1139  	var order []string
  1140  	var orderLock sync.Mutex
  1141  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
  1142  		orderLock.Lock()
  1143  		defer orderLock.Unlock()
  1144  
  1145  		order = append(order, req.PriorState.GetAttr("id").AsString())
  1146  		return providers.ReadResourceResponse{
  1147  			NewState: req.PriorState,
  1148  		}
  1149  	}
  1150  
  1151  	state := states.NewState()
  1152  	root := state.EnsureModule(addrs.RootModuleInstance)
  1153  	root.SetResourceInstanceCurrent(
  1154  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1155  		&states.ResourceInstanceObjectSrc{
  1156  			Status:    states.ObjectReady,
  1157  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  1158  			Dependencies: []addrs.ConfigResource{
  1159  				{Module: addrs.Module{"module.child"}},
  1160  				{Module: addrs.Module{"module.child"}},
  1161  			},
  1162  		},
  1163  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1164  	)
  1165  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1166  	child.SetResourceInstanceCurrent(
  1167  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1168  		&states.ResourceInstanceObjectSrc{
  1169  			Status:       states.ObjectReady,
  1170  			AttrsJSON:    []byte(`{"id":"i-bcd23"}`),
  1171  			Dependencies: []addrs.ConfigResource{{Module: addrs.Module{"module.grandchild"}}},
  1172  		},
  1173  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1174  	)
  1175  	grandchild := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("grandchild", addrs.NoKey))
  1176  	testSetResourceInstanceCurrent(grandchild, "aws_instance.baz", `{"id":"i-cde345"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
  1177  
  1178  	ctx := testContext2(t, &ContextOpts{
  1179  		Providers: map[addrs.Provider]providers.Factory{
  1180  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1181  		},
  1182  	})
  1183  
  1184  	testCheckDeadlock(t, func() {
  1185  		_, err := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
  1186  		if err != nil {
  1187  			t.Fatalf("err: %s", err.Err())
  1188  		}
  1189  
  1190  		// TODO: handle order properly for orphaned modules / resources
  1191  		// expected := []string{"i-abc123", "i-bcd234", "i-cde345"}
  1192  		// if !reflect.DeepEqual(order, expected) {
  1193  		// 	t.Fatalf("expected: %#v, got: %#v", expected, order)
  1194  		// }
  1195  	})
  1196  }
  1197  
  1198  func TestContext2Validate(t *testing.T) {
  1199  	p := testProvider("aws")
  1200  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1201  		Provider: &configschema.Block{},
  1202  		ResourceTypes: map[string]*configschema.Block{
  1203  			"aws_instance": {
  1204  				Attributes: map[string]*configschema.Attribute{
  1205  					"foo": {
  1206  						Type:     cty.String,
  1207  						Optional: true,
  1208  					},
  1209  					"num": {
  1210  						Type:     cty.String,
  1211  						Optional: true,
  1212  					},
  1213  				},
  1214  			},
  1215  		},
  1216  	})
  1217  
  1218  	m := testModule(t, "validate-good")
  1219  	c := testContext2(t, &ContextOpts{
  1220  		Providers: map[addrs.Provider]providers.Factory{
  1221  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1222  		},
  1223  	})
  1224  
  1225  	diags := c.Validate(m)
  1226  	if len(diags) != 0 {
  1227  		t.Fatalf("unexpected error: %#v", diags.ErrWithWarnings())
  1228  	}
  1229  }
  1230  
  1231  func TestContext2Refresh_updateProviderInState(t *testing.T) {
  1232  	m := testModule(t, "update-resource-provider")
  1233  	p := testProvider("aws")
  1234  
  1235  	state := states.NewState()
  1236  	root := state.EnsureModule(addrs.RootModuleInstance)
  1237  	testSetResourceInstanceCurrent(root, "aws_instance.bar", `{"id":"foo"}`, `provider["registry.terraform.io/hashicorp/aws"].baz`)
  1238  
  1239  	ctx := testContext2(t, &ContextOpts{
  1240  		Providers: map[addrs.Provider]providers.Factory{
  1241  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1242  		},
  1243  	})
  1244  
  1245  	expected := strings.TrimSpace(`
  1246  aws_instance.bar:
  1247    ID = foo
  1248    provider = provider["registry.terraform.io/hashicorp/aws"].foo`)
  1249  
  1250  	s, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
  1251  	if diags.HasErrors() {
  1252  		t.Fatal(diags.Err())
  1253  	}
  1254  
  1255  	actual := s.String()
  1256  	if actual != expected {
  1257  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  1258  	}
  1259  }
  1260  
  1261  func TestContext2Refresh_schemaUpgradeFlatmap(t *testing.T) {
  1262  	m := testModule(t, "refresh-schema-upgrade")
  1263  	p := testProvider("test")
  1264  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1265  		ResourceTypes: map[string]*configschema.Block{
  1266  			"test_thing": {
  1267  				Attributes: map[string]*configschema.Attribute{
  1268  					"name": { // imagining we renamed this from "id"
  1269  						Type:     cty.String,
  1270  						Optional: true,
  1271  					},
  1272  				},
  1273  			},
  1274  		},
  1275  		ResourceTypeSchemaVersions: map[string]uint64{
  1276  			"test_thing": 5,
  1277  		},
  1278  	})
  1279  	p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{
  1280  		UpgradedState: cty.ObjectVal(map[string]cty.Value{
  1281  			"name": cty.StringVal("foo"),
  1282  		}),
  1283  	}
  1284  
  1285  	s := states.BuildState(func(s *states.SyncState) {
  1286  		s.SetResourceInstanceCurrent(
  1287  			addrs.Resource{
  1288  				Mode: addrs.ManagedResourceMode,
  1289  				Type: "test_thing",
  1290  				Name: "bar",
  1291  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  1292  			&states.ResourceInstanceObjectSrc{
  1293  				Status:        states.ObjectReady,
  1294  				SchemaVersion: 3,
  1295  				AttrsFlat: map[string]string{
  1296  					"id": "foo",
  1297  				},
  1298  			},
  1299  			addrs.AbsProviderConfig{
  1300  				Provider: addrs.NewDefaultProvider("test"),
  1301  				Module:   addrs.RootModule,
  1302  			},
  1303  		)
  1304  	})
  1305  
  1306  	ctx := testContext2(t, &ContextOpts{
  1307  		Providers: map[addrs.Provider]providers.Factory{
  1308  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1309  		},
  1310  	})
  1311  
  1312  	state, diags := ctx.Refresh(m, s, &PlanOpts{Mode: plans.NormalMode})
  1313  	if diags.HasErrors() {
  1314  		t.Fatal(diags.Err())
  1315  	}
  1316  
  1317  	{
  1318  		got := p.UpgradeResourceStateRequest
  1319  		want := providers.UpgradeResourceStateRequest{
  1320  			TypeName: "test_thing",
  1321  			Version:  3,
  1322  			RawStateFlatmap: map[string]string{
  1323  				"id": "foo",
  1324  			},
  1325  		}
  1326  		if !cmp.Equal(got, want) {
  1327  			t.Errorf("wrong upgrade request\n%s", cmp.Diff(want, got))
  1328  		}
  1329  	}
  1330  
  1331  	{
  1332  		got := state.String()
  1333  		want := strings.TrimSpace(`
  1334  test_thing.bar:
  1335    ID = 
  1336    provider = provider["registry.terraform.io/hashicorp/test"]
  1337    name = foo
  1338  `)
  1339  		if got != want {
  1340  			t.Fatalf("wrong result state\ngot:\n%s\n\nwant:\n%s", got, want)
  1341  		}
  1342  	}
  1343  }
  1344  
  1345  func TestContext2Refresh_schemaUpgradeJSON(t *testing.T) {
  1346  	m := testModule(t, "refresh-schema-upgrade")
  1347  	p := testProvider("test")
  1348  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1349  		ResourceTypes: map[string]*configschema.Block{
  1350  			"test_thing": {
  1351  				Attributes: map[string]*configschema.Attribute{
  1352  					"name": { // imagining we renamed this from "id"
  1353  						Type:     cty.String,
  1354  						Optional: true,
  1355  					},
  1356  				},
  1357  			},
  1358  		},
  1359  		ResourceTypeSchemaVersions: map[string]uint64{
  1360  			"test_thing": 5,
  1361  		},
  1362  	})
  1363  	p.UpgradeResourceStateResponse = &providers.UpgradeResourceStateResponse{
  1364  		UpgradedState: cty.ObjectVal(map[string]cty.Value{
  1365  			"name": cty.StringVal("foo"),
  1366  		}),
  1367  	}
  1368  
  1369  	s := states.BuildState(func(s *states.SyncState) {
  1370  		s.SetResourceInstanceCurrent(
  1371  			addrs.Resource{
  1372  				Mode: addrs.ManagedResourceMode,
  1373  				Type: "test_thing",
  1374  				Name: "bar",
  1375  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  1376  			&states.ResourceInstanceObjectSrc{
  1377  				Status:        states.ObjectReady,
  1378  				SchemaVersion: 3,
  1379  				AttrsJSON:     []byte(`{"id":"foo"}`),
  1380  			},
  1381  			addrs.AbsProviderConfig{
  1382  				Provider: addrs.NewDefaultProvider("test"),
  1383  				Module:   addrs.RootModule,
  1384  			},
  1385  		)
  1386  	})
  1387  
  1388  	ctx := testContext2(t, &ContextOpts{
  1389  		Providers: map[addrs.Provider]providers.Factory{
  1390  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1391  		},
  1392  	})
  1393  
  1394  	state, diags := ctx.Refresh(m, s, &PlanOpts{Mode: plans.NormalMode})
  1395  	if diags.HasErrors() {
  1396  		t.Fatal(diags.Err())
  1397  	}
  1398  
  1399  	{
  1400  		got := p.UpgradeResourceStateRequest
  1401  		want := providers.UpgradeResourceStateRequest{
  1402  			TypeName:     "test_thing",
  1403  			Version:      3,
  1404  			RawStateJSON: []byte(`{"id":"foo"}`),
  1405  		}
  1406  		if !cmp.Equal(got, want) {
  1407  			t.Errorf("wrong upgrade request\n%s", cmp.Diff(want, got))
  1408  		}
  1409  	}
  1410  
  1411  	{
  1412  		got := state.String()
  1413  		want := strings.TrimSpace(`
  1414  test_thing.bar:
  1415    ID = 
  1416    provider = provider["registry.terraform.io/hashicorp/test"]
  1417    name = foo
  1418  `)
  1419  		if got != want {
  1420  			t.Fatalf("wrong result state\ngot:\n%s\n\nwant:\n%s", got, want)
  1421  		}
  1422  	}
  1423  }
  1424  
  1425  func TestContext2Refresh_dataValidation(t *testing.T) {
  1426  	m := testModuleInline(t, map[string]string{
  1427  		"main.tf": `
  1428  data "aws_data_source" "foo" {
  1429    foo = "bar"
  1430  }
  1431  `,
  1432  	})
  1433  
  1434  	p := testProvider("aws")
  1435  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  1436  		resp.PlannedState = req.ProposedNewState
  1437  		return
  1438  	}
  1439  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
  1440  		resp.State = req.Config
  1441  		return
  1442  	}
  1443  
  1444  	ctx := testContext2(t, &ContextOpts{
  1445  		Providers: map[addrs.Provider]providers.Factory{
  1446  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1447  		},
  1448  	})
  1449  
  1450  	_, diags := ctx.Refresh(m, states.NewState(), &PlanOpts{Mode: plans.NormalMode})
  1451  	if diags.HasErrors() {
  1452  		// Should get this error:
  1453  		// Unsupported attribute: This object does not have an attribute named "missing"
  1454  		t.Fatal(diags.Err())
  1455  	}
  1456  
  1457  	if !p.ValidateDataResourceConfigCalled {
  1458  		t.Fatal("ValidateDataSourceConfig not called during plan")
  1459  	}
  1460  }
  1461  
  1462  func TestContext2Refresh_dataResourceDependsOn(t *testing.T) {
  1463  	m := testModule(t, "plan-data-depends-on")
  1464  	p := testProvider("test")
  1465  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1466  		ResourceTypes: map[string]*configschema.Block{
  1467  			"test_resource": {
  1468  				Attributes: map[string]*configschema.Attribute{
  1469  					"id":  {Type: cty.String, Computed: true},
  1470  					"foo": {Type: cty.String, Optional: true},
  1471  				},
  1472  			},
  1473  		},
  1474  		DataSources: map[string]*configschema.Block{
  1475  			"test_data": {
  1476  				Attributes: map[string]*configschema.Attribute{
  1477  					"compute": {Type: cty.String, Computed: true},
  1478  				},
  1479  			},
  1480  		},
  1481  	})
  1482  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  1483  		State: cty.ObjectVal(map[string]cty.Value{
  1484  			"compute": cty.StringVal("value"),
  1485  		}),
  1486  	}
  1487  
  1488  	state := states.NewState()
  1489  	root := state.EnsureModule(addrs.RootModuleInstance)
  1490  	testSetResourceInstanceCurrent(root, "test_resource.a", `{"id":"a"}`, `provider["registry.terraform.io/hashicorp/test"]`)
  1491  
  1492  	ctx := testContext2(t, &ContextOpts{
  1493  		Providers: map[addrs.Provider]providers.Factory{
  1494  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1495  		},
  1496  	})
  1497  
  1498  	_, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
  1499  	if diags.HasErrors() {
  1500  		t.Fatalf("unexpected errors: %s", diags.Err())
  1501  	}
  1502  }
  1503  
  1504  // verify that create_before_destroy is updated in the state during refresh
  1505  func TestRefresh_updateLifecycle(t *testing.T) {
  1506  	state := states.NewState()
  1507  	root := state.EnsureModule(addrs.RootModuleInstance)
  1508  	root.SetResourceInstanceCurrent(
  1509  		addrs.Resource{
  1510  			Mode: addrs.ManagedResourceMode,
  1511  			Type: "aws_instance",
  1512  			Name: "bar",
  1513  		}.Instance(addrs.NoKey),
  1514  		&states.ResourceInstanceObjectSrc{
  1515  			Status:    states.ObjectReady,
  1516  			AttrsJSON: []byte(`{"id":"bar"}`),
  1517  		},
  1518  		addrs.AbsProviderConfig{
  1519  			Provider: addrs.NewDefaultProvider("aws"),
  1520  			Module:   addrs.RootModule,
  1521  		},
  1522  	)
  1523  
  1524  	m := testModuleInline(t, map[string]string{
  1525  		"main.tf": `
  1526  resource "aws_instance" "bar" {
  1527    lifecycle {
  1528      create_before_destroy = true
  1529    }
  1530  }
  1531  `,
  1532  	})
  1533  
  1534  	p := testProvider("aws")
  1535  
  1536  	ctx := testContext2(t, &ContextOpts{
  1537  		Providers: map[addrs.Provider]providers.Factory{
  1538  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1539  		},
  1540  	})
  1541  
  1542  	state, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
  1543  	if diags.HasErrors() {
  1544  		t.Fatalf("plan errors: %s", diags.Err())
  1545  	}
  1546  
  1547  	r := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.bar"))
  1548  	if !r.Current.CreateBeforeDestroy {
  1549  		t.Fatal("create_before_destroy not updated in instance state")
  1550  	}
  1551  }
  1552  
  1553  func TestContext2Refresh_dataSourceOrphan(t *testing.T) {
  1554  	m := testModuleInline(t, map[string]string{
  1555  		"main.tf": ``,
  1556  	})
  1557  
  1558  	state := states.NewState()
  1559  	root := state.EnsureModule(addrs.RootModuleInstance)
  1560  	root.SetResourceInstanceCurrent(
  1561  		addrs.Resource{
  1562  			Mode: addrs.DataResourceMode,
  1563  			Type: "test_data_source",
  1564  			Name: "foo",
  1565  		}.Instance(addrs.NoKey),
  1566  		&states.ResourceInstanceObjectSrc{
  1567  			Status:       states.ObjectReady,
  1568  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1569  			Dependencies: []addrs.ConfigResource{},
  1570  		},
  1571  		addrs.AbsProviderConfig{
  1572  			Provider: addrs.NewDefaultProvider("test"),
  1573  			Module:   addrs.RootModule,
  1574  		},
  1575  	)
  1576  	p := testProvider("test")
  1577  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
  1578  		resp.State = cty.NullVal(req.Config.Type())
  1579  		return
  1580  	}
  1581  
  1582  	ctx := testContext2(t, &ContextOpts{
  1583  		Providers: map[addrs.Provider]providers.Factory{
  1584  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1585  		},
  1586  	})
  1587  
  1588  	_, diags := ctx.Refresh(m, state, &PlanOpts{Mode: plans.NormalMode})
  1589  	if diags.HasErrors() {
  1590  		t.Fatal(diags.Err())
  1591  	}
  1592  
  1593  	if p.ReadResourceCalled {
  1594  		t.Fatal("there are no managed resources to read")
  1595  	}
  1596  
  1597  	if p.ReadDataSourceCalled {
  1598  		t.Fatal("orphaned data source instance should not be read")
  1599  	}
  1600  }