github.com/opentofu/opentofu@v1.7.1/internal/tofu/context_apply_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  	"bytes"
    10  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  	"log"
    14  	"reflect"
    15  	"runtime"
    16  	"sort"
    17  	"strings"
    18  	"sync"
    19  	"sync/atomic"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/davecgh/go-spew/spew"
    24  	"github.com/go-test/deep"
    25  	"github.com/google/go-cmp/cmp"
    26  	"github.com/zclconf/go-cty/cty"
    27  	"github.com/zclconf/go-cty/cty/gocty"
    28  
    29  	"github.com/opentofu/opentofu/internal/addrs"
    30  	"github.com/opentofu/opentofu/internal/configs"
    31  	"github.com/opentofu/opentofu/internal/configs/configschema"
    32  	"github.com/opentofu/opentofu/internal/configs/hcl2shim"
    33  	"github.com/opentofu/opentofu/internal/lang/marks"
    34  	"github.com/opentofu/opentofu/internal/plans"
    35  	"github.com/opentofu/opentofu/internal/providers"
    36  	"github.com/opentofu/opentofu/internal/provisioners"
    37  	"github.com/opentofu/opentofu/internal/states"
    38  	"github.com/opentofu/opentofu/internal/tfdiags"
    39  )
    40  
    41  func TestContext2Apply_basic(t *testing.T) {
    42  	m := testModule(t, "apply-good")
    43  	p := testProvider("aws")
    44  	p.PlanResourceChangeFn = testDiffFn
    45  	p.ApplyResourceChangeFn = testApplyFn
    46  	ctx := testContext2(t, &ContextOpts{
    47  		Providers: map[addrs.Provider]providers.Factory{
    48  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
    49  		},
    50  	})
    51  
    52  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
    53  	assertNoErrors(t, diags)
    54  
    55  	state, diags := ctx.Apply(plan, m)
    56  	if diags.HasErrors() {
    57  		t.Fatalf("diags: %s", diags.Err())
    58  	}
    59  
    60  	mod := state.RootModule()
    61  	if len(mod.Resources) < 2 {
    62  		t.Fatalf("bad: %#v", mod.Resources)
    63  	}
    64  
    65  	actual := strings.TrimSpace(state.String())
    66  	expected := strings.TrimSpace(testTofuApplyStr)
    67  	if actual != expected {
    68  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
    69  	}
    70  }
    71  
    72  func TestContext2Apply_stop(t *testing.T) {
    73  	t.Parallel()
    74  
    75  	m := testModule(t, "apply-stop")
    76  	stopCh := make(chan struct{})
    77  	waitCh := make(chan struct{})
    78  	stoppedCh := make(chan struct{})
    79  	stopCalled := uint32(0)
    80  	applyStopped := uint32(0)
    81  	p := &MockProvider{
    82  		GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{
    83  			ResourceTypes: map[string]providers.Schema{
    84  				"indefinite": {
    85  					Version: 1,
    86  					Block: &configschema.Block{
    87  						Attributes: map[string]*configschema.Attribute{
    88  							"result": {
    89  								Type:     cty.String,
    90  								Computed: true,
    91  							},
    92  						},
    93  					},
    94  				},
    95  			},
    96  		},
    97  		PlanResourceChangeFn: func(prcr providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
    98  			log.Printf("[TRACE] TestContext2Apply_stop: no-op PlanResourceChange")
    99  			return providers.PlanResourceChangeResponse{
   100  				PlannedState: cty.ObjectVal(map[string]cty.Value{
   101  					"result": cty.UnknownVal(cty.String),
   102  				}),
   103  			}
   104  		},
   105  		ApplyResourceChangeFn: func(arcr providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
   106  			// This will unblock the main test code once we reach this
   107  			// point, so that it'll then be guaranteed to call Stop
   108  			// while we're waiting in here.
   109  			close(waitCh)
   110  
   111  			log.Printf("[TRACE] TestContext2Apply_stop: ApplyResourceChange waiting for Stop call")
   112  			// This will block until StopFn closes this channel below.
   113  			<-stopCh
   114  			atomic.AddUint32(&applyStopped, 1)
   115  			// This unblocks StopFn below, thereby acknowledging the request
   116  			// to stop.
   117  			close(stoppedCh)
   118  			return providers.ApplyResourceChangeResponse{
   119  				NewState: cty.ObjectVal(map[string]cty.Value{
   120  					"result": cty.StringVal("complete"),
   121  				}),
   122  			}
   123  		},
   124  		StopFn: func() error {
   125  			// Closing this channel will unblock the channel read in
   126  			// ApplyResourceChangeFn above.
   127  			log.Printf("[TRACE] TestContext2Apply_stop: Stop called")
   128  			atomic.AddUint32(&stopCalled, 1)
   129  			close(stopCh)
   130  			// This will block until ApplyResourceChange has reacted to
   131  			// being stopped.
   132  			log.Printf("[TRACE] TestContext2Apply_stop: Waiting for ApplyResourceChange to react to being stopped")
   133  			<-stoppedCh
   134  			log.Printf("[TRACE] TestContext2Apply_stop: Stop is completing")
   135  			return nil
   136  		},
   137  	}
   138  
   139  	hook := &testHook{}
   140  	ctx := testContext2(t, &ContextOpts{
   141  		Hooks: []Hook{hook},
   142  		Providers: map[addrs.Provider]providers.Factory{
   143  			addrs.MustParseProviderSourceString("terraform.io/test/indefinite"): testProviderFuncFixed(p),
   144  		},
   145  	})
   146  
   147  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   148  	assertNoErrors(t, diags)
   149  
   150  	// We'll reset the hook events before we apply because we only care about
   151  	// the apply-time events.
   152  	hook.Calls = hook.Calls[:0]
   153  
   154  	// We'll apply in the background so that we can call Stop in the foreground.
   155  	stateCh := make(chan *states.State)
   156  	go func(plan *plans.Plan) {
   157  		state, _ := ctx.Apply(plan, m)
   158  		stateCh <- state
   159  	}(plan)
   160  
   161  	// We'll wait until the provider signals that we've reached the
   162  	// ApplyResourceChange function, so we can guarantee the expected
   163  	// order of operations so our hook events below will always match.
   164  	t.Log("waiting for the apply phase to get started")
   165  	<-waitCh
   166  
   167  	// This will block until the apply operation has unwound, so we should
   168  	// be able to observe all of the apply side-effects afterwards.
   169  	t.Log("waiting for ctx.Stop to return")
   170  	ctx.Stop()
   171  
   172  	t.Log("waiting for apply goroutine to return state")
   173  	state := <-stateCh
   174  
   175  	t.Log("apply is all complete")
   176  	if state == nil {
   177  		t.Fatalf("final state is nil")
   178  	}
   179  
   180  	if got, want := atomic.LoadUint32(&stopCalled), uint32(1); got != want {
   181  		t.Errorf("provider's Stop method was not called")
   182  	}
   183  	if got, want := atomic.LoadUint32(&applyStopped), uint32(1); got != want {
   184  		// This should not happen if things are working correctly but this is
   185  		// to catch weird situations such as if a bug in this test causes us
   186  		// to inadvertently stop OpenTofu before it reaches te apply phase,
   187  		// or if the apply operation fails in a way that causes it not to reach
   188  		// the ApplyResourceChange function.
   189  		t.Errorf("somehow provider's ApplyResourceChange didn't react to being stopped")
   190  	}
   191  
   192  	// Because we interrupted the apply phase while applying the resource,
   193  	// we should have halted immediately after we finished visiting that
   194  	// resource. We don't visit indefinite.bar at all.
   195  	gotEvents := hook.Calls
   196  	wantEvents := []*testHookCall{
   197  		{"PreDiff", "indefinite.foo"},
   198  		{"PostDiff", "indefinite.foo"},
   199  		{"PreApply", "indefinite.foo"},
   200  		{"PostApply", "indefinite.foo"},
   201  		{"PostStateUpdate", ""}, // State gets updated one more time to include the apply result.
   202  	}
   203  	// The "Stopping" event gets sent to the hook asynchronously from the others
   204  	// because it is triggered in the ctx.Stop call above, rather than from
   205  	// the goroutine where ctx.Apply was running, and therefore it doesn't
   206  	// appear in a guaranteed position in gotEvents. We already checked above
   207  	// that the provider's Stop method was called, so we'll just strip that
   208  	// event out of our gotEvents.
   209  	seenStopped := false
   210  	for i, call := range gotEvents {
   211  		if call.Action == "Stopping" {
   212  			seenStopped = true
   213  			// We'll shift up everything else in the slice to create the
   214  			// effect of the Stopping event not having been present at all,
   215  			// which should therefore make this slice match "wantEvents".
   216  			copy(gotEvents[i:], gotEvents[i+1:])
   217  			gotEvents = gotEvents[:len(gotEvents)-1]
   218  			break
   219  		}
   220  	}
   221  	if diff := cmp.Diff(wantEvents, gotEvents); diff != "" {
   222  		t.Errorf("wrong hook events\n%s", diff)
   223  	}
   224  	if !seenStopped {
   225  		t.Errorf("'Stopping' event did not get sent to the hook")
   226  	}
   227  
   228  	rov := state.OutputValue(addrs.OutputValue{Name: "result"}.Absolute(addrs.RootModuleInstance))
   229  	if rov != nil && rov.Value != cty.NilVal && !rov.Value.IsNull() {
   230  		t.Errorf("'result' output value unexpectedly populated: %#v", rov.Value)
   231  	}
   232  
   233  	resourceAddr := addrs.Resource{
   234  		Mode: addrs.ManagedResourceMode,
   235  		Type: "indefinite",
   236  		Name: "foo",
   237  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
   238  	rv := state.ResourceInstance(resourceAddr)
   239  	if rv == nil || rv.Current == nil {
   240  		t.Fatalf("no state entry for %s", resourceAddr)
   241  	}
   242  
   243  	resourceAddr.Resource.Resource.Name = "bar"
   244  	rv = state.ResourceInstance(resourceAddr)
   245  	if rv != nil && rv.Current != nil {
   246  		t.Fatalf("unexpected state entry for %s", resourceAddr)
   247  	}
   248  }
   249  
   250  func TestContext2Apply_unstable(t *testing.T) {
   251  	// This tests behavior when the configuration contains an unstable value,
   252  	// such as the result of uuid() or timestamp(), where each call produces
   253  	// a different result.
   254  	//
   255  	// This is an important case to test because we need to ensure that
   256  	// we don't re-call the function during the apply phase: the value should
   257  	// be fixed during plan
   258  
   259  	m := testModule(t, "apply-unstable")
   260  	p := testProvider("test")
   261  	p.PlanResourceChangeFn = testDiffFn
   262  	ctx := testContext2(t, &ContextOpts{
   263  		Providers: map[addrs.Provider]providers.Factory{
   264  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
   265  		},
   266  	})
   267  
   268  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   269  	if diags.HasErrors() {
   270  		t.Fatalf("unexpected error during Plan: %s", diags.Err())
   271  	}
   272  
   273  	addr := addrs.Resource{
   274  		Mode: addrs.ManagedResourceMode,
   275  		Type: "test_resource",
   276  		Name: "foo",
   277  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
   278  	schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
   279  	rds := plan.Changes.ResourceInstance(addr)
   280  	rd, err := rds.Decode(schema.ImpliedType())
   281  	if err != nil {
   282  		t.Fatal(err)
   283  	}
   284  	if rd.After.GetAttr("random").IsKnown() {
   285  		t.Fatalf("Attribute 'random' has known value %#v; should be unknown in plan", rd.After.GetAttr("random"))
   286  	}
   287  
   288  	state, diags := ctx.Apply(plan, m)
   289  	if diags.HasErrors() {
   290  		t.Fatalf("unexpected error during Apply: %s", diags.Err())
   291  	}
   292  
   293  	mod := state.Module(addr.Module)
   294  	rss := state.ResourceInstance(addr)
   295  
   296  	if len(mod.Resources) != 1 {
   297  		t.Fatalf("wrong number of resources %d; want 1", len(mod.Resources))
   298  	}
   299  
   300  	rs, err := rss.Current.Decode(schema.ImpliedType())
   301  	if err != nil {
   302  		t.Fatalf("decode error: %v", err)
   303  	}
   304  	got := rs.Value.GetAttr("random")
   305  	if !got.IsKnown() {
   306  		t.Fatalf("random is still unknown after apply")
   307  	}
   308  	if got, want := len(got.AsString()), 36; got != want {
   309  		t.Fatalf("random string has wrong length %d; want %d", got, want)
   310  	}
   311  }
   312  
   313  func TestContext2Apply_escape(t *testing.T) {
   314  	m := testModule(t, "apply-escape")
   315  	p := testProvider("aws")
   316  	p.PlanResourceChangeFn = testDiffFn
   317  	p.ApplyResourceChangeFn = testApplyFn
   318  	ctx := testContext2(t, &ContextOpts{
   319  		Providers: map[addrs.Provider]providers.Factory{
   320  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   321  		},
   322  	})
   323  
   324  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   325  	assertNoErrors(t, diags)
   326  
   327  	state, diags := ctx.Apply(plan, m)
   328  	if diags.HasErrors() {
   329  		t.Fatalf("diags: %s", diags.Err())
   330  	}
   331  
   332  	checkStateString(t, state, `
   333  aws_instance.bar:
   334    ID = foo
   335    provider = provider["registry.opentofu.org/hashicorp/aws"]
   336    foo = "bar"
   337    type = aws_instance
   338  `)
   339  }
   340  
   341  func TestContext2Apply_resourceCountOneList(t *testing.T) {
   342  	m := testModule(t, "apply-resource-count-one-list")
   343  	p := testProvider("null")
   344  	p.PlanResourceChangeFn = testDiffFn
   345  	p.ApplyResourceChangeFn = testApplyFn
   346  	ctx := testContext2(t, &ContextOpts{
   347  		Providers: map[addrs.Provider]providers.Factory{
   348  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   349  		},
   350  	})
   351  
   352  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   353  	assertNoErrors(t, diags)
   354  
   355  	state, diags := ctx.Apply(plan, m)
   356  	assertNoDiagnostics(t, diags)
   357  
   358  	got := strings.TrimSpace(state.String())
   359  	want := strings.TrimSpace(`null_resource.foo.0:
   360    ID = foo
   361    provider = provider["registry.opentofu.org/hashicorp/null"]
   362  
   363  Outputs:
   364  
   365  test = [foo]`)
   366  	if got != want {
   367  		t.Fatalf("got:\n%s\n\nwant:\n%s\n", got, want)
   368  	}
   369  }
   370  func TestContext2Apply_resourceCountZeroList(t *testing.T) {
   371  	m := testModule(t, "apply-resource-count-zero-list")
   372  	p := testProvider("null")
   373  	p.PlanResourceChangeFn = testDiffFn
   374  	ctx := testContext2(t, &ContextOpts{
   375  		Providers: map[addrs.Provider]providers.Factory{
   376  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   377  		},
   378  	})
   379  
   380  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   381  	assertNoErrors(t, diags)
   382  
   383  	state, diags := ctx.Apply(plan, m)
   384  	if diags.HasErrors() {
   385  		t.Fatalf("diags: %s", diags.Err())
   386  	}
   387  
   388  	got := strings.TrimSpace(state.String())
   389  	want := strings.TrimSpace(`<no state>
   390  Outputs:
   391  
   392  test = []`)
   393  	if got != want {
   394  		t.Fatalf("wrong state\n\ngot:\n%s\n\nwant:\n%s\n", got, want)
   395  	}
   396  }
   397  
   398  func TestContext2Apply_resourceDependsOnModule(t *testing.T) {
   399  	m := testModule(t, "apply-resource-depends-on-module")
   400  	p := testProvider("aws")
   401  	p.PlanResourceChangeFn = testDiffFn
   402  
   403  	// verify the apply happens in the correct order
   404  	var mu sync.Mutex
   405  	var order []string
   406  
   407  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   408  		ami := req.PlannedState.GetAttr("ami").AsString()
   409  		switch ami {
   410  		case "child":
   411  
   412  			// make the child slower than the parent
   413  			time.Sleep(50 * time.Millisecond)
   414  
   415  			mu.Lock()
   416  			order = append(order, "child")
   417  			mu.Unlock()
   418  		case "parent":
   419  			mu.Lock()
   420  			order = append(order, "parent")
   421  			mu.Unlock()
   422  		}
   423  
   424  		return testApplyFn(req)
   425  	}
   426  
   427  	ctx := testContext2(t, &ContextOpts{
   428  		Providers: map[addrs.Provider]providers.Factory{
   429  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   430  		},
   431  	})
   432  
   433  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   434  	assertNoErrors(t, diags)
   435  
   436  	state, diags := ctx.Apply(plan, m)
   437  	if diags.HasErrors() {
   438  		t.Fatalf("diags: %s", diags.Err())
   439  	}
   440  
   441  	if !reflect.DeepEqual(order, []string{"child", "parent"}) {
   442  		t.Fatal("resources applied out of order")
   443  	}
   444  
   445  	checkStateString(t, state, testTofuApplyResourceDependsOnModuleStr)
   446  }
   447  
   448  // Test that without a config, the Dependencies in the state are enough
   449  // to maintain proper ordering.
   450  func TestContext2Apply_resourceDependsOnModuleStateOnly(t *testing.T) {
   451  	m := testModule(t, "apply-resource-depends-on-module-empty")
   452  	p := testProvider("aws")
   453  	p.PlanResourceChangeFn = testDiffFn
   454  
   455  	state := states.NewState()
   456  	root := state.EnsureModule(addrs.RootModuleInstance)
   457  	root.SetResourceInstanceCurrent(
   458  		mustResourceInstanceAddr("aws_instance.a").Resource,
   459  		&states.ResourceInstanceObjectSrc{
   460  			Status:       states.ObjectReady,
   461  			AttrsJSON:    []byte(`{"id":"parent"}`),
   462  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.child")},
   463  		},
   464  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
   465  	)
   466  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
   467  	child.SetResourceInstanceCurrent(
   468  		mustResourceInstanceAddr("aws_instance.child").Resource,
   469  		&states.ResourceInstanceObjectSrc{
   470  			Status:    states.ObjectReady,
   471  			AttrsJSON: []byte(`{"id":"child"}`),
   472  		},
   473  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
   474  	)
   475  
   476  	{
   477  		// verify the apply happens in the correct order
   478  		var mu sync.Mutex
   479  		var order []string
   480  
   481  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   482  			id := req.PriorState.GetAttr("id")
   483  			if id.IsKnown() && id.AsString() == "parent" {
   484  				// make the dep slower than the parent
   485  				time.Sleep(50 * time.Millisecond)
   486  
   487  				mu.Lock()
   488  				order = append(order, "child")
   489  				mu.Unlock()
   490  			} else {
   491  				mu.Lock()
   492  				order = append(order, "parent")
   493  				mu.Unlock()
   494  			}
   495  
   496  			return testApplyFn(req)
   497  		}
   498  
   499  		ctx := testContext2(t, &ContextOpts{
   500  			Providers: map[addrs.Provider]providers.Factory{
   501  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   502  			},
   503  		})
   504  
   505  		plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   506  		assertNoErrors(t, diags)
   507  
   508  		state, diags := ctx.Apply(plan, m)
   509  		assertNoErrors(t, diags)
   510  
   511  		if !reflect.DeepEqual(order, []string{"child", "parent"}) {
   512  			t.Fatal("resources applied out of order")
   513  		}
   514  
   515  		checkStateString(t, state, "<no state>")
   516  	}
   517  }
   518  
   519  func TestContext2Apply_resourceDependsOnModuleDestroy(t *testing.T) {
   520  	m := testModule(t, "apply-resource-depends-on-module")
   521  	p := testProvider("aws")
   522  	p.PlanResourceChangeFn = testDiffFn
   523  
   524  	var globalState *states.State
   525  	{
   526  		ctx := testContext2(t, &ContextOpts{
   527  			Providers: map[addrs.Provider]providers.Factory{
   528  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   529  			},
   530  		})
   531  
   532  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   533  		assertNoErrors(t, diags)
   534  
   535  		state, diags := ctx.Apply(plan, m)
   536  		if diags.HasErrors() {
   537  			t.Fatalf("diags: %s", diags.Err())
   538  		}
   539  
   540  		globalState = state
   541  	}
   542  
   543  	{
   544  		// Wait for the dependency, sleep, and verify the graph never
   545  		// called a child.
   546  		var called int32
   547  		var checked bool
   548  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   549  			ami := req.PriorState.GetAttr("ami").AsString()
   550  			if ami == "parent" {
   551  				checked = true
   552  
   553  				// Sleep to allow parallel execution
   554  				time.Sleep(50 * time.Millisecond)
   555  
   556  				// Verify that called is 0 (dep not called)
   557  				if atomic.LoadInt32(&called) != 0 {
   558  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("module child should not be called"))
   559  					return resp
   560  				}
   561  			}
   562  
   563  			atomic.AddInt32(&called, 1)
   564  			return testApplyFn(req)
   565  		}
   566  
   567  		ctx := testContext2(t, &ContextOpts{
   568  			Providers: map[addrs.Provider]providers.Factory{
   569  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   570  			},
   571  		})
   572  
   573  		plan, diags := ctx.Plan(m, globalState, &PlanOpts{
   574  			Mode: plans.DestroyMode,
   575  		})
   576  		assertNoErrors(t, diags)
   577  
   578  		state, diags := ctx.Apply(plan, m)
   579  		if diags.HasErrors() {
   580  			t.Fatalf("diags: %s", diags.Err())
   581  		}
   582  
   583  		if !checked {
   584  			t.Fatal("should check")
   585  		}
   586  
   587  		checkStateString(t, state, `<no state>`)
   588  	}
   589  }
   590  
   591  func TestContext2Apply_resourceDependsOnModuleGrandchild(t *testing.T) {
   592  	m := testModule(t, "apply-resource-depends-on-module-deep")
   593  	p := testProvider("aws")
   594  	p.PlanResourceChangeFn = testDiffFn
   595  
   596  	{
   597  		// Wait for the dependency, sleep, and verify the graph never
   598  		// called a child.
   599  		var called int32
   600  		var checked bool
   601  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   602  			planned := req.PlannedState.AsValueMap()
   603  			if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" {
   604  				checked = true
   605  
   606  				// Sleep to allow parallel execution
   607  				time.Sleep(50 * time.Millisecond)
   608  
   609  				// Verify that called is 0 (dep not called)
   610  				if atomic.LoadInt32(&called) != 0 {
   611  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("aws_instance.a should not be called"))
   612  					return resp
   613  				}
   614  			}
   615  
   616  			atomic.AddInt32(&called, 1)
   617  			return testApplyFn(req)
   618  		}
   619  
   620  		ctx := testContext2(t, &ContextOpts{
   621  			Providers: map[addrs.Provider]providers.Factory{
   622  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   623  			},
   624  		})
   625  
   626  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   627  		assertNoErrors(t, diags)
   628  
   629  		state, diags := ctx.Apply(plan, m)
   630  		if diags.HasErrors() {
   631  			t.Fatalf("diags: %s", diags.Err())
   632  		}
   633  
   634  		if !checked {
   635  			t.Fatal("should check")
   636  		}
   637  
   638  		checkStateString(t, state, testTofuApplyResourceDependsOnModuleDeepStr)
   639  	}
   640  }
   641  
   642  func TestContext2Apply_resourceDependsOnModuleInModule(t *testing.T) {
   643  	m := testModule(t, "apply-resource-depends-on-module-in-module")
   644  	p := testProvider("aws")
   645  	p.PlanResourceChangeFn = testDiffFn
   646  
   647  	{
   648  		// Wait for the dependency, sleep, and verify the graph never
   649  		// called a child.
   650  		var called int32
   651  		var checked bool
   652  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   653  			planned := req.PlannedState.AsValueMap()
   654  			if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" {
   655  				checked = true
   656  
   657  				// Sleep to allow parallel execution
   658  				time.Sleep(50 * time.Millisecond)
   659  
   660  				// Verify that called is 0 (dep not called)
   661  				if atomic.LoadInt32(&called) != 0 {
   662  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("something else was applied before grandchild; grandchild should be first"))
   663  					return resp
   664  				}
   665  			}
   666  
   667  			atomic.AddInt32(&called, 1)
   668  			return testApplyFn(req)
   669  		}
   670  
   671  		ctx := testContext2(t, &ContextOpts{
   672  			Providers: map[addrs.Provider]providers.Factory{
   673  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   674  			},
   675  		})
   676  
   677  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   678  		assertNoErrors(t, diags)
   679  
   680  		state, diags := ctx.Apply(plan, m)
   681  		if diags.HasErrors() {
   682  			t.Fatalf("diags: %s", diags.Err())
   683  		}
   684  
   685  		if !checked {
   686  			t.Fatal("should check")
   687  		}
   688  
   689  		checkStateString(t, state, testTofuApplyResourceDependsOnModuleInModuleStr)
   690  	}
   691  }
   692  
   693  func TestContext2Apply_mapVarBetweenModules(t *testing.T) {
   694  	m := testModule(t, "apply-map-var-through-module")
   695  	p := testProvider("null")
   696  	p.PlanResourceChangeFn = testDiffFn
   697  	p.ApplyResourceChangeFn = testApplyFn
   698  	ctx := testContext2(t, &ContextOpts{
   699  		Providers: map[addrs.Provider]providers.Factory{
   700  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   701  		},
   702  	})
   703  
   704  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
   705  	assertNoErrors(t, diags)
   706  
   707  	state, diags := ctx.Apply(plan, m)
   708  	if diags.HasErrors() {
   709  		t.Fatalf("diags: %s", diags.Err())
   710  	}
   711  
   712  	actual := strings.TrimSpace(state.String())
   713  	expected := strings.TrimSpace(`<no state>
   714  Outputs:
   715  
   716  amis_from_module = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }
   717  
   718  module.test:
   719    null_resource.noop:
   720      ID = foo
   721      provider = provider["registry.opentofu.org/hashicorp/null"]
   722  
   723    Outputs:
   724  
   725    amis_out = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }`)
   726  	if actual != expected {
   727  		t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual)
   728  	}
   729  }
   730  
   731  func TestContext2Apply_refCount(t *testing.T) {
   732  	m := testModule(t, "apply-ref-count")
   733  	p := testProvider("aws")
   734  	p.PlanResourceChangeFn = testDiffFn
   735  	p.ApplyResourceChangeFn = testApplyFn
   736  	ctx := testContext2(t, &ContextOpts{
   737  		Providers: map[addrs.Provider]providers.Factory{
   738  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   739  		},
   740  	})
   741  
   742  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   743  	assertNoErrors(t, diags)
   744  
   745  	state, diags := ctx.Apply(plan, m)
   746  	if diags.HasErrors() {
   747  		t.Fatalf("diags: %s", diags.Err())
   748  	}
   749  
   750  	mod := state.RootModule()
   751  	if len(mod.Resources) < 2 {
   752  		t.Fatalf("bad: %#v", mod.Resources)
   753  	}
   754  
   755  	actual := strings.TrimSpace(state.String())
   756  	expected := strings.TrimSpace(testTofuApplyRefCountStr)
   757  	if actual != expected {
   758  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   759  	}
   760  }
   761  
   762  func TestContext2Apply_providerAlias(t *testing.T) {
   763  	m := testModule(t, "apply-provider-alias")
   764  
   765  	// Each provider instance must be completely independent to ensure that we
   766  	// are verifying the correct state of each.
   767  	p := func() (providers.Interface, error) {
   768  		p := testProvider("aws")
   769  		p.PlanResourceChangeFn = testDiffFn
   770  		p.ApplyResourceChangeFn = testApplyFn
   771  		return p, nil
   772  	}
   773  	ctx := testContext2(t, &ContextOpts{
   774  		Providers: map[addrs.Provider]providers.Factory{
   775  			addrs.NewDefaultProvider("aws"): p,
   776  		},
   777  	})
   778  
   779  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   780  	assertNoErrors(t, diags)
   781  
   782  	state, diags := ctx.Apply(plan, m)
   783  	if diags.HasErrors() {
   784  		t.Fatalf("diags: %s", diags.Err())
   785  	}
   786  
   787  	mod := state.RootModule()
   788  	if len(mod.Resources) < 2 {
   789  		t.Fatalf("bad: %#v", mod.Resources)
   790  	}
   791  
   792  	actual := strings.TrimSpace(state.String())
   793  	expected := strings.TrimSpace(testTofuApplyProviderAliasStr)
   794  	if actual != expected {
   795  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   796  	}
   797  }
   798  
   799  // Two providers that are configured should both be configured prior to apply
   800  func TestContext2Apply_providerAliasConfigure(t *testing.T) {
   801  	m := testModule(t, "apply-provider-alias-configure")
   802  
   803  	// Each provider instance must be completely independent to ensure that we
   804  	// are verifying the correct state of each.
   805  	p := func() (providers.Interface, error) {
   806  		p := testProvider("another")
   807  		p.ApplyResourceChangeFn = testApplyFn
   808  		p.PlanResourceChangeFn = testDiffFn
   809  		return p, nil
   810  	}
   811  
   812  	ctx := testContext2(t, &ContextOpts{
   813  		Providers: map[addrs.Provider]providers.Factory{
   814  			addrs.NewDefaultProvider("another"): p,
   815  		},
   816  	})
   817  
   818  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   819  	if diags.HasErrors() {
   820  		t.Fatalf("diags: %s", diags.Err())
   821  	} else {
   822  		t.Logf(legacyDiffComparisonString(plan.Changes))
   823  	}
   824  
   825  	// Configure to record calls AFTER Plan above
   826  	var configCount int32
   827  	p = func() (providers.Interface, error) {
   828  		p := testProvider("another")
   829  		p.ApplyResourceChangeFn = testApplyFn
   830  		p.PlanResourceChangeFn = testDiffFn
   831  		p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
   832  			atomic.AddInt32(&configCount, 1)
   833  
   834  			foo := req.Config.GetAttr("foo").AsString()
   835  			if foo != "bar" {
   836  				resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("foo: %#v", foo))
   837  			}
   838  
   839  			return
   840  		}
   841  		return p, nil
   842  	}
   843  
   844  	ctx = testContext2(t, &ContextOpts{
   845  		Providers: map[addrs.Provider]providers.Factory{
   846  			addrs.NewDefaultProvider("another"): p,
   847  		},
   848  	})
   849  
   850  	state, diags := ctx.Apply(plan, m)
   851  	if diags.HasErrors() {
   852  		t.Fatalf("diags: %s", diags.Err())
   853  	}
   854  
   855  	if configCount != 2 {
   856  		t.Fatalf("provider config expected 2 calls, got: %d", configCount)
   857  	}
   858  
   859  	actual := strings.TrimSpace(state.String())
   860  	expected := strings.TrimSpace(testTofuApplyProviderAliasConfigStr)
   861  	if actual != expected {
   862  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   863  	}
   864  }
   865  
   866  // GH-2870
   867  func TestContext2Apply_providerWarning(t *testing.T) {
   868  	m := testModule(t, "apply-provider-warning")
   869  	p := testProvider("aws")
   870  	p.PlanResourceChangeFn = testDiffFn
   871  	p.ApplyResourceChangeFn = testApplyFn
   872  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
   873  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("just a warning"))
   874  		return
   875  	}
   876  	ctx := testContext2(t, &ContextOpts{
   877  		Providers: map[addrs.Provider]providers.Factory{
   878  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   879  		},
   880  	})
   881  
   882  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   883  	assertNoErrors(t, diags)
   884  
   885  	state, diags := ctx.Apply(plan, m)
   886  	if diags.HasErrors() {
   887  		t.Fatalf("diags: %s", diags.Err())
   888  	}
   889  
   890  	actual := strings.TrimSpace(state.String())
   891  	expected := strings.TrimSpace(`
   892  aws_instance.foo:
   893    ID = foo
   894    provider = provider["registry.opentofu.org/hashicorp/aws"]
   895    type = aws_instance
   896  	`)
   897  	if actual != expected {
   898  		t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected)
   899  	}
   900  
   901  	if !p.ConfigureProviderCalled {
   902  		t.Fatalf("provider Configure() was never called!")
   903  	}
   904  }
   905  
   906  func TestContext2Apply_emptyModule(t *testing.T) {
   907  	// A module with only outputs (no resources)
   908  	m := testModule(t, "apply-empty-module")
   909  	p := testProvider("aws")
   910  	p.PlanResourceChangeFn = testDiffFn
   911  	ctx := testContext2(t, &ContextOpts{
   912  		Providers: map[addrs.Provider]providers.Factory{
   913  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   914  		},
   915  	})
   916  
   917  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   918  	assertNoErrors(t, diags)
   919  
   920  	state, diags := ctx.Apply(plan, m)
   921  	if diags.HasErrors() {
   922  		t.Fatalf("diags: %s", diags.Err())
   923  	}
   924  
   925  	actual := strings.TrimSpace(state.String())
   926  	actual = strings.Replace(actual, "  ", "", -1)
   927  	expected := strings.TrimSpace(testTofuApplyEmptyModuleStr)
   928  	if actual != expected {
   929  		t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected)
   930  	}
   931  }
   932  
   933  func TestContext2Apply_createBeforeDestroy(t *testing.T) {
   934  	m := testModule(t, "apply-good-create-before")
   935  	p := testProvider("aws")
   936  	p.PlanResourceChangeFn = testDiffFn
   937  	p.ApplyResourceChangeFn = testApplyFn
   938  	state := states.NewState()
   939  	root := state.EnsureModule(addrs.RootModuleInstance)
   940  	root.SetResourceInstanceCurrent(
   941  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   942  		&states.ResourceInstanceObjectSrc{
   943  			Status:    states.ObjectReady,
   944  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
   945  		},
   946  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
   947  	)
   948  	ctx := testContext2(t, &ContextOpts{
   949  		Providers: map[addrs.Provider]providers.Factory{
   950  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   951  		},
   952  	})
   953  
   954  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   955  	if diags.HasErrors() {
   956  		t.Fatalf("diags: %s", diags.Err())
   957  	} else {
   958  		t.Logf(legacyDiffComparisonString(plan.Changes))
   959  	}
   960  
   961  	state, diags = ctx.Apply(plan, m)
   962  	if diags.HasErrors() {
   963  		t.Fatalf("diags: %s", diags.Err())
   964  	}
   965  
   966  	mod := state.RootModule()
   967  	if got, want := len(mod.Resources), 1; got != want {
   968  		t.Logf("state:\n%s", state)
   969  		t.Fatalf("wrong number of resources %d; want %d", got, want)
   970  	}
   971  
   972  	actual := strings.TrimSpace(state.String())
   973  	expected := strings.TrimSpace(testTofuApplyCreateBeforeStr)
   974  	if actual != expected {
   975  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
   976  	}
   977  }
   978  
   979  func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) {
   980  	m := testModule(t, "apply-good-create-before-update")
   981  	p := testProvider("aws")
   982  	p.PlanResourceChangeFn = testDiffFn
   983  
   984  	// signal that resource foo has started applying
   985  	fooChan := make(chan struct{})
   986  
   987  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   988  		id := req.PriorState.GetAttr("id").AsString()
   989  		switch id {
   990  		case "bar":
   991  			select {
   992  			case <-fooChan:
   993  				resp.Diagnostics = resp.Diagnostics.Append(errors.New("bar must be updated before foo is destroyed"))
   994  				return resp
   995  			case <-time.After(100 * time.Millisecond):
   996  				// wait a moment to ensure that foo is not going to be destroyed first
   997  			}
   998  		case "foo":
   999  			close(fooChan)
  1000  		}
  1001  
  1002  		return testApplyFn(req)
  1003  	}
  1004  
  1005  	state := states.NewState()
  1006  	root := state.EnsureModule(addrs.RootModuleInstance)
  1007  	fooAddr := mustResourceInstanceAddr("aws_instance.foo")
  1008  	root.SetResourceInstanceCurrent(
  1009  		fooAddr.Resource,
  1010  		&states.ResourceInstanceObjectSrc{
  1011  			Status:              states.ObjectReady,
  1012  			AttrsJSON:           []byte(`{"id":"foo","foo":"bar"}`),
  1013  			CreateBeforeDestroy: true,
  1014  		},
  1015  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1016  	)
  1017  	root.SetResourceInstanceCurrent(
  1018  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1019  		&states.ResourceInstanceObjectSrc{
  1020  			Status:              states.ObjectReady,
  1021  			AttrsJSON:           []byte(`{"id":"bar","foo":"bar"}`),
  1022  			CreateBeforeDestroy: true,
  1023  			Dependencies:        []addrs.ConfigResource{fooAddr.ContainingResource().Config()},
  1024  		},
  1025  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1026  	)
  1027  
  1028  	ctx := testContext2(t, &ContextOpts{
  1029  		Providers: map[addrs.Provider]providers.Factory{
  1030  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1031  		},
  1032  	})
  1033  
  1034  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1035  	if diags.HasErrors() {
  1036  		t.Fatalf("diags: %s", diags.Err())
  1037  	} else {
  1038  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1039  	}
  1040  
  1041  	state, diags = ctx.Apply(plan, m)
  1042  	if diags.HasErrors() {
  1043  		t.Fatalf("diags: %s", diags.Err())
  1044  	}
  1045  
  1046  	mod := state.RootModule()
  1047  	if len(mod.Resources) != 1 {
  1048  		t.Fatalf("bad: %s", state)
  1049  	}
  1050  
  1051  	actual := strings.TrimSpace(state.String())
  1052  	expected := strings.TrimSpace(testTofuApplyCreateBeforeUpdateStr)
  1053  	if actual != expected {
  1054  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1055  	}
  1056  }
  1057  
  1058  // This tests that when a CBD resource depends on a non-CBD resource,
  1059  // we can still properly apply changes that require new for both.
  1060  func TestContext2Apply_createBeforeDestroy_dependsNonCBD(t *testing.T) {
  1061  	m := testModule(t, "apply-cbd-depends-non-cbd")
  1062  	p := testProvider("aws")
  1063  	p.PlanResourceChangeFn = testDiffFn
  1064  	p.ApplyResourceChangeFn = testApplyFn
  1065  
  1066  	state := states.NewState()
  1067  	root := state.EnsureModule(addrs.RootModuleInstance)
  1068  	root.SetResourceInstanceCurrent(
  1069  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1070  		&states.ResourceInstanceObjectSrc{
  1071  			Status:    states.ObjectReady,
  1072  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
  1073  		},
  1074  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1075  	)
  1076  	root.SetResourceInstanceCurrent(
  1077  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1078  		&states.ResourceInstanceObjectSrc{
  1079  			Status:    states.ObjectReady,
  1080  			AttrsJSON: []byte(`{"id":"foo", "require_new": "abc"}`),
  1081  		},
  1082  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1083  	)
  1084  
  1085  	ctx := testContext2(t, &ContextOpts{
  1086  		Providers: map[addrs.Provider]providers.Factory{
  1087  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1088  		},
  1089  	})
  1090  
  1091  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1092  	if diags.HasErrors() {
  1093  		t.Fatalf("diags: %s", diags.Err())
  1094  	} else {
  1095  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1096  	}
  1097  
  1098  	state, diags = ctx.Apply(plan, m)
  1099  	if diags.HasErrors() {
  1100  		t.Fatalf("diags: %s", diags.Err())
  1101  	}
  1102  
  1103  	checkStateString(t, state, `
  1104  aws_instance.bar:
  1105    ID = foo
  1106    provider = provider["registry.opentofu.org/hashicorp/aws"]
  1107    require_new = yes
  1108    type = aws_instance
  1109    value = foo
  1110  
  1111    Dependencies:
  1112      aws_instance.foo
  1113  aws_instance.foo:
  1114    ID = foo
  1115    provider = provider["registry.opentofu.org/hashicorp/aws"]
  1116    require_new = yes
  1117    type = aws_instance
  1118  	`)
  1119  }
  1120  
  1121  func TestContext2Apply_createBeforeDestroy_hook(t *testing.T) {
  1122  	h := new(MockHook)
  1123  	m := testModule(t, "apply-good-create-before")
  1124  	p := testProvider("aws")
  1125  	p.PlanResourceChangeFn = testDiffFn
  1126  	p.ApplyResourceChangeFn = testApplyFn
  1127  	state := states.NewState()
  1128  	root := state.EnsureModule(addrs.RootModuleInstance)
  1129  	root.SetResourceInstanceCurrent(
  1130  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1131  		&states.ResourceInstanceObjectSrc{
  1132  			Status:    states.ObjectReady,
  1133  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
  1134  		},
  1135  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1136  	)
  1137  
  1138  	var actual []cty.Value
  1139  	var actualLock sync.Mutex
  1140  	h.PostApplyFn = func(addr addrs.AbsResourceInstance, gen states.Generation, sv cty.Value, e error) (HookAction, error) {
  1141  		actualLock.Lock()
  1142  
  1143  		defer actualLock.Unlock()
  1144  		actual = append(actual, sv)
  1145  		return HookActionContinue, nil
  1146  	}
  1147  
  1148  	ctx := testContext2(t, &ContextOpts{
  1149  		Hooks: []Hook{h},
  1150  		Providers: map[addrs.Provider]providers.Factory{
  1151  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1152  		},
  1153  	})
  1154  
  1155  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1156  	if diags.HasErrors() {
  1157  		t.Fatalf("diags: %s", diags.Err())
  1158  	} else {
  1159  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1160  	}
  1161  
  1162  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1163  		t.Fatalf("apply errors: %s", diags.Err())
  1164  	}
  1165  
  1166  	expected := []cty.Value{
  1167  		cty.ObjectVal(map[string]cty.Value{
  1168  			"id":          cty.StringVal("foo"),
  1169  			"require_new": cty.StringVal("xyz"),
  1170  			"type":        cty.StringVal("aws_instance"),
  1171  		}),
  1172  		cty.NullVal(cty.DynamicPseudoType),
  1173  	}
  1174  
  1175  	cmpOpt := cmp.Transformer("ctyshim", hcl2shim.ConfigValueFromHCL2)
  1176  	if !cmp.Equal(actual, expected, cmpOpt) {
  1177  		t.Fatalf("wrong state snapshot sequence\n%s", cmp.Diff(expected, actual, cmpOpt))
  1178  	}
  1179  }
  1180  
  1181  // Test that we can perform an apply with CBD in a count with deposed instances.
  1182  func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) {
  1183  	m := testModule(t, "apply-cbd-count")
  1184  	p := testProvider("aws")
  1185  	p.PlanResourceChangeFn = testDiffFn
  1186  	p.ApplyResourceChangeFn = testApplyFn
  1187  
  1188  	state := states.NewState()
  1189  	root := state.EnsureModule(addrs.RootModuleInstance)
  1190  	root.SetResourceInstanceCurrent(
  1191  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  1192  		&states.ResourceInstanceObjectSrc{
  1193  			Status:    states.ObjectTainted,
  1194  			AttrsJSON: []byte(`{"id":"bar"}`),
  1195  		},
  1196  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1197  	)
  1198  	root.SetResourceInstanceDeposed(
  1199  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  1200  		states.NewDeposedKey(),
  1201  		&states.ResourceInstanceObjectSrc{
  1202  			Status:    states.ObjectTainted,
  1203  			AttrsJSON: []byte(`{"id":"foo"}`),
  1204  		},
  1205  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1206  	)
  1207  	root.SetResourceInstanceCurrent(
  1208  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  1209  		&states.ResourceInstanceObjectSrc{
  1210  			Status:    states.ObjectTainted,
  1211  			AttrsJSON: []byte(`{"id":"bar"}`),
  1212  		},
  1213  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1214  	)
  1215  	root.SetResourceInstanceDeposed(
  1216  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  1217  		states.NewDeposedKey(),
  1218  		&states.ResourceInstanceObjectSrc{
  1219  			Status:    states.ObjectTainted,
  1220  			AttrsJSON: []byte(`{"id":"bar"}`),
  1221  		},
  1222  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1223  	)
  1224  
  1225  	ctx := testContext2(t, &ContextOpts{
  1226  		Providers: map[addrs.Provider]providers.Factory{
  1227  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1228  		},
  1229  	})
  1230  
  1231  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1232  	if diags.HasErrors() {
  1233  		t.Fatalf("diags: %s", diags.Err())
  1234  	} else {
  1235  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1236  	}
  1237  
  1238  	state, diags = ctx.Apply(plan, m)
  1239  	if diags.HasErrors() {
  1240  		t.Fatalf("diags: %s", diags.Err())
  1241  	}
  1242  
  1243  	checkStateString(t, state, `
  1244  aws_instance.bar.0:
  1245    ID = foo
  1246    provider = provider["registry.opentofu.org/hashicorp/aws"]
  1247    foo = bar
  1248    type = aws_instance
  1249  aws_instance.bar.1:
  1250    ID = foo
  1251    provider = provider["registry.opentofu.org/hashicorp/aws"]
  1252    foo = bar
  1253    type = aws_instance
  1254  	`)
  1255  }
  1256  
  1257  // Test that when we have a deposed instance but a good primary, we still
  1258  // destroy the deposed instance.
  1259  func TestContext2Apply_createBeforeDestroy_deposedOnly(t *testing.T) {
  1260  	m := testModule(t, "apply-cbd-deposed-only")
  1261  	p := testProvider("aws")
  1262  	p.PlanResourceChangeFn = testDiffFn
  1263  	p.ApplyResourceChangeFn = testApplyFn
  1264  
  1265  	state := states.NewState()
  1266  	root := state.EnsureModule(addrs.RootModuleInstance)
  1267  	root.SetResourceInstanceCurrent(
  1268  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1269  		&states.ResourceInstanceObjectSrc{
  1270  			Status:    states.ObjectReady,
  1271  			AttrsJSON: []byte(`{"id":"bar"}`),
  1272  		},
  1273  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1274  	)
  1275  	root.SetResourceInstanceDeposed(
  1276  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1277  		states.NewDeposedKey(),
  1278  		&states.ResourceInstanceObjectSrc{
  1279  			Status:    states.ObjectTainted,
  1280  			AttrsJSON: []byte(`{"id":"foo"}`),
  1281  		},
  1282  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1283  	)
  1284  
  1285  	ctx := testContext2(t, &ContextOpts{
  1286  		Providers: map[addrs.Provider]providers.Factory{
  1287  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1288  		},
  1289  	})
  1290  
  1291  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1292  	if diags.HasErrors() {
  1293  		t.Fatalf("diags: %s", diags.Err())
  1294  	} else {
  1295  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1296  	}
  1297  
  1298  	state, diags = ctx.Apply(plan, m)
  1299  	if diags.HasErrors() {
  1300  		t.Fatalf("diags: %s", diags.Err())
  1301  	}
  1302  
  1303  	checkStateString(t, state, `
  1304  aws_instance.bar:
  1305    ID = bar
  1306    provider = provider["registry.opentofu.org/hashicorp/aws"]
  1307    type = aws_instance
  1308  	`)
  1309  }
  1310  
  1311  func TestContext2Apply_destroyComputed(t *testing.T) {
  1312  	m := testModule(t, "apply-destroy-computed")
  1313  	p := testProvider("aws")
  1314  	p.PlanResourceChangeFn = testDiffFn
  1315  	state := states.NewState()
  1316  	root := state.EnsureModule(addrs.RootModuleInstance)
  1317  	root.SetResourceInstanceCurrent(
  1318  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1319  		&states.ResourceInstanceObjectSrc{
  1320  			Status:    states.ObjectReady,
  1321  			AttrsJSON: []byte(`{"id":"foo", "output": "value"}`),
  1322  		},
  1323  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1324  	)
  1325  	ctx := testContext2(t, &ContextOpts{
  1326  		Providers: map[addrs.Provider]providers.Factory{
  1327  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1328  		},
  1329  	})
  1330  
  1331  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1332  		Mode: plans.DestroyMode,
  1333  	})
  1334  	if diags.HasErrors() {
  1335  		logDiagnostics(t, diags)
  1336  		t.Fatal("plan failed")
  1337  	} else {
  1338  		t.Logf("plan:\n\n%s", legacyDiffComparisonString(plan.Changes))
  1339  	}
  1340  
  1341  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1342  		logDiagnostics(t, diags)
  1343  		t.Fatal("apply failed")
  1344  	}
  1345  }
  1346  
  1347  // Test that the destroy operation uses depends_on as a source of ordering.
  1348  func TestContext2Apply_destroyDependsOn(t *testing.T) {
  1349  	// It is possible for this to be racy, so we loop a number of times
  1350  	// just to check.
  1351  	for i := 0; i < 10; i++ {
  1352  		testContext2Apply_destroyDependsOn(t)
  1353  	}
  1354  }
  1355  
  1356  func testContext2Apply_destroyDependsOn(t *testing.T) {
  1357  	m := testModule(t, "apply-destroy-depends-on")
  1358  	p := testProvider("aws")
  1359  	p.PlanResourceChangeFn = testDiffFn
  1360  
  1361  	state := states.NewState()
  1362  	root := state.EnsureModule(addrs.RootModuleInstance)
  1363  	root.SetResourceInstanceCurrent(
  1364  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1365  		&states.ResourceInstanceObjectSrc{
  1366  			Status:    states.ObjectReady,
  1367  			AttrsJSON: []byte(`{"id":"bar"}`),
  1368  		},
  1369  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1370  	)
  1371  	root.SetResourceInstanceCurrent(
  1372  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1373  		&states.ResourceInstanceObjectSrc{
  1374  			Status:       states.ObjectReady,
  1375  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1376  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
  1377  		},
  1378  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1379  	)
  1380  
  1381  	// Record the order we see Apply
  1382  	var actual []string
  1383  	var actualLock sync.Mutex
  1384  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1385  		actualLock.Lock()
  1386  		defer actualLock.Unlock()
  1387  		id := req.PriorState.GetAttr("id").AsString()
  1388  		actual = append(actual, id)
  1389  
  1390  		return testApplyFn(req)
  1391  	}
  1392  
  1393  	ctx := testContext2(t, &ContextOpts{
  1394  		Providers: map[addrs.Provider]providers.Factory{
  1395  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1396  		},
  1397  		Parallelism: 1, // To check ordering
  1398  	})
  1399  
  1400  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1401  		Mode: plans.DestroyMode,
  1402  	})
  1403  	assertNoErrors(t, diags)
  1404  
  1405  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1406  		t.Fatalf("apply errors: %s", diags.Err())
  1407  	}
  1408  
  1409  	expected := []string{"foo", "bar"}
  1410  	if !reflect.DeepEqual(actual, expected) {
  1411  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1412  	}
  1413  }
  1414  
  1415  // Test that destroy ordering is correct with dependencies only
  1416  // in the state.
  1417  func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) {
  1418  	newState := states.NewState()
  1419  	root := newState.EnsureModule(addrs.RootModuleInstance)
  1420  	root.SetResourceInstanceCurrent(
  1421  		addrs.Resource{
  1422  			Mode: addrs.ManagedResourceMode,
  1423  			Type: "aws_instance",
  1424  			Name: "foo",
  1425  		}.Instance(addrs.NoKey),
  1426  		&states.ResourceInstanceObjectSrc{
  1427  			Status:       states.ObjectReady,
  1428  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1429  			Dependencies: []addrs.ConfigResource{},
  1430  		},
  1431  		addrs.AbsProviderConfig{
  1432  			Provider: addrs.NewDefaultProvider("aws"),
  1433  			Module:   addrs.RootModule,
  1434  		},
  1435  	)
  1436  	root.SetResourceInstanceCurrent(
  1437  		addrs.Resource{
  1438  			Mode: addrs.ManagedResourceMode,
  1439  			Type: "aws_instance",
  1440  			Name: "bar",
  1441  		}.Instance(addrs.NoKey),
  1442  		&states.ResourceInstanceObjectSrc{
  1443  			Status:    states.ObjectReady,
  1444  			AttrsJSON: []byte(`{"id":"bar"}`),
  1445  			Dependencies: []addrs.ConfigResource{
  1446  				{
  1447  					Resource: addrs.Resource{
  1448  						Mode: addrs.ManagedResourceMode,
  1449  						Type: "aws_instance",
  1450  						Name: "foo",
  1451  					},
  1452  					Module: root.Addr.Module(),
  1453  				},
  1454  			},
  1455  		},
  1456  		addrs.AbsProviderConfig{
  1457  			Provider: addrs.NewDefaultProvider("aws"),
  1458  			Module:   addrs.RootModule,
  1459  		},
  1460  	)
  1461  
  1462  	// It is possible for this to be racy, so we loop a number of times
  1463  	// just to check.
  1464  	for i := 0; i < 10; i++ {
  1465  		t.Run("new", func(t *testing.T) {
  1466  			testContext2Apply_destroyDependsOnStateOnly(t, newState)
  1467  		})
  1468  	}
  1469  }
  1470  
  1471  func testContext2Apply_destroyDependsOnStateOnly(t *testing.T, state *states.State) {
  1472  	state = state.DeepCopy()
  1473  	m := testModule(t, "empty")
  1474  	p := testProvider("aws")
  1475  	p.PlanResourceChangeFn = testDiffFn
  1476  	// Record the order we see Apply
  1477  	var actual []string
  1478  	var actualLock sync.Mutex
  1479  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1480  		actualLock.Lock()
  1481  		defer actualLock.Unlock()
  1482  		id := req.PriorState.GetAttr("id").AsString()
  1483  		actual = append(actual, id)
  1484  		return testApplyFn(req)
  1485  	}
  1486  
  1487  	ctx := testContext2(t, &ContextOpts{
  1488  		Providers: map[addrs.Provider]providers.Factory{
  1489  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1490  		},
  1491  		Parallelism: 1, // To check ordering
  1492  	})
  1493  
  1494  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1495  		Mode: plans.DestroyMode,
  1496  	})
  1497  	assertNoErrors(t, diags)
  1498  
  1499  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1500  		t.Fatalf("apply errors: %s", diags.Err())
  1501  	}
  1502  
  1503  	expected := []string{"bar", "foo"}
  1504  	if !reflect.DeepEqual(actual, expected) {
  1505  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1506  	}
  1507  }
  1508  
  1509  // Test that destroy ordering is correct with dependencies only
  1510  // in the state within a module (GH-11749)
  1511  func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) {
  1512  	newState := states.NewState()
  1513  	child := newState.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1514  	child.SetResourceInstanceCurrent(
  1515  		addrs.Resource{
  1516  			Mode: addrs.ManagedResourceMode,
  1517  			Type: "aws_instance",
  1518  			Name: "foo",
  1519  		}.Instance(addrs.NoKey),
  1520  		&states.ResourceInstanceObjectSrc{
  1521  			Status:       states.ObjectReady,
  1522  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1523  			Dependencies: []addrs.ConfigResource{},
  1524  		},
  1525  		addrs.AbsProviderConfig{
  1526  			Provider: addrs.NewDefaultProvider("aws"),
  1527  			Module:   addrs.RootModule,
  1528  		},
  1529  	)
  1530  	child.SetResourceInstanceCurrent(
  1531  		addrs.Resource{
  1532  			Mode: addrs.ManagedResourceMode,
  1533  			Type: "aws_instance",
  1534  			Name: "bar",
  1535  		}.Instance(addrs.NoKey),
  1536  		&states.ResourceInstanceObjectSrc{
  1537  			Status:    states.ObjectReady,
  1538  			AttrsJSON: []byte(`{"id":"bar"}`),
  1539  			Dependencies: []addrs.ConfigResource{
  1540  				{
  1541  					Resource: addrs.Resource{
  1542  						Mode: addrs.ManagedResourceMode,
  1543  						Type: "aws_instance",
  1544  						Name: "foo",
  1545  					},
  1546  					Module: child.Addr.Module(),
  1547  				},
  1548  			},
  1549  		},
  1550  		addrs.AbsProviderConfig{
  1551  			Provider: addrs.NewDefaultProvider("aws"),
  1552  			Module:   addrs.RootModule,
  1553  		},
  1554  	)
  1555  
  1556  	// It is possible for this to be racy, so we loop a number of times
  1557  	// just to check.
  1558  	for i := 0; i < 10; i++ {
  1559  		t.Run("new", func(t *testing.T) {
  1560  			testContext2Apply_destroyDependsOnStateOnlyModule(t, newState)
  1561  		})
  1562  	}
  1563  }
  1564  
  1565  func testContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T, state *states.State) {
  1566  	state = state.DeepCopy()
  1567  	m := testModule(t, "empty")
  1568  	p := testProvider("aws")
  1569  	p.PlanResourceChangeFn = testDiffFn
  1570  
  1571  	// Record the order we see Apply
  1572  	var actual []string
  1573  	var actualLock sync.Mutex
  1574  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1575  		actualLock.Lock()
  1576  		defer actualLock.Unlock()
  1577  		id := req.PriorState.GetAttr("id").AsString()
  1578  		actual = append(actual, id)
  1579  		return testApplyFn(req)
  1580  	}
  1581  
  1582  	ctx := testContext2(t, &ContextOpts{
  1583  		Providers: map[addrs.Provider]providers.Factory{
  1584  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1585  		},
  1586  		Parallelism: 1, // To check ordering
  1587  	})
  1588  
  1589  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1590  		Mode: plans.DestroyMode,
  1591  	})
  1592  	assertNoErrors(t, diags)
  1593  
  1594  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1595  		t.Fatalf("apply errors: %s", diags.Err())
  1596  	}
  1597  
  1598  	expected := []string{"bar", "foo"}
  1599  	if !reflect.DeepEqual(actual, expected) {
  1600  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1601  	}
  1602  }
  1603  
  1604  func TestContext2Apply_dataBasic(t *testing.T) {
  1605  	m := testModule(t, "apply-data-basic")
  1606  	p := testProvider("null")
  1607  	p.PlanResourceChangeFn = testDiffFn
  1608  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  1609  		State: cty.ObjectVal(map[string]cty.Value{
  1610  			"id":  cty.StringVal("yo"),
  1611  			"foo": cty.NullVal(cty.String),
  1612  		}),
  1613  	}
  1614  
  1615  	hook := new(MockHook)
  1616  	ctx := testContext2(t, &ContextOpts{
  1617  		Hooks: []Hook{hook},
  1618  		Providers: map[addrs.Provider]providers.Factory{
  1619  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  1620  		},
  1621  	})
  1622  
  1623  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1624  	if diags.HasErrors() {
  1625  		t.Fatalf("diags: %s", diags.Err())
  1626  	} else {
  1627  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1628  	}
  1629  
  1630  	state, diags := ctx.Apply(plan, m)
  1631  	assertNoErrors(t, diags)
  1632  
  1633  	actual := strings.TrimSpace(state.String())
  1634  	expected := strings.TrimSpace(testTofuApplyDataBasicStr)
  1635  	if actual != expected {
  1636  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1637  	}
  1638  
  1639  	if !hook.PreApplyCalled {
  1640  		t.Fatal("PreApply not called for data source read")
  1641  	}
  1642  	if !hook.PostApplyCalled {
  1643  		t.Fatal("PostApply not called for data source read")
  1644  	}
  1645  }
  1646  
  1647  func TestContext2Apply_destroyData(t *testing.T) {
  1648  	m := testModule(t, "apply-destroy-data-resource")
  1649  	p := testProvider("null")
  1650  	p.PlanResourceChangeFn = testDiffFn
  1651  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  1652  		return providers.ReadDataSourceResponse{
  1653  			State: req.Config,
  1654  		}
  1655  	}
  1656  
  1657  	state := states.NewState()
  1658  	root := state.EnsureModule(addrs.RootModuleInstance)
  1659  	root.SetResourceInstanceCurrent(
  1660  		mustResourceInstanceAddr("data.null_data_source.testing").Resource,
  1661  		&states.ResourceInstanceObjectSrc{
  1662  			Status:    states.ObjectReady,
  1663  			AttrsJSON: []byte(`{"id":"-"}`),
  1664  		},
  1665  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/null"]`),
  1666  	)
  1667  
  1668  	hook := &testHook{}
  1669  	ctx := testContext2(t, &ContextOpts{
  1670  		Providers: map[addrs.Provider]providers.Factory{
  1671  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  1672  		},
  1673  		Hooks: []Hook{hook},
  1674  	})
  1675  
  1676  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1677  		Mode: plans.DestroyMode,
  1678  	})
  1679  	if diags.HasErrors() {
  1680  		t.Fatalf("diags: %s", diags.Err())
  1681  	} else {
  1682  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1683  	}
  1684  
  1685  	newState, diags := ctx.Apply(plan, m)
  1686  	if diags.HasErrors() {
  1687  		t.Fatalf("diags: %s", diags.Err())
  1688  	}
  1689  
  1690  	if got := len(newState.Modules); got != 1 {
  1691  		t.Fatalf("state has %d modules after destroy; want 1", got)
  1692  	}
  1693  
  1694  	if got := len(newState.RootModule().Resources); got != 0 {
  1695  		t.Fatalf("state has %d resources after destroy; want 0", got)
  1696  	}
  1697  
  1698  	wantHookCalls := []*testHookCall{
  1699  		{"PreApply", "data.null_data_source.testing"},
  1700  		{"PostApply", "data.null_data_source.testing"},
  1701  		{"PostStateUpdate", ""},
  1702  	}
  1703  	if !reflect.DeepEqual(hook.Calls, wantHookCalls) {
  1704  		t.Errorf("wrong hook calls\ngot: %swant: %s", spew.Sdump(hook.Calls), spew.Sdump(wantHookCalls))
  1705  	}
  1706  }
  1707  
  1708  // https://github.com/hashicorp/terraform/pull/5096
  1709  func TestContext2Apply_destroySkipsCBD(t *testing.T) {
  1710  	// Config contains CBD resource depending on non-CBD resource, which triggers
  1711  	// a cycle if they are both replaced, but should _not_ trigger a cycle when
  1712  	// just doing a `tofu destroy`.
  1713  	m := testModule(t, "apply-destroy-cbd")
  1714  	p := testProvider("aws")
  1715  	p.PlanResourceChangeFn = testDiffFn
  1716  	state := states.NewState()
  1717  	root := state.EnsureModule(addrs.RootModuleInstance)
  1718  	root.SetResourceInstanceCurrent(
  1719  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1720  		&states.ResourceInstanceObjectSrc{
  1721  			Status:    states.ObjectReady,
  1722  			AttrsJSON: []byte(`{"id":"foo"}`),
  1723  		},
  1724  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1725  	)
  1726  	root.SetResourceInstanceCurrent(
  1727  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1728  		&states.ResourceInstanceObjectSrc{
  1729  			Status:    states.ObjectReady,
  1730  			AttrsJSON: []byte(`{"id":"foo"}`),
  1731  		},
  1732  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1733  	)
  1734  
  1735  	ctx := testContext2(t, &ContextOpts{
  1736  		Providers: map[addrs.Provider]providers.Factory{
  1737  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1738  		},
  1739  	})
  1740  
  1741  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1742  		Mode: plans.DestroyMode,
  1743  	})
  1744  	if diags.HasErrors() {
  1745  		t.Fatalf("diags: %s", diags.Err())
  1746  	} else {
  1747  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1748  	}
  1749  
  1750  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1751  		t.Fatalf("apply errors: %s", diags.Err())
  1752  	}
  1753  }
  1754  
  1755  func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) {
  1756  	m := testModule(t, "apply-destroy-mod-var-provider-config")
  1757  	p := func() (providers.Interface, error) {
  1758  		p := testProvider("aws")
  1759  		p.PlanResourceChangeFn = testDiffFn
  1760  		return p, nil
  1761  	}
  1762  	state := states.NewState()
  1763  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1764  	child.SetResourceInstanceCurrent(
  1765  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1766  		&states.ResourceInstanceObjectSrc{
  1767  			Status:    states.ObjectReady,
  1768  			AttrsJSON: []byte(`{"id":"foo"}`),
  1769  		},
  1770  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1771  	)
  1772  	ctx := testContext2(t, &ContextOpts{
  1773  		Providers: map[addrs.Provider]providers.Factory{
  1774  			addrs.NewDefaultProvider("aws"): p,
  1775  		},
  1776  	})
  1777  
  1778  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1779  		Mode: plans.DestroyMode,
  1780  	})
  1781  	assertNoErrors(t, diags)
  1782  
  1783  	_, diags = ctx.Apply(plan, m)
  1784  	if diags.HasErrors() {
  1785  		t.Fatalf("diags: %s", diags.Err())
  1786  	}
  1787  }
  1788  
  1789  func TestContext2Apply_destroyCrossProviders(t *testing.T) {
  1790  	m := testModule(t, "apply-destroy-cross-providers")
  1791  
  1792  	p_aws := testProvider("aws")
  1793  	p_aws.ApplyResourceChangeFn = testApplyFn
  1794  	p_aws.PlanResourceChangeFn = testDiffFn
  1795  	p_aws.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1796  		ResourceTypes: map[string]*configschema.Block{
  1797  			"aws_instance": {
  1798  				Attributes: map[string]*configschema.Attribute{
  1799  					"id": {
  1800  						Type:     cty.String,
  1801  						Computed: true,
  1802  					},
  1803  				},
  1804  			},
  1805  			"aws_vpc": {
  1806  				Attributes: map[string]*configschema.Attribute{
  1807  					"id": {
  1808  						Type:     cty.String,
  1809  						Computed: true,
  1810  					},
  1811  					"value": {
  1812  						Type:     cty.String,
  1813  						Optional: true,
  1814  					},
  1815  				},
  1816  			},
  1817  		},
  1818  	})
  1819  
  1820  	providers := map[addrs.Provider]providers.Factory{
  1821  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p_aws),
  1822  	}
  1823  
  1824  	ctx, m, state := getContextForApply_destroyCrossProviders(t, m, providers)
  1825  
  1826  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1827  		Mode: plans.DestroyMode,
  1828  	})
  1829  	assertNoErrors(t, diags)
  1830  
  1831  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1832  		logDiagnostics(t, diags)
  1833  		t.Fatal("apply failed")
  1834  	}
  1835  }
  1836  
  1837  func getContextForApply_destroyCrossProviders(t *testing.T, m *configs.Config, providerFactories map[addrs.Provider]providers.Factory) (*Context, *configs.Config, *states.State) {
  1838  	state := states.NewState()
  1839  	root := state.EnsureModule(addrs.RootModuleInstance)
  1840  	root.SetResourceInstanceCurrent(
  1841  		mustResourceInstanceAddr("aws_instance.shared").Resource,
  1842  		&states.ResourceInstanceObjectSrc{
  1843  			Status:    states.ObjectReady,
  1844  			AttrsJSON: []byte(`{"id":"test"}`),
  1845  		},
  1846  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1847  	)
  1848  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1849  	child.SetResourceInstanceCurrent(
  1850  		mustResourceInstanceAddr("aws_vpc.bar").Resource,
  1851  		&states.ResourceInstanceObjectSrc{
  1852  			Status:    states.ObjectReady,
  1853  			AttrsJSON: []byte(`{"id": "vpc-aaabbb12", "value":"test"}`),
  1854  		},
  1855  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  1856  	)
  1857  
  1858  	ctx := testContext2(t, &ContextOpts{
  1859  		Providers: providerFactories,
  1860  	})
  1861  
  1862  	return ctx, m, state
  1863  }
  1864  
  1865  func TestContext2Apply_minimal(t *testing.T) {
  1866  	m := testModule(t, "apply-minimal")
  1867  	p := testProvider("aws")
  1868  	p.PlanResourceChangeFn = testDiffFn
  1869  	p.ApplyResourceChangeFn = testApplyFn
  1870  	ctx := testContext2(t, &ContextOpts{
  1871  		Providers: map[addrs.Provider]providers.Factory{
  1872  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1873  		},
  1874  	})
  1875  
  1876  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1877  	assertNoErrors(t, diags)
  1878  
  1879  	state, diags := ctx.Apply(plan, m)
  1880  	if diags.HasErrors() {
  1881  		t.Fatalf("diags: %s", diags.Err())
  1882  	}
  1883  
  1884  	actual := strings.TrimSpace(state.String())
  1885  	expected := strings.TrimSpace(testTofuApplyMinimalStr)
  1886  	if actual != expected {
  1887  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1888  	}
  1889  }
  1890  
  1891  func TestContext2Apply_cancel(t *testing.T) {
  1892  	stopped := false
  1893  
  1894  	m := testModule(t, "apply-cancel")
  1895  	p := testProvider("aws")
  1896  	ctx := testContext2(t, &ContextOpts{
  1897  		Providers: map[addrs.Provider]providers.Factory{
  1898  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1899  		},
  1900  	})
  1901  
  1902  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1903  		if !stopped {
  1904  			stopped = true
  1905  			go ctx.Stop()
  1906  
  1907  			for {
  1908  				if ctx.sh.Stopped() {
  1909  					break
  1910  				}
  1911  				time.Sleep(10 * time.Millisecond)
  1912  			}
  1913  		}
  1914  		return testApplyFn(req)
  1915  	}
  1916  	p.PlanResourceChangeFn = testDiffFn
  1917  
  1918  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1919  	assertNoErrors(t, diags)
  1920  
  1921  	// Start the Apply in a goroutine
  1922  	var applyDiags tfdiags.Diagnostics
  1923  	stateCh := make(chan *states.State)
  1924  	go func() {
  1925  		state, diags := ctx.Apply(plan, m)
  1926  		applyDiags = diags
  1927  
  1928  		stateCh <- state
  1929  	}()
  1930  
  1931  	state := <-stateCh
  1932  	// only expecting an early exit error
  1933  	if !applyDiags.HasErrors() {
  1934  		t.Fatal("expected early exit error")
  1935  	}
  1936  
  1937  	for _, d := range applyDiags {
  1938  		desc := d.Description()
  1939  		if desc.Summary != "execution halted" {
  1940  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  1941  		}
  1942  	}
  1943  
  1944  	actual := strings.TrimSpace(state.String())
  1945  	expected := strings.TrimSpace(testTofuApplyCancelStr)
  1946  	if actual != expected {
  1947  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1948  	}
  1949  
  1950  	if !p.StopCalled {
  1951  		t.Fatal("stop should be called")
  1952  	}
  1953  }
  1954  
  1955  func TestContext2Apply_cancelBlock(t *testing.T) {
  1956  	m := testModule(t, "apply-cancel-block")
  1957  	p := testProvider("aws")
  1958  	ctx := testContext2(t, &ContextOpts{
  1959  		Providers: map[addrs.Provider]providers.Factory{
  1960  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1961  		},
  1962  	})
  1963  
  1964  	applyCh := make(chan struct{})
  1965  	p.PlanResourceChangeFn = testDiffFn
  1966  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1967  		close(applyCh)
  1968  
  1969  		for !ctx.sh.Stopped() {
  1970  			// Wait for stop to be called. We call Gosched here so that
  1971  			// the other goroutines can always be scheduled to set Stopped.
  1972  			runtime.Gosched()
  1973  		}
  1974  
  1975  		// Sleep
  1976  		time.Sleep(100 * time.Millisecond)
  1977  		return testApplyFn(req)
  1978  	}
  1979  
  1980  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1981  	assertNoErrors(t, diags)
  1982  
  1983  	// Start the Apply in a goroutine
  1984  	var applyDiags tfdiags.Diagnostics
  1985  	stateCh := make(chan *states.State)
  1986  	go func() {
  1987  		state, diags := ctx.Apply(plan, m)
  1988  		applyDiags = diags
  1989  
  1990  		stateCh <- state
  1991  	}()
  1992  
  1993  	stopDone := make(chan struct{})
  1994  	go func() {
  1995  		defer close(stopDone)
  1996  		<-applyCh
  1997  		ctx.Stop()
  1998  	}()
  1999  
  2000  	// Make sure that stop blocks
  2001  	select {
  2002  	case <-stopDone:
  2003  		t.Fatal("stop should block")
  2004  	case <-time.After(10 * time.Millisecond):
  2005  	}
  2006  
  2007  	// Wait for stop
  2008  	select {
  2009  	case <-stopDone:
  2010  	case <-time.After(500 * time.Millisecond):
  2011  		t.Fatal("stop should be done")
  2012  	}
  2013  
  2014  	// Wait for apply to complete
  2015  	state := <-stateCh
  2016  	// only expecting an early exit error
  2017  	if !applyDiags.HasErrors() {
  2018  		t.Fatal("expected early exit error")
  2019  	}
  2020  
  2021  	for _, d := range applyDiags {
  2022  		desc := d.Description()
  2023  		if desc.Summary != "execution halted" {
  2024  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  2025  		}
  2026  	}
  2027  
  2028  	checkStateString(t, state, `
  2029  aws_instance.foo:
  2030    ID = foo
  2031    provider = provider["registry.opentofu.org/hashicorp/aws"]
  2032    num = 2
  2033    type = aws_instance
  2034  	`)
  2035  }
  2036  
  2037  func TestContext2Apply_cancelProvisioner(t *testing.T) {
  2038  	m := testModule(t, "apply-cancel-provisioner")
  2039  	p := testProvider("aws")
  2040  	p.PlanResourceChangeFn = testDiffFn
  2041  	p.ApplyResourceChangeFn = testApplyFn
  2042  
  2043  	pr := testProvisioner()
  2044  	pr.GetSchemaResponse = provisioners.GetSchemaResponse{
  2045  		Provisioner: &configschema.Block{
  2046  			Attributes: map[string]*configschema.Attribute{
  2047  				"foo": {
  2048  					Type:     cty.String,
  2049  					Optional: true,
  2050  				},
  2051  			},
  2052  		},
  2053  	}
  2054  
  2055  	ctx := testContext2(t, &ContextOpts{
  2056  		Providers: map[addrs.Provider]providers.Factory{
  2057  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2058  		},
  2059  		Provisioners: map[string]provisioners.Factory{
  2060  			"shell": testProvisionerFuncFixed(pr),
  2061  		},
  2062  	})
  2063  
  2064  	prStopped := make(chan struct{})
  2065  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  2066  		// Start the stop process
  2067  		go ctx.Stop()
  2068  
  2069  		<-prStopped
  2070  		return
  2071  	}
  2072  	pr.StopFn = func() error {
  2073  		close(prStopped)
  2074  		return nil
  2075  	}
  2076  
  2077  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2078  	assertNoErrors(t, diags)
  2079  
  2080  	// Start the Apply in a goroutine
  2081  	var applyDiags tfdiags.Diagnostics
  2082  	stateCh := make(chan *states.State)
  2083  	go func() {
  2084  		state, diags := ctx.Apply(plan, m)
  2085  		applyDiags = diags
  2086  
  2087  		stateCh <- state
  2088  	}()
  2089  
  2090  	// Wait for completion
  2091  	state := <-stateCh
  2092  
  2093  	// we are expecting only an early exit error
  2094  	if !applyDiags.HasErrors() {
  2095  		t.Fatal("expected early exit error")
  2096  	}
  2097  
  2098  	for _, d := range applyDiags {
  2099  		desc := d.Description()
  2100  		if desc.Summary != "execution halted" {
  2101  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  2102  		}
  2103  	}
  2104  
  2105  	checkStateString(t, state, `
  2106  aws_instance.foo: (tainted)
  2107    ID = foo
  2108    provider = provider["registry.opentofu.org/hashicorp/aws"]
  2109    num = 2
  2110    type = aws_instance
  2111  	`)
  2112  
  2113  	if !pr.StopCalled {
  2114  		t.Fatal("stop should be called")
  2115  	}
  2116  }
  2117  
  2118  func TestContext2Apply_compute(t *testing.T) {
  2119  	m := testModule(t, "apply-compute")
  2120  	p := testProvider("aws")
  2121  	p.PlanResourceChangeFn = testDiffFn
  2122  	p.ApplyResourceChangeFn = testApplyFn
  2123  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2124  		ResourceTypes: map[string]*configschema.Block{
  2125  			"aws_instance": {
  2126  				Attributes: map[string]*configschema.Attribute{
  2127  					"num": {
  2128  						Type:     cty.Number,
  2129  						Optional: true,
  2130  					},
  2131  					"compute": {
  2132  						Type:     cty.String,
  2133  						Optional: true,
  2134  					},
  2135  					"compute_value": {
  2136  						Type:     cty.String,
  2137  						Optional: true,
  2138  					},
  2139  					"foo": {
  2140  						Type:     cty.String,
  2141  						Optional: true,
  2142  					},
  2143  					"id": {
  2144  						Type:     cty.String,
  2145  						Computed: true,
  2146  					},
  2147  					"type": {
  2148  						Type:     cty.String,
  2149  						Computed: true,
  2150  					},
  2151  					"value": { // Populated from compute_value because compute = "value" in the config fixture
  2152  						Type:     cty.String,
  2153  						Computed: true,
  2154  					},
  2155  				},
  2156  			},
  2157  		},
  2158  	})
  2159  
  2160  	ctx := testContext2(t, &ContextOpts{
  2161  		Providers: map[addrs.Provider]providers.Factory{
  2162  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2163  		},
  2164  	})
  2165  
  2166  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2167  		SetVariables: InputValues{
  2168  			"value": &InputValue{
  2169  				Value:      cty.NumberIntVal(1),
  2170  				SourceType: ValueFromCaller,
  2171  			},
  2172  		},
  2173  	})
  2174  	assertNoErrors(t, diags)
  2175  
  2176  	state, diags := ctx.Apply(plan, m)
  2177  	if diags.HasErrors() {
  2178  		t.Fatalf("unexpected errors: %s", diags.Err())
  2179  	}
  2180  
  2181  	actual := strings.TrimSpace(state.String())
  2182  	expected := strings.TrimSpace(testTofuApplyComputeStr)
  2183  	if actual != expected {
  2184  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2185  	}
  2186  }
  2187  
  2188  func TestContext2Apply_countDecrease(t *testing.T) {
  2189  	m := testModule(t, "apply-count-dec")
  2190  	p := testProvider("aws")
  2191  	p.PlanResourceChangeFn = testDiffFn
  2192  	p.ApplyResourceChangeFn = testApplyFn
  2193  	state := states.NewState()
  2194  	root := state.EnsureModule(addrs.RootModuleInstance)
  2195  	root.SetResourceInstanceCurrent(
  2196  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2197  		&states.ResourceInstanceObjectSrc{
  2198  			Status:    states.ObjectReady,
  2199  			AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`),
  2200  		},
  2201  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2202  	)
  2203  	root.SetResourceInstanceCurrent(
  2204  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  2205  		&states.ResourceInstanceObjectSrc{
  2206  			Status:    states.ObjectReady,
  2207  			AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`),
  2208  		},
  2209  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2210  	)
  2211  	root.SetResourceInstanceCurrent(
  2212  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  2213  		&states.ResourceInstanceObjectSrc{
  2214  			Status:    states.ObjectReady,
  2215  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  2216  		},
  2217  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2218  	)
  2219  
  2220  	ctx := testContext2(t, &ContextOpts{
  2221  		Providers: map[addrs.Provider]providers.Factory{
  2222  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2223  		},
  2224  	})
  2225  
  2226  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2227  	assertNoErrors(t, diags)
  2228  
  2229  	s, diags := ctx.Apply(plan, m)
  2230  	assertNoErrors(t, diags)
  2231  
  2232  	actual := strings.TrimSpace(s.String())
  2233  	expected := strings.TrimSpace(testTofuApplyCountDecStr)
  2234  	if actual != expected {
  2235  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2236  	}
  2237  }
  2238  
  2239  func TestContext2Apply_countDecreaseToOneX(t *testing.T) {
  2240  	m := testModule(t, "apply-count-dec-one")
  2241  	p := testProvider("aws")
  2242  	p.PlanResourceChangeFn = testDiffFn
  2243  	state := states.NewState()
  2244  	root := state.EnsureModule(addrs.RootModuleInstance)
  2245  	root.SetResourceInstanceCurrent(
  2246  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2247  		&states.ResourceInstanceObjectSrc{
  2248  			Status:    states.ObjectReady,
  2249  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  2250  		},
  2251  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2252  	)
  2253  	root.SetResourceInstanceCurrent(
  2254  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  2255  		&states.ResourceInstanceObjectSrc{
  2256  			Status:    states.ObjectReady,
  2257  			AttrsJSON: []byte(`{"id":"bar"}`),
  2258  		},
  2259  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2260  	)
  2261  	root.SetResourceInstanceCurrent(
  2262  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  2263  		&states.ResourceInstanceObjectSrc{
  2264  			Status:    states.ObjectReady,
  2265  			AttrsJSON: []byte(`{"id":"bar"}`),
  2266  		},
  2267  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2268  	)
  2269  
  2270  	ctx := testContext2(t, &ContextOpts{
  2271  		Providers: map[addrs.Provider]providers.Factory{
  2272  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2273  		},
  2274  	})
  2275  
  2276  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2277  	assertNoErrors(t, diags)
  2278  
  2279  	s, diags := ctx.Apply(plan, m)
  2280  	if diags.HasErrors() {
  2281  		t.Fatalf("diags: %s", diags.Err())
  2282  	}
  2283  
  2284  	actual := strings.TrimSpace(s.String())
  2285  	expected := strings.TrimSpace(testTofuApplyCountDecToOneStr)
  2286  	if actual != expected {
  2287  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2288  	}
  2289  }
  2290  
  2291  // https://github.com/PeoplePerHour/terraform/pull/11
  2292  //
  2293  // This tests a rare but possible situation where we have both a no-key and
  2294  // a zero-key instance of the same resource in the configuration when we
  2295  // disable count.
  2296  //
  2297  // The main way to get here is for a provider to fail to destroy the zero-key
  2298  // instance but succeed in creating the no-key instance, since those two
  2299  // can typically happen concurrently. There are various other ways to get here
  2300  // that might be considered user error, such as using "tofu state mv"
  2301  // to create a strange combination of different key types on the same resource.
  2302  //
  2303  // This test indirectly exercises an intentional interaction between
  2304  // refactoring.ImpliedMoveStatements and refactoring.ApplyMoves: we'll first
  2305  // generate an implied move statement from aws_instance.foo[0] to
  2306  // aws_instance.foo, but then refactoring.ApplyMoves should notice that and
  2307  // ignore the statement, in the same way as it would if an explicit move
  2308  // statement specified the same situation.
  2309  func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) {
  2310  	m := testModule(t, "apply-count-dec-one")
  2311  	p := testProvider("aws")
  2312  	p.PlanResourceChangeFn = testDiffFn
  2313  	state := states.NewState()
  2314  	root := state.EnsureModule(addrs.RootModuleInstance)
  2315  	root.SetResourceInstanceCurrent(
  2316  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2317  		&states.ResourceInstanceObjectSrc{
  2318  			Status:    states.ObjectReady,
  2319  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  2320  		},
  2321  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2322  	)
  2323  	root.SetResourceInstanceCurrent(
  2324  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2325  		&states.ResourceInstanceObjectSrc{
  2326  			Status:    states.ObjectReady,
  2327  			AttrsJSON: []byte(`{"id":"baz", "type": "aws_instance"}`),
  2328  		},
  2329  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2330  	)
  2331  
  2332  	ctx := testContext2(t, &ContextOpts{
  2333  		Providers: map[addrs.Provider]providers.Factory{
  2334  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2335  		},
  2336  	})
  2337  
  2338  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2339  	assertNoErrors(t, diags)
  2340  	{
  2341  		got := strings.TrimSpace(legacyPlanComparisonString(state, plan.Changes))
  2342  		want := strings.TrimSpace(testTofuApplyCountDecToOneCorruptedPlanStr)
  2343  		if got != want {
  2344  			t.Fatalf("wrong plan result\ngot:\n%s\nwant:\n%s", got, want)
  2345  		}
  2346  	}
  2347  	{
  2348  		change := plan.Changes.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo[0]"))
  2349  		if change == nil {
  2350  			t.Fatalf("no planned change for instance zero")
  2351  		}
  2352  		if got, want := change.Action, plans.Delete; got != want {
  2353  			t.Errorf("wrong action for instance zero %s; want %s", got, want)
  2354  		}
  2355  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want {
  2356  			t.Errorf("wrong action reason for instance zero %s; want %s", got, want)
  2357  		}
  2358  	}
  2359  	{
  2360  		change := plan.Changes.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo"))
  2361  		if change == nil {
  2362  			t.Fatalf("no planned change for no-key instance")
  2363  		}
  2364  		if got, want := change.Action, plans.NoOp; got != want {
  2365  			t.Errorf("wrong action for no-key instance %s; want %s", got, want)
  2366  		}
  2367  		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
  2368  			t.Errorf("wrong action reason for no-key instance %s; want %s", got, want)
  2369  		}
  2370  	}
  2371  
  2372  	s, diags := ctx.Apply(plan, m)
  2373  	if diags.HasErrors() {
  2374  		t.Fatalf("diags: %s", diags.Err())
  2375  	}
  2376  
  2377  	actual := strings.TrimSpace(s.String())
  2378  	expected := strings.TrimSpace(testTofuApplyCountDecToOneCorruptedStr)
  2379  	if actual != expected {
  2380  		t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2381  	}
  2382  }
  2383  
  2384  func TestContext2Apply_countTainted(t *testing.T) {
  2385  	m := testModule(t, "apply-count-tainted")
  2386  	p := testProvider("aws")
  2387  	p.PlanResourceChangeFn = testDiffFn
  2388  	p.ApplyResourceChangeFn = testApplyFn
  2389  	state := states.NewState()
  2390  	root := state.EnsureModule(addrs.RootModuleInstance)
  2391  	root.SetResourceInstanceCurrent(
  2392  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2393  		&states.ResourceInstanceObjectSrc{
  2394  			Status:    states.ObjectTainted,
  2395  			AttrsJSON: []byte(`{"id":"bar", "type": "aws_instance", "foo": "foo"}`),
  2396  		},
  2397  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2398  	)
  2399  	ctx := testContext2(t, &ContextOpts{
  2400  		Providers: map[addrs.Provider]providers.Factory{
  2401  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2402  		},
  2403  	})
  2404  
  2405  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2406  	assertNoErrors(t, diags)
  2407  	{
  2408  		got := strings.TrimSpace(legacyDiffComparisonString(plan.Changes))
  2409  		want := strings.TrimSpace(`
  2410  DESTROY/CREATE: aws_instance.foo[0]
  2411    foo:  "foo" => "foo"
  2412    id:   "bar" => "<computed>"
  2413    type: "aws_instance" => "<computed>"
  2414  CREATE: aws_instance.foo[1]
  2415    foo:  "" => "foo"
  2416    id:   "" => "<computed>"
  2417    type: "" => "<computed>"
  2418  `)
  2419  		if got != want {
  2420  			t.Fatalf("wrong plan\n\ngot:\n%s\n\nwant:\n%s", got, want)
  2421  		}
  2422  	}
  2423  
  2424  	s, diags := ctx.Apply(plan, m)
  2425  	assertNoErrors(t, diags)
  2426  
  2427  	got := strings.TrimSpace(s.String())
  2428  	want := strings.TrimSpace(`
  2429  aws_instance.foo.0:
  2430    ID = foo
  2431    provider = provider["registry.opentofu.org/hashicorp/aws"]
  2432    foo = foo
  2433    type = aws_instance
  2434  aws_instance.foo.1:
  2435    ID = foo
  2436    provider = provider["registry.opentofu.org/hashicorp/aws"]
  2437    foo = foo
  2438    type = aws_instance
  2439  `)
  2440  	if got != want {
  2441  		t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", got, want)
  2442  	}
  2443  }
  2444  
  2445  func TestContext2Apply_countVariable(t *testing.T) {
  2446  	m := testModule(t, "apply-count-variable")
  2447  	p := testProvider("aws")
  2448  	p.PlanResourceChangeFn = testDiffFn
  2449  	p.ApplyResourceChangeFn = testApplyFn
  2450  	ctx := testContext2(t, &ContextOpts{
  2451  		Providers: map[addrs.Provider]providers.Factory{
  2452  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2453  		},
  2454  	})
  2455  
  2456  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  2457  	assertNoErrors(t, diags)
  2458  
  2459  	state, diags := ctx.Apply(plan, m)
  2460  	if diags.HasErrors() {
  2461  		t.Fatalf("diags: %s", diags.Err())
  2462  	}
  2463  
  2464  	actual := strings.TrimSpace(state.String())
  2465  	expected := strings.TrimSpace(testTofuApplyCountVariableStr)
  2466  	if actual != expected {
  2467  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2468  	}
  2469  }
  2470  
  2471  func TestContext2Apply_countVariableRef(t *testing.T) {
  2472  	m := testModule(t, "apply-count-variable-ref")
  2473  	p := testProvider("aws")
  2474  	p.PlanResourceChangeFn = testDiffFn
  2475  	p.ApplyResourceChangeFn = testApplyFn
  2476  	ctx := testContext2(t, &ContextOpts{
  2477  		Providers: map[addrs.Provider]providers.Factory{
  2478  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2479  		},
  2480  	})
  2481  
  2482  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  2483  	assertNoErrors(t, diags)
  2484  
  2485  	state, diags := ctx.Apply(plan, m)
  2486  	if diags.HasErrors() {
  2487  		t.Fatalf("diags: %s", diags.Err())
  2488  	}
  2489  
  2490  	actual := strings.TrimSpace(state.String())
  2491  	expected := strings.TrimSpace(testTofuApplyCountVariableRefStr)
  2492  	if actual != expected {
  2493  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2494  	}
  2495  }
  2496  
  2497  func TestContext2Apply_provisionerInterpCount(t *testing.T) {
  2498  	// This test ensures that a provisioner can interpolate a resource count
  2499  	// even though the provisioner expression is evaluated during the plan
  2500  	// walk. https://github.com/hashicorp/terraform/issues/16840
  2501  
  2502  	m, snap := testModuleWithSnapshot(t, "apply-provisioner-interp-count")
  2503  
  2504  	p := testProvider("aws")
  2505  	p.PlanResourceChangeFn = testDiffFn
  2506  
  2507  	pr := testProvisioner()
  2508  
  2509  	Providers := map[addrs.Provider]providers.Factory{
  2510  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2511  	}
  2512  
  2513  	provisioners := map[string]provisioners.Factory{
  2514  		"local-exec": testProvisionerFuncFixed(pr),
  2515  	}
  2516  	ctx := testContext2(t, &ContextOpts{
  2517  		Providers:    Providers,
  2518  		Provisioners: provisioners,
  2519  	})
  2520  
  2521  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  2522  	assertNoErrors(t, diags)
  2523  
  2524  	// We'll marshal and unmarshal the plan here, to ensure that we have
  2525  	// a clean new context as would be created if we separately ran
  2526  	// tofu plan -out=tfplan && tofu apply tfplan
  2527  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  2528  	if err != nil {
  2529  		t.Fatal(err)
  2530  	}
  2531  	ctxOpts.Providers = Providers
  2532  	ctxOpts.Provisioners = provisioners
  2533  	ctx, diags = NewContext(ctxOpts)
  2534  	if diags.HasErrors() {
  2535  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  2536  	}
  2537  
  2538  	// Applying the plan should now succeed
  2539  	_, diags = ctx.Apply(plan, m)
  2540  	if diags.HasErrors() {
  2541  		t.Fatalf("apply failed unexpectedly: %s", diags.Err())
  2542  	}
  2543  
  2544  	// Verify apply was invoked
  2545  	if !pr.ProvisionResourceCalled {
  2546  		t.Fatalf("provisioner was not called")
  2547  	}
  2548  }
  2549  
  2550  func TestContext2Apply_foreachVariable(t *testing.T) {
  2551  	m := testModule(t, "plan-for-each-unknown-value")
  2552  	p := testProvider("aws")
  2553  	p.PlanResourceChangeFn = testDiffFn
  2554  	p.ApplyResourceChangeFn = testApplyFn
  2555  	ctx := testContext2(t, &ContextOpts{
  2556  		Providers: map[addrs.Provider]providers.Factory{
  2557  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2558  		},
  2559  	})
  2560  
  2561  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2562  		Mode: plans.NormalMode,
  2563  		SetVariables: InputValues{
  2564  			"foo": &InputValue{
  2565  				Value: cty.StringVal("hello"),
  2566  			},
  2567  		},
  2568  	})
  2569  	assertNoErrors(t, diags)
  2570  
  2571  	state, diags := ctx.Apply(plan, m)
  2572  	if diags.HasErrors() {
  2573  		t.Fatalf("diags: %s", diags.Err())
  2574  	}
  2575  
  2576  	actual := strings.TrimSpace(state.String())
  2577  	expected := strings.TrimSpace(testTofuApplyForEachVariableStr)
  2578  	if actual != expected {
  2579  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2580  	}
  2581  }
  2582  
  2583  func TestContext2Apply_moduleBasic(t *testing.T) {
  2584  	m := testModule(t, "apply-module")
  2585  	p := testProvider("aws")
  2586  	p.PlanResourceChangeFn = testDiffFn
  2587  	p.ApplyResourceChangeFn = testApplyFn
  2588  	ctx := testContext2(t, &ContextOpts{
  2589  		Providers: map[addrs.Provider]providers.Factory{
  2590  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2591  		},
  2592  	})
  2593  
  2594  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2595  	assertNoErrors(t, diags)
  2596  
  2597  	state, diags := ctx.Apply(plan, m)
  2598  	if diags.HasErrors() {
  2599  		t.Fatalf("diags: %s", diags.Err())
  2600  	}
  2601  
  2602  	actual := strings.TrimSpace(state.String())
  2603  	expected := strings.TrimSpace(testTofuApplyModuleStr)
  2604  	if actual != expected {
  2605  		t.Fatalf("bad, expected:\n%s\n\nactual:\n%s", expected, actual)
  2606  	}
  2607  }
  2608  
  2609  func TestContext2Apply_moduleDestroyOrder(t *testing.T) {
  2610  	m := testModule(t, "apply-module-destroy-order")
  2611  	p := testProvider("aws")
  2612  	p.PlanResourceChangeFn = testDiffFn
  2613  
  2614  	// Create a custom apply function to track the order they were destroyed
  2615  	var order []string
  2616  	var orderLock sync.Mutex
  2617  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  2618  		id := req.PriorState.GetAttr("id").AsString()
  2619  
  2620  		if id == "b" {
  2621  			// Pause briefly to make any race conditions more visible, since
  2622  			// missing edges here can cause undeterministic ordering.
  2623  			time.Sleep(100 * time.Millisecond)
  2624  		}
  2625  
  2626  		orderLock.Lock()
  2627  		defer orderLock.Unlock()
  2628  
  2629  		order = append(order, id)
  2630  		resp.NewState = req.PlannedState
  2631  		return resp
  2632  	}
  2633  
  2634  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2635  		ResourceTypes: map[string]*configschema.Block{
  2636  			"aws_instance": {
  2637  				Attributes: map[string]*configschema.Attribute{
  2638  					"id":    {Type: cty.String, Required: true},
  2639  					"blah":  {Type: cty.String, Optional: true},
  2640  					"value": {Type: cty.String, Optional: true},
  2641  				},
  2642  			},
  2643  		},
  2644  	})
  2645  
  2646  	state := states.NewState()
  2647  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2648  	child.SetResourceInstanceCurrent(
  2649  		mustResourceInstanceAddr("aws_instance.a").Resource,
  2650  		&states.ResourceInstanceObjectSrc{
  2651  			Status:    states.ObjectReady,
  2652  			AttrsJSON: []byte(`{"id":"a"}`),
  2653  		},
  2654  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2655  	)
  2656  	root := state.EnsureModule(addrs.RootModuleInstance)
  2657  	root.SetResourceInstanceCurrent(
  2658  		mustResourceInstanceAddr("aws_instance.b").Resource,
  2659  		&states.ResourceInstanceObjectSrc{
  2660  			Status:       states.ObjectReady,
  2661  			AttrsJSON:    []byte(`{"id":"b"}`),
  2662  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.a")},
  2663  		},
  2664  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2665  	)
  2666  
  2667  	ctx := testContext2(t, &ContextOpts{
  2668  		Providers: map[addrs.Provider]providers.Factory{
  2669  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2670  		},
  2671  	})
  2672  
  2673  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  2674  		Mode: plans.DestroyMode,
  2675  	})
  2676  	assertNoErrors(t, diags)
  2677  
  2678  	state, diags = ctx.Apply(plan, m)
  2679  	if diags.HasErrors() {
  2680  		t.Fatalf("diags: %s", diags.Err())
  2681  	}
  2682  
  2683  	expected := []string{"b", "a"}
  2684  	if !reflect.DeepEqual(order, expected) {
  2685  		t.Errorf("wrong order\ngot: %#v\nwant: %#v", order, expected)
  2686  	}
  2687  
  2688  	{
  2689  		actual := strings.TrimSpace(state.String())
  2690  		expected := strings.TrimSpace(testTofuApplyModuleDestroyOrderStr)
  2691  		if actual != expected {
  2692  			t.Errorf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2693  		}
  2694  	}
  2695  }
  2696  
  2697  func TestContext2Apply_moduleInheritAlias(t *testing.T) {
  2698  	m := testModule(t, "apply-module-provider-inherit-alias")
  2699  	p := testProvider("aws")
  2700  	p.PlanResourceChangeFn = testDiffFn
  2701  	p.ApplyResourceChangeFn = testApplyFn
  2702  
  2703  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2704  		val := req.Config.GetAttr("value")
  2705  		if val.IsNull() {
  2706  			return
  2707  		}
  2708  
  2709  		root := req.Config.GetAttr("root")
  2710  		if !root.IsNull() {
  2711  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root"))
  2712  		}
  2713  
  2714  		return
  2715  	}
  2716  
  2717  	ctx := testContext2(t, &ContextOpts{
  2718  		Providers: map[addrs.Provider]providers.Factory{
  2719  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2720  		},
  2721  	})
  2722  
  2723  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2724  	assertNoErrors(t, diags)
  2725  
  2726  	state, diags := ctx.Apply(plan, m)
  2727  	if diags.HasErrors() {
  2728  		t.Fatalf("diags: %s", diags.Err())
  2729  	}
  2730  
  2731  	checkStateString(t, state, `
  2732  <no state>
  2733  module.child:
  2734    aws_instance.foo:
  2735      ID = foo
  2736      provider = provider["registry.opentofu.org/hashicorp/aws"].eu
  2737      type = aws_instance
  2738  	`)
  2739  }
  2740  
  2741  func TestContext2Apply_orphanResource(t *testing.T) {
  2742  	// This is a two-step test:
  2743  	// 1. Apply a configuration with resources that have count set.
  2744  	//    This should place the empty resource object in the state to record
  2745  	//    that each exists, and record any instances.
  2746  	// 2. Apply an empty configuration against the same state, which should
  2747  	//    then clean up both the instances and the containing resource objects.
  2748  	p := testProvider("test")
  2749  	p.PlanResourceChangeFn = testDiffFn
  2750  	p.ApplyResourceChangeFn = testApplyFn
  2751  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2752  		ResourceTypes: map[string]*configschema.Block{
  2753  			"test_thing": {
  2754  				Attributes: map[string]*configschema.Attribute{
  2755  					"id":  {Type: cty.String, Computed: true},
  2756  					"foo": {Type: cty.String, Optional: true},
  2757  				},
  2758  			},
  2759  		},
  2760  	})
  2761  
  2762  	// Step 1: create the resources and instances
  2763  	m := testModule(t, "apply-orphan-resource")
  2764  	ctx := testContext2(t, &ContextOpts{
  2765  		Providers: map[addrs.Provider]providers.Factory{
  2766  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  2767  		},
  2768  	})
  2769  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2770  	assertNoErrors(t, diags)
  2771  	state, diags := ctx.Apply(plan, m)
  2772  	assertNoErrors(t, diags)
  2773  
  2774  	// At this point both resources should be recorded in the state, along
  2775  	// with the single instance associated with test_thing.one.
  2776  	want := states.BuildState(func(s *states.SyncState) {
  2777  		providerAddr := addrs.AbsProviderConfig{
  2778  			Provider: addrs.NewDefaultProvider("test"),
  2779  			Module:   addrs.RootModule,
  2780  		}
  2781  		oneAddr := addrs.Resource{
  2782  			Mode: addrs.ManagedResourceMode,
  2783  			Type: "test_thing",
  2784  			Name: "one",
  2785  		}.Absolute(addrs.RootModuleInstance)
  2786  		s.SetResourceProvider(oneAddr, providerAddr)
  2787  		s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{
  2788  			Status:    states.ObjectReady,
  2789  			AttrsJSON: []byte(`{"id":"foo"}`),
  2790  		}, providerAddr)
  2791  	})
  2792  
  2793  	if state.String() != want.String() {
  2794  		t.Fatalf("wrong state after step 1\n%s", cmp.Diff(want, state))
  2795  	}
  2796  
  2797  	// Step 2: update with an empty config, to destroy everything
  2798  	m = testModule(t, "empty")
  2799  	ctx = testContext2(t, &ContextOpts{
  2800  		Providers: map[addrs.Provider]providers.Factory{
  2801  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  2802  		},
  2803  	})
  2804  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  2805  	assertNoErrors(t, diags)
  2806  	{
  2807  		addr := mustResourceInstanceAddr("test_thing.one[0]")
  2808  		change := plan.Changes.ResourceInstance(addr)
  2809  		if change == nil {
  2810  			t.Fatalf("no planned change for %s", addr)
  2811  		}
  2812  		if got, want := change.Action, plans.Delete; got != want {
  2813  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2814  		}
  2815  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want {
  2816  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2817  		}
  2818  	}
  2819  
  2820  	state, diags = ctx.Apply(plan, m)
  2821  	assertNoErrors(t, diags)
  2822  
  2823  	// The state should now be _totally_ empty, with just an empty root module
  2824  	// (since that always exists) and no resources at all.
  2825  	want = states.NewState()
  2826  	want.CheckResults = &states.CheckResults{}
  2827  	if !cmp.Equal(state, want) {
  2828  		t.Fatalf("wrong state after step 2\ngot: %swant: %s", spew.Sdump(state), spew.Sdump(want))
  2829  	}
  2830  
  2831  }
  2832  
  2833  func TestContext2Apply_moduleOrphanInheritAlias(t *testing.T) {
  2834  	m := testModule(t, "apply-module-provider-inherit-alias-orphan")
  2835  	p := testProvider("aws")
  2836  	p.PlanResourceChangeFn = testDiffFn
  2837  
  2838  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2839  		val := req.Config.GetAttr("value")
  2840  		if val.IsNull() {
  2841  			return
  2842  		}
  2843  
  2844  		root := req.Config.GetAttr("root")
  2845  		if !root.IsNull() {
  2846  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root"))
  2847  		}
  2848  
  2849  		return
  2850  	}
  2851  
  2852  	// Create a state with an orphan module
  2853  	state := states.NewState()
  2854  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2855  	child.SetResourceInstanceCurrent(
  2856  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2857  		&states.ResourceInstanceObjectSrc{
  2858  			Status:    states.ObjectReady,
  2859  			AttrsJSON: []byte(`{"id":"bar"}`),
  2860  		},
  2861  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2862  	)
  2863  
  2864  	ctx := testContext2(t, &ContextOpts{
  2865  		Providers: map[addrs.Provider]providers.Factory{
  2866  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2867  		},
  2868  	})
  2869  
  2870  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2871  	assertNoErrors(t, diags)
  2872  	{
  2873  		addr := mustResourceInstanceAddr("module.child.aws_instance.bar")
  2874  		change := plan.Changes.ResourceInstance(addr)
  2875  		if change == nil {
  2876  			t.Fatalf("no planned change for %s", addr)
  2877  		}
  2878  		if got, want := change.Action, plans.Delete; got != want {
  2879  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2880  		}
  2881  		// This should ideally be ResourceInstanceDeleteBecauseNoModule, but
  2882  		// the codepath deciding this doesn't currently have enough information
  2883  		// to differentiate, and so this is a compromise.
  2884  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want {
  2885  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2886  		}
  2887  	}
  2888  
  2889  	state, diags = ctx.Apply(plan, m)
  2890  	if diags.HasErrors() {
  2891  		t.Fatalf("diags: %s", diags.Err())
  2892  	}
  2893  
  2894  	if !p.ConfigureProviderCalled {
  2895  		t.Fatal("must call configure")
  2896  	}
  2897  
  2898  	checkStateString(t, state, "<no state>")
  2899  }
  2900  
  2901  func TestContext2Apply_moduleOrphanProvider(t *testing.T) {
  2902  	m := testModule(t, "apply-module-orphan-provider-inherit")
  2903  	p := testProvider("aws")
  2904  	p.PlanResourceChangeFn = testDiffFn
  2905  
  2906  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2907  		val := req.Config.GetAttr("value")
  2908  		if val.IsNull() {
  2909  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2910  		}
  2911  
  2912  		return
  2913  	}
  2914  
  2915  	// Create a state with an orphan module
  2916  	state := states.NewState()
  2917  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2918  	child.SetResourceInstanceCurrent(
  2919  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2920  		&states.ResourceInstanceObjectSrc{
  2921  			Status:    states.ObjectReady,
  2922  			AttrsJSON: []byte(`{"id":"bar"}`),
  2923  		},
  2924  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2925  	)
  2926  
  2927  	ctx := testContext2(t, &ContextOpts{
  2928  		Providers: map[addrs.Provider]providers.Factory{
  2929  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2930  		},
  2931  	})
  2932  
  2933  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2934  	assertNoErrors(t, diags)
  2935  
  2936  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2937  		t.Fatalf("apply errors: %s", diags.Err())
  2938  	}
  2939  }
  2940  
  2941  func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) {
  2942  	m := testModule(t, "apply-module-orphan-provider-inherit")
  2943  	p := testProvider("aws")
  2944  	p.PlanResourceChangeFn = testDiffFn
  2945  
  2946  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2947  		val := req.Config.GetAttr("value")
  2948  		if val.IsNull() {
  2949  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2950  		}
  2951  
  2952  		return
  2953  	}
  2954  
  2955  	// Create a state with an orphan module that is nested (grandchild)
  2956  	state := states.NewState()
  2957  	child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child", addrs.NoKey))
  2958  	child.SetResourceInstanceCurrent(
  2959  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2960  		&states.ResourceInstanceObjectSrc{
  2961  			Status:    states.ObjectReady,
  2962  			AttrsJSON: []byte(`{"id":"bar"}`),
  2963  		},
  2964  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  2965  	)
  2966  
  2967  	ctx := testContext2(t, &ContextOpts{
  2968  		Providers: map[addrs.Provider]providers.Factory{
  2969  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2970  		},
  2971  	})
  2972  
  2973  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2974  	assertNoErrors(t, diags)
  2975  
  2976  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2977  		t.Fatalf("apply errors: %s", diags.Err())
  2978  	}
  2979  }
  2980  
  2981  func TestContext2Apply_moduleGrandchildProvider(t *testing.T) {
  2982  	m := testModule(t, "apply-module-grandchild-provider-inherit")
  2983  	p := testProvider("aws")
  2984  	p.PlanResourceChangeFn = testDiffFn
  2985  
  2986  	var callLock sync.Mutex
  2987  	called := false
  2988  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2989  		val := req.Config.GetAttr("value")
  2990  		if val.IsNull() {
  2991  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2992  		}
  2993  
  2994  		callLock.Lock()
  2995  		called = true
  2996  		callLock.Unlock()
  2997  
  2998  		return
  2999  	}
  3000  
  3001  	ctx := testContext2(t, &ContextOpts{
  3002  		Providers: map[addrs.Provider]providers.Factory{
  3003  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3004  		},
  3005  	})
  3006  
  3007  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3008  	assertNoErrors(t, diags)
  3009  
  3010  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3011  		t.Fatalf("apply errors: %s", diags.Err())
  3012  	}
  3013  
  3014  	callLock.Lock()
  3015  	defer callLock.Unlock()
  3016  	if called != true {
  3017  		t.Fatalf("err: configure never called")
  3018  	}
  3019  }
  3020  
  3021  // This tests an issue where all the providers in a module but not
  3022  // in the root weren't being added to the root properly. In this test
  3023  // case: aws is explicitly added to root, but "test" should be added to.
  3024  // With the bug, it wasn't.
  3025  func TestContext2Apply_moduleOnlyProvider(t *testing.T) {
  3026  	m := testModule(t, "apply-module-only-provider")
  3027  	p := testProvider("aws")
  3028  	p.PlanResourceChangeFn = testDiffFn
  3029  	p.ApplyResourceChangeFn = testApplyFn
  3030  	pTest := testProvider("test")
  3031  	pTest.ApplyResourceChangeFn = testApplyFn
  3032  	pTest.PlanResourceChangeFn = testDiffFn
  3033  
  3034  	ctx := testContext2(t, &ContextOpts{
  3035  		Providers: map[addrs.Provider]providers.Factory{
  3036  			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
  3037  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
  3038  		},
  3039  	})
  3040  
  3041  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3042  	assertNoErrors(t, diags)
  3043  
  3044  	state, diags := ctx.Apply(plan, m)
  3045  	if diags.HasErrors() {
  3046  		t.Fatalf("diags: %s", diags.Err())
  3047  	}
  3048  
  3049  	actual := strings.TrimSpace(state.String())
  3050  	expected := strings.TrimSpace(testTofuApplyModuleOnlyProviderStr)
  3051  	if actual != expected {
  3052  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3053  	}
  3054  }
  3055  
  3056  func TestContext2Apply_moduleProviderAlias(t *testing.T) {
  3057  	m := testModule(t, "apply-module-provider-alias")
  3058  	p := testProvider("aws")
  3059  	p.PlanResourceChangeFn = testDiffFn
  3060  	p.ApplyResourceChangeFn = testApplyFn
  3061  	ctx := testContext2(t, &ContextOpts{
  3062  		Providers: map[addrs.Provider]providers.Factory{
  3063  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3064  		},
  3065  	})
  3066  
  3067  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3068  	assertNoErrors(t, diags)
  3069  
  3070  	state, diags := ctx.Apply(plan, m)
  3071  	if diags.HasErrors() {
  3072  		t.Fatalf("diags: %s", diags.Err())
  3073  	}
  3074  
  3075  	actual := strings.TrimSpace(state.String())
  3076  	expected := strings.TrimSpace(testTofuApplyModuleProviderAliasStr)
  3077  	if actual != expected {
  3078  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3079  	}
  3080  }
  3081  
  3082  func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) {
  3083  	m := testModule(t, "apply-module-provider-alias")
  3084  	p := testProvider("aws")
  3085  	p.PlanResourceChangeFn = testDiffFn
  3086  	ctx := testContext2(t, &ContextOpts{
  3087  		Providers: map[addrs.Provider]providers.Factory{
  3088  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3089  		},
  3090  	})
  3091  
  3092  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3093  		Mode: plans.NormalMode,
  3094  		Targets: []addrs.Targetable{
  3095  			addrs.ConfigResource{
  3096  				Module: addrs.RootModule,
  3097  				Resource: addrs.Resource{
  3098  					Mode: addrs.ManagedResourceMode,
  3099  					Type: "nonexistent",
  3100  					Name: "thing",
  3101  				},
  3102  			},
  3103  		},
  3104  	})
  3105  	assertNoErrors(t, diags)
  3106  
  3107  	state, diags := ctx.Apply(plan, m)
  3108  	if diags.HasErrors() {
  3109  		t.Fatalf("diags: %s", diags.Err())
  3110  	}
  3111  
  3112  	actual := strings.TrimSpace(state.String())
  3113  	expected := strings.TrimSpace(`
  3114  <no state>
  3115  	`)
  3116  	if actual != expected {
  3117  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3118  	}
  3119  }
  3120  
  3121  func TestContext2Apply_moduleProviderCloseNested(t *testing.T) {
  3122  	m := testModule(t, "apply-module-provider-close-nested")
  3123  	p := testProvider("aws")
  3124  	p.PlanResourceChangeFn = testDiffFn
  3125  	state := states.NewState()
  3126  	root := state.EnsureModule(addrs.RootModuleInstance)
  3127  	root.SetResourceInstanceCurrent(
  3128  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  3129  		&states.ResourceInstanceObjectSrc{
  3130  			Status:    states.ObjectReady,
  3131  			AttrsJSON: []byte(`{"id":"bar"}`),
  3132  		},
  3133  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  3134  	)
  3135  
  3136  	ctx := testContext2(t, &ContextOpts{
  3137  		Providers: map[addrs.Provider]providers.Factory{
  3138  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3139  		},
  3140  	})
  3141  
  3142  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  3143  		Mode: plans.DestroyMode,
  3144  	})
  3145  	assertNoErrors(t, diags)
  3146  
  3147  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3148  		t.Fatalf("apply errors: %s", diags.Err())
  3149  	}
  3150  }
  3151  
  3152  // Tests that variables used as module vars that reference data that
  3153  // already exists in the state and requires no diff works properly. This
  3154  // fixes an issue faced where module variables were pruned because they were
  3155  // accessing "non-existent" resources (they existed, just not in the graph
  3156  // cause they weren't in the diff).
  3157  func TestContext2Apply_moduleVarRefExisting(t *testing.T) {
  3158  	m := testModule(t, "apply-ref-existing")
  3159  	p := testProvider("aws")
  3160  	p.PlanResourceChangeFn = testDiffFn
  3161  	p.ApplyResourceChangeFn = testApplyFn
  3162  	state := states.NewState()
  3163  	root := state.EnsureModule(addrs.RootModuleInstance)
  3164  	root.SetResourceInstanceCurrent(
  3165  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  3166  		&states.ResourceInstanceObjectSrc{
  3167  			Status:    states.ObjectReady,
  3168  			AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`),
  3169  		},
  3170  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  3171  	)
  3172  
  3173  	ctx := testContext2(t, &ContextOpts{
  3174  		Providers: map[addrs.Provider]providers.Factory{
  3175  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3176  		},
  3177  	})
  3178  
  3179  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3180  	assertNoErrors(t, diags)
  3181  
  3182  	state, diags = ctx.Apply(plan, m)
  3183  	if diags.HasErrors() {
  3184  		t.Fatalf("diags: %s", diags.Err())
  3185  	}
  3186  
  3187  	actual := strings.TrimSpace(state.String())
  3188  	expected := strings.TrimSpace(testTofuApplyModuleVarRefExistingStr)
  3189  	if actual != expected {
  3190  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3191  	}
  3192  }
  3193  
  3194  func TestContext2Apply_moduleVarResourceCount(t *testing.T) {
  3195  	m := testModule(t, "apply-module-var-resource-count")
  3196  	p := testProvider("aws")
  3197  	p.PlanResourceChangeFn = testDiffFn
  3198  	ctx := testContext2(t, &ContextOpts{
  3199  		Providers: map[addrs.Provider]providers.Factory{
  3200  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3201  		},
  3202  	})
  3203  
  3204  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3205  		Mode: plans.DestroyMode,
  3206  		SetVariables: InputValues{
  3207  			"num": &InputValue{
  3208  				Value:      cty.NumberIntVal(2),
  3209  				SourceType: ValueFromCaller,
  3210  			},
  3211  		},
  3212  	})
  3213  	assertNoErrors(t, diags)
  3214  
  3215  	state, diags := ctx.Apply(plan, m)
  3216  	assertNoErrors(t, diags)
  3217  
  3218  	ctx = testContext2(t, &ContextOpts{
  3219  		Providers: map[addrs.Provider]providers.Factory{
  3220  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3221  		},
  3222  	})
  3223  
  3224  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  3225  		Mode: plans.NormalMode,
  3226  		SetVariables: InputValues{
  3227  			"num": &InputValue{
  3228  				Value:      cty.NumberIntVal(5),
  3229  				SourceType: ValueFromCaller,
  3230  			},
  3231  		},
  3232  	})
  3233  	assertNoErrors(t, diags)
  3234  
  3235  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3236  		t.Fatalf("apply errors: %s", diags.Err())
  3237  	}
  3238  }
  3239  
  3240  // GH-819
  3241  func TestContext2Apply_moduleBool(t *testing.T) {
  3242  	m := testModule(t, "apply-module-bool")
  3243  	p := testProvider("aws")
  3244  	p.PlanResourceChangeFn = testDiffFn
  3245  	p.ApplyResourceChangeFn = testApplyFn
  3246  	ctx := testContext2(t, &ContextOpts{
  3247  		Providers: map[addrs.Provider]providers.Factory{
  3248  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3249  		},
  3250  	})
  3251  
  3252  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3253  	assertNoErrors(t, diags)
  3254  
  3255  	state, diags := ctx.Apply(plan, m)
  3256  	if diags.HasErrors() {
  3257  		t.Fatalf("diags: %s", diags.Err())
  3258  	}
  3259  
  3260  	actual := strings.TrimSpace(state.String())
  3261  	expected := strings.TrimSpace(testTofuApplyModuleBoolStr)
  3262  	if actual != expected {
  3263  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3264  	}
  3265  }
  3266  
  3267  // Tests that a module can be targeted and everything is properly created.
  3268  // This adds to the plan test to also just verify that apply works.
  3269  func TestContext2Apply_moduleTarget(t *testing.T) {
  3270  	m := testModule(t, "plan-targeted-cross-module")
  3271  	p := testProvider("aws")
  3272  	p.PlanResourceChangeFn = testDiffFn
  3273  	p.ApplyResourceChangeFn = testApplyFn
  3274  	ctx := testContext2(t, &ContextOpts{
  3275  		Providers: map[addrs.Provider]providers.Factory{
  3276  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3277  		},
  3278  	})
  3279  
  3280  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3281  		Mode: plans.NormalMode,
  3282  		Targets: []addrs.Targetable{
  3283  			addrs.RootModuleInstance.Child("B", addrs.NoKey),
  3284  		},
  3285  	})
  3286  	assertNoErrors(t, diags)
  3287  
  3288  	state, diags := ctx.Apply(plan, m)
  3289  	if diags.HasErrors() {
  3290  		t.Fatalf("diags: %s", diags.Err())
  3291  	}
  3292  
  3293  	checkStateString(t, state, `
  3294  <no state>
  3295  module.A:
  3296    aws_instance.foo:
  3297      ID = foo
  3298      provider = provider["registry.opentofu.org/hashicorp/aws"]
  3299      foo = bar
  3300      type = aws_instance
  3301  
  3302    Outputs:
  3303  
  3304    value = foo
  3305  module.B:
  3306    aws_instance.bar:
  3307      ID = foo
  3308      provider = provider["registry.opentofu.org/hashicorp/aws"]
  3309      foo = foo
  3310      type = aws_instance
  3311  
  3312      Dependencies:
  3313        module.A.aws_instance.foo
  3314  	`)
  3315  }
  3316  
  3317  func TestContext2Apply_multiProvider(t *testing.T) {
  3318  	m := testModule(t, "apply-multi-provider")
  3319  	p := testProvider("aws")
  3320  	p.PlanResourceChangeFn = testDiffFn
  3321  	p.ApplyResourceChangeFn = testApplyFn
  3322  
  3323  	pDO := testProvider("do")
  3324  	pDO.ApplyResourceChangeFn = testApplyFn
  3325  	pDO.PlanResourceChangeFn = testDiffFn
  3326  
  3327  	ctx := testContext2(t, &ContextOpts{
  3328  		Providers: map[addrs.Provider]providers.Factory{
  3329  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3330  			addrs.NewDefaultProvider("do"):  testProviderFuncFixed(pDO),
  3331  		},
  3332  	})
  3333  
  3334  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3335  	assertNoErrors(t, diags)
  3336  
  3337  	state, diags := ctx.Apply(plan, m)
  3338  	if diags.HasErrors() {
  3339  		t.Fatalf("diags: %s", diags.Err())
  3340  	}
  3341  
  3342  	mod := state.RootModule()
  3343  	if len(mod.Resources) < 2 {
  3344  		t.Fatalf("bad: %#v", mod.Resources)
  3345  	}
  3346  
  3347  	actual := strings.TrimSpace(state.String())
  3348  	expected := strings.TrimSpace(testTofuApplyMultiProviderStr)
  3349  	if actual != expected {
  3350  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3351  	}
  3352  }
  3353  
  3354  func TestContext2Apply_multiProviderDestroy(t *testing.T) {
  3355  	m := testModule(t, "apply-multi-provider-destroy")
  3356  	p := testProvider("aws")
  3357  	p.PlanResourceChangeFn = testDiffFn
  3358  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3359  		Provider: &configschema.Block{
  3360  			Attributes: map[string]*configschema.Attribute{
  3361  				"addr": {Type: cty.String, Optional: true},
  3362  			},
  3363  		},
  3364  		ResourceTypes: map[string]*configschema.Block{
  3365  			"aws_instance": {
  3366  				Attributes: map[string]*configschema.Attribute{
  3367  					"id":  {Type: cty.String, Computed: true},
  3368  					"foo": {Type: cty.String, Optional: true},
  3369  				},
  3370  			},
  3371  		},
  3372  	})
  3373  
  3374  	p2 := testProvider("vault")
  3375  	p2.ApplyResourceChangeFn = testApplyFn
  3376  	p2.PlanResourceChangeFn = testDiffFn
  3377  	p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3378  		ResourceTypes: map[string]*configschema.Block{
  3379  			"vault_instance": {
  3380  				Attributes: map[string]*configschema.Attribute{
  3381  					"id": {Type: cty.String, Computed: true},
  3382  				},
  3383  			},
  3384  		},
  3385  	})
  3386  
  3387  	var state *states.State
  3388  
  3389  	// First, create the instances
  3390  	{
  3391  		ctx := testContext2(t, &ContextOpts{
  3392  			Providers: map[addrs.Provider]providers.Factory{
  3393  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3394  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3395  			},
  3396  		})
  3397  
  3398  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3399  		assertNoErrors(t, diags)
  3400  
  3401  		s, diags := ctx.Apply(plan, m)
  3402  		assertNoErrors(t, diags)
  3403  
  3404  		state = s
  3405  	}
  3406  
  3407  	// Destroy them
  3408  	{
  3409  		// Verify that aws_instance.bar is destroyed first
  3410  		var checked bool
  3411  		var called int32
  3412  		var lock sync.Mutex
  3413  		applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3414  			lock.Lock()
  3415  			defer lock.Unlock()
  3416  
  3417  			if req.TypeName == "aws_instance" {
  3418  				checked = true
  3419  
  3420  				// Sleep to allow parallel execution
  3421  				time.Sleep(50 * time.Millisecond)
  3422  
  3423  				// Verify that called is 0 (dep not called)
  3424  				if atomic.LoadInt32(&called) != 0 {
  3425  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3426  					return resp
  3427  				}
  3428  			}
  3429  
  3430  			atomic.AddInt32(&called, 1)
  3431  			return testApplyFn(req)
  3432  		}
  3433  
  3434  		// Set the apply functions
  3435  		p.ApplyResourceChangeFn = applyFn
  3436  		p2.ApplyResourceChangeFn = applyFn
  3437  
  3438  		ctx := testContext2(t, &ContextOpts{
  3439  			Providers: map[addrs.Provider]providers.Factory{
  3440  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3441  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3442  			},
  3443  		})
  3444  
  3445  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3446  			Mode: plans.DestroyMode,
  3447  		})
  3448  		assertNoErrors(t, diags)
  3449  
  3450  		s, diags := ctx.Apply(plan, m)
  3451  		assertNoErrors(t, diags)
  3452  
  3453  		if !checked {
  3454  			t.Fatal("should be checked")
  3455  		}
  3456  
  3457  		state = s
  3458  	}
  3459  
  3460  	checkStateString(t, state, `<no state>`)
  3461  }
  3462  
  3463  // This is like the multiProviderDestroy test except it tests that
  3464  // dependent resources within a child module that inherit provider
  3465  // configuration are still destroyed first.
  3466  func TestContext2Apply_multiProviderDestroyChild(t *testing.T) {
  3467  	m := testModule(t, "apply-multi-provider-destroy-child")
  3468  	p := testProvider("aws")
  3469  	p.PlanResourceChangeFn = testDiffFn
  3470  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3471  		Provider: &configschema.Block{
  3472  			Attributes: map[string]*configschema.Attribute{
  3473  				"value": {Type: cty.String, Optional: true},
  3474  			},
  3475  		},
  3476  		ResourceTypes: map[string]*configschema.Block{
  3477  			"aws_instance": {
  3478  				Attributes: map[string]*configschema.Attribute{
  3479  					"id":  {Type: cty.String, Computed: true},
  3480  					"foo": {Type: cty.String, Optional: true},
  3481  				},
  3482  			},
  3483  		},
  3484  	})
  3485  
  3486  	p2 := testProvider("vault")
  3487  	p2.ApplyResourceChangeFn = testApplyFn
  3488  	p2.PlanResourceChangeFn = testDiffFn
  3489  	p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3490  		Provider: &configschema.Block{},
  3491  		ResourceTypes: map[string]*configschema.Block{
  3492  			"vault_instance": {
  3493  				Attributes: map[string]*configschema.Attribute{
  3494  					"id": {Type: cty.String, Computed: true},
  3495  				},
  3496  			},
  3497  		},
  3498  	})
  3499  
  3500  	var state *states.State
  3501  
  3502  	// First, create the instances
  3503  	{
  3504  		ctx := testContext2(t, &ContextOpts{
  3505  			Providers: map[addrs.Provider]providers.Factory{
  3506  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3507  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3508  			},
  3509  		})
  3510  
  3511  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3512  		assertNoErrors(t, diags)
  3513  
  3514  		s, diags := ctx.Apply(plan, m)
  3515  		if diags.HasErrors() {
  3516  			t.Fatalf("diags: %s", diags.Err())
  3517  		}
  3518  
  3519  		state = s
  3520  	}
  3521  
  3522  	// Destroy them
  3523  	{
  3524  		// Verify that aws_instance.bar is destroyed first
  3525  		var checked bool
  3526  		var called int32
  3527  		var lock sync.Mutex
  3528  		applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3529  			lock.Lock()
  3530  			defer lock.Unlock()
  3531  
  3532  			if req.TypeName == "aws_instance" {
  3533  				checked = true
  3534  
  3535  				// Sleep to allow parallel execution
  3536  				time.Sleep(50 * time.Millisecond)
  3537  
  3538  				// Verify that called is 0 (dep not called)
  3539  				if atomic.LoadInt32(&called) != 0 {
  3540  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3541  					return resp
  3542  				}
  3543  			}
  3544  
  3545  			atomic.AddInt32(&called, 1)
  3546  			return testApplyFn(req)
  3547  		}
  3548  
  3549  		// Set the apply functions
  3550  		p.ApplyResourceChangeFn = applyFn
  3551  		p2.ApplyResourceChangeFn = applyFn
  3552  
  3553  		ctx := testContext2(t, &ContextOpts{
  3554  			Providers: map[addrs.Provider]providers.Factory{
  3555  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3556  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3557  			},
  3558  		})
  3559  
  3560  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3561  			Mode: plans.DestroyMode,
  3562  		})
  3563  		assertNoErrors(t, diags)
  3564  
  3565  		s, diags := ctx.Apply(plan, m)
  3566  		if diags.HasErrors() {
  3567  			t.Fatalf("diags: %s", diags.Err())
  3568  		}
  3569  
  3570  		if !checked {
  3571  			t.Fatal("should be checked")
  3572  		}
  3573  
  3574  		state = s
  3575  	}
  3576  
  3577  	checkStateString(t, state, `
  3578  <no state>
  3579  `)
  3580  }
  3581  
  3582  func TestContext2Apply_multiVar(t *testing.T) {
  3583  	m := testModule(t, "apply-multi-var")
  3584  	p := testProvider("aws")
  3585  	p.PlanResourceChangeFn = testDiffFn
  3586  
  3587  	// First, apply with a count of 3
  3588  	ctx := testContext2(t, &ContextOpts{
  3589  		Providers: map[addrs.Provider]providers.Factory{
  3590  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3591  		},
  3592  	})
  3593  
  3594  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3595  		Mode: plans.NormalMode,
  3596  		SetVariables: InputValues{
  3597  			"num": &InputValue{
  3598  				Value:      cty.NumberIntVal(3),
  3599  				SourceType: ValueFromCaller,
  3600  			},
  3601  		},
  3602  	})
  3603  	assertNoErrors(t, diags)
  3604  
  3605  	state, diags := ctx.Apply(plan, m)
  3606  	if diags.HasErrors() {
  3607  		t.Fatalf("diags: %s", diags.Err())
  3608  	}
  3609  
  3610  	actual := state.RootModule().OutputValues["output"]
  3611  	expected := cty.StringVal("bar0,bar1,bar2")
  3612  	if actual == nil || actual.Value != expected {
  3613  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3614  	}
  3615  
  3616  	t.Logf("Initial state: %s", state.String())
  3617  
  3618  	// Apply again, reduce the count to 1
  3619  	{
  3620  		ctx := testContext2(t, &ContextOpts{
  3621  			Providers: map[addrs.Provider]providers.Factory{
  3622  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3623  			},
  3624  		})
  3625  
  3626  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3627  			Mode: plans.NormalMode,
  3628  			SetVariables: InputValues{
  3629  				"num": &InputValue{
  3630  					Value:      cty.NumberIntVal(1),
  3631  					SourceType: ValueFromCaller,
  3632  				},
  3633  			},
  3634  		})
  3635  		assertNoErrors(t, diags)
  3636  
  3637  		state, diags := ctx.Apply(plan, m)
  3638  		if diags.HasErrors() {
  3639  			t.Fatalf("diags: %s", diags.Err())
  3640  		}
  3641  
  3642  		t.Logf("End state: %s", state.String())
  3643  
  3644  		actual := state.RootModule().OutputValues["output"]
  3645  		if actual == nil {
  3646  			t.Fatal("missing output")
  3647  		}
  3648  
  3649  		expected := cty.StringVal("bar0")
  3650  		if actual.Value != expected {
  3651  			t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3652  		}
  3653  	}
  3654  }
  3655  
  3656  // This is a holistic test of multi-var (aka "splat variable") handling
  3657  // across several different OpenTofu subsystems. This is here because
  3658  // historically there were quirky differences in handling across different
  3659  // parts of OpenTofu and so here we want to assert the expected behavior and
  3660  // ensure that it remains consistent in future.
  3661  func TestContext2Apply_multiVarComprehensive(t *testing.T) {
  3662  	m := testModule(t, "apply-multi-var-comprehensive")
  3663  	p := testProvider("test")
  3664  
  3665  	configs := map[string]cty.Value{}
  3666  	var configsLock sync.Mutex
  3667  
  3668  	p.ApplyResourceChangeFn = testApplyFn
  3669  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  3670  		proposed := req.ProposedNewState
  3671  		configsLock.Lock()
  3672  		defer configsLock.Unlock()
  3673  		key := proposed.GetAttr("key").AsString()
  3674  		// This test was originally written using the legacy p.PlanResourceChangeFn interface,
  3675  		// and so the assertions below expect an old-style ResourceConfig, which
  3676  		// we'll construct via our shim for now to avoid rewriting all of the
  3677  		// assertions.
  3678  		configs[key] = req.ProposedNewState
  3679  
  3680  		retVals := make(map[string]cty.Value)
  3681  		for it := proposed.ElementIterator(); it.Next(); {
  3682  			idxVal, val := it.Element()
  3683  			idx := idxVal.AsString()
  3684  
  3685  			switch idx {
  3686  			case "id":
  3687  				retVals[idx] = cty.UnknownVal(cty.String)
  3688  			case "name":
  3689  				retVals[idx] = cty.StringVal(key)
  3690  			default:
  3691  				retVals[idx] = val
  3692  			}
  3693  		}
  3694  
  3695  		return providers.PlanResourceChangeResponse{
  3696  			PlannedState: cty.ObjectVal(retVals),
  3697  		}
  3698  	}
  3699  
  3700  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3701  		ResourceTypes: map[string]*configschema.Block{
  3702  			"test_thing": {
  3703  				Attributes: map[string]*configschema.Attribute{
  3704  					"key": {Type: cty.String, Required: true},
  3705  
  3706  					"source_id":              {Type: cty.String, Optional: true},
  3707  					"source_name":            {Type: cty.String, Optional: true},
  3708  					"first_source_id":        {Type: cty.String, Optional: true},
  3709  					"first_source_name":      {Type: cty.String, Optional: true},
  3710  					"source_ids":             {Type: cty.List(cty.String), Optional: true},
  3711  					"source_names":           {Type: cty.List(cty.String), Optional: true},
  3712  					"source_ids_from_func":   {Type: cty.List(cty.String), Optional: true},
  3713  					"source_names_from_func": {Type: cty.List(cty.String), Optional: true},
  3714  					"source_ids_wrapped":     {Type: cty.List(cty.List(cty.String)), Optional: true},
  3715  					"source_names_wrapped":   {Type: cty.List(cty.List(cty.String)), Optional: true},
  3716  
  3717  					"id":   {Type: cty.String, Computed: true},
  3718  					"name": {Type: cty.String, Computed: true},
  3719  				},
  3720  			},
  3721  		},
  3722  	})
  3723  
  3724  	// First, apply with a count of 3
  3725  	ctx := testContext2(t, &ContextOpts{
  3726  		Providers: map[addrs.Provider]providers.Factory{
  3727  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  3728  		},
  3729  	})
  3730  
  3731  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3732  		Mode: plans.NormalMode,
  3733  		SetVariables: InputValues{
  3734  			"num": &InputValue{
  3735  				Value:      cty.NumberIntVal(3),
  3736  				SourceType: ValueFromCaller,
  3737  			},
  3738  		},
  3739  	})
  3740  	assertNoErrors(t, diags)
  3741  
  3742  	checkConfig := func(key string, want cty.Value) {
  3743  		configsLock.Lock()
  3744  		defer configsLock.Unlock()
  3745  
  3746  		got, ok := configs[key]
  3747  		if !ok {
  3748  			t.Errorf("no config recorded for %s; expected a configuration", key)
  3749  			return
  3750  		}
  3751  
  3752  		t.Run("config for "+key, func(t *testing.T) {
  3753  			for _, problem := range deep.Equal(got, want) {
  3754  				t.Errorf(problem)
  3755  			}
  3756  		})
  3757  	}
  3758  
  3759  	checkConfig("multi_count_var.0", cty.ObjectVal(map[string]cty.Value{
  3760  		"source_id":   cty.UnknownVal(cty.String),
  3761  		"source_name": cty.StringVal("source.0"),
  3762  	}))
  3763  	checkConfig("multi_count_var.2", cty.ObjectVal(map[string]cty.Value{
  3764  		"source_id":   cty.UnknownVal(cty.String),
  3765  		"source_name": cty.StringVal("source.2"),
  3766  	}))
  3767  	checkConfig("multi_count_derived.0", cty.ObjectVal(map[string]cty.Value{
  3768  		"source_id":   cty.UnknownVal(cty.String),
  3769  		"source_name": cty.StringVal("source.0"),
  3770  	}))
  3771  	checkConfig("multi_count_derived.2", cty.ObjectVal(map[string]cty.Value{
  3772  		"source_id":   cty.UnknownVal(cty.String),
  3773  		"source_name": cty.StringVal("source.2"),
  3774  	}))
  3775  	checkConfig("whole_splat", cty.ObjectVal(map[string]cty.Value{
  3776  		"source_ids": cty.ListVal([]cty.Value{
  3777  			cty.UnknownVal(cty.String),
  3778  			cty.UnknownVal(cty.String),
  3779  			cty.UnknownVal(cty.String),
  3780  		}),
  3781  		"source_names": cty.ListVal([]cty.Value{
  3782  			cty.StringVal("source.0"),
  3783  			cty.StringVal("source.1"),
  3784  			cty.StringVal("source.2"),
  3785  		}),
  3786  		"source_ids_from_func": cty.UnknownVal(cty.String),
  3787  		"source_names_from_func": cty.ListVal([]cty.Value{
  3788  			cty.StringVal("source.0"),
  3789  			cty.StringVal("source.1"),
  3790  			cty.StringVal("source.2"),
  3791  		}),
  3792  		"source_ids_wrapped": cty.ListVal([]cty.Value{
  3793  			cty.ListVal([]cty.Value{
  3794  				cty.UnknownVal(cty.String),
  3795  				cty.UnknownVal(cty.String),
  3796  				cty.UnknownVal(cty.String),
  3797  			}),
  3798  		}),
  3799  		"source_names_wrapped": cty.ListVal([]cty.Value{
  3800  			cty.ListVal([]cty.Value{
  3801  				cty.StringVal("source.0"),
  3802  				cty.StringVal("source.1"),
  3803  				cty.StringVal("source.2"),
  3804  			}),
  3805  		}),
  3806  		"first_source_id":   cty.UnknownVal(cty.String),
  3807  		"first_source_name": cty.StringVal("source.0"),
  3808  	}))
  3809  	checkConfig("child.whole_splat", cty.ObjectVal(map[string]cty.Value{
  3810  		"source_ids": cty.ListVal([]cty.Value{
  3811  			cty.UnknownVal(cty.String),
  3812  			cty.UnknownVal(cty.String),
  3813  			cty.UnknownVal(cty.String),
  3814  		}),
  3815  		"source_names": cty.ListVal([]cty.Value{
  3816  			cty.StringVal("source.0"),
  3817  			cty.StringVal("source.1"),
  3818  			cty.StringVal("source.2"),
  3819  		}),
  3820  		"source_ids_wrapped": cty.ListVal([]cty.Value{
  3821  			cty.ListVal([]cty.Value{
  3822  				cty.UnknownVal(cty.String),
  3823  				cty.UnknownVal(cty.String),
  3824  				cty.UnknownVal(cty.String),
  3825  			}),
  3826  		}),
  3827  		"source_names_wrapped": cty.ListVal([]cty.Value{
  3828  			cty.ListVal([]cty.Value{
  3829  				cty.StringVal("source.0"),
  3830  				cty.StringVal("source.1"),
  3831  				cty.StringVal("source.2"),
  3832  			}),
  3833  		}),
  3834  	}))
  3835  
  3836  	t.Run("apply", func(t *testing.T) {
  3837  		state, diags := ctx.Apply(plan, m)
  3838  		if diags.HasErrors() {
  3839  			t.Fatalf("error during apply: %s", diags.Err())
  3840  		}
  3841  
  3842  		want := map[string]interface{}{
  3843  			"source_ids": []interface{}{"foo", "foo", "foo"},
  3844  			"source_names": []interface{}{
  3845  				"source.0",
  3846  				"source.1",
  3847  				"source.2",
  3848  			},
  3849  		}
  3850  		got := map[string]interface{}{}
  3851  		for k, s := range state.RootModule().OutputValues {
  3852  			got[k] = hcl2shim.ConfigValueFromHCL2(s.Value)
  3853  		}
  3854  		if !reflect.DeepEqual(got, want) {
  3855  			t.Errorf(
  3856  				"wrong outputs\ngot:  %s\nwant: %s",
  3857  				spew.Sdump(got), spew.Sdump(want),
  3858  			)
  3859  		}
  3860  	})
  3861  }
  3862  
  3863  // Test that multi-var (splat) access is ordered by count, not by
  3864  // value.
  3865  func TestContext2Apply_multiVarOrder(t *testing.T) {
  3866  	m := testModule(t, "apply-multi-var-order")
  3867  	p := testProvider("aws")
  3868  	p.PlanResourceChangeFn = testDiffFn
  3869  
  3870  	// First, apply with a count of 3
  3871  	ctx := testContext2(t, &ContextOpts{
  3872  		Providers: map[addrs.Provider]providers.Factory{
  3873  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3874  		},
  3875  	})
  3876  
  3877  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  3878  	assertNoErrors(t, diags)
  3879  
  3880  	state, diags := ctx.Apply(plan, m)
  3881  	if diags.HasErrors() {
  3882  		t.Fatalf("diags: %s", diags.Err())
  3883  	}
  3884  
  3885  	t.Logf("State: %s", state.String())
  3886  
  3887  	actual := state.RootModule().OutputValues["should-be-11"]
  3888  	expected := cty.StringVal("index-11")
  3889  	if actual == nil || actual.Value != expected {
  3890  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3891  	}
  3892  }
  3893  
  3894  // Test that multi-var (splat) access is ordered by count, not by
  3895  // value, through interpolations.
  3896  func TestContext2Apply_multiVarOrderInterp(t *testing.T) {
  3897  	m := testModule(t, "apply-multi-var-order-interp")
  3898  	p := testProvider("aws")
  3899  	p.PlanResourceChangeFn = testDiffFn
  3900  
  3901  	// First, apply with a count of 3
  3902  	ctx := testContext2(t, &ContextOpts{
  3903  		Providers: map[addrs.Provider]providers.Factory{
  3904  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3905  		},
  3906  	})
  3907  
  3908  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  3909  	assertNoErrors(t, diags)
  3910  
  3911  	state, diags := ctx.Apply(plan, m)
  3912  	if diags.HasErrors() {
  3913  		t.Fatalf("diags: %s", diags.Err())
  3914  	}
  3915  
  3916  	t.Logf("State: %s", state.String())
  3917  
  3918  	actual := state.RootModule().OutputValues["should-be-11"]
  3919  	expected := cty.StringVal("baz-index-11")
  3920  	if actual == nil || actual.Value != expected {
  3921  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3922  	}
  3923  }
  3924  
  3925  // Based on GH-10440 where a graph edge wasn't properly being created
  3926  // between a modified resource and a count instance being destroyed.
  3927  func TestContext2Apply_multiVarCountDec(t *testing.T) {
  3928  	var s *states.State
  3929  
  3930  	// First create resources. Nothing sneaky here.
  3931  	{
  3932  		m := testModule(t, "apply-multi-var-count-dec")
  3933  		p := testProvider("aws")
  3934  		p.PlanResourceChangeFn = testDiffFn
  3935  		p.ApplyResourceChangeFn = testApplyFn
  3936  		ctx := testContext2(t, &ContextOpts{
  3937  			Providers: map[addrs.Provider]providers.Factory{
  3938  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3939  			},
  3940  		})
  3941  
  3942  		log.Print("\n========\nStep 1 Plan\n========")
  3943  		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3944  			Mode: plans.NormalMode,
  3945  			SetVariables: InputValues{
  3946  				"num": &InputValue{
  3947  					Value:      cty.NumberIntVal(2),
  3948  					SourceType: ValueFromCaller,
  3949  				},
  3950  			},
  3951  		})
  3952  		assertNoErrors(t, diags)
  3953  
  3954  		log.Print("\n========\nStep 1 Apply\n========")
  3955  		state, diags := ctx.Apply(plan, m)
  3956  		if diags.HasErrors() {
  3957  			t.Fatalf("diags: %s", diags.Err())
  3958  		}
  3959  
  3960  		t.Logf("Step 1 state:\n%s", state)
  3961  
  3962  		s = state
  3963  	}
  3964  
  3965  	// Decrease the count by 1 and verify that everything happens in the
  3966  	// right order.
  3967  	m := testModule(t, "apply-multi-var-count-dec")
  3968  	p := testProvider("aws")
  3969  	p.PlanResourceChangeFn = testDiffFn
  3970  
  3971  	// Verify that aws_instance.bar is modified first and nothing
  3972  	// else happens at the same time.
  3973  	{
  3974  		var checked bool
  3975  		var called int32
  3976  		var lock sync.Mutex
  3977  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3978  			lock.Lock()
  3979  			defer lock.Unlock()
  3980  
  3981  			if !req.PlannedState.IsNull() {
  3982  				s := req.PlannedState.AsValueMap()
  3983  				if ami, ok := s["ami"]; ok && !ami.IsNull() && ami.AsString() == "special" {
  3984  					checked = true
  3985  
  3986  					// Sleep to allow parallel execution
  3987  					time.Sleep(50 * time.Millisecond)
  3988  
  3989  					// Verify that called is 0 (dep not called)
  3990  					if atomic.LoadInt32(&called) != 1 {
  3991  						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3992  						return
  3993  					}
  3994  				}
  3995  			}
  3996  			atomic.AddInt32(&called, 1)
  3997  			return testApplyFn(req)
  3998  		}
  3999  
  4000  		ctx := testContext2(t, &ContextOpts{
  4001  			Providers: map[addrs.Provider]providers.Factory{
  4002  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4003  			},
  4004  		})
  4005  
  4006  		log.Print("\n========\nStep 2 Plan\n========")
  4007  		plan, diags := ctx.Plan(m, s, &PlanOpts{
  4008  			Mode: plans.NormalMode,
  4009  			SetVariables: InputValues{
  4010  				"num": &InputValue{
  4011  					Value:      cty.NumberIntVal(1),
  4012  					SourceType: ValueFromCaller,
  4013  				},
  4014  			},
  4015  		})
  4016  		assertNoErrors(t, diags)
  4017  
  4018  		t.Logf("Step 2 plan:\n%s", legacyDiffComparisonString(plan.Changes))
  4019  
  4020  		log.Print("\n========\nStep 2 Apply\n========")
  4021  		_, diags = ctx.Apply(plan, m)
  4022  		if diags.HasErrors() {
  4023  			t.Fatalf("apply errors: %s", diags.Err())
  4024  		}
  4025  
  4026  		if !checked {
  4027  			t.Error("apply never called")
  4028  		}
  4029  	}
  4030  }
  4031  
  4032  // Test that we can resolve a multi-var (splat) for the first resource
  4033  // created in a non-root module, which happens when the module state doesn't
  4034  // exist yet.
  4035  // https://github.com/hashicorp/terraform/issues/14438
  4036  func TestContext2Apply_multiVarMissingState(t *testing.T) {
  4037  	m := testModule(t, "apply-multi-var-missing-state")
  4038  	p := testProvider("test")
  4039  	p.PlanResourceChangeFn = testDiffFn
  4040  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4041  		ResourceTypes: map[string]*configschema.Block{
  4042  			"test_thing": {
  4043  				Attributes: map[string]*configschema.Attribute{
  4044  					"a_ids": {Type: cty.String, Optional: true},
  4045  					"id":    {Type: cty.String, Computed: true},
  4046  				},
  4047  			},
  4048  		},
  4049  	})
  4050  
  4051  	// First, apply with a count of 3
  4052  	ctx := testContext2(t, &ContextOpts{
  4053  		Providers: map[addrs.Provider]providers.Factory{
  4054  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  4055  		},
  4056  	})
  4057  
  4058  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4059  	assertNoErrors(t, diags)
  4060  
  4061  	// Before the relevant bug was fixed, OpenTofu would panic during apply.
  4062  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  4063  		t.Fatalf("apply failed: %s", diags.Err())
  4064  	}
  4065  
  4066  	// If we get here with no errors or panics then our test was successful.
  4067  }
  4068  
  4069  func TestContext2Apply_outputOrphan(t *testing.T) {
  4070  	m := testModule(t, "apply-output-orphan")
  4071  	p := testProvider("aws")
  4072  	p.PlanResourceChangeFn = testDiffFn
  4073  
  4074  	state := states.NewState()
  4075  	root := state.EnsureModule(addrs.RootModuleInstance)
  4076  	root.SetOutputValue("foo", cty.StringVal("bar"), false)
  4077  	root.SetOutputValue("bar", cty.StringVal("baz"), false)
  4078  
  4079  	ctx := testContext2(t, &ContextOpts{
  4080  		Providers: map[addrs.Provider]providers.Factory{
  4081  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4082  		},
  4083  	})
  4084  
  4085  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4086  	assertNoErrors(t, diags)
  4087  
  4088  	state, diags = ctx.Apply(plan, m)
  4089  	if diags.HasErrors() {
  4090  		t.Fatalf("diags: %s", diags.Err())
  4091  	}
  4092  
  4093  	actual := strings.TrimSpace(state.String())
  4094  	expected := strings.TrimSpace(testTofuApplyOutputOrphanStr)
  4095  	if actual != expected {
  4096  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4097  	}
  4098  }
  4099  
  4100  func TestContext2Apply_outputOrphanModule(t *testing.T) {
  4101  	m := testModule(t, "apply-output-orphan-module")
  4102  	p := testProvider("aws")
  4103  	p.PlanResourceChangeFn = testDiffFn
  4104  
  4105  	state := states.NewState()
  4106  
  4107  	ctx := testContext2(t, &ContextOpts{
  4108  		Providers: map[addrs.Provider]providers.Factory{
  4109  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4110  		},
  4111  	})
  4112  
  4113  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4114  	assertNoErrors(t, diags)
  4115  
  4116  	s, diags := ctx.Apply(plan, m)
  4117  	if diags.HasErrors() {
  4118  		t.Fatalf("diags: %s", diags.Err())
  4119  	}
  4120  
  4121  	actual := strings.TrimSpace(s.String())
  4122  	expected := strings.TrimSpace(testTofuApplyOutputOrphanModuleStr)
  4123  	if actual != expected {
  4124  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  4125  	}
  4126  
  4127  	// now apply with no module in the config, which should remove the
  4128  	// remaining output
  4129  	ctx = testContext2(t, &ContextOpts{
  4130  		Providers: map[addrs.Provider]providers.Factory{
  4131  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4132  		},
  4133  	})
  4134  
  4135  	emptyConfig := configs.NewEmptyConfig()
  4136  
  4137  	// NOTE: While updating this test to pass the state in as a Plan argument,
  4138  	// rather than into the testContext2 call above, it previously said
  4139  	// State: state.DeepCopy(), which is a little weird since we just
  4140  	// created "s" above as the result of the previous apply, but I've preserved
  4141  	// it to avoid changing the flow of this test in case that's important
  4142  	// for some reason.
  4143  	plan, diags = ctx.Plan(emptyConfig, state.DeepCopy(), DefaultPlanOpts)
  4144  	assertNoErrors(t, diags)
  4145  
  4146  	state, diags = ctx.Apply(plan, emptyConfig)
  4147  	if diags.HasErrors() {
  4148  		t.Fatalf("diags: %s", diags.Err())
  4149  	}
  4150  
  4151  	if !state.Empty() {
  4152  		t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(state))
  4153  	}
  4154  }
  4155  
  4156  func TestContext2Apply_providerComputedVar(t *testing.T) {
  4157  	m := testModule(t, "apply-provider-computed")
  4158  	p := testProvider("aws")
  4159  	p.PlanResourceChangeFn = testDiffFn
  4160  
  4161  	pTest := testProvider("test")
  4162  	pTest.ApplyResourceChangeFn = testApplyFn
  4163  	pTest.PlanResourceChangeFn = testDiffFn
  4164  
  4165  	ctx := testContext2(t, &ContextOpts{
  4166  		Providers: map[addrs.Provider]providers.Factory{
  4167  			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
  4168  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
  4169  		},
  4170  	})
  4171  
  4172  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  4173  		val := req.Config.GetAttr("value")
  4174  		if val.IsNull() {
  4175  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  4176  			return
  4177  		}
  4178  		return
  4179  	}
  4180  
  4181  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4182  	assertNoErrors(t, diags)
  4183  
  4184  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  4185  		t.Fatalf("apply errors: %s", diags.Err())
  4186  	}
  4187  }
  4188  
  4189  func TestContext2Apply_providerConfigureDisabled(t *testing.T) {
  4190  	m := testModule(t, "apply-provider-configure-disabled")
  4191  	p := testProvider("aws")
  4192  	p.PlanResourceChangeFn = testDiffFn
  4193  
  4194  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  4195  		val := req.Config.GetAttr("value")
  4196  		if val.IsNull() {
  4197  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  4198  		}
  4199  
  4200  		return
  4201  	}
  4202  
  4203  	ctx := testContext2(t, &ContextOpts{
  4204  		Providers: map[addrs.Provider]providers.Factory{
  4205  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4206  		},
  4207  	})
  4208  
  4209  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4210  	assertNoErrors(t, diags)
  4211  
  4212  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  4213  		t.Fatalf("apply errors: %s", diags.Err())
  4214  	}
  4215  
  4216  	if !p.ConfigureProviderCalled {
  4217  		t.Fatal("configure never called")
  4218  	}
  4219  }
  4220  
  4221  func TestContext2Apply_provisionerModule(t *testing.T) {
  4222  	m := testModule(t, "apply-provisioner-module")
  4223  
  4224  	p := testProvider("aws")
  4225  	p.PlanResourceChangeFn = testDiffFn
  4226  	p.ApplyResourceChangeFn = testApplyFn
  4227  
  4228  	pr := testProvisioner()
  4229  	pr.GetSchemaResponse = provisioners.GetSchemaResponse{
  4230  		Provisioner: &configschema.Block{
  4231  			Attributes: map[string]*configschema.Attribute{
  4232  				"foo": {Type: cty.String, Optional: true},
  4233  			},
  4234  		},
  4235  	}
  4236  
  4237  	ctx := testContext2(t, &ContextOpts{
  4238  		Providers: map[addrs.Provider]providers.Factory{
  4239  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4240  		},
  4241  		Provisioners: map[string]provisioners.Factory{
  4242  			"shell": testProvisionerFuncFixed(pr),
  4243  		},
  4244  	})
  4245  
  4246  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4247  	assertNoErrors(t, diags)
  4248  
  4249  	state, diags := ctx.Apply(plan, m)
  4250  	if diags.HasErrors() {
  4251  		t.Fatalf("diags: %s", diags.Err())
  4252  	}
  4253  
  4254  	actual := strings.TrimSpace(state.String())
  4255  	expected := strings.TrimSpace(testTofuApplyProvisionerModuleStr)
  4256  	if actual != expected {
  4257  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4258  	}
  4259  
  4260  	// Verify apply was invoked
  4261  	if !pr.ProvisionResourceCalled {
  4262  		t.Fatalf("provisioner not invoked")
  4263  	}
  4264  }
  4265  
  4266  func TestContext2Apply_Provisioner_compute(t *testing.T) {
  4267  	m := testModule(t, "apply-provisioner-compute")
  4268  	p := testProvider("aws")
  4269  	pr := testProvisioner()
  4270  	p.PlanResourceChangeFn = testDiffFn
  4271  	p.ApplyResourceChangeFn = testApplyFn
  4272  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4273  
  4274  		val := req.Config.GetAttr("command").AsString()
  4275  		if val != "computed_value" {
  4276  			t.Fatalf("bad value for foo: %q", val)
  4277  		}
  4278  		req.UIOutput.Output(fmt.Sprintf("Executing: %q", val))
  4279  
  4280  		return
  4281  	}
  4282  	h := new(MockHook)
  4283  	ctx := testContext2(t, &ContextOpts{
  4284  		Hooks: []Hook{h},
  4285  		Providers: map[addrs.Provider]providers.Factory{
  4286  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4287  		},
  4288  		Provisioners: map[string]provisioners.Factory{
  4289  			"shell": testProvisionerFuncFixed(pr),
  4290  		},
  4291  	})
  4292  
  4293  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  4294  		Mode: plans.NormalMode,
  4295  		SetVariables: InputValues{
  4296  			"value": &InputValue{
  4297  				Value:      cty.NumberIntVal(1),
  4298  				SourceType: ValueFromCaller,
  4299  			},
  4300  		},
  4301  	})
  4302  	assertNoErrors(t, diags)
  4303  
  4304  	state, diags := ctx.Apply(plan, m)
  4305  	if diags.HasErrors() {
  4306  		t.Fatalf("diags: %s", diags.Err())
  4307  	}
  4308  
  4309  	actual := strings.TrimSpace(state.String())
  4310  	expected := strings.TrimSpace(testTofuApplyProvisionerStr)
  4311  	if actual != expected {
  4312  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4313  	}
  4314  
  4315  	// Verify apply was invoked
  4316  	if !pr.ProvisionResourceCalled {
  4317  		t.Fatalf("provisioner not invoked")
  4318  	}
  4319  
  4320  	// Verify output was rendered
  4321  	if !h.ProvisionOutputCalled {
  4322  		t.Fatalf("ProvisionOutput hook not called")
  4323  	}
  4324  	if got, want := h.ProvisionOutputMessage, `Executing: "computed_value"`; got != want {
  4325  		t.Errorf("expected output to be %q, but was %q", want, got)
  4326  	}
  4327  }
  4328  
  4329  func TestContext2Apply_provisionerCreateFail(t *testing.T) {
  4330  	m := testModule(t, "apply-provisioner-fail-create")
  4331  	p := testProvider("aws")
  4332  	pr := testProvisioner()
  4333  	p.PlanResourceChangeFn = testDiffFn
  4334  
  4335  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  4336  		resp := testApplyFn(req)
  4337  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4338  
  4339  		return resp
  4340  	}
  4341  
  4342  	ctx := testContext2(t, &ContextOpts{
  4343  		Providers: map[addrs.Provider]providers.Factory{
  4344  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4345  		},
  4346  		Provisioners: map[string]provisioners.Factory{
  4347  			"shell": testProvisionerFuncFixed(pr),
  4348  		},
  4349  	})
  4350  
  4351  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4352  	assertNoErrors(t, diags)
  4353  
  4354  	state, diags := ctx.Apply(plan, m)
  4355  	if diags == nil {
  4356  		t.Fatal("should error")
  4357  	}
  4358  
  4359  	got := strings.TrimSpace(state.String())
  4360  	want := strings.TrimSpace(testTofuApplyProvisionerFailCreateStr)
  4361  	if got != want {
  4362  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want)
  4363  	}
  4364  }
  4365  
  4366  func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) {
  4367  	m := testModule(t, "apply-provisioner-fail-create")
  4368  	p := testProvider("aws")
  4369  	pr := testProvisioner()
  4370  	p.PlanResourceChangeFn = testDiffFn
  4371  
  4372  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4373  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4374  		return
  4375  	}
  4376  
  4377  	ctx := testContext2(t, &ContextOpts{
  4378  		Providers: map[addrs.Provider]providers.Factory{
  4379  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4380  		},
  4381  		Provisioners: map[string]provisioners.Factory{
  4382  			"shell": testProvisionerFuncFixed(pr),
  4383  		},
  4384  	})
  4385  
  4386  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4387  	assertNoErrors(t, diags)
  4388  
  4389  	state, diags := ctx.Apply(plan, m)
  4390  	if diags == nil {
  4391  		t.Fatal("should error")
  4392  	}
  4393  
  4394  	actual := strings.TrimSpace(state.String())
  4395  	expected := strings.TrimSpace(testTofuApplyProvisionerFailCreateNoIdStr)
  4396  	if actual != expected {
  4397  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4398  	}
  4399  }
  4400  
  4401  func TestContext2Apply_provisionerFail(t *testing.T) {
  4402  	m := testModule(t, "apply-provisioner-fail")
  4403  	p := testProvider("aws")
  4404  	p.PlanResourceChangeFn = testDiffFn
  4405  	p.ApplyResourceChangeFn = testApplyFn
  4406  	pr := testProvisioner()
  4407  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4408  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION"))
  4409  		return
  4410  	}
  4411  
  4412  	ctx := testContext2(t, &ContextOpts{
  4413  		Providers: map[addrs.Provider]providers.Factory{
  4414  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4415  		},
  4416  		Provisioners: map[string]provisioners.Factory{
  4417  			"shell": testProvisionerFuncFixed(pr),
  4418  		},
  4419  	})
  4420  
  4421  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4422  	assertNoErrors(t, diags)
  4423  
  4424  	state, diags := ctx.Apply(plan, m)
  4425  	if diags == nil {
  4426  		t.Fatal("should error")
  4427  	}
  4428  
  4429  	actual := strings.TrimSpace(state.String())
  4430  	expected := strings.TrimSpace(testTofuApplyProvisionerFailStr)
  4431  	if actual != expected {
  4432  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4433  	}
  4434  }
  4435  
  4436  func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) {
  4437  	m := testModule(t, "apply-provisioner-fail-create-before")
  4438  	p := testProvider("aws")
  4439  	pr := testProvisioner()
  4440  	p.PlanResourceChangeFn = testDiffFn
  4441  	p.ApplyResourceChangeFn = testApplyFn
  4442  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4443  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION"))
  4444  		return
  4445  	}
  4446  
  4447  	state := states.NewState()
  4448  	root := state.EnsureModule(addrs.RootModuleInstance)
  4449  	root.SetResourceInstanceCurrent(
  4450  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4451  		&states.ResourceInstanceObjectSrc{
  4452  			Status:    states.ObjectReady,
  4453  			AttrsJSON: []byte(`{"id":"bar","require_new":"abc"}`),
  4454  		},
  4455  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  4456  	)
  4457  
  4458  	ctx := testContext2(t, &ContextOpts{
  4459  		Providers: map[addrs.Provider]providers.Factory{
  4460  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4461  		},
  4462  		Provisioners: map[string]provisioners.Factory{
  4463  			"shell": testProvisionerFuncFixed(pr),
  4464  		},
  4465  	})
  4466  
  4467  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4468  	assertNoErrors(t, diags)
  4469  
  4470  	state, diags = ctx.Apply(plan, m)
  4471  	if !diags.HasErrors() {
  4472  		t.Fatal("should error")
  4473  	}
  4474  
  4475  	actual := strings.TrimSpace(state.String())
  4476  	expected := strings.TrimSpace(testTofuApplyProvisionerFailCreateBeforeDestroyStr)
  4477  	if actual != expected {
  4478  		t.Fatalf("expected:\n%s\n:got\n%s", expected, actual)
  4479  	}
  4480  }
  4481  
  4482  func TestContext2Apply_error_createBeforeDestroy(t *testing.T) {
  4483  	m := testModule(t, "apply-error-create-before")
  4484  	p := testProvider("aws")
  4485  
  4486  	state := states.NewState()
  4487  	root := state.EnsureModule(addrs.RootModuleInstance)
  4488  	root.SetResourceInstanceCurrent(
  4489  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4490  		&states.ResourceInstanceObjectSrc{
  4491  			Status:    states.ObjectReady,
  4492  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc","type":"aws_instance"}`),
  4493  		},
  4494  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  4495  	)
  4496  
  4497  	ctx := testContext2(t, &ContextOpts{
  4498  		Providers: map[addrs.Provider]providers.Factory{
  4499  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4500  		},
  4501  	})
  4502  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4503  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("placeholder error from ApplyFn"))
  4504  		return
  4505  	}
  4506  	p.PlanResourceChangeFn = testDiffFn
  4507  
  4508  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4509  	assertNoErrors(t, diags)
  4510  
  4511  	state, diags = ctx.Apply(plan, m)
  4512  	if !diags.HasErrors() {
  4513  		t.Fatal("should have error")
  4514  	}
  4515  	if got, want := diags.Err().Error(), "placeholder error from ApplyFn"; got != want {
  4516  		// We're looking for our artificial error from ApplyFn above, whose
  4517  		// message is literally "placeholder error from ApplyFn".
  4518  		t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
  4519  	}
  4520  
  4521  	actual := strings.TrimSpace(state.String())
  4522  	expected := strings.TrimSpace(testTofuApplyErrorCreateBeforeDestroyStr)
  4523  	if actual != expected {
  4524  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4525  	}
  4526  }
  4527  
  4528  func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) {
  4529  	m := testModule(t, "apply-error-create-before")
  4530  	p := testProvider("aws")
  4531  
  4532  	state := states.NewState()
  4533  	root := state.EnsureModule(addrs.RootModuleInstance)
  4534  	root.SetResourceInstanceCurrent(
  4535  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4536  		&states.ResourceInstanceObjectSrc{
  4537  			Status:    states.ObjectReady,
  4538  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
  4539  		},
  4540  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  4541  	)
  4542  
  4543  	ctx := testContext2(t, &ContextOpts{
  4544  		Providers: map[addrs.Provider]providers.Factory{
  4545  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4546  		},
  4547  	})
  4548  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4549  		// Fail the destroy!
  4550  		if req.PlannedState.IsNull() {
  4551  			resp.NewState = req.PriorState
  4552  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4553  			return
  4554  		}
  4555  
  4556  		return testApplyFn(req)
  4557  	}
  4558  	p.PlanResourceChangeFn = testDiffFn
  4559  
  4560  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4561  	assertNoErrors(t, diags)
  4562  
  4563  	state, diags = ctx.Apply(plan, m)
  4564  	if !diags.HasErrors() {
  4565  		t.Fatal("should have error")
  4566  	}
  4567  
  4568  	actual := strings.TrimSpace(state.String())
  4569  	expected := strings.TrimSpace(testTofuApplyErrorDestroyCreateBeforeDestroyStr)
  4570  	if actual != expected {
  4571  		t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected)
  4572  	}
  4573  }
  4574  
  4575  func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) {
  4576  	m := testModule(t, "apply-multi-depose-create-before-destroy")
  4577  	p := testProvider("aws")
  4578  	ps := map[addrs.Provider]providers.Factory{addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p)}
  4579  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4580  		ResourceTypes: map[string]*configschema.Block{
  4581  			"aws_instance": {
  4582  				Attributes: map[string]*configschema.Attribute{
  4583  					"require_new": {Type: cty.String, Optional: true},
  4584  					"id":          {Type: cty.String, Computed: true},
  4585  				},
  4586  			},
  4587  		},
  4588  	})
  4589  
  4590  	state := states.NewState()
  4591  	root := state.EnsureModule(addrs.RootModuleInstance)
  4592  	root.SetResourceInstanceCurrent(
  4593  		mustResourceInstanceAddr("aws_instance.web").Resource,
  4594  		&states.ResourceInstanceObjectSrc{
  4595  			Status:    states.ObjectReady,
  4596  			AttrsJSON: []byte(`{"id":"foo"}`),
  4597  		},
  4598  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  4599  	)
  4600  
  4601  	p.PlanResourceChangeFn = testDiffFn
  4602  
  4603  	ctx := testContext2(t, &ContextOpts{
  4604  		Providers: ps,
  4605  	})
  4606  	createdInstanceId := "bar"
  4607  	// Create works
  4608  	createFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4609  		s := req.PlannedState.AsValueMap()
  4610  		s["id"] = cty.StringVal(createdInstanceId)
  4611  		resp.NewState = cty.ObjectVal(s)
  4612  		return
  4613  	}
  4614  
  4615  	// Destroy starts broken
  4616  	destroyFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4617  		resp.NewState = req.PriorState
  4618  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy failed"))
  4619  		return
  4620  	}
  4621  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4622  		if req.PlannedState.IsNull() {
  4623  			return destroyFunc(req)
  4624  		} else {
  4625  			return createFunc(req)
  4626  		}
  4627  	}
  4628  
  4629  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4630  		Mode: plans.NormalMode,
  4631  		SetVariables: InputValues{
  4632  			"require_new": &InputValue{
  4633  				Value: cty.StringVal("yes"),
  4634  			},
  4635  		},
  4636  	})
  4637  	assertNoErrors(t, diags)
  4638  
  4639  	// Destroy is broken, so even though CBD successfully replaces the instance,
  4640  	// we'll have to save the Deposed instance to destroy later
  4641  	state, diags = ctx.Apply(plan, m)
  4642  	if !diags.HasErrors() {
  4643  		t.Fatal("should have error")
  4644  	}
  4645  
  4646  	checkStateString(t, state, `
  4647  aws_instance.web: (1 deposed)
  4648    ID = bar
  4649    provider = provider["registry.opentofu.org/hashicorp/aws"]
  4650    require_new = yes
  4651    Deposed ID 1 = foo
  4652  	`)
  4653  
  4654  	createdInstanceId = "baz"
  4655  	ctx = testContext2(t, &ContextOpts{
  4656  		Providers: ps,
  4657  	})
  4658  
  4659  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4660  		Mode: plans.NormalMode,
  4661  		SetVariables: InputValues{
  4662  			"require_new": &InputValue{
  4663  				Value: cty.StringVal("baz"),
  4664  			},
  4665  		},
  4666  	})
  4667  	assertNoErrors(t, diags)
  4668  
  4669  	// We're replacing the primary instance once again. Destroy is _still_
  4670  	// broken, so the Deposed list gets longer
  4671  	state, diags = ctx.Apply(plan, m)
  4672  	if !diags.HasErrors() {
  4673  		t.Fatal("should have error")
  4674  	}
  4675  
  4676  	// For this one we can't rely on checkStateString because its result is
  4677  	// not deterministic when multiple deposed objects are present. Instead,
  4678  	// we will probe the state object directly.
  4679  	{
  4680  		is := state.RootModule().Resources["aws_instance.web"].Instances[addrs.NoKey]
  4681  		if is.Current == nil {
  4682  			t.Fatalf("no current object for aws_instance web; should have one")
  4683  		}
  4684  		if !bytes.Contains(is.Current.AttrsJSON, []byte("baz")) {
  4685  			t.Fatalf("incorrect current object attrs %s; want id=baz", is.Current.AttrsJSON)
  4686  		}
  4687  		if got, want := len(is.Deposed), 2; got != want {
  4688  			t.Fatalf("wrong number of deposed instances %d; want %d", got, want)
  4689  		}
  4690  		var foos, bars int
  4691  		for _, obj := range is.Deposed {
  4692  			if bytes.Contains(obj.AttrsJSON, []byte("foo")) {
  4693  				foos++
  4694  			}
  4695  			if bytes.Contains(obj.AttrsJSON, []byte("bar")) {
  4696  				bars++
  4697  			}
  4698  		}
  4699  		if got, want := foos, 1; got != want {
  4700  			t.Fatalf("wrong number of deposed instances with id=foo %d; want %d", got, want)
  4701  		}
  4702  		if got, want := bars, 1; got != want {
  4703  			t.Fatalf("wrong number of deposed instances with id=bar %d; want %d", got, want)
  4704  		}
  4705  	}
  4706  
  4707  	// Destroy partially fixed!
  4708  	destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4709  		s := req.PriorState.AsValueMap()
  4710  		id := s["id"].AsString()
  4711  		if id == "foo" || id == "baz" {
  4712  			resp.NewState = cty.NullVal(req.PriorState.Type())
  4713  		} else {
  4714  			resp.NewState = req.PriorState
  4715  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy partially failed"))
  4716  		}
  4717  		return
  4718  	}
  4719  
  4720  	createdInstanceId = "qux"
  4721  	ctx = testContext2(t, &ContextOpts{
  4722  		Providers: ps,
  4723  	})
  4724  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4725  		Mode: plans.NormalMode,
  4726  		SetVariables: InputValues{
  4727  			"require_new": &InputValue{
  4728  				Value: cty.StringVal("qux"),
  4729  			},
  4730  		},
  4731  	})
  4732  	assertNoErrors(t, diags)
  4733  
  4734  	state, diags = ctx.Apply(plan, m)
  4735  	// Expect error because 1/2 of Deposed destroys failed
  4736  	if !diags.HasErrors() {
  4737  		t.Fatal("should have error")
  4738  	}
  4739  
  4740  	// foo and baz are now gone, bar sticks around
  4741  	checkStateString(t, state, `
  4742  aws_instance.web: (1 deposed)
  4743    ID = qux
  4744    provider = provider["registry.opentofu.org/hashicorp/aws"]
  4745    require_new = qux
  4746    Deposed ID 1 = bar
  4747  	`)
  4748  
  4749  	// Destroy working fully!
  4750  	destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4751  		resp.NewState = cty.NullVal(req.PriorState.Type())
  4752  		return
  4753  	}
  4754  
  4755  	createdInstanceId = "quux"
  4756  	ctx = testContext2(t, &ContextOpts{
  4757  		Providers: ps,
  4758  	})
  4759  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4760  		Mode: plans.NormalMode,
  4761  		SetVariables: InputValues{
  4762  			"require_new": &InputValue{
  4763  				Value: cty.StringVal("quux"),
  4764  			},
  4765  		},
  4766  	})
  4767  	assertNoErrors(t, diags)
  4768  	state, diags = ctx.Apply(plan, m)
  4769  	if diags.HasErrors() {
  4770  		t.Fatal("should not have error:", diags.Err())
  4771  	}
  4772  
  4773  	// And finally the state is clean
  4774  	checkStateString(t, state, `
  4775  aws_instance.web:
  4776    ID = quux
  4777    provider = provider["registry.opentofu.org/hashicorp/aws"]
  4778    require_new = quux
  4779  	`)
  4780  }
  4781  
  4782  // Verify that a normal provisioner with on_failure "continue" set won't
  4783  // taint the resource and continues executing.
  4784  func TestContext2Apply_provisionerFailContinue(t *testing.T) {
  4785  	m := testModule(t, "apply-provisioner-fail-continue")
  4786  	p := testProvider("aws")
  4787  	pr := testProvisioner()
  4788  	p.PlanResourceChangeFn = testDiffFn
  4789  	p.ApplyResourceChangeFn = testApplyFn
  4790  
  4791  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4792  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4793  		return
  4794  	}
  4795  
  4796  	ctx := testContext2(t, &ContextOpts{
  4797  		Providers: map[addrs.Provider]providers.Factory{
  4798  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4799  		},
  4800  		Provisioners: map[string]provisioners.Factory{
  4801  			"shell": testProvisionerFuncFixed(pr),
  4802  		},
  4803  	})
  4804  
  4805  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4806  	assertNoErrors(t, diags)
  4807  
  4808  	state, diags := ctx.Apply(plan, m)
  4809  	if diags.HasErrors() {
  4810  		t.Fatalf("diags: %s", diags.Err())
  4811  	}
  4812  
  4813  	checkStateString(t, state, `
  4814  aws_instance.foo:
  4815    ID = foo
  4816    provider = provider["registry.opentofu.org/hashicorp/aws"]
  4817    foo = bar
  4818    type = aws_instance
  4819    `)
  4820  
  4821  	// Verify apply was invoked
  4822  	if !pr.ProvisionResourceCalled {
  4823  		t.Fatalf("provisioner not invoked")
  4824  	}
  4825  }
  4826  
  4827  // Verify that a normal provisioner with on_failure "continue" records
  4828  // the error with the hook.
  4829  func TestContext2Apply_provisionerFailContinueHook(t *testing.T) {
  4830  	h := new(MockHook)
  4831  	m := testModule(t, "apply-provisioner-fail-continue")
  4832  	p := testProvider("aws")
  4833  	pr := testProvisioner()
  4834  	p.PlanResourceChangeFn = testDiffFn
  4835  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4836  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4837  		return
  4838  	}
  4839  
  4840  	ctx := testContext2(t, &ContextOpts{
  4841  		Hooks: []Hook{h},
  4842  		Providers: map[addrs.Provider]providers.Factory{
  4843  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4844  		},
  4845  		Provisioners: map[string]provisioners.Factory{
  4846  			"shell": testProvisionerFuncFixed(pr),
  4847  		},
  4848  	})
  4849  
  4850  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4851  	assertNoErrors(t, diags)
  4852  
  4853  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  4854  		t.Fatalf("apply errors: %s", diags.Err())
  4855  	}
  4856  
  4857  	if !h.PostProvisionInstanceStepCalled {
  4858  		t.Fatal("PostProvisionInstanceStep not called")
  4859  	}
  4860  	if h.PostProvisionInstanceStepErrorArg == nil {
  4861  		t.Fatal("should have error")
  4862  	}
  4863  }
  4864  
  4865  func TestContext2Apply_provisionerDestroy(t *testing.T) {
  4866  	m := testModule(t, "apply-provisioner-destroy")
  4867  	p := testProvider("aws")
  4868  	pr := testProvisioner()
  4869  	p.PlanResourceChangeFn = testDiffFn
  4870  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4871  		val := req.Config.GetAttr("command").AsString()
  4872  		if val != "destroy a bar" {
  4873  			t.Fatalf("bad value for foo: %q", val)
  4874  		}
  4875  
  4876  		return
  4877  	}
  4878  
  4879  	state := states.NewState()
  4880  	root := state.RootModule()
  4881  	root.SetResourceInstanceCurrent(
  4882  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4883  		&states.ResourceInstanceObjectSrc{
  4884  			Status:    states.ObjectReady,
  4885  			AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
  4886  		},
  4887  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  4888  	)
  4889  
  4890  	ctx := testContext2(t, &ContextOpts{
  4891  		Providers: map[addrs.Provider]providers.Factory{
  4892  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4893  		},
  4894  		Provisioners: map[string]provisioners.Factory{
  4895  			"shell": testProvisionerFuncFixed(pr),
  4896  		},
  4897  	})
  4898  
  4899  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
  4900  	assertNoErrors(t, diags)
  4901  
  4902  	state, diags = ctx.Apply(plan, m)
  4903  	if diags.HasErrors() {
  4904  		t.Fatalf("diags: %s", diags.Err())
  4905  	}
  4906  
  4907  	checkStateString(t, state, `<no state>`)
  4908  
  4909  	// Verify apply was invoked
  4910  	if !pr.ProvisionResourceCalled {
  4911  		t.Fatalf("provisioner not invoked")
  4912  	}
  4913  }
  4914  
  4915  // Verify that on destroy provisioner failure, nothing happens to the instance
  4916  func TestContext2Apply_provisionerDestroyFail(t *testing.T) {
  4917  	m := testModule(t, "apply-provisioner-destroy")
  4918  	p := testProvider("aws")
  4919  	pr := testProvisioner()
  4920  	p.PlanResourceChangeFn = testDiffFn
  4921  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4922  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4923  		return
  4924  	}
  4925  
  4926  	state := states.NewState()
  4927  	root := state.RootModule()
  4928  	root.SetResourceInstanceCurrent(
  4929  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4930  		&states.ResourceInstanceObjectSrc{
  4931  			Status:    states.ObjectReady,
  4932  			AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
  4933  		},
  4934  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  4935  	)
  4936  
  4937  	ctx := testContext2(t, &ContextOpts{
  4938  		Providers: map[addrs.Provider]providers.Factory{
  4939  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4940  		},
  4941  		Provisioners: map[string]provisioners.Factory{
  4942  			"shell": testProvisionerFuncFixed(pr),
  4943  		},
  4944  	})
  4945  
  4946  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
  4947  	assertNoErrors(t, diags)
  4948  
  4949  	state, diags = ctx.Apply(plan, m)
  4950  	if diags == nil {
  4951  		t.Fatal("should error")
  4952  	}
  4953  
  4954  	checkStateString(t, state, `
  4955  aws_instance.foo["a"]:
  4956    ID = bar
  4957    provider = provider["registry.opentofu.org/hashicorp/aws"]
  4958    foo = bar
  4959  	`)
  4960  
  4961  	// Verify apply was invoked
  4962  	if !pr.ProvisionResourceCalled {
  4963  		t.Fatalf("provisioner not invoked")
  4964  	}
  4965  }
  4966  
  4967  // Verify that on destroy provisioner failure with "continue" that
  4968  // we continue to the next provisioner.
  4969  func TestContext2Apply_provisionerDestroyFailContinue(t *testing.T) {
  4970  	m := testModule(t, "apply-provisioner-destroy-continue")
  4971  	p := testProvider("aws")
  4972  	pr := testProvisioner()
  4973  	p.PlanResourceChangeFn = testDiffFn
  4974  
  4975  	var l sync.Mutex
  4976  	var calls []string
  4977  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4978  		val := req.Config.GetAttr("command")
  4979  		if val.IsNull() {
  4980  			t.Fatalf("bad value for foo: %#v", val)
  4981  		}
  4982  
  4983  		l.Lock()
  4984  		defer l.Unlock()
  4985  		calls = append(calls, val.AsString())
  4986  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4987  		return
  4988  	}
  4989  
  4990  	state := states.NewState()
  4991  	root := state.RootModule()
  4992  	root.SetResourceInstanceCurrent(
  4993  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4994  		&states.ResourceInstanceObjectSrc{
  4995  			Status:    states.ObjectReady,
  4996  			AttrsJSON: []byte(`{"id":"bar"}`),
  4997  		},
  4998  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  4999  	)
  5000  
  5001  	ctx := testContext2(t, &ContextOpts{
  5002  		Providers: map[addrs.Provider]providers.Factory{
  5003  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5004  		},
  5005  		Provisioners: map[string]provisioners.Factory{
  5006  			"shell": testProvisionerFuncFixed(pr),
  5007  		},
  5008  	})
  5009  
  5010  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  5011  		Mode: plans.DestroyMode,
  5012  	})
  5013  	assertNoErrors(t, diags)
  5014  
  5015  	state, diags = ctx.Apply(plan, m)
  5016  	if diags.HasErrors() {
  5017  		t.Fatalf("diags: %s", diags.Err())
  5018  	}
  5019  
  5020  	checkStateString(t, state, `<no state>`)
  5021  
  5022  	// Verify apply was invoked
  5023  	if !pr.ProvisionResourceCalled {
  5024  		t.Fatalf("provisioner not invoked")
  5025  	}
  5026  
  5027  	expected := []string{"one", "two"}
  5028  	if !reflect.DeepEqual(calls, expected) {
  5029  		t.Fatalf("wrong commands\ngot:  %#v\nwant: %#v", calls, expected)
  5030  	}
  5031  }
  5032  
  5033  // Verify that on destroy provisioner failure with "continue" that
  5034  // we continue to the next provisioner. But if the next provisioner defines
  5035  // to fail, then we fail after running it.
  5036  func TestContext2Apply_provisionerDestroyFailContinueFail(t *testing.T) {
  5037  	m := testModule(t, "apply-provisioner-destroy-fail")
  5038  	p := testProvider("aws")
  5039  	pr := testProvisioner()
  5040  	p.PlanResourceChangeFn = testDiffFn
  5041  
  5042  	var l sync.Mutex
  5043  	var calls []string
  5044  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5045  		val := req.Config.GetAttr("command")
  5046  		if val.IsNull() {
  5047  			t.Fatalf("bad value for foo: %#v", val)
  5048  		}
  5049  
  5050  		l.Lock()
  5051  		defer l.Unlock()
  5052  		calls = append(calls, val.AsString())
  5053  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  5054  		return
  5055  	}
  5056  
  5057  	state := states.NewState()
  5058  	root := state.EnsureModule(addrs.RootModuleInstance)
  5059  	root.SetResourceInstanceCurrent(
  5060  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  5061  		&states.ResourceInstanceObjectSrc{
  5062  			Status:    states.ObjectReady,
  5063  			AttrsJSON: []byte(`{"id":"bar"}`),
  5064  		},
  5065  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  5066  	)
  5067  
  5068  	ctx := testContext2(t, &ContextOpts{
  5069  		Providers: map[addrs.Provider]providers.Factory{
  5070  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5071  		},
  5072  		Provisioners: map[string]provisioners.Factory{
  5073  			"shell": testProvisionerFuncFixed(pr),
  5074  		},
  5075  	})
  5076  
  5077  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  5078  		Mode: plans.DestroyMode,
  5079  	})
  5080  	assertNoErrors(t, diags)
  5081  
  5082  	state, diags = ctx.Apply(plan, m)
  5083  	if diags == nil {
  5084  		t.Fatal("apply succeeded; wanted error from second provisioner")
  5085  	}
  5086  
  5087  	checkStateString(t, state, `
  5088  aws_instance.foo:
  5089    ID = bar
  5090    provider = provider["registry.opentofu.org/hashicorp/aws"]
  5091    `)
  5092  
  5093  	// Verify apply was invoked
  5094  	if !pr.ProvisionResourceCalled {
  5095  		t.Fatalf("provisioner not invoked")
  5096  	}
  5097  
  5098  	expected := []string{"one", "two"}
  5099  	if !reflect.DeepEqual(calls, expected) {
  5100  		t.Fatalf("bad: %#v", calls)
  5101  	}
  5102  }
  5103  
  5104  // Verify destroy provisioners are not run for tainted instances.
  5105  func TestContext2Apply_provisionerDestroyTainted(t *testing.T) {
  5106  	m := testModule(t, "apply-provisioner-destroy")
  5107  	p := testProvider("aws")
  5108  	pr := testProvisioner()
  5109  	p.PlanResourceChangeFn = testDiffFn
  5110  	p.ApplyResourceChangeFn = testApplyFn
  5111  
  5112  	destroyCalled := false
  5113  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5114  		expected := "create a b"
  5115  		val := req.Config.GetAttr("command")
  5116  		if val.AsString() != expected {
  5117  			t.Fatalf("bad value for command: %#v", val)
  5118  		}
  5119  
  5120  		return
  5121  	}
  5122  
  5123  	state := states.NewState()
  5124  	root := state.RootModule()
  5125  	root.SetResourceInstanceCurrent(
  5126  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  5127  		&states.ResourceInstanceObjectSrc{
  5128  			Status:    states.ObjectTainted,
  5129  			AttrsJSON: []byte(`{"id":"bar"}`),
  5130  		},
  5131  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  5132  	)
  5133  
  5134  	ctx := testContext2(t, &ContextOpts{
  5135  		Providers: map[addrs.Provider]providers.Factory{
  5136  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5137  		},
  5138  		Provisioners: map[string]provisioners.Factory{
  5139  			"shell": testProvisionerFuncFixed(pr),
  5140  		},
  5141  	})
  5142  
  5143  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  5144  		Mode: plans.NormalMode,
  5145  		SetVariables: InputValues{
  5146  			"input": &InputValue{
  5147  				Value: cty.MapVal(map[string]cty.Value{
  5148  					"a": cty.StringVal("b"),
  5149  				}),
  5150  				SourceType: ValueFromInput,
  5151  			},
  5152  		},
  5153  	})
  5154  	assertNoErrors(t, diags)
  5155  
  5156  	state, diags = ctx.Apply(plan, m)
  5157  	if diags.HasErrors() {
  5158  		t.Fatalf("diags: %s", diags.Err())
  5159  	}
  5160  
  5161  	checkStateString(t, state, `
  5162  aws_instance.foo["a"]:
  5163    ID = foo
  5164    provider = provider["registry.opentofu.org/hashicorp/aws"]
  5165    foo = bar
  5166    type = aws_instance
  5167  	`)
  5168  
  5169  	// Verify apply was invoked
  5170  	if !pr.ProvisionResourceCalled {
  5171  		t.Fatalf("provisioner not invoked")
  5172  	}
  5173  
  5174  	if destroyCalled {
  5175  		t.Fatal("destroy should not be called")
  5176  	}
  5177  }
  5178  
  5179  func TestContext2Apply_provisionerResourceRef(t *testing.T) {
  5180  	m := testModule(t, "apply-provisioner-resource-ref")
  5181  	p := testProvider("aws")
  5182  	p.PlanResourceChangeFn = testDiffFn
  5183  	p.ApplyResourceChangeFn = testApplyFn
  5184  
  5185  	pr := testProvisioner()
  5186  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5187  		val := req.Config.GetAttr("command")
  5188  		if val.AsString() != "2" {
  5189  			t.Fatalf("bad value for command: %#v", val)
  5190  		}
  5191  
  5192  		return
  5193  	}
  5194  
  5195  	ctx := testContext2(t, &ContextOpts{
  5196  		Providers: map[addrs.Provider]providers.Factory{
  5197  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5198  		},
  5199  		Provisioners: map[string]provisioners.Factory{
  5200  			"shell": testProvisionerFuncFixed(pr),
  5201  		},
  5202  	})
  5203  
  5204  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5205  	assertNoErrors(t, diags)
  5206  
  5207  	state, diags := ctx.Apply(plan, m)
  5208  	if diags.HasErrors() {
  5209  		t.Fatalf("diags: %s", diags.Err())
  5210  	}
  5211  
  5212  	actual := strings.TrimSpace(state.String())
  5213  	expected := strings.TrimSpace(testTofuApplyProvisionerResourceRefStr)
  5214  	if actual != expected {
  5215  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5216  	}
  5217  
  5218  	// Verify apply was invoked
  5219  	if !pr.ProvisionResourceCalled {
  5220  		t.Fatalf("provisioner not invoked")
  5221  	}
  5222  }
  5223  
  5224  func TestContext2Apply_provisionerSelfRef(t *testing.T) {
  5225  	m := testModule(t, "apply-provisioner-self-ref")
  5226  	p := testProvider("aws")
  5227  	pr := testProvisioner()
  5228  	p.PlanResourceChangeFn = testDiffFn
  5229  	p.ApplyResourceChangeFn = testApplyFn
  5230  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5231  		val := req.Config.GetAttr("command")
  5232  		if val.AsString() != "bar" {
  5233  			t.Fatalf("bad value for command: %#v", val)
  5234  		}
  5235  
  5236  		return
  5237  	}
  5238  
  5239  	ctx := testContext2(t, &ContextOpts{
  5240  		Providers: map[addrs.Provider]providers.Factory{
  5241  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5242  		},
  5243  		Provisioners: map[string]provisioners.Factory{
  5244  			"shell": testProvisionerFuncFixed(pr),
  5245  		},
  5246  	})
  5247  
  5248  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5249  	assertNoErrors(t, diags)
  5250  
  5251  	state, diags := ctx.Apply(plan, m)
  5252  	if diags.HasErrors() {
  5253  		t.Fatalf("diags: %s", diags.Err())
  5254  	}
  5255  
  5256  	actual := strings.TrimSpace(state.String())
  5257  	expected := strings.TrimSpace(testTofuApplyProvisionerSelfRefStr)
  5258  	if actual != expected {
  5259  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5260  	}
  5261  
  5262  	// Verify apply was invoked
  5263  	if !pr.ProvisionResourceCalled {
  5264  		t.Fatalf("provisioner not invoked")
  5265  	}
  5266  }
  5267  
  5268  func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) {
  5269  	var lock sync.Mutex
  5270  	commands := make([]string, 0, 5)
  5271  
  5272  	m := testModule(t, "apply-provisioner-multi-self-ref")
  5273  	p := testProvider("aws")
  5274  	pr := testProvisioner()
  5275  	p.PlanResourceChangeFn = testDiffFn
  5276  	p.ApplyResourceChangeFn = testApplyFn
  5277  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5278  		lock.Lock()
  5279  		defer lock.Unlock()
  5280  
  5281  		val := req.Config.GetAttr("command")
  5282  		if val.IsNull() {
  5283  			t.Fatalf("bad value for command: %#v", val)
  5284  		}
  5285  
  5286  		commands = append(commands, val.AsString())
  5287  		return
  5288  	}
  5289  
  5290  	ctx := testContext2(t, &ContextOpts{
  5291  		Providers: map[addrs.Provider]providers.Factory{
  5292  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5293  		},
  5294  		Provisioners: map[string]provisioners.Factory{
  5295  			"shell": testProvisionerFuncFixed(pr),
  5296  		},
  5297  	})
  5298  
  5299  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5300  	assertNoErrors(t, diags)
  5301  
  5302  	state, diags := ctx.Apply(plan, m)
  5303  	if diags.HasErrors() {
  5304  		t.Fatalf("diags: %s", diags.Err())
  5305  	}
  5306  
  5307  	actual := strings.TrimSpace(state.String())
  5308  	expected := strings.TrimSpace(testTofuApplyProvisionerMultiSelfRefStr)
  5309  	if actual != expected {
  5310  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5311  	}
  5312  
  5313  	// Verify apply was invoked
  5314  	if !pr.ProvisionResourceCalled {
  5315  		t.Fatalf("provisioner not invoked")
  5316  	}
  5317  
  5318  	// Verify our result
  5319  	sort.Strings(commands)
  5320  	expectedCommands := []string{"number 0", "number 1", "number 2"}
  5321  	if !reflect.DeepEqual(commands, expectedCommands) {
  5322  		t.Fatalf("bad: %#v", commands)
  5323  	}
  5324  }
  5325  
  5326  func TestContext2Apply_provisionerMultiSelfRefSingle(t *testing.T) {
  5327  	var lock sync.Mutex
  5328  	order := make([]string, 0, 5)
  5329  
  5330  	m := testModule(t, "apply-provisioner-multi-self-ref-single")
  5331  	p := testProvider("aws")
  5332  	pr := testProvisioner()
  5333  	p.PlanResourceChangeFn = testDiffFn
  5334  	p.ApplyResourceChangeFn = testApplyFn
  5335  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5336  		lock.Lock()
  5337  		defer lock.Unlock()
  5338  
  5339  		val := req.Config.GetAttr("order")
  5340  		if val.IsNull() {
  5341  			t.Fatalf("no val for order")
  5342  		}
  5343  
  5344  		order = append(order, val.AsString())
  5345  		return
  5346  	}
  5347  
  5348  	ctx := testContext2(t, &ContextOpts{
  5349  		Providers: map[addrs.Provider]providers.Factory{
  5350  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5351  		},
  5352  		Provisioners: map[string]provisioners.Factory{
  5353  			"shell": testProvisionerFuncFixed(pr),
  5354  		},
  5355  	})
  5356  
  5357  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5358  	assertNoErrors(t, diags)
  5359  
  5360  	state, diags := ctx.Apply(plan, m)
  5361  	if diags.HasErrors() {
  5362  		t.Fatalf("diags: %s", diags.Err())
  5363  	}
  5364  
  5365  	actual := strings.TrimSpace(state.String())
  5366  	expected := strings.TrimSpace(testTofuApplyProvisionerMultiSelfRefSingleStr)
  5367  	if actual != expected {
  5368  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5369  	}
  5370  
  5371  	// Verify apply was invoked
  5372  	if !pr.ProvisionResourceCalled {
  5373  		t.Fatalf("provisioner not invoked")
  5374  	}
  5375  
  5376  	// Verify our result
  5377  	sort.Strings(order)
  5378  	expectedOrder := []string{"0", "1", "2"}
  5379  	if !reflect.DeepEqual(order, expectedOrder) {
  5380  		t.Fatalf("bad: %#v", order)
  5381  	}
  5382  }
  5383  
  5384  func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) {
  5385  	m := testModule(t, "apply-provisioner-explicit-self-ref")
  5386  	p := testProvider("aws")
  5387  	pr := testProvisioner()
  5388  	p.PlanResourceChangeFn = testDiffFn
  5389  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5390  		val := req.Config.GetAttr("command")
  5391  		if val.IsNull() || val.AsString() != "bar" {
  5392  			t.Fatalf("bad value for command: %#v", val)
  5393  		}
  5394  
  5395  		return
  5396  	}
  5397  
  5398  	var state *states.State
  5399  	{
  5400  		ctx := testContext2(t, &ContextOpts{
  5401  			Providers: map[addrs.Provider]providers.Factory{
  5402  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5403  			},
  5404  			Provisioners: map[string]provisioners.Factory{
  5405  				"shell": testProvisionerFuncFixed(pr),
  5406  			},
  5407  		})
  5408  
  5409  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5410  		if diags.HasErrors() {
  5411  			t.Fatalf("diags: %s", diags.Err())
  5412  		}
  5413  
  5414  		state, diags = ctx.Apply(plan, m)
  5415  		if diags.HasErrors() {
  5416  			t.Fatalf("diags: %s", diags.Err())
  5417  		}
  5418  
  5419  		// Verify apply was invoked
  5420  		if !pr.ProvisionResourceCalled {
  5421  			t.Fatalf("provisioner not invoked")
  5422  		}
  5423  	}
  5424  
  5425  	{
  5426  		ctx := testContext2(t, &ContextOpts{
  5427  			Providers: map[addrs.Provider]providers.Factory{
  5428  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5429  			},
  5430  			Provisioners: map[string]provisioners.Factory{
  5431  				"shell": testProvisionerFuncFixed(pr),
  5432  			},
  5433  		})
  5434  
  5435  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5436  			Mode: plans.DestroyMode,
  5437  		})
  5438  		if diags.HasErrors() {
  5439  			t.Fatalf("diags: %s", diags.Err())
  5440  		}
  5441  
  5442  		state, diags = ctx.Apply(plan, m)
  5443  		if diags.HasErrors() {
  5444  			t.Fatalf("diags: %s", diags.Err())
  5445  		}
  5446  
  5447  		checkStateString(t, state, `<no state>`)
  5448  	}
  5449  }
  5450  
  5451  func TestContext2Apply_provisionerForEachSelfRef(t *testing.T) {
  5452  	m := testModule(t, "apply-provisioner-for-each-self")
  5453  	p := testProvider("aws")
  5454  	pr := testProvisioner()
  5455  	p.PlanResourceChangeFn = testDiffFn
  5456  
  5457  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5458  		val := req.Config.GetAttr("command")
  5459  		if val.IsNull() {
  5460  			t.Fatalf("bad value for command: %#v", val)
  5461  		}
  5462  
  5463  		return resp
  5464  	}
  5465  
  5466  	ctx := testContext2(t, &ContextOpts{
  5467  		Providers: map[addrs.Provider]providers.Factory{
  5468  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5469  		},
  5470  		Provisioners: map[string]provisioners.Factory{
  5471  			"shell": testProvisionerFuncFixed(pr),
  5472  		},
  5473  	})
  5474  
  5475  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5476  	assertNoErrors(t, diags)
  5477  
  5478  	_, diags = ctx.Apply(plan, m)
  5479  	if diags.HasErrors() {
  5480  		t.Fatalf("diags: %s", diags.Err())
  5481  	}
  5482  }
  5483  
  5484  // Provisioner should NOT run on a diff, only create
  5485  func TestContext2Apply_Provisioner_Diff(t *testing.T) {
  5486  	m := testModule(t, "apply-provisioner-diff")
  5487  	p := testProvider("aws")
  5488  	pr := testProvisioner()
  5489  	p.PlanResourceChangeFn = testDiffFn
  5490  	p.ApplyResourceChangeFn = testApplyFn
  5491  	ctx := testContext2(t, &ContextOpts{
  5492  		Providers: map[addrs.Provider]providers.Factory{
  5493  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5494  		},
  5495  		Provisioners: map[string]provisioners.Factory{
  5496  			"shell": testProvisionerFuncFixed(pr),
  5497  		},
  5498  	})
  5499  
  5500  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5501  	assertNoErrors(t, diags)
  5502  
  5503  	state, diags := ctx.Apply(plan, m)
  5504  	if diags.HasErrors() {
  5505  		logDiagnostics(t, diags)
  5506  		t.Fatal("apply failed")
  5507  	}
  5508  
  5509  	actual := strings.TrimSpace(state.String())
  5510  	expected := strings.TrimSpace(testTofuApplyProvisionerDiffStr)
  5511  	if actual != expected {
  5512  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5513  	}
  5514  
  5515  	// Verify apply was invoked
  5516  	if !pr.ProvisionResourceCalled {
  5517  		t.Fatalf("provisioner was not called on first apply")
  5518  	}
  5519  	pr.ProvisionResourceCalled = false
  5520  
  5521  	// Change the state to force a diff
  5522  	mod := state.RootModule()
  5523  	obj := mod.Resources["aws_instance.bar"].Instances[addrs.NoKey].Current
  5524  	var attrs map[string]interface{}
  5525  	err := json.Unmarshal(obj.AttrsJSON, &attrs)
  5526  	if err != nil {
  5527  		t.Fatal(err)
  5528  	}
  5529  	attrs["foo"] = "baz"
  5530  	obj.AttrsJSON, err = json.Marshal(attrs)
  5531  	if err != nil {
  5532  		t.Fatal(err)
  5533  	}
  5534  
  5535  	// Re-create context with state
  5536  	ctx = testContext2(t, &ContextOpts{
  5537  		Providers: map[addrs.Provider]providers.Factory{
  5538  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5539  		},
  5540  		Provisioners: map[string]provisioners.Factory{
  5541  			"shell": testProvisionerFuncFixed(pr),
  5542  		},
  5543  	})
  5544  
  5545  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  5546  	assertNoErrors(t, diags)
  5547  
  5548  	state2, diags := ctx.Apply(plan, m)
  5549  	if diags.HasErrors() {
  5550  		logDiagnostics(t, diags)
  5551  		t.Fatal("apply failed")
  5552  	}
  5553  
  5554  	actual = strings.TrimSpace(state2.String())
  5555  	if actual != expected {
  5556  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5557  	}
  5558  
  5559  	// Verify apply was NOT invoked
  5560  	if pr.ProvisionResourceCalled {
  5561  		t.Fatalf("provisioner was called on second apply; should not have been")
  5562  	}
  5563  }
  5564  
  5565  func TestContext2Apply_outputDiffVars(t *testing.T) {
  5566  	m := testModule(t, "apply-good")
  5567  	p := testProvider("aws")
  5568  
  5569  	state := states.NewState()
  5570  	root := state.EnsureModule(addrs.RootModuleInstance)
  5571  	root.SetResourceInstanceCurrent(
  5572  		mustResourceInstanceAddr("aws_instance.baz").Resource,
  5573  		&states.ResourceInstanceObjectSrc{
  5574  			Status:    states.ObjectReady,
  5575  			AttrsJSON: []byte(`{"id":"bar"}`),
  5576  		},
  5577  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  5578  	)
  5579  
  5580  	ctx := testContext2(t, &ContextOpts{
  5581  		Providers: map[addrs.Provider]providers.Factory{
  5582  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5583  		},
  5584  	})
  5585  
  5586  	p.PlanResourceChangeFn = testDiffFn
  5587  	//func(info *InstanceInfo, s *InstanceState, rc *ResourceConfig) (*InstanceDiff, error) {
  5588  	//    d := &InstanceDiff{
  5589  	//        Attributes: map[string]*ResourceAttrDiff{},
  5590  	//    }
  5591  	//    if new, ok := rc.Get("value"); ok {
  5592  	//        d.Attributes["value"] = &ResourceAttrDiff{
  5593  	//            New: new.(string),
  5594  	//        }
  5595  	//    }
  5596  	//    if new, ok := rc.Get("foo"); ok {
  5597  	//        d.Attributes["foo"] = &ResourceAttrDiff{
  5598  	//            New: new.(string),
  5599  	//        }
  5600  	//    } else if rc.IsComputed("foo") {
  5601  	//        d.Attributes["foo"] = &ResourceAttrDiff{
  5602  	//            NewComputed: true,
  5603  	//            Type:        DiffAttrOutput, // This doesn't actually really do anything anymore, but this test originally set it.
  5604  	//        }
  5605  	//    }
  5606  	//    if new, ok := rc.Get("num"); ok {
  5607  	//        d.Attributes["num"] = &ResourceAttrDiff{
  5608  	//            New: fmt.Sprintf("%#v", new),
  5609  	//        }
  5610  	//    }
  5611  	//    return d, nil
  5612  	// }
  5613  
  5614  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5615  	assertNoErrors(t, diags)
  5616  
  5617  	_, diags = ctx.Apply(plan, m)
  5618  	assertNoErrors(t, diags)
  5619  }
  5620  
  5621  func TestContext2Apply_destroyX(t *testing.T) {
  5622  	m := testModule(t, "apply-destroy")
  5623  	h := new(HookRecordApplyOrder)
  5624  	p := testProvider("aws")
  5625  	p.PlanResourceChangeFn = testDiffFn
  5626  	ctx := testContext2(t, &ContextOpts{
  5627  		Hooks: []Hook{h},
  5628  		Providers: map[addrs.Provider]providers.Factory{
  5629  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5630  		},
  5631  	})
  5632  
  5633  	// First plan and apply a create operation
  5634  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5635  	assertNoErrors(t, diags)
  5636  
  5637  	state, diags := ctx.Apply(plan, m)
  5638  	if diags.HasErrors() {
  5639  		t.Fatalf("diags: %s", diags.Err())
  5640  	}
  5641  
  5642  	// Next, plan and apply a destroy operation
  5643  	h.Active = true
  5644  	ctx = testContext2(t, &ContextOpts{
  5645  		Hooks: []Hook{h},
  5646  		Providers: map[addrs.Provider]providers.Factory{
  5647  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5648  		},
  5649  	})
  5650  
  5651  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5652  		Mode: plans.DestroyMode,
  5653  	})
  5654  	assertNoErrors(t, diags)
  5655  
  5656  	state, diags = ctx.Apply(plan, m)
  5657  	if diags.HasErrors() {
  5658  		t.Fatalf("diags: %s", diags.Err())
  5659  	}
  5660  
  5661  	// Test that things were destroyed
  5662  	actual := strings.TrimSpace(state.String())
  5663  	expected := strings.TrimSpace(testTofuApplyDestroyStr)
  5664  	if actual != expected {
  5665  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5666  	}
  5667  
  5668  	// Test that things were destroyed _in the right order_
  5669  	expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
  5670  	actual2 := h.IDs
  5671  	if !reflect.DeepEqual(actual2, expected2) {
  5672  		t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
  5673  	}
  5674  }
  5675  
  5676  func TestContext2Apply_destroyOrder(t *testing.T) {
  5677  	m := testModule(t, "apply-destroy")
  5678  	h := new(HookRecordApplyOrder)
  5679  	p := testProvider("aws")
  5680  	p.PlanResourceChangeFn = testDiffFn
  5681  	ctx := testContext2(t, &ContextOpts{
  5682  		Hooks: []Hook{h},
  5683  		Providers: map[addrs.Provider]providers.Factory{
  5684  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5685  		},
  5686  	})
  5687  
  5688  	// First plan and apply a create operation
  5689  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5690  	assertNoErrors(t, diags)
  5691  
  5692  	state, diags := ctx.Apply(plan, m)
  5693  	if diags.HasErrors() {
  5694  		t.Fatalf("diags: %s", diags.Err())
  5695  	}
  5696  
  5697  	t.Logf("State 1: %s", state)
  5698  
  5699  	// Next, plan and apply a destroy
  5700  	h.Active = true
  5701  	ctx = testContext2(t, &ContextOpts{
  5702  		Hooks: []Hook{h},
  5703  		Providers: map[addrs.Provider]providers.Factory{
  5704  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5705  		},
  5706  	})
  5707  
  5708  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5709  		Mode: plans.DestroyMode,
  5710  	})
  5711  	assertNoErrors(t, diags)
  5712  
  5713  	state, diags = ctx.Apply(plan, m)
  5714  	if diags.HasErrors() {
  5715  		t.Fatalf("diags: %s", diags.Err())
  5716  	}
  5717  
  5718  	// Test that things were destroyed
  5719  	actual := strings.TrimSpace(state.String())
  5720  	expected := strings.TrimSpace(testTofuApplyDestroyStr)
  5721  	if actual != expected {
  5722  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5723  	}
  5724  
  5725  	// Test that things were destroyed _in the right order_
  5726  	expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
  5727  	actual2 := h.IDs
  5728  	if !reflect.DeepEqual(actual2, expected2) {
  5729  		t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
  5730  	}
  5731  }
  5732  
  5733  // https://github.com/hashicorp/terraform/issues/2767
  5734  func TestContext2Apply_destroyModulePrefix(t *testing.T) {
  5735  	m := testModule(t, "apply-destroy-module-resource-prefix")
  5736  	h := new(MockHook)
  5737  	p := testProvider("aws")
  5738  	p.PlanResourceChangeFn = testDiffFn
  5739  	ctx := testContext2(t, &ContextOpts{
  5740  		Hooks: []Hook{h},
  5741  		Providers: map[addrs.Provider]providers.Factory{
  5742  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5743  		},
  5744  	})
  5745  
  5746  	// First plan and apply a create operation
  5747  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5748  	assertNoErrors(t, diags)
  5749  
  5750  	state, diags := ctx.Apply(plan, m)
  5751  	if diags.HasErrors() {
  5752  		t.Fatalf("diags: %s", diags.Err())
  5753  	}
  5754  
  5755  	// Verify that we got the apply info correct
  5756  	if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" {
  5757  		t.Fatalf("bad: %s", v)
  5758  	}
  5759  
  5760  	// Next, plan and apply a destroy operation and reset the hook
  5761  	h = new(MockHook)
  5762  	ctx = testContext2(t, &ContextOpts{
  5763  		Hooks: []Hook{h},
  5764  		Providers: map[addrs.Provider]providers.Factory{
  5765  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5766  		},
  5767  	})
  5768  
  5769  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5770  		Mode: plans.DestroyMode,
  5771  	})
  5772  	assertNoErrors(t, diags)
  5773  
  5774  	_, diags = ctx.Apply(plan, m)
  5775  	if diags.HasErrors() {
  5776  		t.Fatalf("diags: %s", diags.Err())
  5777  	}
  5778  
  5779  	// Test that things were destroyed
  5780  	if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" {
  5781  		t.Fatalf("bad: %s", v)
  5782  	}
  5783  }
  5784  
  5785  func TestContext2Apply_destroyNestedModule(t *testing.T) {
  5786  	m := testModule(t, "apply-destroy-nested-module")
  5787  	p := testProvider("aws")
  5788  	p.PlanResourceChangeFn = testDiffFn
  5789  
  5790  	state := states.NewState()
  5791  	root := state.EnsureModule(addrs.RootModuleInstance)
  5792  	root.SetResourceInstanceCurrent(
  5793  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  5794  		&states.ResourceInstanceObjectSrc{
  5795  			Status:    states.ObjectReady,
  5796  			AttrsJSON: []byte(`{"id":"bar"}`),
  5797  		},
  5798  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  5799  	)
  5800  
  5801  	ctx := testContext2(t, &ContextOpts{
  5802  		Providers: map[addrs.Provider]providers.Factory{
  5803  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5804  		},
  5805  	})
  5806  
  5807  	// First plan and apply a create operation
  5808  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5809  	assertNoErrors(t, diags)
  5810  
  5811  	s, diags := ctx.Apply(plan, m)
  5812  	if diags.HasErrors() {
  5813  		t.Fatalf("diags: %s", diags.Err())
  5814  	}
  5815  
  5816  	// Test that things were destroyed
  5817  	actual := strings.TrimSpace(s.String())
  5818  	if actual != "<no state>" {
  5819  		t.Fatalf("expected no state, got: %s", actual)
  5820  	}
  5821  }
  5822  
  5823  func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) {
  5824  	m := testModule(t, "apply-destroy-deeply-nested-module")
  5825  	p := testProvider("aws")
  5826  	p.PlanResourceChangeFn = testDiffFn
  5827  
  5828  	state := states.NewState()
  5829  	root := state.EnsureModule(addrs.RootModuleInstance)
  5830  	root.SetResourceInstanceCurrent(
  5831  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  5832  		&states.ResourceInstanceObjectSrc{
  5833  			Status:    states.ObjectReady,
  5834  			AttrsJSON: []byte(`{"id":"bar"}`),
  5835  		},
  5836  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  5837  	)
  5838  
  5839  	ctx := testContext2(t, &ContextOpts{
  5840  		Providers: map[addrs.Provider]providers.Factory{
  5841  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5842  		},
  5843  	})
  5844  
  5845  	// First plan and apply a create operation
  5846  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5847  	assertNoErrors(t, diags)
  5848  
  5849  	s, diags := ctx.Apply(plan, m)
  5850  	if diags.HasErrors() {
  5851  		t.Fatalf("diags: %s", diags.Err())
  5852  	}
  5853  
  5854  	// Test that things were destroyed
  5855  	if !s.Empty() {
  5856  		t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(s))
  5857  	}
  5858  }
  5859  
  5860  // https://github.com/hashicorp/terraform/issues/5440
  5861  func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) {
  5862  	m, snap := testModuleWithSnapshot(t, "apply-destroy-module-with-attrs")
  5863  	p := testProvider("aws")
  5864  	p.PlanResourceChangeFn = testDiffFn
  5865  
  5866  	var state *states.State
  5867  	{
  5868  		ctx := testContext2(t, &ContextOpts{
  5869  			Providers: map[addrs.Provider]providers.Factory{
  5870  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5871  			},
  5872  		})
  5873  
  5874  		// First plan and apply a create operation
  5875  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5876  		if diags.HasErrors() {
  5877  			t.Fatalf("plan diags: %s", diags.Err())
  5878  		} else {
  5879  			t.Logf("Step 1 plan: %s", legacyDiffComparisonString(plan.Changes))
  5880  		}
  5881  
  5882  		state, diags = ctx.Apply(plan, m)
  5883  		if diags.HasErrors() {
  5884  			t.Fatalf("apply errs: %s", diags.Err())
  5885  		}
  5886  
  5887  		t.Logf("Step 1 state: %s", state)
  5888  	}
  5889  
  5890  	h := new(HookRecordApplyOrder)
  5891  	h.Active = true
  5892  
  5893  	{
  5894  		ctx := testContext2(t, &ContextOpts{
  5895  			Hooks: []Hook{h},
  5896  			Providers: map[addrs.Provider]providers.Factory{
  5897  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5898  			},
  5899  		})
  5900  
  5901  		// First plan and apply a create operation
  5902  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5903  			Mode: plans.DestroyMode,
  5904  		})
  5905  		if diags.HasErrors() {
  5906  			t.Fatalf("destroy plan err: %s", diags.Err())
  5907  		}
  5908  
  5909  		t.Logf("Step 2 plan: %s", legacyDiffComparisonString(plan.Changes))
  5910  
  5911  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  5912  		if err != nil {
  5913  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5914  		}
  5915  
  5916  		ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  5917  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5918  		}
  5919  
  5920  		ctx, diags = NewContext(ctxOpts)
  5921  		if diags.HasErrors() {
  5922  			t.Fatalf("err: %s", diags.Err())
  5923  		}
  5924  
  5925  		state, diags = ctx.Apply(plan, m)
  5926  		if diags.HasErrors() {
  5927  			t.Fatalf("destroy apply err: %s", diags.Err())
  5928  		}
  5929  
  5930  		t.Logf("Step 2 state: %s", state)
  5931  	}
  5932  
  5933  	// Test that things were destroyed
  5934  	if state.HasManagedResourceInstanceObjects() {
  5935  		t.Fatal("expected empty state, got:", state)
  5936  	}
  5937  }
  5938  
  5939  func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) {
  5940  	m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count")
  5941  	p := testProvider("aws")
  5942  	p.PlanResourceChangeFn = testDiffFn
  5943  
  5944  	var state *states.State
  5945  	{
  5946  		ctx := testContext2(t, &ContextOpts{
  5947  			Providers: map[addrs.Provider]providers.Factory{
  5948  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5949  			},
  5950  		})
  5951  
  5952  		// First plan and apply a create operation
  5953  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5954  		assertNoErrors(t, diags)
  5955  
  5956  		state, diags = ctx.Apply(plan, m)
  5957  		if diags.HasErrors() {
  5958  			t.Fatalf("apply err: %s", diags.Err())
  5959  		}
  5960  	}
  5961  
  5962  	h := new(HookRecordApplyOrder)
  5963  	h.Active = true
  5964  
  5965  	{
  5966  		ctx := testContext2(t, &ContextOpts{
  5967  			Hooks: []Hook{h},
  5968  			Providers: map[addrs.Provider]providers.Factory{
  5969  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5970  			},
  5971  		})
  5972  
  5973  		// First plan and apply a create operation
  5974  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5975  			Mode: plans.DestroyMode,
  5976  		})
  5977  		if diags.HasErrors() {
  5978  			t.Fatalf("destroy plan err: %s", diags.Err())
  5979  		}
  5980  
  5981  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  5982  		if err != nil {
  5983  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5984  		}
  5985  
  5986  		ctxOpts.Providers =
  5987  			map[addrs.Provider]providers.Factory{
  5988  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5989  			}
  5990  
  5991  		ctx, diags = NewContext(ctxOpts)
  5992  		if diags.HasErrors() {
  5993  			t.Fatalf("err: %s", diags.Err())
  5994  		}
  5995  
  5996  		state, diags = ctx.Apply(plan, m)
  5997  		if diags.HasErrors() {
  5998  			t.Fatalf("destroy apply err: %s", diags.Err())
  5999  		}
  6000  	}
  6001  
  6002  	// Test that things were destroyed
  6003  	actual := strings.TrimSpace(state.String())
  6004  	expected := strings.TrimSpace(`
  6005  <no state>`)
  6006  	if actual != expected {
  6007  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  6008  	}
  6009  }
  6010  
  6011  func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) {
  6012  	m := testModule(t, "apply-destroy-mod-var-and-count")
  6013  	p := testProvider("aws")
  6014  	p.PlanResourceChangeFn = testDiffFn
  6015  
  6016  	var state *states.State
  6017  	{
  6018  		ctx := testContext2(t, &ContextOpts{
  6019  			Providers: map[addrs.Provider]providers.Factory{
  6020  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6021  			},
  6022  		})
  6023  
  6024  		// First plan and apply a create operation
  6025  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6026  		assertNoErrors(t, diags)
  6027  
  6028  		state, diags = ctx.Apply(plan, m)
  6029  		if diags.HasErrors() {
  6030  			t.Fatalf("apply err: %s", diags.Err())
  6031  		}
  6032  	}
  6033  
  6034  	{
  6035  		ctx := testContext2(t, &ContextOpts{
  6036  			Providers: map[addrs.Provider]providers.Factory{
  6037  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6038  			},
  6039  		})
  6040  
  6041  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  6042  			Mode: plans.DestroyMode,
  6043  			Targets: []addrs.Targetable{
  6044  				addrs.RootModuleInstance.Child("child", addrs.NoKey),
  6045  			},
  6046  		})
  6047  		if diags.HasErrors() {
  6048  			t.Fatalf("plan err: %s", diags)
  6049  		}
  6050  		if len(diags) != 1 {
  6051  			// Should have one warning that -target is in effect.
  6052  			t.Fatalf("got %d diagnostics in plan; want 1", len(diags))
  6053  		}
  6054  		if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
  6055  			t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
  6056  		}
  6057  		if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want {
  6058  			t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
  6059  		}
  6060  
  6061  		// Destroy, targeting the module explicitly
  6062  		state, diags = ctx.Apply(plan, m)
  6063  		if diags.HasErrors() {
  6064  			t.Fatalf("destroy apply err: %s", diags)
  6065  		}
  6066  		if len(diags) != 1 {
  6067  			t.Fatalf("got %d diagnostics; want 1", len(diags))
  6068  		}
  6069  		if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
  6070  			t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
  6071  		}
  6072  		if got, want := diags[0].Description().Summary, "Applied changes may be incomplete"; got != want {
  6073  			t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
  6074  		}
  6075  	}
  6076  
  6077  	// Test that things were destroyed
  6078  	actual := strings.TrimSpace(state.String())
  6079  	expected := strings.TrimSpace(`<no state>`)
  6080  	if actual != expected {
  6081  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  6082  	}
  6083  }
  6084  
  6085  func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) {
  6086  	m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count-nested")
  6087  	p := testProvider("aws")
  6088  	p.PlanResourceChangeFn = testDiffFn
  6089  
  6090  	var state *states.State
  6091  	{
  6092  		ctx := testContext2(t, &ContextOpts{
  6093  			Providers: map[addrs.Provider]providers.Factory{
  6094  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6095  			},
  6096  		})
  6097  
  6098  		// First plan and apply a create operation
  6099  		plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  6100  		assertNoErrors(t, diags)
  6101  
  6102  		state, diags = ctx.Apply(plan, m)
  6103  		if diags.HasErrors() {
  6104  			t.Fatalf("apply err: %s", diags.Err())
  6105  		}
  6106  	}
  6107  
  6108  	h := new(HookRecordApplyOrder)
  6109  	h.Active = true
  6110  
  6111  	{
  6112  		ctx := testContext2(t, &ContextOpts{
  6113  			Hooks: []Hook{h},
  6114  			Providers: map[addrs.Provider]providers.Factory{
  6115  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6116  			},
  6117  		})
  6118  
  6119  		// First plan and apply a create operation
  6120  		plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
  6121  		if diags.HasErrors() {
  6122  			t.Fatalf("destroy plan err: %s", diags.Err())
  6123  		}
  6124  
  6125  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  6126  		if err != nil {
  6127  			t.Fatalf("failed to round-trip through planfile: %s", err)
  6128  		}
  6129  
  6130  		ctxOpts.Providers =
  6131  			map[addrs.Provider]providers.Factory{
  6132  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6133  			}
  6134  
  6135  		ctx, diags = NewContext(ctxOpts)
  6136  		if diags.HasErrors() {
  6137  			t.Fatalf("err: %s", diags.Err())
  6138  		}
  6139  
  6140  		state, diags = ctx.Apply(plan, m)
  6141  		if diags.HasErrors() {
  6142  			t.Fatalf("destroy apply err: %s", diags.Err())
  6143  		}
  6144  	}
  6145  
  6146  	// Test that things were destroyed
  6147  	actual := strings.TrimSpace(state.String())
  6148  	expected := strings.TrimSpace(`
  6149  <no state>`)
  6150  	if actual != expected {
  6151  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  6152  	}
  6153  }
  6154  
  6155  func TestContext2Apply_destroyOutputs(t *testing.T) {
  6156  	m := testModule(t, "apply-destroy-outputs")
  6157  	p := testProvider("test")
  6158  	p.PlanResourceChangeFn = testDiffFn
  6159  
  6160  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  6161  		// add the required id
  6162  		m := req.Config.AsValueMap()
  6163  		m["id"] = cty.StringVal("foo")
  6164  
  6165  		return providers.ReadDataSourceResponse{
  6166  			State: cty.ObjectVal(m),
  6167  		}
  6168  	}
  6169  
  6170  	ctx := testContext2(t, &ContextOpts{
  6171  		Providers: map[addrs.Provider]providers.Factory{
  6172  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6173  		},
  6174  	})
  6175  
  6176  	// First plan and apply a create operation
  6177  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6178  	assertNoErrors(t, diags)
  6179  
  6180  	state, diags := ctx.Apply(plan, m)
  6181  
  6182  	if diags.HasErrors() {
  6183  		t.Fatalf("diags: %s", diags.Err())
  6184  	}
  6185  
  6186  	// Next, plan and apply a destroy operation
  6187  	ctx = testContext2(t, &ContextOpts{
  6188  		Providers: map[addrs.Provider]providers.Factory{
  6189  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6190  		},
  6191  	})
  6192  
  6193  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  6194  		Mode: plans.DestroyMode,
  6195  	})
  6196  	assertNoErrors(t, diags)
  6197  
  6198  	state, diags = ctx.Apply(plan, m)
  6199  	if diags.HasErrors() {
  6200  		t.Fatalf("diags: %s", diags.Err())
  6201  	}
  6202  
  6203  	mod := state.RootModule()
  6204  	if len(mod.Resources) > 0 {
  6205  		t.Fatalf("expected no resources, got: %#v", mod)
  6206  	}
  6207  
  6208  	// destroying again should produce no errors
  6209  	ctx = testContext2(t, &ContextOpts{
  6210  		Providers: map[addrs.Provider]providers.Factory{
  6211  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6212  		},
  6213  	})
  6214  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  6215  		Mode: plans.DestroyMode,
  6216  	})
  6217  	assertNoErrors(t, diags)
  6218  
  6219  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6220  		t.Fatal(diags.Err())
  6221  	}
  6222  }
  6223  
  6224  func TestContext2Apply_destroyOrphan(t *testing.T) {
  6225  	m := testModule(t, "apply-error")
  6226  	p := testProvider("aws")
  6227  	state := states.NewState()
  6228  	root := state.EnsureModule(addrs.RootModuleInstance)
  6229  	root.SetResourceInstanceCurrent(
  6230  		mustResourceInstanceAddr("aws_instance.baz").Resource,
  6231  		&states.ResourceInstanceObjectSrc{
  6232  			Status:    states.ObjectReady,
  6233  			AttrsJSON: []byte(`{"id":"bar"}`),
  6234  		},
  6235  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  6236  	)
  6237  	ctx := testContext2(t, &ContextOpts{
  6238  		Providers: map[addrs.Provider]providers.Factory{
  6239  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6240  		},
  6241  	})
  6242  
  6243  	p.PlanResourceChangeFn = testDiffFn
  6244  
  6245  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6246  	assertNoErrors(t, diags)
  6247  
  6248  	s, diags := ctx.Apply(plan, m)
  6249  	if diags.HasErrors() {
  6250  		t.Fatalf("diags: %s", diags.Err())
  6251  	}
  6252  
  6253  	mod := s.RootModule()
  6254  	if _, ok := mod.Resources["aws_instance.baz"]; ok {
  6255  		t.Fatalf("bad: %#v", mod.Resources)
  6256  	}
  6257  }
  6258  
  6259  func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) {
  6260  	m := testModule(t, "apply-destroy-provisioner")
  6261  	p := testProvider("aws")
  6262  	pr := testProvisioner()
  6263  	p.PlanResourceChangeFn = testDiffFn
  6264  
  6265  	state := states.NewState()
  6266  	root := state.EnsureModule(addrs.RootModuleInstance)
  6267  	root.SetResourceInstanceCurrent(
  6268  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6269  		&states.ResourceInstanceObjectSrc{
  6270  			Status:    states.ObjectReady,
  6271  			AttrsJSON: []byte(`{"id":"bar"}`),
  6272  		},
  6273  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  6274  	)
  6275  
  6276  	ctx := testContext2(t, &ContextOpts{
  6277  		Providers: map[addrs.Provider]providers.Factory{
  6278  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6279  		},
  6280  		Provisioners: map[string]provisioners.Factory{
  6281  			"shell": testProvisionerFuncFixed(pr),
  6282  		},
  6283  	})
  6284  
  6285  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  6286  		Mode: plans.DestroyMode,
  6287  	})
  6288  	assertNoErrors(t, diags)
  6289  
  6290  	s, diags := ctx.Apply(plan, m)
  6291  	if diags.HasErrors() {
  6292  		t.Fatalf("diags: %s", diags.Err())
  6293  	}
  6294  
  6295  	if pr.ProvisionResourceCalled {
  6296  		t.Fatal("provisioner should not be called")
  6297  	}
  6298  
  6299  	actual := strings.TrimSpace(s.String())
  6300  	expected := strings.TrimSpace("<no state>")
  6301  	if actual != expected {
  6302  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6303  	}
  6304  }
  6305  
  6306  func TestContext2Apply_error(t *testing.T) {
  6307  	errored := false
  6308  
  6309  	m := testModule(t, "apply-error")
  6310  	p := testProvider("aws")
  6311  	ctx := testContext2(t, &ContextOpts{
  6312  		Providers: map[addrs.Provider]providers.Factory{
  6313  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6314  		},
  6315  	})
  6316  
  6317  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  6318  		if errored {
  6319  			resp.NewState = req.PlannedState
  6320  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  6321  			return
  6322  		}
  6323  		errored = true
  6324  
  6325  		return testApplyFn(req)
  6326  	}
  6327  	p.PlanResourceChangeFn = testDiffFn
  6328  
  6329  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6330  	assertNoErrors(t, diags)
  6331  
  6332  	state, diags := ctx.Apply(plan, m)
  6333  	if diags == nil {
  6334  		t.Fatal("should have error")
  6335  	}
  6336  
  6337  	actual := strings.TrimSpace(state.String())
  6338  	expected := strings.TrimSpace(testTofuApplyErrorStr)
  6339  	if actual != expected {
  6340  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6341  	}
  6342  }
  6343  
  6344  func TestContext2Apply_errorDestroy(t *testing.T) {
  6345  	m := testModule(t, "empty")
  6346  	p := testProvider("test")
  6347  
  6348  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6349  		ResourceTypes: map[string]*configschema.Block{
  6350  			"test_thing": {
  6351  				Attributes: map[string]*configschema.Attribute{
  6352  					"id": {Type: cty.String, Optional: true},
  6353  				},
  6354  			},
  6355  		},
  6356  	})
  6357  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6358  		// Should actually be called for this test, because OpenTofu Core
  6359  		// constructs the plan for a destroy operation itself.
  6360  		return providers.PlanResourceChangeResponse{
  6361  			PlannedState: req.ProposedNewState,
  6362  		}
  6363  	}
  6364  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6365  		// The apply (in this case, a destroy) always fails, so we can verify
  6366  		// that the object stays in the state after a destroy fails even though
  6367  		// we aren't returning a new state object here.
  6368  		return providers.ApplyResourceChangeResponse{
  6369  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("failed")),
  6370  		}
  6371  	}
  6372  
  6373  	ctx := testContext2(t, &ContextOpts{
  6374  		Providers: map[addrs.Provider]providers.Factory{
  6375  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6376  		},
  6377  	})
  6378  
  6379  	state := states.BuildState(func(ss *states.SyncState) {
  6380  		ss.SetResourceInstanceCurrent(
  6381  			addrs.Resource{
  6382  				Mode: addrs.ManagedResourceMode,
  6383  				Type: "test_thing",
  6384  				Name: "foo",
  6385  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  6386  			&states.ResourceInstanceObjectSrc{
  6387  				Status:    states.ObjectReady,
  6388  				AttrsJSON: []byte(`{"id":"baz"}`),
  6389  			},
  6390  			addrs.AbsProviderConfig{
  6391  				Provider: addrs.NewDefaultProvider("test"),
  6392  				Module:   addrs.RootModule,
  6393  			},
  6394  		)
  6395  	})
  6396  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6397  	assertNoErrors(t, diags)
  6398  
  6399  	state, diags = ctx.Apply(plan, m)
  6400  	if !diags.HasErrors() {
  6401  		t.Fatal("should have error")
  6402  	}
  6403  
  6404  	actual := strings.TrimSpace(state.String())
  6405  	expected := strings.TrimSpace(`
  6406  test_thing.foo:
  6407    ID = baz
  6408    provider = provider["registry.opentofu.org/hashicorp/test"]
  6409  `) // test_thing.foo is still here, even though provider returned no new state along with its error
  6410  	if actual != expected {
  6411  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6412  	}
  6413  }
  6414  
  6415  func TestContext2Apply_errorCreateInvalidNew(t *testing.T) {
  6416  	m := testModule(t, "apply-error")
  6417  
  6418  	p := testProvider("aws")
  6419  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6420  		ResourceTypes: map[string]*configschema.Block{
  6421  			"aws_instance": {
  6422  				Attributes: map[string]*configschema.Attribute{
  6423  					"value": {Type: cty.String, Optional: true},
  6424  					"foo":   {Type: cty.String, Optional: true},
  6425  				},
  6426  			},
  6427  		},
  6428  	})
  6429  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6430  		return providers.PlanResourceChangeResponse{
  6431  			PlannedState: req.ProposedNewState,
  6432  		}
  6433  	}
  6434  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6435  		// We're intentionally returning an inconsistent new state here
  6436  		// because we want to test that OpenTofu ignores the inconsistency
  6437  		// when accompanied by another error.
  6438  		return providers.ApplyResourceChangeResponse{
  6439  			NewState: cty.ObjectVal(map[string]cty.Value{
  6440  				"value": cty.StringVal("wrong wrong wrong wrong"),
  6441  				"foo":   cty.StringVal("absolutely brimming over with wrongability"),
  6442  			}),
  6443  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")),
  6444  		}
  6445  	}
  6446  
  6447  	ctx := testContext2(t, &ContextOpts{
  6448  		Providers: map[addrs.Provider]providers.Factory{
  6449  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6450  		},
  6451  	})
  6452  
  6453  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6454  	assertNoErrors(t, diags)
  6455  
  6456  	state, diags := ctx.Apply(plan, m)
  6457  	if diags == nil {
  6458  		t.Fatal("should have error")
  6459  	}
  6460  	if got, want := len(diags), 1; got != want {
  6461  		// There should be no additional diagnostics generated by OpenTofu's own eval logic,
  6462  		// because the provider's own error supersedes them.
  6463  		t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err())
  6464  	}
  6465  	if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) {
  6466  		t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err())
  6467  	}
  6468  	if got, want := len(state.RootModule().Resources), 1; got != want {
  6469  		t.Errorf("%d resources in state before prune; should have %d\n%s", got, want, spew.Sdump(state))
  6470  	}
  6471  	state.PruneResourceHusks() // aws_instance.bar with no instances gets left behind when we bail out, but that's okay
  6472  	if got, want := len(state.RootModule().Resources), 1; got != want {
  6473  		t.Errorf("%d resources in state after prune; should have only one (aws_instance.foo, tainted)\n%s", got, spew.Sdump(state))
  6474  	}
  6475  }
  6476  
  6477  func TestContext2Apply_errorUpdateNullNew(t *testing.T) {
  6478  	m := testModule(t, "apply-error")
  6479  
  6480  	p := testProvider("aws")
  6481  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6482  		ResourceTypes: map[string]*configschema.Block{
  6483  			"aws_instance": {
  6484  				Attributes: map[string]*configschema.Attribute{
  6485  					"value": {Type: cty.String, Optional: true},
  6486  					"foo":   {Type: cty.String, Optional: true},
  6487  				},
  6488  			},
  6489  		},
  6490  	})
  6491  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6492  		return providers.PlanResourceChangeResponse{
  6493  			PlannedState: req.ProposedNewState,
  6494  		}
  6495  	}
  6496  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6497  		// We're intentionally returning no NewState here because we want to
  6498  		// test that OpenTofu retains the prior state, rather than treating
  6499  		// the returned null as "no state" (object deleted).
  6500  		return providers.ApplyResourceChangeResponse{
  6501  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")),
  6502  		}
  6503  	}
  6504  
  6505  	ctx := testContext2(t, &ContextOpts{
  6506  		Providers: map[addrs.Provider]providers.Factory{
  6507  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6508  		},
  6509  	})
  6510  
  6511  	state := states.BuildState(func(ss *states.SyncState) {
  6512  		ss.SetResourceInstanceCurrent(
  6513  			addrs.Resource{
  6514  				Mode: addrs.ManagedResourceMode,
  6515  				Type: "aws_instance",
  6516  				Name: "foo",
  6517  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  6518  			&states.ResourceInstanceObjectSrc{
  6519  				Status:    states.ObjectReady,
  6520  				AttrsJSON: []byte(`{"value":"old"}`),
  6521  			},
  6522  			addrs.AbsProviderConfig{
  6523  				Provider: addrs.NewDefaultProvider("aws"),
  6524  				Module:   addrs.RootModule,
  6525  			},
  6526  		)
  6527  	})
  6528  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6529  	assertNoErrors(t, diags)
  6530  
  6531  	state, diags = ctx.Apply(plan, m)
  6532  	if !diags.HasErrors() {
  6533  		t.Fatal("should have error")
  6534  	}
  6535  	if got, want := len(diags), 1; got != want {
  6536  		// There should be no additional diagnostics generated by OpenTofu's own eval logic,
  6537  		// because the provider's own error supersedes them.
  6538  		t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err())
  6539  	}
  6540  	if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) {
  6541  		t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err())
  6542  	}
  6543  	state.PruneResourceHusks()
  6544  	if got, want := len(state.RootModule().Resources), 1; got != want {
  6545  		t.Fatalf("%d resources in state; should have only one (aws_instance.foo, unmodified)\n%s", got, spew.Sdump(state))
  6546  	}
  6547  
  6548  	is := state.ResourceInstance(addrs.Resource{
  6549  		Mode: addrs.ManagedResourceMode,
  6550  		Type: "aws_instance",
  6551  		Name: "foo",
  6552  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
  6553  	if is == nil {
  6554  		t.Fatalf("aws_instance.foo is not in the state after apply")
  6555  	}
  6556  	if got, want := is.Current.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) {
  6557  		t.Fatalf("incorrect attributes for aws_instance.foo\ngot: %s\nwant: JSON containing %s\n\n%s", got, want, spew.Sdump(is))
  6558  	}
  6559  }
  6560  
  6561  func TestContext2Apply_errorPartial(t *testing.T) {
  6562  	errored := false
  6563  
  6564  	m := testModule(t, "apply-error")
  6565  	p := testProvider("aws")
  6566  
  6567  	state := states.NewState()
  6568  	root := state.EnsureModule(addrs.RootModuleInstance)
  6569  	root.SetResourceInstanceCurrent(
  6570  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6571  		&states.ResourceInstanceObjectSrc{
  6572  			Status:    states.ObjectReady,
  6573  			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
  6574  		},
  6575  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  6576  	)
  6577  
  6578  	ctx := testContext2(t, &ContextOpts{
  6579  		Providers: map[addrs.Provider]providers.Factory{
  6580  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6581  		},
  6582  	})
  6583  
  6584  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  6585  		if errored {
  6586  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  6587  			return
  6588  		}
  6589  		errored = true
  6590  
  6591  		return testApplyFn(req)
  6592  	}
  6593  	p.PlanResourceChangeFn = testDiffFn
  6594  
  6595  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6596  	assertNoErrors(t, diags)
  6597  
  6598  	s, diags := ctx.Apply(plan, m)
  6599  	if diags == nil {
  6600  		t.Fatal("should have error")
  6601  	}
  6602  
  6603  	mod := s.RootModule()
  6604  	if len(mod.Resources) != 2 {
  6605  		t.Fatalf("bad: %#v", mod.Resources)
  6606  	}
  6607  
  6608  	actual := strings.TrimSpace(s.String())
  6609  	expected := strings.TrimSpace(testTofuApplyErrorPartialStr)
  6610  	if actual != expected {
  6611  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6612  	}
  6613  }
  6614  
  6615  func TestContext2Apply_hook(t *testing.T) {
  6616  	m := testModule(t, "apply-good")
  6617  	h := new(MockHook)
  6618  	p := testProvider("aws")
  6619  	p.PlanResourceChangeFn = testDiffFn
  6620  	ctx := testContext2(t, &ContextOpts{
  6621  		Hooks: []Hook{h},
  6622  		Providers: map[addrs.Provider]providers.Factory{
  6623  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6624  		},
  6625  	})
  6626  
  6627  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6628  	assertNoErrors(t, diags)
  6629  
  6630  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6631  		t.Fatalf("apply errors: %s", diags.Err())
  6632  	}
  6633  
  6634  	if !h.PreApplyCalled {
  6635  		t.Fatal("should be called")
  6636  	}
  6637  	if !h.PostApplyCalled {
  6638  		t.Fatal("should be called")
  6639  	}
  6640  	if !h.PostStateUpdateCalled {
  6641  		t.Fatalf("should call post state update")
  6642  	}
  6643  }
  6644  
  6645  func TestContext2Apply_hookOrphan(t *testing.T) {
  6646  	m := testModule(t, "apply-blank")
  6647  	h := new(MockHook)
  6648  	p := testProvider("aws")
  6649  	p.PlanResourceChangeFn = testDiffFn
  6650  
  6651  	state := states.NewState()
  6652  	root := state.EnsureModule(addrs.RootModuleInstance)
  6653  	root.SetResourceInstanceCurrent(
  6654  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6655  		&states.ResourceInstanceObjectSrc{
  6656  			Status:    states.ObjectReady,
  6657  			AttrsJSON: []byte(`{"id":"bar"}`),
  6658  		},
  6659  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  6660  	)
  6661  
  6662  	ctx := testContext2(t, &ContextOpts{
  6663  		Hooks: []Hook{h},
  6664  		Providers: map[addrs.Provider]providers.Factory{
  6665  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6666  		},
  6667  	})
  6668  
  6669  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6670  	assertNoErrors(t, diags)
  6671  
  6672  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6673  		t.Fatalf("apply errors: %s", diags.Err())
  6674  	}
  6675  
  6676  	if !h.PreApplyCalled {
  6677  		t.Fatal("should be called")
  6678  	}
  6679  	if !h.PostApplyCalled {
  6680  		t.Fatal("should be called")
  6681  	}
  6682  	if !h.PostStateUpdateCalled {
  6683  		t.Fatalf("should call post state update")
  6684  	}
  6685  }
  6686  
  6687  func TestContext2Apply_idAttr(t *testing.T) {
  6688  	m := testModule(t, "apply-idattr")
  6689  	p := testProvider("aws")
  6690  	ctx := testContext2(t, &ContextOpts{
  6691  		Providers: map[addrs.Provider]providers.Factory{
  6692  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6693  		},
  6694  	})
  6695  
  6696  	p.PlanResourceChangeFn = testDiffFn
  6697  	p.ApplyResourceChangeFn = testApplyFn
  6698  
  6699  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6700  	assertNoErrors(t, diags)
  6701  
  6702  	state, diags := ctx.Apply(plan, m)
  6703  	if diags.HasErrors() {
  6704  		t.Fatalf("apply errors: %s", diags.Err())
  6705  	}
  6706  
  6707  	mod := state.RootModule()
  6708  	rs, ok := mod.Resources["aws_instance.foo"]
  6709  	if !ok {
  6710  		t.Fatal("not in state")
  6711  	}
  6712  	var attrs map[string]interface{}
  6713  	err := json.Unmarshal(rs.Instances[addrs.NoKey].Current.AttrsJSON, &attrs)
  6714  	if err != nil {
  6715  		t.Fatal(err)
  6716  	}
  6717  	if got, want := attrs["id"], "foo"; got != want {
  6718  		t.Fatalf("wrong id\ngot:  %#v\nwant: %#v", got, want)
  6719  	}
  6720  }
  6721  
  6722  func TestContext2Apply_outputBasic(t *testing.T) {
  6723  	m := testModule(t, "apply-output")
  6724  	p := testProvider("aws")
  6725  	p.PlanResourceChangeFn = testDiffFn
  6726  	p.ApplyResourceChangeFn = testApplyFn
  6727  	ctx := testContext2(t, &ContextOpts{
  6728  		Providers: map[addrs.Provider]providers.Factory{
  6729  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6730  		},
  6731  	})
  6732  
  6733  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6734  	assertNoErrors(t, diags)
  6735  
  6736  	state, diags := ctx.Apply(plan, m)
  6737  	if diags.HasErrors() {
  6738  		t.Fatalf("diags: %s", diags.Err())
  6739  	}
  6740  
  6741  	actual := strings.TrimSpace(state.String())
  6742  	expected := strings.TrimSpace(testTofuApplyOutputStr)
  6743  	if actual != expected {
  6744  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6745  	}
  6746  }
  6747  
  6748  func TestContext2Apply_outputAdd(t *testing.T) {
  6749  	m1 := testModule(t, "apply-output-add-before")
  6750  	p1 := testProvider("aws")
  6751  	p1.ApplyResourceChangeFn = testApplyFn
  6752  	p1.PlanResourceChangeFn = testDiffFn
  6753  	ctx1 := testContext2(t, &ContextOpts{
  6754  		Providers: map[addrs.Provider]providers.Factory{
  6755  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p1),
  6756  		},
  6757  	})
  6758  
  6759  	plan1, diags := ctx1.Plan(m1, states.NewState(), DefaultPlanOpts)
  6760  	assertNoErrors(t, diags)
  6761  
  6762  	state1, diags := ctx1.Apply(plan1, m1)
  6763  	if diags.HasErrors() {
  6764  		t.Fatalf("diags: %s", diags.Err())
  6765  	}
  6766  
  6767  	m2 := testModule(t, "apply-output-add-after")
  6768  	p2 := testProvider("aws")
  6769  	p2.ApplyResourceChangeFn = testApplyFn
  6770  	p2.PlanResourceChangeFn = testDiffFn
  6771  	ctx2 := testContext2(t, &ContextOpts{
  6772  		Providers: map[addrs.Provider]providers.Factory{
  6773  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p2),
  6774  		},
  6775  	})
  6776  
  6777  	plan2, diags := ctx1.Plan(m2, state1, DefaultPlanOpts)
  6778  	assertNoErrors(t, diags)
  6779  
  6780  	state2, diags := ctx2.Apply(plan2, m2)
  6781  	if diags.HasErrors() {
  6782  		t.Fatalf("diags: %s", diags.Err())
  6783  	}
  6784  
  6785  	actual := strings.TrimSpace(state2.String())
  6786  	expected := strings.TrimSpace(testTofuApplyOutputAddStr)
  6787  	if actual != expected {
  6788  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6789  	}
  6790  }
  6791  
  6792  func TestContext2Apply_outputList(t *testing.T) {
  6793  	m := testModule(t, "apply-output-list")
  6794  	p := testProvider("aws")
  6795  	p.PlanResourceChangeFn = testDiffFn
  6796  	p.ApplyResourceChangeFn = testApplyFn
  6797  	ctx := testContext2(t, &ContextOpts{
  6798  		Providers: map[addrs.Provider]providers.Factory{
  6799  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6800  		},
  6801  	})
  6802  
  6803  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6804  	assertNoErrors(t, diags)
  6805  
  6806  	state, diags := ctx.Apply(plan, m)
  6807  	if diags.HasErrors() {
  6808  		t.Fatalf("diags: %s", diags.Err())
  6809  	}
  6810  
  6811  	actual := strings.TrimSpace(state.String())
  6812  	expected := strings.TrimSpace(testTofuApplyOutputListStr)
  6813  	if actual != expected {
  6814  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  6815  	}
  6816  }
  6817  
  6818  func TestContext2Apply_outputMulti(t *testing.T) {
  6819  	m := testModule(t, "apply-output-multi")
  6820  	p := testProvider("aws")
  6821  	p.PlanResourceChangeFn = testDiffFn
  6822  	p.ApplyResourceChangeFn = testApplyFn
  6823  	ctx := testContext2(t, &ContextOpts{
  6824  		Providers: map[addrs.Provider]providers.Factory{
  6825  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6826  		},
  6827  	})
  6828  
  6829  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6830  	assertNoErrors(t, diags)
  6831  
  6832  	state, diags := ctx.Apply(plan, m)
  6833  	if diags.HasErrors() {
  6834  		t.Fatalf("diags: %s", diags.Err())
  6835  	}
  6836  
  6837  	actual := strings.TrimSpace(state.String())
  6838  	expected := strings.TrimSpace(testTofuApplyOutputMultiStr)
  6839  	if actual != expected {
  6840  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6841  	}
  6842  }
  6843  
  6844  func TestContext2Apply_outputMultiIndex(t *testing.T) {
  6845  	m := testModule(t, "apply-output-multi-index")
  6846  	p := testProvider("aws")
  6847  	p.PlanResourceChangeFn = testDiffFn
  6848  	p.ApplyResourceChangeFn = testApplyFn
  6849  	ctx := testContext2(t, &ContextOpts{
  6850  		Providers: map[addrs.Provider]providers.Factory{
  6851  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6852  		},
  6853  	})
  6854  
  6855  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6856  	assertNoErrors(t, diags)
  6857  
  6858  	state, diags := ctx.Apply(plan, m)
  6859  	if diags.HasErrors() {
  6860  		t.Fatalf("diags: %s", diags.Err())
  6861  	}
  6862  
  6863  	actual := strings.TrimSpace(state.String())
  6864  	expected := strings.TrimSpace(testTofuApplyOutputMultiIndexStr)
  6865  	if actual != expected {
  6866  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6867  	}
  6868  }
  6869  
  6870  func TestContext2Apply_taintX(t *testing.T) {
  6871  	m := testModule(t, "apply-taint")
  6872  	p := testProvider("aws")
  6873  	// destroyCount tests against regression of
  6874  	// https://github.com/hashicorp/terraform/issues/1056
  6875  	var destroyCount = int32(0)
  6876  	var once sync.Once
  6877  	simulateProviderDelay := func() {
  6878  		time.Sleep(10 * time.Millisecond)
  6879  	}
  6880  
  6881  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6882  		once.Do(simulateProviderDelay)
  6883  		if req.PlannedState.IsNull() {
  6884  			atomic.AddInt32(&destroyCount, 1)
  6885  		}
  6886  		return testApplyFn(req)
  6887  	}
  6888  	p.PlanResourceChangeFn = testDiffFn
  6889  
  6890  	state := states.NewState()
  6891  	root := state.EnsureModule(addrs.RootModuleInstance)
  6892  	root.SetResourceInstanceCurrent(
  6893  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6894  		&states.ResourceInstanceObjectSrc{
  6895  			Status:    states.ObjectTainted,
  6896  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6897  		},
  6898  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  6899  	)
  6900  
  6901  	ctx := testContext2(t, &ContextOpts{
  6902  		Providers: map[addrs.Provider]providers.Factory{
  6903  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6904  		},
  6905  	})
  6906  
  6907  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6908  	if diags.HasErrors() {
  6909  		t.Fatalf("diags: %s", diags.Err())
  6910  	} else {
  6911  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6912  	}
  6913  
  6914  	s, diags := ctx.Apply(plan, m)
  6915  	if diags.HasErrors() {
  6916  		t.Fatalf("diags: %s", diags.Err())
  6917  	}
  6918  
  6919  	actual := strings.TrimSpace(s.String())
  6920  	expected := strings.TrimSpace(testTofuApplyTaintStr)
  6921  	if actual != expected {
  6922  		t.Fatalf("bad:\n%s", actual)
  6923  	}
  6924  
  6925  	if destroyCount != 1 {
  6926  		t.Fatalf("Expected 1 destroy, got %d", destroyCount)
  6927  	}
  6928  }
  6929  
  6930  func TestContext2Apply_taintDep(t *testing.T) {
  6931  	m := testModule(t, "apply-taint-dep")
  6932  	p := testProvider("aws")
  6933  	p.PlanResourceChangeFn = testDiffFn
  6934  	p.ApplyResourceChangeFn = testApplyFn
  6935  
  6936  	state := states.NewState()
  6937  	root := state.EnsureModule(addrs.RootModuleInstance)
  6938  	root.SetResourceInstanceCurrent(
  6939  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6940  		&states.ResourceInstanceObjectSrc{
  6941  			Status:    states.ObjectTainted,
  6942  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6943  		},
  6944  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  6945  	)
  6946  	root.SetResourceInstanceCurrent(
  6947  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6948  		&states.ResourceInstanceObjectSrc{
  6949  			Status:       states.ObjectReady,
  6950  			AttrsJSON:    []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`),
  6951  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  6952  		},
  6953  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  6954  	)
  6955  
  6956  	ctx := testContext2(t, &ContextOpts{
  6957  		Providers: map[addrs.Provider]providers.Factory{
  6958  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6959  		},
  6960  	})
  6961  
  6962  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6963  	if diags.HasErrors() {
  6964  		t.Fatalf("diags: %s", diags.Err())
  6965  	} else {
  6966  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6967  	}
  6968  
  6969  	s, diags := ctx.Apply(plan, m)
  6970  	if diags.HasErrors() {
  6971  		t.Fatalf("diags: %s", diags.Err())
  6972  	}
  6973  
  6974  	actual := strings.TrimSpace(s.String())
  6975  	expected := strings.TrimSpace(testTofuApplyTaintDepStr)
  6976  	if actual != expected {
  6977  		t.Fatalf("bad:\n%s", actual)
  6978  	}
  6979  }
  6980  
  6981  func TestContext2Apply_taintDepRequiresNew(t *testing.T) {
  6982  	m := testModule(t, "apply-taint-dep-requires-new")
  6983  	p := testProvider("aws")
  6984  	p.PlanResourceChangeFn = testDiffFn
  6985  	p.ApplyResourceChangeFn = testApplyFn
  6986  
  6987  	state := states.NewState()
  6988  	root := state.EnsureModule(addrs.RootModuleInstance)
  6989  	root.SetResourceInstanceCurrent(
  6990  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6991  		&states.ResourceInstanceObjectSrc{
  6992  			Status:    states.ObjectTainted,
  6993  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6994  		},
  6995  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  6996  	)
  6997  	root.SetResourceInstanceCurrent(
  6998  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6999  		&states.ResourceInstanceObjectSrc{
  7000  			Status:       states.ObjectReady,
  7001  			AttrsJSON:    []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`),
  7002  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  7003  		},
  7004  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7005  	)
  7006  
  7007  	ctx := testContext2(t, &ContextOpts{
  7008  		Providers: map[addrs.Provider]providers.Factory{
  7009  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7010  		},
  7011  	})
  7012  
  7013  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  7014  	if diags.HasErrors() {
  7015  		t.Fatalf("diags: %s", diags.Err())
  7016  	} else {
  7017  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  7018  	}
  7019  
  7020  	s, diags := ctx.Apply(plan, m)
  7021  	if diags.HasErrors() {
  7022  		t.Fatalf("diags: %s", diags.Err())
  7023  	}
  7024  
  7025  	actual := strings.TrimSpace(s.String())
  7026  	expected := strings.TrimSpace(testTofuApplyTaintDepRequireNewStr)
  7027  	if actual != expected {
  7028  		t.Fatalf("bad:\n%s", actual)
  7029  	}
  7030  }
  7031  
  7032  func TestContext2Apply_targeted(t *testing.T) {
  7033  	m := testModule(t, "apply-targeted")
  7034  	p := testProvider("aws")
  7035  	p.PlanResourceChangeFn = testDiffFn
  7036  	p.ApplyResourceChangeFn = testApplyFn
  7037  	ctx := testContext2(t, &ContextOpts{
  7038  		Providers: map[addrs.Provider]providers.Factory{
  7039  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7040  		},
  7041  	})
  7042  
  7043  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7044  		Mode: plans.NormalMode,
  7045  		Targets: []addrs.Targetable{
  7046  			addrs.RootModuleInstance.Resource(
  7047  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7048  			),
  7049  		},
  7050  	})
  7051  	assertNoErrors(t, diags)
  7052  
  7053  	state, diags := ctx.Apply(plan, m)
  7054  	if diags.HasErrors() {
  7055  		t.Fatalf("diags: %s", diags.Err())
  7056  	}
  7057  
  7058  	mod := state.RootModule()
  7059  	if len(mod.Resources) != 1 {
  7060  		t.Fatalf("expected 1 resource, got: %#v", mod.Resources)
  7061  	}
  7062  
  7063  	checkStateString(t, state, `
  7064  aws_instance.foo:
  7065    ID = foo
  7066    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7067    num = 2
  7068    type = aws_instance
  7069  	`)
  7070  }
  7071  
  7072  func TestContext2Apply_targetedCount(t *testing.T) {
  7073  	m := testModule(t, "apply-targeted-count")
  7074  	p := testProvider("aws")
  7075  	p.PlanResourceChangeFn = testDiffFn
  7076  	p.ApplyResourceChangeFn = testApplyFn
  7077  	ctx := testContext2(t, &ContextOpts{
  7078  		Providers: map[addrs.Provider]providers.Factory{
  7079  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7080  		},
  7081  	})
  7082  
  7083  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7084  		Mode: plans.NormalMode,
  7085  		Targets: []addrs.Targetable{
  7086  			addrs.RootModuleInstance.Resource(
  7087  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7088  			),
  7089  		},
  7090  	})
  7091  	assertNoErrors(t, diags)
  7092  
  7093  	state, diags := ctx.Apply(plan, m)
  7094  	if diags.HasErrors() {
  7095  		t.Fatalf("diags: %s", diags.Err())
  7096  	}
  7097  
  7098  	checkStateString(t, state, `
  7099  aws_instance.foo.0:
  7100    ID = foo
  7101    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7102    type = aws_instance
  7103  aws_instance.foo.1:
  7104    ID = foo
  7105    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7106    type = aws_instance
  7107  aws_instance.foo.2:
  7108    ID = foo
  7109    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7110    type = aws_instance
  7111  	`)
  7112  }
  7113  
  7114  func TestContext2Apply_targetedCountIndex(t *testing.T) {
  7115  	m := testModule(t, "apply-targeted-count")
  7116  	p := testProvider("aws")
  7117  	p.PlanResourceChangeFn = testDiffFn
  7118  	p.ApplyResourceChangeFn = testApplyFn
  7119  	ctx := testContext2(t, &ContextOpts{
  7120  		Providers: map[addrs.Provider]providers.Factory{
  7121  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7122  		},
  7123  	})
  7124  
  7125  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7126  		Mode: plans.NormalMode,
  7127  		Targets: []addrs.Targetable{
  7128  			addrs.RootModuleInstance.ResourceInstance(
  7129  				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(1),
  7130  			),
  7131  		},
  7132  	})
  7133  	assertNoErrors(t, diags)
  7134  
  7135  	state, diags := ctx.Apply(plan, m)
  7136  	if diags.HasErrors() {
  7137  		t.Fatalf("diags: %s", diags.Err())
  7138  	}
  7139  
  7140  	checkStateString(t, state, `
  7141  aws_instance.foo.1:
  7142    ID = foo
  7143    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7144    type = aws_instance
  7145  	`)
  7146  }
  7147  
  7148  func TestContext2Apply_targetedDestroy(t *testing.T) {
  7149  	m := testModule(t, "destroy-targeted")
  7150  	p := testProvider("aws")
  7151  	p.PlanResourceChangeFn = testDiffFn
  7152  
  7153  	state := states.NewState()
  7154  	root := state.EnsureModule(addrs.RootModuleInstance)
  7155  	root.SetResourceInstanceCurrent(
  7156  		mustResourceInstanceAddr("aws_instance.a").Resource,
  7157  		&states.ResourceInstanceObjectSrc{
  7158  			Status:    states.ObjectReady,
  7159  			AttrsJSON: []byte(`{"id":"bar"}`),
  7160  		},
  7161  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7162  	)
  7163  	root.SetOutputValue("out", cty.StringVal("bar"), false)
  7164  
  7165  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7166  	child.SetResourceInstanceCurrent(
  7167  		mustResourceInstanceAddr("aws_instance.b").Resource,
  7168  		&states.ResourceInstanceObjectSrc{
  7169  			Status:    states.ObjectReady,
  7170  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7171  		},
  7172  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7173  	)
  7174  
  7175  	ctx := testContext2(t, &ContextOpts{
  7176  		Providers: map[addrs.Provider]providers.Factory{
  7177  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7178  		},
  7179  	})
  7180  
  7181  	if diags := ctx.Validate(m); diags.HasErrors() {
  7182  		t.Fatalf("validate errors: %s", diags.Err())
  7183  	}
  7184  
  7185  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7186  		Mode: plans.DestroyMode,
  7187  		Targets: []addrs.Targetable{
  7188  			addrs.RootModuleInstance.Resource(
  7189  				addrs.ManagedResourceMode, "aws_instance", "a",
  7190  			),
  7191  		},
  7192  	})
  7193  	assertNoErrors(t, diags)
  7194  
  7195  	state, diags = ctx.Apply(plan, m)
  7196  	if diags.HasErrors() {
  7197  		t.Fatalf("diags: %s", diags.Err())
  7198  	}
  7199  
  7200  	mod := state.RootModule()
  7201  	if len(mod.Resources) != 0 {
  7202  		t.Fatalf("expected 0 resources, got: %#v", mod.Resources)
  7203  	}
  7204  
  7205  	// the root output should not get removed; only the targeted resource.
  7206  	//
  7207  	// Note: earlier versions of this test expected 0 outputs, but it turns out
  7208  	// that was because Validate - not apply or destroy - removed the output
  7209  	// (which depends on the targeted resource) from state. That version of this
  7210  	// test did not match actual tofu behavior: the output remains in
  7211  	// state.
  7212  	//
  7213  	// The reason it remains in the state is that we prune out the root module
  7214  	// output values from the destroy graph as part of pruning out the "update"
  7215  	// nodes for the resources, because otherwise the root module output values
  7216  	// force the resources to stay in the graph and can therefore cause
  7217  	// unwanted dependency cycles.
  7218  	//
  7219  	// TODO: Future refactoring may enable us to remove the output from state in
  7220  	// this case, and that would be Just Fine - this test can be modified to
  7221  	// expect 0 outputs.
  7222  	if len(mod.OutputValues) != 1 {
  7223  		t.Fatalf("expected 1 outputs, got: %#v", mod.OutputValues)
  7224  	}
  7225  
  7226  	// the module instance should remain
  7227  	mod = state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7228  	if len(mod.Resources) != 1 {
  7229  		t.Fatalf("expected 1 resources, got: %#v", mod.Resources)
  7230  	}
  7231  }
  7232  
  7233  func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) {
  7234  	m := testModule(t, "apply-destroy-targeted-count")
  7235  	p := testProvider("aws")
  7236  	p.PlanResourceChangeFn = testDiffFn
  7237  
  7238  	state := states.NewState()
  7239  	root := state.EnsureModule(addrs.RootModuleInstance)
  7240  	root.SetResourceInstanceCurrent(
  7241  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7242  		&states.ResourceInstanceObjectSrc{
  7243  			Status:    states.ObjectReady,
  7244  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7245  		},
  7246  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7247  	)
  7248  	root.SetResourceInstanceCurrent(
  7249  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7250  		&states.ResourceInstanceObjectSrc{
  7251  			Status:       states.ObjectReady,
  7252  			AttrsJSON:    []byte(`{"id":"i-abc123"}`),
  7253  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  7254  		},
  7255  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7256  	)
  7257  
  7258  	ctx := testContext2(t, &ContextOpts{
  7259  		Providers: map[addrs.Provider]providers.Factory{
  7260  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7261  		},
  7262  	})
  7263  
  7264  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7265  		Mode: plans.DestroyMode,
  7266  		Targets: []addrs.Targetable{
  7267  			addrs.RootModuleInstance.Resource(
  7268  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7269  			),
  7270  		},
  7271  	})
  7272  	assertNoErrors(t, diags)
  7273  
  7274  	state, diags = ctx.Apply(plan, m)
  7275  	if diags.HasErrors() {
  7276  		t.Fatalf("diags: %s", diags.Err())
  7277  	}
  7278  
  7279  	checkStateString(t, state, `<no state>`)
  7280  }
  7281  
  7282  // https://github.com/hashicorp/terraform/issues/4462
  7283  func TestContext2Apply_targetedDestroyModule(t *testing.T) {
  7284  	m := testModule(t, "apply-targeted-module")
  7285  	p := testProvider("aws")
  7286  	p.PlanResourceChangeFn = testDiffFn
  7287  
  7288  	state := states.NewState()
  7289  	root := state.EnsureModule(addrs.RootModuleInstance)
  7290  	root.SetResourceInstanceCurrent(
  7291  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7292  		&states.ResourceInstanceObjectSrc{
  7293  			Status:    states.ObjectReady,
  7294  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7295  		},
  7296  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7297  	)
  7298  	root.SetResourceInstanceCurrent(
  7299  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7300  		&states.ResourceInstanceObjectSrc{
  7301  			Status:    states.ObjectReady,
  7302  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7303  		},
  7304  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7305  	)
  7306  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7307  	child.SetResourceInstanceCurrent(
  7308  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7309  		&states.ResourceInstanceObjectSrc{
  7310  			Status:    states.ObjectReady,
  7311  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7312  		},
  7313  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7314  	)
  7315  	child.SetResourceInstanceCurrent(
  7316  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7317  		&states.ResourceInstanceObjectSrc{
  7318  			Status:    states.ObjectReady,
  7319  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7320  		},
  7321  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7322  	)
  7323  
  7324  	ctx := testContext2(t, &ContextOpts{
  7325  		Providers: map[addrs.Provider]providers.Factory{
  7326  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7327  		},
  7328  	})
  7329  
  7330  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7331  		Mode: plans.DestroyMode,
  7332  		Targets: []addrs.Targetable{
  7333  			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
  7334  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7335  			),
  7336  		},
  7337  	})
  7338  	assertNoErrors(t, diags)
  7339  
  7340  	state, diags = ctx.Apply(plan, m)
  7341  	if diags.HasErrors() {
  7342  		t.Fatalf("diags: %s", diags.Err())
  7343  	}
  7344  
  7345  	checkStateString(t, state, `
  7346  aws_instance.bar:
  7347    ID = i-abc123
  7348    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7349  aws_instance.foo:
  7350    ID = i-bcd345
  7351    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7352  
  7353  module.child:
  7354    aws_instance.bar:
  7355      ID = i-abc123
  7356      provider = provider["registry.opentofu.org/hashicorp/aws"]
  7357  	`)
  7358  }
  7359  
  7360  func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) {
  7361  	m := testModule(t, "apply-targeted-count")
  7362  	p := testProvider("aws")
  7363  	p.PlanResourceChangeFn = testDiffFn
  7364  
  7365  	foo := &states.ResourceInstanceObjectSrc{
  7366  		Status:    states.ObjectReady,
  7367  		AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7368  	}
  7369  	bar := &states.ResourceInstanceObjectSrc{
  7370  		Status:    states.ObjectReady,
  7371  		AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7372  	}
  7373  
  7374  	state := states.NewState()
  7375  	root := state.EnsureModule(addrs.RootModuleInstance)
  7376  	root.SetResourceInstanceCurrent(
  7377  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  7378  		foo,
  7379  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7380  	)
  7381  	root.SetResourceInstanceCurrent(
  7382  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  7383  		foo,
  7384  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7385  	)
  7386  	root.SetResourceInstanceCurrent(
  7387  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  7388  		foo,
  7389  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7390  	)
  7391  	root.SetResourceInstanceCurrent(
  7392  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  7393  		bar,
  7394  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7395  	)
  7396  	root.SetResourceInstanceCurrent(
  7397  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  7398  		bar,
  7399  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7400  	)
  7401  	root.SetResourceInstanceCurrent(
  7402  		mustResourceInstanceAddr("aws_instance.bar[2]").Resource,
  7403  		bar,
  7404  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7405  	)
  7406  
  7407  	ctx := testContext2(t, &ContextOpts{
  7408  		Providers: map[addrs.Provider]providers.Factory{
  7409  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7410  		},
  7411  	})
  7412  
  7413  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7414  		Mode: plans.DestroyMode,
  7415  		Targets: []addrs.Targetable{
  7416  			addrs.RootModuleInstance.ResourceInstance(
  7417  				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(2),
  7418  			),
  7419  			addrs.RootModuleInstance.ResourceInstance(
  7420  				addrs.ManagedResourceMode, "aws_instance", "bar", addrs.IntKey(1),
  7421  			),
  7422  		},
  7423  	})
  7424  	assertNoErrors(t, diags)
  7425  
  7426  	state, diags = ctx.Apply(plan, m)
  7427  	if diags.HasErrors() {
  7428  		t.Fatalf("diags: %s", diags.Err())
  7429  	}
  7430  
  7431  	checkStateString(t, state, `
  7432  aws_instance.bar.0:
  7433    ID = i-abc123
  7434    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7435  aws_instance.bar.2:
  7436    ID = i-abc123
  7437    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7438  aws_instance.foo.0:
  7439    ID = i-bcd345
  7440    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7441  aws_instance.foo.1:
  7442    ID = i-bcd345
  7443    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7444  	`)
  7445  }
  7446  
  7447  func TestContext2Apply_targetedModule(t *testing.T) {
  7448  	m := testModule(t, "apply-targeted-module")
  7449  	p := testProvider("aws")
  7450  	p.PlanResourceChangeFn = testDiffFn
  7451  	p.ApplyResourceChangeFn = testApplyFn
  7452  	ctx := testContext2(t, &ContextOpts{
  7453  		Providers: map[addrs.Provider]providers.Factory{
  7454  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7455  		},
  7456  	})
  7457  
  7458  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7459  		Mode: plans.NormalMode,
  7460  		Targets: []addrs.Targetable{
  7461  			addrs.RootModuleInstance.Child("child", addrs.NoKey),
  7462  		},
  7463  	})
  7464  	assertNoErrors(t, diags)
  7465  
  7466  	state, diags := ctx.Apply(plan, m)
  7467  	if diags.HasErrors() {
  7468  		t.Fatalf("diags: %s", diags.Err())
  7469  	}
  7470  
  7471  	mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7472  	if mod == nil {
  7473  		t.Fatalf("no child module found in the state!\n\n%#v", state)
  7474  	}
  7475  	if len(mod.Resources) != 2 {
  7476  		t.Fatalf("expected 2 resources, got: %#v", mod.Resources)
  7477  	}
  7478  
  7479  	checkStateString(t, state, `
  7480  <no state>
  7481  module.child:
  7482    aws_instance.bar:
  7483      ID = foo
  7484      provider = provider["registry.opentofu.org/hashicorp/aws"]
  7485      num = 2
  7486      type = aws_instance
  7487    aws_instance.foo:
  7488      ID = foo
  7489      provider = provider["registry.opentofu.org/hashicorp/aws"]
  7490      num = 2
  7491      type = aws_instance
  7492  	`)
  7493  }
  7494  
  7495  // GH-1858
  7496  func TestContext2Apply_targetedModuleDep(t *testing.T) {
  7497  	m := testModule(t, "apply-targeted-module-dep")
  7498  	p := testProvider("aws")
  7499  	p.PlanResourceChangeFn = testDiffFn
  7500  	p.ApplyResourceChangeFn = testApplyFn
  7501  	ctx := testContext2(t, &ContextOpts{
  7502  		Providers: map[addrs.Provider]providers.Factory{
  7503  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7504  		},
  7505  	})
  7506  
  7507  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7508  		Mode: plans.NormalMode,
  7509  		Targets: []addrs.Targetable{
  7510  			addrs.RootModuleInstance.Resource(
  7511  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7512  			),
  7513  		},
  7514  	})
  7515  	if diags.HasErrors() {
  7516  		t.Fatalf("diags: %s", diags.Err())
  7517  	} else {
  7518  		t.Logf("Diff: %s", legacyDiffComparisonString(plan.Changes))
  7519  	}
  7520  
  7521  	state, diags := ctx.Apply(plan, m)
  7522  	if diags.HasErrors() {
  7523  		t.Fatalf("diags: %s", diags.Err())
  7524  	}
  7525  
  7526  	checkStateString(t, state, `
  7527  aws_instance.foo:
  7528    ID = foo
  7529    provider = provider["registry.opentofu.org/hashicorp/aws"]
  7530    foo = foo
  7531    type = aws_instance
  7532  
  7533    Dependencies:
  7534      module.child.aws_instance.mod
  7535  
  7536  module.child:
  7537    aws_instance.mod:
  7538      ID = foo
  7539      provider = provider["registry.opentofu.org/hashicorp/aws"]
  7540      type = aws_instance
  7541  
  7542    Outputs:
  7543  
  7544    output = foo
  7545  	`)
  7546  }
  7547  
  7548  // GH-10911 untargeted outputs should not be in the graph, and therefore
  7549  // not execute.
  7550  func TestContext2Apply_targetedModuleUnrelatedOutputs(t *testing.T) {
  7551  	m := testModule(t, "apply-targeted-module-unrelated-outputs")
  7552  	p := testProvider("aws")
  7553  	p.PlanResourceChangeFn = testDiffFn
  7554  	p.ApplyResourceChangeFn = testApplyFn
  7555  
  7556  	state := states.NewState()
  7557  	_ = state.EnsureModule(addrs.RootModuleInstance.Child("child2", addrs.NoKey))
  7558  
  7559  	ctx := testContext2(t, &ContextOpts{
  7560  		Providers: map[addrs.Provider]providers.Factory{
  7561  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7562  		},
  7563  	})
  7564  
  7565  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7566  		Mode: plans.NormalMode,
  7567  		Targets: []addrs.Targetable{
  7568  			addrs.RootModuleInstance.Child("child2", addrs.NoKey),
  7569  		},
  7570  	})
  7571  	assertNoErrors(t, diags)
  7572  
  7573  	s, diags := ctx.Apply(plan, m)
  7574  	if diags.HasErrors() {
  7575  		t.Fatalf("diags: %s", diags.Err())
  7576  	}
  7577  
  7578  	// - module.child1's instance_id output is dropped because we don't preserve
  7579  	//   non-root module outputs between runs (they can be recalculated from config)
  7580  	// - module.child2's instance_id is updated because its dependency is updated
  7581  	// - child2_id is updated because if its transitive dependency via module.child2
  7582  	checkStateString(t, s, `
  7583  <no state>
  7584  Outputs:
  7585  
  7586  child2_id = foo
  7587  
  7588  module.child2:
  7589    aws_instance.foo:
  7590      ID = foo
  7591      provider = provider["registry.opentofu.org/hashicorp/aws"]
  7592      type = aws_instance
  7593  
  7594    Outputs:
  7595  
  7596    instance_id = foo
  7597  `)
  7598  }
  7599  
  7600  func TestContext2Apply_targetedModuleResource(t *testing.T) {
  7601  	m := testModule(t, "apply-targeted-module-resource")
  7602  	p := testProvider("aws")
  7603  	p.PlanResourceChangeFn = testDiffFn
  7604  	p.ApplyResourceChangeFn = testApplyFn
  7605  	ctx := testContext2(t, &ContextOpts{
  7606  		Providers: map[addrs.Provider]providers.Factory{
  7607  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7608  		},
  7609  	})
  7610  
  7611  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7612  		Mode: plans.NormalMode,
  7613  		Targets: []addrs.Targetable{
  7614  			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
  7615  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7616  			),
  7617  		},
  7618  	})
  7619  	assertNoErrors(t, diags)
  7620  
  7621  	state, diags := ctx.Apply(plan, m)
  7622  	if diags.HasErrors() {
  7623  		t.Fatalf("diags: %s", diags.Err())
  7624  	}
  7625  
  7626  	mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7627  	if mod == nil || len(mod.Resources) != 1 {
  7628  		t.Fatalf("expected 1 resource, got: %#v", mod)
  7629  	}
  7630  
  7631  	checkStateString(t, state, `
  7632  <no state>
  7633  module.child:
  7634    aws_instance.foo:
  7635      ID = foo
  7636      provider = provider["registry.opentofu.org/hashicorp/aws"]
  7637      num = 2
  7638      type = aws_instance
  7639  	`)
  7640  }
  7641  
  7642  func TestContext2Apply_targetedResourceOrphanModule(t *testing.T) {
  7643  	m := testModule(t, "apply-targeted-resource-orphan-module")
  7644  	p := testProvider("aws")
  7645  	p.PlanResourceChangeFn = testDiffFn
  7646  
  7647  	state := states.NewState()
  7648  	child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey))
  7649  	child.SetResourceInstanceCurrent(
  7650  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7651  		&states.ResourceInstanceObjectSrc{
  7652  			Status:    states.ObjectReady,
  7653  			AttrsJSON: []byte(`{"type":"aws_instance"}`),
  7654  		},
  7655  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  7656  	)
  7657  
  7658  	ctx := testContext2(t, &ContextOpts{
  7659  		Providers: map[addrs.Provider]providers.Factory{
  7660  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7661  		},
  7662  	})
  7663  
  7664  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7665  		Mode: plans.NormalMode,
  7666  		Targets: []addrs.Targetable{
  7667  			addrs.RootModuleInstance.Resource(
  7668  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7669  			),
  7670  		},
  7671  	})
  7672  	assertNoErrors(t, diags)
  7673  
  7674  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  7675  		t.Fatalf("apply errors: %s", diags.Err())
  7676  	}
  7677  }
  7678  
  7679  func TestContext2Apply_unknownAttribute(t *testing.T) {
  7680  	m := testModule(t, "apply-unknown")
  7681  	p := testProvider("aws")
  7682  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  7683  		resp = testDiffFn(req)
  7684  		planned := resp.PlannedState.AsValueMap()
  7685  		planned["unknown"] = cty.UnknownVal(cty.String)
  7686  		resp.PlannedState = cty.ObjectVal(planned)
  7687  		return resp
  7688  	}
  7689  	p.ApplyResourceChangeFn = testApplyFn
  7690  
  7691  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  7692  		ResourceTypes: map[string]*configschema.Block{
  7693  			"aws_instance": {
  7694  				Attributes: map[string]*configschema.Attribute{
  7695  					"id":      {Type: cty.String, Computed: true},
  7696  					"num":     {Type: cty.Number, Optional: true},
  7697  					"unknown": {Type: cty.String, Computed: true},
  7698  					"type":    {Type: cty.String, Computed: true},
  7699  				},
  7700  			},
  7701  		},
  7702  	})
  7703  
  7704  	ctx := testContext2(t, &ContextOpts{
  7705  		Providers: map[addrs.Provider]providers.Factory{
  7706  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7707  		},
  7708  	})
  7709  
  7710  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  7711  	assertNoErrors(t, diags)
  7712  
  7713  	state, diags := ctx.Apply(plan, m)
  7714  	if !diags.HasErrors() {
  7715  		t.Error("should error, because attribute 'unknown' is still unknown after apply")
  7716  	}
  7717  
  7718  	actual := strings.TrimSpace(state.String())
  7719  	expected := strings.TrimSpace(testTofuApplyUnknownAttrStr)
  7720  	if actual != expected {
  7721  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  7722  	}
  7723  }
  7724  
  7725  func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) {
  7726  	m := testModule(t, "apply-unknown-interpolate")
  7727  	p := testProvider("aws")
  7728  	p.PlanResourceChangeFn = testDiffFn
  7729  	ctx := testContext2(t, &ContextOpts{
  7730  		Providers: map[addrs.Provider]providers.Factory{
  7731  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7732  		},
  7733  	})
  7734  
  7735  	if _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts); diags == nil {
  7736  		t.Fatal("should error")
  7737  	}
  7738  }
  7739  
  7740  func TestContext2Apply_vars(t *testing.T) {
  7741  	fixture := contextFixtureApplyVars(t)
  7742  	opts := fixture.ContextOpts()
  7743  	ctx := testContext2(t, opts)
  7744  	m := fixture.Config
  7745  
  7746  	diags := ctx.Validate(m)
  7747  	if len(diags) != 0 {
  7748  		t.Fatalf("bad: %s", diags.ErrWithWarnings())
  7749  	}
  7750  
  7751  	variables := InputValues{
  7752  		"foo": &InputValue{
  7753  			Value:      cty.StringVal("us-east-1"),
  7754  			SourceType: ValueFromCaller,
  7755  		},
  7756  		"bar": &InputValue{
  7757  			// This one is not explicitly set but that's okay because it
  7758  			// has a declared default, which OpenTofu Core will use instead.
  7759  			Value:      cty.NilVal,
  7760  			SourceType: ValueFromCaller,
  7761  		},
  7762  		"test_list": &InputValue{
  7763  			Value: cty.ListVal([]cty.Value{
  7764  				cty.StringVal("Hello"),
  7765  				cty.StringVal("World"),
  7766  			}),
  7767  			SourceType: ValueFromCaller,
  7768  		},
  7769  		"test_map": &InputValue{
  7770  			Value: cty.MapVal(map[string]cty.Value{
  7771  				"Hello": cty.StringVal("World"),
  7772  				"Foo":   cty.StringVal("Bar"),
  7773  				"Baz":   cty.StringVal("Foo"),
  7774  			}),
  7775  			SourceType: ValueFromCaller,
  7776  		},
  7777  		"amis": &InputValue{
  7778  			Value: cty.MapVal(map[string]cty.Value{
  7779  				"us-east-1": cty.StringVal("override"),
  7780  			}),
  7781  			SourceType: ValueFromCaller,
  7782  		},
  7783  	}
  7784  
  7785  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7786  		Mode:         plans.NormalMode,
  7787  		SetVariables: variables,
  7788  	})
  7789  	assertNoErrors(t, diags)
  7790  
  7791  	state, diags := ctx.Apply(plan, m)
  7792  	if diags.HasErrors() {
  7793  		t.Fatalf("err: %s", diags.Err())
  7794  	}
  7795  
  7796  	got := strings.TrimSpace(state.String())
  7797  	want := strings.TrimSpace(testTofuApplyVarsStr)
  7798  	if got != want {
  7799  		t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want)
  7800  	}
  7801  }
  7802  
  7803  func TestContext2Apply_varsEnv(t *testing.T) {
  7804  	fixture := contextFixtureApplyVarsEnv(t)
  7805  	opts := fixture.ContextOpts()
  7806  	ctx := testContext2(t, opts)
  7807  	m := fixture.Config
  7808  
  7809  	diags := ctx.Validate(m)
  7810  	if len(diags) != 0 {
  7811  		t.Fatalf("bad: %s", diags.ErrWithWarnings())
  7812  	}
  7813  
  7814  	variables := InputValues{
  7815  		"string": &InputValue{
  7816  			Value:      cty.StringVal("baz"),
  7817  			SourceType: ValueFromEnvVar,
  7818  		},
  7819  		"list": &InputValue{
  7820  			Value: cty.ListVal([]cty.Value{
  7821  				cty.StringVal("Hello"),
  7822  				cty.StringVal("World"),
  7823  			}),
  7824  			SourceType: ValueFromEnvVar,
  7825  		},
  7826  		"map": &InputValue{
  7827  			Value: cty.MapVal(map[string]cty.Value{
  7828  				"Hello": cty.StringVal("World"),
  7829  				"Foo":   cty.StringVal("Bar"),
  7830  				"Baz":   cty.StringVal("Foo"),
  7831  			}),
  7832  			SourceType: ValueFromEnvVar,
  7833  		},
  7834  	}
  7835  
  7836  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7837  		Mode:         plans.NormalMode,
  7838  		SetVariables: variables,
  7839  	})
  7840  	assertNoErrors(t, diags)
  7841  
  7842  	state, diags := ctx.Apply(plan, m)
  7843  	if diags.HasErrors() {
  7844  		t.Fatalf("err: %s", diags.Err())
  7845  	}
  7846  
  7847  	actual := strings.TrimSpace(state.String())
  7848  	expected := strings.TrimSpace(testTofuApplyVarsEnvStr)
  7849  	if actual != expected {
  7850  		t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  7851  	}
  7852  }
  7853  
  7854  func TestContext2Apply_createBefore_depends(t *testing.T) {
  7855  	m := testModule(t, "apply-depends-create-before")
  7856  	h := new(HookRecordApplyOrder)
  7857  	p := testProvider("aws")
  7858  	p.PlanResourceChangeFn = testDiffFn
  7859  	p.ApplyResourceChangeFn = testApplyFn
  7860  	state := states.NewState()
  7861  	root := state.EnsureModule(addrs.RootModuleInstance)
  7862  	root.SetResourceInstanceCurrent(
  7863  		addrs.Resource{
  7864  			Mode: addrs.ManagedResourceMode,
  7865  			Type: "aws_instance",
  7866  			Name: "web",
  7867  		}.Instance(addrs.NoKey),
  7868  		&states.ResourceInstanceObjectSrc{
  7869  			Status:    states.ObjectReady,
  7870  			AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`),
  7871  		},
  7872  		addrs.AbsProviderConfig{
  7873  			Provider: addrs.NewDefaultProvider("aws"),
  7874  			Module:   addrs.RootModule,
  7875  		},
  7876  	)
  7877  
  7878  	root.SetResourceInstanceCurrent(
  7879  		addrs.Resource{
  7880  			Mode: addrs.ManagedResourceMode,
  7881  			Type: "aws_instance",
  7882  			Name: "lb",
  7883  		}.Instance(addrs.NoKey),
  7884  		&states.ResourceInstanceObjectSrc{
  7885  			Status:    states.ObjectReady,
  7886  			AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`),
  7887  			Dependencies: []addrs.ConfigResource{
  7888  				{
  7889  					Resource: addrs.Resource{
  7890  						Mode: addrs.ManagedResourceMode,
  7891  						Type: "aws_instance",
  7892  						Name: "web",
  7893  					},
  7894  					Module: addrs.RootModule,
  7895  				},
  7896  			},
  7897  		},
  7898  		addrs.AbsProviderConfig{
  7899  			Provider: addrs.NewDefaultProvider("aws"),
  7900  			Module:   addrs.RootModule,
  7901  		},
  7902  	)
  7903  
  7904  	ctx := testContext2(t, &ContextOpts{
  7905  		Hooks: []Hook{h},
  7906  		Providers: map[addrs.Provider]providers.Factory{
  7907  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7908  		},
  7909  	})
  7910  
  7911  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  7912  	if diags.HasErrors() {
  7913  		logDiagnostics(t, diags)
  7914  		t.Fatal("plan failed")
  7915  	} else {
  7916  		t.Logf("plan:\n%s", legacyDiffComparisonString(plan.Changes))
  7917  	}
  7918  
  7919  	h.Active = true
  7920  	state, diags = ctx.Apply(plan, m)
  7921  	if diags.HasErrors() {
  7922  		logDiagnostics(t, diags)
  7923  		t.Fatal("apply failed")
  7924  	}
  7925  
  7926  	mod := state.RootModule()
  7927  	if len(mod.Resources) < 2 {
  7928  		t.Logf("state after apply:\n%s", state.String())
  7929  		t.Fatalf("only %d resources in root module; want at least 2", len(mod.Resources))
  7930  	}
  7931  
  7932  	got := strings.TrimSpace(state.String())
  7933  	want := strings.TrimSpace(testTofuApplyDependsCreateBeforeStr)
  7934  	if got != want {
  7935  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", got, want)
  7936  	}
  7937  
  7938  	// Test that things were managed _in the right order_
  7939  	order := h.States
  7940  
  7941  	diffs := h.Diffs
  7942  	if !order[0].IsNull() || diffs[0].Action == plans.Delete {
  7943  		t.Fatalf("should create new instance first: %#v", order)
  7944  	}
  7945  
  7946  	if order[1].GetAttr("id").AsString() != "baz" {
  7947  		t.Fatalf("update must happen after create: %#v", order[1])
  7948  	}
  7949  
  7950  	if order[2].GetAttr("id").AsString() != "bar" || diffs[2].Action != plans.Delete {
  7951  		t.Fatalf("destroy must happen after update: %#v", order[2])
  7952  	}
  7953  }
  7954  
  7955  func TestContext2Apply_singleDestroy(t *testing.T) {
  7956  	m := testModule(t, "apply-depends-create-before")
  7957  	h := new(HookRecordApplyOrder)
  7958  	p := testProvider("aws")
  7959  	invokeCount := 0
  7960  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  7961  		invokeCount++
  7962  		switch invokeCount {
  7963  		case 1:
  7964  			if req.PlannedState.IsNull() {
  7965  				t.Fatalf("should not destroy")
  7966  			}
  7967  			if id := req.PlannedState.GetAttr("id"); id.IsKnown() {
  7968  				t.Fatalf("should not have ID")
  7969  			}
  7970  		case 2:
  7971  			if req.PlannedState.IsNull() {
  7972  				t.Fatalf("should not destroy")
  7973  			}
  7974  			if id := req.PlannedState.GetAttr("id"); id.AsString() != "baz" {
  7975  				t.Fatalf("should have id")
  7976  			}
  7977  		case 3:
  7978  			if !req.PlannedState.IsNull() {
  7979  				t.Fatalf("should destroy")
  7980  			}
  7981  		default:
  7982  			t.Fatalf("bad invoke count %d", invokeCount)
  7983  		}
  7984  		return testApplyFn(req)
  7985  	}
  7986  
  7987  	p.PlanResourceChangeFn = testDiffFn
  7988  	state := states.NewState()
  7989  	root := state.EnsureModule(addrs.RootModuleInstance)
  7990  	root.SetResourceInstanceCurrent(
  7991  		addrs.Resource{
  7992  			Mode: addrs.ManagedResourceMode,
  7993  			Type: "aws_instance",
  7994  			Name: "web",
  7995  		}.Instance(addrs.NoKey),
  7996  		&states.ResourceInstanceObjectSrc{
  7997  			Status:    states.ObjectReady,
  7998  			AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`),
  7999  		},
  8000  		addrs.AbsProviderConfig{
  8001  			Provider: addrs.NewDefaultProvider("aws"),
  8002  			Module:   addrs.RootModule,
  8003  		},
  8004  	)
  8005  
  8006  	root.SetResourceInstanceCurrent(
  8007  		addrs.Resource{
  8008  			Mode: addrs.ManagedResourceMode,
  8009  			Type: "aws_instance",
  8010  			Name: "lb",
  8011  		}.Instance(addrs.NoKey),
  8012  		&states.ResourceInstanceObjectSrc{
  8013  			Status:    states.ObjectReady,
  8014  			AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`),
  8015  			Dependencies: []addrs.ConfigResource{
  8016  				{
  8017  					Resource: addrs.Resource{
  8018  						Mode: addrs.ManagedResourceMode,
  8019  						Type: "aws_instance",
  8020  						Name: "web",
  8021  					},
  8022  					Module: addrs.RootModule,
  8023  				},
  8024  			},
  8025  		},
  8026  		addrs.AbsProviderConfig{
  8027  			Provider: addrs.NewDefaultProvider("aws"),
  8028  			Module:   addrs.RootModule,
  8029  		},
  8030  	)
  8031  
  8032  	ctx := testContext2(t, &ContextOpts{
  8033  		Hooks: []Hook{h},
  8034  		Providers: map[addrs.Provider]providers.Factory{
  8035  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8036  		},
  8037  	})
  8038  
  8039  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  8040  	assertNoErrors(t, diags)
  8041  
  8042  	h.Active = true
  8043  	_, diags = ctx.Apply(plan, m)
  8044  	if diags.HasErrors() {
  8045  		t.Fatalf("diags: %s", diags.Err())
  8046  	}
  8047  
  8048  	if invokeCount != 3 {
  8049  		t.Fatalf("bad: %d", invokeCount)
  8050  	}
  8051  }
  8052  
  8053  // GH-7824
  8054  func TestContext2Apply_issue7824(t *testing.T) {
  8055  	p := testProvider("template")
  8056  	p.PlanResourceChangeFn = testDiffFn
  8057  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  8058  		ResourceTypes: map[string]*configschema.Block{
  8059  			"template_file": {
  8060  				Attributes: map[string]*configschema.Attribute{
  8061  					"template":                {Type: cty.String, Optional: true},
  8062  					"__template_requires_new": {Type: cty.Bool, Optional: true},
  8063  				},
  8064  			},
  8065  		},
  8066  	})
  8067  
  8068  	m, snap := testModuleWithSnapshot(t, "issue-7824")
  8069  
  8070  	// Apply cleanly step 0
  8071  	ctx := testContext2(t, &ContextOpts{
  8072  		Providers: map[addrs.Provider]providers.Factory{
  8073  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  8074  		},
  8075  	})
  8076  
  8077  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  8078  	if diags.HasErrors() {
  8079  		t.Fatalf("err: %s", diags.Err())
  8080  	}
  8081  
  8082  	// Write / Read plan to simulate running it through a Plan file
  8083  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  8084  	if err != nil {
  8085  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8086  	}
  8087  
  8088  	ctxOpts.Providers =
  8089  		map[addrs.Provider]providers.Factory{
  8090  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  8091  		}
  8092  
  8093  	ctx, diags = NewContext(ctxOpts)
  8094  	if diags.HasErrors() {
  8095  		t.Fatalf("err: %s", diags.Err())
  8096  	}
  8097  
  8098  	_, diags = ctx.Apply(plan, m)
  8099  	if diags.HasErrors() {
  8100  		t.Fatalf("err: %s", diags.Err())
  8101  	}
  8102  }
  8103  
  8104  // This deals with the situation where a splat expression is used referring
  8105  // to another resource whose count is non-constant.
  8106  func TestContext2Apply_issue5254(t *testing.T) {
  8107  	// Create a provider. We use "template" here just to match the repro
  8108  	// we got from the issue itself.
  8109  	p := testProvider("template")
  8110  	p.PlanResourceChangeFn = testDiffFn
  8111  	p.ApplyResourceChangeFn = testApplyFn
  8112  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  8113  		ResourceTypes: map[string]*configschema.Block{
  8114  			"template_file": {
  8115  				Attributes: map[string]*configschema.Attribute{
  8116  					"template":                {Type: cty.String, Optional: true},
  8117  					"__template_requires_new": {Type: cty.Bool, Optional: true},
  8118  					"id":                      {Type: cty.String, Computed: true},
  8119  					"type":                    {Type: cty.String, Computed: true},
  8120  				},
  8121  			},
  8122  		},
  8123  	})
  8124  
  8125  	// Apply cleanly step 0
  8126  	m := testModule(t, "issue-5254/step-0")
  8127  	ctx := testContext2(t, &ContextOpts{
  8128  		Providers: map[addrs.Provider]providers.Factory{
  8129  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  8130  		},
  8131  	})
  8132  
  8133  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  8134  	if diags.HasErrors() {
  8135  		t.Fatalf("err: %s", diags.Err())
  8136  	}
  8137  
  8138  	state, diags := ctx.Apply(plan, m)
  8139  	if diags.HasErrors() {
  8140  		t.Fatalf("err: %s", diags.Err())
  8141  	}
  8142  
  8143  	m, snap := testModuleWithSnapshot(t, "issue-5254/step-1")
  8144  
  8145  	// Application success. Now make the modification and store a plan
  8146  	ctx = testContext2(t, &ContextOpts{
  8147  		Providers: map[addrs.Provider]providers.Factory{
  8148  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  8149  		},
  8150  	})
  8151  
  8152  	plan, diags = ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  8153  	if diags.HasErrors() {
  8154  		t.Fatalf("err: %s", diags.Err())
  8155  	}
  8156  
  8157  	// Write / Read plan to simulate running it through a Plan file
  8158  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  8159  	if err != nil {
  8160  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8161  	}
  8162  
  8163  	ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  8164  		addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  8165  	}
  8166  
  8167  	ctx, diags = NewContext(ctxOpts)
  8168  	if diags.HasErrors() {
  8169  		t.Fatalf("err: %s", diags.Err())
  8170  	}
  8171  
  8172  	state, diags = ctx.Apply(plan, m)
  8173  	if diags.HasErrors() {
  8174  		t.Fatalf("err: %s", diags.Err())
  8175  	}
  8176  
  8177  	actual := strings.TrimSpace(state.String())
  8178  	expected := strings.TrimSpace(`
  8179  template_file.child:
  8180    ID = foo
  8181    provider = provider["registry.opentofu.org/hashicorp/template"]
  8182    __template_requires_new = true
  8183    template = Hi
  8184    type = template_file
  8185  
  8186    Dependencies:
  8187      template_file.parent
  8188  template_file.parent.0:
  8189    ID = foo
  8190    provider = provider["registry.opentofu.org/hashicorp/template"]
  8191    template = Hi
  8192    type = template_file
  8193  `)
  8194  	if actual != expected {
  8195  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected)
  8196  	}
  8197  }
  8198  
  8199  func TestContext2Apply_targetedWithTaintedInState(t *testing.T) {
  8200  	p := testProvider("aws")
  8201  	p.PlanResourceChangeFn = testDiffFn
  8202  	p.ApplyResourceChangeFn = testApplyFn
  8203  	m, snap := testModuleWithSnapshot(t, "apply-tainted-targets")
  8204  
  8205  	state := states.NewState()
  8206  	root := state.EnsureModule(addrs.RootModuleInstance)
  8207  	root.SetResourceInstanceCurrent(
  8208  		mustResourceInstanceAddr("aws_instance.ifailedprovisioners").Resource,
  8209  		&states.ResourceInstanceObjectSrc{
  8210  			Status:    states.ObjectTainted,
  8211  			AttrsJSON: []byte(`{"id":"ifailedprovisioners"}`),
  8212  		},
  8213  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  8214  	)
  8215  
  8216  	ctx := testContext2(t, &ContextOpts{
  8217  		Providers: map[addrs.Provider]providers.Factory{
  8218  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8219  		},
  8220  	})
  8221  
  8222  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8223  		Mode: plans.NormalMode,
  8224  		Targets: []addrs.Targetable{
  8225  			addrs.RootModuleInstance.Resource(
  8226  				addrs.ManagedResourceMode, "aws_instance", "iambeingadded",
  8227  			),
  8228  		},
  8229  	})
  8230  	if diags.HasErrors() {
  8231  		t.Fatalf("err: %s", diags.Err())
  8232  	}
  8233  
  8234  	// Write / Read plan to simulate running it through a Plan file
  8235  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  8236  	if err != nil {
  8237  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8238  	}
  8239  
  8240  	ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  8241  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8242  	}
  8243  
  8244  	ctx, diags = NewContext(ctxOpts)
  8245  	if diags.HasErrors() {
  8246  		t.Fatalf("err: %s", diags.Err())
  8247  	}
  8248  
  8249  	s, diags := ctx.Apply(plan, m)
  8250  	if diags.HasErrors() {
  8251  		t.Fatalf("err: %s", diags.Err())
  8252  	}
  8253  
  8254  	actual := strings.TrimSpace(s.String())
  8255  	expected := strings.TrimSpace(`
  8256  aws_instance.iambeingadded:
  8257    ID = foo
  8258    provider = provider["registry.opentofu.org/hashicorp/aws"]
  8259    type = aws_instance
  8260  aws_instance.ifailedprovisioners: (tainted)
  8261    ID = ifailedprovisioners
  8262    provider = provider["registry.opentofu.org/hashicorp/aws"]
  8263  		`)
  8264  	if actual != expected {
  8265  		t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual)
  8266  	}
  8267  }
  8268  
  8269  // Higher level test exposing the bug this covers in
  8270  // TestResource_ignoreChangesRequired
  8271  func TestContext2Apply_ignoreChangesCreate(t *testing.T) {
  8272  	m := testModule(t, "apply-ignore-changes-create")
  8273  	p := testProvider("aws")
  8274  	p.PlanResourceChangeFn = testDiffFn
  8275  	p.ApplyResourceChangeFn = testApplyFn
  8276  
  8277  	instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  8278  	instanceSchema.Attributes["required_field"] = &configschema.Attribute{
  8279  		Type:     cty.String,
  8280  		Required: true,
  8281  	}
  8282  
  8283  	ctx := testContext2(t, &ContextOpts{
  8284  		Providers: map[addrs.Provider]providers.Factory{
  8285  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8286  		},
  8287  	})
  8288  
  8289  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8290  	if diags.HasErrors() {
  8291  		t.Fatalf("diags: %s", diags.Err())
  8292  	} else {
  8293  		t.Logf(legacyDiffComparisonString(plan.Changes))
  8294  	}
  8295  
  8296  	state, diags := ctx.Apply(plan, m)
  8297  	if diags.HasErrors() {
  8298  		t.Fatalf("diags: %s", diags.Err())
  8299  	}
  8300  
  8301  	mod := state.RootModule()
  8302  	if len(mod.Resources) != 1 {
  8303  		t.Fatalf("bad: %s", state)
  8304  	}
  8305  
  8306  	actual := strings.TrimSpace(state.String())
  8307  	// Expect no changes from original state
  8308  	expected := strings.TrimSpace(`
  8309  aws_instance.foo:
  8310    ID = foo
  8311    provider = provider["registry.opentofu.org/hashicorp/aws"]
  8312    required_field = set
  8313    type = aws_instance
  8314  `)
  8315  	if actual != expected {
  8316  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
  8317  	}
  8318  }
  8319  
  8320  func TestContext2Apply_ignoreChangesWithDep(t *testing.T) {
  8321  	m := testModule(t, "apply-ignore-changes-dep")
  8322  	p := testProvider("aws")
  8323  
  8324  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  8325  		resp.PlannedState = req.ProposedNewState
  8326  
  8327  		switch req.TypeName {
  8328  		case "aws_instance":
  8329  			resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: "ami"}})
  8330  		case "aws_eip":
  8331  			return testDiffFn(req)
  8332  		default:
  8333  			t.Fatalf("Unexpected type: %s", req.TypeName)
  8334  		}
  8335  		return
  8336  	}
  8337  
  8338  	state := states.NewState()
  8339  	root := state.EnsureModule(addrs.RootModuleInstance)
  8340  	root.SetResourceInstanceCurrent(
  8341  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  8342  		&states.ResourceInstanceObjectSrc{
  8343  			Status:    states.ObjectReady,
  8344  			AttrsJSON: []byte(`{"id":"i-abc123","ami":"ami-abcd1234"}`),
  8345  		},
  8346  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  8347  	)
  8348  	root.SetResourceInstanceCurrent(
  8349  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  8350  		&states.ResourceInstanceObjectSrc{
  8351  			Status:    states.ObjectReady,
  8352  			AttrsJSON: []byte(`{"id":"i-bcd234","ami":"i-bcd234"}`),
  8353  		},
  8354  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  8355  	)
  8356  	root.SetResourceInstanceCurrent(
  8357  		mustResourceInstanceAddr("aws_eip.foo[0]").Resource,
  8358  		&states.ResourceInstanceObjectSrc{
  8359  			Status:    states.ObjectReady,
  8360  			AttrsJSON: []byte(`{"id":"eip-abc123","instance":"i-abc123"}`),
  8361  			Dependencies: []addrs.ConfigResource{
  8362  				{
  8363  					Resource: addrs.Resource{
  8364  						Mode: addrs.ManagedResourceMode,
  8365  						Type: "aws_instance",
  8366  						Name: "foo",
  8367  					},
  8368  					Module: addrs.RootModule,
  8369  				},
  8370  			},
  8371  		},
  8372  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  8373  	)
  8374  	root.SetResourceInstanceCurrent(
  8375  		mustResourceInstanceAddr("aws_eip.foo[1]").Resource,
  8376  		&states.ResourceInstanceObjectSrc{
  8377  			Status:    states.ObjectReady,
  8378  			AttrsJSON: []byte(`{"id":"eip-bcd234","instance":"i-bcd234"}`),
  8379  			Dependencies: []addrs.ConfigResource{
  8380  				{
  8381  					Resource: addrs.Resource{
  8382  						Mode: addrs.ManagedResourceMode,
  8383  						Type: "aws_instance",
  8384  						Name: "foo",
  8385  					},
  8386  					Module: addrs.RootModule,
  8387  				},
  8388  			},
  8389  		},
  8390  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  8391  	)
  8392  
  8393  	ctx := testContext2(t, &ContextOpts{
  8394  		Providers: map[addrs.Provider]providers.Factory{
  8395  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8396  		},
  8397  	})
  8398  
  8399  	plan, diags := ctx.Plan(m, state.DeepCopy(), DefaultPlanOpts)
  8400  	assertNoErrors(t, diags)
  8401  
  8402  	s, diags := ctx.Apply(plan, m)
  8403  	assertNoErrors(t, diags)
  8404  
  8405  	actual := strings.TrimSpace(s.String())
  8406  	expected := strings.TrimSpace(state.String())
  8407  	if actual != expected {
  8408  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  8409  	}
  8410  }
  8411  
  8412  func TestContext2Apply_ignoreChangesAll(t *testing.T) {
  8413  	m := testModule(t, "apply-ignore-changes-all")
  8414  	p := testProvider("aws")
  8415  	p.PlanResourceChangeFn = testDiffFn
  8416  	p.ApplyResourceChangeFn = testApplyFn
  8417  
  8418  	instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  8419  	instanceSchema.Attributes["required_field"] = &configschema.Attribute{
  8420  		Type:     cty.String,
  8421  		Required: true,
  8422  	}
  8423  
  8424  	ctx := testContext2(t, &ContextOpts{
  8425  		Providers: map[addrs.Provider]providers.Factory{
  8426  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8427  		},
  8428  	})
  8429  
  8430  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8431  	if diags.HasErrors() {
  8432  		logDiagnostics(t, diags)
  8433  		t.Fatal("plan failed")
  8434  	} else {
  8435  		t.Logf(legacyDiffComparisonString(plan.Changes))
  8436  	}
  8437  
  8438  	state, diags := ctx.Apply(plan, m)
  8439  	assertNoErrors(t, diags)
  8440  
  8441  	mod := state.RootModule()
  8442  	if len(mod.Resources) != 1 {
  8443  		t.Fatalf("bad: %s", state)
  8444  	}
  8445  
  8446  	actual := strings.TrimSpace(state.String())
  8447  	// Expect no changes from original state
  8448  	expected := strings.TrimSpace(`
  8449  aws_instance.foo:
  8450    ID = foo
  8451    provider = provider["registry.opentofu.org/hashicorp/aws"]
  8452    required_field = set
  8453    type = aws_instance
  8454  `)
  8455  	if actual != expected {
  8456  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
  8457  	}
  8458  }
  8459  
  8460  // https://github.com/hashicorp/terraform/issues/7378
  8461  func TestContext2Apply_destroyNestedModuleWithAttrsReferencingResource(t *testing.T) {
  8462  	m, snap := testModuleWithSnapshot(t, "apply-destroy-nested-module-with-attrs")
  8463  	p := testProvider("null")
  8464  	p.PlanResourceChangeFn = testDiffFn
  8465  
  8466  	var state *states.State
  8467  	{
  8468  		ctx := testContext2(t, &ContextOpts{
  8469  			Providers: map[addrs.Provider]providers.Factory{
  8470  				addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8471  			},
  8472  		})
  8473  
  8474  		// First plan and apply a create operation
  8475  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8476  		assertNoErrors(t, diags)
  8477  
  8478  		state, diags = ctx.Apply(plan, m)
  8479  		if diags.HasErrors() {
  8480  			t.Fatalf("apply err: %s", diags.Err())
  8481  		}
  8482  	}
  8483  
  8484  	{
  8485  		ctx := testContext2(t, &ContextOpts{
  8486  			Providers: map[addrs.Provider]providers.Factory{
  8487  				addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8488  			},
  8489  		})
  8490  
  8491  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  8492  			Mode: plans.DestroyMode,
  8493  		})
  8494  		if diags.HasErrors() {
  8495  			t.Fatalf("destroy plan err: %s", diags.Err())
  8496  		}
  8497  
  8498  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  8499  		if err != nil {
  8500  			t.Fatalf("failed to round-trip through planfile: %s", err)
  8501  		}
  8502  
  8503  		ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  8504  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8505  		}
  8506  
  8507  		ctx, diags = NewContext(ctxOpts)
  8508  		if diags.HasErrors() {
  8509  			t.Fatalf("err: %s", diags.Err())
  8510  		}
  8511  
  8512  		state, diags = ctx.Apply(plan, m)
  8513  		if diags.HasErrors() {
  8514  			t.Fatalf("destroy apply err: %s", diags.Err())
  8515  		}
  8516  	}
  8517  
  8518  	if !state.Empty() {
  8519  		t.Fatalf("state after apply: %s\nwant empty state", spew.Sdump(state))
  8520  	}
  8521  }
  8522  
  8523  // If a data source explicitly depends on another resource, it's because we need
  8524  // that resource to be applied first.
  8525  func TestContext2Apply_dataDependsOn(t *testing.T) {
  8526  	p := testProvider("null")
  8527  	m := testModuleInline(t, map[string]string{
  8528  		"main.tf": `
  8529  resource "null_instance" "write" {
  8530    foo = "attribute"
  8531  }
  8532  
  8533  data "null_data_source" "read" {
  8534    count = 1
  8535    depends_on = ["null_instance.write"]
  8536  }
  8537  
  8538  resource "null_instance" "depends" {
  8539    foo = data.null_data_source.read[0].foo
  8540  }
  8541  `})
  8542  
  8543  	ctx := testContext2(t, &ContextOpts{
  8544  		Providers: map[addrs.Provider]providers.Factory{
  8545  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8546  		},
  8547  	})
  8548  
  8549  	// the "provisioner" here writes to this variable, because the intent is to
  8550  	// create a dependency which can't be viewed through the graph, and depends
  8551  	// solely on the configuration providing "depends_on"
  8552  	provisionerOutput := ""
  8553  
  8554  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  8555  		// the side effect of the resource being applied
  8556  		provisionerOutput = "APPLIED"
  8557  		return testApplyFn(req)
  8558  	}
  8559  
  8560  	p.PlanResourceChangeFn = testDiffFn
  8561  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  8562  		return providers.ReadDataSourceResponse{
  8563  			State: cty.ObjectVal(map[string]cty.Value{
  8564  				"id":  cty.StringVal("boop"),
  8565  				"foo": cty.StringVal(provisionerOutput),
  8566  			}),
  8567  		}
  8568  	}
  8569  
  8570  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8571  	assertNoErrors(t, diags)
  8572  
  8573  	state, diags := ctx.Apply(plan, m)
  8574  	assertNoErrors(t, diags)
  8575  
  8576  	root := state.Module(addrs.RootModuleInstance)
  8577  	is := root.ResourceInstance(addrs.Resource{
  8578  		Mode: addrs.DataResourceMode,
  8579  		Type: "null_data_source",
  8580  		Name: "read",
  8581  	}.Instance(addrs.IntKey(0)))
  8582  	if is == nil {
  8583  		t.Fatal("data resource instance is not present in state; should be")
  8584  	}
  8585  	var attrs map[string]interface{}
  8586  	err := json.Unmarshal(is.Current.AttrsJSON, &attrs)
  8587  	if err != nil {
  8588  		t.Fatal(err)
  8589  	}
  8590  	actual := attrs["foo"]
  8591  	expected := "APPLIED"
  8592  	if actual != expected {
  8593  		t.Fatalf("bad:\n%s", strings.TrimSpace(state.String()))
  8594  	}
  8595  
  8596  	// run another plan to make sure the data source doesn't show as a change
  8597  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  8598  	assertNoErrors(t, diags)
  8599  
  8600  	for _, c := range plan.Changes.Resources {
  8601  		if c.Action != plans.NoOp {
  8602  			t.Fatalf("unexpected change for %s", c.Addr)
  8603  		}
  8604  	}
  8605  
  8606  	// now we cause a change in the first resource, which should trigger a plan
  8607  	// in the data source, and the resource that depends on the data source
  8608  	// must plan a change as well.
  8609  	m = testModuleInline(t, map[string]string{
  8610  		"main.tf": `
  8611  resource "null_instance" "write" {
  8612    foo = "new"
  8613  }
  8614  
  8615  data "null_data_source" "read" {
  8616    depends_on = ["null_instance.write"]
  8617  }
  8618  
  8619  resource "null_instance" "depends" {
  8620    foo = data.null_data_source.read.foo
  8621  }
  8622  `})
  8623  
  8624  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  8625  		// the side effect of the resource being applied
  8626  		provisionerOutput = "APPLIED_AGAIN"
  8627  		return testApplyFn(req)
  8628  	}
  8629  
  8630  	ctx = testContext2(t, &ContextOpts{
  8631  		Providers: map[addrs.Provider]providers.Factory{
  8632  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8633  		},
  8634  	})
  8635  
  8636  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  8637  	assertNoErrors(t, diags)
  8638  
  8639  	expectedChanges := map[string]plans.Action{
  8640  		"null_instance.write":        plans.Update,
  8641  		"data.null_data_source.read": plans.Read,
  8642  		"null_instance.depends":      plans.Update,
  8643  	}
  8644  
  8645  	for _, c := range plan.Changes.Resources {
  8646  		if c.Action != expectedChanges[c.Addr.String()] {
  8647  			t.Errorf("unexpected %s for %s", c.Action, c.Addr)
  8648  		}
  8649  	}
  8650  }
  8651  
  8652  func TestContext2Apply_terraformWorkspace(t *testing.T) {
  8653  	m := testModule(t, "apply-tofu-workspace")
  8654  	p := testProvider("aws")
  8655  	p.PlanResourceChangeFn = testDiffFn
  8656  
  8657  	ctx := testContext2(t, &ContextOpts{
  8658  		Meta: &ContextMeta{Env: "foo"},
  8659  		Providers: map[addrs.Provider]providers.Factory{
  8660  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8661  		},
  8662  	})
  8663  
  8664  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8665  	assertNoErrors(t, diags)
  8666  
  8667  	state, diags := ctx.Apply(plan, m)
  8668  	if diags.HasErrors() {
  8669  		t.Fatalf("diags: %s", diags.Err())
  8670  	}
  8671  
  8672  	actual := state.RootModule().OutputValues["output"]
  8673  	expected := cty.StringVal("foo")
  8674  	if actual == nil || actual.Value != expected {
  8675  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  8676  	}
  8677  }
  8678  
  8679  // verify that multiple config references only create a single depends_on entry
  8680  func TestContext2Apply_multiRef(t *testing.T) {
  8681  	m := testModule(t, "apply-multi-ref")
  8682  	p := testProvider("aws")
  8683  	p.PlanResourceChangeFn = testDiffFn
  8684  	ctx := testContext2(t, &ContextOpts{
  8685  		Providers: map[addrs.Provider]providers.Factory{
  8686  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8687  		},
  8688  	})
  8689  
  8690  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8691  	assertNoErrors(t, diags)
  8692  
  8693  	state, diags := ctx.Apply(plan, m)
  8694  	if diags.HasErrors() {
  8695  		t.Fatalf("err: %s", diags.Err())
  8696  	}
  8697  
  8698  	deps := state.Modules[""].Resources["aws_instance.other"].Instances[addrs.NoKey].Current.Dependencies
  8699  	if len(deps) != 1 || deps[0].String() != "aws_instance.create" {
  8700  		t.Fatalf("expected 1 depends_on entry for aws_instance.create, got %q", deps)
  8701  	}
  8702  }
  8703  
  8704  func TestContext2Apply_targetedModuleRecursive(t *testing.T) {
  8705  	m := testModule(t, "apply-targeted-module-recursive")
  8706  	p := testProvider("aws")
  8707  	p.PlanResourceChangeFn = testDiffFn
  8708  	p.ApplyResourceChangeFn = testApplyFn
  8709  	ctx := testContext2(t, &ContextOpts{
  8710  		Providers: map[addrs.Provider]providers.Factory{
  8711  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8712  		},
  8713  	})
  8714  
  8715  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  8716  		Mode: plans.NormalMode,
  8717  		Targets: []addrs.Targetable{
  8718  			addrs.RootModuleInstance.Child("child", addrs.NoKey),
  8719  		},
  8720  	})
  8721  	assertNoErrors(t, diags)
  8722  
  8723  	state, diags := ctx.Apply(plan, m)
  8724  	if diags.HasErrors() {
  8725  		t.Fatalf("err: %s", diags.Err())
  8726  	}
  8727  
  8728  	mod := state.Module(
  8729  		addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("subchild", addrs.NoKey),
  8730  	)
  8731  	if mod == nil {
  8732  		t.Fatalf("no subchild module found in the state!\n\n%#v", state)
  8733  	}
  8734  	if len(mod.Resources) != 1 {
  8735  		t.Fatalf("expected 1 resources, got: %#v", mod.Resources)
  8736  	}
  8737  
  8738  	checkStateString(t, state, `
  8739  <no state>
  8740  module.child.subchild:
  8741    aws_instance.foo:
  8742      ID = foo
  8743      provider = provider["registry.opentofu.org/hashicorp/aws"]
  8744      num = 2
  8745      type = aws_instance
  8746  	`)
  8747  }
  8748  
  8749  func TestContext2Apply_localVal(t *testing.T) {
  8750  	m := testModule(t, "apply-local-val")
  8751  	ctx := testContext2(t, &ContextOpts{
  8752  		Providers: map[addrs.Provider]providers.Factory{},
  8753  	})
  8754  
  8755  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8756  	assertNoErrors(t, diags)
  8757  
  8758  	state, diags := ctx.Apply(plan, m)
  8759  	if diags.HasErrors() {
  8760  		t.Fatalf("error during apply: %s", diags.Err())
  8761  	}
  8762  
  8763  	got := strings.TrimSpace(state.String())
  8764  	want := strings.TrimSpace(`
  8765  <no state>
  8766  Outputs:
  8767  
  8768  result_1 = hello
  8769  result_3 = hello world
  8770  `)
  8771  	if got != want {
  8772  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8773  	}
  8774  }
  8775  
  8776  func TestContext2Apply_destroyWithLocals(t *testing.T) {
  8777  	m := testModule(t, "apply-destroy-with-locals")
  8778  	p := testProvider("aws")
  8779  	p.PlanResourceChangeFn = testDiffFn
  8780  
  8781  	state := states.NewState()
  8782  	root := state.EnsureModule(addrs.RootModuleInstance)
  8783  	root.SetResourceInstanceCurrent(
  8784  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  8785  		&states.ResourceInstanceObjectSrc{
  8786  			Status:    states.ObjectReady,
  8787  			AttrsJSON: []byte(`{"id":"foo"}`),
  8788  		},
  8789  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  8790  	)
  8791  	root.SetOutputValue("name", cty.StringVal("test-bar"), false)
  8792  
  8793  	ctx := testContext2(t, &ContextOpts{
  8794  		Providers: map[addrs.Provider]providers.Factory{
  8795  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8796  		},
  8797  	})
  8798  
  8799  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8800  		Mode: plans.DestroyMode,
  8801  	})
  8802  	assertNoErrors(t, diags)
  8803  
  8804  	s, diags := ctx.Apply(plan, m)
  8805  	if diags.HasErrors() {
  8806  		t.Fatalf("error during apply: %s", diags.Err())
  8807  	}
  8808  
  8809  	got := strings.TrimSpace(s.String())
  8810  	want := strings.TrimSpace(`<no state>`)
  8811  	if got != want {
  8812  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8813  	}
  8814  }
  8815  
  8816  func TestContext2Apply_providerWithLocals(t *testing.T) {
  8817  	m := testModule(t, "provider-with-locals")
  8818  	p := testProvider("aws")
  8819  
  8820  	providerRegion := ""
  8821  	// this should not be overridden during destroy
  8822  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  8823  		val := req.Config.GetAttr("region")
  8824  		if !val.IsNull() {
  8825  			providerRegion = val.AsString()
  8826  		}
  8827  
  8828  		return
  8829  	}
  8830  
  8831  	p.PlanResourceChangeFn = testDiffFn
  8832  	ctx := testContext2(t, &ContextOpts{
  8833  		Providers: map[addrs.Provider]providers.Factory{
  8834  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8835  		},
  8836  	})
  8837  
  8838  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8839  	assertNoErrors(t, diags)
  8840  
  8841  	state, diags := ctx.Apply(plan, m)
  8842  	if diags.HasErrors() {
  8843  		t.Fatalf("err: %s", diags.Err())
  8844  	}
  8845  
  8846  	ctx = testContext2(t, &ContextOpts{
  8847  		Providers: map[addrs.Provider]providers.Factory{
  8848  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8849  		},
  8850  	})
  8851  
  8852  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  8853  		Mode: plans.DestroyMode,
  8854  	})
  8855  	assertNoErrors(t, diags)
  8856  
  8857  	state, diags = ctx.Apply(plan, m)
  8858  	if diags.HasErrors() {
  8859  		t.Fatalf("err: %s", diags.Err())
  8860  	}
  8861  
  8862  	if state.HasManagedResourceInstanceObjects() {
  8863  		t.Fatal("expected no state, got:", state)
  8864  	}
  8865  
  8866  	if providerRegion != "bar" {
  8867  		t.Fatalf("expected region %q, got: %q", "bar", providerRegion)
  8868  	}
  8869  }
  8870  
  8871  func TestContext2Apply_destroyWithProviders(t *testing.T) {
  8872  	m := testModule(t, "destroy-module-with-provider")
  8873  	p := testProvider("aws")
  8874  	p.PlanResourceChangeFn = testDiffFn
  8875  
  8876  	state := states.NewState()
  8877  	removed := state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.NoKey).Child("removed", addrs.NoKey))
  8878  	removed.SetResourceInstanceCurrent(
  8879  		mustResourceInstanceAddr("aws_instance.child").Resource,
  8880  		&states.ResourceInstanceObjectSrc{
  8881  			Status:    states.ObjectReady,
  8882  			AttrsJSON: []byte(`{"id":"bar"}`),
  8883  		},
  8884  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"].baz`),
  8885  	)
  8886  
  8887  	ctx := testContext2(t, &ContextOpts{
  8888  		Providers: map[addrs.Provider]providers.Factory{
  8889  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8890  		},
  8891  	})
  8892  
  8893  	// test that we can't destroy if the provider is missing
  8894  	if _, diags := ctx.Plan(m, state, &PlanOpts{Mode: plans.DestroyMode}); diags == nil {
  8895  		t.Fatal("expected plan error, provider.aws.baz doesn't exist")
  8896  	}
  8897  
  8898  	// correct the state
  8899  	state.Modules["module.mod.module.removed"].Resources["aws_instance.child"].ProviderConfig = mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"].bar`)
  8900  
  8901  	ctx = testContext2(t, &ContextOpts{
  8902  		Providers: map[addrs.Provider]providers.Factory{
  8903  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8904  		},
  8905  	})
  8906  
  8907  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8908  		Mode: plans.DestroyMode,
  8909  	})
  8910  	assertNoErrors(t, diags)
  8911  
  8912  	state, diags = ctx.Apply(plan, m)
  8913  	if diags.HasErrors() {
  8914  		t.Fatalf("error during apply: %s", diags.Err())
  8915  	}
  8916  
  8917  	got := strings.TrimSpace(state.String())
  8918  
  8919  	want := strings.TrimSpace("<no state>")
  8920  	if got != want {
  8921  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8922  	}
  8923  }
  8924  
  8925  func TestContext2Apply_providersFromState(t *testing.T) {
  8926  	m := configs.NewEmptyConfig()
  8927  	p := testProvider("aws")
  8928  	p.PlanResourceChangeFn = testDiffFn
  8929  
  8930  	implicitProviderState := states.NewState()
  8931  	impRoot := implicitProviderState.EnsureModule(addrs.RootModuleInstance)
  8932  	impRoot.SetResourceInstanceCurrent(
  8933  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8934  		&states.ResourceInstanceObjectSrc{
  8935  			Status:    states.ObjectReady,
  8936  			AttrsJSON: []byte(`{"id":"bar"}`),
  8937  		},
  8938  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  8939  	)
  8940  
  8941  	aliasedProviderState := states.NewState()
  8942  	aliasRoot := aliasedProviderState.EnsureModule(addrs.RootModuleInstance)
  8943  	aliasRoot.SetResourceInstanceCurrent(
  8944  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8945  		&states.ResourceInstanceObjectSrc{
  8946  			Status:    states.ObjectReady,
  8947  			AttrsJSON: []byte(`{"id":"bar"}`),
  8948  		},
  8949  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"].bar`),
  8950  	)
  8951  
  8952  	moduleProviderState := states.NewState()
  8953  	moduleProviderRoot := moduleProviderState.EnsureModule(addrs.RootModuleInstance)
  8954  	moduleProviderRoot.SetResourceInstanceCurrent(
  8955  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8956  		&states.ResourceInstanceObjectSrc{
  8957  			Status:    states.ObjectReady,
  8958  			AttrsJSON: []byte(`{"id":"bar"}`),
  8959  		},
  8960  		mustProviderConfig(`module.child.provider["registry.opentofu.org/hashicorp/aws"]`),
  8961  	)
  8962  
  8963  	for _, tc := range []struct {
  8964  		name   string
  8965  		state  *states.State
  8966  		output string
  8967  		err    bool
  8968  	}{
  8969  		{
  8970  			name:   "add implicit provider",
  8971  			state:  implicitProviderState,
  8972  			err:    false,
  8973  			output: "<no state>",
  8974  		},
  8975  
  8976  		// an aliased provider must be in the config to remove a resource
  8977  		{
  8978  			name:  "add aliased provider",
  8979  			state: aliasedProviderState,
  8980  			err:   true,
  8981  		},
  8982  
  8983  		// a provider in a module implies some sort of config, so this isn't
  8984  		// allowed even without an alias
  8985  		{
  8986  			name:  "add unaliased module provider",
  8987  			state: moduleProviderState,
  8988  			err:   true,
  8989  		},
  8990  	} {
  8991  		t.Run(tc.name, func(t *testing.T) {
  8992  			ctx := testContext2(t, &ContextOpts{
  8993  				Providers: map[addrs.Provider]providers.Factory{
  8994  					addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8995  				},
  8996  			})
  8997  
  8998  			plan, diags := ctx.Plan(m, tc.state, DefaultPlanOpts)
  8999  			if tc.err {
  9000  				if diags == nil {
  9001  					t.Fatal("expected error")
  9002  				} else {
  9003  					return
  9004  				}
  9005  			}
  9006  			if !tc.err && diags.HasErrors() {
  9007  				t.Fatal(diags.Err())
  9008  			}
  9009  
  9010  			state, diags := ctx.Apply(plan, m)
  9011  			if diags.HasErrors() {
  9012  				t.Fatalf("diags: %s", diags.Err())
  9013  			}
  9014  
  9015  			checkStateString(t, state, "<no state>")
  9016  
  9017  		})
  9018  	}
  9019  }
  9020  
  9021  func TestContext2Apply_plannedInterpolatedCount(t *testing.T) {
  9022  	m, snap := testModuleWithSnapshot(t, "apply-interpolated-count")
  9023  
  9024  	p := testProvider("aws")
  9025  	p.PlanResourceChangeFn = testDiffFn
  9026  
  9027  	Providers := map[addrs.Provider]providers.Factory{
  9028  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  9029  	}
  9030  
  9031  	state := states.NewState()
  9032  	root := state.EnsureModule(addrs.RootModuleInstance)
  9033  	root.SetResourceInstanceCurrent(
  9034  		mustResourceInstanceAddr("aws_instance.test").Resource,
  9035  		&states.ResourceInstanceObjectSrc{
  9036  			Status:    states.ObjectReady,
  9037  			AttrsJSON: []byte(`{"id":"foo"}`),
  9038  		},
  9039  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  9040  	)
  9041  
  9042  	ctx := testContext2(t, &ContextOpts{
  9043  		Providers: Providers,
  9044  	})
  9045  
  9046  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  9047  	if diags.HasErrors() {
  9048  		t.Fatalf("plan failed: %s", diags.Err())
  9049  	}
  9050  
  9051  	// We'll marshal and unmarshal the plan here, to ensure that we have
  9052  	// a clean new context as would be created if we separately ran
  9053  	// tofu plan -out=tfplan && tofu apply tfplan
  9054  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  9055  	if err != nil {
  9056  		t.Fatalf("failed to round-trip through planfile: %s", err)
  9057  	}
  9058  
  9059  	ctxOpts.Providers = Providers
  9060  	ctx, diags = NewContext(ctxOpts)
  9061  	if diags.HasErrors() {
  9062  		t.Fatalf("err: %s", diags.Err())
  9063  	}
  9064  
  9065  	// Applying the plan should now succeed
  9066  	_, diags = ctx.Apply(plan, m)
  9067  	if diags.HasErrors() {
  9068  		t.Fatalf("apply failed: %s", diags.Err())
  9069  	}
  9070  }
  9071  
  9072  func TestContext2Apply_plannedDestroyInterpolatedCount(t *testing.T) {
  9073  	m, snap := testModuleWithSnapshot(t, "plan-destroy-interpolated-count")
  9074  
  9075  	p := testProvider("aws")
  9076  	p.PlanResourceChangeFn = testDiffFn
  9077  	providers := map[addrs.Provider]providers.Factory{
  9078  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  9079  	}
  9080  
  9081  	state := states.NewState()
  9082  	root := state.EnsureModule(addrs.RootModuleInstance)
  9083  	root.SetResourceInstanceCurrent(
  9084  		mustResourceInstanceAddr("aws_instance.a[0]").Resource,
  9085  		&states.ResourceInstanceObjectSrc{
  9086  			Status:    states.ObjectReady,
  9087  			AttrsJSON: []byte(`{"id":"foo"}`),
  9088  		},
  9089  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  9090  	)
  9091  	root.SetResourceInstanceCurrent(
  9092  		mustResourceInstanceAddr("aws_instance.a[1]").Resource,
  9093  		&states.ResourceInstanceObjectSrc{
  9094  			Status:    states.ObjectReady,
  9095  			AttrsJSON: []byte(`{"id":"foo"}`),
  9096  		},
  9097  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  9098  	)
  9099  	root.SetOutputValue("out", cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("foo")}), false)
  9100  
  9101  	ctx := testContext2(t, &ContextOpts{
  9102  		Providers: providers,
  9103  	})
  9104  
  9105  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
  9106  	if diags.HasErrors() {
  9107  		t.Fatalf("plan failed: %s", diags.Err())
  9108  	}
  9109  
  9110  	// We'll marshal and unmarshal the plan here, to ensure that we have
  9111  	// a clean new context as would be created if we separately ran
  9112  	// tofu plan -out=tfplan && tofu apply tfplan
  9113  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  9114  	if err != nil {
  9115  		t.Fatalf("failed to round-trip through planfile: %s", err)
  9116  	}
  9117  
  9118  	ctxOpts.Providers = providers
  9119  	ctx, diags = NewContext(ctxOpts)
  9120  	if diags.HasErrors() {
  9121  		t.Fatalf("err: %s", diags.Err())
  9122  	}
  9123  
  9124  	// Applying the plan should now succeed
  9125  	state, diags = ctx.Apply(plan, m)
  9126  	if diags.HasErrors() {
  9127  		t.Fatalf("apply failed: %s", diags.Err())
  9128  	}
  9129  	if !state.Empty() {
  9130  		t.Fatalf("state not empty: %s\n", state)
  9131  	}
  9132  }
  9133  
  9134  func TestContext2Apply_scaleInMultivarRef(t *testing.T) {
  9135  	m := testModule(t, "apply-resource-scale-in")
  9136  
  9137  	p := testProvider("aws")
  9138  	p.PlanResourceChangeFn = testDiffFn
  9139  
  9140  	Providers := map[addrs.Provider]providers.Factory{
  9141  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  9142  	}
  9143  
  9144  	state := states.NewState()
  9145  	root := state.EnsureModule(addrs.RootModuleInstance)
  9146  	root.SetResourceInstanceCurrent(
  9147  		mustResourceInstanceAddr("aws_instance.one").Resource,
  9148  		&states.ResourceInstanceObjectSrc{
  9149  			Status:    states.ObjectReady,
  9150  			AttrsJSON: []byte(`{"id":"foo"}`),
  9151  		},
  9152  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  9153  	)
  9154  	root.SetResourceInstanceCurrent(
  9155  		mustResourceInstanceAddr("aws_instance.two").Resource,
  9156  		&states.ResourceInstanceObjectSrc{
  9157  			Status:    states.ObjectReady,
  9158  			AttrsJSON: []byte(`{"id":"foo"}`),
  9159  		},
  9160  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/aws"]`),
  9161  	)
  9162  
  9163  	ctx := testContext2(t, &ContextOpts{
  9164  		Providers: Providers,
  9165  	})
  9166  
  9167  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  9168  		Mode: plans.NormalMode,
  9169  		SetVariables: InputValues{
  9170  			"instance_count": {
  9171  				Value:      cty.NumberIntVal(0),
  9172  				SourceType: ValueFromCaller,
  9173  			},
  9174  		},
  9175  	})
  9176  	assertNoErrors(t, diags)
  9177  	{
  9178  		addr := mustResourceInstanceAddr("aws_instance.one[0]")
  9179  		change := plan.Changes.ResourceInstance(addr)
  9180  		if change == nil {
  9181  			t.Fatalf("no planned change for %s", addr)
  9182  		}
  9183  		// This test was originally written with Terraform v0.11 and earlier
  9184  		// in mind, so it declares a no-key instance of aws_instance.one,
  9185  		// but its configuration sets count (to zero) and so we end up first
  9186  		// moving the no-key instance to the zero key and then planning to
  9187  		// destroy the zero key.
  9188  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("aws_instance.one"); !want.Equal(got) {
  9189  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
  9190  		}
  9191  		if got, want := change.Action, plans.Delete; got != want {
  9192  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  9193  		}
  9194  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
  9195  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
  9196  		}
  9197  	}
  9198  	{
  9199  		addr := mustResourceInstanceAddr("aws_instance.two")
  9200  		change := plan.Changes.ResourceInstance(addr)
  9201  		if change == nil {
  9202  			t.Fatalf("no planned change for %s", addr)
  9203  		}
  9204  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("aws_instance.two"); !want.Equal(got) {
  9205  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
  9206  		}
  9207  		if got, want := change.Action, plans.Update; got != want {
  9208  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  9209  		}
  9210  		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
  9211  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
  9212  		}
  9213  	}
  9214  
  9215  	// Applying the plan should now succeed
  9216  	_, diags = ctx.Apply(plan, m)
  9217  	assertNoErrors(t, diags)
  9218  }
  9219  
  9220  func TestContext2Apply_inconsistentWithPlan(t *testing.T) {
  9221  	m := testModule(t, "apply-inconsistent-with-plan")
  9222  	p := testProvider("test")
  9223  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9224  		ResourceTypes: map[string]*configschema.Block{
  9225  			"test": {
  9226  				Attributes: map[string]*configschema.Attribute{
  9227  					"id": {Type: cty.String, Computed: true},
  9228  				},
  9229  			},
  9230  		},
  9231  	})
  9232  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  9233  		return providers.PlanResourceChangeResponse{
  9234  			PlannedState: cty.ObjectVal(map[string]cty.Value{
  9235  				"id": cty.StringVal("before"),
  9236  			}),
  9237  		}
  9238  	}
  9239  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9240  		return providers.ApplyResourceChangeResponse{
  9241  			NewState: cty.ObjectVal(map[string]cty.Value{
  9242  				// This is intentionally incorrect: because id was fixed at "before"
  9243  				// during plan, it must not change during apply.
  9244  				"id": cty.StringVal("after"),
  9245  			}),
  9246  		}
  9247  	}
  9248  	ctx := testContext2(t, &ContextOpts{
  9249  		Providers: map[addrs.Provider]providers.Factory{
  9250  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9251  		},
  9252  	})
  9253  
  9254  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9255  	assertNoErrors(t, diags)
  9256  
  9257  	_, diags = ctx.Apply(plan, m)
  9258  	if !diags.HasErrors() {
  9259  		t.Fatalf("apply succeeded; want error")
  9260  	}
  9261  	if got, want := diags.Err().Error(), "Provider produced inconsistent result after apply"; !strings.Contains(got, want) {
  9262  		t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want)
  9263  	}
  9264  }
  9265  
  9266  // Issue 19908 was about retaining an existing object in the state when an
  9267  // update to it fails and the provider does not return a partially-updated
  9268  // value for it. Previously we were incorrectly removing it from the state
  9269  // in that case, but instead it should be retained so the update can be
  9270  // retried.
  9271  func TestContext2Apply_issue19908(t *testing.T) {
  9272  	m := testModule(t, "apply-issue19908")
  9273  	p := testProvider("test")
  9274  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9275  		ResourceTypes: map[string]*configschema.Block{
  9276  			"test": {
  9277  				Attributes: map[string]*configschema.Attribute{
  9278  					"baz": {Type: cty.String, Required: true},
  9279  				},
  9280  			},
  9281  		},
  9282  	})
  9283  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  9284  		return providers.PlanResourceChangeResponse{
  9285  			PlannedState: req.ProposedNewState,
  9286  		}
  9287  	}
  9288  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9289  		var diags tfdiags.Diagnostics
  9290  		diags = diags.Append(fmt.Errorf("update failed"))
  9291  		return providers.ApplyResourceChangeResponse{
  9292  			Diagnostics: diags,
  9293  		}
  9294  	}
  9295  	ctx := testContext2(t, &ContextOpts{
  9296  		Providers: map[addrs.Provider]providers.Factory{
  9297  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9298  		},
  9299  	})
  9300  
  9301  	state := states.BuildState(func(s *states.SyncState) {
  9302  		s.SetResourceInstanceCurrent(
  9303  			addrs.Resource{
  9304  				Mode: addrs.ManagedResourceMode,
  9305  				Type: "test",
  9306  				Name: "foo",
  9307  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  9308  			&states.ResourceInstanceObjectSrc{
  9309  				AttrsJSON: []byte(`{"baz":"old"}`),
  9310  				Status:    states.ObjectReady,
  9311  			},
  9312  			addrs.AbsProviderConfig{
  9313  				Provider: addrs.NewDefaultProvider("test"),
  9314  				Module:   addrs.RootModule,
  9315  			},
  9316  		)
  9317  	})
  9318  
  9319  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9320  	assertNoErrors(t, diags)
  9321  
  9322  	state, diags = ctx.Apply(plan, m)
  9323  	if !diags.HasErrors() {
  9324  		t.Fatalf("apply succeeded; want error")
  9325  	}
  9326  	if got, want := diags.Err().Error(), "update failed"; !strings.Contains(got, want) {
  9327  		t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want)
  9328  	}
  9329  
  9330  	mod := state.RootModule()
  9331  	rs := mod.Resources["test.foo"]
  9332  	if rs == nil {
  9333  		t.Fatalf("test.foo not in state after apply, but should be")
  9334  	}
  9335  	is := rs.Instances[addrs.NoKey]
  9336  	if is == nil {
  9337  		t.Fatalf("test.foo not in state after apply, but should be")
  9338  	}
  9339  	obj := is.Current
  9340  	if obj == nil {
  9341  		t.Fatalf("test.foo has no current object in state after apply, but should do")
  9342  	}
  9343  
  9344  	if got, want := obj.Status, states.ObjectReady; got != want {
  9345  		t.Errorf("test.foo has wrong status %s after apply; want %s", got, want)
  9346  	}
  9347  	if got, want := obj.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) {
  9348  		t.Errorf("test.foo attributes JSON doesn't contain %s after apply\ngot: %s", want, got)
  9349  	}
  9350  }
  9351  
  9352  func TestContext2Apply_invalidIndexRef(t *testing.T) {
  9353  	p := testProvider("test")
  9354  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9355  		ResourceTypes: map[string]*configschema.Block{
  9356  			"test_instance": {
  9357  				Attributes: map[string]*configschema.Attribute{
  9358  					"value": {Type: cty.String, Optional: true, Computed: true},
  9359  				},
  9360  			},
  9361  		},
  9362  	})
  9363  	p.PlanResourceChangeFn = testDiffFn
  9364  
  9365  	m := testModule(t, "apply-invalid-index")
  9366  	c := testContext2(t, &ContextOpts{
  9367  		Providers: map[addrs.Provider]providers.Factory{
  9368  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9369  		},
  9370  	})
  9371  	diags := c.Validate(m)
  9372  	if diags.HasErrors() {
  9373  		t.Fatalf("unexpected validation failure: %s", diags.Err())
  9374  	}
  9375  
  9376  	wantErr := `The given key does not identify an element in this collection value`
  9377  	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
  9378  
  9379  	if !diags.HasErrors() {
  9380  		t.Fatalf("plan succeeded; want error")
  9381  	}
  9382  	gotErr := diags.Err().Error()
  9383  
  9384  	if !strings.Contains(gotErr, wantErr) {
  9385  		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErr, wantErr)
  9386  	}
  9387  }
  9388  
  9389  func TestContext2Apply_moduleReplaceCycle(t *testing.T) {
  9390  	for _, mode := range []string{"normal", "cbd"} {
  9391  		var m *configs.Config
  9392  
  9393  		switch mode {
  9394  		case "normal":
  9395  			m = testModule(t, "apply-module-replace-cycle")
  9396  		case "cbd":
  9397  			m = testModule(t, "apply-module-replace-cycle-cbd")
  9398  		}
  9399  
  9400  		p := testProvider("aws")
  9401  		p.PlanResourceChangeFn = testDiffFn
  9402  
  9403  		instanceSchema := &configschema.Block{
  9404  			Attributes: map[string]*configschema.Attribute{
  9405  				"id":          {Type: cty.String, Computed: true},
  9406  				"require_new": {Type: cty.String, Optional: true},
  9407  			},
  9408  		}
  9409  
  9410  		p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9411  			ResourceTypes: map[string]*configschema.Block{
  9412  				"aws_instance": instanceSchema,
  9413  			},
  9414  		})
  9415  
  9416  		state := states.NewState()
  9417  		modA := state.EnsureModule(addrs.RootModuleInstance.Child("a", addrs.NoKey))
  9418  		modA.SetResourceInstanceCurrent(
  9419  			addrs.Resource{
  9420  				Mode: addrs.ManagedResourceMode,
  9421  				Type: "aws_instance",
  9422  				Name: "a",
  9423  			}.Instance(addrs.NoKey),
  9424  			&states.ResourceInstanceObjectSrc{
  9425  				Status:              states.ObjectReady,
  9426  				AttrsJSON:           []byte(`{"id":"a","require_new":"old"}`),
  9427  				CreateBeforeDestroy: mode == "cbd",
  9428  			},
  9429  			addrs.AbsProviderConfig{
  9430  				Provider: addrs.NewDefaultProvider("aws"),
  9431  				Module:   addrs.RootModule,
  9432  			},
  9433  		)
  9434  
  9435  		modB := state.EnsureModule(addrs.RootModuleInstance.Child("b", addrs.NoKey))
  9436  		modB.SetResourceInstanceCurrent(
  9437  			addrs.Resource{
  9438  				Mode: addrs.ManagedResourceMode,
  9439  				Type: "aws_instance",
  9440  				Name: "b",
  9441  			}.Instance(addrs.IntKey(0)),
  9442  			&states.ResourceInstanceObjectSrc{
  9443  				Status:    states.ObjectReady,
  9444  				AttrsJSON: []byte(`{"id":"b","require_new":"old"}`),
  9445  			},
  9446  			addrs.AbsProviderConfig{
  9447  				Provider: addrs.NewDefaultProvider("aws"),
  9448  				Module:   addrs.RootModule,
  9449  			},
  9450  		)
  9451  
  9452  		aBefore, _ := plans.NewDynamicValue(
  9453  			cty.ObjectVal(map[string]cty.Value{
  9454  				"id":          cty.StringVal("a"),
  9455  				"require_new": cty.StringVal("old"),
  9456  			}), instanceSchema.ImpliedType())
  9457  		aAfter, _ := plans.NewDynamicValue(
  9458  			cty.ObjectVal(map[string]cty.Value{
  9459  				"id":          cty.UnknownVal(cty.String),
  9460  				"require_new": cty.StringVal("new"),
  9461  			}), instanceSchema.ImpliedType())
  9462  		bBefore, _ := plans.NewDynamicValue(
  9463  			cty.ObjectVal(map[string]cty.Value{
  9464  				"id":          cty.StringVal("b"),
  9465  				"require_new": cty.StringVal("old"),
  9466  			}), instanceSchema.ImpliedType())
  9467  		bAfter, _ := plans.NewDynamicValue(
  9468  			cty.ObjectVal(map[string]cty.Value{
  9469  				"id":          cty.UnknownVal(cty.String),
  9470  				"require_new": cty.UnknownVal(cty.String),
  9471  			}), instanceSchema.ImpliedType())
  9472  
  9473  		var aAction plans.Action
  9474  		switch mode {
  9475  		case "normal":
  9476  			aAction = plans.DeleteThenCreate
  9477  		case "cbd":
  9478  			aAction = plans.CreateThenDelete
  9479  		}
  9480  
  9481  		ctx := testContext2(t, &ContextOpts{
  9482  			Providers: map[addrs.Provider]providers.Factory{
  9483  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  9484  			},
  9485  		})
  9486  
  9487  		changes := &plans.Changes{
  9488  			Resources: []*plans.ResourceInstanceChangeSrc{
  9489  				{
  9490  					Addr: addrs.Resource{
  9491  						Mode: addrs.ManagedResourceMode,
  9492  						Type: "aws_instance",
  9493  						Name: "a",
  9494  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("a", addrs.NoKey)),
  9495  					ProviderAddr: addrs.AbsProviderConfig{
  9496  						Provider: addrs.NewDefaultProvider("aws"),
  9497  						Module:   addrs.RootModule,
  9498  					},
  9499  					ChangeSrc: plans.ChangeSrc{
  9500  						Action: aAction,
  9501  						Before: aBefore,
  9502  						After:  aAfter,
  9503  					},
  9504  				},
  9505  				{
  9506  					Addr: addrs.Resource{
  9507  						Mode: addrs.ManagedResourceMode,
  9508  						Type: "aws_instance",
  9509  						Name: "b",
  9510  					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("b", addrs.NoKey)),
  9511  					ProviderAddr: addrs.AbsProviderConfig{
  9512  						Provider: addrs.NewDefaultProvider("aws"),
  9513  						Module:   addrs.RootModule,
  9514  					},
  9515  					ChangeSrc: plans.ChangeSrc{
  9516  						Action: plans.DeleteThenCreate,
  9517  						Before: bBefore,
  9518  						After:  bAfter,
  9519  					},
  9520  				},
  9521  			},
  9522  		}
  9523  
  9524  		plan := &plans.Plan{
  9525  			UIMode:       plans.NormalMode,
  9526  			Changes:      changes,
  9527  			PriorState:   state.DeepCopy(),
  9528  			PrevRunState: state.DeepCopy(),
  9529  		}
  9530  
  9531  		t.Run(mode, func(t *testing.T) {
  9532  			_, diags := ctx.Apply(plan, m)
  9533  			if diags.HasErrors() {
  9534  				t.Fatal(diags.Err())
  9535  			}
  9536  		})
  9537  	}
  9538  }
  9539  
  9540  func TestContext2Apply_destroyDataCycle(t *testing.T) {
  9541  	m, snap := testModuleWithSnapshot(t, "apply-destroy-data-cycle")
  9542  	p := testProvider("null")
  9543  	p.PlanResourceChangeFn = testDiffFn
  9544  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  9545  		return providers.ReadDataSourceResponse{
  9546  			State: cty.ObjectVal(map[string]cty.Value{
  9547  				"id":  cty.StringVal("new"),
  9548  				"foo": cty.NullVal(cty.String),
  9549  			}),
  9550  		}
  9551  	}
  9552  
  9553  	tp := testProvider("test")
  9554  	tp.PlanResourceChangeFn = testDiffFn
  9555  
  9556  	state := states.NewState()
  9557  	root := state.EnsureModule(addrs.RootModuleInstance)
  9558  	root.SetResourceInstanceCurrent(
  9559  		addrs.Resource{
  9560  			Mode: addrs.ManagedResourceMode,
  9561  			Type: "null_resource",
  9562  			Name: "a",
  9563  		}.Instance(addrs.IntKey(0)),
  9564  		&states.ResourceInstanceObjectSrc{
  9565  			Status:    states.ObjectReady,
  9566  			AttrsJSON: []byte(`{"id":"a"}`),
  9567  		},
  9568  		addrs.AbsProviderConfig{
  9569  			Provider: addrs.NewDefaultProvider("null"),
  9570  			Module:   addrs.RootModule,
  9571  		},
  9572  	)
  9573  	root.SetResourceInstanceCurrent(
  9574  		addrs.Resource{
  9575  			Mode: addrs.ManagedResourceMode,
  9576  			Type: "test_resource",
  9577  			Name: "a",
  9578  		}.Instance(addrs.IntKey(0)),
  9579  		&states.ResourceInstanceObjectSrc{
  9580  			Status:    states.ObjectReady,
  9581  			AttrsJSON: []byte(`{"id":"a"}`),
  9582  			Dependencies: []addrs.ConfigResource{
  9583  				{
  9584  					Resource: addrs.Resource{
  9585  						Mode: addrs.DataResourceMode,
  9586  						Type: "null_data_source",
  9587  						Name: "d",
  9588  					},
  9589  					Module: addrs.RootModule,
  9590  				},
  9591  			},
  9592  		},
  9593  		addrs.AbsProviderConfig{
  9594  			Provider: addrs.NewDefaultProvider("test"),
  9595  			Module:   addrs.RootModule,
  9596  		},
  9597  	)
  9598  	root.SetResourceInstanceCurrent(
  9599  		addrs.Resource{
  9600  			Mode: addrs.DataResourceMode,
  9601  			Type: "null_data_source",
  9602  			Name: "d",
  9603  		}.Instance(addrs.NoKey),
  9604  		&states.ResourceInstanceObjectSrc{
  9605  			Status:    states.ObjectReady,
  9606  			AttrsJSON: []byte(`{"id":"old"}`),
  9607  		},
  9608  		addrs.AbsProviderConfig{
  9609  			Provider: addrs.NewDefaultProvider("null"),
  9610  			Module:   addrs.RootModule,
  9611  		},
  9612  	)
  9613  
  9614  	Providers := map[addrs.Provider]providers.Factory{
  9615  		addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  9616  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(tp),
  9617  	}
  9618  
  9619  	ctx := testContext2(t, &ContextOpts{
  9620  		Providers: Providers,
  9621  	})
  9622  
  9623  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  9624  		Mode: plans.DestroyMode,
  9625  	})
  9626  	diags.HasErrors()
  9627  	if diags.HasErrors() {
  9628  		t.Fatalf("diags: %s", diags.Err())
  9629  	}
  9630  
  9631  	// We'll marshal and unmarshal the plan here, to ensure that we have
  9632  	// a clean new context as would be created if we separately ran
  9633  	// tofu plan -out=tfplan && tofu apply tfplan
  9634  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  9635  	if err != nil {
  9636  		t.Fatal(err)
  9637  	}
  9638  	ctxOpts.Providers = Providers
  9639  	ctx, diags = NewContext(ctxOpts)
  9640  	if diags.HasErrors() {
  9641  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  9642  	}
  9643  
  9644  	tp.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  9645  		foo := req.Config.GetAttr("foo")
  9646  		if !foo.IsKnown() {
  9647  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown config value foo"))
  9648  			return resp
  9649  		}
  9650  
  9651  		if foo.AsString() != "new" {
  9652  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("wrong config value: %q", foo.AsString()))
  9653  		}
  9654  		return resp
  9655  	}
  9656  
  9657  	_, diags = ctx.Apply(plan, m)
  9658  	if diags.HasErrors() {
  9659  		t.Fatalf("diags: %s", diags.Err())
  9660  	}
  9661  }
  9662  
  9663  func TestContext2Apply_taintedDestroyFailure(t *testing.T) {
  9664  	m := testModule(t, "apply-destroy-tainted")
  9665  	p := testProvider("test")
  9666  	p.PlanResourceChangeFn = testDiffFn
  9667  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  9668  		// All destroys fail.
  9669  		if req.PlannedState.IsNull() {
  9670  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure"))
  9671  			return
  9672  		}
  9673  
  9674  		// c will also fail to create, meaning the existing tainted instance
  9675  		// becomes deposed, ans is then promoted back to current.
  9676  		// only C has a foo attribute
  9677  		planned := req.PlannedState.AsValueMap()
  9678  		foo, ok := planned["foo"]
  9679  		if ok && !foo.IsNull() && foo.AsString() == "c" {
  9680  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure"))
  9681  			return
  9682  		}
  9683  
  9684  		return testApplyFn(req)
  9685  	}
  9686  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9687  		ResourceTypes: map[string]*configschema.Block{
  9688  			"test_instance": {
  9689  				Attributes: map[string]*configschema.Attribute{
  9690  					"id": {
  9691  						Type:     cty.String,
  9692  						Computed: true,
  9693  					},
  9694  					"foo": {
  9695  						Type:     cty.String,
  9696  						Optional: true,
  9697  					},
  9698  				},
  9699  			},
  9700  		},
  9701  	})
  9702  
  9703  	state := states.NewState()
  9704  	root := state.EnsureModule(addrs.RootModuleInstance)
  9705  	root.SetResourceInstanceCurrent(
  9706  		addrs.Resource{
  9707  			Mode: addrs.ManagedResourceMode,
  9708  			Type: "test_instance",
  9709  			Name: "a",
  9710  		}.Instance(addrs.NoKey),
  9711  		&states.ResourceInstanceObjectSrc{
  9712  			Status:    states.ObjectTainted,
  9713  			AttrsJSON: []byte(`{"id":"a","foo":"a"}`),
  9714  		},
  9715  		addrs.AbsProviderConfig{
  9716  			Provider: addrs.NewDefaultProvider("test"),
  9717  			Module:   addrs.RootModule,
  9718  		},
  9719  	)
  9720  	root.SetResourceInstanceCurrent(
  9721  		addrs.Resource{
  9722  			Mode: addrs.ManagedResourceMode,
  9723  			Type: "test_instance",
  9724  			Name: "b",
  9725  		}.Instance(addrs.NoKey),
  9726  		&states.ResourceInstanceObjectSrc{
  9727  			Status:    states.ObjectTainted,
  9728  			AttrsJSON: []byte(`{"id":"b","foo":"b"}`),
  9729  		},
  9730  		addrs.AbsProviderConfig{
  9731  			Provider: addrs.NewDefaultProvider("test"),
  9732  			Module:   addrs.RootModule,
  9733  		},
  9734  	)
  9735  	root.SetResourceInstanceCurrent(
  9736  		addrs.Resource{
  9737  			Mode: addrs.ManagedResourceMode,
  9738  			Type: "test_instance",
  9739  			Name: "c",
  9740  		}.Instance(addrs.NoKey),
  9741  		&states.ResourceInstanceObjectSrc{
  9742  			Status:    states.ObjectTainted,
  9743  			AttrsJSON: []byte(`{"id":"c","foo":"old"}`),
  9744  		},
  9745  		addrs.AbsProviderConfig{
  9746  			Provider: addrs.NewDefaultProvider("test"),
  9747  			Module:   addrs.RootModule,
  9748  		},
  9749  	)
  9750  
  9751  	Providers := map[addrs.Provider]providers.Factory{
  9752  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9753  	}
  9754  
  9755  	ctx := testContext2(t, &ContextOpts{
  9756  		Providers: Providers,
  9757  		Hooks:     []Hook{&testHook{}},
  9758  	})
  9759  
  9760  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9761  	diags.HasErrors()
  9762  	if diags.HasErrors() {
  9763  		t.Fatalf("diags: %s", diags.Err())
  9764  	}
  9765  
  9766  	state, diags = ctx.Apply(plan, m)
  9767  	if !diags.HasErrors() {
  9768  		t.Fatal("expected error")
  9769  	}
  9770  
  9771  	root = state.Module(addrs.RootModuleInstance)
  9772  
  9773  	// the instance that failed to destroy should remain tainted
  9774  	a := root.ResourceInstance(addrs.Resource{
  9775  		Mode: addrs.ManagedResourceMode,
  9776  		Type: "test_instance",
  9777  		Name: "a",
  9778  	}.Instance(addrs.NoKey))
  9779  
  9780  	if a.Current.Status != states.ObjectTainted {
  9781  		t.Fatal("test_instance.a should be tainted")
  9782  	}
  9783  
  9784  	// b is create_before_destroy, and the destroy failed, so there should be 1
  9785  	// deposed instance.
  9786  	b := root.ResourceInstance(addrs.Resource{
  9787  		Mode: addrs.ManagedResourceMode,
  9788  		Type: "test_instance",
  9789  		Name: "b",
  9790  	}.Instance(addrs.NoKey))
  9791  
  9792  	if b.Current.Status != states.ObjectReady {
  9793  		t.Fatal("test_instance.b should be Ready")
  9794  	}
  9795  
  9796  	if len(b.Deposed) != 1 {
  9797  		t.Fatal("test_instance.b failed to keep deposed instance")
  9798  	}
  9799  
  9800  	// the desposed c instance should be promoted back to Current, and remain
  9801  	// tainted
  9802  	c := root.ResourceInstance(addrs.Resource{
  9803  		Mode: addrs.ManagedResourceMode,
  9804  		Type: "test_instance",
  9805  		Name: "c",
  9806  	}.Instance(addrs.NoKey))
  9807  
  9808  	if c.Current == nil {
  9809  		t.Fatal("test_instance.c has no current instance, but it should")
  9810  	}
  9811  
  9812  	if c.Current.Status != states.ObjectTainted {
  9813  		t.Fatal("test_instance.c should be tainted")
  9814  	}
  9815  
  9816  	if len(c.Deposed) != 0 {
  9817  		t.Fatal("test_instance.c should have no deposed instances")
  9818  	}
  9819  
  9820  	if string(c.Current.AttrsJSON) != `{"foo":"old","id":"c"}` {
  9821  		t.Fatalf("unexpected attrs for c: %q\n", c.Current.AttrsJSON)
  9822  	}
  9823  }
  9824  
  9825  func TestContext2Apply_plannedConnectionRefs(t *testing.T) {
  9826  	m := testModule(t, "apply-plan-connection-refs")
  9827  	p := testProvider("test")
  9828  	p.PlanResourceChangeFn = testDiffFn
  9829  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  9830  		s := req.PlannedState.AsValueMap()
  9831  		// delay "a" slightly, so if the reference edge is missing the "b"
  9832  		// provisioner will see an unknown value.
  9833  		if s["foo"].AsString() == "a" {
  9834  			time.Sleep(500 * time.Millisecond)
  9835  		}
  9836  
  9837  		s["id"] = cty.StringVal("ID")
  9838  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
  9839  			s["type"] = cty.StringVal(req.TypeName)
  9840  		}
  9841  		resp.NewState = cty.ObjectVal(s)
  9842  		return resp
  9843  	}
  9844  
  9845  	provisionerFactory := func() (provisioners.Interface, error) {
  9846  		pr := testProvisioner()
  9847  		pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  9848  			host := req.Connection.GetAttr("host")
  9849  			if host.IsNull() || !host.IsKnown() {
  9850  				resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("invalid host value: %#v", host))
  9851  			}
  9852  
  9853  			return resp
  9854  		}
  9855  		return pr, nil
  9856  	}
  9857  
  9858  	Providers := map[addrs.Provider]providers.Factory{
  9859  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9860  	}
  9861  
  9862  	provisioners := map[string]provisioners.Factory{
  9863  		"shell": provisionerFactory,
  9864  	}
  9865  
  9866  	hook := &testHook{}
  9867  	ctx := testContext2(t, &ContextOpts{
  9868  		Providers:    Providers,
  9869  		Provisioners: provisioners,
  9870  		Hooks:        []Hook{hook},
  9871  	})
  9872  
  9873  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  9874  	diags.HasErrors()
  9875  	if diags.HasErrors() {
  9876  		t.Fatalf("diags: %s", diags.Err())
  9877  	}
  9878  
  9879  	_, diags = ctx.Apply(plan, m)
  9880  	if diags.HasErrors() {
  9881  		t.Fatalf("diags: %s", diags.Err())
  9882  	}
  9883  }
  9884  
  9885  func TestContext2Apply_cbdCycle(t *testing.T) {
  9886  	m, snap := testModuleWithSnapshot(t, "apply-cbd-cycle")
  9887  	p := testProvider("test")
  9888  	p.PlanResourceChangeFn = testDiffFn
  9889  
  9890  	state := states.NewState()
  9891  	root := state.EnsureModule(addrs.RootModuleInstance)
  9892  	root.SetResourceInstanceCurrent(
  9893  		addrs.Resource{
  9894  			Mode: addrs.ManagedResourceMode,
  9895  			Type: "test_instance",
  9896  			Name: "a",
  9897  		}.Instance(addrs.NoKey),
  9898  		&states.ResourceInstanceObjectSrc{
  9899  			Status:    states.ObjectReady,
  9900  			AttrsJSON: []byte(`{"id":"a","require_new":"old","foo":"b"}`),
  9901  			Dependencies: []addrs.ConfigResource{
  9902  				{
  9903  					Resource: addrs.Resource{
  9904  						Mode: addrs.ManagedResourceMode,
  9905  						Type: "test_instance",
  9906  						Name: "b",
  9907  					},
  9908  					Module: addrs.RootModule,
  9909  				},
  9910  				{
  9911  					Resource: addrs.Resource{
  9912  						Mode: addrs.ManagedResourceMode,
  9913  						Type: "test_instance",
  9914  						Name: "c",
  9915  					},
  9916  					Module: addrs.RootModule,
  9917  				},
  9918  			},
  9919  		},
  9920  		addrs.AbsProviderConfig{
  9921  			Provider: addrs.NewDefaultProvider("test"),
  9922  			Module:   addrs.RootModule,
  9923  		},
  9924  	)
  9925  	root.SetResourceInstanceCurrent(
  9926  		addrs.Resource{
  9927  			Mode: addrs.ManagedResourceMode,
  9928  			Type: "test_instance",
  9929  			Name: "b",
  9930  		}.Instance(addrs.NoKey),
  9931  		&states.ResourceInstanceObjectSrc{
  9932  			Status:    states.ObjectReady,
  9933  			AttrsJSON: []byte(`{"id":"b","require_new":"old","foo":"c"}`),
  9934  			Dependencies: []addrs.ConfigResource{
  9935  				{
  9936  					Resource: addrs.Resource{
  9937  						Mode: addrs.ManagedResourceMode,
  9938  						Type: "test_instance",
  9939  						Name: "c",
  9940  					},
  9941  					Module: addrs.RootModule,
  9942  				},
  9943  			},
  9944  		},
  9945  		addrs.AbsProviderConfig{
  9946  			Provider: addrs.NewDefaultProvider("test"),
  9947  			Module:   addrs.RootModule,
  9948  		},
  9949  	)
  9950  	root.SetResourceInstanceCurrent(
  9951  		addrs.Resource{
  9952  			Mode: addrs.ManagedResourceMode,
  9953  			Type: "test_instance",
  9954  			Name: "c",
  9955  		}.Instance(addrs.NoKey),
  9956  		&states.ResourceInstanceObjectSrc{
  9957  			Status:    states.ObjectReady,
  9958  			AttrsJSON: []byte(`{"id":"c","require_new":"old"}`),
  9959  		},
  9960  		addrs.AbsProviderConfig{
  9961  			Provider: addrs.NewDefaultProvider("test"),
  9962  			Module:   addrs.RootModule,
  9963  		},
  9964  	)
  9965  
  9966  	Providers := map[addrs.Provider]providers.Factory{
  9967  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9968  	}
  9969  
  9970  	hook := &testHook{}
  9971  	ctx := testContext2(t, &ContextOpts{
  9972  		Providers: Providers,
  9973  		Hooks:     []Hook{hook},
  9974  	})
  9975  
  9976  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9977  	diags.HasErrors()
  9978  	if diags.HasErrors() {
  9979  		t.Fatalf("diags: %s", diags.Err())
  9980  	}
  9981  
  9982  	// We'll marshal and unmarshal the plan here, to ensure that we have
  9983  	// a clean new context as would be created if we separately ran
  9984  	// tofu plan -out=tfplan && tofu apply tfplan
  9985  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  9986  	if err != nil {
  9987  		t.Fatal(err)
  9988  	}
  9989  	ctxOpts.Providers = Providers
  9990  	ctx, diags = NewContext(ctxOpts)
  9991  	if diags.HasErrors() {
  9992  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  9993  	}
  9994  
  9995  	_, diags = ctx.Apply(plan, m)
  9996  	if diags.HasErrors() {
  9997  		t.Fatalf("diags: %s", diags.Err())
  9998  	}
  9999  }
 10000  
 10001  func TestContext2Apply_ProviderMeta_apply_set(t *testing.T) {
 10002  	m := testModule(t, "provider-meta-set")
 10003  	p := testProvider("test")
 10004  	p.PlanResourceChangeFn = testDiffFn
 10005  	schema := p.ProviderSchema()
 10006  	schema.ProviderMeta = &configschema.Block{
 10007  		Attributes: map[string]*configschema.Attribute{
 10008  			"baz": {
 10009  				Type:     cty.String,
 10010  				Required: true,
 10011  			},
 10012  		},
 10013  	}
 10014  
 10015  	var pmMu sync.Mutex
 10016  	arcPMs := map[string]cty.Value{}
 10017  
 10018  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
 10019  		pmMu.Lock()
 10020  		defer pmMu.Unlock()
 10021  		arcPMs[req.TypeName] = req.ProviderMeta
 10022  
 10023  		s := req.PlannedState.AsValueMap()
 10024  		s["id"] = cty.StringVal("ID")
 10025  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
 10026  			s["type"] = cty.StringVal(req.TypeName)
 10027  		}
 10028  		return providers.ApplyResourceChangeResponse{
 10029  			NewState: cty.ObjectVal(s),
 10030  		}
 10031  	}
 10032  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10033  	ctx := testContext2(t, &ContextOpts{
 10034  		Providers: map[addrs.Provider]providers.Factory{
 10035  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10036  		},
 10037  	})
 10038  
 10039  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10040  	assertNoErrors(t, diags)
 10041  
 10042  	_, diags = ctx.Apply(plan, m)
 10043  	assertNoErrors(t, diags)
 10044  
 10045  	if !p.ApplyResourceChangeCalled {
 10046  		t.Fatalf("ApplyResourceChange not called")
 10047  	}
 10048  
 10049  	expectations := map[string]cty.Value{}
 10050  
 10051  	if pm, ok := arcPMs["test_resource"]; !ok {
 10052  		t.Fatalf("sub-module ApplyResourceChange not called")
 10053  	} else if pm.IsNull() {
 10054  		t.Fatalf("null ProviderMeta in sub-module ApplyResourceChange")
 10055  	} else {
 10056  		expectations["quux-submodule"] = pm
 10057  	}
 10058  
 10059  	if pm, ok := arcPMs["test_instance"]; !ok {
 10060  		t.Fatalf("root module ApplyResourceChange not called")
 10061  	} else if pm.IsNull() {
 10062  		t.Fatalf("null ProviderMeta in root module ApplyResourceChange")
 10063  	} else {
 10064  		expectations["quux"] = pm
 10065  	}
 10066  
 10067  	type metaStruct struct {
 10068  		Baz string `cty:"baz"`
 10069  	}
 10070  
 10071  	for expected, v := range expectations {
 10072  		var meta metaStruct
 10073  		err := gocty.FromCtyValue(v, &meta)
 10074  		if err != nil {
 10075  			t.Fatalf("Error parsing cty value: %s", err)
 10076  		}
 10077  		if meta.Baz != expected {
 10078  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10079  		}
 10080  	}
 10081  }
 10082  
 10083  func TestContext2Apply_ProviderMeta_apply_unset(t *testing.T) {
 10084  	m := testModule(t, "provider-meta-unset")
 10085  	p := testProvider("test")
 10086  	p.PlanResourceChangeFn = testDiffFn
 10087  	schema := p.ProviderSchema()
 10088  	schema.ProviderMeta = &configschema.Block{
 10089  		Attributes: map[string]*configschema.Attribute{
 10090  			"baz": {
 10091  				Type:     cty.String,
 10092  				Required: true,
 10093  			},
 10094  		},
 10095  	}
 10096  	var pmMu sync.Mutex
 10097  	arcPMs := map[string]cty.Value{}
 10098  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
 10099  		pmMu.Lock()
 10100  		defer pmMu.Unlock()
 10101  		arcPMs[req.TypeName] = req.ProviderMeta
 10102  
 10103  		s := req.PlannedState.AsValueMap()
 10104  		s["id"] = cty.StringVal("ID")
 10105  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
 10106  			s["type"] = cty.StringVal(req.TypeName)
 10107  		}
 10108  		return providers.ApplyResourceChangeResponse{
 10109  			NewState: cty.ObjectVal(s),
 10110  		}
 10111  	}
 10112  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10113  	ctx := testContext2(t, &ContextOpts{
 10114  		Providers: map[addrs.Provider]providers.Factory{
 10115  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10116  		},
 10117  	})
 10118  
 10119  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10120  	assertNoErrors(t, diags)
 10121  
 10122  	_, diags = ctx.Apply(plan, m)
 10123  	assertNoErrors(t, diags)
 10124  
 10125  	if !p.ApplyResourceChangeCalled {
 10126  		t.Fatalf("ApplyResourceChange not called")
 10127  	}
 10128  
 10129  	if pm, ok := arcPMs["test_resource"]; !ok {
 10130  		t.Fatalf("sub-module ApplyResourceChange not called")
 10131  	} else if !pm.IsNull() {
 10132  		t.Fatalf("non-null ProviderMeta in sub-module ApplyResourceChange: %+v", pm)
 10133  	}
 10134  
 10135  	if pm, ok := arcPMs["test_instance"]; !ok {
 10136  		t.Fatalf("root module ApplyResourceChange not called")
 10137  	} else if !pm.IsNull() {
 10138  		t.Fatalf("non-null ProviderMeta in root module ApplyResourceChange: %+v", pm)
 10139  	}
 10140  }
 10141  
 10142  func TestContext2Apply_ProviderMeta_plan_set(t *testing.T) {
 10143  	m := testModule(t, "provider-meta-set")
 10144  	p := testProvider("test")
 10145  	schema := p.ProviderSchema()
 10146  	schema.ProviderMeta = &configschema.Block{
 10147  		Attributes: map[string]*configschema.Attribute{
 10148  			"baz": {
 10149  				Type:     cty.String,
 10150  				Required: true,
 10151  			},
 10152  		},
 10153  	}
 10154  	prcPMs := map[string]cty.Value{}
 10155  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
 10156  		prcPMs[req.TypeName] = req.ProviderMeta
 10157  		return providers.PlanResourceChangeResponse{
 10158  			PlannedState: req.ProposedNewState,
 10159  		}
 10160  	}
 10161  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10162  	ctx := testContext2(t, &ContextOpts{
 10163  		Providers: map[addrs.Provider]providers.Factory{
 10164  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10165  		},
 10166  	})
 10167  
 10168  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10169  	assertNoErrors(t, diags)
 10170  
 10171  	if !p.PlanResourceChangeCalled {
 10172  		t.Fatalf("PlanResourceChange not called")
 10173  	}
 10174  
 10175  	expectations := map[string]cty.Value{}
 10176  
 10177  	if pm, ok := prcPMs["test_resource"]; !ok {
 10178  		t.Fatalf("sub-module PlanResourceChange not called")
 10179  	} else if pm.IsNull() {
 10180  		t.Fatalf("null ProviderMeta in sub-module PlanResourceChange")
 10181  	} else {
 10182  		expectations["quux-submodule"] = pm
 10183  	}
 10184  
 10185  	if pm, ok := prcPMs["test_instance"]; !ok {
 10186  		t.Fatalf("root module PlanResourceChange not called")
 10187  	} else if pm.IsNull() {
 10188  		t.Fatalf("null ProviderMeta in root module PlanResourceChange")
 10189  	} else {
 10190  		expectations["quux"] = pm
 10191  	}
 10192  
 10193  	type metaStruct struct {
 10194  		Baz string `cty:"baz"`
 10195  	}
 10196  
 10197  	for expected, v := range expectations {
 10198  		var meta metaStruct
 10199  		err := gocty.FromCtyValue(v, &meta)
 10200  		if err != nil {
 10201  			t.Fatalf("Error parsing cty value: %s", err)
 10202  		}
 10203  		if meta.Baz != expected {
 10204  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10205  		}
 10206  	}
 10207  }
 10208  
 10209  func TestContext2Apply_ProviderMeta_plan_unset(t *testing.T) {
 10210  	m := testModule(t, "provider-meta-unset")
 10211  	p := testProvider("test")
 10212  	schema := p.ProviderSchema()
 10213  	schema.ProviderMeta = &configschema.Block{
 10214  		Attributes: map[string]*configschema.Attribute{
 10215  			"baz": {
 10216  				Type:     cty.String,
 10217  				Required: true,
 10218  			},
 10219  		},
 10220  	}
 10221  	prcPMs := map[string]cty.Value{}
 10222  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
 10223  		prcPMs[req.TypeName] = req.ProviderMeta
 10224  		return providers.PlanResourceChangeResponse{
 10225  			PlannedState: req.ProposedNewState,
 10226  		}
 10227  	}
 10228  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10229  	ctx := testContext2(t, &ContextOpts{
 10230  		Providers: map[addrs.Provider]providers.Factory{
 10231  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10232  		},
 10233  	})
 10234  
 10235  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10236  	assertNoErrors(t, diags)
 10237  
 10238  	if !p.PlanResourceChangeCalled {
 10239  		t.Fatalf("PlanResourceChange not called")
 10240  	}
 10241  
 10242  	if pm, ok := prcPMs["test_resource"]; !ok {
 10243  		t.Fatalf("sub-module PlanResourceChange not called")
 10244  	} else if !pm.IsNull() {
 10245  		t.Fatalf("non-null ProviderMeta in sub-module PlanResourceChange: %+v", pm)
 10246  	}
 10247  
 10248  	if pm, ok := prcPMs["test_instance"]; !ok {
 10249  		t.Fatalf("root module PlanResourceChange not called")
 10250  	} else if !pm.IsNull() {
 10251  		t.Fatalf("non-null ProviderMeta in root module PlanResourceChange: %+v", pm)
 10252  	}
 10253  }
 10254  
 10255  func TestContext2Apply_ProviderMeta_plan_setNoSchema(t *testing.T) {
 10256  	m := testModule(t, "provider-meta-set")
 10257  	p := testProvider("test")
 10258  	p.PlanResourceChangeFn = testDiffFn
 10259  	ctx := testContext2(t, &ContextOpts{
 10260  		Providers: map[addrs.Provider]providers.Factory{
 10261  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10262  		},
 10263  	})
 10264  
 10265  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10266  	if !diags.HasErrors() {
 10267  		t.Fatalf("plan supposed to error, has no errors")
 10268  	}
 10269  
 10270  	var rootErr, subErr bool
 10271  	errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks"
 10272  	for _, diag := range diags {
 10273  		if diag.Description().Summary != "Provider registry.opentofu.org/hashicorp/test doesn't support provider_meta" {
 10274  			t.Errorf("Unexpected error: %+v", diag.Description())
 10275  		}
 10276  		switch diag.Description().Detail {
 10277  		case fmt.Sprintf(errorSummary, "instance"):
 10278  			rootErr = true
 10279  		case fmt.Sprintf(errorSummary, "resource"):
 10280  			subErr = true
 10281  		default:
 10282  			t.Errorf("Unexpected error: %s", diag.Description())
 10283  		}
 10284  	}
 10285  	if !rootErr {
 10286  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10287  	}
 10288  	if !subErr {
 10289  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10290  	}
 10291  }
 10292  
 10293  func TestContext2Apply_ProviderMeta_plan_setInvalid(t *testing.T) {
 10294  	m := testModule(t, "provider-meta-set")
 10295  	p := testProvider("test")
 10296  	p.PlanResourceChangeFn = testDiffFn
 10297  	schema := p.ProviderSchema()
 10298  	schema.ProviderMeta = &configschema.Block{
 10299  		Attributes: map[string]*configschema.Attribute{
 10300  			"quux": {
 10301  				Type:     cty.String,
 10302  				Required: true,
 10303  			},
 10304  		},
 10305  	}
 10306  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10307  	ctx := testContext2(t, &ContextOpts{
 10308  		Providers: map[addrs.Provider]providers.Factory{
 10309  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10310  		},
 10311  	})
 10312  
 10313  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10314  	if !diags.HasErrors() {
 10315  		t.Fatalf("plan supposed to error, has no errors")
 10316  	}
 10317  
 10318  	var reqErr, invalidErr bool
 10319  	for _, diag := range diags {
 10320  		switch diag.Description().Summary {
 10321  		case "Missing required argument":
 10322  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10323  				reqErr = true
 10324  			} else {
 10325  				t.Errorf("Unexpected error %+v", diag.Description())
 10326  			}
 10327  		case "Unsupported argument":
 10328  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10329  				invalidErr = true
 10330  			} else {
 10331  				t.Errorf("Unexpected error %+v", diag.Description())
 10332  			}
 10333  		default:
 10334  			t.Errorf("Unexpected error %+v", diag.Description())
 10335  		}
 10336  	}
 10337  	if !reqErr {
 10338  		t.Errorf("Expected missing required argument error, none received")
 10339  	}
 10340  	if !invalidErr {
 10341  		t.Errorf("Expected unsupported argument error, none received")
 10342  	}
 10343  }
 10344  
 10345  func TestContext2Apply_ProviderMeta_refresh_set(t *testing.T) {
 10346  	m := testModule(t, "provider-meta-set")
 10347  	p := testProvider("test")
 10348  	p.PlanResourceChangeFn = testDiffFn
 10349  	schema := p.ProviderSchema()
 10350  	schema.ProviderMeta = &configschema.Block{
 10351  		Attributes: map[string]*configschema.Attribute{
 10352  			"baz": {
 10353  				Type:     cty.String,
 10354  				Required: true,
 10355  			},
 10356  		},
 10357  	}
 10358  	rrcPMs := map[string]cty.Value{}
 10359  	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
 10360  		rrcPMs[req.TypeName] = req.ProviderMeta
 10361  		newState, err := p.GetProviderSchemaResponse.ResourceTypes[req.TypeName].Block.CoerceValue(req.PriorState)
 10362  		if err != nil {
 10363  			panic(err)
 10364  		}
 10365  		resp.NewState = newState
 10366  		return resp
 10367  	}
 10368  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10369  	ctx := testContext2(t, &ContextOpts{
 10370  		Providers: map[addrs.Provider]providers.Factory{
 10371  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10372  		},
 10373  	})
 10374  
 10375  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10376  	assertNoErrors(t, diags)
 10377  
 10378  	state, diags := ctx.Apply(plan, m)
 10379  	assertNoErrors(t, diags)
 10380  
 10381  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10382  	assertNoErrors(t, diags)
 10383  
 10384  	if !p.ReadResourceCalled {
 10385  		t.Fatalf("ReadResource not called")
 10386  	}
 10387  
 10388  	expectations := map[string]cty.Value{}
 10389  
 10390  	if pm, ok := rrcPMs["test_resource"]; !ok {
 10391  		t.Fatalf("sub-module ReadResource not called")
 10392  	} else if pm.IsNull() {
 10393  		t.Fatalf("null ProviderMeta in sub-module ReadResource")
 10394  	} else {
 10395  		expectations["quux-submodule"] = pm
 10396  	}
 10397  
 10398  	if pm, ok := rrcPMs["test_instance"]; !ok {
 10399  		t.Fatalf("root module ReadResource not called")
 10400  	} else if pm.IsNull() {
 10401  		t.Fatalf("null ProviderMeta in root module ReadResource")
 10402  	} else {
 10403  		expectations["quux"] = pm
 10404  	}
 10405  
 10406  	type metaStruct struct {
 10407  		Baz string `cty:"baz"`
 10408  	}
 10409  
 10410  	for expected, v := range expectations {
 10411  		var meta metaStruct
 10412  		err := gocty.FromCtyValue(v, &meta)
 10413  		if err != nil {
 10414  			t.Fatalf("Error parsing cty value: %s", err)
 10415  		}
 10416  		if meta.Baz != expected {
 10417  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10418  		}
 10419  	}
 10420  }
 10421  
 10422  func TestContext2Apply_ProviderMeta_refresh_setNoSchema(t *testing.T) {
 10423  	m := testModule(t, "provider-meta-set")
 10424  	p := testProvider("test")
 10425  	p.PlanResourceChangeFn = testDiffFn
 10426  
 10427  	// we need a schema for plan/apply so they don't error
 10428  	schema := p.ProviderSchema()
 10429  	schema.ProviderMeta = &configschema.Block{
 10430  		Attributes: map[string]*configschema.Attribute{
 10431  			"baz": {
 10432  				Type:     cty.String,
 10433  				Required: true,
 10434  			},
 10435  		},
 10436  	}
 10437  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10438  	ctx := testContext2(t, &ContextOpts{
 10439  		Providers: map[addrs.Provider]providers.Factory{
 10440  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10441  		},
 10442  	})
 10443  
 10444  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10445  	assertNoErrors(t, diags)
 10446  
 10447  	state, diags := ctx.Apply(plan, m)
 10448  	assertNoErrors(t, diags)
 10449  
 10450  	// drop the schema before refresh, to test that it errors
 10451  	schema.ProviderMeta = nil
 10452  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10453  	ctx = testContext2(t, &ContextOpts{
 10454  		Providers: map[addrs.Provider]providers.Factory{
 10455  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10456  		},
 10457  	})
 10458  
 10459  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10460  	if !diags.HasErrors() {
 10461  		t.Fatalf("refresh supposed to error, has no errors")
 10462  	}
 10463  
 10464  	var rootErr, subErr bool
 10465  	errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks"
 10466  	for _, diag := range diags {
 10467  		if diag.Description().Summary != "Provider registry.opentofu.org/hashicorp/test doesn't support provider_meta" {
 10468  			t.Errorf("Unexpected error: %+v", diag.Description())
 10469  		}
 10470  		switch diag.Description().Detail {
 10471  		case fmt.Sprintf(errorSummary, "instance"):
 10472  			rootErr = true
 10473  		case fmt.Sprintf(errorSummary, "resource"):
 10474  			subErr = true
 10475  		default:
 10476  			t.Errorf("Unexpected error: %s", diag.Description())
 10477  		}
 10478  	}
 10479  	if !rootErr {
 10480  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10481  	}
 10482  	if !subErr {
 10483  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10484  	}
 10485  }
 10486  
 10487  func TestContext2Apply_ProviderMeta_refresh_setInvalid(t *testing.T) {
 10488  	m := testModule(t, "provider-meta-set")
 10489  	p := testProvider("test")
 10490  	p.PlanResourceChangeFn = testDiffFn
 10491  
 10492  	// we need a matching schema for plan/apply so they don't error
 10493  	schema := p.ProviderSchema()
 10494  	schema.ProviderMeta = &configschema.Block{
 10495  		Attributes: map[string]*configschema.Attribute{
 10496  			"baz": {
 10497  				Type:     cty.String,
 10498  				Required: true,
 10499  			},
 10500  		},
 10501  	}
 10502  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10503  	ctx := testContext2(t, &ContextOpts{
 10504  		Providers: map[addrs.Provider]providers.Factory{
 10505  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10506  		},
 10507  	})
 10508  
 10509  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10510  	assertNoErrors(t, diags)
 10511  
 10512  	state, diags := ctx.Apply(plan, m)
 10513  	assertNoErrors(t, diags)
 10514  
 10515  	// change the schema before refresh, to test that it errors
 10516  	schema.ProviderMeta = &configschema.Block{
 10517  		Attributes: map[string]*configschema.Attribute{
 10518  			"quux": {
 10519  				Type:     cty.String,
 10520  				Required: true,
 10521  			},
 10522  		},
 10523  	}
 10524  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10525  	ctx = testContext2(t, &ContextOpts{
 10526  		Providers: map[addrs.Provider]providers.Factory{
 10527  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10528  		},
 10529  	})
 10530  
 10531  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10532  	if !diags.HasErrors() {
 10533  		t.Fatalf("refresh supposed to error, has no errors")
 10534  	}
 10535  
 10536  	var reqErr, invalidErr bool
 10537  	for _, diag := range diags {
 10538  		switch diag.Description().Summary {
 10539  		case "Missing required argument":
 10540  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10541  				reqErr = true
 10542  			} else {
 10543  				t.Errorf("Unexpected error %+v", diag.Description())
 10544  			}
 10545  		case "Unsupported argument":
 10546  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10547  				invalidErr = true
 10548  			} else {
 10549  				t.Errorf("Unexpected error %+v", diag.Description())
 10550  			}
 10551  		default:
 10552  			t.Errorf("Unexpected error %+v", diag.Description())
 10553  		}
 10554  	}
 10555  	if !reqErr {
 10556  		t.Errorf("Expected missing required argument error, none received")
 10557  	}
 10558  	if !invalidErr {
 10559  		t.Errorf("Expected unsupported argument error, none received")
 10560  	}
 10561  }
 10562  
 10563  func TestContext2Apply_ProviderMeta_refreshdata_set(t *testing.T) {
 10564  	m := testModule(t, "provider-meta-data-set")
 10565  	p := testProvider("test")
 10566  	p.PlanResourceChangeFn = testDiffFn
 10567  	schema := p.ProviderSchema()
 10568  	schema.ProviderMeta = &configschema.Block{
 10569  		Attributes: map[string]*configschema.Attribute{
 10570  			"baz": {
 10571  				Type:     cty.String,
 10572  				Required: true,
 10573  			},
 10574  		},
 10575  	}
 10576  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10577  	ctx := testContext2(t, &ContextOpts{
 10578  		Providers: map[addrs.Provider]providers.Factory{
 10579  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10580  		},
 10581  	})
 10582  	rdsPMs := map[string]cty.Value{}
 10583  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10584  		rdsPMs[req.TypeName] = req.ProviderMeta
 10585  		switch req.TypeName {
 10586  		case "test_data_source":
 10587  			log.Printf("[TRACE] test_data_source RDSR returning")
 10588  			return providers.ReadDataSourceResponse{
 10589  				State: cty.ObjectVal(map[string]cty.Value{
 10590  					"id":  cty.StringVal("yo"),
 10591  					"foo": cty.StringVal("bar"),
 10592  				}),
 10593  			}
 10594  		case "test_file":
 10595  			log.Printf("[TRACE] test_file RDSR returning")
 10596  			return providers.ReadDataSourceResponse{
 10597  				State: cty.ObjectVal(map[string]cty.Value{
 10598  					"id":       cty.StringVal("bar"),
 10599  					"rendered": cty.StringVal("baz"),
 10600  					"template": cty.StringVal(""),
 10601  				}),
 10602  			}
 10603  		default:
 10604  			// config drift, oops
 10605  			log.Printf("[TRACE] unknown request TypeName: %q", req.TypeName)
 10606  			return providers.ReadDataSourceResponse{}
 10607  		}
 10608  	}
 10609  
 10610  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10611  	assertNoErrors(t, diags)
 10612  
 10613  	state, diags := ctx.Apply(plan, m)
 10614  	assertNoErrors(t, diags)
 10615  
 10616  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10617  	assertNoErrors(t, diags)
 10618  
 10619  	if !p.ReadDataSourceCalled {
 10620  		t.Fatalf("ReadDataSource not called")
 10621  	}
 10622  
 10623  	expectations := map[string]cty.Value{}
 10624  
 10625  	if pm, ok := rdsPMs["test_file"]; !ok {
 10626  		t.Fatalf("sub-module ReadDataSource not called")
 10627  	} else if pm.IsNull() {
 10628  		t.Fatalf("null ProviderMeta in sub-module ReadDataSource")
 10629  	} else {
 10630  		expectations["quux-submodule"] = pm
 10631  	}
 10632  
 10633  	if pm, ok := rdsPMs["test_data_source"]; !ok {
 10634  		t.Fatalf("root module ReadDataSource not called")
 10635  	} else if pm.IsNull() {
 10636  		t.Fatalf("null ProviderMeta in root module ReadDataSource")
 10637  	} else {
 10638  		expectations["quux"] = pm
 10639  	}
 10640  
 10641  	type metaStruct struct {
 10642  		Baz string `cty:"baz"`
 10643  	}
 10644  
 10645  	for expected, v := range expectations {
 10646  		var meta metaStruct
 10647  		err := gocty.FromCtyValue(v, &meta)
 10648  		if err != nil {
 10649  			t.Fatalf("Error parsing cty value: %s", err)
 10650  		}
 10651  		if meta.Baz != expected {
 10652  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10653  		}
 10654  	}
 10655  }
 10656  
 10657  func TestContext2Apply_ProviderMeta_refreshdata_unset(t *testing.T) {
 10658  	m := testModule(t, "provider-meta-data-unset")
 10659  	p := testProvider("test")
 10660  	p.PlanResourceChangeFn = testDiffFn
 10661  	schema := p.ProviderSchema()
 10662  	schema.ProviderMeta = &configschema.Block{
 10663  		Attributes: map[string]*configschema.Attribute{
 10664  			"baz": {
 10665  				Type:     cty.String,
 10666  				Required: true,
 10667  			},
 10668  		},
 10669  	}
 10670  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10671  	ctx := testContext2(t, &ContextOpts{
 10672  		Providers: map[addrs.Provider]providers.Factory{
 10673  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10674  		},
 10675  	})
 10676  	rdsPMs := map[string]cty.Value{}
 10677  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10678  		rdsPMs[req.TypeName] = req.ProviderMeta
 10679  		switch req.TypeName {
 10680  		case "test_data_source":
 10681  			return providers.ReadDataSourceResponse{
 10682  				State: cty.ObjectVal(map[string]cty.Value{
 10683  					"id":  cty.StringVal("yo"),
 10684  					"foo": cty.StringVal("bar"),
 10685  				}),
 10686  			}
 10687  		case "test_file":
 10688  			return providers.ReadDataSourceResponse{
 10689  				State: cty.ObjectVal(map[string]cty.Value{
 10690  					"id":       cty.StringVal("bar"),
 10691  					"rendered": cty.StringVal("baz"),
 10692  					"template": cty.StringVal(""),
 10693  				}),
 10694  			}
 10695  		default:
 10696  			// config drift, oops
 10697  			return providers.ReadDataSourceResponse{}
 10698  		}
 10699  	}
 10700  
 10701  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10702  	assertNoErrors(t, diags)
 10703  
 10704  	_, diags = ctx.Apply(plan, m)
 10705  	assertNoErrors(t, diags)
 10706  
 10707  	if !p.ReadDataSourceCalled {
 10708  		t.Fatalf("ReadDataSource not called")
 10709  	}
 10710  
 10711  	if pm, ok := rdsPMs["test_file"]; !ok {
 10712  		t.Fatalf("sub-module ReadDataSource not called")
 10713  	} else if !pm.IsNull() {
 10714  		t.Fatalf("non-null ProviderMeta in sub-module ReadDataSource")
 10715  	}
 10716  
 10717  	if pm, ok := rdsPMs["test_data_source"]; !ok {
 10718  		t.Fatalf("root module ReadDataSource not called")
 10719  	} else if !pm.IsNull() {
 10720  		t.Fatalf("non-null ProviderMeta in root module ReadDataSource")
 10721  	}
 10722  }
 10723  
 10724  func TestContext2Apply_ProviderMeta_refreshdata_setNoSchema(t *testing.T) {
 10725  	m := testModule(t, "provider-meta-data-set")
 10726  	p := testProvider("test")
 10727  	p.PlanResourceChangeFn = testDiffFn
 10728  	ctx := testContext2(t, &ContextOpts{
 10729  		Providers: map[addrs.Provider]providers.Factory{
 10730  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10731  		},
 10732  	})
 10733  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 10734  		State: cty.ObjectVal(map[string]cty.Value{
 10735  			"id":  cty.StringVal("yo"),
 10736  			"foo": cty.StringVal("bar"),
 10737  		}),
 10738  	}
 10739  
 10740  	_, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts)
 10741  	if !diags.HasErrors() {
 10742  		t.Fatalf("refresh supposed to error, has no errors")
 10743  	}
 10744  
 10745  	var rootErr, subErr bool
 10746  	errorSummary := "The resource data.test_%s.foo belongs to a provider that doesn't support provider_meta blocks"
 10747  	for _, diag := range diags {
 10748  		if diag.Description().Summary != "Provider registry.opentofu.org/hashicorp/test doesn't support provider_meta" {
 10749  			t.Errorf("Unexpected error: %+v", diag.Description())
 10750  		}
 10751  		switch diag.Description().Detail {
 10752  		case fmt.Sprintf(errorSummary, "data_source"):
 10753  			rootErr = true
 10754  		case fmt.Sprintf(errorSummary, "file"):
 10755  			subErr = true
 10756  		default:
 10757  			t.Errorf("Unexpected error: %s", diag.Description())
 10758  		}
 10759  	}
 10760  	if !rootErr {
 10761  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10762  	}
 10763  	if !subErr {
 10764  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10765  	}
 10766  }
 10767  
 10768  func TestContext2Apply_ProviderMeta_refreshdata_setInvalid(t *testing.T) {
 10769  	m := testModule(t, "provider-meta-data-set")
 10770  	p := testProvider("test")
 10771  	p.PlanResourceChangeFn = testDiffFn
 10772  	schema := p.ProviderSchema()
 10773  	schema.ProviderMeta = &configschema.Block{
 10774  		Attributes: map[string]*configschema.Attribute{
 10775  			"quux": {
 10776  				Type:     cty.String,
 10777  				Required: true,
 10778  			},
 10779  		},
 10780  	}
 10781  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10782  	ctx := testContext2(t, &ContextOpts{
 10783  		Providers: map[addrs.Provider]providers.Factory{
 10784  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10785  		},
 10786  	})
 10787  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 10788  		State: cty.ObjectVal(map[string]cty.Value{
 10789  			"id":  cty.StringVal("yo"),
 10790  			"foo": cty.StringVal("bar"),
 10791  		}),
 10792  	}
 10793  
 10794  	_, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts)
 10795  	if !diags.HasErrors() {
 10796  		t.Fatalf("refresh supposed to error, has no errors")
 10797  	}
 10798  
 10799  	var reqErr, invalidErr bool
 10800  	for _, diag := range diags {
 10801  		switch diag.Description().Summary {
 10802  		case "Missing required argument":
 10803  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10804  				reqErr = true
 10805  			} else {
 10806  				t.Errorf("Unexpected error %+v", diag.Description())
 10807  			}
 10808  		case "Unsupported argument":
 10809  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10810  				invalidErr = true
 10811  			} else {
 10812  				t.Errorf("Unexpected error %+v", diag.Description())
 10813  			}
 10814  		default:
 10815  			t.Errorf("Unexpected error %+v", diag.Description())
 10816  		}
 10817  	}
 10818  	if !reqErr {
 10819  		t.Errorf("Expected missing required argument error, none received")
 10820  	}
 10821  	if !invalidErr {
 10822  		t.Errorf("Expected unsupported argument error, none received")
 10823  	}
 10824  }
 10825  
 10826  func TestContext2Apply_expandModuleVariables(t *testing.T) {
 10827  	m := testModuleInline(t, map[string]string{
 10828  		"main.tf": `
 10829  module "mod1" {
 10830    for_each = toset(["a"])
 10831    source = "./mod"
 10832  }
 10833  
 10834  module "mod2" {
 10835    source = "./mod"
 10836    in = module.mod1["a"].out
 10837  }
 10838  `,
 10839  		"mod/main.tf": `
 10840  resource "aws_instance" "foo" {
 10841    foo = var.in
 10842  }
 10843  
 10844  variable "in" {
 10845    type = string
 10846    default = "default"
 10847  }
 10848  
 10849  output "out" {
 10850    value = aws_instance.foo.id
 10851  }
 10852  `,
 10853  	})
 10854  
 10855  	p := testProvider("aws")
 10856  	p.PlanResourceChangeFn = testDiffFn
 10857  	p.ApplyResourceChangeFn = testApplyFn
 10858  	ctx := testContext2(t, &ContextOpts{
 10859  		Providers: map[addrs.Provider]providers.Factory{
 10860  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 10861  		},
 10862  	})
 10863  
 10864  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10865  	if diags.HasErrors() {
 10866  		t.Fatal(diags.ErrWithWarnings())
 10867  	}
 10868  
 10869  	state, diags := ctx.Apply(plan, m)
 10870  	if diags.HasErrors() {
 10871  		t.Fatal(diags.ErrWithWarnings())
 10872  	}
 10873  
 10874  	expected := `<no state>
 10875  module.mod1["a"]:
 10876    aws_instance.foo:
 10877      ID = foo
 10878      provider = provider["registry.opentofu.org/hashicorp/aws"]
 10879      foo = default
 10880      type = aws_instance
 10881  
 10882    Outputs:
 10883  
 10884    out = foo
 10885  module.mod2:
 10886    aws_instance.foo:
 10887      ID = foo
 10888      provider = provider["registry.opentofu.org/hashicorp/aws"]
 10889      foo = foo
 10890      type = aws_instance
 10891  
 10892      Dependencies:
 10893        module.mod1.aws_instance.foo`
 10894  
 10895  	if state.String() != expected {
 10896  		t.Fatalf("expected:\n%s\ngot:\n%s\n", expected, state)
 10897  	}
 10898  }
 10899  
 10900  func TestContext2Apply_inheritAndStoreCBD(t *testing.T) {
 10901  	m := testModuleInline(t, map[string]string{
 10902  		"main.tf": `
 10903  resource "aws_instance" "foo" {
 10904  }
 10905  
 10906  resource "aws_instance" "cbd" {
 10907    foo = aws_instance.foo.id
 10908    lifecycle {
 10909      create_before_destroy = true
 10910    }
 10911  }
 10912  `,
 10913  	})
 10914  
 10915  	p := testProvider("aws")
 10916  	p.PlanResourceChangeFn = testDiffFn
 10917  	ctx := testContext2(t, &ContextOpts{
 10918  		Providers: map[addrs.Provider]providers.Factory{
 10919  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 10920  		},
 10921  	})
 10922  
 10923  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10924  	if diags.HasErrors() {
 10925  		t.Fatal(diags.ErrWithWarnings())
 10926  	}
 10927  
 10928  	state, diags := ctx.Apply(plan, m)
 10929  	if diags.HasErrors() {
 10930  		t.Fatal(diags.ErrWithWarnings())
 10931  	}
 10932  
 10933  	foo := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo"))
 10934  	if !foo.Current.CreateBeforeDestroy {
 10935  		t.Fatal("aws_instance.foo should also be create_before_destroy")
 10936  	}
 10937  }
 10938  
 10939  func TestContext2Apply_moduleDependsOn(t *testing.T) {
 10940  	m := testModule(t, "apply-module-depends-on")
 10941  
 10942  	p := testProvider("test")
 10943  
 10944  	// each instance being applied should happen in sequential order
 10945  	applied := int64(0)
 10946  
 10947  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10948  		cfg := req.Config.AsValueMap()
 10949  		foo := cfg["foo"].AsString()
 10950  		ord := atomic.LoadInt64(&applied)
 10951  
 10952  		resp := providers.ReadDataSourceResponse{
 10953  			State: cty.ObjectVal(map[string]cty.Value{
 10954  				"id":  cty.StringVal("data"),
 10955  				"foo": cfg["foo"],
 10956  			}),
 10957  		}
 10958  
 10959  		if foo == "a" && ord < 4 {
 10960  			// due to data source "a"'s module depending on instance 4, this
 10961  			// should not be less than 4
 10962  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source a read too early"))
 10963  		}
 10964  		if foo == "b" && ord < 1 {
 10965  			// due to data source "b"'s module depending on instance 1, this
 10966  			// should not be less than 1
 10967  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source b read too early"))
 10968  		}
 10969  		return resp
 10970  	}
 10971  	p.PlanResourceChangeFn = testDiffFn
 10972  
 10973  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 10974  		state := req.PlannedState.AsValueMap()
 10975  		num, _ := state["num"].AsBigFloat().Float64()
 10976  		ord := int64(num)
 10977  		if !atomic.CompareAndSwapInt64(&applied, ord-1, ord) {
 10978  			actual := atomic.LoadInt64(&applied)
 10979  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("instance %d was applied after %d", ord, actual))
 10980  		}
 10981  
 10982  		state["id"] = cty.StringVal(fmt.Sprintf("test_%d", ord))
 10983  		state["type"] = cty.StringVal("test_instance")
 10984  		resp.NewState = cty.ObjectVal(state)
 10985  
 10986  		return resp
 10987  	}
 10988  
 10989  	ctx := testContext2(t, &ContextOpts{
 10990  		Providers: map[addrs.Provider]providers.Factory{
 10991  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10992  		},
 10993  	})
 10994  
 10995  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10996  	if diags.HasErrors() {
 10997  		t.Fatal(diags.ErrWithWarnings())
 10998  	}
 10999  
 11000  	state, diags := ctx.Apply(plan, m)
 11001  	if diags.HasErrors() {
 11002  		t.Fatal(diags.ErrWithWarnings())
 11003  	}
 11004  
 11005  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
 11006  	if diags.HasErrors() {
 11007  		t.Fatal(diags.ErrWithWarnings())
 11008  	}
 11009  
 11010  	for _, res := range plan.Changes.Resources {
 11011  		if res.Action != plans.NoOp {
 11012  			t.Fatalf("expected NoOp, got %s for %s", res.Action, res.Addr)
 11013  		}
 11014  	}
 11015  }
 11016  
 11017  func TestContext2Apply_moduleSelfReference(t *testing.T) {
 11018  	m := testModuleInline(t, map[string]string{
 11019  		"main.tf": `
 11020  module "test" {
 11021    source = "./test"
 11022  
 11023    a = module.test.b
 11024  }
 11025  
 11026  output "c" {
 11027    value = module.test.c
 11028  }
 11029  `,
 11030  		"test/main.tf": `
 11031  variable "a" {}
 11032  
 11033  resource "test_instance" "test" {
 11034  }
 11035  
 11036  output "b" {
 11037    value = test_instance.test.id
 11038  }
 11039  
 11040  output "c" {
 11041    value = var.a
 11042  }`})
 11043  
 11044  	p := testProvider("test")
 11045  	p.PlanResourceChangeFn = testDiffFn
 11046  	ctx := testContext2(t, &ContextOpts{
 11047  		Providers: map[addrs.Provider]providers.Factory{
 11048  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11049  		},
 11050  	})
 11051  
 11052  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11053  	if diags.HasErrors() {
 11054  		t.Fatal(diags.ErrWithWarnings())
 11055  	}
 11056  
 11057  	state, diags := ctx.Apply(plan, m)
 11058  	if diags.HasErrors() {
 11059  		t.Fatal(diags.ErrWithWarnings())
 11060  	}
 11061  
 11062  	ctx = testContext2(t, &ContextOpts{
 11063  		Providers: map[addrs.Provider]providers.Factory{
 11064  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11065  		},
 11066  	})
 11067  
 11068  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11069  		Mode: plans.DestroyMode,
 11070  	})
 11071  	if diags.HasErrors() {
 11072  		t.Fatal(diags.ErrWithWarnings())
 11073  	}
 11074  
 11075  	state, diags = ctx.Apply(plan, m)
 11076  	if diags.HasErrors() {
 11077  		t.Fatal(diags.ErrWithWarnings())
 11078  	}
 11079  
 11080  	if !state.Empty() {
 11081  		t.Fatal("expected empty state, got:", state)
 11082  	}
 11083  }
 11084  
 11085  func TestContext2Apply_moduleExpandDependsOn(t *testing.T) {
 11086  	m := testModuleInline(t, map[string]string{
 11087  		"main.tf": `
 11088  module "child" {
 11089    count = 1
 11090    source = "./child"
 11091  
 11092    depends_on = [test_instance.a, test_instance.b]
 11093  }
 11094  
 11095  resource "test_instance" "a" {
 11096  }
 11097  
 11098  
 11099  resource "test_instance" "b" {
 11100  }
 11101  `,
 11102  		"child/main.tf": `
 11103  resource "test_instance" "foo" {
 11104  }
 11105  
 11106  output "myoutput" {
 11107    value = "literal string"
 11108  }
 11109  `})
 11110  
 11111  	p := testProvider("test")
 11112  	p.PlanResourceChangeFn = testDiffFn
 11113  	ctx := testContext2(t, &ContextOpts{
 11114  		Providers: map[addrs.Provider]providers.Factory{
 11115  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11116  		},
 11117  	})
 11118  
 11119  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11120  	if diags.HasErrors() {
 11121  		t.Fatal(diags.ErrWithWarnings())
 11122  	}
 11123  
 11124  	state, diags := ctx.Apply(plan, m)
 11125  	if diags.HasErrors() {
 11126  		t.Fatal(diags.ErrWithWarnings())
 11127  	}
 11128  
 11129  	ctx = testContext2(t, &ContextOpts{
 11130  		Providers: map[addrs.Provider]providers.Factory{
 11131  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11132  		},
 11133  	})
 11134  
 11135  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11136  		Mode: plans.DestroyMode,
 11137  	})
 11138  	if diags.HasErrors() {
 11139  		t.Fatal(diags.ErrWithWarnings())
 11140  	}
 11141  
 11142  	state, diags = ctx.Apply(plan, m)
 11143  	if diags.HasErrors() {
 11144  		t.Fatal(diags.ErrWithWarnings())
 11145  	}
 11146  
 11147  	if !state.Empty() {
 11148  		t.Fatal("expected empty state, got:", state)
 11149  	}
 11150  }
 11151  
 11152  func TestContext2Apply_scaleInCBD(t *testing.T) {
 11153  	m := testModuleInline(t, map[string]string{
 11154  		"main.tf": `
 11155  variable "ct" {
 11156    type = number
 11157  }
 11158  
 11159  resource "test_instance" "a" {
 11160    count = var.ct
 11161  }
 11162  
 11163  resource "test_instance" "b" {
 11164    require_new = local.removable
 11165    lifecycle {
 11166  	create_before_destroy = true
 11167    }
 11168  }
 11169  
 11170  resource "test_instance" "c" {
 11171    require_new = test_instance.b.id
 11172    lifecycle {
 11173  	create_before_destroy = true
 11174    }
 11175  }
 11176  
 11177  output "out" {
 11178    value = join(".", test_instance.a[*].id)
 11179  }
 11180  
 11181  locals {
 11182    removable = join(".", test_instance.a[*].id)
 11183  }
 11184  `})
 11185  
 11186  	state := states.NewState()
 11187  	root := state.EnsureModule(addrs.RootModuleInstance)
 11188  	root.SetResourceInstanceCurrent(
 11189  		mustResourceInstanceAddr("test_instance.a[0]").Resource,
 11190  		&states.ResourceInstanceObjectSrc{
 11191  			Status:              states.ObjectReady,
 11192  			AttrsJSON:           []byte(`{"id":"a0"}`),
 11193  			Dependencies:        []addrs.ConfigResource{},
 11194  			CreateBeforeDestroy: true,
 11195  		},
 11196  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
 11197  	)
 11198  	root.SetResourceInstanceCurrent(
 11199  		mustResourceInstanceAddr("test_instance.a[1]").Resource,
 11200  		&states.ResourceInstanceObjectSrc{
 11201  			Status:              states.ObjectReady,
 11202  			AttrsJSON:           []byte(`{"id":"a1"}`),
 11203  			Dependencies:        []addrs.ConfigResource{},
 11204  			CreateBeforeDestroy: true,
 11205  		},
 11206  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
 11207  	)
 11208  	root.SetResourceInstanceCurrent(
 11209  		mustResourceInstanceAddr("test_instance.b").Resource,
 11210  		&states.ResourceInstanceObjectSrc{
 11211  			Status:              states.ObjectReady,
 11212  			AttrsJSON:           []byte(`{"id":"b", "require_new":"old.old"}`),
 11213  			Dependencies:        []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")},
 11214  			CreateBeforeDestroy: true,
 11215  		},
 11216  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
 11217  	)
 11218  	root.SetResourceInstanceCurrent(
 11219  		mustResourceInstanceAddr("test_instance.c").Resource,
 11220  		&states.ResourceInstanceObjectSrc{
 11221  			Status:    states.ObjectReady,
 11222  			AttrsJSON: []byte(`{"id":"c", "require_new":"b"}`),
 11223  			Dependencies: []addrs.ConfigResource{
 11224  				mustConfigResourceAddr("test_instance.a"),
 11225  				mustConfigResourceAddr("test_instance.b"),
 11226  			},
 11227  			CreateBeforeDestroy: true,
 11228  		},
 11229  		mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`),
 11230  	)
 11231  
 11232  	p := testProvider("test")
 11233  
 11234  	p.PlanResourceChangeFn = func(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
 11235  		// this is a destroy plan
 11236  		if r.ProposedNewState.IsNull() {
 11237  			resp.PlannedState = r.ProposedNewState
 11238  			resp.PlannedPrivate = r.PriorPrivate
 11239  			return resp
 11240  		}
 11241  
 11242  		n := r.ProposedNewState.AsValueMap()
 11243  
 11244  		if r.PriorState.IsNull() {
 11245  			n["id"] = cty.UnknownVal(cty.String)
 11246  			resp.PlannedState = cty.ObjectVal(n)
 11247  			return resp
 11248  		}
 11249  
 11250  		p := r.PriorState.AsValueMap()
 11251  
 11252  		priorRN := p["require_new"]
 11253  		newRN := n["require_new"]
 11254  
 11255  		if eq := priorRN.Equals(newRN); !eq.IsKnown() || eq.False() {
 11256  			resp.RequiresReplace = []cty.Path{{cty.GetAttrStep{Name: "require_new"}}}
 11257  			n["id"] = cty.UnknownVal(cty.String)
 11258  		}
 11259  
 11260  		resp.PlannedState = cty.ObjectVal(n)
 11261  		return resp
 11262  	}
 11263  
 11264  	// reduce the count to 1
 11265  	ctx := testContext2(t, &ContextOpts{
 11266  		Providers: map[addrs.Provider]providers.Factory{
 11267  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11268  		},
 11269  	})
 11270  
 11271  	plan, diags := ctx.Plan(m, state, &PlanOpts{
 11272  		Mode: plans.NormalMode,
 11273  		SetVariables: InputValues{
 11274  			"ct": &InputValue{
 11275  				Value:      cty.NumberIntVal(1),
 11276  				SourceType: ValueFromCaller,
 11277  			},
 11278  		},
 11279  	})
 11280  	if diags.HasErrors() {
 11281  		t.Fatal(diags.ErrWithWarnings())
 11282  	}
 11283  	{
 11284  		addr := mustResourceInstanceAddr("test_instance.a[0]")
 11285  		change := plan.Changes.ResourceInstance(addr)
 11286  		if change == nil {
 11287  			t.Fatalf("no planned change for %s", addr)
 11288  		}
 11289  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[0]"); !want.Equal(got) {
 11290  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
 11291  		}
 11292  		if got, want := change.Action, plans.NoOp; got != want {
 11293  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
 11294  		}
 11295  		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
 11296  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
 11297  		}
 11298  	}
 11299  	{
 11300  		addr := mustResourceInstanceAddr("test_instance.a[1]")
 11301  		change := plan.Changes.ResourceInstance(addr)
 11302  		if change == nil {
 11303  			t.Fatalf("no planned change for %s", addr)
 11304  		}
 11305  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[1]"); !want.Equal(got) {
 11306  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
 11307  		}
 11308  		if got, want := change.Action, plans.Delete; got != want {
 11309  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
 11310  		}
 11311  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
 11312  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
 11313  		}
 11314  	}
 11315  
 11316  	state, diags = ctx.Apply(plan, m)
 11317  	if diags.HasErrors() {
 11318  		log.Fatal(diags.ErrWithWarnings())
 11319  	}
 11320  
 11321  	// check the output, as those can't cause an error planning the value
 11322  	out := state.RootModule().OutputValues["out"].Value.AsString()
 11323  	if out != "a0" {
 11324  		t.Fatalf(`expected output "a0", got: %q`, out)
 11325  	}
 11326  
 11327  	// reduce the count to 0
 11328  	ctx = testContext2(t, &ContextOpts{
 11329  		Providers: map[addrs.Provider]providers.Factory{
 11330  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11331  		},
 11332  	})
 11333  
 11334  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11335  		Mode: plans.NormalMode,
 11336  		SetVariables: InputValues{
 11337  			"ct": &InputValue{
 11338  				Value:      cty.NumberIntVal(0),
 11339  				SourceType: ValueFromCaller,
 11340  			},
 11341  		},
 11342  	})
 11343  	if diags.HasErrors() {
 11344  		t.Fatal(diags.ErrWithWarnings())
 11345  	}
 11346  	{
 11347  		addr := mustResourceInstanceAddr("test_instance.a[0]")
 11348  		change := plan.Changes.ResourceInstance(addr)
 11349  		if change == nil {
 11350  			t.Fatalf("no planned change for %s", addr)
 11351  		}
 11352  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[0]"); !want.Equal(got) {
 11353  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
 11354  		}
 11355  		if got, want := change.Action, plans.Delete; got != want {
 11356  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
 11357  		}
 11358  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
 11359  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
 11360  		}
 11361  	}
 11362  	{
 11363  		addr := mustResourceInstanceAddr("test_instance.a[1]")
 11364  		change := plan.Changes.ResourceInstance(addr)
 11365  		if change != nil {
 11366  			// It was already removed in the previous plan/apply
 11367  			t.Errorf("unexpected planned change for %s", addr)
 11368  		}
 11369  	}
 11370  
 11371  	state, diags = ctx.Apply(plan, m)
 11372  	if diags.HasErrors() {
 11373  		t.Fatal(diags.ErrWithWarnings())
 11374  	}
 11375  
 11376  	// check the output, as those can't cause an error planning the value
 11377  	out = state.RootModule().OutputValues["out"].Value.AsString()
 11378  	if out != "" {
 11379  		t.Fatalf(`expected output "", got: %q`, out)
 11380  	}
 11381  }
 11382  
 11383  // Ensure that we can destroy when a provider references a resource that will
 11384  // also be destroyed
 11385  func TestContext2Apply_destroyProviderReference(t *testing.T) {
 11386  	m, snap := testModuleWithSnapshot(t, "apply-destroy-provisider-refs")
 11387  
 11388  	schemaFn := func(name string) *ProviderSchema {
 11389  		return &ProviderSchema{
 11390  			Provider: &configschema.Block{
 11391  				Attributes: map[string]*configschema.Attribute{
 11392  					"value": {
 11393  						Type:     cty.String,
 11394  						Required: true,
 11395  					},
 11396  				},
 11397  			},
 11398  			ResourceTypes: map[string]*configschema.Block{
 11399  				name + "_instance": {
 11400  					Attributes: map[string]*configschema.Attribute{
 11401  						"id": {
 11402  							Type:     cty.String,
 11403  							Computed: true,
 11404  						},
 11405  						"foo": {
 11406  							Type:     cty.String,
 11407  							Optional: true,
 11408  						},
 11409  					},
 11410  				},
 11411  			},
 11412  			DataSources: map[string]*configschema.Block{
 11413  				name + "_data_source": {
 11414  					Attributes: map[string]*configschema.Attribute{
 11415  						"id": {
 11416  							Type:     cty.String,
 11417  							Computed: true,
 11418  						},
 11419  						"output": {
 11420  							Type:     cty.String,
 11421  							Computed: true,
 11422  						},
 11423  					},
 11424  				},
 11425  			},
 11426  		}
 11427  	}
 11428  
 11429  	testP := new(MockProvider)
 11430  	testP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11431  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11432  	}
 11433  	testP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("test"))
 11434  
 11435  	providerConfig := ""
 11436  	testP.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
 11437  		value := req.Config.GetAttr("value")
 11438  		if value.IsKnown() && !value.IsNull() {
 11439  			providerConfig = value.AsString()
 11440  		} else {
 11441  			providerConfig = ""
 11442  		}
 11443  		return resp
 11444  	}
 11445  	testP.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 11446  		if providerConfig != "valid" {
 11447  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provider config is %q", providerConfig))
 11448  			return
 11449  		}
 11450  		return testApplyFn(req)
 11451  	}
 11452  	testP.PlanResourceChangeFn = testDiffFn
 11453  
 11454  	nullP := new(MockProvider)
 11455  	nullP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11456  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11457  	}
 11458  	nullP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("null"))
 11459  
 11460  	nullP.ApplyResourceChangeFn = testApplyFn
 11461  	nullP.PlanResourceChangeFn = testDiffFn
 11462  
 11463  	nullP.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 11464  		State: cty.ObjectVal(map[string]cty.Value{
 11465  			"id":     cty.StringVal("ID"),
 11466  			"output": cty.StringVal("valid"),
 11467  		}),
 11468  	}
 11469  
 11470  	ctx := testContext2(t, &ContextOpts{
 11471  		Providers: map[addrs.Provider]providers.Factory{
 11472  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP),
 11473  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP),
 11474  		},
 11475  	})
 11476  
 11477  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11478  	assertNoErrors(t, diags)
 11479  
 11480  	state, diags := ctx.Apply(plan, m)
 11481  	if diags.HasErrors() {
 11482  		t.Fatalf("apply errors: %s", diags.Err())
 11483  	}
 11484  
 11485  	providers := map[addrs.Provider]providers.Factory{
 11486  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP),
 11487  		addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP),
 11488  	}
 11489  	ctx = testContext2(t, &ContextOpts{
 11490  		Providers: providers,
 11491  	})
 11492  
 11493  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11494  		Mode: plans.DestroyMode,
 11495  	})
 11496  	assertNoErrors(t, diags)
 11497  
 11498  	// We'll marshal and unmarshal the plan here, to ensure that we have
 11499  	// a clean new context as would be created if we separately ran
 11500  	// tofu plan -out=tfplan && tofu apply tfplan
 11501  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
 11502  	if err != nil {
 11503  		t.Fatal(err)
 11504  	}
 11505  	ctxOpts.Providers = providers
 11506  	ctx, diags = NewContext(ctxOpts)
 11507  
 11508  	if diags.HasErrors() {
 11509  		t.Fatalf("failed to create context for plan: %s", diags.Err())
 11510  	}
 11511  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
 11512  		t.Fatalf("destroy apply errors: %s", diags.Err())
 11513  	}
 11514  }
 11515  
 11516  // Destroying properly requires pruning out all unneeded config nodes to
 11517  // prevent incorrect expansion evaluation.
 11518  func TestContext2Apply_destroyInterModuleExpansion(t *testing.T) {
 11519  	m := testModuleInline(t, map[string]string{
 11520  		"main.tf": `
 11521  data "test_data_source" "a" {
 11522    for_each = {
 11523      one = "thing"
 11524    }
 11525  }
 11526  
 11527  locals {
 11528    module_input = {
 11529      for k, v in data.test_data_source.a : k => v.id
 11530    }
 11531  }
 11532  
 11533  module "mod1" {
 11534    source = "./mod"
 11535    input = local.module_input
 11536  }
 11537  
 11538  module "mod2" {
 11539    source = "./mod"
 11540    input = module.mod1.outputs
 11541  }
 11542  
 11543  resource "test_instance" "bar" {
 11544    for_each = module.mod2.outputs
 11545  }
 11546  
 11547  output "module_output" {
 11548    value = module.mod2.outputs
 11549  }
 11550  output "test_instances" {
 11551    value = test_instance.bar
 11552  }
 11553  `,
 11554  		"mod/main.tf": `
 11555  variable "input" {
 11556  }
 11557  
 11558  data "test_data_source" "foo" {
 11559    for_each = var.input
 11560  }
 11561  
 11562  output "outputs" {
 11563    value = data.test_data_source.foo
 11564  }
 11565  `})
 11566  
 11567  	p := testProvider("test")
 11568  	p.PlanResourceChangeFn = testDiffFn
 11569  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 11570  		return providers.ReadDataSourceResponse{
 11571  			State: cty.ObjectVal(map[string]cty.Value{
 11572  				"id":  cty.StringVal("data_source"),
 11573  				"foo": cty.StringVal("output"),
 11574  			}),
 11575  		}
 11576  	}
 11577  
 11578  	ctx := testContext2(t, &ContextOpts{
 11579  		Providers: map[addrs.Provider]providers.Factory{
 11580  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11581  		},
 11582  	})
 11583  
 11584  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11585  	assertNoErrors(t, diags)
 11586  
 11587  	state, diags := ctx.Apply(plan, m)
 11588  	if diags.HasErrors() {
 11589  		t.Fatalf("apply errors: %s", diags.Err())
 11590  	}
 11591  
 11592  	destroy := func() {
 11593  		ctx = testContext2(t, &ContextOpts{
 11594  			Providers: map[addrs.Provider]providers.Factory{
 11595  				addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11596  			},
 11597  		})
 11598  
 11599  		plan, diags = ctx.Plan(m, state, &PlanOpts{
 11600  			Mode: plans.DestroyMode,
 11601  		})
 11602  		assertNoErrors(t, diags)
 11603  
 11604  		state, diags = ctx.Apply(plan, m)
 11605  		if diags.HasErrors() {
 11606  			t.Fatalf("destroy apply errors: %s", diags.Err())
 11607  		}
 11608  	}
 11609  
 11610  	destroy()
 11611  	// Destroying again from the empty state should not cause any errors either
 11612  	destroy()
 11613  }
 11614  
 11615  func TestContext2Apply_createBeforeDestroyWithModule(t *testing.T) {
 11616  	m := testModuleInline(t, map[string]string{
 11617  		"main.tf": `
 11618  variable "v" {}
 11619  
 11620  module "mod" {
 11621      source = "./mod"
 11622      in = var.v
 11623  }
 11624  
 11625  resource "test_resource" "a" {
 11626    value = var.v
 11627    depends_on = [module.mod]
 11628    lifecycle {
 11629      create_before_destroy = true
 11630    }
 11631  }
 11632  `,
 11633  		"mod/main.tf": `
 11634  variable "in" {}
 11635  
 11636  resource "test_resource" "a" {
 11637    value = var.in
 11638  }
 11639  `})
 11640  
 11641  	p := testProvider("test")
 11642  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
 11643  		// this is a destroy plan
 11644  		if req.ProposedNewState.IsNull() {
 11645  			resp.PlannedState = req.ProposedNewState
 11646  			resp.PlannedPrivate = req.PriorPrivate
 11647  			return resp
 11648  		}
 11649  
 11650  		proposed := req.ProposedNewState.AsValueMap()
 11651  		proposed["id"] = cty.UnknownVal(cty.String)
 11652  
 11653  		resp.PlannedState = cty.ObjectVal(proposed)
 11654  		resp.RequiresReplace = []cty.Path{{cty.GetAttrStep{Name: "value"}}}
 11655  		return resp
 11656  	}
 11657  
 11658  	ctx := testContext2(t, &ContextOpts{
 11659  		Providers: map[addrs.Provider]providers.Factory{
 11660  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11661  		},
 11662  	})
 11663  
 11664  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11665  		Mode: plans.NormalMode,
 11666  		SetVariables: InputValues{
 11667  			"v": &InputValue{
 11668  				Value: cty.StringVal("A"),
 11669  			},
 11670  		},
 11671  	})
 11672  	assertNoErrors(t, diags)
 11673  
 11674  	state, diags := ctx.Apply(plan, m)
 11675  	if diags.HasErrors() {
 11676  		t.Fatalf("apply errors: %s", diags.Err())
 11677  	}
 11678  
 11679  	ctx = testContext2(t, &ContextOpts{
 11680  		Providers: map[addrs.Provider]providers.Factory{
 11681  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11682  		},
 11683  	})
 11684  
 11685  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11686  		Mode: plans.NormalMode,
 11687  		SetVariables: InputValues{
 11688  			"v": &InputValue{
 11689  				Value: cty.StringVal("B"),
 11690  			},
 11691  		},
 11692  	})
 11693  	assertNoErrors(t, diags)
 11694  
 11695  	_, diags = ctx.Apply(plan, m)
 11696  	if diags.HasErrors() {
 11697  		t.Fatalf("apply errors: %s", diags.Err())
 11698  	}
 11699  }
 11700  
 11701  func TestContext2Apply_forcedCBD(t *testing.T) {
 11702  	m := testModuleInline(t, map[string]string{
 11703  		"main.tf": `
 11704  variable "v" {}
 11705  
 11706  resource "test_instance" "a" {
 11707    require_new = var.v
 11708  }
 11709  
 11710  resource "test_instance" "b" {
 11711    depends_on = [test_instance.a]
 11712    lifecycle {
 11713      create_before_destroy = true
 11714    }
 11715  }
 11716  `})
 11717  
 11718  	p := testProvider("test")
 11719  	p.PlanResourceChangeFn = testDiffFn
 11720  
 11721  	ctx := testContext2(t, &ContextOpts{
 11722  		Providers: map[addrs.Provider]providers.Factory{
 11723  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11724  		},
 11725  	})
 11726  
 11727  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11728  		Mode: plans.NormalMode,
 11729  		SetVariables: InputValues{
 11730  			"v": &InputValue{
 11731  				Value: cty.StringVal("A"),
 11732  			},
 11733  		},
 11734  	})
 11735  	assertNoErrors(t, diags)
 11736  
 11737  	state, diags := ctx.Apply(plan, m)
 11738  	if diags.HasErrors() {
 11739  		t.Fatalf("apply errors: %s", diags.Err())
 11740  	}
 11741  
 11742  	ctx = testContext2(t, &ContextOpts{
 11743  		Providers: map[addrs.Provider]providers.Factory{
 11744  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11745  		},
 11746  	})
 11747  
 11748  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11749  		Mode: plans.NormalMode,
 11750  		SetVariables: InputValues{
 11751  			"v": &InputValue{
 11752  				Value: cty.StringVal("B"),
 11753  			},
 11754  		},
 11755  	})
 11756  	assertNoErrors(t, diags)
 11757  
 11758  	_, diags = ctx.Apply(plan, m)
 11759  	if diags.HasErrors() {
 11760  		t.Fatalf("apply errors: %s", diags.Err())
 11761  	}
 11762  }
 11763  
 11764  func TestContext2Apply_removeReferencedResource(t *testing.T) {
 11765  	m := testModuleInline(t, map[string]string{
 11766  		"main.tf": `
 11767  variable "ct" {
 11768  }
 11769  
 11770  resource "test_resource" "to_remove" {
 11771    count = var.ct
 11772  }
 11773  
 11774  resource "test_resource" "c" {
 11775    value = join("", test_resource.to_remove[*].id)
 11776  }
 11777  `})
 11778  
 11779  	p := testProvider("test")
 11780  	p.PlanResourceChangeFn = testDiffFn
 11781  
 11782  	ctx := testContext2(t, &ContextOpts{
 11783  		Providers: map[addrs.Provider]providers.Factory{
 11784  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11785  		},
 11786  	})
 11787  
 11788  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11789  		Mode: plans.NormalMode,
 11790  		SetVariables: InputValues{
 11791  			"ct": &InputValue{
 11792  				Value: cty.NumberIntVal(1),
 11793  			},
 11794  		},
 11795  	})
 11796  	assertNoErrors(t, diags)
 11797  
 11798  	state, diags := ctx.Apply(plan, m)
 11799  	if diags.HasErrors() {
 11800  		t.Fatalf("apply errors: %s", diags.Err())
 11801  	}
 11802  
 11803  	ctx = testContext2(t, &ContextOpts{
 11804  		Providers: map[addrs.Provider]providers.Factory{
 11805  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11806  		},
 11807  	})
 11808  
 11809  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11810  		Mode: plans.NormalMode,
 11811  		SetVariables: InputValues{
 11812  			"ct": &InputValue{
 11813  				Value: cty.NumberIntVal(0),
 11814  			},
 11815  		},
 11816  	})
 11817  	assertNoErrors(t, diags)
 11818  
 11819  	_, diags = ctx.Apply(plan, m)
 11820  	if diags.HasErrors() {
 11821  		t.Fatalf("apply errors: %s", diags.Err())
 11822  	}
 11823  }
 11824  
 11825  func TestContext2Apply_variableSensitivity(t *testing.T) {
 11826  	m := testModuleInline(t, map[string]string{
 11827  		"main.tf": `
 11828  variable "sensitive_var" {
 11829  	default = "foo"
 11830  	sensitive = true
 11831  }
 11832  
 11833  variable "sensitive_id" {
 11834  	default = "secret id"
 11835  	sensitive = true
 11836  }
 11837  
 11838  resource "test_resource" "foo" {
 11839  	value   = var.sensitive_var
 11840  
 11841  	network_interface {
 11842  		network_interface_id = var.sensitive_id
 11843  	}
 11844  }`,
 11845  	})
 11846  
 11847  	p := new(MockProvider)
 11848  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11849  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11850  	}
 11851  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
 11852  		Provider: &configschema.Block{},
 11853  		ResourceTypes: map[string]*configschema.Block{
 11854  			"test_resource": {
 11855  				Attributes: map[string]*configschema.Attribute{
 11856  					"id": {
 11857  						Type:     cty.String,
 11858  						Computed: true,
 11859  					},
 11860  					"value": {
 11861  						Type:     cty.String,
 11862  						Optional: true,
 11863  						Computed: true,
 11864  					},
 11865  				},
 11866  				BlockTypes: map[string]*configschema.NestedBlock{
 11867  					"network_interface": {
 11868  						Block: configschema.Block{
 11869  							Attributes: map[string]*configschema.Attribute{
 11870  								"network_interface_id": {Type: cty.String, Optional: true},
 11871  								"device_index":         {Type: cty.Number, Optional: true},
 11872  							},
 11873  						},
 11874  						Nesting: configschema.NestingSet,
 11875  					},
 11876  				},
 11877  			},
 11878  		},
 11879  	})
 11880  	p.PlanResourceChangeFn = testDiffFn
 11881  
 11882  	ctx := testContext2(t, &ContextOpts{
 11883  		Providers: map[addrs.Provider]providers.Factory{
 11884  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11885  		},
 11886  	})
 11887  
 11888  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 11889  	assertNoErrors(t, diags)
 11890  
 11891  	state, diags := ctx.Apply(plan, m)
 11892  	if diags.HasErrors() {
 11893  		t.Fatalf("apply errors: %s", diags.Err())
 11894  	}
 11895  
 11896  	// Run a second apply with no changes
 11897  	ctx = testContext2(t, &ContextOpts{
 11898  		Providers: map[addrs.Provider]providers.Factory{
 11899  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11900  		},
 11901  	})
 11902  
 11903  	plan, diags = ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 11904  	assertNoErrors(t, diags)
 11905  
 11906  	state, diags = ctx.Apply(plan, m)
 11907  	if diags.HasErrors() {
 11908  		t.Fatalf("apply errors: %s", diags.Err())
 11909  	}
 11910  
 11911  	// Now change the variable value for sensitive_var
 11912  	ctx = testContext2(t, &ContextOpts{
 11913  		Providers: map[addrs.Provider]providers.Factory{
 11914  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11915  		},
 11916  	})
 11917  
 11918  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11919  		Mode: plans.NormalMode,
 11920  		SetVariables: InputValues{
 11921  			"sensitive_id": &InputValue{Value: cty.NilVal},
 11922  			"sensitive_var": &InputValue{
 11923  				Value: cty.StringVal("bar"),
 11924  			},
 11925  		},
 11926  	})
 11927  	assertNoErrors(t, diags)
 11928  
 11929  	_, diags = ctx.Apply(plan, m)
 11930  	if diags.HasErrors() {
 11931  		t.Fatalf("apply errors: %s", diags.Err())
 11932  	}
 11933  }
 11934  
 11935  func TestContext2Apply_variableSensitivityPropagation(t *testing.T) {
 11936  	m := testModuleInline(t, map[string]string{
 11937  		"main.tf": `
 11938  variable "sensitive_map" {
 11939  	type = map(string)
 11940  	default = {
 11941  		"x" = "foo"
 11942  	}
 11943  	sensitive = true
 11944  }
 11945  
 11946  resource "test_resource" "foo" {
 11947  	value = var.sensitive_map.x
 11948  }
 11949  `,
 11950  	})
 11951  
 11952  	p := testProvider("test")
 11953  	p.PlanResourceChangeFn = testDiffFn
 11954  
 11955  	ctx := testContext2(t, &ContextOpts{
 11956  		Providers: map[addrs.Provider]providers.Factory{
 11957  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11958  		},
 11959  	})
 11960  
 11961  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 11962  	if diags.HasErrors() {
 11963  		t.Fatalf("plan errors: %s", diags.Err())
 11964  	}
 11965  
 11966  	verifySensitiveValue := func(pvms []cty.PathValueMarks) {
 11967  		if len(pvms) != 1 {
 11968  			t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 11969  		}
 11970  		pvm := pvms[0]
 11971  		if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) {
 11972  			t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 11973  		}
 11974  		if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 11975  			t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 11976  		}
 11977  	}
 11978  
 11979  	addr := mustResourceInstanceAddr("test_resource.foo")
 11980  	fooChangeSrc := plan.Changes.ResourceInstance(addr)
 11981  	verifySensitiveValue(fooChangeSrc.AfterValMarks)
 11982  
 11983  	state, diags := ctx.Apply(plan, m)
 11984  	if diags.HasErrors() {
 11985  		t.Fatalf("apply errors: %s", diags.Err())
 11986  	}
 11987  
 11988  	fooState := state.ResourceInstance(addr)
 11989  	verifySensitiveValue(fooState.Current.AttrSensitivePaths)
 11990  }
 11991  
 11992  func TestContext2Apply_variableSensitivityProviders(t *testing.T) {
 11993  	m := testModuleInline(t, map[string]string{
 11994  		"main.tf": `
 11995  resource "test_resource" "foo" {
 11996  	sensitive_value = "should get marked"
 11997  }
 11998  
 11999  resource "test_resource" "bar" {
 12000  	value  = test_resource.foo.sensitive_value
 12001  	random = test_resource.foo.id # not sensitive
 12002  
 12003  	nesting_single {
 12004  		value           = "abc"
 12005  		sensitive_value = "xyz"
 12006  	}
 12007  }
 12008  
 12009  resource "test_resource" "baz" {
 12010  	value = test_resource.bar.nesting_single.sensitive_value
 12011  }
 12012  `,
 12013  	})
 12014  
 12015  	p := testProvider("test")
 12016  	p.PlanResourceChangeFn = testDiffFn
 12017  
 12018  	ctx := testContext2(t, &ContextOpts{
 12019  		Providers: map[addrs.Provider]providers.Factory{
 12020  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12021  		},
 12022  	})
 12023  
 12024  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12025  	if diags.HasErrors() {
 12026  		t.Fatalf("plan errors: %s", diags.Err())
 12027  	}
 12028  
 12029  	verifySensitiveValue := func(pvms []cty.PathValueMarks) {
 12030  		if len(pvms) != 1 {
 12031  			t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 12032  		}
 12033  		pvm := pvms[0]
 12034  		if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) {
 12035  			t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 12036  		}
 12037  		if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 12038  			t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 12039  		}
 12040  	}
 12041  
 12042  	// Sensitive attributes (defined by the provider) are marked
 12043  	// as sensitive when referenced from another resource
 12044  	// "bar" references sensitive resources in "foo"
 12045  	barAddr := mustResourceInstanceAddr("test_resource.bar")
 12046  	barChangeSrc := plan.Changes.ResourceInstance(barAddr)
 12047  	verifySensitiveValue(barChangeSrc.AfterValMarks)
 12048  
 12049  	bazAddr := mustResourceInstanceAddr("test_resource.baz")
 12050  	bazChangeSrc := plan.Changes.ResourceInstance(bazAddr)
 12051  	verifySensitiveValue(bazChangeSrc.AfterValMarks)
 12052  
 12053  	state, diags := ctx.Apply(plan, m)
 12054  	if diags.HasErrors() {
 12055  		t.Fatalf("apply errors: %s", diags.Err())
 12056  	}
 12057  
 12058  	barState := state.ResourceInstance(barAddr)
 12059  	verifySensitiveValue(barState.Current.AttrSensitivePaths)
 12060  
 12061  	bazState := state.ResourceInstance(bazAddr)
 12062  	verifySensitiveValue(bazState.Current.AttrSensitivePaths)
 12063  }
 12064  
 12065  func TestContext2Apply_variableSensitivityChange(t *testing.T) {
 12066  	m := testModuleInline(t, map[string]string{
 12067  		"main.tf": `
 12068  variable "sensitive_var" {
 12069  	default = "hello"
 12070  	sensitive = true
 12071  }
 12072  
 12073  resource "test_resource" "foo" {
 12074  	value = var.sensitive_var
 12075  }`,
 12076  	})
 12077  
 12078  	p := testProvider("test")
 12079  	p.PlanResourceChangeFn = testDiffFn
 12080  
 12081  	ctx := testContext2(t, &ContextOpts{
 12082  		Providers: map[addrs.Provider]providers.Factory{
 12083  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12084  		},
 12085  	})
 12086  
 12087  	state := states.BuildState(func(s *states.SyncState) {
 12088  		s.SetResourceInstanceCurrent(
 12089  			addrs.Resource{
 12090  				Mode: addrs.ManagedResourceMode,
 12091  				Type: "test_resource",
 12092  				Name: "foo",
 12093  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
 12094  			&states.ResourceInstanceObjectSrc{
 12095  				Status:    states.ObjectReady,
 12096  				AttrsJSON: []byte(`{"id":"foo", "value":"hello"}`),
 12097  				// No AttrSensitivePaths present
 12098  			},
 12099  			addrs.AbsProviderConfig{
 12100  				Provider: addrs.NewDefaultProvider("test"),
 12101  				Module:   addrs.RootModule,
 12102  			},
 12103  		)
 12104  	})
 12105  
 12106  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 12107  	assertNoErrors(t, diags)
 12108  
 12109  	addr := mustResourceInstanceAddr("test_resource.foo")
 12110  
 12111  	state, diags = ctx.Apply(plan, m)
 12112  	assertNoErrors(t, diags)
 12113  
 12114  	fooState := state.ResourceInstance(addr)
 12115  
 12116  	if len(fooState.Current.AttrSensitivePaths) != 1 {
 12117  		t.Fatalf("wrong number of sensitive paths, expected 1, got, %v", len(fooState.Current.AttrSensitivePaths))
 12118  	}
 12119  	got := fooState.Current.AttrSensitivePaths[0]
 12120  	want := cty.PathValueMarks{
 12121  		Path:  cty.GetAttrPath("value"),
 12122  		Marks: cty.NewValueMarks(marks.Sensitive),
 12123  	}
 12124  
 12125  	if !got.Equal(want) {
 12126  		t.Fatalf("wrong value marks; got:\n%#v\n\nwant:\n%#v\n", got, want)
 12127  	}
 12128  
 12129  	m2 := testModuleInline(t, map[string]string{
 12130  		"main.tf": `
 12131  variable "sensitive_var" {
 12132  	default = "hello"
 12133  	sensitive = false
 12134  }
 12135  
 12136  resource "test_resource" "foo" {
 12137  	value = var.sensitive_var
 12138  }`,
 12139  	})
 12140  
 12141  	ctx2 := testContext2(t, &ContextOpts{
 12142  		Providers: map[addrs.Provider]providers.Factory{
 12143  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12144  		},
 12145  	})
 12146  
 12147  	// NOTE: Prior to our refactoring to make the state an explicit argument
 12148  	// of Plan, as opposed to hidden state inside Context, this test was
 12149  	// calling ctx.Apply instead of ctx2.Apply and thus using the previous
 12150  	// plan instead of this new plan. "Fixing" it to use the new plan seems
 12151  	// to break the test, so we've preserved that oddity here by saving the
 12152  	// old plan as oldPlan and essentially discarding the new plan entirely,
 12153  	// but this seems rather suspicious and we should ideally figure out what
 12154  	// this test was originally intending to do and make it do that.
 12155  	oldPlan := plan
 12156  	_, diags = ctx2.Plan(m2, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 12157  	assertNoErrors(t, diags)
 12158  	stateWithoutSensitive, diags := ctx.Apply(oldPlan, m)
 12159  	assertNoErrors(t, diags)
 12160  
 12161  	fooState2 := stateWithoutSensitive.ResourceInstance(addr)
 12162  	if len(fooState2.Current.AttrSensitivePaths) > 0 {
 12163  		t.Fatalf(
 12164  			"wrong number of sensitive paths, expected 0, got, %v\n%s",
 12165  			len(fooState2.Current.AttrSensitivePaths),
 12166  			spew.Sdump(fooState2.Current.AttrSensitivePaths),
 12167  		)
 12168  	}
 12169  }
 12170  
 12171  func TestContext2Apply_moduleVariableOptionalAttributes(t *testing.T) {
 12172  	m := testModuleInline(t, map[string]string{
 12173  		"main.tf": `
 12174  variable "in" {
 12175    type = object({
 12176      required = string
 12177      optional = optional(string)
 12178      default  = optional(bool, true)
 12179      nested   = optional(
 12180        map(object({
 12181          a = optional(string, "foo")
 12182          b = optional(number, 5)
 12183        })), {
 12184          "boop": {}
 12185        }
 12186      )
 12187    })
 12188  }
 12189  
 12190  output "out" {
 12191    value = var.in
 12192  }
 12193  `})
 12194  
 12195  	ctx := testContext2(t, &ContextOpts{})
 12196  
 12197  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 12198  		Mode: plans.NormalMode,
 12199  		SetVariables: InputValues{
 12200  			"in": &InputValue{
 12201  				Value: cty.MapVal(map[string]cty.Value{
 12202  					"required": cty.StringVal("boop"),
 12203  				}),
 12204  				SourceType: ValueFromCaller,
 12205  			},
 12206  		},
 12207  	})
 12208  	if diags.HasErrors() {
 12209  		t.Fatal(diags.ErrWithWarnings())
 12210  	}
 12211  
 12212  	state, diags := ctx.Apply(plan, m)
 12213  	if diags.HasErrors() {
 12214  		t.Fatal(diags.ErrWithWarnings())
 12215  	}
 12216  
 12217  	got := state.RootModule().OutputValues["out"].Value
 12218  	want := cty.ObjectVal(map[string]cty.Value{
 12219  		"required": cty.StringVal("boop"),
 12220  
 12221  		// Because "optional" was marked as optional, it got silently filled
 12222  		// in as a null value of string type rather than returning an error.
 12223  		"optional": cty.NullVal(cty.String),
 12224  
 12225  		// Similarly, "default" was marked as optional with a default value,
 12226  		// and since it was omitted should be filled in with that default.
 12227  		"default": cty.True,
 12228  
 12229  		// Nested is a complex structure which has fully described defaults,
 12230  		// so again it should be filled with the default structure.
 12231  		"nested": cty.MapVal(map[string]cty.Value{
 12232  			"boop": cty.ObjectVal(map[string]cty.Value{
 12233  				"a": cty.StringVal("foo"),
 12234  				"b": cty.NumberIntVal(5),
 12235  			}),
 12236  		}),
 12237  	})
 12238  	if !want.RawEquals(got) {
 12239  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
 12240  	}
 12241  }
 12242  
 12243  func TestContext2Apply_moduleVariableOptionalAttributesDefault(t *testing.T) {
 12244  	m := testModuleInline(t, map[string]string{
 12245  		"main.tf": `
 12246  variable "in" {
 12247    type    = object({
 12248      required = string
 12249      optional = optional(string)
 12250      default  = optional(bool, true)
 12251    })
 12252    default = {
 12253      required = "boop"
 12254    }
 12255  }
 12256  
 12257  output "out" {
 12258    value = var.in
 12259  }
 12260  `})
 12261  
 12262  	ctx := testContext2(t, &ContextOpts{})
 12263  
 12264  	// We don't specify a value for the variable here, relying on its defined
 12265  	// default.
 12266  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 12267  	if diags.HasErrors() {
 12268  		t.Fatal(diags.ErrWithWarnings())
 12269  	}
 12270  
 12271  	state, diags := ctx.Apply(plan, m)
 12272  	if diags.HasErrors() {
 12273  		t.Fatal(diags.ErrWithWarnings())
 12274  	}
 12275  
 12276  	got := state.RootModule().OutputValues["out"].Value
 12277  	want := cty.ObjectVal(map[string]cty.Value{
 12278  		"required": cty.StringVal("boop"),
 12279  
 12280  		// "optional" is not present in the variable default, so it is filled
 12281  		// with null.
 12282  		"optional": cty.NullVal(cty.String),
 12283  
 12284  		// Similarly, "default" is not present in the variable default, so its
 12285  		// value is replaced with the type's specified default.
 12286  		"default": cty.True,
 12287  	})
 12288  	if !want.RawEquals(got) {
 12289  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
 12290  	}
 12291  }
 12292  
 12293  func TestContext2Apply_moduleVariableOptionalAttributesDefaultNull(t *testing.T) {
 12294  	m := testModuleInline(t, map[string]string{
 12295  		"main.tf": `
 12296  variable "in" {
 12297    type    = object({
 12298      required = string
 12299      optional = optional(string)
 12300      default  = optional(bool, true)
 12301    })
 12302    default = null
 12303  }
 12304  
 12305  # Wrap the input variable in a tuple because a null output value is elided from
 12306  # the plan, which prevents us from testing its type.
 12307  output "out" {
 12308    value = [var.in]
 12309  }
 12310  `})
 12311  
 12312  	ctx := testContext2(t, &ContextOpts{})
 12313  
 12314  	// We don't specify a value for the variable here, relying on its defined
 12315  	// default.
 12316  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 12317  	if diags.HasErrors() {
 12318  		t.Fatal(diags.ErrWithWarnings())
 12319  	}
 12320  
 12321  	state, diags := ctx.Apply(plan, m)
 12322  	if diags.HasErrors() {
 12323  		t.Fatal(diags.ErrWithWarnings())
 12324  	}
 12325  
 12326  	got := state.RootModule().OutputValues["out"].Value
 12327  	// The null default value should be bound, after type converting to the
 12328  	// full object type
 12329  	want := cty.TupleVal([]cty.Value{cty.NullVal(cty.Object(map[string]cty.Type{
 12330  		"required": cty.String,
 12331  		"optional": cty.String,
 12332  		"default":  cty.Bool,
 12333  	}))})
 12334  	if !want.RawEquals(got) {
 12335  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
 12336  	}
 12337  }
 12338  
 12339  func TestContext2Apply_moduleVariableOptionalAttributesDefaultChild(t *testing.T) {
 12340  	m := testModuleInline(t, map[string]string{
 12341  		"main.tf": `
 12342  variable "in" {
 12343    type    = list(object({
 12344      a = optional(set(string))
 12345    }))
 12346    default = [
 12347  	{ a = [ "foo" ] },
 12348  	{ },
 12349    ]
 12350  }
 12351  
 12352  module "child" {
 12353    source = "./child"
 12354    in     = var.in
 12355  }
 12356  
 12357  output "out" {
 12358    value = module.child.out
 12359  }
 12360  `,
 12361  		"child/main.tf": `
 12362  variable "in" {
 12363    type    = list(object({
 12364      a = optional(set(string), [])
 12365    }))
 12366    default = []
 12367  }
 12368  
 12369  output "out" {
 12370    value = var.in
 12371  }
 12372  `,
 12373  	})
 12374  
 12375  	ctx := testContext2(t, &ContextOpts{})
 12376  
 12377  	// We don't specify a value for the variable here, relying on its defined
 12378  	// default.
 12379  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 12380  	if diags.HasErrors() {
 12381  		t.Fatal(diags.ErrWithWarnings())
 12382  	}
 12383  
 12384  	state, diags := ctx.Apply(plan, m)
 12385  	if diags.HasErrors() {
 12386  		t.Fatal(diags.ErrWithWarnings())
 12387  	}
 12388  
 12389  	got := state.RootModule().OutputValues["out"].Value
 12390  	want := cty.ListVal([]cty.Value{
 12391  		cty.ObjectVal(map[string]cty.Value{
 12392  			"a": cty.SetVal([]cty.Value{cty.StringVal("foo")}),
 12393  		}),
 12394  		cty.ObjectVal(map[string]cty.Value{
 12395  			"a": cty.SetValEmpty(cty.String),
 12396  		}),
 12397  	})
 12398  	if !want.RawEquals(got) {
 12399  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
 12400  	}
 12401  }
 12402  
 12403  func TestContext2Apply_provisionerSensitive(t *testing.T) {
 12404  	m := testModule(t, "apply-provisioner-sensitive")
 12405  	p := testProvider("aws")
 12406  
 12407  	pr := testProvisioner()
 12408  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
 12409  		if req.Config.ContainsMarked() {
 12410  			t.Fatalf("unexpectedly marked config value: %#v", req.Config)
 12411  		}
 12412  		command := req.Config.GetAttr("command")
 12413  		if command.IsMarked() {
 12414  			t.Fatalf("unexpectedly marked command argument: %#v", command.Marks())
 12415  		}
 12416  		req.UIOutput.Output(fmt.Sprintf("Executing: %q", command.AsString()))
 12417  		return
 12418  	}
 12419  	p.PlanResourceChangeFn = testDiffFn
 12420  	p.ApplyResourceChangeFn = testApplyFn
 12421  
 12422  	h := new(MockHook)
 12423  	ctx := testContext2(t, &ContextOpts{
 12424  		Hooks: []Hook{h},
 12425  		Providers: map[addrs.Provider]providers.Factory{
 12426  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 12427  		},
 12428  		Provisioners: map[string]provisioners.Factory{
 12429  			"shell": testProvisionerFuncFixed(pr),
 12430  		},
 12431  	})
 12432  
 12433  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 12434  		Mode: plans.NormalMode,
 12435  		SetVariables: InputValues{
 12436  			"password": &InputValue{
 12437  				Value:      cty.StringVal("secret"),
 12438  				SourceType: ValueFromCaller,
 12439  			},
 12440  		},
 12441  	})
 12442  	assertNoErrors(t, diags)
 12443  
 12444  	// "restart" provisioner
 12445  	pr.CloseCalled = false
 12446  
 12447  	state, diags := ctx.Apply(plan, m)
 12448  	if diags.HasErrors() {
 12449  		logDiagnostics(t, diags)
 12450  		t.Fatal("apply failed")
 12451  	}
 12452  
 12453  	actual := strings.TrimSpace(state.String())
 12454  	expected := strings.TrimSpace(testTofuApplyProvisionerSensitiveStr)
 12455  	if actual != expected {
 12456  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
 12457  	}
 12458  
 12459  	// Verify apply was invoked
 12460  	if !pr.ProvisionResourceCalled {
 12461  		t.Fatalf("provisioner was not called on apply")
 12462  	}
 12463  
 12464  	// Verify output was suppressed
 12465  	if !h.ProvisionOutputCalled {
 12466  		t.Fatalf("ProvisionOutput hook not called")
 12467  	}
 12468  	if got, doNotWant := h.ProvisionOutputMessage, "secret"; strings.Contains(got, doNotWant) {
 12469  		t.Errorf("sensitive value %q included in output:\n%s", doNotWant, got)
 12470  	}
 12471  	if got, want := h.ProvisionOutputMessage, "output suppressed"; !strings.Contains(got, want) {
 12472  		t.Errorf("expected hook to be called with %q, but was:\n%s", want, got)
 12473  	}
 12474  }
 12475  
 12476  func TestContext2Apply_warnings(t *testing.T) {
 12477  	m := testModuleInline(t, map[string]string{
 12478  		"main.tf": `
 12479  resource "test_resource" "foo" {
 12480  }`,
 12481  	})
 12482  
 12483  	p := testProvider("test")
 12484  	p.PlanResourceChangeFn = testDiffFn
 12485  
 12486  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
 12487  		resp := testApplyFn(req)
 12488  
 12489  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warning"))
 12490  		return resp
 12491  	}
 12492  
 12493  	ctx := testContext2(t, &ContextOpts{
 12494  		Providers: map[addrs.Provider]providers.Factory{
 12495  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12496  		},
 12497  	})
 12498  
 12499  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12500  	assertNoErrors(t, diags)
 12501  
 12502  	state, diags := ctx.Apply(plan, m)
 12503  	if diags.HasErrors() {
 12504  		t.Fatalf("diags: %s", diags.Err())
 12505  	}
 12506  
 12507  	inst := state.ResourceInstance(mustResourceInstanceAddr("test_resource.foo"))
 12508  	if inst == nil {
 12509  		t.Fatal("missing 'test_resource.foo' in state:", state)
 12510  	}
 12511  }
 12512  
 12513  func TestContext2Apply_rpcDiagnostics(t *testing.T) {
 12514  	m := testModuleInline(t, map[string]string{
 12515  		"main.tf": `
 12516  resource "test_instance" "a" {
 12517  }
 12518  `,
 12519  	})
 12520  
 12521  	p := testProvider("test")
 12522  	p.PlanResourceChangeFn = testDiffFn
 12523  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 12524  		resp = testApplyFn(req)
 12525  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("don't frobble"))
 12526  		return resp
 12527  	}
 12528  
 12529  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
 12530  		ResourceTypes: map[string]*configschema.Block{
 12531  			"test_instance": {
 12532  				Attributes: map[string]*configschema.Attribute{
 12533  					"id": {Type: cty.String, Computed: true},
 12534  				},
 12535  			},
 12536  		},
 12537  	})
 12538  
 12539  	ctx := testContext2(t, &ContextOpts{
 12540  		Providers: map[addrs.Provider]providers.Factory{
 12541  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12542  		},
 12543  	})
 12544  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12545  	if diags.HasErrors() {
 12546  		t.Fatal(diags.Err())
 12547  	}
 12548  
 12549  	_, diags = ctx.Apply(plan, m)
 12550  	if diags.HasErrors() {
 12551  		t.Fatal(diags.Err())
 12552  	}
 12553  
 12554  	if len(diags) == 0 {
 12555  		t.Fatal("expected warnings")
 12556  	}
 12557  
 12558  	for _, d := range diags {
 12559  		des := d.Description().Summary
 12560  		if !strings.Contains(des, "frobble") {
 12561  			t.Fatalf(`expected frobble, got %q`, des)
 12562  		}
 12563  	}
 12564  }
 12565  
 12566  func TestContext2Apply_dataSensitive(t *testing.T) {
 12567  	m := testModule(t, "apply-data-sensitive")
 12568  	p := testProvider("null")
 12569  	p.PlanResourceChangeFn = testDiffFn
 12570  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 12571  		// add the required id
 12572  		m := req.Config.AsValueMap()
 12573  		m["id"] = cty.StringVal("foo")
 12574  
 12575  		return providers.ReadDataSourceResponse{
 12576  			State: cty.ObjectVal(m),
 12577  		}
 12578  	}
 12579  
 12580  	ctx := testContext2(t, &ContextOpts{
 12581  		Providers: map[addrs.Provider]providers.Factory{
 12582  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
 12583  		},
 12584  	})
 12585  
 12586  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 12587  	if diags.HasErrors() {
 12588  		t.Fatalf("diags: %s", diags.Err())
 12589  	} else {
 12590  		t.Logf(legacyDiffComparisonString(plan.Changes))
 12591  	}
 12592  
 12593  	state, diags := ctx.Apply(plan, m)
 12594  	assertNoErrors(t, diags)
 12595  
 12596  	addr := mustResourceInstanceAddr("data.null_data_source.testing")
 12597  
 12598  	dataSourceState := state.ResourceInstance(addr)
 12599  	pvms := dataSourceState.Current.AttrSensitivePaths
 12600  	if len(pvms) != 1 {
 12601  		t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 12602  	}
 12603  	pvm := pvms[0]
 12604  	if gotPath, wantPath := pvm.Path, cty.GetAttrPath("foo"); !gotPath.Equals(wantPath) {
 12605  		t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 12606  	}
 12607  	if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 12608  		t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 12609  	}
 12610  }
 12611  
 12612  func TestContext2Apply_errorRestorePrivateData(t *testing.T) {
 12613  	// empty config to remove our resource
 12614  	m := testModuleInline(t, map[string]string{
 12615  		"main.tf": "",
 12616  	})
 12617  
 12618  	p := simpleMockProvider()
 12619  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
 12620  		// we error during apply, which will trigger core to preserve the last
 12621  		// known state, including private data
 12622  		Diagnostics: tfdiags.Diagnostics(nil).Append(errors.New("oops")),
 12623  	}
 12624  
 12625  	addr := mustResourceInstanceAddr("test_object.a")
 12626  
 12627  	state := states.BuildState(func(s *states.SyncState) {
 12628  		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
 12629  			Status:    states.ObjectReady,
 12630  			AttrsJSON: []byte(`{"id":"foo"}`),
 12631  			Private:   []byte("private"),
 12632  		}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
 12633  	})
 12634  
 12635  	ctx := testContext2(t, &ContextOpts{
 12636  		Providers: map[addrs.Provider]providers.Factory{
 12637  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12638  		},
 12639  	})
 12640  
 12641  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
 12642  	if diags.HasErrors() {
 12643  		t.Fatal(diags.Err())
 12644  	}
 12645  
 12646  	state, _ = ctx.Apply(plan, m)
 12647  	if string(state.ResourceInstance(addr).Current.Private) != "private" {
 12648  		t.Fatal("missing private data in state")
 12649  	}
 12650  }
 12651  
 12652  func TestContext2Apply_errorRestoreStatus(t *testing.T) {
 12653  	// empty config to remove our resource
 12654  	m := testModuleInline(t, map[string]string{
 12655  		"main.tf": "",
 12656  	})
 12657  
 12658  	p := simpleMockProvider()
 12659  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 12660  		// We error during apply, but return the current object state.
 12661  		resp.Diagnostics = resp.Diagnostics.Append(errors.New("oops"))
 12662  		// return a warning too to make sure it isn't dropped
 12663  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warned"))
 12664  		resp.NewState = req.PriorState
 12665  		resp.Private = req.PlannedPrivate
 12666  		return resp
 12667  	}
 12668  
 12669  	addr := mustResourceInstanceAddr("test_object.a")
 12670  
 12671  	state := states.BuildState(func(s *states.SyncState) {
 12672  		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
 12673  			Status:       states.ObjectTainted,
 12674  			AttrsJSON:    []byte(`{"test_string":"foo"}`),
 12675  			Private:      []byte("private"),
 12676  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.b")},
 12677  		}, mustProviderConfig(`provider["registry.opentofu.org/hashicorp/test"]`))
 12678  	})
 12679  
 12680  	ctx := testContext2(t, &ContextOpts{
 12681  		Providers: map[addrs.Provider]providers.Factory{
 12682  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12683  		},
 12684  	})
 12685  
 12686  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
 12687  	if diags.HasErrors() {
 12688  		t.Fatal(diags.Err())
 12689  	}
 12690  
 12691  	state, diags = ctx.Apply(plan, m)
 12692  
 12693  	errString := diags.ErrWithWarnings().Error()
 12694  	if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") {
 12695  		t.Fatalf("error missing expected info: %q", errString)
 12696  	}
 12697  
 12698  	if len(diags) != 2 {
 12699  		t.Fatalf("expected 1 error and 1 warning, got: %q", errString)
 12700  	}
 12701  
 12702  	res := state.ResourceInstance(addr)
 12703  	if res == nil {
 12704  		t.Fatal("resource was removed from state")
 12705  	}
 12706  
 12707  	if res.Current.Status != states.ObjectTainted {
 12708  		t.Fatal("resource should still be tainted in the state")
 12709  	}
 12710  
 12711  	if len(res.Current.Dependencies) != 1 || !res.Current.Dependencies[0].Equal(mustConfigResourceAddr("test_object.b")) {
 12712  		t.Fatalf("incorrect dependencies, got %q", res.Current.Dependencies)
 12713  	}
 12714  
 12715  	if string(res.Current.Private) != "private" {
 12716  		t.Fatalf("incorrect private data, got %q", res.Current.Private)
 12717  	}
 12718  }
 12719  
 12720  func TestContext2Apply_nonConformingResponse(t *testing.T) {
 12721  	// empty config to remove our resource
 12722  	m := testModuleInline(t, map[string]string{
 12723  		"main.tf": `
 12724  resource "test_object" "a" {
 12725    test_string = "x"
 12726  }
 12727  `,
 12728  	})
 12729  
 12730  	p := simpleMockProvider()
 12731  	respDiags := tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("warned"))
 12732  	respDiags = respDiags.Append(errors.New("oops"))
 12733  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
 12734  		// Don't lose these diagnostics
 12735  		Diagnostics: respDiags,
 12736  		// This state is missing required attributes, and should produce an error
 12737  		NewState: cty.ObjectVal(map[string]cty.Value{
 12738  			"test_string": cty.StringVal("x"),
 12739  		}),
 12740  	}
 12741  
 12742  	ctx := testContext2(t, &ContextOpts{
 12743  		Providers: map[addrs.Provider]providers.Factory{
 12744  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12745  		},
 12746  	})
 12747  
 12748  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12749  	if diags.HasErrors() {
 12750  		t.Fatal(diags.Err())
 12751  	}
 12752  
 12753  	_, diags = ctx.Apply(plan, m)
 12754  	errString := diags.ErrWithWarnings().Error()
 12755  	if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") {
 12756  		t.Fatalf("error missing expected info: %q", errString)
 12757  	}
 12758  
 12759  	// we should have more than the ones returned from the provider, and they
 12760  	// should not be coalesced into a single value
 12761  	if len(diags) < 3 {
 12762  		t.Fatalf("incorrect diagnostics, got %d values with %s", len(diags), diags.ErrWithWarnings())
 12763  	}
 12764  }
 12765  
 12766  func TestContext2Apply_nilResponse(t *testing.T) {
 12767  	// empty config to remove our resource
 12768  	m := testModuleInline(t, map[string]string{
 12769  		"main.tf": `
 12770  resource "test_object" "a" {
 12771  }
 12772  `,
 12773  	})
 12774  
 12775  	p := simpleMockProvider()
 12776  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{}
 12777  
 12778  	ctx := testContext2(t, &ContextOpts{
 12779  		Providers: map[addrs.Provider]providers.Factory{
 12780  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12781  		},
 12782  	})
 12783  
 12784  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12785  	if diags.HasErrors() {
 12786  		t.Fatal(diags.Err())
 12787  	}
 12788  
 12789  	_, diags = ctx.Apply(plan, m)
 12790  	if !diags.HasErrors() {
 12791  		t.Fatal("expected and error")
 12792  	}
 12793  
 12794  	errString := diags.ErrWithWarnings().Error()
 12795  	if !strings.Contains(errString, "invalid nil value") {
 12796  		t.Fatalf("error missing expected info: %q", errString)
 12797  	}
 12798  }
 12799  
 12800  ////////////////////////////////////////////////////////////////////////////////
 12801  // NOTE: Due to the size of this file, new tests should be added to
 12802  // context_apply2_test.go.
 12803  ////////////////////////////////////////////////////////////////////////////////