github.com/opentofu/opentofu@v1.7.1/internal/tofu/context_refresh_test.go (about)

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