github.com/jaredpalmer/terraform@v1.1.0-alpha20210908.0.20210911170307-88705c943a03/internal/terraform/context_refresh_test.go (about)

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