github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/terraform/context_apply_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"log"
     9  	"reflect"
    10  	"runtime"
    11  	"sort"
    12  	"strings"
    13  	"sync"
    14  	"sync/atomic"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/davecgh/go-spew/spew"
    19  	"github.com/go-test/deep"
    20  	"github.com/google/go-cmp/cmp"
    21  	"github.com/muratcelep/terraform/not-internal/addrs"
    22  	"github.com/muratcelep/terraform/not-internal/configs"
    23  	"github.com/muratcelep/terraform/not-internal/configs/configschema"
    24  	"github.com/muratcelep/terraform/not-internal/configs/hcl2shim"
    25  	"github.com/muratcelep/terraform/not-internal/lang/marks"
    26  	"github.com/muratcelep/terraform/not-internal/plans"
    27  	"github.com/muratcelep/terraform/not-internal/providers"
    28  	"github.com/muratcelep/terraform/not-internal/provisioners"
    29  	"github.com/muratcelep/terraform/not-internal/states"
    30  	"github.com/muratcelep/terraform/not-internal/tfdiags"
    31  	"github.com/zclconf/go-cty/cty"
    32  	"github.com/zclconf/go-cty/cty/gocty"
    33  )
    34  
    35  func TestContext2Apply_basic(t *testing.T) {
    36  	m := testModule(t, "apply-good")
    37  	p := testProvider("aws")
    38  	p.PlanResourceChangeFn = testDiffFn
    39  	p.ApplyResourceChangeFn = testApplyFn
    40  	ctx := testContext2(t, &ContextOpts{
    41  		Providers: map[addrs.Provider]providers.Factory{
    42  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
    43  		},
    44  	})
    45  
    46  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
    47  	assertNoErrors(t, diags)
    48  
    49  	state, diags := ctx.Apply(plan, m)
    50  	if diags.HasErrors() {
    51  		t.Fatalf("diags: %s", diags.Err())
    52  	}
    53  
    54  	mod := state.RootModule()
    55  	if len(mod.Resources) < 2 {
    56  		t.Fatalf("bad: %#v", mod.Resources)
    57  	}
    58  
    59  	actual := strings.TrimSpace(state.String())
    60  	expected := strings.TrimSpace(testTerraformApplyStr)
    61  	if actual != expected {
    62  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
    63  	}
    64  }
    65  
    66  func TestContext2Apply_unstable(t *testing.T) {
    67  	// This tests behavior when the configuration contains an unstable value,
    68  	// such as the result of uuid() or timestamp(), where each call produces
    69  	// a different result.
    70  	//
    71  	// This is an important case to test because we need to ensure that
    72  	// we don't re-call the function during the apply phase: the value should
    73  	// be fixed during plan
    74  
    75  	m := testModule(t, "apply-unstable")
    76  	p := testProvider("test")
    77  	p.PlanResourceChangeFn = testDiffFn
    78  	ctx := testContext2(t, &ContextOpts{
    79  		Providers: map[addrs.Provider]providers.Factory{
    80  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
    81  		},
    82  	})
    83  
    84  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
    85  	if diags.HasErrors() {
    86  		t.Fatalf("unexpected error during Plan: %s", diags.Err())
    87  	}
    88  
    89  	addr := addrs.Resource{
    90  		Mode: addrs.ManagedResourceMode,
    91  		Type: "test_resource",
    92  		Name: "foo",
    93  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
    94  	schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
    95  	rds := plan.Changes.ResourceInstance(addr)
    96  	rd, err := rds.Decode(schema.ImpliedType())
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  	if rd.After.GetAttr("random").IsKnown() {
   101  		t.Fatalf("Attribute 'random' has known value %#v; should be unknown in plan", rd.After.GetAttr("random"))
   102  	}
   103  
   104  	state, diags := ctx.Apply(plan, m)
   105  	if diags.HasErrors() {
   106  		t.Fatalf("unexpected error during Apply: %s", diags.Err())
   107  	}
   108  
   109  	mod := state.Module(addr.Module)
   110  	rss := state.ResourceInstance(addr)
   111  
   112  	if len(mod.Resources) != 1 {
   113  		t.Fatalf("wrong number of resources %d; want 1", len(mod.Resources))
   114  	}
   115  
   116  	rs, err := rss.Current.Decode(schema.ImpliedType())
   117  	if err != nil {
   118  		t.Fatalf("decode error: %v", err)
   119  	}
   120  	got := rs.Value.GetAttr("random")
   121  	if !got.IsKnown() {
   122  		t.Fatalf("random is still unknown after apply")
   123  	}
   124  	if got, want := len(got.AsString()), 36; got != want {
   125  		t.Fatalf("random string has wrong length %d; want %d", got, want)
   126  	}
   127  }
   128  
   129  func TestContext2Apply_escape(t *testing.T) {
   130  	m := testModule(t, "apply-escape")
   131  	p := testProvider("aws")
   132  	p.PlanResourceChangeFn = testDiffFn
   133  	p.ApplyResourceChangeFn = testApplyFn
   134  	ctx := testContext2(t, &ContextOpts{
   135  		Providers: map[addrs.Provider]providers.Factory{
   136  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   137  		},
   138  	})
   139  
   140  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   141  	assertNoErrors(t, diags)
   142  
   143  	state, diags := ctx.Apply(plan, m)
   144  	if diags.HasErrors() {
   145  		t.Fatalf("diags: %s", diags.Err())
   146  	}
   147  
   148  	checkStateString(t, state, `
   149  aws_instance.bar:
   150    ID = foo
   151    provider = provider["registry.terraform.io/hashicorp/aws"]
   152    foo = "bar"
   153    type = aws_instance
   154  `)
   155  }
   156  
   157  func TestContext2Apply_resourceCountOneList(t *testing.T) {
   158  	m := testModule(t, "apply-resource-count-one-list")
   159  	p := testProvider("null")
   160  	p.PlanResourceChangeFn = testDiffFn
   161  	p.ApplyResourceChangeFn = testApplyFn
   162  	ctx := testContext2(t, &ContextOpts{
   163  		Providers: map[addrs.Provider]providers.Factory{
   164  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   165  		},
   166  	})
   167  
   168  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   169  	assertNoErrors(t, diags)
   170  
   171  	state, diags := ctx.Apply(plan, m)
   172  	assertNoDiagnostics(t, diags)
   173  
   174  	got := strings.TrimSpace(state.String())
   175  	want := strings.TrimSpace(`null_resource.foo.0:
   176    ID = foo
   177    provider = provider["registry.terraform.io/hashicorp/null"]
   178  
   179  Outputs:
   180  
   181  test = [foo]`)
   182  	if got != want {
   183  		t.Fatalf("got:\n%s\n\nwant:\n%s\n", got, want)
   184  	}
   185  }
   186  func TestContext2Apply_resourceCountZeroList(t *testing.T) {
   187  	m := testModule(t, "apply-resource-count-zero-list")
   188  	p := testProvider("null")
   189  	p.PlanResourceChangeFn = testDiffFn
   190  	ctx := testContext2(t, &ContextOpts{
   191  		Providers: map[addrs.Provider]providers.Factory{
   192  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   193  		},
   194  	})
   195  
   196  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   197  	assertNoErrors(t, diags)
   198  
   199  	state, diags := ctx.Apply(plan, m)
   200  	if diags.HasErrors() {
   201  		t.Fatalf("diags: %s", diags.Err())
   202  	}
   203  
   204  	got := strings.TrimSpace(state.String())
   205  	want := strings.TrimSpace(`<no state>
   206  Outputs:
   207  
   208  test = []`)
   209  	if got != want {
   210  		t.Fatalf("wrong state\n\ngot:\n%s\n\nwant:\n%s\n", got, want)
   211  	}
   212  }
   213  
   214  func TestContext2Apply_resourceDependsOnModule(t *testing.T) {
   215  	m := testModule(t, "apply-resource-depends-on-module")
   216  	p := testProvider("aws")
   217  	p.PlanResourceChangeFn = testDiffFn
   218  
   219  	// verify the apply happens in the correct order
   220  	var mu sync.Mutex
   221  	var order []string
   222  
   223  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   224  		ami := req.PlannedState.GetAttr("ami").AsString()
   225  		switch ami {
   226  		case "child":
   227  
   228  			// make the child slower than the parent
   229  			time.Sleep(50 * time.Millisecond)
   230  
   231  			mu.Lock()
   232  			order = append(order, "child")
   233  			mu.Unlock()
   234  		case "parent":
   235  			mu.Lock()
   236  			order = append(order, "parent")
   237  			mu.Unlock()
   238  		}
   239  
   240  		return testApplyFn(req)
   241  	}
   242  
   243  	ctx := testContext2(t, &ContextOpts{
   244  		Providers: map[addrs.Provider]providers.Factory{
   245  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   246  		},
   247  	})
   248  
   249  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   250  	assertNoErrors(t, diags)
   251  
   252  	state, diags := ctx.Apply(plan, m)
   253  	if diags.HasErrors() {
   254  		t.Fatalf("diags: %s", diags.Err())
   255  	}
   256  
   257  	if !reflect.DeepEqual(order, []string{"child", "parent"}) {
   258  		t.Fatal("resources applied out of order")
   259  	}
   260  
   261  	checkStateString(t, state, testTerraformApplyResourceDependsOnModuleStr)
   262  }
   263  
   264  // Test that without a config, the Dependencies in the state are enough
   265  // to maintain proper ordering.
   266  func TestContext2Apply_resourceDependsOnModuleStateOnly(t *testing.T) {
   267  	m := testModule(t, "apply-resource-depends-on-module-empty")
   268  	p := testProvider("aws")
   269  	p.PlanResourceChangeFn = testDiffFn
   270  
   271  	state := states.NewState()
   272  	root := state.EnsureModule(addrs.RootModuleInstance)
   273  	root.SetResourceInstanceCurrent(
   274  		mustResourceInstanceAddr("aws_instance.a").Resource,
   275  		&states.ResourceInstanceObjectSrc{
   276  			Status:       states.ObjectReady,
   277  			AttrsJSON:    []byte(`{"id":"parent"}`),
   278  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.child")},
   279  		},
   280  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   281  	)
   282  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
   283  	child.SetResourceInstanceCurrent(
   284  		mustResourceInstanceAddr("aws_instance.child").Resource,
   285  		&states.ResourceInstanceObjectSrc{
   286  			Status:    states.ObjectReady,
   287  			AttrsJSON: []byte(`{"id":"child"}`),
   288  		},
   289  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   290  	)
   291  
   292  	{
   293  		// verify the apply happens in the correct order
   294  		var mu sync.Mutex
   295  		var order []string
   296  
   297  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   298  			id := req.PriorState.GetAttr("id")
   299  			if id.IsKnown() && id.AsString() == "parent" {
   300  				// make the dep slower than the parent
   301  				time.Sleep(50 * time.Millisecond)
   302  
   303  				mu.Lock()
   304  				order = append(order, "child")
   305  				mu.Unlock()
   306  			} else {
   307  				mu.Lock()
   308  				order = append(order, "parent")
   309  				mu.Unlock()
   310  			}
   311  
   312  			return testApplyFn(req)
   313  		}
   314  
   315  		ctx := testContext2(t, &ContextOpts{
   316  			Providers: map[addrs.Provider]providers.Factory{
   317  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   318  			},
   319  		})
   320  
   321  		plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   322  		assertNoErrors(t, diags)
   323  
   324  		state, diags := ctx.Apply(plan, m)
   325  		assertNoErrors(t, diags)
   326  
   327  		if !reflect.DeepEqual(order, []string{"child", "parent"}) {
   328  			t.Fatal("resources applied out of order")
   329  		}
   330  
   331  		checkStateString(t, state, "<no state>")
   332  	}
   333  }
   334  
   335  func TestContext2Apply_resourceDependsOnModuleDestroy(t *testing.T) {
   336  	m := testModule(t, "apply-resource-depends-on-module")
   337  	p := testProvider("aws")
   338  	p.PlanResourceChangeFn = testDiffFn
   339  
   340  	var globalState *states.State
   341  	{
   342  		ctx := testContext2(t, &ContextOpts{
   343  			Providers: map[addrs.Provider]providers.Factory{
   344  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   345  			},
   346  		})
   347  
   348  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   349  		assertNoErrors(t, diags)
   350  
   351  		state, diags := ctx.Apply(plan, m)
   352  		if diags.HasErrors() {
   353  			t.Fatalf("diags: %s", diags.Err())
   354  		}
   355  
   356  		globalState = state
   357  	}
   358  
   359  	{
   360  		// Wait for the dependency, sleep, and verify the graph never
   361  		// called a child.
   362  		var called int32
   363  		var checked bool
   364  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   365  			ami := req.PriorState.GetAttr("ami").AsString()
   366  			if ami == "parent" {
   367  				checked = true
   368  
   369  				// Sleep to allow parallel execution
   370  				time.Sleep(50 * time.Millisecond)
   371  
   372  				// Verify that called is 0 (dep not called)
   373  				if atomic.LoadInt32(&called) != 0 {
   374  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("module child should not be called"))
   375  					return resp
   376  				}
   377  			}
   378  
   379  			atomic.AddInt32(&called, 1)
   380  			return testApplyFn(req)
   381  		}
   382  
   383  		ctx := testContext2(t, &ContextOpts{
   384  			Providers: map[addrs.Provider]providers.Factory{
   385  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   386  			},
   387  		})
   388  
   389  		plan, diags := ctx.Plan(m, globalState, &PlanOpts{
   390  			Mode: plans.DestroyMode,
   391  		})
   392  		assertNoErrors(t, diags)
   393  
   394  		state, diags := ctx.Apply(plan, m)
   395  		if diags.HasErrors() {
   396  			t.Fatalf("diags: %s", diags.Err())
   397  		}
   398  
   399  		if !checked {
   400  			t.Fatal("should check")
   401  		}
   402  
   403  		checkStateString(t, state, `<no state>`)
   404  	}
   405  }
   406  
   407  func TestContext2Apply_resourceDependsOnModuleGrandchild(t *testing.T) {
   408  	m := testModule(t, "apply-resource-depends-on-module-deep")
   409  	p := testProvider("aws")
   410  	p.PlanResourceChangeFn = testDiffFn
   411  
   412  	{
   413  		// Wait for the dependency, sleep, and verify the graph never
   414  		// called a child.
   415  		var called int32
   416  		var checked bool
   417  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   418  			planned := req.PlannedState.AsValueMap()
   419  			if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" {
   420  				checked = true
   421  
   422  				// Sleep to allow parallel execution
   423  				time.Sleep(50 * time.Millisecond)
   424  
   425  				// Verify that called is 0 (dep not called)
   426  				if atomic.LoadInt32(&called) != 0 {
   427  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("aws_instance.a should not be called"))
   428  					return resp
   429  				}
   430  			}
   431  
   432  			atomic.AddInt32(&called, 1)
   433  			return testApplyFn(req)
   434  		}
   435  
   436  		ctx := testContext2(t, &ContextOpts{
   437  			Providers: map[addrs.Provider]providers.Factory{
   438  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   439  			},
   440  		})
   441  
   442  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   443  		assertNoErrors(t, diags)
   444  
   445  		state, diags := ctx.Apply(plan, m)
   446  		if diags.HasErrors() {
   447  			t.Fatalf("diags: %s", diags.Err())
   448  		}
   449  
   450  		if !checked {
   451  			t.Fatal("should check")
   452  		}
   453  
   454  		checkStateString(t, state, testTerraformApplyResourceDependsOnModuleDeepStr)
   455  	}
   456  }
   457  
   458  func TestContext2Apply_resourceDependsOnModuleInModule(t *testing.T) {
   459  	m := testModule(t, "apply-resource-depends-on-module-in-module")
   460  	p := testProvider("aws")
   461  	p.PlanResourceChangeFn = testDiffFn
   462  
   463  	{
   464  		// Wait for the dependency, sleep, and verify the graph never
   465  		// called a child.
   466  		var called int32
   467  		var checked bool
   468  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   469  			planned := req.PlannedState.AsValueMap()
   470  			if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" {
   471  				checked = true
   472  
   473  				// Sleep to allow parallel execution
   474  				time.Sleep(50 * time.Millisecond)
   475  
   476  				// Verify that called is 0 (dep not called)
   477  				if atomic.LoadInt32(&called) != 0 {
   478  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("something else was applied before grandchild; grandchild should be first"))
   479  					return resp
   480  				}
   481  			}
   482  
   483  			atomic.AddInt32(&called, 1)
   484  			return testApplyFn(req)
   485  		}
   486  
   487  		ctx := testContext2(t, &ContextOpts{
   488  			Providers: map[addrs.Provider]providers.Factory{
   489  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   490  			},
   491  		})
   492  
   493  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   494  		assertNoErrors(t, diags)
   495  
   496  		state, diags := ctx.Apply(plan, m)
   497  		if diags.HasErrors() {
   498  			t.Fatalf("diags: %s", diags.Err())
   499  		}
   500  
   501  		if !checked {
   502  			t.Fatal("should check")
   503  		}
   504  
   505  		checkStateString(t, state, testTerraformApplyResourceDependsOnModuleInModuleStr)
   506  	}
   507  }
   508  
   509  func TestContext2Apply_mapVarBetweenModules(t *testing.T) {
   510  	m := testModule(t, "apply-map-var-through-module")
   511  	p := testProvider("null")
   512  	p.PlanResourceChangeFn = testDiffFn
   513  	p.ApplyResourceChangeFn = testApplyFn
   514  	ctx := testContext2(t, &ContextOpts{
   515  		Providers: map[addrs.Provider]providers.Factory{
   516  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   517  		},
   518  	})
   519  
   520  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   521  	assertNoErrors(t, diags)
   522  
   523  	state, diags := ctx.Apply(plan, m)
   524  	if diags.HasErrors() {
   525  		t.Fatalf("diags: %s", diags.Err())
   526  	}
   527  
   528  	actual := strings.TrimSpace(state.String())
   529  	expected := strings.TrimSpace(`<no state>
   530  Outputs:
   531  
   532  amis_from_module = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }
   533  
   534  module.test:
   535    null_resource.noop:
   536      ID = foo
   537      provider = provider["registry.terraform.io/hashicorp/null"]
   538  
   539    Outputs:
   540  
   541    amis_out = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }`)
   542  	if actual != expected {
   543  		t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual)
   544  	}
   545  }
   546  
   547  func TestContext2Apply_refCount(t *testing.T) {
   548  	m := testModule(t, "apply-ref-count")
   549  	p := testProvider("aws")
   550  	p.PlanResourceChangeFn = testDiffFn
   551  	p.ApplyResourceChangeFn = testApplyFn
   552  	ctx := testContext2(t, &ContextOpts{
   553  		Providers: map[addrs.Provider]providers.Factory{
   554  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   555  		},
   556  	})
   557  
   558  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   559  	assertNoErrors(t, diags)
   560  
   561  	state, diags := ctx.Apply(plan, m)
   562  	if diags.HasErrors() {
   563  		t.Fatalf("diags: %s", diags.Err())
   564  	}
   565  
   566  	mod := state.RootModule()
   567  	if len(mod.Resources) < 2 {
   568  		t.Fatalf("bad: %#v", mod.Resources)
   569  	}
   570  
   571  	actual := strings.TrimSpace(state.String())
   572  	expected := strings.TrimSpace(testTerraformApplyRefCountStr)
   573  	if actual != expected {
   574  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   575  	}
   576  }
   577  
   578  func TestContext2Apply_providerAlias(t *testing.T) {
   579  	m := testModule(t, "apply-provider-alias")
   580  
   581  	// Each provider instance must be completely independent to ensure that we
   582  	// are verifying the correct state of each.
   583  	p := func() (providers.Interface, error) {
   584  		p := testProvider("aws")
   585  		p.PlanResourceChangeFn = testDiffFn
   586  		p.ApplyResourceChangeFn = testApplyFn
   587  		return p, nil
   588  	}
   589  	ctx := testContext2(t, &ContextOpts{
   590  		Providers: map[addrs.Provider]providers.Factory{
   591  			addrs.NewDefaultProvider("aws"): p,
   592  		},
   593  	})
   594  
   595  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   596  	assertNoErrors(t, diags)
   597  
   598  	state, diags := ctx.Apply(plan, m)
   599  	if diags.HasErrors() {
   600  		t.Fatalf("diags: %s", diags.Err())
   601  	}
   602  
   603  	mod := state.RootModule()
   604  	if len(mod.Resources) < 2 {
   605  		t.Fatalf("bad: %#v", mod.Resources)
   606  	}
   607  
   608  	actual := strings.TrimSpace(state.String())
   609  	expected := strings.TrimSpace(testTerraformApplyProviderAliasStr)
   610  	if actual != expected {
   611  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   612  	}
   613  }
   614  
   615  // Two providers that are configured should both be configured prior to apply
   616  func TestContext2Apply_providerAliasConfigure(t *testing.T) {
   617  	m := testModule(t, "apply-provider-alias-configure")
   618  
   619  	// Each provider instance must be completely independent to ensure that we
   620  	// are verifying the correct state of each.
   621  	p := func() (providers.Interface, error) {
   622  		p := testProvider("another")
   623  		p.ApplyResourceChangeFn = testApplyFn
   624  		p.PlanResourceChangeFn = testDiffFn
   625  		return p, nil
   626  	}
   627  
   628  	ctx := testContext2(t, &ContextOpts{
   629  		Providers: map[addrs.Provider]providers.Factory{
   630  			addrs.NewDefaultProvider("another"): p,
   631  		},
   632  	})
   633  
   634  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   635  	if diags.HasErrors() {
   636  		t.Fatalf("diags: %s", diags.Err())
   637  	} else {
   638  		t.Logf(legacyDiffComparisonString(plan.Changes))
   639  	}
   640  
   641  	// Configure to record calls AFTER Plan above
   642  	var configCount int32
   643  	p = func() (providers.Interface, error) {
   644  		p := testProvider("another")
   645  		p.ApplyResourceChangeFn = testApplyFn
   646  		p.PlanResourceChangeFn = testDiffFn
   647  		p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
   648  			atomic.AddInt32(&configCount, 1)
   649  
   650  			foo := req.Config.GetAttr("foo").AsString()
   651  			if foo != "bar" {
   652  				resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("foo: %#v", foo))
   653  			}
   654  
   655  			return
   656  		}
   657  		return p, nil
   658  	}
   659  
   660  	ctx = testContext2(t, &ContextOpts{
   661  		Providers: map[addrs.Provider]providers.Factory{
   662  			addrs.NewDefaultProvider("another"): p,
   663  		},
   664  	})
   665  
   666  	state, diags := ctx.Apply(plan, m)
   667  	if diags.HasErrors() {
   668  		t.Fatalf("diags: %s", diags.Err())
   669  	}
   670  
   671  	if configCount != 2 {
   672  		t.Fatalf("provider config expected 2 calls, got: %d", configCount)
   673  	}
   674  
   675  	actual := strings.TrimSpace(state.String())
   676  	expected := strings.TrimSpace(testTerraformApplyProviderAliasConfigStr)
   677  	if actual != expected {
   678  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   679  	}
   680  }
   681  
   682  // GH-2870
   683  func TestContext2Apply_providerWarning(t *testing.T) {
   684  	m := testModule(t, "apply-provider-warning")
   685  	p := testProvider("aws")
   686  	p.PlanResourceChangeFn = testDiffFn
   687  	p.ApplyResourceChangeFn = testApplyFn
   688  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
   689  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("just a warning"))
   690  		return
   691  	}
   692  	ctx := testContext2(t, &ContextOpts{
   693  		Providers: map[addrs.Provider]providers.Factory{
   694  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   695  		},
   696  	})
   697  
   698  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   699  	assertNoErrors(t, diags)
   700  
   701  	state, diags := ctx.Apply(plan, m)
   702  	if diags.HasErrors() {
   703  		t.Fatalf("diags: %s", diags.Err())
   704  	}
   705  
   706  	actual := strings.TrimSpace(state.String())
   707  	expected := strings.TrimSpace(`
   708  aws_instance.foo:
   709    ID = foo
   710    provider = provider["registry.terraform.io/hashicorp/aws"]
   711    type = aws_instance
   712  	`)
   713  	if actual != expected {
   714  		t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected)
   715  	}
   716  
   717  	if !p.ConfigureProviderCalled {
   718  		t.Fatalf("provider Configure() was never called!")
   719  	}
   720  }
   721  
   722  func TestContext2Apply_emptyModule(t *testing.T) {
   723  	// A module with only outputs (no resources)
   724  	m := testModule(t, "apply-empty-module")
   725  	p := testProvider("aws")
   726  	p.PlanResourceChangeFn = testDiffFn
   727  	ctx := testContext2(t, &ContextOpts{
   728  		Providers: map[addrs.Provider]providers.Factory{
   729  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   730  		},
   731  	})
   732  
   733  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   734  	assertNoErrors(t, diags)
   735  
   736  	state, diags := ctx.Apply(plan, m)
   737  	if diags.HasErrors() {
   738  		t.Fatalf("diags: %s", diags.Err())
   739  	}
   740  
   741  	actual := strings.TrimSpace(state.String())
   742  	actual = strings.Replace(actual, "  ", "", -1)
   743  	expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr)
   744  	if actual != expected {
   745  		t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected)
   746  	}
   747  }
   748  
   749  func TestContext2Apply_createBeforeDestroy(t *testing.T) {
   750  	m := testModule(t, "apply-good-create-before")
   751  	p := testProvider("aws")
   752  	p.PlanResourceChangeFn = testDiffFn
   753  	p.ApplyResourceChangeFn = testApplyFn
   754  	state := states.NewState()
   755  	root := state.EnsureModule(addrs.RootModuleInstance)
   756  	root.SetResourceInstanceCurrent(
   757  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   758  		&states.ResourceInstanceObjectSrc{
   759  			Status:    states.ObjectReady,
   760  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
   761  		},
   762  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   763  	)
   764  	ctx := testContext2(t, &ContextOpts{
   765  		Providers: map[addrs.Provider]providers.Factory{
   766  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   767  		},
   768  	})
   769  
   770  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   771  	if diags.HasErrors() {
   772  		t.Fatalf("diags: %s", diags.Err())
   773  	} else {
   774  		t.Logf(legacyDiffComparisonString(plan.Changes))
   775  	}
   776  
   777  	state, diags = ctx.Apply(plan, m)
   778  	if diags.HasErrors() {
   779  		t.Fatalf("diags: %s", diags.Err())
   780  	}
   781  
   782  	mod := state.RootModule()
   783  	if got, want := len(mod.Resources), 1; got != want {
   784  		t.Logf("state:\n%s", state)
   785  		t.Fatalf("wrong number of resources %d; want %d", got, want)
   786  	}
   787  
   788  	actual := strings.TrimSpace(state.String())
   789  	expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr)
   790  	if actual != expected {
   791  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
   792  	}
   793  }
   794  
   795  func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) {
   796  	m := testModule(t, "apply-good-create-before-update")
   797  	p := testProvider("aws")
   798  	p.PlanResourceChangeFn = testDiffFn
   799  
   800  	// signal that resource foo has started applying
   801  	fooChan := make(chan struct{})
   802  
   803  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   804  		id := req.PriorState.GetAttr("id").AsString()
   805  		switch id {
   806  		case "bar":
   807  			select {
   808  			case <-fooChan:
   809  				resp.Diagnostics = resp.Diagnostics.Append(errors.New("bar must be updated before foo is destroyed"))
   810  				return resp
   811  			case <-time.After(100 * time.Millisecond):
   812  				// wait a moment to ensure that foo is not going to be destroyed first
   813  			}
   814  		case "foo":
   815  			close(fooChan)
   816  		}
   817  
   818  		return testApplyFn(req)
   819  	}
   820  
   821  	state := states.NewState()
   822  	root := state.EnsureModule(addrs.RootModuleInstance)
   823  	fooAddr := mustResourceInstanceAddr("aws_instance.foo")
   824  	root.SetResourceInstanceCurrent(
   825  		fooAddr.Resource,
   826  		&states.ResourceInstanceObjectSrc{
   827  			Status:              states.ObjectReady,
   828  			AttrsJSON:           []byte(`{"id":"foo","foo":"bar"}`),
   829  			CreateBeforeDestroy: true,
   830  		},
   831  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   832  	)
   833  	root.SetResourceInstanceCurrent(
   834  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   835  		&states.ResourceInstanceObjectSrc{
   836  			Status:              states.ObjectReady,
   837  			AttrsJSON:           []byte(`{"id":"bar","foo":"bar"}`),
   838  			CreateBeforeDestroy: true,
   839  			Dependencies:        []addrs.ConfigResource{fooAddr.ContainingResource().Config()},
   840  		},
   841  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   842  	)
   843  
   844  	ctx := testContext2(t, &ContextOpts{
   845  		Providers: map[addrs.Provider]providers.Factory{
   846  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   847  		},
   848  	})
   849  
   850  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   851  	if diags.HasErrors() {
   852  		t.Fatalf("diags: %s", diags.Err())
   853  	} else {
   854  		t.Logf(legacyDiffComparisonString(plan.Changes))
   855  	}
   856  
   857  	state, diags = ctx.Apply(plan, m)
   858  	if diags.HasErrors() {
   859  		t.Fatalf("diags: %s", diags.Err())
   860  	}
   861  
   862  	mod := state.RootModule()
   863  	if len(mod.Resources) != 1 {
   864  		t.Fatalf("bad: %s", state)
   865  	}
   866  
   867  	actual := strings.TrimSpace(state.String())
   868  	expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr)
   869  	if actual != expected {
   870  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   871  	}
   872  }
   873  
   874  // This tests that when a CBD resource depends on a non-CBD resource,
   875  // we can still properly apply changes that require new for both.
   876  func TestContext2Apply_createBeforeDestroy_dependsNonCBD(t *testing.T) {
   877  	m := testModule(t, "apply-cbd-depends-non-cbd")
   878  	p := testProvider("aws")
   879  	p.PlanResourceChangeFn = testDiffFn
   880  	p.ApplyResourceChangeFn = testApplyFn
   881  
   882  	state := states.NewState()
   883  	root := state.EnsureModule(addrs.RootModuleInstance)
   884  	root.SetResourceInstanceCurrent(
   885  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   886  		&states.ResourceInstanceObjectSrc{
   887  			Status:    states.ObjectReady,
   888  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
   889  		},
   890  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   891  	)
   892  	root.SetResourceInstanceCurrent(
   893  		mustResourceInstanceAddr("aws_instance.foo").Resource,
   894  		&states.ResourceInstanceObjectSrc{
   895  			Status:    states.ObjectReady,
   896  			AttrsJSON: []byte(`{"id":"foo", "require_new": "abc"}`),
   897  		},
   898  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   899  	)
   900  
   901  	ctx := testContext2(t, &ContextOpts{
   902  		Providers: map[addrs.Provider]providers.Factory{
   903  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   904  		},
   905  	})
   906  
   907  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   908  	if diags.HasErrors() {
   909  		t.Fatalf("diags: %s", diags.Err())
   910  	} else {
   911  		t.Logf(legacyDiffComparisonString(plan.Changes))
   912  	}
   913  
   914  	state, diags = ctx.Apply(plan, m)
   915  	if diags.HasErrors() {
   916  		t.Fatalf("diags: %s", diags.Err())
   917  	}
   918  
   919  	checkStateString(t, state, `
   920  aws_instance.bar:
   921    ID = foo
   922    provider = provider["registry.terraform.io/hashicorp/aws"]
   923    require_new = yes
   924    type = aws_instance
   925    value = foo
   926  
   927    Dependencies:
   928      aws_instance.foo
   929  aws_instance.foo:
   930    ID = foo
   931    provider = provider["registry.terraform.io/hashicorp/aws"]
   932    require_new = yes
   933    type = aws_instance
   934  	`)
   935  }
   936  
   937  func TestContext2Apply_createBeforeDestroy_hook(t *testing.T) {
   938  	h := new(MockHook)
   939  	m := testModule(t, "apply-good-create-before")
   940  	p := testProvider("aws")
   941  	p.PlanResourceChangeFn = testDiffFn
   942  	p.ApplyResourceChangeFn = testApplyFn
   943  	state := states.NewState()
   944  	root := state.EnsureModule(addrs.RootModuleInstance)
   945  	root.SetResourceInstanceCurrent(
   946  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   947  		&states.ResourceInstanceObjectSrc{
   948  			Status:    states.ObjectReady,
   949  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
   950  		},
   951  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   952  	)
   953  
   954  	var actual []cty.Value
   955  	var actualLock sync.Mutex
   956  	h.PostApplyFn = func(addr addrs.AbsResourceInstance, gen states.Generation, sv cty.Value, e error) (HookAction, error) {
   957  		actualLock.Lock()
   958  
   959  		defer actualLock.Unlock()
   960  		actual = append(actual, sv)
   961  		return HookActionContinue, nil
   962  	}
   963  
   964  	ctx := testContext2(t, &ContextOpts{
   965  		Hooks: []Hook{h},
   966  		Providers: map[addrs.Provider]providers.Factory{
   967  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   968  		},
   969  	})
   970  
   971  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   972  	if diags.HasErrors() {
   973  		t.Fatalf("diags: %s", diags.Err())
   974  	} else {
   975  		t.Logf(legacyDiffComparisonString(plan.Changes))
   976  	}
   977  
   978  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
   979  		t.Fatalf("apply errors: %s", diags.Err())
   980  	}
   981  
   982  	expected := []cty.Value{
   983  		cty.ObjectVal(map[string]cty.Value{
   984  			"id":          cty.StringVal("foo"),
   985  			"require_new": cty.StringVal("xyz"),
   986  			"type":        cty.StringVal("aws_instance"),
   987  		}),
   988  		cty.NullVal(cty.DynamicPseudoType),
   989  	}
   990  
   991  	cmpOpt := cmp.Transformer("ctyshim", hcl2shim.ConfigValueFromHCL2)
   992  	if !cmp.Equal(actual, expected, cmpOpt) {
   993  		t.Fatalf("wrong state snapshot sequence\n%s", cmp.Diff(expected, actual, cmpOpt))
   994  	}
   995  }
   996  
   997  // Test that we can perform an apply with CBD in a count with deposed instances.
   998  func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) {
   999  	m := testModule(t, "apply-cbd-count")
  1000  	p := testProvider("aws")
  1001  	p.PlanResourceChangeFn = testDiffFn
  1002  	p.ApplyResourceChangeFn = testApplyFn
  1003  
  1004  	state := states.NewState()
  1005  	root := state.EnsureModule(addrs.RootModuleInstance)
  1006  	root.SetResourceInstanceCurrent(
  1007  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  1008  		&states.ResourceInstanceObjectSrc{
  1009  			Status:    states.ObjectTainted,
  1010  			AttrsJSON: []byte(`{"id":"bar"}`),
  1011  		},
  1012  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1013  	)
  1014  	root.SetResourceInstanceDeposed(
  1015  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  1016  		states.NewDeposedKey(),
  1017  		&states.ResourceInstanceObjectSrc{
  1018  			Status:    states.ObjectTainted,
  1019  			AttrsJSON: []byte(`{"id":"foo"}`),
  1020  		},
  1021  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1022  	)
  1023  	root.SetResourceInstanceCurrent(
  1024  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  1025  		&states.ResourceInstanceObjectSrc{
  1026  			Status:    states.ObjectTainted,
  1027  			AttrsJSON: []byte(`{"id":"bar"}`),
  1028  		},
  1029  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1030  	)
  1031  	root.SetResourceInstanceDeposed(
  1032  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  1033  		states.NewDeposedKey(),
  1034  		&states.ResourceInstanceObjectSrc{
  1035  			Status:    states.ObjectTainted,
  1036  			AttrsJSON: []byte(`{"id":"bar"}`),
  1037  		},
  1038  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1039  	)
  1040  
  1041  	ctx := testContext2(t, &ContextOpts{
  1042  		Providers: map[addrs.Provider]providers.Factory{
  1043  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1044  		},
  1045  	})
  1046  
  1047  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1048  	if diags.HasErrors() {
  1049  		t.Fatalf("diags: %s", diags.Err())
  1050  	} else {
  1051  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1052  	}
  1053  
  1054  	state, diags = ctx.Apply(plan, m)
  1055  	if diags.HasErrors() {
  1056  		t.Fatalf("diags: %s", diags.Err())
  1057  	}
  1058  
  1059  	checkStateString(t, state, `
  1060  aws_instance.bar.0:
  1061    ID = foo
  1062    provider = provider["registry.terraform.io/hashicorp/aws"]
  1063    foo = bar
  1064    type = aws_instance
  1065  aws_instance.bar.1:
  1066    ID = foo
  1067    provider = provider["registry.terraform.io/hashicorp/aws"]
  1068    foo = bar
  1069    type = aws_instance
  1070  	`)
  1071  }
  1072  
  1073  // Test that when we have a deposed instance but a good primary, we still
  1074  // destroy the deposed instance.
  1075  func TestContext2Apply_createBeforeDestroy_deposedOnly(t *testing.T) {
  1076  	m := testModule(t, "apply-cbd-deposed-only")
  1077  	p := testProvider("aws")
  1078  	p.PlanResourceChangeFn = testDiffFn
  1079  	p.ApplyResourceChangeFn = testApplyFn
  1080  
  1081  	state := states.NewState()
  1082  	root := state.EnsureModule(addrs.RootModuleInstance)
  1083  	root.SetResourceInstanceCurrent(
  1084  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1085  		&states.ResourceInstanceObjectSrc{
  1086  			Status:    states.ObjectReady,
  1087  			AttrsJSON: []byte(`{"id":"bar"}`),
  1088  		},
  1089  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1090  	)
  1091  	root.SetResourceInstanceDeposed(
  1092  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1093  		states.NewDeposedKey(),
  1094  		&states.ResourceInstanceObjectSrc{
  1095  			Status:    states.ObjectTainted,
  1096  			AttrsJSON: []byte(`{"id":"foo"}`),
  1097  		},
  1098  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1099  	)
  1100  
  1101  	ctx := testContext2(t, &ContextOpts{
  1102  		Providers: map[addrs.Provider]providers.Factory{
  1103  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1104  		},
  1105  	})
  1106  
  1107  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1108  	if diags.HasErrors() {
  1109  		t.Fatalf("diags: %s", diags.Err())
  1110  	} else {
  1111  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1112  	}
  1113  
  1114  	state, diags = ctx.Apply(plan, m)
  1115  	if diags.HasErrors() {
  1116  		t.Fatalf("diags: %s", diags.Err())
  1117  	}
  1118  
  1119  	checkStateString(t, state, `
  1120  aws_instance.bar:
  1121    ID = bar
  1122    provider = provider["registry.terraform.io/hashicorp/aws"]
  1123    type = aws_instance
  1124  	`)
  1125  }
  1126  
  1127  func TestContext2Apply_destroyComputed(t *testing.T) {
  1128  	m := testModule(t, "apply-destroy-computed")
  1129  	p := testProvider("aws")
  1130  	p.PlanResourceChangeFn = testDiffFn
  1131  	state := states.NewState()
  1132  	root := state.EnsureModule(addrs.RootModuleInstance)
  1133  	root.SetResourceInstanceCurrent(
  1134  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1135  		&states.ResourceInstanceObjectSrc{
  1136  			Status:    states.ObjectReady,
  1137  			AttrsJSON: []byte(`{"id":"foo", "output": "value"}`),
  1138  		},
  1139  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1140  	)
  1141  	ctx := testContext2(t, &ContextOpts{
  1142  		Providers: map[addrs.Provider]providers.Factory{
  1143  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1144  		},
  1145  	})
  1146  
  1147  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1148  		Mode: plans.DestroyMode,
  1149  	})
  1150  	if diags.HasErrors() {
  1151  		logDiagnostics(t, diags)
  1152  		t.Fatal("plan failed")
  1153  	} else {
  1154  		t.Logf("plan:\n\n%s", legacyDiffComparisonString(plan.Changes))
  1155  	}
  1156  
  1157  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1158  		logDiagnostics(t, diags)
  1159  		t.Fatal("apply failed")
  1160  	}
  1161  }
  1162  
  1163  // Test that the destroy operation uses depends_on as a source of ordering.
  1164  func TestContext2Apply_destroyDependsOn(t *testing.T) {
  1165  	// It is possible for this to be racy, so we loop a number of times
  1166  	// just to check.
  1167  	for i := 0; i < 10; i++ {
  1168  		testContext2Apply_destroyDependsOn(t)
  1169  	}
  1170  }
  1171  
  1172  func testContext2Apply_destroyDependsOn(t *testing.T) {
  1173  	m := testModule(t, "apply-destroy-depends-on")
  1174  	p := testProvider("aws")
  1175  	p.PlanResourceChangeFn = testDiffFn
  1176  
  1177  	state := states.NewState()
  1178  	root := state.EnsureModule(addrs.RootModuleInstance)
  1179  	root.SetResourceInstanceCurrent(
  1180  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1181  		&states.ResourceInstanceObjectSrc{
  1182  			Status:    states.ObjectReady,
  1183  			AttrsJSON: []byte(`{"id":"bar"}`),
  1184  		},
  1185  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1186  	)
  1187  	root.SetResourceInstanceCurrent(
  1188  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1189  		&states.ResourceInstanceObjectSrc{
  1190  			Status:       states.ObjectReady,
  1191  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1192  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
  1193  		},
  1194  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1195  	)
  1196  
  1197  	// Record the order we see Apply
  1198  	var actual []string
  1199  	var actualLock sync.Mutex
  1200  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1201  		actualLock.Lock()
  1202  		defer actualLock.Unlock()
  1203  		id := req.PriorState.GetAttr("id").AsString()
  1204  		actual = append(actual, id)
  1205  
  1206  		return testApplyFn(req)
  1207  	}
  1208  
  1209  	ctx := testContext2(t, &ContextOpts{
  1210  		Providers: map[addrs.Provider]providers.Factory{
  1211  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1212  		},
  1213  		Parallelism: 1, // To check ordering
  1214  	})
  1215  
  1216  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1217  		Mode: plans.DestroyMode,
  1218  	})
  1219  	assertNoErrors(t, diags)
  1220  
  1221  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1222  		t.Fatalf("apply errors: %s", diags.Err())
  1223  	}
  1224  
  1225  	expected := []string{"foo", "bar"}
  1226  	if !reflect.DeepEqual(actual, expected) {
  1227  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1228  	}
  1229  }
  1230  
  1231  // Test that destroy ordering is correct with dependencies only
  1232  // in the state.
  1233  func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) {
  1234  	newState := states.NewState()
  1235  	root := newState.EnsureModule(addrs.RootModuleInstance)
  1236  	root.SetResourceInstanceCurrent(
  1237  		addrs.Resource{
  1238  			Mode: addrs.ManagedResourceMode,
  1239  			Type: "aws_instance",
  1240  			Name: "foo",
  1241  		}.Instance(addrs.NoKey),
  1242  		&states.ResourceInstanceObjectSrc{
  1243  			Status:       states.ObjectReady,
  1244  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1245  			Dependencies: []addrs.ConfigResource{},
  1246  		},
  1247  		addrs.AbsProviderConfig{
  1248  			Provider: addrs.NewDefaultProvider("aws"),
  1249  			Module:   addrs.RootModule,
  1250  		},
  1251  	)
  1252  	root.SetResourceInstanceCurrent(
  1253  		addrs.Resource{
  1254  			Mode: addrs.ManagedResourceMode,
  1255  			Type: "aws_instance",
  1256  			Name: "bar",
  1257  		}.Instance(addrs.NoKey),
  1258  		&states.ResourceInstanceObjectSrc{
  1259  			Status:    states.ObjectReady,
  1260  			AttrsJSON: []byte(`{"id":"bar"}`),
  1261  			Dependencies: []addrs.ConfigResource{
  1262  				{
  1263  					Resource: addrs.Resource{
  1264  						Mode: addrs.ManagedResourceMode,
  1265  						Type: "aws_instance",
  1266  						Name: "foo",
  1267  					},
  1268  					Module: root.Addr.Module(),
  1269  				},
  1270  			},
  1271  		},
  1272  		addrs.AbsProviderConfig{
  1273  			Provider: addrs.NewDefaultProvider("aws"),
  1274  			Module:   addrs.RootModule,
  1275  		},
  1276  	)
  1277  
  1278  	// It is possible for this to be racy, so we loop a number of times
  1279  	// just to check.
  1280  	for i := 0; i < 10; i++ {
  1281  		t.Run("new", func(t *testing.T) {
  1282  			testContext2Apply_destroyDependsOnStateOnly(t, newState)
  1283  		})
  1284  	}
  1285  }
  1286  
  1287  func testContext2Apply_destroyDependsOnStateOnly(t *testing.T, state *states.State) {
  1288  	state = state.DeepCopy()
  1289  	m := testModule(t, "empty")
  1290  	p := testProvider("aws")
  1291  	p.PlanResourceChangeFn = testDiffFn
  1292  	// Record the order we see Apply
  1293  	var actual []string
  1294  	var actualLock sync.Mutex
  1295  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1296  		actualLock.Lock()
  1297  		defer actualLock.Unlock()
  1298  		id := req.PriorState.GetAttr("id").AsString()
  1299  		actual = append(actual, id)
  1300  		return testApplyFn(req)
  1301  	}
  1302  
  1303  	ctx := testContext2(t, &ContextOpts{
  1304  		Providers: map[addrs.Provider]providers.Factory{
  1305  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1306  		},
  1307  		Parallelism: 1, // To check ordering
  1308  	})
  1309  
  1310  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1311  		Mode: plans.DestroyMode,
  1312  	})
  1313  	assertNoErrors(t, diags)
  1314  
  1315  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1316  		t.Fatalf("apply errors: %s", diags.Err())
  1317  	}
  1318  
  1319  	expected := []string{"bar", "foo"}
  1320  	if !reflect.DeepEqual(actual, expected) {
  1321  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1322  	}
  1323  }
  1324  
  1325  // Test that destroy ordering is correct with dependencies only
  1326  // in the state within a module (GH-11749)
  1327  func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) {
  1328  	newState := states.NewState()
  1329  	child := newState.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1330  	child.SetResourceInstanceCurrent(
  1331  		addrs.Resource{
  1332  			Mode: addrs.ManagedResourceMode,
  1333  			Type: "aws_instance",
  1334  			Name: "foo",
  1335  		}.Instance(addrs.NoKey),
  1336  		&states.ResourceInstanceObjectSrc{
  1337  			Status:       states.ObjectReady,
  1338  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1339  			Dependencies: []addrs.ConfigResource{},
  1340  		},
  1341  		addrs.AbsProviderConfig{
  1342  			Provider: addrs.NewDefaultProvider("aws"),
  1343  			Module:   addrs.RootModule,
  1344  		},
  1345  	)
  1346  	child.SetResourceInstanceCurrent(
  1347  		addrs.Resource{
  1348  			Mode: addrs.ManagedResourceMode,
  1349  			Type: "aws_instance",
  1350  			Name: "bar",
  1351  		}.Instance(addrs.NoKey),
  1352  		&states.ResourceInstanceObjectSrc{
  1353  			Status:    states.ObjectReady,
  1354  			AttrsJSON: []byte(`{"id":"bar"}`),
  1355  			Dependencies: []addrs.ConfigResource{
  1356  				{
  1357  					Resource: addrs.Resource{
  1358  						Mode: addrs.ManagedResourceMode,
  1359  						Type: "aws_instance",
  1360  						Name: "foo",
  1361  					},
  1362  					Module: child.Addr.Module(),
  1363  				},
  1364  			},
  1365  		},
  1366  		addrs.AbsProviderConfig{
  1367  			Provider: addrs.NewDefaultProvider("aws"),
  1368  			Module:   addrs.RootModule,
  1369  		},
  1370  	)
  1371  
  1372  	// It is possible for this to be racy, so we loop a number of times
  1373  	// just to check.
  1374  	for i := 0; i < 10; i++ {
  1375  		t.Run("new", func(t *testing.T) {
  1376  			testContext2Apply_destroyDependsOnStateOnlyModule(t, newState)
  1377  		})
  1378  	}
  1379  }
  1380  
  1381  func testContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T, state *states.State) {
  1382  	state = state.DeepCopy()
  1383  	m := testModule(t, "empty")
  1384  	p := testProvider("aws")
  1385  	p.PlanResourceChangeFn = testDiffFn
  1386  
  1387  	// Record the order we see Apply
  1388  	var actual []string
  1389  	var actualLock sync.Mutex
  1390  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1391  		actualLock.Lock()
  1392  		defer actualLock.Unlock()
  1393  		id := req.PriorState.GetAttr("id").AsString()
  1394  		actual = append(actual, id)
  1395  		return testApplyFn(req)
  1396  	}
  1397  
  1398  	ctx := testContext2(t, &ContextOpts{
  1399  		Providers: map[addrs.Provider]providers.Factory{
  1400  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1401  		},
  1402  		Parallelism: 1, // To check ordering
  1403  	})
  1404  
  1405  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1406  		Mode: plans.DestroyMode,
  1407  	})
  1408  	assertNoErrors(t, diags)
  1409  
  1410  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1411  		t.Fatalf("apply errors: %s", diags.Err())
  1412  	}
  1413  
  1414  	expected := []string{"bar", "foo"}
  1415  	if !reflect.DeepEqual(actual, expected) {
  1416  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1417  	}
  1418  }
  1419  
  1420  func TestContext2Apply_dataBasic(t *testing.T) {
  1421  	m := testModule(t, "apply-data-basic")
  1422  	p := testProvider("null")
  1423  	p.PlanResourceChangeFn = testDiffFn
  1424  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  1425  		State: cty.ObjectVal(map[string]cty.Value{
  1426  			"id":  cty.StringVal("yo"),
  1427  			"foo": cty.NullVal(cty.String),
  1428  		}),
  1429  	}
  1430  
  1431  	ctx := testContext2(t, &ContextOpts{
  1432  		Providers: map[addrs.Provider]providers.Factory{
  1433  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  1434  		},
  1435  	})
  1436  
  1437  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1438  	if diags.HasErrors() {
  1439  		t.Fatalf("diags: %s", diags.Err())
  1440  	} else {
  1441  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1442  	}
  1443  
  1444  	state, diags := ctx.Apply(plan, m)
  1445  	assertNoErrors(t, diags)
  1446  
  1447  	actual := strings.TrimSpace(state.String())
  1448  	expected := strings.TrimSpace(testTerraformApplyDataBasicStr)
  1449  	if actual != expected {
  1450  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1451  	}
  1452  }
  1453  
  1454  func TestContext2Apply_destroyData(t *testing.T) {
  1455  	m := testModule(t, "apply-destroy-data-resource")
  1456  	p := testProvider("null")
  1457  	p.PlanResourceChangeFn = testDiffFn
  1458  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  1459  		return providers.ReadDataSourceResponse{
  1460  			State: req.Config,
  1461  		}
  1462  	}
  1463  
  1464  	state := states.NewState()
  1465  	root := state.EnsureModule(addrs.RootModuleInstance)
  1466  	root.SetResourceInstanceCurrent(
  1467  		mustResourceInstanceAddr("data.null_data_source.testing").Resource,
  1468  		&states.ResourceInstanceObjectSrc{
  1469  			Status:    states.ObjectReady,
  1470  			AttrsJSON: []byte(`{"id":"-"}`),
  1471  		},
  1472  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/null"]`),
  1473  	)
  1474  
  1475  	hook := &testHook{}
  1476  	ctx := testContext2(t, &ContextOpts{
  1477  		Providers: map[addrs.Provider]providers.Factory{
  1478  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  1479  		},
  1480  		Hooks: []Hook{hook},
  1481  	})
  1482  
  1483  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1484  		Mode: plans.DestroyMode,
  1485  	})
  1486  	if diags.HasErrors() {
  1487  		t.Fatalf("diags: %s", diags.Err())
  1488  	} else {
  1489  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1490  	}
  1491  
  1492  	newState, diags := ctx.Apply(plan, m)
  1493  	if diags.HasErrors() {
  1494  		t.Fatalf("diags: %s", diags.Err())
  1495  	}
  1496  
  1497  	if got := len(newState.Modules); got != 1 {
  1498  		t.Fatalf("state has %d modules after destroy; want 1", got)
  1499  	}
  1500  
  1501  	if got := len(newState.RootModule().Resources); got != 0 {
  1502  		t.Fatalf("state has %d resources after destroy; want 0", got)
  1503  	}
  1504  
  1505  	wantHookCalls := []*testHookCall{
  1506  		{"PreDiff", "data.null_data_source.testing"},
  1507  		{"PostDiff", "data.null_data_source.testing"},
  1508  		{"PreDiff", "data.null_data_source.testing"},
  1509  		{"PostDiff", "data.null_data_source.testing"},
  1510  		{"PostStateUpdate", ""},
  1511  	}
  1512  	if !reflect.DeepEqual(hook.Calls, wantHookCalls) {
  1513  		t.Errorf("wrong hook calls\ngot: %swant: %s", spew.Sdump(hook.Calls), spew.Sdump(wantHookCalls))
  1514  	}
  1515  }
  1516  
  1517  // https://github.com/muratcelep/terraform/pull/5096
  1518  func TestContext2Apply_destroySkipsCBD(t *testing.T) {
  1519  	// Config contains CBD resource depending on non-CBD resource, which triggers
  1520  	// a cycle if they are both replaced, but should _not_ trigger a cycle when
  1521  	// just doing a `terraform destroy`.
  1522  	m := testModule(t, "apply-destroy-cbd")
  1523  	p := testProvider("aws")
  1524  	p.PlanResourceChangeFn = testDiffFn
  1525  	state := states.NewState()
  1526  	root := state.EnsureModule(addrs.RootModuleInstance)
  1527  	root.SetResourceInstanceCurrent(
  1528  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1529  		&states.ResourceInstanceObjectSrc{
  1530  			Status:    states.ObjectReady,
  1531  			AttrsJSON: []byte(`{"id":"foo"}`),
  1532  		},
  1533  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1534  	)
  1535  	root.SetResourceInstanceCurrent(
  1536  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1537  		&states.ResourceInstanceObjectSrc{
  1538  			Status:    states.ObjectReady,
  1539  			AttrsJSON: []byte(`{"id":"foo"}`),
  1540  		},
  1541  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1542  	)
  1543  
  1544  	ctx := testContext2(t, &ContextOpts{
  1545  		Providers: map[addrs.Provider]providers.Factory{
  1546  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1547  		},
  1548  	})
  1549  
  1550  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1551  		Mode: plans.DestroyMode,
  1552  	})
  1553  	if diags.HasErrors() {
  1554  		t.Fatalf("diags: %s", diags.Err())
  1555  	} else {
  1556  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1557  	}
  1558  
  1559  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1560  		t.Fatalf("apply errors: %s", diags.Err())
  1561  	}
  1562  }
  1563  
  1564  func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) {
  1565  	m := testModule(t, "apply-destroy-mod-var-provider-config")
  1566  	p := func() (providers.Interface, error) {
  1567  		p := testProvider("aws")
  1568  		p.PlanResourceChangeFn = testDiffFn
  1569  		return p, nil
  1570  	}
  1571  	state := states.NewState()
  1572  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1573  	child.SetResourceInstanceCurrent(
  1574  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1575  		&states.ResourceInstanceObjectSrc{
  1576  			Status:    states.ObjectReady,
  1577  			AttrsJSON: []byte(`{"id":"foo"}`),
  1578  		},
  1579  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1580  	)
  1581  	ctx := testContext2(t, &ContextOpts{
  1582  		Providers: map[addrs.Provider]providers.Factory{
  1583  			addrs.NewDefaultProvider("aws"): p,
  1584  		},
  1585  	})
  1586  
  1587  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1588  		Mode: plans.DestroyMode,
  1589  	})
  1590  	assertNoErrors(t, diags)
  1591  
  1592  	_, diags = ctx.Apply(plan, m)
  1593  	if diags.HasErrors() {
  1594  		t.Fatalf("diags: %s", diags.Err())
  1595  	}
  1596  }
  1597  
  1598  func TestContext2Apply_destroyCrossProviders(t *testing.T) {
  1599  	m := testModule(t, "apply-destroy-cross-providers")
  1600  
  1601  	p_aws := testProvider("aws")
  1602  	p_aws.ApplyResourceChangeFn = testApplyFn
  1603  	p_aws.PlanResourceChangeFn = testDiffFn
  1604  	p_aws.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1605  		ResourceTypes: map[string]*configschema.Block{
  1606  			"aws_instance": {
  1607  				Attributes: map[string]*configschema.Attribute{
  1608  					"id": {
  1609  						Type:     cty.String,
  1610  						Computed: true,
  1611  					},
  1612  				},
  1613  			},
  1614  			"aws_vpc": {
  1615  				Attributes: map[string]*configschema.Attribute{
  1616  					"id": {
  1617  						Type:     cty.String,
  1618  						Computed: true,
  1619  					},
  1620  					"value": {
  1621  						Type:     cty.String,
  1622  						Optional: true,
  1623  					},
  1624  				},
  1625  			},
  1626  		},
  1627  	})
  1628  
  1629  	providers := map[addrs.Provider]providers.Factory{
  1630  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p_aws),
  1631  	}
  1632  
  1633  	ctx, m, state := getContextForApply_destroyCrossProviders(t, m, providers)
  1634  
  1635  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1636  		Mode: plans.DestroyMode,
  1637  	})
  1638  	assertNoErrors(t, diags)
  1639  
  1640  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1641  		logDiagnostics(t, diags)
  1642  		t.Fatal("apply failed")
  1643  	}
  1644  }
  1645  
  1646  func getContextForApply_destroyCrossProviders(t *testing.T, m *configs.Config, providerFactories map[addrs.Provider]providers.Factory) (*Context, *configs.Config, *states.State) {
  1647  	state := states.NewState()
  1648  	root := state.EnsureModule(addrs.RootModuleInstance)
  1649  	root.SetResourceInstanceCurrent(
  1650  		mustResourceInstanceAddr("aws_instance.shared").Resource,
  1651  		&states.ResourceInstanceObjectSrc{
  1652  			Status:    states.ObjectReady,
  1653  			AttrsJSON: []byte(`{"id":"test"}`),
  1654  		},
  1655  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1656  	)
  1657  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1658  	child.SetResourceInstanceCurrent(
  1659  		mustResourceInstanceAddr("aws_vpc.bar").Resource,
  1660  		&states.ResourceInstanceObjectSrc{
  1661  			Status:    states.ObjectReady,
  1662  			AttrsJSON: []byte(`{"id": "vpc-aaabbb12", "value":"test"}`),
  1663  		},
  1664  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1665  	)
  1666  
  1667  	ctx := testContext2(t, &ContextOpts{
  1668  		Providers: providerFactories,
  1669  	})
  1670  
  1671  	return ctx, m, state
  1672  }
  1673  
  1674  func TestContext2Apply_minimal(t *testing.T) {
  1675  	m := testModule(t, "apply-minimal")
  1676  	p := testProvider("aws")
  1677  	p.PlanResourceChangeFn = testDiffFn
  1678  	p.ApplyResourceChangeFn = testApplyFn
  1679  	ctx := testContext2(t, &ContextOpts{
  1680  		Providers: map[addrs.Provider]providers.Factory{
  1681  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1682  		},
  1683  	})
  1684  
  1685  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1686  	assertNoErrors(t, diags)
  1687  
  1688  	state, diags := ctx.Apply(plan, m)
  1689  	if diags.HasErrors() {
  1690  		t.Fatalf("diags: %s", diags.Err())
  1691  	}
  1692  
  1693  	actual := strings.TrimSpace(state.String())
  1694  	expected := strings.TrimSpace(testTerraformApplyMinimalStr)
  1695  	if actual != expected {
  1696  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1697  	}
  1698  }
  1699  
  1700  func TestContext2Apply_cancel(t *testing.T) {
  1701  	stopped := false
  1702  
  1703  	m := testModule(t, "apply-cancel")
  1704  	p := testProvider("aws")
  1705  	ctx := testContext2(t, &ContextOpts{
  1706  		Providers: map[addrs.Provider]providers.Factory{
  1707  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1708  		},
  1709  	})
  1710  
  1711  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1712  		if !stopped {
  1713  			stopped = true
  1714  			go ctx.Stop()
  1715  
  1716  			for {
  1717  				if ctx.sh.Stopped() {
  1718  					break
  1719  				}
  1720  				time.Sleep(10 * time.Millisecond)
  1721  			}
  1722  		}
  1723  		return testApplyFn(req)
  1724  	}
  1725  	p.PlanResourceChangeFn = testDiffFn
  1726  
  1727  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1728  	assertNoErrors(t, diags)
  1729  
  1730  	// Start the Apply in a goroutine
  1731  	var applyDiags tfdiags.Diagnostics
  1732  	stateCh := make(chan *states.State)
  1733  	go func() {
  1734  		state, diags := ctx.Apply(plan, m)
  1735  		applyDiags = diags
  1736  
  1737  		stateCh <- state
  1738  	}()
  1739  
  1740  	state := <-stateCh
  1741  	// only expecting an early exit error
  1742  	if !applyDiags.HasErrors() {
  1743  		t.Fatal("expected early exit error")
  1744  	}
  1745  
  1746  	for _, d := range applyDiags {
  1747  		desc := d.Description()
  1748  		if desc.Summary != "execution halted" {
  1749  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  1750  		}
  1751  	}
  1752  
  1753  	actual := strings.TrimSpace(state.String())
  1754  	expected := strings.TrimSpace(testTerraformApplyCancelStr)
  1755  	if actual != expected {
  1756  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1757  	}
  1758  
  1759  	if !p.StopCalled {
  1760  		t.Fatal("stop should be called")
  1761  	}
  1762  }
  1763  
  1764  func TestContext2Apply_cancelBlock(t *testing.T) {
  1765  	m := testModule(t, "apply-cancel-block")
  1766  	p := testProvider("aws")
  1767  	ctx := testContext2(t, &ContextOpts{
  1768  		Providers: map[addrs.Provider]providers.Factory{
  1769  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1770  		},
  1771  	})
  1772  
  1773  	applyCh := make(chan struct{})
  1774  	p.PlanResourceChangeFn = testDiffFn
  1775  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1776  		close(applyCh)
  1777  
  1778  		for !ctx.sh.Stopped() {
  1779  			// Wait for stop to be called. We call Gosched here so that
  1780  			// the other goroutines can always be scheduled to set Stopped.
  1781  			runtime.Gosched()
  1782  		}
  1783  
  1784  		// Sleep
  1785  		time.Sleep(100 * time.Millisecond)
  1786  		return testApplyFn(req)
  1787  	}
  1788  
  1789  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1790  	assertNoErrors(t, diags)
  1791  
  1792  	// Start the Apply in a goroutine
  1793  	var applyDiags tfdiags.Diagnostics
  1794  	stateCh := make(chan *states.State)
  1795  	go func() {
  1796  		state, diags := ctx.Apply(plan, m)
  1797  		applyDiags = diags
  1798  
  1799  		stateCh <- state
  1800  	}()
  1801  
  1802  	stopDone := make(chan struct{})
  1803  	go func() {
  1804  		defer close(stopDone)
  1805  		<-applyCh
  1806  		ctx.Stop()
  1807  	}()
  1808  
  1809  	// Make sure that stop blocks
  1810  	select {
  1811  	case <-stopDone:
  1812  		t.Fatal("stop should block")
  1813  	case <-time.After(10 * time.Millisecond):
  1814  	}
  1815  
  1816  	// Wait for stop
  1817  	select {
  1818  	case <-stopDone:
  1819  	case <-time.After(500 * time.Millisecond):
  1820  		t.Fatal("stop should be done")
  1821  	}
  1822  
  1823  	// Wait for apply to complete
  1824  	state := <-stateCh
  1825  	// only expecting an early exit error
  1826  	if !applyDiags.HasErrors() {
  1827  		t.Fatal("expected early exit error")
  1828  	}
  1829  
  1830  	for _, d := range applyDiags {
  1831  		desc := d.Description()
  1832  		if desc.Summary != "execution halted" {
  1833  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  1834  		}
  1835  	}
  1836  
  1837  	checkStateString(t, state, `
  1838  aws_instance.foo:
  1839    ID = foo
  1840    provider = provider["registry.terraform.io/hashicorp/aws"]
  1841    num = 2
  1842    type = aws_instance
  1843  	`)
  1844  }
  1845  
  1846  func TestContext2Apply_cancelProvisioner(t *testing.T) {
  1847  	m := testModule(t, "apply-cancel-provisioner")
  1848  	p := testProvider("aws")
  1849  	p.PlanResourceChangeFn = testDiffFn
  1850  	p.ApplyResourceChangeFn = testApplyFn
  1851  
  1852  	pr := testProvisioner()
  1853  	pr.GetSchemaResponse = provisioners.GetSchemaResponse{
  1854  		Provisioner: &configschema.Block{
  1855  			Attributes: map[string]*configschema.Attribute{
  1856  				"foo": {
  1857  					Type:     cty.String,
  1858  					Optional: true,
  1859  				},
  1860  			},
  1861  		},
  1862  	}
  1863  
  1864  	ctx := testContext2(t, &ContextOpts{
  1865  		Providers: map[addrs.Provider]providers.Factory{
  1866  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1867  		},
  1868  		Provisioners: map[string]provisioners.Factory{
  1869  			"shell": testProvisionerFuncFixed(pr),
  1870  		},
  1871  	})
  1872  
  1873  	prStopped := make(chan struct{})
  1874  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  1875  		// Start the stop process
  1876  		go ctx.Stop()
  1877  
  1878  		<-prStopped
  1879  		return
  1880  	}
  1881  	pr.StopFn = func() error {
  1882  		close(prStopped)
  1883  		return nil
  1884  	}
  1885  
  1886  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1887  	assertNoErrors(t, diags)
  1888  
  1889  	// Start the Apply in a goroutine
  1890  	var applyDiags tfdiags.Diagnostics
  1891  	stateCh := make(chan *states.State)
  1892  	go func() {
  1893  		state, diags := ctx.Apply(plan, m)
  1894  		applyDiags = diags
  1895  
  1896  		stateCh <- state
  1897  	}()
  1898  
  1899  	// Wait for completion
  1900  	state := <-stateCh
  1901  
  1902  	// we are expecting only an early exit error
  1903  	if !applyDiags.HasErrors() {
  1904  		t.Fatal("expected early exit error")
  1905  	}
  1906  
  1907  	for _, d := range applyDiags {
  1908  		desc := d.Description()
  1909  		if desc.Summary != "execution halted" {
  1910  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  1911  		}
  1912  	}
  1913  
  1914  	checkStateString(t, state, `
  1915  aws_instance.foo: (tainted)
  1916    ID = foo
  1917    provider = provider["registry.terraform.io/hashicorp/aws"]
  1918    num = 2
  1919    type = aws_instance
  1920  	`)
  1921  
  1922  	if !pr.StopCalled {
  1923  		t.Fatal("stop should be called")
  1924  	}
  1925  }
  1926  
  1927  func TestContext2Apply_compute(t *testing.T) {
  1928  	m := testModule(t, "apply-compute")
  1929  	p := testProvider("aws")
  1930  	p.PlanResourceChangeFn = testDiffFn
  1931  	p.ApplyResourceChangeFn = testApplyFn
  1932  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1933  		ResourceTypes: map[string]*configschema.Block{
  1934  			"aws_instance": {
  1935  				Attributes: map[string]*configschema.Attribute{
  1936  					"num": {
  1937  						Type:     cty.Number,
  1938  						Optional: true,
  1939  					},
  1940  					"compute": {
  1941  						Type:     cty.String,
  1942  						Optional: true,
  1943  					},
  1944  					"compute_value": {
  1945  						Type:     cty.String,
  1946  						Optional: true,
  1947  					},
  1948  					"foo": {
  1949  						Type:     cty.String,
  1950  						Optional: true,
  1951  					},
  1952  					"id": {
  1953  						Type:     cty.String,
  1954  						Computed: true,
  1955  					},
  1956  					"type": {
  1957  						Type:     cty.String,
  1958  						Computed: true,
  1959  					},
  1960  					"value": { // Populated from compute_value because compute = "value" in the config fixture
  1961  						Type:     cty.String,
  1962  						Computed: true,
  1963  					},
  1964  				},
  1965  			},
  1966  		},
  1967  	})
  1968  
  1969  	ctx := testContext2(t, &ContextOpts{
  1970  		Providers: map[addrs.Provider]providers.Factory{
  1971  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1972  		},
  1973  	})
  1974  
  1975  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  1976  		SetVariables: InputValues{
  1977  			"value": &InputValue{
  1978  				Value:      cty.NumberIntVal(1),
  1979  				SourceType: ValueFromCaller,
  1980  			},
  1981  		},
  1982  	})
  1983  	assertNoErrors(t, diags)
  1984  
  1985  	state, diags := ctx.Apply(plan, m)
  1986  	if diags.HasErrors() {
  1987  		t.Fatalf("unexpected errors: %s", diags.Err())
  1988  	}
  1989  
  1990  	actual := strings.TrimSpace(state.String())
  1991  	expected := strings.TrimSpace(testTerraformApplyComputeStr)
  1992  	if actual != expected {
  1993  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1994  	}
  1995  }
  1996  
  1997  func TestContext2Apply_countDecrease(t *testing.T) {
  1998  	m := testModule(t, "apply-count-dec")
  1999  	p := testProvider("aws")
  2000  	p.PlanResourceChangeFn = testDiffFn
  2001  	p.ApplyResourceChangeFn = testApplyFn
  2002  	state := states.NewState()
  2003  	root := state.EnsureModule(addrs.RootModuleInstance)
  2004  	root.SetResourceInstanceCurrent(
  2005  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2006  		&states.ResourceInstanceObjectSrc{
  2007  			Status:    states.ObjectReady,
  2008  			AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`),
  2009  		},
  2010  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2011  	)
  2012  	root.SetResourceInstanceCurrent(
  2013  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  2014  		&states.ResourceInstanceObjectSrc{
  2015  			Status:    states.ObjectReady,
  2016  			AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`),
  2017  		},
  2018  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2019  	)
  2020  	root.SetResourceInstanceCurrent(
  2021  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  2022  		&states.ResourceInstanceObjectSrc{
  2023  			Status:    states.ObjectReady,
  2024  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  2025  		},
  2026  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2027  	)
  2028  
  2029  	ctx := testContext2(t, &ContextOpts{
  2030  		Providers: map[addrs.Provider]providers.Factory{
  2031  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2032  		},
  2033  	})
  2034  
  2035  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2036  	assertNoErrors(t, diags)
  2037  
  2038  	s, diags := ctx.Apply(plan, m)
  2039  	assertNoErrors(t, diags)
  2040  
  2041  	actual := strings.TrimSpace(s.String())
  2042  	expected := strings.TrimSpace(testTerraformApplyCountDecStr)
  2043  	if actual != expected {
  2044  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2045  	}
  2046  }
  2047  
  2048  func TestContext2Apply_countDecreaseToOneX(t *testing.T) {
  2049  	m := testModule(t, "apply-count-dec-one")
  2050  	p := testProvider("aws")
  2051  	p.PlanResourceChangeFn = testDiffFn
  2052  	state := states.NewState()
  2053  	root := state.EnsureModule(addrs.RootModuleInstance)
  2054  	root.SetResourceInstanceCurrent(
  2055  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2056  		&states.ResourceInstanceObjectSrc{
  2057  			Status:    states.ObjectReady,
  2058  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  2059  		},
  2060  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2061  	)
  2062  	root.SetResourceInstanceCurrent(
  2063  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  2064  		&states.ResourceInstanceObjectSrc{
  2065  			Status:    states.ObjectReady,
  2066  			AttrsJSON: []byte(`{"id":"bar"}`),
  2067  		},
  2068  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2069  	)
  2070  	root.SetResourceInstanceCurrent(
  2071  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  2072  		&states.ResourceInstanceObjectSrc{
  2073  			Status:    states.ObjectReady,
  2074  			AttrsJSON: []byte(`{"id":"bar"}`),
  2075  		},
  2076  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2077  	)
  2078  
  2079  	ctx := testContext2(t, &ContextOpts{
  2080  		Providers: map[addrs.Provider]providers.Factory{
  2081  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2082  		},
  2083  	})
  2084  
  2085  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2086  	assertNoErrors(t, diags)
  2087  
  2088  	s, diags := ctx.Apply(plan, m)
  2089  	if diags.HasErrors() {
  2090  		t.Fatalf("diags: %s", diags.Err())
  2091  	}
  2092  
  2093  	actual := strings.TrimSpace(s.String())
  2094  	expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr)
  2095  	if actual != expected {
  2096  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2097  	}
  2098  }
  2099  
  2100  // https://github.com/PeoplePerHour/terraform/pull/11
  2101  //
  2102  // This tests a rare but possible situation where we have both a no-key and
  2103  // a zero-key instance of the same resource in the configuration when we
  2104  // disable count.
  2105  //
  2106  // The main way to get here is for a provider to fail to destroy the zero-key
  2107  // instance but succeed in creating the no-key instance, since those two
  2108  // can typically happen concurrently. There are various other ways to get here
  2109  // that might be considered user error, such as using "terraform state mv"
  2110  // to create a strange combination of different key types on the same resource.
  2111  //
  2112  // This test indirectly exercises an intentional interaction between
  2113  // refactoring.ImpliedMoveStatements and refactoring.ApplyMoves: we'll first
  2114  // generate an implied move statement from aws_instance.foo[0] to
  2115  // aws_instance.foo, but then refactoring.ApplyMoves should notice that and
  2116  // ignore the statement, in the same way as it would if an explicit move
  2117  // statement specified the same situation.
  2118  func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) {
  2119  	m := testModule(t, "apply-count-dec-one")
  2120  	p := testProvider("aws")
  2121  	p.PlanResourceChangeFn = testDiffFn
  2122  	state := states.NewState()
  2123  	root := state.EnsureModule(addrs.RootModuleInstance)
  2124  	root.SetResourceInstanceCurrent(
  2125  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2126  		&states.ResourceInstanceObjectSrc{
  2127  			Status:    states.ObjectReady,
  2128  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  2129  		},
  2130  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2131  	)
  2132  	root.SetResourceInstanceCurrent(
  2133  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2134  		&states.ResourceInstanceObjectSrc{
  2135  			Status:    states.ObjectReady,
  2136  			AttrsJSON: []byte(`{"id":"baz", "type": "aws_instance"}`),
  2137  		},
  2138  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2139  	)
  2140  
  2141  	ctx := testContext2(t, &ContextOpts{
  2142  		Providers: map[addrs.Provider]providers.Factory{
  2143  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2144  		},
  2145  	})
  2146  
  2147  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2148  	assertNoErrors(t, diags)
  2149  	{
  2150  		got := strings.TrimSpace(legacyPlanComparisonString(state, plan.Changes))
  2151  		want := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedPlanStr)
  2152  		if got != want {
  2153  			t.Fatalf("wrong plan result\ngot:\n%s\nwant:\n%s", got, want)
  2154  		}
  2155  	}
  2156  	{
  2157  		change := plan.Changes.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo[0]"))
  2158  		if change == nil {
  2159  			t.Fatalf("no planned change for instance zero")
  2160  		}
  2161  		if got, want := change.Action, plans.Delete; got != want {
  2162  			t.Errorf("wrong action for instance zero %s; want %s", got, want)
  2163  		}
  2164  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want {
  2165  			t.Errorf("wrong action reason for instance zero %s; want %s", got, want)
  2166  		}
  2167  	}
  2168  	{
  2169  		change := plan.Changes.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo"))
  2170  		if change == nil {
  2171  			t.Fatalf("no planned change for no-key instance")
  2172  		}
  2173  		if got, want := change.Action, plans.NoOp; got != want {
  2174  			t.Errorf("wrong action for no-key instance %s; want %s", got, want)
  2175  		}
  2176  		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
  2177  			t.Errorf("wrong action reason for no-key instance %s; want %s", got, want)
  2178  		}
  2179  	}
  2180  
  2181  	s, diags := ctx.Apply(plan, m)
  2182  	if diags.HasErrors() {
  2183  		t.Fatalf("diags: %s", diags.Err())
  2184  	}
  2185  
  2186  	actual := strings.TrimSpace(s.String())
  2187  	expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr)
  2188  	if actual != expected {
  2189  		t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2190  	}
  2191  }
  2192  
  2193  func TestContext2Apply_countTainted(t *testing.T) {
  2194  	m := testModule(t, "apply-count-tainted")
  2195  	p := testProvider("aws")
  2196  	p.PlanResourceChangeFn = testDiffFn
  2197  	p.ApplyResourceChangeFn = testApplyFn
  2198  	state := states.NewState()
  2199  	root := state.EnsureModule(addrs.RootModuleInstance)
  2200  	root.SetResourceInstanceCurrent(
  2201  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2202  		&states.ResourceInstanceObjectSrc{
  2203  			Status:    states.ObjectTainted,
  2204  			AttrsJSON: []byte(`{"id":"bar", "type": "aws_instance", "foo": "foo"}`),
  2205  		},
  2206  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2207  	)
  2208  	ctx := testContext2(t, &ContextOpts{
  2209  		Providers: map[addrs.Provider]providers.Factory{
  2210  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2211  		},
  2212  	})
  2213  
  2214  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2215  	assertNoErrors(t, diags)
  2216  	{
  2217  		got := strings.TrimSpace(legacyDiffComparisonString(plan.Changes))
  2218  		want := strings.TrimSpace(`
  2219  DESTROY/CREATE: aws_instance.foo[0]
  2220    foo:  "foo" => "foo"
  2221    id:   "bar" => "<computed>"
  2222    type: "aws_instance" => "<computed>"
  2223  CREATE: aws_instance.foo[1]
  2224    foo:  "" => "foo"
  2225    id:   "" => "<computed>"
  2226    type: "" => "<computed>"
  2227  `)
  2228  		if got != want {
  2229  			t.Fatalf("wrong plan\n\ngot:\n%s\n\nwant:\n%s", got, want)
  2230  		}
  2231  	}
  2232  
  2233  	s, diags := ctx.Apply(plan, m)
  2234  	assertNoErrors(t, diags)
  2235  
  2236  	got := strings.TrimSpace(s.String())
  2237  	want := strings.TrimSpace(`
  2238  aws_instance.foo.0:
  2239    ID = foo
  2240    provider = provider["registry.terraform.io/hashicorp/aws"]
  2241    foo = foo
  2242    type = aws_instance
  2243  aws_instance.foo.1:
  2244    ID = foo
  2245    provider = provider["registry.terraform.io/hashicorp/aws"]
  2246    foo = foo
  2247    type = aws_instance
  2248  `)
  2249  	if got != want {
  2250  		t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", got, want)
  2251  	}
  2252  }
  2253  
  2254  func TestContext2Apply_countVariable(t *testing.T) {
  2255  	m := testModule(t, "apply-count-variable")
  2256  	p := testProvider("aws")
  2257  	p.PlanResourceChangeFn = testDiffFn
  2258  	p.ApplyResourceChangeFn = testApplyFn
  2259  	ctx := testContext2(t, &ContextOpts{
  2260  		Providers: map[addrs.Provider]providers.Factory{
  2261  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2262  		},
  2263  	})
  2264  
  2265  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2266  	assertNoErrors(t, diags)
  2267  
  2268  	state, diags := ctx.Apply(plan, m)
  2269  	if diags.HasErrors() {
  2270  		t.Fatalf("diags: %s", diags.Err())
  2271  	}
  2272  
  2273  	actual := strings.TrimSpace(state.String())
  2274  	expected := strings.TrimSpace(testTerraformApplyCountVariableStr)
  2275  	if actual != expected {
  2276  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2277  	}
  2278  }
  2279  
  2280  func TestContext2Apply_countVariableRef(t *testing.T) {
  2281  	m := testModule(t, "apply-count-variable-ref")
  2282  	p := testProvider("aws")
  2283  	p.PlanResourceChangeFn = testDiffFn
  2284  	p.ApplyResourceChangeFn = testApplyFn
  2285  	ctx := testContext2(t, &ContextOpts{
  2286  		Providers: map[addrs.Provider]providers.Factory{
  2287  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2288  		},
  2289  	})
  2290  
  2291  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2292  	assertNoErrors(t, diags)
  2293  
  2294  	state, diags := ctx.Apply(plan, m)
  2295  	if diags.HasErrors() {
  2296  		t.Fatalf("diags: %s", diags.Err())
  2297  	}
  2298  
  2299  	actual := strings.TrimSpace(state.String())
  2300  	expected := strings.TrimSpace(testTerraformApplyCountVariableRefStr)
  2301  	if actual != expected {
  2302  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2303  	}
  2304  }
  2305  
  2306  func TestContext2Apply_provisionerInterpCount(t *testing.T) {
  2307  	// This test ensures that a provisioner can interpolate a resource count
  2308  	// even though the provisioner expression is evaluated during the plan
  2309  	// walk. https://github.com/muratcelep/terraform/issues/16840
  2310  
  2311  	m, snap := testModuleWithSnapshot(t, "apply-provisioner-interp-count")
  2312  
  2313  	p := testProvider("aws")
  2314  	p.PlanResourceChangeFn = testDiffFn
  2315  
  2316  	pr := testProvisioner()
  2317  
  2318  	Providers := map[addrs.Provider]providers.Factory{
  2319  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2320  	}
  2321  
  2322  	provisioners := map[string]provisioners.Factory{
  2323  		"local-exec": testProvisionerFuncFixed(pr),
  2324  	}
  2325  	ctx := testContext2(t, &ContextOpts{
  2326  		Providers:    Providers,
  2327  		Provisioners: provisioners,
  2328  	})
  2329  
  2330  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2331  	assertNoErrors(t, diags)
  2332  
  2333  	// We'll marshal and unmarshal the plan here, to ensure that we have
  2334  	// a clean new context as would be created if we separately ran
  2335  	// terraform plan -out=tfplan && terraform apply tfplan
  2336  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  2337  	if err != nil {
  2338  		t.Fatal(err)
  2339  	}
  2340  	ctxOpts.Providers = Providers
  2341  	ctxOpts.Provisioners = provisioners
  2342  	ctx, diags = NewContext(ctxOpts)
  2343  	if diags.HasErrors() {
  2344  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  2345  	}
  2346  
  2347  	// Applying the plan should now succeed
  2348  	_, diags = ctx.Apply(plan, m)
  2349  	if diags.HasErrors() {
  2350  		t.Fatalf("apply failed unexpectedly: %s", diags.Err())
  2351  	}
  2352  
  2353  	// Verify apply was invoked
  2354  	if !pr.ProvisionResourceCalled {
  2355  		t.Fatalf("provisioner was not called")
  2356  	}
  2357  }
  2358  
  2359  func TestContext2Apply_foreachVariable(t *testing.T) {
  2360  	m := testModule(t, "plan-for-each-unknown-value")
  2361  	p := testProvider("aws")
  2362  	p.PlanResourceChangeFn = testDiffFn
  2363  	p.ApplyResourceChangeFn = testApplyFn
  2364  	ctx := testContext2(t, &ContextOpts{
  2365  		Providers: map[addrs.Provider]providers.Factory{
  2366  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2367  		},
  2368  	})
  2369  
  2370  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2371  		Mode: plans.NormalMode,
  2372  		SetVariables: InputValues{
  2373  			"foo": &InputValue{
  2374  				Value: cty.StringVal("hello"),
  2375  			},
  2376  		},
  2377  	})
  2378  	assertNoErrors(t, diags)
  2379  
  2380  	state, diags := ctx.Apply(plan, m)
  2381  	if diags.HasErrors() {
  2382  		t.Fatalf("diags: %s", diags.Err())
  2383  	}
  2384  
  2385  	actual := strings.TrimSpace(state.String())
  2386  	expected := strings.TrimSpace(testTerraformApplyForEachVariableStr)
  2387  	if actual != expected {
  2388  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2389  	}
  2390  }
  2391  
  2392  func TestContext2Apply_moduleBasic(t *testing.T) {
  2393  	m := testModule(t, "apply-module")
  2394  	p := testProvider("aws")
  2395  	p.PlanResourceChangeFn = testDiffFn
  2396  	p.ApplyResourceChangeFn = testApplyFn
  2397  	ctx := testContext2(t, &ContextOpts{
  2398  		Providers: map[addrs.Provider]providers.Factory{
  2399  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2400  		},
  2401  	})
  2402  
  2403  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2404  	assertNoErrors(t, diags)
  2405  
  2406  	state, diags := ctx.Apply(plan, m)
  2407  	if diags.HasErrors() {
  2408  		t.Fatalf("diags: %s", diags.Err())
  2409  	}
  2410  
  2411  	actual := strings.TrimSpace(state.String())
  2412  	expected := strings.TrimSpace(testTerraformApplyModuleStr)
  2413  	if actual != expected {
  2414  		t.Fatalf("bad, expected:\n%s\n\nactual:\n%s", expected, actual)
  2415  	}
  2416  }
  2417  
  2418  func TestContext2Apply_moduleDestroyOrder(t *testing.T) {
  2419  	m := testModule(t, "apply-module-destroy-order")
  2420  	p := testProvider("aws")
  2421  	p.PlanResourceChangeFn = testDiffFn
  2422  
  2423  	// Create a custom apply function to track the order they were destroyed
  2424  	var order []string
  2425  	var orderLock sync.Mutex
  2426  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  2427  		id := req.PriorState.GetAttr("id").AsString()
  2428  
  2429  		if id == "b" {
  2430  			// Pause briefly to make any race conditions more visible, since
  2431  			// missing edges here can cause undeterministic ordering.
  2432  			time.Sleep(100 * time.Millisecond)
  2433  		}
  2434  
  2435  		orderLock.Lock()
  2436  		defer orderLock.Unlock()
  2437  
  2438  		order = append(order, id)
  2439  		resp.NewState = req.PlannedState
  2440  		return resp
  2441  	}
  2442  
  2443  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2444  		ResourceTypes: map[string]*configschema.Block{
  2445  			"aws_instance": {
  2446  				Attributes: map[string]*configschema.Attribute{
  2447  					"id":    {Type: cty.String, Required: true},
  2448  					"blah":  {Type: cty.String, Optional: true},
  2449  					"value": {Type: cty.String, Optional: true},
  2450  				},
  2451  			},
  2452  		},
  2453  	})
  2454  
  2455  	state := states.NewState()
  2456  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2457  	child.SetResourceInstanceCurrent(
  2458  		mustResourceInstanceAddr("aws_instance.a").Resource,
  2459  		&states.ResourceInstanceObjectSrc{
  2460  			Status:    states.ObjectReady,
  2461  			AttrsJSON: []byte(`{"id":"a"}`),
  2462  		},
  2463  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2464  	)
  2465  	root := state.EnsureModule(addrs.RootModuleInstance)
  2466  	root.SetResourceInstanceCurrent(
  2467  		mustResourceInstanceAddr("aws_instance.b").Resource,
  2468  		&states.ResourceInstanceObjectSrc{
  2469  			Status:       states.ObjectReady,
  2470  			AttrsJSON:    []byte(`{"id":"b"}`),
  2471  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.a")},
  2472  		},
  2473  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2474  	)
  2475  
  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, state, &PlanOpts{
  2483  		Mode: plans.DestroyMode,
  2484  	})
  2485  	assertNoErrors(t, diags)
  2486  
  2487  	state, diags = ctx.Apply(plan, m)
  2488  	if diags.HasErrors() {
  2489  		t.Fatalf("diags: %s", diags.Err())
  2490  	}
  2491  
  2492  	expected := []string{"b", "a"}
  2493  	if !reflect.DeepEqual(order, expected) {
  2494  		t.Errorf("wrong order\ngot: %#v\nwant: %#v", order, expected)
  2495  	}
  2496  
  2497  	{
  2498  		actual := strings.TrimSpace(state.String())
  2499  		expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr)
  2500  		if actual != expected {
  2501  			t.Errorf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2502  		}
  2503  	}
  2504  }
  2505  
  2506  func TestContext2Apply_moduleInheritAlias(t *testing.T) {
  2507  	m := testModule(t, "apply-module-provider-inherit-alias")
  2508  	p := testProvider("aws")
  2509  	p.PlanResourceChangeFn = testDiffFn
  2510  	p.ApplyResourceChangeFn = testApplyFn
  2511  
  2512  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2513  		val := req.Config.GetAttr("value")
  2514  		if val.IsNull() {
  2515  			return
  2516  		}
  2517  
  2518  		root := req.Config.GetAttr("root")
  2519  		if !root.IsNull() {
  2520  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root"))
  2521  		}
  2522  
  2523  		return
  2524  	}
  2525  
  2526  	ctx := testContext2(t, &ContextOpts{
  2527  		Providers: map[addrs.Provider]providers.Factory{
  2528  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2529  		},
  2530  	})
  2531  
  2532  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2533  	assertNoErrors(t, diags)
  2534  
  2535  	state, diags := ctx.Apply(plan, m)
  2536  	if diags.HasErrors() {
  2537  		t.Fatalf("diags: %s", diags.Err())
  2538  	}
  2539  
  2540  	checkStateString(t, state, `
  2541  <no state>
  2542  module.child:
  2543    aws_instance.foo:
  2544      ID = foo
  2545      provider = provider["registry.terraform.io/hashicorp/aws"].eu
  2546      type = aws_instance
  2547  	`)
  2548  }
  2549  
  2550  func TestContext2Apply_orphanResource(t *testing.T) {
  2551  	// This is a two-step test:
  2552  	// 1. Apply a configuration with resources that have count set.
  2553  	//    This should place the empty resource object in the state to record
  2554  	//    that each exists, and record any instances.
  2555  	// 2. Apply an empty configuration against the same state, which should
  2556  	//    then clean up both the instances and the containing resource objects.
  2557  	p := testProvider("test")
  2558  	p.PlanResourceChangeFn = testDiffFn
  2559  	p.ApplyResourceChangeFn = testApplyFn
  2560  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2561  		ResourceTypes: map[string]*configschema.Block{
  2562  			"test_thing": {
  2563  				Attributes: map[string]*configschema.Attribute{
  2564  					"id":  {Type: cty.String, Computed: true},
  2565  					"foo": {Type: cty.String, Optional: true},
  2566  				},
  2567  			},
  2568  		},
  2569  	})
  2570  
  2571  	// Step 1: create the resources and instances
  2572  	m := testModule(t, "apply-orphan-resource")
  2573  	ctx := testContext2(t, &ContextOpts{
  2574  		Providers: map[addrs.Provider]providers.Factory{
  2575  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  2576  		},
  2577  	})
  2578  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2579  	assertNoErrors(t, diags)
  2580  	state, diags := ctx.Apply(plan, m)
  2581  	assertNoErrors(t, diags)
  2582  
  2583  	// At this point both resources should be recorded in the state, along
  2584  	// with the single instance associated with test_thing.one.
  2585  	want := states.BuildState(func(s *states.SyncState) {
  2586  		providerAddr := addrs.AbsProviderConfig{
  2587  			Provider: addrs.NewDefaultProvider("test"),
  2588  			Module:   addrs.RootModule,
  2589  		}
  2590  		oneAddr := addrs.Resource{
  2591  			Mode: addrs.ManagedResourceMode,
  2592  			Type: "test_thing",
  2593  			Name: "one",
  2594  		}.Absolute(addrs.RootModuleInstance)
  2595  		s.SetResourceProvider(oneAddr, providerAddr)
  2596  		s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{
  2597  			Status:    states.ObjectReady,
  2598  			AttrsJSON: []byte(`{"id":"foo"}`),
  2599  		}, providerAddr)
  2600  	})
  2601  
  2602  	if state.String() != want.String() {
  2603  		t.Fatalf("wrong state after step 1\n%s", cmp.Diff(want, state))
  2604  	}
  2605  
  2606  	// Step 2: update with an empty config, to destroy everything
  2607  	m = testModule(t, "empty")
  2608  	ctx = testContext2(t, &ContextOpts{
  2609  		Providers: map[addrs.Provider]providers.Factory{
  2610  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  2611  		},
  2612  	})
  2613  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  2614  	assertNoErrors(t, diags)
  2615  	{
  2616  		addr := mustResourceInstanceAddr("test_thing.one[0]")
  2617  		change := plan.Changes.ResourceInstance(addr)
  2618  		if change == nil {
  2619  			t.Fatalf("no planned change for %s", addr)
  2620  		}
  2621  		if got, want := change.Action, plans.Delete; got != want {
  2622  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2623  		}
  2624  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want {
  2625  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2626  		}
  2627  	}
  2628  
  2629  	state, diags = ctx.Apply(plan, m)
  2630  	assertNoErrors(t, diags)
  2631  
  2632  	// The state should now be _totally_ empty, with just an empty root module
  2633  	// (since that always exists) and no resources at all.
  2634  	want = states.NewState()
  2635  	if !cmp.Equal(state, want) {
  2636  		t.Fatalf("wrong state after step 2\ngot: %swant: %s", spew.Sdump(state), spew.Sdump(want))
  2637  	}
  2638  
  2639  }
  2640  
  2641  func TestContext2Apply_moduleOrphanInheritAlias(t *testing.T) {
  2642  	m := testModule(t, "apply-module-provider-inherit-alias-orphan")
  2643  	p := testProvider("aws")
  2644  	p.PlanResourceChangeFn = testDiffFn
  2645  
  2646  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2647  		val := req.Config.GetAttr("value")
  2648  		if val.IsNull() {
  2649  			return
  2650  		}
  2651  
  2652  		root := req.Config.GetAttr("root")
  2653  		if !root.IsNull() {
  2654  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root"))
  2655  		}
  2656  
  2657  		return
  2658  	}
  2659  
  2660  	// Create a state with an orphan module
  2661  	state := states.NewState()
  2662  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2663  	child.SetResourceInstanceCurrent(
  2664  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2665  		&states.ResourceInstanceObjectSrc{
  2666  			Status:    states.ObjectReady,
  2667  			AttrsJSON: []byte(`{"id":"bar"}`),
  2668  		},
  2669  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2670  	)
  2671  
  2672  	ctx := testContext2(t, &ContextOpts{
  2673  		Providers: map[addrs.Provider]providers.Factory{
  2674  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2675  		},
  2676  	})
  2677  
  2678  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2679  	assertNoErrors(t, diags)
  2680  	{
  2681  		addr := mustResourceInstanceAddr("module.child.aws_instance.bar")
  2682  		change := plan.Changes.ResourceInstance(addr)
  2683  		if change == nil {
  2684  			t.Fatalf("no planned change for %s", addr)
  2685  		}
  2686  		if got, want := change.Action, plans.Delete; got != want {
  2687  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2688  		}
  2689  		// This should ideally be ResourceInstanceDeleteBecauseNoModule, but
  2690  		// the codepath deciding this doesn't currently have enough information
  2691  		// to differentiate, and so this is a compromise.
  2692  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want {
  2693  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2694  		}
  2695  	}
  2696  
  2697  	state, diags = ctx.Apply(plan, m)
  2698  	if diags.HasErrors() {
  2699  		t.Fatalf("diags: %s", diags.Err())
  2700  	}
  2701  
  2702  	if !p.ConfigureProviderCalled {
  2703  		t.Fatal("must call configure")
  2704  	}
  2705  
  2706  	checkStateString(t, state, "<no state>")
  2707  }
  2708  
  2709  func TestContext2Apply_moduleOrphanProvider(t *testing.T) {
  2710  	m := testModule(t, "apply-module-orphan-provider-inherit")
  2711  	p := testProvider("aws")
  2712  	p.PlanResourceChangeFn = testDiffFn
  2713  
  2714  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2715  		val := req.Config.GetAttr("value")
  2716  		if val.IsNull() {
  2717  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2718  		}
  2719  
  2720  		return
  2721  	}
  2722  
  2723  	// Create a state with an orphan module
  2724  	state := states.NewState()
  2725  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2726  	child.SetResourceInstanceCurrent(
  2727  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2728  		&states.ResourceInstanceObjectSrc{
  2729  			Status:    states.ObjectReady,
  2730  			AttrsJSON: []byte(`{"id":"bar"}`),
  2731  		},
  2732  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2733  	)
  2734  
  2735  	ctx := testContext2(t, &ContextOpts{
  2736  		Providers: map[addrs.Provider]providers.Factory{
  2737  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2738  		},
  2739  	})
  2740  
  2741  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2742  	assertNoErrors(t, diags)
  2743  
  2744  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2745  		t.Fatalf("apply errors: %s", diags.Err())
  2746  	}
  2747  }
  2748  
  2749  func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) {
  2750  	m := testModule(t, "apply-module-orphan-provider-inherit")
  2751  	p := testProvider("aws")
  2752  	p.PlanResourceChangeFn = testDiffFn
  2753  
  2754  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2755  		val := req.Config.GetAttr("value")
  2756  		if val.IsNull() {
  2757  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2758  		}
  2759  
  2760  		return
  2761  	}
  2762  
  2763  	// Create a state with an orphan module that is nested (grandchild)
  2764  	state := states.NewState()
  2765  	child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child", addrs.NoKey))
  2766  	child.SetResourceInstanceCurrent(
  2767  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2768  		&states.ResourceInstanceObjectSrc{
  2769  			Status:    states.ObjectReady,
  2770  			AttrsJSON: []byte(`{"id":"bar"}`),
  2771  		},
  2772  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2773  	)
  2774  
  2775  	ctx := testContext2(t, &ContextOpts{
  2776  		Providers: map[addrs.Provider]providers.Factory{
  2777  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2778  		},
  2779  	})
  2780  
  2781  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2782  	assertNoErrors(t, diags)
  2783  
  2784  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2785  		t.Fatalf("apply errors: %s", diags.Err())
  2786  	}
  2787  }
  2788  
  2789  func TestContext2Apply_moduleGrandchildProvider(t *testing.T) {
  2790  	m := testModule(t, "apply-module-grandchild-provider-inherit")
  2791  	p := testProvider("aws")
  2792  	p.PlanResourceChangeFn = testDiffFn
  2793  
  2794  	var callLock sync.Mutex
  2795  	called := false
  2796  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2797  		val := req.Config.GetAttr("value")
  2798  		if val.IsNull() {
  2799  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2800  		}
  2801  
  2802  		callLock.Lock()
  2803  		called = true
  2804  		callLock.Unlock()
  2805  
  2806  		return
  2807  	}
  2808  
  2809  	ctx := testContext2(t, &ContextOpts{
  2810  		Providers: map[addrs.Provider]providers.Factory{
  2811  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2812  		},
  2813  	})
  2814  
  2815  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2816  	assertNoErrors(t, diags)
  2817  
  2818  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2819  		t.Fatalf("apply errors: %s", diags.Err())
  2820  	}
  2821  
  2822  	callLock.Lock()
  2823  	defer callLock.Unlock()
  2824  	if called != true {
  2825  		t.Fatalf("err: configure never called")
  2826  	}
  2827  }
  2828  
  2829  // This tests an issue where all the providers in a module but not
  2830  // in the root weren't being added to the root properly. In this test
  2831  // case: aws is explicitly added to root, but "test" should be added to.
  2832  // With the bug, it wasn't.
  2833  func TestContext2Apply_moduleOnlyProvider(t *testing.T) {
  2834  	m := testModule(t, "apply-module-only-provider")
  2835  	p := testProvider("aws")
  2836  	p.PlanResourceChangeFn = testDiffFn
  2837  	p.ApplyResourceChangeFn = testApplyFn
  2838  	pTest := testProvider("test")
  2839  	pTest.ApplyResourceChangeFn = testApplyFn
  2840  	pTest.PlanResourceChangeFn = testDiffFn
  2841  
  2842  	ctx := testContext2(t, &ContextOpts{
  2843  		Providers: map[addrs.Provider]providers.Factory{
  2844  			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
  2845  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
  2846  		},
  2847  	})
  2848  
  2849  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2850  	assertNoErrors(t, diags)
  2851  
  2852  	state, diags := ctx.Apply(plan, m)
  2853  	if diags.HasErrors() {
  2854  		t.Fatalf("diags: %s", diags.Err())
  2855  	}
  2856  
  2857  	actual := strings.TrimSpace(state.String())
  2858  	expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr)
  2859  	if actual != expected {
  2860  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2861  	}
  2862  }
  2863  
  2864  func TestContext2Apply_moduleProviderAlias(t *testing.T) {
  2865  	m := testModule(t, "apply-module-provider-alias")
  2866  	p := testProvider("aws")
  2867  	p.PlanResourceChangeFn = testDiffFn
  2868  	p.ApplyResourceChangeFn = testApplyFn
  2869  	ctx := testContext2(t, &ContextOpts{
  2870  		Providers: map[addrs.Provider]providers.Factory{
  2871  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2872  		},
  2873  	})
  2874  
  2875  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2876  	assertNoErrors(t, diags)
  2877  
  2878  	state, diags := ctx.Apply(plan, m)
  2879  	if diags.HasErrors() {
  2880  		t.Fatalf("diags: %s", diags.Err())
  2881  	}
  2882  
  2883  	actual := strings.TrimSpace(state.String())
  2884  	expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr)
  2885  	if actual != expected {
  2886  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2887  	}
  2888  }
  2889  
  2890  func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) {
  2891  	m := testModule(t, "apply-module-provider-alias")
  2892  	p := testProvider("aws")
  2893  	p.PlanResourceChangeFn = testDiffFn
  2894  	ctx := testContext2(t, &ContextOpts{
  2895  		Providers: map[addrs.Provider]providers.Factory{
  2896  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2897  		},
  2898  	})
  2899  
  2900  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2901  		Mode: plans.NormalMode,
  2902  		Targets: []addrs.Targetable{
  2903  			addrs.ConfigResource{
  2904  				Module: addrs.RootModule,
  2905  				Resource: addrs.Resource{
  2906  					Mode: addrs.ManagedResourceMode,
  2907  					Type: "nonexistent",
  2908  					Name: "thing",
  2909  				},
  2910  			},
  2911  		},
  2912  	})
  2913  	assertNoErrors(t, diags)
  2914  
  2915  	state, diags := ctx.Apply(plan, m)
  2916  	if diags.HasErrors() {
  2917  		t.Fatalf("diags: %s", diags.Err())
  2918  	}
  2919  
  2920  	actual := strings.TrimSpace(state.String())
  2921  	expected := strings.TrimSpace(`
  2922  <no state>
  2923  	`)
  2924  	if actual != expected {
  2925  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2926  	}
  2927  }
  2928  
  2929  func TestContext2Apply_moduleProviderCloseNested(t *testing.T) {
  2930  	m := testModule(t, "apply-module-provider-close-nested")
  2931  	p := testProvider("aws")
  2932  	p.PlanResourceChangeFn = testDiffFn
  2933  	state := states.NewState()
  2934  	root := state.EnsureModule(addrs.RootModuleInstance)
  2935  	root.SetResourceInstanceCurrent(
  2936  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2937  		&states.ResourceInstanceObjectSrc{
  2938  			Status:    states.ObjectReady,
  2939  			AttrsJSON: []byte(`{"id":"bar"}`),
  2940  		},
  2941  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2942  	)
  2943  
  2944  	ctx := testContext2(t, &ContextOpts{
  2945  		Providers: map[addrs.Provider]providers.Factory{
  2946  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2947  		},
  2948  	})
  2949  
  2950  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  2951  		Mode: plans.DestroyMode,
  2952  	})
  2953  	assertNoErrors(t, diags)
  2954  
  2955  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2956  		t.Fatalf("apply errors: %s", diags.Err())
  2957  	}
  2958  }
  2959  
  2960  // Tests that variables used as module vars that reference data that
  2961  // already exists in the state and requires no diff works properly. This
  2962  // fixes an issue faced where module variables were pruned because they were
  2963  // accessing "non-existent" resources (they existed, just not in the graph
  2964  // cause they weren't in the diff).
  2965  func TestContext2Apply_moduleVarRefExisting(t *testing.T) {
  2966  	m := testModule(t, "apply-ref-existing")
  2967  	p := testProvider("aws")
  2968  	p.PlanResourceChangeFn = testDiffFn
  2969  	p.ApplyResourceChangeFn = testApplyFn
  2970  	state := states.NewState()
  2971  	root := state.EnsureModule(addrs.RootModuleInstance)
  2972  	root.SetResourceInstanceCurrent(
  2973  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2974  		&states.ResourceInstanceObjectSrc{
  2975  			Status:    states.ObjectReady,
  2976  			AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`),
  2977  		},
  2978  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2979  	)
  2980  
  2981  	ctx := testContext2(t, &ContextOpts{
  2982  		Providers: map[addrs.Provider]providers.Factory{
  2983  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2984  		},
  2985  	})
  2986  
  2987  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2988  	assertNoErrors(t, diags)
  2989  
  2990  	state, diags = ctx.Apply(plan, m)
  2991  	if diags.HasErrors() {
  2992  		t.Fatalf("diags: %s", diags.Err())
  2993  	}
  2994  
  2995  	actual := strings.TrimSpace(state.String())
  2996  	expected := strings.TrimSpace(testTerraformApplyModuleVarRefExistingStr)
  2997  	if actual != expected {
  2998  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2999  	}
  3000  }
  3001  
  3002  func TestContext2Apply_moduleVarResourceCount(t *testing.T) {
  3003  	m := testModule(t, "apply-module-var-resource-count")
  3004  	p := testProvider("aws")
  3005  	p.PlanResourceChangeFn = testDiffFn
  3006  	ctx := testContext2(t, &ContextOpts{
  3007  		Providers: map[addrs.Provider]providers.Factory{
  3008  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3009  		},
  3010  	})
  3011  
  3012  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3013  		Mode: plans.DestroyMode,
  3014  		SetVariables: InputValues{
  3015  			"num": &InputValue{
  3016  				Value:      cty.NumberIntVal(2),
  3017  				SourceType: ValueFromCaller,
  3018  			},
  3019  		},
  3020  	})
  3021  	assertNoErrors(t, diags)
  3022  
  3023  	state, diags := ctx.Apply(plan, m)
  3024  	assertNoErrors(t, diags)
  3025  
  3026  	ctx = testContext2(t, &ContextOpts{
  3027  		Providers: map[addrs.Provider]providers.Factory{
  3028  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3029  		},
  3030  	})
  3031  
  3032  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  3033  		Mode: plans.NormalMode,
  3034  		SetVariables: InputValues{
  3035  			"num": &InputValue{
  3036  				Value:      cty.NumberIntVal(5),
  3037  				SourceType: ValueFromCaller,
  3038  			},
  3039  		},
  3040  	})
  3041  	assertNoErrors(t, diags)
  3042  
  3043  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3044  		t.Fatalf("apply errors: %s", diags.Err())
  3045  	}
  3046  }
  3047  
  3048  // GH-819
  3049  func TestContext2Apply_moduleBool(t *testing.T) {
  3050  	m := testModule(t, "apply-module-bool")
  3051  	p := testProvider("aws")
  3052  	p.PlanResourceChangeFn = testDiffFn
  3053  	p.ApplyResourceChangeFn = testApplyFn
  3054  	ctx := testContext2(t, &ContextOpts{
  3055  		Providers: map[addrs.Provider]providers.Factory{
  3056  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3057  		},
  3058  	})
  3059  
  3060  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3061  	assertNoErrors(t, diags)
  3062  
  3063  	state, diags := ctx.Apply(plan, m)
  3064  	if diags.HasErrors() {
  3065  		t.Fatalf("diags: %s", diags.Err())
  3066  	}
  3067  
  3068  	actual := strings.TrimSpace(state.String())
  3069  	expected := strings.TrimSpace(testTerraformApplyModuleBoolStr)
  3070  	if actual != expected {
  3071  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3072  	}
  3073  }
  3074  
  3075  // Tests that a module can be targeted and everything is properly created.
  3076  // This adds to the plan test to also just verify that apply works.
  3077  func TestContext2Apply_moduleTarget(t *testing.T) {
  3078  	m := testModule(t, "plan-targeted-cross-module")
  3079  	p := testProvider("aws")
  3080  	p.PlanResourceChangeFn = testDiffFn
  3081  	p.ApplyResourceChangeFn = testApplyFn
  3082  	ctx := testContext2(t, &ContextOpts{
  3083  		Providers: map[addrs.Provider]providers.Factory{
  3084  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3085  		},
  3086  	})
  3087  
  3088  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3089  		Mode: plans.NormalMode,
  3090  		Targets: []addrs.Targetable{
  3091  			addrs.RootModuleInstance.Child("B", addrs.NoKey),
  3092  		},
  3093  	})
  3094  	assertNoErrors(t, diags)
  3095  
  3096  	state, diags := ctx.Apply(plan, m)
  3097  	if diags.HasErrors() {
  3098  		t.Fatalf("diags: %s", diags.Err())
  3099  	}
  3100  
  3101  	checkStateString(t, state, `
  3102  <no state>
  3103  module.A:
  3104    aws_instance.foo:
  3105      ID = foo
  3106      provider = provider["registry.terraform.io/hashicorp/aws"]
  3107      foo = bar
  3108      type = aws_instance
  3109  
  3110    Outputs:
  3111  
  3112    value = foo
  3113  module.B:
  3114    aws_instance.bar:
  3115      ID = foo
  3116      provider = provider["registry.terraform.io/hashicorp/aws"]
  3117      foo = foo
  3118      type = aws_instance
  3119  
  3120      Dependencies:
  3121        module.A.aws_instance.foo
  3122  	`)
  3123  }
  3124  
  3125  func TestContext2Apply_multiProvider(t *testing.T) {
  3126  	m := testModule(t, "apply-multi-provider")
  3127  	p := testProvider("aws")
  3128  	p.PlanResourceChangeFn = testDiffFn
  3129  	p.ApplyResourceChangeFn = testApplyFn
  3130  
  3131  	pDO := testProvider("do")
  3132  	pDO.ApplyResourceChangeFn = testApplyFn
  3133  	pDO.PlanResourceChangeFn = testDiffFn
  3134  
  3135  	ctx := testContext2(t, &ContextOpts{
  3136  		Providers: map[addrs.Provider]providers.Factory{
  3137  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3138  			addrs.NewDefaultProvider("do"):  testProviderFuncFixed(pDO),
  3139  		},
  3140  	})
  3141  
  3142  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3143  	assertNoErrors(t, diags)
  3144  
  3145  	state, diags := ctx.Apply(plan, m)
  3146  	if diags.HasErrors() {
  3147  		t.Fatalf("diags: %s", diags.Err())
  3148  	}
  3149  
  3150  	mod := state.RootModule()
  3151  	if len(mod.Resources) < 2 {
  3152  		t.Fatalf("bad: %#v", mod.Resources)
  3153  	}
  3154  
  3155  	actual := strings.TrimSpace(state.String())
  3156  	expected := strings.TrimSpace(testTerraformApplyMultiProviderStr)
  3157  	if actual != expected {
  3158  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3159  	}
  3160  }
  3161  
  3162  func TestContext2Apply_multiProviderDestroy(t *testing.T) {
  3163  	m := testModule(t, "apply-multi-provider-destroy")
  3164  	p := testProvider("aws")
  3165  	p.PlanResourceChangeFn = testDiffFn
  3166  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3167  		Provider: &configschema.Block{
  3168  			Attributes: map[string]*configschema.Attribute{
  3169  				"addr": {Type: cty.String, Optional: true},
  3170  			},
  3171  		},
  3172  		ResourceTypes: map[string]*configschema.Block{
  3173  			"aws_instance": {
  3174  				Attributes: map[string]*configschema.Attribute{
  3175  					"id":  {Type: cty.String, Computed: true},
  3176  					"foo": {Type: cty.String, Optional: true},
  3177  				},
  3178  			},
  3179  		},
  3180  	})
  3181  
  3182  	p2 := testProvider("vault")
  3183  	p2.ApplyResourceChangeFn = testApplyFn
  3184  	p2.PlanResourceChangeFn = testDiffFn
  3185  	p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3186  		ResourceTypes: map[string]*configschema.Block{
  3187  			"vault_instance": {
  3188  				Attributes: map[string]*configschema.Attribute{
  3189  					"id": {Type: cty.String, Computed: true},
  3190  				},
  3191  			},
  3192  		},
  3193  	})
  3194  
  3195  	var state *states.State
  3196  
  3197  	// First, create the instances
  3198  	{
  3199  		ctx := testContext2(t, &ContextOpts{
  3200  			Providers: map[addrs.Provider]providers.Factory{
  3201  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3202  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3203  			},
  3204  		})
  3205  
  3206  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3207  		assertNoErrors(t, diags)
  3208  
  3209  		s, diags := ctx.Apply(plan, m)
  3210  		assertNoErrors(t, diags)
  3211  
  3212  		state = s
  3213  	}
  3214  
  3215  	// Destroy them
  3216  	{
  3217  		// Verify that aws_instance.bar is destroyed first
  3218  		var checked bool
  3219  		var called int32
  3220  		var lock sync.Mutex
  3221  		applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3222  			lock.Lock()
  3223  			defer lock.Unlock()
  3224  
  3225  			if req.TypeName == "aws_instance" {
  3226  				checked = true
  3227  
  3228  				// Sleep to allow parallel execution
  3229  				time.Sleep(50 * time.Millisecond)
  3230  
  3231  				// Verify that called is 0 (dep not called)
  3232  				if atomic.LoadInt32(&called) != 0 {
  3233  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3234  					return resp
  3235  				}
  3236  			}
  3237  
  3238  			atomic.AddInt32(&called, 1)
  3239  			return testApplyFn(req)
  3240  		}
  3241  
  3242  		// Set the apply functions
  3243  		p.ApplyResourceChangeFn = applyFn
  3244  		p2.ApplyResourceChangeFn = applyFn
  3245  
  3246  		ctx := testContext2(t, &ContextOpts{
  3247  			Providers: map[addrs.Provider]providers.Factory{
  3248  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3249  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3250  			},
  3251  		})
  3252  
  3253  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3254  			Mode: plans.DestroyMode,
  3255  		})
  3256  		assertNoErrors(t, diags)
  3257  
  3258  		s, diags := ctx.Apply(plan, m)
  3259  		assertNoErrors(t, diags)
  3260  
  3261  		if !checked {
  3262  			t.Fatal("should be checked")
  3263  		}
  3264  
  3265  		state = s
  3266  	}
  3267  
  3268  	checkStateString(t, state, `<no state>`)
  3269  }
  3270  
  3271  // This is like the multiProviderDestroy test except it tests that
  3272  // dependent resources within a child module that inherit provider
  3273  // configuration are still destroyed first.
  3274  func TestContext2Apply_multiProviderDestroyChild(t *testing.T) {
  3275  	m := testModule(t, "apply-multi-provider-destroy-child")
  3276  	p := testProvider("aws")
  3277  	p.PlanResourceChangeFn = testDiffFn
  3278  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3279  		Provider: &configschema.Block{
  3280  			Attributes: map[string]*configschema.Attribute{
  3281  				"value": {Type: cty.String, Optional: true},
  3282  			},
  3283  		},
  3284  		ResourceTypes: map[string]*configschema.Block{
  3285  			"aws_instance": {
  3286  				Attributes: map[string]*configschema.Attribute{
  3287  					"id":  {Type: cty.String, Computed: true},
  3288  					"foo": {Type: cty.String, Optional: true},
  3289  				},
  3290  			},
  3291  		},
  3292  	})
  3293  
  3294  	p2 := testProvider("vault")
  3295  	p2.ApplyResourceChangeFn = testApplyFn
  3296  	p2.PlanResourceChangeFn = testDiffFn
  3297  	p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3298  		Provider: &configschema.Block{},
  3299  		ResourceTypes: map[string]*configschema.Block{
  3300  			"vault_instance": {
  3301  				Attributes: map[string]*configschema.Attribute{
  3302  					"id": {Type: cty.String, Computed: true},
  3303  				},
  3304  			},
  3305  		},
  3306  	})
  3307  
  3308  	var state *states.State
  3309  
  3310  	// First, create the instances
  3311  	{
  3312  		ctx := testContext2(t, &ContextOpts{
  3313  			Providers: map[addrs.Provider]providers.Factory{
  3314  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3315  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3316  			},
  3317  		})
  3318  
  3319  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3320  		assertNoErrors(t, diags)
  3321  
  3322  		s, diags := ctx.Apply(plan, m)
  3323  		if diags.HasErrors() {
  3324  			t.Fatalf("diags: %s", diags.Err())
  3325  		}
  3326  
  3327  		state = s
  3328  	}
  3329  
  3330  	// Destroy them
  3331  	{
  3332  		// Verify that aws_instance.bar is destroyed first
  3333  		var checked bool
  3334  		var called int32
  3335  		var lock sync.Mutex
  3336  		applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3337  			lock.Lock()
  3338  			defer lock.Unlock()
  3339  
  3340  			if req.TypeName == "aws_instance" {
  3341  				checked = true
  3342  
  3343  				// Sleep to allow parallel execution
  3344  				time.Sleep(50 * time.Millisecond)
  3345  
  3346  				// Verify that called is 0 (dep not called)
  3347  				if atomic.LoadInt32(&called) != 0 {
  3348  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3349  					return resp
  3350  				}
  3351  			}
  3352  
  3353  			atomic.AddInt32(&called, 1)
  3354  			return testApplyFn(req)
  3355  		}
  3356  
  3357  		// Set the apply functions
  3358  		p.ApplyResourceChangeFn = applyFn
  3359  		p2.ApplyResourceChangeFn = applyFn
  3360  
  3361  		ctx := testContext2(t, &ContextOpts{
  3362  			Providers: map[addrs.Provider]providers.Factory{
  3363  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3364  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3365  			},
  3366  		})
  3367  
  3368  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3369  			Mode: plans.DestroyMode,
  3370  		})
  3371  		assertNoErrors(t, diags)
  3372  
  3373  		s, diags := ctx.Apply(plan, m)
  3374  		if diags.HasErrors() {
  3375  			t.Fatalf("diags: %s", diags.Err())
  3376  		}
  3377  
  3378  		if !checked {
  3379  			t.Fatal("should be checked")
  3380  		}
  3381  
  3382  		state = s
  3383  	}
  3384  
  3385  	checkStateString(t, state, `
  3386  <no state>
  3387  `)
  3388  }
  3389  
  3390  func TestContext2Apply_multiVar(t *testing.T) {
  3391  	m := testModule(t, "apply-multi-var")
  3392  	p := testProvider("aws")
  3393  	p.PlanResourceChangeFn = testDiffFn
  3394  
  3395  	// First, apply with a count of 3
  3396  	ctx := testContext2(t, &ContextOpts{
  3397  		Providers: map[addrs.Provider]providers.Factory{
  3398  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3399  		},
  3400  	})
  3401  
  3402  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3403  		Mode: plans.NormalMode,
  3404  		SetVariables: InputValues{
  3405  			"num": &InputValue{
  3406  				Value:      cty.NumberIntVal(3),
  3407  				SourceType: ValueFromCaller,
  3408  			},
  3409  		},
  3410  	})
  3411  	assertNoErrors(t, diags)
  3412  
  3413  	state, diags := ctx.Apply(plan, m)
  3414  	if diags.HasErrors() {
  3415  		t.Fatalf("diags: %s", diags.Err())
  3416  	}
  3417  
  3418  	actual := state.RootModule().OutputValues["output"]
  3419  	expected := cty.StringVal("bar0,bar1,bar2")
  3420  	if actual == nil || actual.Value != expected {
  3421  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3422  	}
  3423  
  3424  	t.Logf("Initial state: %s", state.String())
  3425  
  3426  	// Apply again, reduce the count to 1
  3427  	{
  3428  		ctx := testContext2(t, &ContextOpts{
  3429  			Providers: map[addrs.Provider]providers.Factory{
  3430  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3431  			},
  3432  		})
  3433  
  3434  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3435  			Mode: plans.NormalMode,
  3436  			SetVariables: InputValues{
  3437  				"num": &InputValue{
  3438  					Value:      cty.NumberIntVal(1),
  3439  					SourceType: ValueFromCaller,
  3440  				},
  3441  			},
  3442  		})
  3443  		assertNoErrors(t, diags)
  3444  
  3445  		state, diags := ctx.Apply(plan, m)
  3446  		if diags.HasErrors() {
  3447  			t.Fatalf("diags: %s", diags.Err())
  3448  		}
  3449  
  3450  		t.Logf("End state: %s", state.String())
  3451  
  3452  		actual := state.RootModule().OutputValues["output"]
  3453  		if actual == nil {
  3454  			t.Fatal("missing output")
  3455  		}
  3456  
  3457  		expected := cty.StringVal("bar0")
  3458  		if actual.Value != expected {
  3459  			t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3460  		}
  3461  	}
  3462  }
  3463  
  3464  // This is a holistic test of multi-var (aka "splat variable") handling
  3465  // across several different Terraform subsystems. This is here because
  3466  // historically there were quirky differences in handling across different
  3467  // parts of Terraform and so here we want to assert the expected behavior and
  3468  // ensure that it remains consistent in future.
  3469  func TestContext2Apply_multiVarComprehensive(t *testing.T) {
  3470  	m := testModule(t, "apply-multi-var-comprehensive")
  3471  	p := testProvider("test")
  3472  
  3473  	configs := map[string]cty.Value{}
  3474  	var configsLock sync.Mutex
  3475  
  3476  	p.ApplyResourceChangeFn = testApplyFn
  3477  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  3478  		proposed := req.ProposedNewState
  3479  		configsLock.Lock()
  3480  		defer configsLock.Unlock()
  3481  		key := proposed.GetAttr("key").AsString()
  3482  		// This test was originally written using the legacy p.PlanResourceChangeFn interface,
  3483  		// and so the assertions below expect an old-style ResourceConfig, which
  3484  		// we'll construct via our shim for now to avoid rewriting all of the
  3485  		// assertions.
  3486  		configs[key] = req.ProposedNewState
  3487  
  3488  		retVals := make(map[string]cty.Value)
  3489  		for it := proposed.ElementIterator(); it.Next(); {
  3490  			idxVal, val := it.Element()
  3491  			idx := idxVal.AsString()
  3492  
  3493  			switch idx {
  3494  			case "id":
  3495  				retVals[idx] = cty.UnknownVal(cty.String)
  3496  			case "name":
  3497  				retVals[idx] = cty.StringVal(key)
  3498  			default:
  3499  				retVals[idx] = val
  3500  			}
  3501  		}
  3502  
  3503  		return providers.PlanResourceChangeResponse{
  3504  			PlannedState: cty.ObjectVal(retVals),
  3505  		}
  3506  	}
  3507  
  3508  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3509  		ResourceTypes: map[string]*configschema.Block{
  3510  			"test_thing": {
  3511  				Attributes: map[string]*configschema.Attribute{
  3512  					"key": {Type: cty.String, Required: true},
  3513  
  3514  					"source_id":              {Type: cty.String, Optional: true},
  3515  					"source_name":            {Type: cty.String, Optional: true},
  3516  					"first_source_id":        {Type: cty.String, Optional: true},
  3517  					"first_source_name":      {Type: cty.String, Optional: true},
  3518  					"source_ids":             {Type: cty.List(cty.String), Optional: true},
  3519  					"source_names":           {Type: cty.List(cty.String), Optional: true},
  3520  					"source_ids_from_func":   {Type: cty.List(cty.String), Optional: true},
  3521  					"source_names_from_func": {Type: cty.List(cty.String), Optional: true},
  3522  					"source_ids_wrapped":     {Type: cty.List(cty.List(cty.String)), Optional: true},
  3523  					"source_names_wrapped":   {Type: cty.List(cty.List(cty.String)), Optional: true},
  3524  
  3525  					"id":   {Type: cty.String, Computed: true},
  3526  					"name": {Type: cty.String, Computed: true},
  3527  				},
  3528  			},
  3529  		},
  3530  	})
  3531  
  3532  	// First, apply with a count of 3
  3533  	ctx := testContext2(t, &ContextOpts{
  3534  		Providers: map[addrs.Provider]providers.Factory{
  3535  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  3536  		},
  3537  	})
  3538  
  3539  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3540  		Mode: plans.NormalMode,
  3541  		SetVariables: InputValues{
  3542  			"num": &InputValue{
  3543  				Value:      cty.NumberIntVal(3),
  3544  				SourceType: ValueFromCaller,
  3545  			},
  3546  		},
  3547  	})
  3548  	assertNoErrors(t, diags)
  3549  
  3550  	checkConfig := func(key string, want cty.Value) {
  3551  		configsLock.Lock()
  3552  		defer configsLock.Unlock()
  3553  
  3554  		got, ok := configs[key]
  3555  		if !ok {
  3556  			t.Errorf("no config recorded for %s; expected a configuration", key)
  3557  			return
  3558  		}
  3559  
  3560  		t.Run("config for "+key, func(t *testing.T) {
  3561  			for _, problem := range deep.Equal(got, want) {
  3562  				t.Errorf(problem)
  3563  			}
  3564  		})
  3565  	}
  3566  
  3567  	checkConfig("multi_count_var.0", cty.ObjectVal(map[string]cty.Value{
  3568  		"source_id":   cty.UnknownVal(cty.String),
  3569  		"source_name": cty.StringVal("source.0"),
  3570  	}))
  3571  	checkConfig("multi_count_var.2", cty.ObjectVal(map[string]cty.Value{
  3572  		"source_id":   cty.UnknownVal(cty.String),
  3573  		"source_name": cty.StringVal("source.2"),
  3574  	}))
  3575  	checkConfig("multi_count_derived.0", cty.ObjectVal(map[string]cty.Value{
  3576  		"source_id":   cty.UnknownVal(cty.String),
  3577  		"source_name": cty.StringVal("source.0"),
  3578  	}))
  3579  	checkConfig("multi_count_derived.2", cty.ObjectVal(map[string]cty.Value{
  3580  		"source_id":   cty.UnknownVal(cty.String),
  3581  		"source_name": cty.StringVal("source.2"),
  3582  	}))
  3583  	checkConfig("whole_splat", cty.ObjectVal(map[string]cty.Value{
  3584  		"source_ids": cty.ListVal([]cty.Value{
  3585  			cty.UnknownVal(cty.String),
  3586  			cty.UnknownVal(cty.String),
  3587  			cty.UnknownVal(cty.String),
  3588  		}),
  3589  		"source_names": cty.ListVal([]cty.Value{
  3590  			cty.StringVal("source.0"),
  3591  			cty.StringVal("source.1"),
  3592  			cty.StringVal("source.2"),
  3593  		}),
  3594  		"source_ids_from_func": cty.UnknownVal(cty.String),
  3595  		"source_names_from_func": cty.ListVal([]cty.Value{
  3596  			cty.StringVal("source.0"),
  3597  			cty.StringVal("source.1"),
  3598  			cty.StringVal("source.2"),
  3599  		}),
  3600  		"source_ids_wrapped": cty.ListVal([]cty.Value{
  3601  			cty.ListVal([]cty.Value{
  3602  				cty.UnknownVal(cty.String),
  3603  				cty.UnknownVal(cty.String),
  3604  				cty.UnknownVal(cty.String),
  3605  			}),
  3606  		}),
  3607  		"source_names_wrapped": cty.ListVal([]cty.Value{
  3608  			cty.ListVal([]cty.Value{
  3609  				cty.StringVal("source.0"),
  3610  				cty.StringVal("source.1"),
  3611  				cty.StringVal("source.2"),
  3612  			}),
  3613  		}),
  3614  		"first_source_id":   cty.UnknownVal(cty.String),
  3615  		"first_source_name": cty.StringVal("source.0"),
  3616  	}))
  3617  	checkConfig("child.whole_splat", cty.ObjectVal(map[string]cty.Value{
  3618  		"source_ids": cty.ListVal([]cty.Value{
  3619  			cty.UnknownVal(cty.String),
  3620  			cty.UnknownVal(cty.String),
  3621  			cty.UnknownVal(cty.String),
  3622  		}),
  3623  		"source_names": cty.ListVal([]cty.Value{
  3624  			cty.StringVal("source.0"),
  3625  			cty.StringVal("source.1"),
  3626  			cty.StringVal("source.2"),
  3627  		}),
  3628  		"source_ids_wrapped": cty.ListVal([]cty.Value{
  3629  			cty.ListVal([]cty.Value{
  3630  				cty.UnknownVal(cty.String),
  3631  				cty.UnknownVal(cty.String),
  3632  				cty.UnknownVal(cty.String),
  3633  			}),
  3634  		}),
  3635  		"source_names_wrapped": cty.ListVal([]cty.Value{
  3636  			cty.ListVal([]cty.Value{
  3637  				cty.StringVal("source.0"),
  3638  				cty.StringVal("source.1"),
  3639  				cty.StringVal("source.2"),
  3640  			}),
  3641  		}),
  3642  	}))
  3643  
  3644  	t.Run("apply", func(t *testing.T) {
  3645  		state, diags := ctx.Apply(plan, m)
  3646  		if diags.HasErrors() {
  3647  			t.Fatalf("error during apply: %s", diags.Err())
  3648  		}
  3649  
  3650  		want := map[string]interface{}{
  3651  			"source_ids": []interface{}{"foo", "foo", "foo"},
  3652  			"source_names": []interface{}{
  3653  				"source.0",
  3654  				"source.1",
  3655  				"source.2",
  3656  			},
  3657  		}
  3658  		got := map[string]interface{}{}
  3659  		for k, s := range state.RootModule().OutputValues {
  3660  			got[k] = hcl2shim.ConfigValueFromHCL2(s.Value)
  3661  		}
  3662  		if !reflect.DeepEqual(got, want) {
  3663  			t.Errorf(
  3664  				"wrong outputs\ngot:  %s\nwant: %s",
  3665  				spew.Sdump(got), spew.Sdump(want),
  3666  			)
  3667  		}
  3668  	})
  3669  }
  3670  
  3671  // Test that multi-var (splat) access is ordered by count, not by
  3672  // value.
  3673  func TestContext2Apply_multiVarOrder(t *testing.T) {
  3674  	m := testModule(t, "apply-multi-var-order")
  3675  	p := testProvider("aws")
  3676  	p.PlanResourceChangeFn = testDiffFn
  3677  
  3678  	// First, apply with a count of 3
  3679  	ctx := testContext2(t, &ContextOpts{
  3680  		Providers: map[addrs.Provider]providers.Factory{
  3681  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3682  		},
  3683  	})
  3684  
  3685  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3686  	assertNoErrors(t, diags)
  3687  
  3688  	state, diags := ctx.Apply(plan, m)
  3689  	if diags.HasErrors() {
  3690  		t.Fatalf("diags: %s", diags.Err())
  3691  	}
  3692  
  3693  	t.Logf("State: %s", state.String())
  3694  
  3695  	actual := state.RootModule().OutputValues["should-be-11"]
  3696  	expected := cty.StringVal("index-11")
  3697  	if actual == nil || actual.Value != expected {
  3698  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3699  	}
  3700  }
  3701  
  3702  // Test that multi-var (splat) access is ordered by count, not by
  3703  // value, through interpolations.
  3704  func TestContext2Apply_multiVarOrderInterp(t *testing.T) {
  3705  	m := testModule(t, "apply-multi-var-order-interp")
  3706  	p := testProvider("aws")
  3707  	p.PlanResourceChangeFn = testDiffFn
  3708  
  3709  	// First, apply with a count of 3
  3710  	ctx := testContext2(t, &ContextOpts{
  3711  		Providers: map[addrs.Provider]providers.Factory{
  3712  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3713  		},
  3714  	})
  3715  
  3716  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3717  	assertNoErrors(t, diags)
  3718  
  3719  	state, diags := ctx.Apply(plan, m)
  3720  	if diags.HasErrors() {
  3721  		t.Fatalf("diags: %s", diags.Err())
  3722  	}
  3723  
  3724  	t.Logf("State: %s", state.String())
  3725  
  3726  	actual := state.RootModule().OutputValues["should-be-11"]
  3727  	expected := cty.StringVal("baz-index-11")
  3728  	if actual == nil || actual.Value != expected {
  3729  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3730  	}
  3731  }
  3732  
  3733  // Based on GH-10440 where a graph edge wasn't properly being created
  3734  // between a modified resource and a count instance being destroyed.
  3735  func TestContext2Apply_multiVarCountDec(t *testing.T) {
  3736  	var s *states.State
  3737  
  3738  	// First create resources. Nothing sneaky here.
  3739  	{
  3740  		m := testModule(t, "apply-multi-var-count-dec")
  3741  		p := testProvider("aws")
  3742  		p.PlanResourceChangeFn = testDiffFn
  3743  		p.ApplyResourceChangeFn = testApplyFn
  3744  		ctx := testContext2(t, &ContextOpts{
  3745  			Providers: map[addrs.Provider]providers.Factory{
  3746  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3747  			},
  3748  		})
  3749  
  3750  		log.Print("\n========\nStep 1 Plan\n========")
  3751  		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3752  			Mode: plans.NormalMode,
  3753  			SetVariables: InputValues{
  3754  				"num": &InputValue{
  3755  					Value:      cty.NumberIntVal(2),
  3756  					SourceType: ValueFromCaller,
  3757  				},
  3758  			},
  3759  		})
  3760  		assertNoErrors(t, diags)
  3761  
  3762  		log.Print("\n========\nStep 1 Apply\n========")
  3763  		state, diags := ctx.Apply(plan, m)
  3764  		if diags.HasErrors() {
  3765  			t.Fatalf("diags: %s", diags.Err())
  3766  		}
  3767  
  3768  		t.Logf("Step 1 state:\n%s", state)
  3769  
  3770  		s = state
  3771  	}
  3772  
  3773  	// Decrease the count by 1 and verify that everything happens in the
  3774  	// right order.
  3775  	m := testModule(t, "apply-multi-var-count-dec")
  3776  	p := testProvider("aws")
  3777  	p.PlanResourceChangeFn = testDiffFn
  3778  
  3779  	// Verify that aws_instance.bar is modified first and nothing
  3780  	// else happens at the same time.
  3781  	{
  3782  		var checked bool
  3783  		var called int32
  3784  		var lock sync.Mutex
  3785  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3786  			lock.Lock()
  3787  			defer lock.Unlock()
  3788  
  3789  			if !req.PlannedState.IsNull() {
  3790  				s := req.PlannedState.AsValueMap()
  3791  				if ami, ok := s["ami"]; ok && !ami.IsNull() && ami.AsString() == "special" {
  3792  					checked = true
  3793  
  3794  					// Sleep to allow parallel execution
  3795  					time.Sleep(50 * time.Millisecond)
  3796  
  3797  					// Verify that called is 0 (dep not called)
  3798  					if atomic.LoadInt32(&called) != 1 {
  3799  						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3800  						return
  3801  					}
  3802  				}
  3803  			}
  3804  			atomic.AddInt32(&called, 1)
  3805  			return testApplyFn(req)
  3806  		}
  3807  
  3808  		ctx := testContext2(t, &ContextOpts{
  3809  			Providers: map[addrs.Provider]providers.Factory{
  3810  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3811  			},
  3812  		})
  3813  
  3814  		log.Print("\n========\nStep 2 Plan\n========")
  3815  		plan, diags := ctx.Plan(m, s, &PlanOpts{
  3816  			Mode: plans.NormalMode,
  3817  			SetVariables: InputValues{
  3818  				"num": &InputValue{
  3819  					Value:      cty.NumberIntVal(1),
  3820  					SourceType: ValueFromCaller,
  3821  				},
  3822  			},
  3823  		})
  3824  		assertNoErrors(t, diags)
  3825  
  3826  		t.Logf("Step 2 plan:\n%s", legacyDiffComparisonString(plan.Changes))
  3827  
  3828  		log.Print("\n========\nStep 2 Apply\n========")
  3829  		_, diags = ctx.Apply(plan, m)
  3830  		if diags.HasErrors() {
  3831  			t.Fatalf("apply errors: %s", diags.Err())
  3832  		}
  3833  
  3834  		if !checked {
  3835  			t.Error("apply never called")
  3836  		}
  3837  	}
  3838  }
  3839  
  3840  // Test that we can resolve a multi-var (splat) for the first resource
  3841  // created in a non-root module, which happens when the module state doesn't
  3842  // exist yet.
  3843  // https://github.com/muratcelep/terraform/issues/14438
  3844  func TestContext2Apply_multiVarMissingState(t *testing.T) {
  3845  	m := testModule(t, "apply-multi-var-missing-state")
  3846  	p := testProvider("test")
  3847  	p.PlanResourceChangeFn = testDiffFn
  3848  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3849  		ResourceTypes: map[string]*configschema.Block{
  3850  			"test_thing": {
  3851  				Attributes: map[string]*configschema.Attribute{
  3852  					"a_ids": {Type: cty.String, Optional: true},
  3853  					"id":    {Type: cty.String, Computed: true},
  3854  				},
  3855  			},
  3856  		},
  3857  	})
  3858  
  3859  	// First, apply with a count of 3
  3860  	ctx := testContext2(t, &ContextOpts{
  3861  		Providers: map[addrs.Provider]providers.Factory{
  3862  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  3863  		},
  3864  	})
  3865  
  3866  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3867  	assertNoErrors(t, diags)
  3868  
  3869  	// Before the relevant bug was fixed, Terraform would panic during apply.
  3870  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3871  		t.Fatalf("apply failed: %s", diags.Err())
  3872  	}
  3873  
  3874  	// If we get here with no errors or panics then our test was successful.
  3875  }
  3876  
  3877  func TestContext2Apply_outputOrphan(t *testing.T) {
  3878  	m := testModule(t, "apply-output-orphan")
  3879  	p := testProvider("aws")
  3880  	p.PlanResourceChangeFn = testDiffFn
  3881  
  3882  	state := states.NewState()
  3883  	root := state.EnsureModule(addrs.RootModuleInstance)
  3884  	root.SetOutputValue("foo", cty.StringVal("bar"), false)
  3885  	root.SetOutputValue("bar", cty.StringVal("baz"), false)
  3886  
  3887  	ctx := testContext2(t, &ContextOpts{
  3888  		Providers: map[addrs.Provider]providers.Factory{
  3889  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3890  		},
  3891  	})
  3892  
  3893  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3894  	assertNoErrors(t, diags)
  3895  
  3896  	state, diags = ctx.Apply(plan, m)
  3897  	if diags.HasErrors() {
  3898  		t.Fatalf("diags: %s", diags.Err())
  3899  	}
  3900  
  3901  	actual := strings.TrimSpace(state.String())
  3902  	expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr)
  3903  	if actual != expected {
  3904  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3905  	}
  3906  }
  3907  
  3908  func TestContext2Apply_outputOrphanModule(t *testing.T) {
  3909  	m := testModule(t, "apply-output-orphan-module")
  3910  	p := testProvider("aws")
  3911  	p.PlanResourceChangeFn = testDiffFn
  3912  
  3913  	state := states.NewState()
  3914  
  3915  	ctx := testContext2(t, &ContextOpts{
  3916  		Providers: map[addrs.Provider]providers.Factory{
  3917  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3918  		},
  3919  	})
  3920  
  3921  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3922  	assertNoErrors(t, diags)
  3923  
  3924  	s, diags := ctx.Apply(plan, m)
  3925  	if diags.HasErrors() {
  3926  		t.Fatalf("diags: %s", diags.Err())
  3927  	}
  3928  
  3929  	actual := strings.TrimSpace(s.String())
  3930  	expected := strings.TrimSpace(testTerraformApplyOutputOrphanModuleStr)
  3931  	if actual != expected {
  3932  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  3933  	}
  3934  
  3935  	// now apply with no module in the config, which should remove the
  3936  	// remaining output
  3937  	ctx = testContext2(t, &ContextOpts{
  3938  		Providers: map[addrs.Provider]providers.Factory{
  3939  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3940  		},
  3941  	})
  3942  
  3943  	emptyConfig := configs.NewEmptyConfig()
  3944  
  3945  	// NOTE: While updating this test to pass the state in as a Plan argument,
  3946  	// rather than into the testContext2 call above, it previously said
  3947  	// State: state.DeepCopy(), which is a little weird since we just
  3948  	// created "s" above as the result of the previous apply, but I've preserved
  3949  	// it to avoid changing the flow of this test in case that's important
  3950  	// for some reason.
  3951  	plan, diags = ctx.Plan(emptyConfig, state.DeepCopy(), DefaultPlanOpts)
  3952  	assertNoErrors(t, diags)
  3953  
  3954  	state, diags = ctx.Apply(plan, emptyConfig)
  3955  	if diags.HasErrors() {
  3956  		t.Fatalf("diags: %s", diags.Err())
  3957  	}
  3958  
  3959  	if !state.Empty() {
  3960  		t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(state))
  3961  	}
  3962  }
  3963  
  3964  func TestContext2Apply_providerComputedVar(t *testing.T) {
  3965  	m := testModule(t, "apply-provider-computed")
  3966  	p := testProvider("aws")
  3967  	p.PlanResourceChangeFn = testDiffFn
  3968  
  3969  	pTest := testProvider("test")
  3970  	pTest.ApplyResourceChangeFn = testApplyFn
  3971  	pTest.PlanResourceChangeFn = testDiffFn
  3972  
  3973  	ctx := testContext2(t, &ContextOpts{
  3974  		Providers: map[addrs.Provider]providers.Factory{
  3975  			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
  3976  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
  3977  		},
  3978  	})
  3979  
  3980  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  3981  		val := req.Config.GetAttr("value")
  3982  		if val.IsNull() {
  3983  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  3984  			return
  3985  		}
  3986  		return
  3987  	}
  3988  
  3989  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3990  	assertNoErrors(t, diags)
  3991  
  3992  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3993  		t.Fatalf("apply errors: %s", diags.Err())
  3994  	}
  3995  }
  3996  
  3997  func TestContext2Apply_providerConfigureDisabled(t *testing.T) {
  3998  	m := testModule(t, "apply-provider-configure-disabled")
  3999  	p := testProvider("aws")
  4000  	p.PlanResourceChangeFn = testDiffFn
  4001  
  4002  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  4003  		val := req.Config.GetAttr("value")
  4004  		if val.IsNull() {
  4005  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  4006  		}
  4007  
  4008  		return
  4009  	}
  4010  
  4011  	ctx := testContext2(t, &ContextOpts{
  4012  		Providers: map[addrs.Provider]providers.Factory{
  4013  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4014  		},
  4015  	})
  4016  
  4017  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4018  	assertNoErrors(t, diags)
  4019  
  4020  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  4021  		t.Fatalf("apply errors: %s", diags.Err())
  4022  	}
  4023  
  4024  	if !p.ConfigureProviderCalled {
  4025  		t.Fatal("configure never called")
  4026  	}
  4027  }
  4028  
  4029  func TestContext2Apply_provisionerModule(t *testing.T) {
  4030  	m := testModule(t, "apply-provisioner-module")
  4031  
  4032  	p := testProvider("aws")
  4033  	p.PlanResourceChangeFn = testDiffFn
  4034  	p.ApplyResourceChangeFn = testApplyFn
  4035  
  4036  	pr := testProvisioner()
  4037  	pr.GetSchemaResponse = provisioners.GetSchemaResponse{
  4038  		Provisioner: &configschema.Block{
  4039  			Attributes: map[string]*configschema.Attribute{
  4040  				"foo": {Type: cty.String, Optional: true},
  4041  			},
  4042  		},
  4043  	}
  4044  
  4045  	ctx := testContext2(t, &ContextOpts{
  4046  		Providers: map[addrs.Provider]providers.Factory{
  4047  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4048  		},
  4049  		Provisioners: map[string]provisioners.Factory{
  4050  			"shell": testProvisionerFuncFixed(pr),
  4051  		},
  4052  	})
  4053  
  4054  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4055  	assertNoErrors(t, diags)
  4056  
  4057  	state, diags := ctx.Apply(plan, m)
  4058  	if diags.HasErrors() {
  4059  		t.Fatalf("diags: %s", diags.Err())
  4060  	}
  4061  
  4062  	actual := strings.TrimSpace(state.String())
  4063  	expected := strings.TrimSpace(testTerraformApplyProvisionerModuleStr)
  4064  	if actual != expected {
  4065  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4066  	}
  4067  
  4068  	// Verify apply was invoked
  4069  	if !pr.ProvisionResourceCalled {
  4070  		t.Fatalf("provisioner not invoked")
  4071  	}
  4072  }
  4073  
  4074  func TestContext2Apply_Provisioner_compute(t *testing.T) {
  4075  	m := testModule(t, "apply-provisioner-compute")
  4076  	p := testProvider("aws")
  4077  	pr := testProvisioner()
  4078  	p.PlanResourceChangeFn = testDiffFn
  4079  	p.ApplyResourceChangeFn = testApplyFn
  4080  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4081  
  4082  		val := req.Config.GetAttr("command").AsString()
  4083  		if val != "computed_value" {
  4084  			t.Fatalf("bad value for foo: %q", val)
  4085  		}
  4086  		req.UIOutput.Output(fmt.Sprintf("Executing: %q", val))
  4087  
  4088  		return
  4089  	}
  4090  	h := new(MockHook)
  4091  	ctx := testContext2(t, &ContextOpts{
  4092  		Hooks: []Hook{h},
  4093  		Providers: map[addrs.Provider]providers.Factory{
  4094  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4095  		},
  4096  		Provisioners: map[string]provisioners.Factory{
  4097  			"shell": testProvisionerFuncFixed(pr),
  4098  		},
  4099  	})
  4100  
  4101  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  4102  		Mode: plans.NormalMode,
  4103  		SetVariables: InputValues{
  4104  			"value": &InputValue{
  4105  				Value:      cty.NumberIntVal(1),
  4106  				SourceType: ValueFromCaller,
  4107  			},
  4108  		},
  4109  	})
  4110  	assertNoErrors(t, diags)
  4111  
  4112  	state, diags := ctx.Apply(plan, m)
  4113  	if diags.HasErrors() {
  4114  		t.Fatalf("diags: %s", diags.Err())
  4115  	}
  4116  
  4117  	actual := strings.TrimSpace(state.String())
  4118  	expected := strings.TrimSpace(testTerraformApplyProvisionerStr)
  4119  	if actual != expected {
  4120  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4121  	}
  4122  
  4123  	// Verify apply was invoked
  4124  	if !pr.ProvisionResourceCalled {
  4125  		t.Fatalf("provisioner not invoked")
  4126  	}
  4127  
  4128  	// Verify output was rendered
  4129  	if !h.ProvisionOutputCalled {
  4130  		t.Fatalf("ProvisionOutput hook not called")
  4131  	}
  4132  	if got, want := h.ProvisionOutputMessage, `Executing: "computed_value"`; got != want {
  4133  		t.Errorf("expected output to be %q, but was %q", want, got)
  4134  	}
  4135  }
  4136  
  4137  func TestContext2Apply_provisionerCreateFail(t *testing.T) {
  4138  	m := testModule(t, "apply-provisioner-fail-create")
  4139  	p := testProvider("aws")
  4140  	pr := testProvisioner()
  4141  	p.PlanResourceChangeFn = testDiffFn
  4142  
  4143  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  4144  		resp := testApplyFn(req)
  4145  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4146  
  4147  		return resp
  4148  	}
  4149  
  4150  	ctx := testContext2(t, &ContextOpts{
  4151  		Providers: map[addrs.Provider]providers.Factory{
  4152  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4153  		},
  4154  		Provisioners: map[string]provisioners.Factory{
  4155  			"shell": testProvisionerFuncFixed(pr),
  4156  		},
  4157  	})
  4158  
  4159  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4160  	assertNoErrors(t, diags)
  4161  
  4162  	state, diags := ctx.Apply(plan, m)
  4163  	if diags == nil {
  4164  		t.Fatal("should error")
  4165  	}
  4166  
  4167  	got := strings.TrimSpace(state.String())
  4168  	want := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr)
  4169  	if got != want {
  4170  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want)
  4171  	}
  4172  }
  4173  
  4174  func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) {
  4175  	m := testModule(t, "apply-provisioner-fail-create")
  4176  	p := testProvider("aws")
  4177  	pr := testProvisioner()
  4178  	p.PlanResourceChangeFn = testDiffFn
  4179  
  4180  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4181  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4182  		return
  4183  	}
  4184  
  4185  	ctx := testContext2(t, &ContextOpts{
  4186  		Providers: map[addrs.Provider]providers.Factory{
  4187  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4188  		},
  4189  		Provisioners: map[string]provisioners.Factory{
  4190  			"shell": testProvisionerFuncFixed(pr),
  4191  		},
  4192  	})
  4193  
  4194  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4195  	assertNoErrors(t, diags)
  4196  
  4197  	state, diags := ctx.Apply(plan, m)
  4198  	if diags == nil {
  4199  		t.Fatal("should error")
  4200  	}
  4201  
  4202  	actual := strings.TrimSpace(state.String())
  4203  	expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr)
  4204  	if actual != expected {
  4205  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4206  	}
  4207  }
  4208  
  4209  func TestContext2Apply_provisionerFail(t *testing.T) {
  4210  	m := testModule(t, "apply-provisioner-fail")
  4211  	p := testProvider("aws")
  4212  	p.PlanResourceChangeFn = testDiffFn
  4213  	p.ApplyResourceChangeFn = testApplyFn
  4214  	pr := testProvisioner()
  4215  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4216  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION"))
  4217  		return
  4218  	}
  4219  
  4220  	ctx := testContext2(t, &ContextOpts{
  4221  		Providers: map[addrs.Provider]providers.Factory{
  4222  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4223  		},
  4224  		Provisioners: map[string]provisioners.Factory{
  4225  			"shell": testProvisionerFuncFixed(pr),
  4226  		},
  4227  	})
  4228  
  4229  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4230  	assertNoErrors(t, diags)
  4231  
  4232  	state, diags := ctx.Apply(plan, m)
  4233  	if diags == nil {
  4234  		t.Fatal("should error")
  4235  	}
  4236  
  4237  	actual := strings.TrimSpace(state.String())
  4238  	expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr)
  4239  	if actual != expected {
  4240  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4241  	}
  4242  }
  4243  
  4244  func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) {
  4245  	m := testModule(t, "apply-provisioner-fail-create-before")
  4246  	p := testProvider("aws")
  4247  	pr := testProvisioner()
  4248  	p.PlanResourceChangeFn = testDiffFn
  4249  	p.ApplyResourceChangeFn = testApplyFn
  4250  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4251  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION"))
  4252  		return
  4253  	}
  4254  
  4255  	state := states.NewState()
  4256  	root := state.EnsureModule(addrs.RootModuleInstance)
  4257  	root.SetResourceInstanceCurrent(
  4258  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4259  		&states.ResourceInstanceObjectSrc{
  4260  			Status:    states.ObjectReady,
  4261  			AttrsJSON: []byte(`{"id":"bar","require_new":"abc"}`),
  4262  		},
  4263  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4264  	)
  4265  
  4266  	ctx := testContext2(t, &ContextOpts{
  4267  		Providers: map[addrs.Provider]providers.Factory{
  4268  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4269  		},
  4270  		Provisioners: map[string]provisioners.Factory{
  4271  			"shell": testProvisionerFuncFixed(pr),
  4272  		},
  4273  	})
  4274  
  4275  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4276  	assertNoErrors(t, diags)
  4277  
  4278  	state, diags = ctx.Apply(plan, m)
  4279  	if !diags.HasErrors() {
  4280  		t.Fatal("should error")
  4281  	}
  4282  
  4283  	actual := strings.TrimSpace(state.String())
  4284  	expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr)
  4285  	if actual != expected {
  4286  		t.Fatalf("expected:\n%s\n:got\n%s", expected, actual)
  4287  	}
  4288  }
  4289  
  4290  func TestContext2Apply_error_createBeforeDestroy(t *testing.T) {
  4291  	m := testModule(t, "apply-error-create-before")
  4292  	p := testProvider("aws")
  4293  
  4294  	state := states.NewState()
  4295  	root := state.EnsureModule(addrs.RootModuleInstance)
  4296  	root.SetResourceInstanceCurrent(
  4297  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4298  		&states.ResourceInstanceObjectSrc{
  4299  			Status:    states.ObjectReady,
  4300  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc","type":"aws_instance"}`),
  4301  		},
  4302  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4303  	)
  4304  
  4305  	ctx := testContext2(t, &ContextOpts{
  4306  		Providers: map[addrs.Provider]providers.Factory{
  4307  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4308  		},
  4309  	})
  4310  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4311  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("placeholder error from ApplyFn"))
  4312  		return
  4313  	}
  4314  	p.PlanResourceChangeFn = testDiffFn
  4315  
  4316  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4317  	assertNoErrors(t, diags)
  4318  
  4319  	state, diags = ctx.Apply(plan, m)
  4320  	if !diags.HasErrors() {
  4321  		t.Fatal("should have error")
  4322  	}
  4323  	if got, want := diags.Err().Error(), "placeholder error from ApplyFn"; got != want {
  4324  		// We're looking for our artificial error from ApplyFn above, whose
  4325  		// message is literally "placeholder error from ApplyFn".
  4326  		t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
  4327  	}
  4328  
  4329  	actual := strings.TrimSpace(state.String())
  4330  	expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr)
  4331  	if actual != expected {
  4332  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4333  	}
  4334  }
  4335  
  4336  func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) {
  4337  	m := testModule(t, "apply-error-create-before")
  4338  	p := testProvider("aws")
  4339  
  4340  	state := states.NewState()
  4341  	root := state.EnsureModule(addrs.RootModuleInstance)
  4342  	root.SetResourceInstanceCurrent(
  4343  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4344  		&states.ResourceInstanceObjectSrc{
  4345  			Status:    states.ObjectReady,
  4346  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
  4347  		},
  4348  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4349  	)
  4350  
  4351  	ctx := testContext2(t, &ContextOpts{
  4352  		Providers: map[addrs.Provider]providers.Factory{
  4353  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4354  		},
  4355  	})
  4356  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4357  		// Fail the destroy!
  4358  		if req.PlannedState.IsNull() {
  4359  			resp.NewState = req.PriorState
  4360  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4361  			return
  4362  		}
  4363  
  4364  		return testApplyFn(req)
  4365  	}
  4366  	p.PlanResourceChangeFn = testDiffFn
  4367  
  4368  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4369  	assertNoErrors(t, diags)
  4370  
  4371  	state, diags = ctx.Apply(plan, m)
  4372  	if !diags.HasErrors() {
  4373  		t.Fatal("should have error")
  4374  	}
  4375  
  4376  	actual := strings.TrimSpace(state.String())
  4377  	expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr)
  4378  	if actual != expected {
  4379  		t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected)
  4380  	}
  4381  }
  4382  
  4383  func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) {
  4384  	m := testModule(t, "apply-multi-depose-create-before-destroy")
  4385  	p := testProvider("aws")
  4386  	ps := map[addrs.Provider]providers.Factory{addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p)}
  4387  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4388  		ResourceTypes: map[string]*configschema.Block{
  4389  			"aws_instance": {
  4390  				Attributes: map[string]*configschema.Attribute{
  4391  					"require_new": {Type: cty.String, Optional: true},
  4392  					"id":          {Type: cty.String, Computed: true},
  4393  				},
  4394  			},
  4395  		},
  4396  	})
  4397  
  4398  	state := states.NewState()
  4399  	root := state.EnsureModule(addrs.RootModuleInstance)
  4400  	root.SetResourceInstanceCurrent(
  4401  		mustResourceInstanceAddr("aws_instance.web").Resource,
  4402  		&states.ResourceInstanceObjectSrc{
  4403  			Status:    states.ObjectReady,
  4404  			AttrsJSON: []byte(`{"id":"foo"}`),
  4405  		},
  4406  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4407  	)
  4408  
  4409  	p.PlanResourceChangeFn = testDiffFn
  4410  
  4411  	ctx := testContext2(t, &ContextOpts{
  4412  		Providers: ps,
  4413  	})
  4414  	createdInstanceId := "bar"
  4415  	// Create works
  4416  	createFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4417  		s := req.PlannedState.AsValueMap()
  4418  		s["id"] = cty.StringVal(createdInstanceId)
  4419  		resp.NewState = cty.ObjectVal(s)
  4420  		return
  4421  	}
  4422  
  4423  	// Destroy starts broken
  4424  	destroyFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4425  		resp.NewState = req.PriorState
  4426  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy failed"))
  4427  		return
  4428  	}
  4429  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4430  		if req.PlannedState.IsNull() {
  4431  			return destroyFunc(req)
  4432  		} else {
  4433  			return createFunc(req)
  4434  		}
  4435  	}
  4436  
  4437  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4438  		Mode: plans.NormalMode,
  4439  		SetVariables: InputValues{
  4440  			"require_new": &InputValue{
  4441  				Value: cty.StringVal("yes"),
  4442  			},
  4443  		},
  4444  	})
  4445  	assertNoErrors(t, diags)
  4446  
  4447  	// Destroy is broken, so even though CBD successfully replaces the instance,
  4448  	// we'll have to save the Deposed instance to destroy later
  4449  	state, diags = ctx.Apply(plan, m)
  4450  	if !diags.HasErrors() {
  4451  		t.Fatal("should have error")
  4452  	}
  4453  
  4454  	checkStateString(t, state, `
  4455  aws_instance.web: (1 deposed)
  4456    ID = bar
  4457    provider = provider["registry.terraform.io/hashicorp/aws"]
  4458    require_new = yes
  4459    Deposed ID 1 = foo
  4460  	`)
  4461  
  4462  	createdInstanceId = "baz"
  4463  	ctx = testContext2(t, &ContextOpts{
  4464  		Providers: ps,
  4465  	})
  4466  
  4467  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4468  		Mode: plans.NormalMode,
  4469  		SetVariables: InputValues{
  4470  			"require_new": &InputValue{
  4471  				Value: cty.StringVal("baz"),
  4472  			},
  4473  		},
  4474  	})
  4475  	assertNoErrors(t, diags)
  4476  
  4477  	// We're replacing the primary instance once again. Destroy is _still_
  4478  	// broken, so the Deposed list gets longer
  4479  	state, diags = ctx.Apply(plan, m)
  4480  	if !diags.HasErrors() {
  4481  		t.Fatal("should have error")
  4482  	}
  4483  
  4484  	// For this one we can't rely on checkStateString because its result is
  4485  	// not deterministic when multiple deposed objects are present. Instead,
  4486  	// we will probe the state object directly.
  4487  	{
  4488  		is := state.RootModule().Resources["aws_instance.web"].Instances[addrs.NoKey]
  4489  		if is.Current == nil {
  4490  			t.Fatalf("no current object for aws_instance web; should have one")
  4491  		}
  4492  		if !bytes.Contains(is.Current.AttrsJSON, []byte("baz")) {
  4493  			t.Fatalf("incorrect current object attrs %s; want id=baz", is.Current.AttrsJSON)
  4494  		}
  4495  		if got, want := len(is.Deposed), 2; got != want {
  4496  			t.Fatalf("wrong number of deposed instances %d; want %d", got, want)
  4497  		}
  4498  		var foos, bars int
  4499  		for _, obj := range is.Deposed {
  4500  			if bytes.Contains(obj.AttrsJSON, []byte("foo")) {
  4501  				foos++
  4502  			}
  4503  			if bytes.Contains(obj.AttrsJSON, []byte("bar")) {
  4504  				bars++
  4505  			}
  4506  		}
  4507  		if got, want := foos, 1; got != want {
  4508  			t.Fatalf("wrong number of deposed instances with id=foo %d; want %d", got, want)
  4509  		}
  4510  		if got, want := bars, 1; got != want {
  4511  			t.Fatalf("wrong number of deposed instances with id=bar %d; want %d", got, want)
  4512  		}
  4513  	}
  4514  
  4515  	// Destroy partially fixed!
  4516  	destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4517  		s := req.PriorState.AsValueMap()
  4518  		id := s["id"].AsString()
  4519  		if id == "foo" || id == "baz" {
  4520  			resp.NewState = cty.NullVal(req.PriorState.Type())
  4521  		} else {
  4522  			resp.NewState = req.PriorState
  4523  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy partially failed"))
  4524  		}
  4525  		return
  4526  	}
  4527  
  4528  	createdInstanceId = "qux"
  4529  	ctx = testContext2(t, &ContextOpts{
  4530  		Providers: ps,
  4531  	})
  4532  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4533  		Mode: plans.NormalMode,
  4534  		SetVariables: InputValues{
  4535  			"require_new": &InputValue{
  4536  				Value: cty.StringVal("qux"),
  4537  			},
  4538  		},
  4539  	})
  4540  	assertNoErrors(t, diags)
  4541  
  4542  	state, diags = ctx.Apply(plan, m)
  4543  	// Expect error because 1/2 of Deposed destroys failed
  4544  	if !diags.HasErrors() {
  4545  		t.Fatal("should have error")
  4546  	}
  4547  
  4548  	// foo and baz are now gone, bar sticks around
  4549  	checkStateString(t, state, `
  4550  aws_instance.web: (1 deposed)
  4551    ID = qux
  4552    provider = provider["registry.terraform.io/hashicorp/aws"]
  4553    require_new = qux
  4554    Deposed ID 1 = bar
  4555  	`)
  4556  
  4557  	// Destroy working fully!
  4558  	destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4559  		resp.NewState = cty.NullVal(req.PriorState.Type())
  4560  		return
  4561  	}
  4562  
  4563  	createdInstanceId = "quux"
  4564  	ctx = testContext2(t, &ContextOpts{
  4565  		Providers: ps,
  4566  	})
  4567  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4568  		Mode: plans.NormalMode,
  4569  		SetVariables: InputValues{
  4570  			"require_new": &InputValue{
  4571  				Value: cty.StringVal("quux"),
  4572  			},
  4573  		},
  4574  	})
  4575  	assertNoErrors(t, diags)
  4576  	state, diags = ctx.Apply(plan, m)
  4577  	if diags.HasErrors() {
  4578  		t.Fatal("should not have error:", diags.Err())
  4579  	}
  4580  
  4581  	// And finally the state is clean
  4582  	checkStateString(t, state, `
  4583  aws_instance.web:
  4584    ID = quux
  4585    provider = provider["registry.terraform.io/hashicorp/aws"]
  4586    require_new = quux
  4587  	`)
  4588  }
  4589  
  4590  // Verify that a normal provisioner with on_failure "continue" set won't
  4591  // taint the resource and continues executing.
  4592  func TestContext2Apply_provisionerFailContinue(t *testing.T) {
  4593  	m := testModule(t, "apply-provisioner-fail-continue")
  4594  	p := testProvider("aws")
  4595  	pr := testProvisioner()
  4596  	p.PlanResourceChangeFn = testDiffFn
  4597  	p.ApplyResourceChangeFn = testApplyFn
  4598  
  4599  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4600  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4601  		return
  4602  	}
  4603  
  4604  	ctx := testContext2(t, &ContextOpts{
  4605  		Providers: map[addrs.Provider]providers.Factory{
  4606  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4607  		},
  4608  		Provisioners: map[string]provisioners.Factory{
  4609  			"shell": testProvisionerFuncFixed(pr),
  4610  		},
  4611  	})
  4612  
  4613  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4614  	assertNoErrors(t, diags)
  4615  
  4616  	state, diags := ctx.Apply(plan, m)
  4617  	if diags.HasErrors() {
  4618  		t.Fatalf("diags: %s", diags.Err())
  4619  	}
  4620  
  4621  	checkStateString(t, state, `
  4622  aws_instance.foo:
  4623    ID = foo
  4624    provider = provider["registry.terraform.io/hashicorp/aws"]
  4625    foo = bar
  4626    type = aws_instance
  4627    `)
  4628  
  4629  	// Verify apply was invoked
  4630  	if !pr.ProvisionResourceCalled {
  4631  		t.Fatalf("provisioner not invoked")
  4632  	}
  4633  }
  4634  
  4635  // Verify that a normal provisioner with on_failure "continue" records
  4636  // the error with the hook.
  4637  func TestContext2Apply_provisionerFailContinueHook(t *testing.T) {
  4638  	h := new(MockHook)
  4639  	m := testModule(t, "apply-provisioner-fail-continue")
  4640  	p := testProvider("aws")
  4641  	pr := testProvisioner()
  4642  	p.PlanResourceChangeFn = testDiffFn
  4643  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4644  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4645  		return
  4646  	}
  4647  
  4648  	ctx := testContext2(t, &ContextOpts{
  4649  		Hooks: []Hook{h},
  4650  		Providers: map[addrs.Provider]providers.Factory{
  4651  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4652  		},
  4653  		Provisioners: map[string]provisioners.Factory{
  4654  			"shell": testProvisionerFuncFixed(pr),
  4655  		},
  4656  	})
  4657  
  4658  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4659  	assertNoErrors(t, diags)
  4660  
  4661  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  4662  		t.Fatalf("apply errors: %s", diags.Err())
  4663  	}
  4664  
  4665  	if !h.PostProvisionInstanceStepCalled {
  4666  		t.Fatal("PostProvisionInstanceStep not called")
  4667  	}
  4668  	if h.PostProvisionInstanceStepErrorArg == nil {
  4669  		t.Fatal("should have error")
  4670  	}
  4671  }
  4672  
  4673  func TestContext2Apply_provisionerDestroy(t *testing.T) {
  4674  	m := testModule(t, "apply-provisioner-destroy")
  4675  	p := testProvider("aws")
  4676  	pr := testProvisioner()
  4677  	p.PlanResourceChangeFn = testDiffFn
  4678  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4679  		val := req.Config.GetAttr("command").AsString()
  4680  		if val != "destroy a bar" {
  4681  			t.Fatalf("bad value for foo: %q", val)
  4682  		}
  4683  
  4684  		return
  4685  	}
  4686  
  4687  	state := states.NewState()
  4688  	root := state.RootModule()
  4689  	root.SetResourceInstanceCurrent(
  4690  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4691  		&states.ResourceInstanceObjectSrc{
  4692  			Status:    states.ObjectReady,
  4693  			AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
  4694  		},
  4695  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4696  	)
  4697  
  4698  	ctx := testContext2(t, &ContextOpts{
  4699  		Providers: map[addrs.Provider]providers.Factory{
  4700  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4701  		},
  4702  		Provisioners: map[string]provisioners.Factory{
  4703  			"shell": testProvisionerFuncFixed(pr),
  4704  		},
  4705  	})
  4706  
  4707  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4708  		Mode: plans.DestroyMode,
  4709  	})
  4710  	assertNoErrors(t, diags)
  4711  
  4712  	state, diags = ctx.Apply(plan, m)
  4713  	if diags.HasErrors() {
  4714  		t.Fatalf("diags: %s", diags.Err())
  4715  	}
  4716  
  4717  	checkStateString(t, state, `<no state>`)
  4718  
  4719  	// Verify apply was invoked
  4720  	if !pr.ProvisionResourceCalled {
  4721  		t.Fatalf("provisioner not invoked")
  4722  	}
  4723  }
  4724  
  4725  // Verify that on destroy provisioner failure, nothing happens to the instance
  4726  func TestContext2Apply_provisionerDestroyFail(t *testing.T) {
  4727  	m := testModule(t, "apply-provisioner-destroy")
  4728  	p := testProvider("aws")
  4729  	pr := testProvisioner()
  4730  	p.PlanResourceChangeFn = testDiffFn
  4731  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4732  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4733  		return
  4734  	}
  4735  
  4736  	state := states.NewState()
  4737  	root := state.RootModule()
  4738  	root.SetResourceInstanceCurrent(
  4739  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4740  		&states.ResourceInstanceObjectSrc{
  4741  			Status:    states.ObjectReady,
  4742  			AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
  4743  		},
  4744  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4745  	)
  4746  
  4747  	ctx := testContext2(t, &ContextOpts{
  4748  		Providers: map[addrs.Provider]providers.Factory{
  4749  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4750  		},
  4751  		Provisioners: map[string]provisioners.Factory{
  4752  			"shell": testProvisionerFuncFixed(pr),
  4753  		},
  4754  	})
  4755  
  4756  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4757  		Mode: plans.DestroyMode,
  4758  	})
  4759  	assertNoErrors(t, diags)
  4760  
  4761  	state, diags = ctx.Apply(plan, m)
  4762  	if diags == nil {
  4763  		t.Fatal("should error")
  4764  	}
  4765  
  4766  	checkStateString(t, state, `
  4767  aws_instance.foo["a"]:
  4768    ID = bar
  4769    provider = provider["registry.terraform.io/hashicorp/aws"]
  4770    foo = bar
  4771  	`)
  4772  
  4773  	// Verify apply was invoked
  4774  	if !pr.ProvisionResourceCalled {
  4775  		t.Fatalf("provisioner not invoked")
  4776  	}
  4777  }
  4778  
  4779  // Verify that on destroy provisioner failure with "continue" that
  4780  // we continue to the next provisioner.
  4781  func TestContext2Apply_provisionerDestroyFailContinue(t *testing.T) {
  4782  	m := testModule(t, "apply-provisioner-destroy-continue")
  4783  	p := testProvider("aws")
  4784  	pr := testProvisioner()
  4785  	p.PlanResourceChangeFn = testDiffFn
  4786  
  4787  	var l sync.Mutex
  4788  	var calls []string
  4789  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4790  		val := req.Config.GetAttr("command")
  4791  		if val.IsNull() {
  4792  			t.Fatalf("bad value for foo: %#v", val)
  4793  		}
  4794  
  4795  		l.Lock()
  4796  		defer l.Unlock()
  4797  		calls = append(calls, val.AsString())
  4798  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4799  		return
  4800  	}
  4801  
  4802  	state := states.NewState()
  4803  	root := state.RootModule()
  4804  	root.SetResourceInstanceCurrent(
  4805  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4806  		&states.ResourceInstanceObjectSrc{
  4807  			Status:    states.ObjectReady,
  4808  			AttrsJSON: []byte(`{"id":"bar"}`),
  4809  		},
  4810  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4811  	)
  4812  
  4813  	ctx := testContext2(t, &ContextOpts{
  4814  		Providers: map[addrs.Provider]providers.Factory{
  4815  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4816  		},
  4817  		Provisioners: map[string]provisioners.Factory{
  4818  			"shell": testProvisionerFuncFixed(pr),
  4819  		},
  4820  	})
  4821  
  4822  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4823  		Mode: plans.DestroyMode,
  4824  	})
  4825  	assertNoErrors(t, diags)
  4826  
  4827  	state, diags = ctx.Apply(plan, m)
  4828  	if diags.HasErrors() {
  4829  		t.Fatalf("diags: %s", diags.Err())
  4830  	}
  4831  
  4832  	checkStateString(t, state, `<no state>`)
  4833  
  4834  	// Verify apply was invoked
  4835  	if !pr.ProvisionResourceCalled {
  4836  		t.Fatalf("provisioner not invoked")
  4837  	}
  4838  
  4839  	expected := []string{"one", "two"}
  4840  	if !reflect.DeepEqual(calls, expected) {
  4841  		t.Fatalf("wrong commands\ngot:  %#v\nwant: %#v", calls, expected)
  4842  	}
  4843  }
  4844  
  4845  // Verify that on destroy provisioner failure with "continue" that
  4846  // we continue to the next provisioner. But if the next provisioner defines
  4847  // to fail, then we fail after running it.
  4848  func TestContext2Apply_provisionerDestroyFailContinueFail(t *testing.T) {
  4849  	m := testModule(t, "apply-provisioner-destroy-fail")
  4850  	p := testProvider("aws")
  4851  	pr := testProvisioner()
  4852  	p.PlanResourceChangeFn = testDiffFn
  4853  
  4854  	var l sync.Mutex
  4855  	var calls []string
  4856  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4857  		val := req.Config.GetAttr("command")
  4858  		if val.IsNull() {
  4859  			t.Fatalf("bad value for foo: %#v", val)
  4860  		}
  4861  
  4862  		l.Lock()
  4863  		defer l.Unlock()
  4864  		calls = append(calls, val.AsString())
  4865  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4866  		return
  4867  	}
  4868  
  4869  	state := states.NewState()
  4870  	root := state.EnsureModule(addrs.RootModuleInstance)
  4871  	root.SetResourceInstanceCurrent(
  4872  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  4873  		&states.ResourceInstanceObjectSrc{
  4874  			Status:    states.ObjectReady,
  4875  			AttrsJSON: []byte(`{"id":"bar"}`),
  4876  		},
  4877  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4878  	)
  4879  
  4880  	ctx := testContext2(t, &ContextOpts{
  4881  		Providers: map[addrs.Provider]providers.Factory{
  4882  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4883  		},
  4884  		Provisioners: map[string]provisioners.Factory{
  4885  			"shell": testProvisionerFuncFixed(pr),
  4886  		},
  4887  	})
  4888  
  4889  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4890  		Mode: plans.DestroyMode,
  4891  	})
  4892  	assertNoErrors(t, diags)
  4893  
  4894  	state, diags = ctx.Apply(plan, m)
  4895  	if diags == nil {
  4896  		t.Fatal("apply succeeded; wanted error from second provisioner")
  4897  	}
  4898  
  4899  	checkStateString(t, state, `
  4900  aws_instance.foo:
  4901    ID = bar
  4902    provider = provider["registry.terraform.io/hashicorp/aws"]
  4903    `)
  4904  
  4905  	// Verify apply was invoked
  4906  	if !pr.ProvisionResourceCalled {
  4907  		t.Fatalf("provisioner not invoked")
  4908  	}
  4909  
  4910  	expected := []string{"one", "two"}
  4911  	if !reflect.DeepEqual(calls, expected) {
  4912  		t.Fatalf("bad: %#v", calls)
  4913  	}
  4914  }
  4915  
  4916  // Verify destroy provisioners are not run for tainted instances.
  4917  func TestContext2Apply_provisionerDestroyTainted(t *testing.T) {
  4918  	m := testModule(t, "apply-provisioner-destroy")
  4919  	p := testProvider("aws")
  4920  	pr := testProvisioner()
  4921  	p.PlanResourceChangeFn = testDiffFn
  4922  	p.ApplyResourceChangeFn = testApplyFn
  4923  
  4924  	destroyCalled := false
  4925  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4926  		expected := "create a b"
  4927  		val := req.Config.GetAttr("command")
  4928  		if val.AsString() != expected {
  4929  			t.Fatalf("bad value for command: %#v", val)
  4930  		}
  4931  
  4932  		return
  4933  	}
  4934  
  4935  	state := states.NewState()
  4936  	root := state.RootModule()
  4937  	root.SetResourceInstanceCurrent(
  4938  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4939  		&states.ResourceInstanceObjectSrc{
  4940  			Status:    states.ObjectTainted,
  4941  			AttrsJSON: []byte(`{"id":"bar"}`),
  4942  		},
  4943  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4944  	)
  4945  
  4946  	ctx := testContext2(t, &ContextOpts{
  4947  		Providers: map[addrs.Provider]providers.Factory{
  4948  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4949  		},
  4950  		Provisioners: map[string]provisioners.Factory{
  4951  			"shell": testProvisionerFuncFixed(pr),
  4952  		},
  4953  	})
  4954  
  4955  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4956  		Mode: plans.NormalMode,
  4957  		SetVariables: InputValues{
  4958  			"input": &InputValue{
  4959  				Value: cty.MapVal(map[string]cty.Value{
  4960  					"a": cty.StringVal("b"),
  4961  				}),
  4962  				SourceType: ValueFromInput,
  4963  			},
  4964  		},
  4965  	})
  4966  	assertNoErrors(t, diags)
  4967  
  4968  	state, diags = ctx.Apply(plan, m)
  4969  	if diags.HasErrors() {
  4970  		t.Fatalf("diags: %s", diags.Err())
  4971  	}
  4972  
  4973  	checkStateString(t, state, `
  4974  aws_instance.foo["a"]:
  4975    ID = foo
  4976    provider = provider["registry.terraform.io/hashicorp/aws"]
  4977    foo = bar
  4978    type = aws_instance
  4979  	`)
  4980  
  4981  	// Verify apply was invoked
  4982  	if !pr.ProvisionResourceCalled {
  4983  		t.Fatalf("provisioner not invoked")
  4984  	}
  4985  
  4986  	if destroyCalled {
  4987  		t.Fatal("destroy should not be called")
  4988  	}
  4989  }
  4990  
  4991  func TestContext2Apply_provisionerResourceRef(t *testing.T) {
  4992  	m := testModule(t, "apply-provisioner-resource-ref")
  4993  	p := testProvider("aws")
  4994  	p.PlanResourceChangeFn = testDiffFn
  4995  	p.ApplyResourceChangeFn = testApplyFn
  4996  
  4997  	pr := testProvisioner()
  4998  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4999  		val := req.Config.GetAttr("command")
  5000  		if val.AsString() != "2" {
  5001  			t.Fatalf("bad value for command: %#v", val)
  5002  		}
  5003  
  5004  		return
  5005  	}
  5006  
  5007  	ctx := testContext2(t, &ContextOpts{
  5008  		Providers: map[addrs.Provider]providers.Factory{
  5009  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5010  		},
  5011  		Provisioners: map[string]provisioners.Factory{
  5012  			"shell": testProvisionerFuncFixed(pr),
  5013  		},
  5014  	})
  5015  
  5016  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5017  	assertNoErrors(t, diags)
  5018  
  5019  	state, diags := ctx.Apply(plan, m)
  5020  	if diags.HasErrors() {
  5021  		t.Fatalf("diags: %s", diags.Err())
  5022  	}
  5023  
  5024  	actual := strings.TrimSpace(state.String())
  5025  	expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr)
  5026  	if actual != expected {
  5027  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5028  	}
  5029  
  5030  	// Verify apply was invoked
  5031  	if !pr.ProvisionResourceCalled {
  5032  		t.Fatalf("provisioner not invoked")
  5033  	}
  5034  }
  5035  
  5036  func TestContext2Apply_provisionerSelfRef(t *testing.T) {
  5037  	m := testModule(t, "apply-provisioner-self-ref")
  5038  	p := testProvider("aws")
  5039  	pr := testProvisioner()
  5040  	p.PlanResourceChangeFn = testDiffFn
  5041  	p.ApplyResourceChangeFn = testApplyFn
  5042  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5043  		val := req.Config.GetAttr("command")
  5044  		if val.AsString() != "bar" {
  5045  			t.Fatalf("bad value for command: %#v", val)
  5046  		}
  5047  
  5048  		return
  5049  	}
  5050  
  5051  	ctx := testContext2(t, &ContextOpts{
  5052  		Providers: map[addrs.Provider]providers.Factory{
  5053  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5054  		},
  5055  		Provisioners: map[string]provisioners.Factory{
  5056  			"shell": testProvisionerFuncFixed(pr),
  5057  		},
  5058  	})
  5059  
  5060  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5061  	assertNoErrors(t, diags)
  5062  
  5063  	state, diags := ctx.Apply(plan, m)
  5064  	if diags.HasErrors() {
  5065  		t.Fatalf("diags: %s", diags.Err())
  5066  	}
  5067  
  5068  	actual := strings.TrimSpace(state.String())
  5069  	expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr)
  5070  	if actual != expected {
  5071  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5072  	}
  5073  
  5074  	// Verify apply was invoked
  5075  	if !pr.ProvisionResourceCalled {
  5076  		t.Fatalf("provisioner not invoked")
  5077  	}
  5078  }
  5079  
  5080  func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) {
  5081  	var lock sync.Mutex
  5082  	commands := make([]string, 0, 5)
  5083  
  5084  	m := testModule(t, "apply-provisioner-multi-self-ref")
  5085  	p := testProvider("aws")
  5086  	pr := testProvisioner()
  5087  	p.PlanResourceChangeFn = testDiffFn
  5088  	p.ApplyResourceChangeFn = testApplyFn
  5089  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5090  		lock.Lock()
  5091  		defer lock.Unlock()
  5092  
  5093  		val := req.Config.GetAttr("command")
  5094  		if val.IsNull() {
  5095  			t.Fatalf("bad value for command: %#v", val)
  5096  		}
  5097  
  5098  		commands = append(commands, val.AsString())
  5099  		return
  5100  	}
  5101  
  5102  	ctx := testContext2(t, &ContextOpts{
  5103  		Providers: map[addrs.Provider]providers.Factory{
  5104  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5105  		},
  5106  		Provisioners: map[string]provisioners.Factory{
  5107  			"shell": testProvisionerFuncFixed(pr),
  5108  		},
  5109  	})
  5110  
  5111  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5112  	assertNoErrors(t, diags)
  5113  
  5114  	state, diags := ctx.Apply(plan, m)
  5115  	if diags.HasErrors() {
  5116  		t.Fatalf("diags: %s", diags.Err())
  5117  	}
  5118  
  5119  	actual := strings.TrimSpace(state.String())
  5120  	expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr)
  5121  	if actual != expected {
  5122  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5123  	}
  5124  
  5125  	// Verify apply was invoked
  5126  	if !pr.ProvisionResourceCalled {
  5127  		t.Fatalf("provisioner not invoked")
  5128  	}
  5129  
  5130  	// Verify our result
  5131  	sort.Strings(commands)
  5132  	expectedCommands := []string{"number 0", "number 1", "number 2"}
  5133  	if !reflect.DeepEqual(commands, expectedCommands) {
  5134  		t.Fatalf("bad: %#v", commands)
  5135  	}
  5136  }
  5137  
  5138  func TestContext2Apply_provisionerMultiSelfRefSingle(t *testing.T) {
  5139  	var lock sync.Mutex
  5140  	order := make([]string, 0, 5)
  5141  
  5142  	m := testModule(t, "apply-provisioner-multi-self-ref-single")
  5143  	p := testProvider("aws")
  5144  	pr := testProvisioner()
  5145  	p.PlanResourceChangeFn = testDiffFn
  5146  	p.ApplyResourceChangeFn = testApplyFn
  5147  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5148  		lock.Lock()
  5149  		defer lock.Unlock()
  5150  
  5151  		val := req.Config.GetAttr("order")
  5152  		if val.IsNull() {
  5153  			t.Fatalf("no val for order")
  5154  		}
  5155  
  5156  		order = append(order, val.AsString())
  5157  		return
  5158  	}
  5159  
  5160  	ctx := testContext2(t, &ContextOpts{
  5161  		Providers: map[addrs.Provider]providers.Factory{
  5162  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5163  		},
  5164  		Provisioners: map[string]provisioners.Factory{
  5165  			"shell": testProvisionerFuncFixed(pr),
  5166  		},
  5167  	})
  5168  
  5169  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5170  	assertNoErrors(t, diags)
  5171  
  5172  	state, diags := ctx.Apply(plan, m)
  5173  	if diags.HasErrors() {
  5174  		t.Fatalf("diags: %s", diags.Err())
  5175  	}
  5176  
  5177  	actual := strings.TrimSpace(state.String())
  5178  	expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefSingleStr)
  5179  	if actual != expected {
  5180  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5181  	}
  5182  
  5183  	// Verify apply was invoked
  5184  	if !pr.ProvisionResourceCalled {
  5185  		t.Fatalf("provisioner not invoked")
  5186  	}
  5187  
  5188  	// Verify our result
  5189  	sort.Strings(order)
  5190  	expectedOrder := []string{"0", "1", "2"}
  5191  	if !reflect.DeepEqual(order, expectedOrder) {
  5192  		t.Fatalf("bad: %#v", order)
  5193  	}
  5194  }
  5195  
  5196  func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) {
  5197  	m := testModule(t, "apply-provisioner-explicit-self-ref")
  5198  	p := testProvider("aws")
  5199  	pr := testProvisioner()
  5200  	p.PlanResourceChangeFn = testDiffFn
  5201  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5202  		val := req.Config.GetAttr("command")
  5203  		if val.IsNull() || val.AsString() != "bar" {
  5204  			t.Fatalf("bad value for command: %#v", val)
  5205  		}
  5206  
  5207  		return
  5208  	}
  5209  
  5210  	var state *states.State
  5211  	{
  5212  		ctx := testContext2(t, &ContextOpts{
  5213  			Providers: map[addrs.Provider]providers.Factory{
  5214  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5215  			},
  5216  			Provisioners: map[string]provisioners.Factory{
  5217  				"shell": testProvisionerFuncFixed(pr),
  5218  			},
  5219  		})
  5220  
  5221  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5222  		if diags.HasErrors() {
  5223  			t.Fatalf("diags: %s", diags.Err())
  5224  		}
  5225  
  5226  		state, diags = ctx.Apply(plan, m)
  5227  		if diags.HasErrors() {
  5228  			t.Fatalf("diags: %s", diags.Err())
  5229  		}
  5230  
  5231  		// Verify apply was invoked
  5232  		if !pr.ProvisionResourceCalled {
  5233  			t.Fatalf("provisioner not invoked")
  5234  		}
  5235  	}
  5236  
  5237  	{
  5238  		ctx := testContext2(t, &ContextOpts{
  5239  			Providers: map[addrs.Provider]providers.Factory{
  5240  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5241  			},
  5242  			Provisioners: map[string]provisioners.Factory{
  5243  				"shell": testProvisionerFuncFixed(pr),
  5244  			},
  5245  		})
  5246  
  5247  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5248  			Mode: plans.DestroyMode,
  5249  		})
  5250  		if diags.HasErrors() {
  5251  			t.Fatalf("diags: %s", diags.Err())
  5252  		}
  5253  
  5254  		state, diags = ctx.Apply(plan, m)
  5255  		if diags.HasErrors() {
  5256  			t.Fatalf("diags: %s", diags.Err())
  5257  		}
  5258  
  5259  		checkStateString(t, state, `<no state>`)
  5260  	}
  5261  }
  5262  
  5263  func TestContext2Apply_provisionerForEachSelfRef(t *testing.T) {
  5264  	m := testModule(t, "apply-provisioner-for-each-self")
  5265  	p := testProvider("aws")
  5266  	pr := testProvisioner()
  5267  	p.PlanResourceChangeFn = testDiffFn
  5268  
  5269  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5270  		val := req.Config.GetAttr("command")
  5271  		if val.IsNull() {
  5272  			t.Fatalf("bad value for command: %#v", val)
  5273  		}
  5274  
  5275  		return resp
  5276  	}
  5277  
  5278  	ctx := testContext2(t, &ContextOpts{
  5279  		Providers: map[addrs.Provider]providers.Factory{
  5280  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5281  		},
  5282  		Provisioners: map[string]provisioners.Factory{
  5283  			"shell": testProvisionerFuncFixed(pr),
  5284  		},
  5285  	})
  5286  
  5287  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5288  	assertNoErrors(t, diags)
  5289  
  5290  	_, diags = ctx.Apply(plan, m)
  5291  	if diags.HasErrors() {
  5292  		t.Fatalf("diags: %s", diags.Err())
  5293  	}
  5294  }
  5295  
  5296  // Provisioner should NOT run on a diff, only create
  5297  func TestContext2Apply_Provisioner_Diff(t *testing.T) {
  5298  	m := testModule(t, "apply-provisioner-diff")
  5299  	p := testProvider("aws")
  5300  	pr := testProvisioner()
  5301  	p.PlanResourceChangeFn = testDiffFn
  5302  	p.ApplyResourceChangeFn = testApplyFn
  5303  	ctx := testContext2(t, &ContextOpts{
  5304  		Providers: map[addrs.Provider]providers.Factory{
  5305  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5306  		},
  5307  		Provisioners: map[string]provisioners.Factory{
  5308  			"shell": testProvisionerFuncFixed(pr),
  5309  		},
  5310  	})
  5311  
  5312  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5313  	assertNoErrors(t, diags)
  5314  
  5315  	state, diags := ctx.Apply(plan, m)
  5316  	if diags.HasErrors() {
  5317  		logDiagnostics(t, diags)
  5318  		t.Fatal("apply failed")
  5319  	}
  5320  
  5321  	actual := strings.TrimSpace(state.String())
  5322  	expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr)
  5323  	if actual != expected {
  5324  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5325  	}
  5326  
  5327  	// Verify apply was invoked
  5328  	if !pr.ProvisionResourceCalled {
  5329  		t.Fatalf("provisioner was not called on first apply")
  5330  	}
  5331  	pr.ProvisionResourceCalled = false
  5332  
  5333  	// Change the state to force a diff
  5334  	mod := state.RootModule()
  5335  	obj := mod.Resources["aws_instance.bar"].Instances[addrs.NoKey].Current
  5336  	var attrs map[string]interface{}
  5337  	err := json.Unmarshal(obj.AttrsJSON, &attrs)
  5338  	if err != nil {
  5339  		t.Fatal(err)
  5340  	}
  5341  	attrs["foo"] = "baz"
  5342  	obj.AttrsJSON, err = json.Marshal(attrs)
  5343  	if err != nil {
  5344  		t.Fatal(err)
  5345  	}
  5346  
  5347  	// Re-create context with state
  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, state, DefaultPlanOpts)
  5358  	assertNoErrors(t, diags)
  5359  
  5360  	state2, diags := ctx.Apply(plan, m)
  5361  	if diags.HasErrors() {
  5362  		logDiagnostics(t, diags)
  5363  		t.Fatal("apply failed")
  5364  	}
  5365  
  5366  	actual = strings.TrimSpace(state2.String())
  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 NOT invoked
  5372  	if pr.ProvisionResourceCalled {
  5373  		t.Fatalf("provisioner was called on second apply; should not have been")
  5374  	}
  5375  }
  5376  
  5377  func TestContext2Apply_outputDiffVars(t *testing.T) {
  5378  	m := testModule(t, "apply-good")
  5379  	p := testProvider("aws")
  5380  
  5381  	state := states.NewState()
  5382  	root := state.EnsureModule(addrs.RootModuleInstance)
  5383  	root.SetResourceInstanceCurrent(
  5384  		mustResourceInstanceAddr("aws_instance.baz").Resource,
  5385  		&states.ResourceInstanceObjectSrc{
  5386  			Status:    states.ObjectReady,
  5387  			AttrsJSON: []byte(`{"id":"bar"}`),
  5388  		},
  5389  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5390  	)
  5391  
  5392  	ctx := testContext2(t, &ContextOpts{
  5393  		Providers: map[addrs.Provider]providers.Factory{
  5394  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5395  		},
  5396  	})
  5397  
  5398  	p.PlanResourceChangeFn = testDiffFn
  5399  	//func(info *InstanceInfo, s *InstanceState, rc *ResourceConfig) (*InstanceDiff, error) {
  5400  	//    d := &InstanceDiff{
  5401  	//        Attributes: map[string]*ResourceAttrDiff{},
  5402  	//    }
  5403  	//    if new, ok := rc.Get("value"); ok {
  5404  	//        d.Attributes["value"] = &ResourceAttrDiff{
  5405  	//            New: new.(string),
  5406  	//        }
  5407  	//    }
  5408  	//    if new, ok := rc.Get("foo"); ok {
  5409  	//        d.Attributes["foo"] = &ResourceAttrDiff{
  5410  	//            New: new.(string),
  5411  	//        }
  5412  	//    } else if rc.IsComputed("foo") {
  5413  	//        d.Attributes["foo"] = &ResourceAttrDiff{
  5414  	//            NewComputed: true,
  5415  	//            Type:        DiffAttrOutput, // This doesn't actually really do anything anymore, but this test originally set it.
  5416  	//        }
  5417  	//    }
  5418  	//    if new, ok := rc.Get("num"); ok {
  5419  	//        d.Attributes["num"] = &ResourceAttrDiff{
  5420  	//            New: fmt.Sprintf("%#v", new),
  5421  	//        }
  5422  	//    }
  5423  	//    return d, nil
  5424  	//}
  5425  
  5426  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5427  	assertNoErrors(t, diags)
  5428  
  5429  	_, diags = ctx.Apply(plan, m)
  5430  	assertNoErrors(t, diags)
  5431  }
  5432  
  5433  func TestContext2Apply_destroyX(t *testing.T) {
  5434  	m := testModule(t, "apply-destroy")
  5435  	h := new(HookRecordApplyOrder)
  5436  	p := testProvider("aws")
  5437  	p.PlanResourceChangeFn = testDiffFn
  5438  	ctx := testContext2(t, &ContextOpts{
  5439  		Hooks: []Hook{h},
  5440  		Providers: map[addrs.Provider]providers.Factory{
  5441  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5442  		},
  5443  	})
  5444  
  5445  	// First plan and apply a create operation
  5446  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5447  	assertNoErrors(t, diags)
  5448  
  5449  	state, diags := ctx.Apply(plan, m)
  5450  	if diags.HasErrors() {
  5451  		t.Fatalf("diags: %s", diags.Err())
  5452  	}
  5453  
  5454  	// Next, plan and apply a destroy operation
  5455  	h.Active = true
  5456  	ctx = testContext2(t, &ContextOpts{
  5457  		Hooks: []Hook{h},
  5458  		Providers: map[addrs.Provider]providers.Factory{
  5459  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5460  		},
  5461  	})
  5462  
  5463  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5464  		Mode: plans.DestroyMode,
  5465  	})
  5466  	assertNoErrors(t, diags)
  5467  
  5468  	state, diags = ctx.Apply(plan, m)
  5469  	if diags.HasErrors() {
  5470  		t.Fatalf("diags: %s", diags.Err())
  5471  	}
  5472  
  5473  	// Test that things were destroyed
  5474  	actual := strings.TrimSpace(state.String())
  5475  	expected := strings.TrimSpace(testTerraformApplyDestroyStr)
  5476  	if actual != expected {
  5477  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5478  	}
  5479  
  5480  	// Test that things were destroyed _in the right order_
  5481  	expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
  5482  	actual2 := h.IDs
  5483  	if !reflect.DeepEqual(actual2, expected2) {
  5484  		t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
  5485  	}
  5486  }
  5487  
  5488  func TestContext2Apply_destroyOrder(t *testing.T) {
  5489  	m := testModule(t, "apply-destroy")
  5490  	h := new(HookRecordApplyOrder)
  5491  	p := testProvider("aws")
  5492  	p.PlanResourceChangeFn = testDiffFn
  5493  	ctx := testContext2(t, &ContextOpts{
  5494  		Hooks: []Hook{h},
  5495  		Providers: map[addrs.Provider]providers.Factory{
  5496  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5497  		},
  5498  	})
  5499  
  5500  	// First plan and apply a create operation
  5501  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5502  	assertNoErrors(t, diags)
  5503  
  5504  	state, diags := ctx.Apply(plan, m)
  5505  	if diags.HasErrors() {
  5506  		t.Fatalf("diags: %s", diags.Err())
  5507  	}
  5508  
  5509  	t.Logf("State 1: %s", state)
  5510  
  5511  	// Next, plan and apply a destroy
  5512  	h.Active = true
  5513  	ctx = testContext2(t, &ContextOpts{
  5514  		Hooks: []Hook{h},
  5515  		Providers: map[addrs.Provider]providers.Factory{
  5516  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5517  		},
  5518  	})
  5519  
  5520  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5521  		Mode: plans.DestroyMode,
  5522  	})
  5523  	assertNoErrors(t, diags)
  5524  
  5525  	state, diags = ctx.Apply(plan, m)
  5526  	if diags.HasErrors() {
  5527  		t.Fatalf("diags: %s", diags.Err())
  5528  	}
  5529  
  5530  	// Test that things were destroyed
  5531  	actual := strings.TrimSpace(state.String())
  5532  	expected := strings.TrimSpace(testTerraformApplyDestroyStr)
  5533  	if actual != expected {
  5534  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5535  	}
  5536  
  5537  	// Test that things were destroyed _in the right order_
  5538  	expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
  5539  	actual2 := h.IDs
  5540  	if !reflect.DeepEqual(actual2, expected2) {
  5541  		t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
  5542  	}
  5543  }
  5544  
  5545  // https://github.com/muratcelep/terraform/issues/2767
  5546  func TestContext2Apply_destroyModulePrefix(t *testing.T) {
  5547  	m := testModule(t, "apply-destroy-module-resource-prefix")
  5548  	h := new(MockHook)
  5549  	p := testProvider("aws")
  5550  	p.PlanResourceChangeFn = testDiffFn
  5551  	ctx := testContext2(t, &ContextOpts{
  5552  		Hooks: []Hook{h},
  5553  		Providers: map[addrs.Provider]providers.Factory{
  5554  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5555  		},
  5556  	})
  5557  
  5558  	// First plan and apply a create operation
  5559  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5560  	assertNoErrors(t, diags)
  5561  
  5562  	state, diags := ctx.Apply(plan, m)
  5563  	if diags.HasErrors() {
  5564  		t.Fatalf("diags: %s", diags.Err())
  5565  	}
  5566  
  5567  	// Verify that we got the apply info correct
  5568  	if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" {
  5569  		t.Fatalf("bad: %s", v)
  5570  	}
  5571  
  5572  	// Next, plan and apply a destroy operation and reset the hook
  5573  	h = new(MockHook)
  5574  	ctx = testContext2(t, &ContextOpts{
  5575  		Hooks: []Hook{h},
  5576  		Providers: map[addrs.Provider]providers.Factory{
  5577  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5578  		},
  5579  	})
  5580  
  5581  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5582  		Mode: plans.DestroyMode,
  5583  	})
  5584  	assertNoErrors(t, diags)
  5585  
  5586  	_, diags = ctx.Apply(plan, m)
  5587  	if diags.HasErrors() {
  5588  		t.Fatalf("diags: %s", diags.Err())
  5589  	}
  5590  
  5591  	// Test that things were destroyed
  5592  	if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" {
  5593  		t.Fatalf("bad: %s", v)
  5594  	}
  5595  }
  5596  
  5597  func TestContext2Apply_destroyNestedModule(t *testing.T) {
  5598  	m := testModule(t, "apply-destroy-nested-module")
  5599  	p := testProvider("aws")
  5600  	p.PlanResourceChangeFn = testDiffFn
  5601  
  5602  	state := states.NewState()
  5603  	root := state.EnsureModule(addrs.RootModuleInstance)
  5604  	root.SetResourceInstanceCurrent(
  5605  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  5606  		&states.ResourceInstanceObjectSrc{
  5607  			Status:    states.ObjectReady,
  5608  			AttrsJSON: []byte(`{"id":"bar"}`),
  5609  		},
  5610  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5611  	)
  5612  
  5613  	ctx := testContext2(t, &ContextOpts{
  5614  		Providers: map[addrs.Provider]providers.Factory{
  5615  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5616  		},
  5617  	})
  5618  
  5619  	// First plan and apply a create operation
  5620  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5621  	assertNoErrors(t, diags)
  5622  
  5623  	s, diags := ctx.Apply(plan, m)
  5624  	if diags.HasErrors() {
  5625  		t.Fatalf("diags: %s", diags.Err())
  5626  	}
  5627  
  5628  	// Test that things were destroyed
  5629  	actual := strings.TrimSpace(s.String())
  5630  	if actual != "<no state>" {
  5631  		t.Fatalf("expected no state, got: %s", actual)
  5632  	}
  5633  }
  5634  
  5635  func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) {
  5636  	m := testModule(t, "apply-destroy-deeply-nested-module")
  5637  	p := testProvider("aws")
  5638  	p.PlanResourceChangeFn = testDiffFn
  5639  
  5640  	state := states.NewState()
  5641  	root := state.EnsureModule(addrs.RootModuleInstance)
  5642  	root.SetResourceInstanceCurrent(
  5643  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  5644  		&states.ResourceInstanceObjectSrc{
  5645  			Status:    states.ObjectReady,
  5646  			AttrsJSON: []byte(`{"id":"bar"}`),
  5647  		},
  5648  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5649  	)
  5650  
  5651  	ctx := testContext2(t, &ContextOpts{
  5652  		Providers: map[addrs.Provider]providers.Factory{
  5653  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5654  		},
  5655  	})
  5656  
  5657  	// First plan and apply a create operation
  5658  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5659  	assertNoErrors(t, diags)
  5660  
  5661  	s, diags := ctx.Apply(plan, m)
  5662  	if diags.HasErrors() {
  5663  		t.Fatalf("diags: %s", diags.Err())
  5664  	}
  5665  
  5666  	// Test that things were destroyed
  5667  	if !s.Empty() {
  5668  		t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(s))
  5669  	}
  5670  }
  5671  
  5672  // https://github.com/muratcelep/terraform/issues/5440
  5673  func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) {
  5674  	m, snap := testModuleWithSnapshot(t, "apply-destroy-module-with-attrs")
  5675  	p := testProvider("aws")
  5676  	p.PlanResourceChangeFn = testDiffFn
  5677  
  5678  	var state *states.State
  5679  	{
  5680  		ctx := testContext2(t, &ContextOpts{
  5681  			Providers: map[addrs.Provider]providers.Factory{
  5682  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5683  			},
  5684  		})
  5685  
  5686  		// First plan and apply a create operation
  5687  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5688  		if diags.HasErrors() {
  5689  			t.Fatalf("plan diags: %s", diags.Err())
  5690  		} else {
  5691  			t.Logf("Step 1 plan: %s", legacyDiffComparisonString(plan.Changes))
  5692  		}
  5693  
  5694  		state, diags = ctx.Apply(plan, m)
  5695  		if diags.HasErrors() {
  5696  			t.Fatalf("apply errs: %s", diags.Err())
  5697  		}
  5698  
  5699  		t.Logf("Step 1 state: %s", state)
  5700  	}
  5701  
  5702  	h := new(HookRecordApplyOrder)
  5703  	h.Active = true
  5704  
  5705  	{
  5706  		ctx := testContext2(t, &ContextOpts{
  5707  			Hooks: []Hook{h},
  5708  			Providers: map[addrs.Provider]providers.Factory{
  5709  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5710  			},
  5711  		})
  5712  
  5713  		// First plan and apply a create operation
  5714  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5715  			Mode: plans.DestroyMode,
  5716  		})
  5717  		if diags.HasErrors() {
  5718  			t.Fatalf("destroy plan err: %s", diags.Err())
  5719  		}
  5720  
  5721  		t.Logf("Step 2 plan: %s", legacyDiffComparisonString(plan.Changes))
  5722  
  5723  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  5724  		if err != nil {
  5725  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5726  		}
  5727  
  5728  		ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  5729  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5730  		}
  5731  
  5732  		ctx, diags = NewContext(ctxOpts)
  5733  		if diags.HasErrors() {
  5734  			t.Fatalf("err: %s", diags.Err())
  5735  		}
  5736  
  5737  		state, diags = ctx.Apply(plan, m)
  5738  		if diags.HasErrors() {
  5739  			t.Fatalf("destroy apply err: %s", diags.Err())
  5740  		}
  5741  
  5742  		t.Logf("Step 2 state: %s", state)
  5743  	}
  5744  
  5745  	//Test that things were destroyed
  5746  	if state.HasManagedResourceInstanceObjects() {
  5747  		t.Fatal("expected empty state, got:", state)
  5748  	}
  5749  }
  5750  
  5751  func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) {
  5752  	m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count")
  5753  	p := testProvider("aws")
  5754  	p.PlanResourceChangeFn = testDiffFn
  5755  
  5756  	var state *states.State
  5757  	{
  5758  		ctx := testContext2(t, &ContextOpts{
  5759  			Providers: map[addrs.Provider]providers.Factory{
  5760  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5761  			},
  5762  		})
  5763  
  5764  		// First plan and apply a create operation
  5765  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5766  		assertNoErrors(t, diags)
  5767  
  5768  		state, diags = ctx.Apply(plan, m)
  5769  		if diags.HasErrors() {
  5770  			t.Fatalf("apply err: %s", diags.Err())
  5771  		}
  5772  	}
  5773  
  5774  	h := new(HookRecordApplyOrder)
  5775  	h.Active = true
  5776  
  5777  	{
  5778  		ctx := testContext2(t, &ContextOpts{
  5779  			Hooks: []Hook{h},
  5780  			Providers: map[addrs.Provider]providers.Factory{
  5781  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5782  			},
  5783  		})
  5784  
  5785  		// First plan and apply a create operation
  5786  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5787  			Mode: plans.DestroyMode,
  5788  		})
  5789  		if diags.HasErrors() {
  5790  			t.Fatalf("destroy plan err: %s", diags.Err())
  5791  		}
  5792  
  5793  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  5794  		if err != nil {
  5795  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5796  		}
  5797  
  5798  		ctxOpts.Providers =
  5799  			map[addrs.Provider]providers.Factory{
  5800  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5801  			}
  5802  
  5803  		ctx, diags = NewContext(ctxOpts)
  5804  		if diags.HasErrors() {
  5805  			t.Fatalf("err: %s", diags.Err())
  5806  		}
  5807  
  5808  		state, diags = ctx.Apply(plan, m)
  5809  		if diags.HasErrors() {
  5810  			t.Fatalf("destroy apply err: %s", diags.Err())
  5811  		}
  5812  	}
  5813  
  5814  	//Test that things were destroyed
  5815  	actual := strings.TrimSpace(state.String())
  5816  	expected := strings.TrimSpace(`
  5817  <no state>`)
  5818  	if actual != expected {
  5819  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  5820  	}
  5821  }
  5822  
  5823  func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) {
  5824  	m := testModule(t, "apply-destroy-mod-var-and-count")
  5825  	p := testProvider("aws")
  5826  	p.PlanResourceChangeFn = testDiffFn
  5827  
  5828  	var state *states.State
  5829  	{
  5830  		ctx := testContext2(t, &ContextOpts{
  5831  			Providers: map[addrs.Provider]providers.Factory{
  5832  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5833  			},
  5834  		})
  5835  
  5836  		// First plan and apply a create operation
  5837  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5838  		assertNoErrors(t, diags)
  5839  
  5840  		state, diags = ctx.Apply(plan, m)
  5841  		if diags.HasErrors() {
  5842  			t.Fatalf("apply err: %s", diags.Err())
  5843  		}
  5844  	}
  5845  
  5846  	{
  5847  		ctx := testContext2(t, &ContextOpts{
  5848  			Providers: map[addrs.Provider]providers.Factory{
  5849  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5850  			},
  5851  		})
  5852  
  5853  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5854  			Mode: plans.DestroyMode,
  5855  			Targets: []addrs.Targetable{
  5856  				addrs.RootModuleInstance.Child("child", addrs.NoKey),
  5857  			},
  5858  		})
  5859  		if diags.HasErrors() {
  5860  			t.Fatalf("plan err: %s", diags)
  5861  		}
  5862  		if len(diags) != 1 {
  5863  			// Should have one warning that -target is in effect.
  5864  			t.Fatalf("got %d diagnostics in plan; want 1", len(diags))
  5865  		}
  5866  		if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
  5867  			t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
  5868  		}
  5869  		if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want {
  5870  			t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
  5871  		}
  5872  
  5873  		// Destroy, targeting the module explicitly
  5874  		state, diags = ctx.Apply(plan, m)
  5875  		if diags.HasErrors() {
  5876  			t.Fatalf("destroy apply err: %s", diags)
  5877  		}
  5878  		if len(diags) != 1 {
  5879  			t.Fatalf("got %d diagnostics; want 1", len(diags))
  5880  		}
  5881  		if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
  5882  			t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
  5883  		}
  5884  		if got, want := diags[0].Description().Summary, "Applied changes may be incomplete"; got != want {
  5885  			t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
  5886  		}
  5887  	}
  5888  
  5889  	//Test that things were destroyed
  5890  	actual := strings.TrimSpace(state.String())
  5891  	expected := strings.TrimSpace(`<no state>`)
  5892  	if actual != expected {
  5893  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  5894  	}
  5895  }
  5896  
  5897  func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) {
  5898  	m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count-nested")
  5899  	p := testProvider("aws")
  5900  	p.PlanResourceChangeFn = testDiffFn
  5901  
  5902  	var state *states.State
  5903  	{
  5904  		ctx := testContext2(t, &ContextOpts{
  5905  			Providers: map[addrs.Provider]providers.Factory{
  5906  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5907  			},
  5908  		})
  5909  
  5910  		// First plan and apply a create operation
  5911  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5912  		assertNoErrors(t, diags)
  5913  
  5914  		state, diags = ctx.Apply(plan, m)
  5915  		if diags.HasErrors() {
  5916  			t.Fatalf("apply err: %s", diags.Err())
  5917  		}
  5918  	}
  5919  
  5920  	h := new(HookRecordApplyOrder)
  5921  	h.Active = true
  5922  
  5923  	{
  5924  		ctx := testContext2(t, &ContextOpts{
  5925  			Hooks: []Hook{h},
  5926  			Providers: map[addrs.Provider]providers.Factory{
  5927  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5928  			},
  5929  		})
  5930  
  5931  		// First plan and apply a create operation
  5932  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5933  			Mode: plans.DestroyMode,
  5934  		})
  5935  		if diags.HasErrors() {
  5936  			t.Fatalf("destroy plan err: %s", diags.Err())
  5937  		}
  5938  
  5939  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  5940  		if err != nil {
  5941  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5942  		}
  5943  
  5944  		ctxOpts.Providers =
  5945  			map[addrs.Provider]providers.Factory{
  5946  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5947  			}
  5948  
  5949  		ctx, diags = NewContext(ctxOpts)
  5950  		if diags.HasErrors() {
  5951  			t.Fatalf("err: %s", diags.Err())
  5952  		}
  5953  
  5954  		state, diags = ctx.Apply(plan, m)
  5955  		if diags.HasErrors() {
  5956  			t.Fatalf("destroy apply err: %s", diags.Err())
  5957  		}
  5958  	}
  5959  
  5960  	//Test that things were destroyed
  5961  	actual := strings.TrimSpace(state.String())
  5962  	expected := strings.TrimSpace(`
  5963  <no state>`)
  5964  	if actual != expected {
  5965  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  5966  	}
  5967  }
  5968  
  5969  func TestContext2Apply_destroyOutputs(t *testing.T) {
  5970  	m := testModule(t, "apply-destroy-outputs")
  5971  	p := testProvider("test")
  5972  	p.PlanResourceChangeFn = testDiffFn
  5973  
  5974  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  5975  		// add the required id
  5976  		m := req.Config.AsValueMap()
  5977  		m["id"] = cty.StringVal("foo")
  5978  
  5979  		return providers.ReadDataSourceResponse{
  5980  			State: cty.ObjectVal(m),
  5981  		}
  5982  	}
  5983  
  5984  	ctx := testContext2(t, &ContextOpts{
  5985  		Providers: map[addrs.Provider]providers.Factory{
  5986  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  5987  		},
  5988  	})
  5989  
  5990  	// First plan and apply a create operation
  5991  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5992  	assertNoErrors(t, diags)
  5993  
  5994  	state, diags := ctx.Apply(plan, m)
  5995  
  5996  	if diags.HasErrors() {
  5997  		t.Fatalf("diags: %s", diags.Err())
  5998  	}
  5999  
  6000  	// Next, plan and apply a destroy operation
  6001  	ctx = testContext2(t, &ContextOpts{
  6002  		Providers: map[addrs.Provider]providers.Factory{
  6003  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6004  		},
  6005  	})
  6006  
  6007  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  6008  		Mode: plans.DestroyMode,
  6009  	})
  6010  	assertNoErrors(t, diags)
  6011  
  6012  	state, diags = ctx.Apply(plan, m)
  6013  	if diags.HasErrors() {
  6014  		t.Fatalf("diags: %s", diags.Err())
  6015  	}
  6016  
  6017  	mod := state.RootModule()
  6018  	if len(mod.Resources) > 0 {
  6019  		t.Fatalf("expected no resources, got: %#v", mod)
  6020  	}
  6021  
  6022  	// destroying again should produce no errors
  6023  	ctx = testContext2(t, &ContextOpts{
  6024  		Providers: map[addrs.Provider]providers.Factory{
  6025  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6026  		},
  6027  	})
  6028  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  6029  		Mode: plans.DestroyMode,
  6030  	})
  6031  	assertNoErrors(t, diags)
  6032  
  6033  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6034  		t.Fatal(diags.Err())
  6035  	}
  6036  }
  6037  
  6038  func TestContext2Apply_destroyOrphan(t *testing.T) {
  6039  	m := testModule(t, "apply-error")
  6040  	p := testProvider("aws")
  6041  	state := states.NewState()
  6042  	root := state.EnsureModule(addrs.RootModuleInstance)
  6043  	root.SetResourceInstanceCurrent(
  6044  		mustResourceInstanceAddr("aws_instance.baz").Resource,
  6045  		&states.ResourceInstanceObjectSrc{
  6046  			Status:    states.ObjectReady,
  6047  			AttrsJSON: []byte(`{"id":"bar"}`),
  6048  		},
  6049  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6050  	)
  6051  	ctx := testContext2(t, &ContextOpts{
  6052  		Providers: map[addrs.Provider]providers.Factory{
  6053  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6054  		},
  6055  	})
  6056  
  6057  	p.PlanResourceChangeFn = testDiffFn
  6058  
  6059  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6060  	assertNoErrors(t, diags)
  6061  
  6062  	s, diags := ctx.Apply(plan, m)
  6063  	if diags.HasErrors() {
  6064  		t.Fatalf("diags: %s", diags.Err())
  6065  	}
  6066  
  6067  	mod := s.RootModule()
  6068  	if _, ok := mod.Resources["aws_instance.baz"]; ok {
  6069  		t.Fatalf("bad: %#v", mod.Resources)
  6070  	}
  6071  }
  6072  
  6073  func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) {
  6074  	m := testModule(t, "apply-destroy-provisioner")
  6075  	p := testProvider("aws")
  6076  	pr := testProvisioner()
  6077  	p.PlanResourceChangeFn = testDiffFn
  6078  
  6079  	state := states.NewState()
  6080  	root := state.EnsureModule(addrs.RootModuleInstance)
  6081  	root.SetResourceInstanceCurrent(
  6082  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6083  		&states.ResourceInstanceObjectSrc{
  6084  			Status:    states.ObjectReady,
  6085  			AttrsJSON: []byte(`{"id":"bar"}`),
  6086  		},
  6087  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6088  	)
  6089  
  6090  	ctx := testContext2(t, &ContextOpts{
  6091  		Providers: map[addrs.Provider]providers.Factory{
  6092  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6093  		},
  6094  		Provisioners: map[string]provisioners.Factory{
  6095  			"shell": testProvisionerFuncFixed(pr),
  6096  		},
  6097  	})
  6098  
  6099  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  6100  		Mode: plans.DestroyMode,
  6101  	})
  6102  	assertNoErrors(t, diags)
  6103  
  6104  	s, diags := ctx.Apply(plan, m)
  6105  	if diags.HasErrors() {
  6106  		t.Fatalf("diags: %s", diags.Err())
  6107  	}
  6108  
  6109  	if pr.ProvisionResourceCalled {
  6110  		t.Fatal("provisioner should not be called")
  6111  	}
  6112  
  6113  	actual := strings.TrimSpace(s.String())
  6114  	expected := strings.TrimSpace("<no state>")
  6115  	if actual != expected {
  6116  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6117  	}
  6118  }
  6119  
  6120  func TestContext2Apply_error(t *testing.T) {
  6121  	errored := false
  6122  
  6123  	m := testModule(t, "apply-error")
  6124  	p := testProvider("aws")
  6125  	ctx := testContext2(t, &ContextOpts{
  6126  		Providers: map[addrs.Provider]providers.Factory{
  6127  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6128  		},
  6129  	})
  6130  
  6131  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  6132  		if errored {
  6133  			resp.NewState = req.PlannedState
  6134  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  6135  			return
  6136  		}
  6137  		errored = true
  6138  
  6139  		return testApplyFn(req)
  6140  	}
  6141  	p.PlanResourceChangeFn = testDiffFn
  6142  
  6143  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6144  	assertNoErrors(t, diags)
  6145  
  6146  	state, diags := ctx.Apply(plan, m)
  6147  	if diags == nil {
  6148  		t.Fatal("should have error")
  6149  	}
  6150  
  6151  	actual := strings.TrimSpace(state.String())
  6152  	expected := strings.TrimSpace(testTerraformApplyErrorStr)
  6153  	if actual != expected {
  6154  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6155  	}
  6156  }
  6157  
  6158  func TestContext2Apply_errorDestroy(t *testing.T) {
  6159  	m := testModule(t, "empty")
  6160  	p := testProvider("test")
  6161  
  6162  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6163  		ResourceTypes: map[string]*configschema.Block{
  6164  			"test_thing": {
  6165  				Attributes: map[string]*configschema.Attribute{
  6166  					"id": {Type: cty.String, Optional: true},
  6167  				},
  6168  			},
  6169  		},
  6170  	})
  6171  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6172  		// Should actually be called for this test, because Terraform Core
  6173  		// constructs the plan for a destroy operation itself.
  6174  		return providers.PlanResourceChangeResponse{
  6175  			PlannedState: req.ProposedNewState,
  6176  		}
  6177  	}
  6178  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6179  		// The apply (in this case, a destroy) always fails, so we can verify
  6180  		// that the object stays in the state after a destroy fails even though
  6181  		// we aren't returning a new state object here.
  6182  		return providers.ApplyResourceChangeResponse{
  6183  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("failed")),
  6184  		}
  6185  	}
  6186  
  6187  	ctx := testContext2(t, &ContextOpts{
  6188  		Providers: map[addrs.Provider]providers.Factory{
  6189  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6190  		},
  6191  	})
  6192  
  6193  	state := states.BuildState(func(ss *states.SyncState) {
  6194  		ss.SetResourceInstanceCurrent(
  6195  			addrs.Resource{
  6196  				Mode: addrs.ManagedResourceMode,
  6197  				Type: "test_thing",
  6198  				Name: "foo",
  6199  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  6200  			&states.ResourceInstanceObjectSrc{
  6201  				Status:    states.ObjectReady,
  6202  				AttrsJSON: []byte(`{"id":"baz"}`),
  6203  			},
  6204  			addrs.AbsProviderConfig{
  6205  				Provider: addrs.NewDefaultProvider("test"),
  6206  				Module:   addrs.RootModule,
  6207  			},
  6208  		)
  6209  	})
  6210  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6211  	assertNoErrors(t, diags)
  6212  
  6213  	state, diags = ctx.Apply(plan, m)
  6214  	if !diags.HasErrors() {
  6215  		t.Fatal("should have error")
  6216  	}
  6217  
  6218  	actual := strings.TrimSpace(state.String())
  6219  	expected := strings.TrimSpace(`
  6220  test_thing.foo:
  6221    ID = baz
  6222    provider = provider["registry.terraform.io/hashicorp/test"]
  6223  `) // test_thing.foo is still here, even though provider returned no new state along with its error
  6224  	if actual != expected {
  6225  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6226  	}
  6227  }
  6228  
  6229  func TestContext2Apply_errorCreateInvalidNew(t *testing.T) {
  6230  	m := testModule(t, "apply-error")
  6231  
  6232  	p := testProvider("aws")
  6233  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6234  		ResourceTypes: map[string]*configschema.Block{
  6235  			"aws_instance": {
  6236  				Attributes: map[string]*configschema.Attribute{
  6237  					"value": {Type: cty.String, Optional: true},
  6238  					"foo":   {Type: cty.String, Optional: true},
  6239  				},
  6240  			},
  6241  		},
  6242  	})
  6243  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6244  		return providers.PlanResourceChangeResponse{
  6245  			PlannedState: req.ProposedNewState,
  6246  		}
  6247  	}
  6248  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6249  		// We're intentionally returning an inconsistent new state here
  6250  		// because we want to test that Terraform ignores the inconsistency
  6251  		// when accompanied by another error.
  6252  		return providers.ApplyResourceChangeResponse{
  6253  			NewState: cty.ObjectVal(map[string]cty.Value{
  6254  				"value": cty.StringVal("wrong wrong wrong wrong"),
  6255  				"foo":   cty.StringVal("absolutely brimming over with wrongability"),
  6256  			}),
  6257  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")),
  6258  		}
  6259  	}
  6260  
  6261  	ctx := testContext2(t, &ContextOpts{
  6262  		Providers: map[addrs.Provider]providers.Factory{
  6263  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6264  		},
  6265  	})
  6266  
  6267  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6268  	assertNoErrors(t, diags)
  6269  
  6270  	state, diags := ctx.Apply(plan, m)
  6271  	if diags == nil {
  6272  		t.Fatal("should have error")
  6273  	}
  6274  	if got, want := len(diags), 1; got != want {
  6275  		// There should be no additional diagnostics generated by Terraform's own eval logic,
  6276  		// because the provider's own error supersedes them.
  6277  		t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err())
  6278  	}
  6279  	if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) {
  6280  		t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err())
  6281  	}
  6282  	if got, want := len(state.RootModule().Resources), 2; got != want {
  6283  		t.Errorf("%d resources in state before prune; should have %d\n%s", got, want, spew.Sdump(state))
  6284  	}
  6285  	state.PruneResourceHusks() // aws_instance.bar with no instances gets left behind when we bail out, but that's okay
  6286  	if got, want := len(state.RootModule().Resources), 1; got != want {
  6287  		t.Errorf("%d resources in state after prune; should have only one (aws_instance.foo, tainted)\n%s", got, spew.Sdump(state))
  6288  	}
  6289  }
  6290  
  6291  func TestContext2Apply_errorUpdateNullNew(t *testing.T) {
  6292  	m := testModule(t, "apply-error")
  6293  
  6294  	p := testProvider("aws")
  6295  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6296  		ResourceTypes: map[string]*configschema.Block{
  6297  			"aws_instance": {
  6298  				Attributes: map[string]*configschema.Attribute{
  6299  					"value": {Type: cty.String, Optional: true},
  6300  					"foo":   {Type: cty.String, Optional: true},
  6301  				},
  6302  			},
  6303  		},
  6304  	})
  6305  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6306  		return providers.PlanResourceChangeResponse{
  6307  			PlannedState: req.ProposedNewState,
  6308  		}
  6309  	}
  6310  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6311  		// We're intentionally returning no NewState here because we want to
  6312  		// test that Terraform retains the prior state, rather than treating
  6313  		// the returned null as "no state" (object deleted).
  6314  		return providers.ApplyResourceChangeResponse{
  6315  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")),
  6316  		}
  6317  	}
  6318  
  6319  	ctx := testContext2(t, &ContextOpts{
  6320  		Providers: map[addrs.Provider]providers.Factory{
  6321  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6322  		},
  6323  	})
  6324  
  6325  	state := states.BuildState(func(ss *states.SyncState) {
  6326  		ss.SetResourceInstanceCurrent(
  6327  			addrs.Resource{
  6328  				Mode: addrs.ManagedResourceMode,
  6329  				Type: "aws_instance",
  6330  				Name: "foo",
  6331  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  6332  			&states.ResourceInstanceObjectSrc{
  6333  				Status:    states.ObjectReady,
  6334  				AttrsJSON: []byte(`{"value":"old"}`),
  6335  			},
  6336  			addrs.AbsProviderConfig{
  6337  				Provider: addrs.NewDefaultProvider("aws"),
  6338  				Module:   addrs.RootModule,
  6339  			},
  6340  		)
  6341  	})
  6342  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6343  	assertNoErrors(t, diags)
  6344  
  6345  	state, diags = ctx.Apply(plan, m)
  6346  	if !diags.HasErrors() {
  6347  		t.Fatal("should have error")
  6348  	}
  6349  	if got, want := len(diags), 1; got != want {
  6350  		// There should be no additional diagnostics generated by Terraform's own eval logic,
  6351  		// because the provider's own error supersedes them.
  6352  		t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err())
  6353  	}
  6354  	if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) {
  6355  		t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err())
  6356  	}
  6357  	state.PruneResourceHusks()
  6358  	if got, want := len(state.RootModule().Resources), 1; got != want {
  6359  		t.Fatalf("%d resources in state; should have only one (aws_instance.foo, unmodified)\n%s", got, spew.Sdump(state))
  6360  	}
  6361  
  6362  	is := state.ResourceInstance(addrs.Resource{
  6363  		Mode: addrs.ManagedResourceMode,
  6364  		Type: "aws_instance",
  6365  		Name: "foo",
  6366  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
  6367  	if is == nil {
  6368  		t.Fatalf("aws_instance.foo is not in the state after apply")
  6369  	}
  6370  	if got, want := is.Current.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) {
  6371  		t.Fatalf("incorrect attributes for aws_instance.foo\ngot: %s\nwant: JSON containing %s\n\n%s", got, want, spew.Sdump(is))
  6372  	}
  6373  }
  6374  
  6375  func TestContext2Apply_errorPartial(t *testing.T) {
  6376  	errored := false
  6377  
  6378  	m := testModule(t, "apply-error")
  6379  	p := testProvider("aws")
  6380  
  6381  	state := states.NewState()
  6382  	root := state.EnsureModule(addrs.RootModuleInstance)
  6383  	root.SetResourceInstanceCurrent(
  6384  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6385  		&states.ResourceInstanceObjectSrc{
  6386  			Status:    states.ObjectReady,
  6387  			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
  6388  		},
  6389  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6390  	)
  6391  
  6392  	ctx := testContext2(t, &ContextOpts{
  6393  		Providers: map[addrs.Provider]providers.Factory{
  6394  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6395  		},
  6396  	})
  6397  
  6398  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  6399  		if errored {
  6400  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  6401  			return
  6402  		}
  6403  		errored = true
  6404  
  6405  		return testApplyFn(req)
  6406  	}
  6407  	p.PlanResourceChangeFn = testDiffFn
  6408  
  6409  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6410  	assertNoErrors(t, diags)
  6411  
  6412  	s, diags := ctx.Apply(plan, m)
  6413  	if diags == nil {
  6414  		t.Fatal("should have error")
  6415  	}
  6416  
  6417  	mod := s.RootModule()
  6418  	if len(mod.Resources) != 2 {
  6419  		t.Fatalf("bad: %#v", mod.Resources)
  6420  	}
  6421  
  6422  	actual := strings.TrimSpace(s.String())
  6423  	expected := strings.TrimSpace(testTerraformApplyErrorPartialStr)
  6424  	if actual != expected {
  6425  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6426  	}
  6427  }
  6428  
  6429  func TestContext2Apply_hook(t *testing.T) {
  6430  	m := testModule(t, "apply-good")
  6431  	h := new(MockHook)
  6432  	p := testProvider("aws")
  6433  	p.PlanResourceChangeFn = testDiffFn
  6434  	ctx := testContext2(t, &ContextOpts{
  6435  		Hooks: []Hook{h},
  6436  		Providers: map[addrs.Provider]providers.Factory{
  6437  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6438  		},
  6439  	})
  6440  
  6441  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6442  	assertNoErrors(t, diags)
  6443  
  6444  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6445  		t.Fatalf("apply errors: %s", diags.Err())
  6446  	}
  6447  
  6448  	if !h.PreApplyCalled {
  6449  		t.Fatal("should be called")
  6450  	}
  6451  	if !h.PostApplyCalled {
  6452  		t.Fatal("should be called")
  6453  	}
  6454  	if !h.PostStateUpdateCalled {
  6455  		t.Fatalf("should call post state update")
  6456  	}
  6457  }
  6458  
  6459  func TestContext2Apply_hookOrphan(t *testing.T) {
  6460  	m := testModule(t, "apply-blank")
  6461  	h := new(MockHook)
  6462  	p := testProvider("aws")
  6463  	p.PlanResourceChangeFn = testDiffFn
  6464  
  6465  	state := states.NewState()
  6466  	root := state.EnsureModule(addrs.RootModuleInstance)
  6467  	root.SetResourceInstanceCurrent(
  6468  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6469  		&states.ResourceInstanceObjectSrc{
  6470  			Status:    states.ObjectReady,
  6471  			AttrsJSON: []byte(`{"id":"bar"}`),
  6472  		},
  6473  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6474  	)
  6475  
  6476  	ctx := testContext2(t, &ContextOpts{
  6477  		Hooks: []Hook{h},
  6478  		Providers: map[addrs.Provider]providers.Factory{
  6479  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6480  		},
  6481  	})
  6482  
  6483  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6484  	assertNoErrors(t, diags)
  6485  
  6486  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6487  		t.Fatalf("apply errors: %s", diags.Err())
  6488  	}
  6489  
  6490  	if !h.PreApplyCalled {
  6491  		t.Fatal("should be called")
  6492  	}
  6493  	if !h.PostApplyCalled {
  6494  		t.Fatal("should be called")
  6495  	}
  6496  	if !h.PostStateUpdateCalled {
  6497  		t.Fatalf("should call post state update")
  6498  	}
  6499  }
  6500  
  6501  func TestContext2Apply_idAttr(t *testing.T) {
  6502  	m := testModule(t, "apply-idattr")
  6503  	p := testProvider("aws")
  6504  	ctx := testContext2(t, &ContextOpts{
  6505  		Providers: map[addrs.Provider]providers.Factory{
  6506  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6507  		},
  6508  	})
  6509  
  6510  	p.PlanResourceChangeFn = testDiffFn
  6511  	p.ApplyResourceChangeFn = testApplyFn
  6512  
  6513  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6514  	assertNoErrors(t, diags)
  6515  
  6516  	state, diags := ctx.Apply(plan, m)
  6517  	if diags.HasErrors() {
  6518  		t.Fatalf("apply errors: %s", diags.Err())
  6519  	}
  6520  
  6521  	mod := state.RootModule()
  6522  	rs, ok := mod.Resources["aws_instance.foo"]
  6523  	if !ok {
  6524  		t.Fatal("not in state")
  6525  	}
  6526  	var attrs map[string]interface{}
  6527  	err := json.Unmarshal(rs.Instances[addrs.NoKey].Current.AttrsJSON, &attrs)
  6528  	if err != nil {
  6529  		t.Fatal(err)
  6530  	}
  6531  	if got, want := attrs["id"], "foo"; got != want {
  6532  		t.Fatalf("wrong id\ngot:  %#v\nwant: %#v", got, want)
  6533  	}
  6534  }
  6535  
  6536  func TestContext2Apply_outputBasic(t *testing.T) {
  6537  	m := testModule(t, "apply-output")
  6538  	p := testProvider("aws")
  6539  	p.PlanResourceChangeFn = testDiffFn
  6540  	p.ApplyResourceChangeFn = testApplyFn
  6541  	ctx := testContext2(t, &ContextOpts{
  6542  		Providers: map[addrs.Provider]providers.Factory{
  6543  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6544  		},
  6545  	})
  6546  
  6547  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6548  	assertNoErrors(t, diags)
  6549  
  6550  	state, diags := ctx.Apply(plan, m)
  6551  	if diags.HasErrors() {
  6552  		t.Fatalf("diags: %s", diags.Err())
  6553  	}
  6554  
  6555  	actual := strings.TrimSpace(state.String())
  6556  	expected := strings.TrimSpace(testTerraformApplyOutputStr)
  6557  	if actual != expected {
  6558  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6559  	}
  6560  }
  6561  
  6562  func TestContext2Apply_outputAdd(t *testing.T) {
  6563  	m1 := testModule(t, "apply-output-add-before")
  6564  	p1 := testProvider("aws")
  6565  	p1.ApplyResourceChangeFn = testApplyFn
  6566  	p1.PlanResourceChangeFn = testDiffFn
  6567  	ctx1 := testContext2(t, &ContextOpts{
  6568  		Providers: map[addrs.Provider]providers.Factory{
  6569  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p1),
  6570  		},
  6571  	})
  6572  
  6573  	plan1, diags := ctx1.Plan(m1, states.NewState(), DefaultPlanOpts)
  6574  	assertNoErrors(t, diags)
  6575  
  6576  	state1, diags := ctx1.Apply(plan1, m1)
  6577  	if diags.HasErrors() {
  6578  		t.Fatalf("diags: %s", diags.Err())
  6579  	}
  6580  
  6581  	m2 := testModule(t, "apply-output-add-after")
  6582  	p2 := testProvider("aws")
  6583  	p2.ApplyResourceChangeFn = testApplyFn
  6584  	p2.PlanResourceChangeFn = testDiffFn
  6585  	ctx2 := testContext2(t, &ContextOpts{
  6586  		Providers: map[addrs.Provider]providers.Factory{
  6587  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p2),
  6588  		},
  6589  	})
  6590  
  6591  	plan2, diags := ctx1.Plan(m2, state1, DefaultPlanOpts)
  6592  	assertNoErrors(t, diags)
  6593  
  6594  	state2, diags := ctx2.Apply(plan2, m2)
  6595  	if diags.HasErrors() {
  6596  		t.Fatalf("diags: %s", diags.Err())
  6597  	}
  6598  
  6599  	actual := strings.TrimSpace(state2.String())
  6600  	expected := strings.TrimSpace(testTerraformApplyOutputAddStr)
  6601  	if actual != expected {
  6602  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6603  	}
  6604  }
  6605  
  6606  func TestContext2Apply_outputList(t *testing.T) {
  6607  	m := testModule(t, "apply-output-list")
  6608  	p := testProvider("aws")
  6609  	p.PlanResourceChangeFn = testDiffFn
  6610  	p.ApplyResourceChangeFn = testApplyFn
  6611  	ctx := testContext2(t, &ContextOpts{
  6612  		Providers: map[addrs.Provider]providers.Factory{
  6613  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6614  		},
  6615  	})
  6616  
  6617  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6618  	assertNoErrors(t, diags)
  6619  
  6620  	state, diags := ctx.Apply(plan, m)
  6621  	if diags.HasErrors() {
  6622  		t.Fatalf("diags: %s", diags.Err())
  6623  	}
  6624  
  6625  	actual := strings.TrimSpace(state.String())
  6626  	expected := strings.TrimSpace(testTerraformApplyOutputListStr)
  6627  	if actual != expected {
  6628  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  6629  	}
  6630  }
  6631  
  6632  func TestContext2Apply_outputMulti(t *testing.T) {
  6633  	m := testModule(t, "apply-output-multi")
  6634  	p := testProvider("aws")
  6635  	p.PlanResourceChangeFn = testDiffFn
  6636  	p.ApplyResourceChangeFn = testApplyFn
  6637  	ctx := testContext2(t, &ContextOpts{
  6638  		Providers: map[addrs.Provider]providers.Factory{
  6639  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6640  		},
  6641  	})
  6642  
  6643  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6644  	assertNoErrors(t, diags)
  6645  
  6646  	state, diags := ctx.Apply(plan, m)
  6647  	if diags.HasErrors() {
  6648  		t.Fatalf("diags: %s", diags.Err())
  6649  	}
  6650  
  6651  	actual := strings.TrimSpace(state.String())
  6652  	expected := strings.TrimSpace(testTerraformApplyOutputMultiStr)
  6653  	if actual != expected {
  6654  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6655  	}
  6656  }
  6657  
  6658  func TestContext2Apply_outputMultiIndex(t *testing.T) {
  6659  	m := testModule(t, "apply-output-multi-index")
  6660  	p := testProvider("aws")
  6661  	p.PlanResourceChangeFn = testDiffFn
  6662  	p.ApplyResourceChangeFn = testApplyFn
  6663  	ctx := testContext2(t, &ContextOpts{
  6664  		Providers: map[addrs.Provider]providers.Factory{
  6665  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6666  		},
  6667  	})
  6668  
  6669  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6670  	assertNoErrors(t, diags)
  6671  
  6672  	state, diags := ctx.Apply(plan, m)
  6673  	if diags.HasErrors() {
  6674  		t.Fatalf("diags: %s", diags.Err())
  6675  	}
  6676  
  6677  	actual := strings.TrimSpace(state.String())
  6678  	expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr)
  6679  	if actual != expected {
  6680  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6681  	}
  6682  }
  6683  
  6684  func TestContext2Apply_taintX(t *testing.T) {
  6685  	m := testModule(t, "apply-taint")
  6686  	p := testProvider("aws")
  6687  	// destroyCount tests against regression of
  6688  	// https://github.com/muratcelep/terraform/issues/1056
  6689  	var destroyCount = int32(0)
  6690  	var once sync.Once
  6691  	simulateProviderDelay := func() {
  6692  		time.Sleep(10 * time.Millisecond)
  6693  	}
  6694  
  6695  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6696  		once.Do(simulateProviderDelay)
  6697  		if req.PlannedState.IsNull() {
  6698  			atomic.AddInt32(&destroyCount, 1)
  6699  		}
  6700  		return testApplyFn(req)
  6701  	}
  6702  	p.PlanResourceChangeFn = testDiffFn
  6703  
  6704  	state := states.NewState()
  6705  	root := state.EnsureModule(addrs.RootModuleInstance)
  6706  	root.SetResourceInstanceCurrent(
  6707  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6708  		&states.ResourceInstanceObjectSrc{
  6709  			Status:    states.ObjectTainted,
  6710  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6711  		},
  6712  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6713  	)
  6714  
  6715  	ctx := testContext2(t, &ContextOpts{
  6716  		Providers: map[addrs.Provider]providers.Factory{
  6717  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6718  		},
  6719  	})
  6720  
  6721  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6722  	if diags.HasErrors() {
  6723  		t.Fatalf("diags: %s", diags.Err())
  6724  	} else {
  6725  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6726  	}
  6727  
  6728  	s, diags := ctx.Apply(plan, m)
  6729  	if diags.HasErrors() {
  6730  		t.Fatalf("diags: %s", diags.Err())
  6731  	}
  6732  
  6733  	actual := strings.TrimSpace(s.String())
  6734  	expected := strings.TrimSpace(testTerraformApplyTaintStr)
  6735  	if actual != expected {
  6736  		t.Fatalf("bad:\n%s", actual)
  6737  	}
  6738  
  6739  	if destroyCount != 1 {
  6740  		t.Fatalf("Expected 1 destroy, got %d", destroyCount)
  6741  	}
  6742  }
  6743  
  6744  func TestContext2Apply_taintDep(t *testing.T) {
  6745  	m := testModule(t, "apply-taint-dep")
  6746  	p := testProvider("aws")
  6747  	p.PlanResourceChangeFn = testDiffFn
  6748  	p.ApplyResourceChangeFn = testApplyFn
  6749  
  6750  	state := states.NewState()
  6751  	root := state.EnsureModule(addrs.RootModuleInstance)
  6752  	root.SetResourceInstanceCurrent(
  6753  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6754  		&states.ResourceInstanceObjectSrc{
  6755  			Status:    states.ObjectTainted,
  6756  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6757  		},
  6758  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6759  	)
  6760  	root.SetResourceInstanceCurrent(
  6761  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6762  		&states.ResourceInstanceObjectSrc{
  6763  			Status:       states.ObjectReady,
  6764  			AttrsJSON:    []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`),
  6765  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  6766  		},
  6767  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6768  	)
  6769  
  6770  	ctx := testContext2(t, &ContextOpts{
  6771  		Providers: map[addrs.Provider]providers.Factory{
  6772  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6773  		},
  6774  	})
  6775  
  6776  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6777  	if diags.HasErrors() {
  6778  		t.Fatalf("diags: %s", diags.Err())
  6779  	} else {
  6780  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6781  	}
  6782  
  6783  	s, diags := ctx.Apply(plan, m)
  6784  	if diags.HasErrors() {
  6785  		t.Fatalf("diags: %s", diags.Err())
  6786  	}
  6787  
  6788  	actual := strings.TrimSpace(s.String())
  6789  	expected := strings.TrimSpace(testTerraformApplyTaintDepStr)
  6790  	if actual != expected {
  6791  		t.Fatalf("bad:\n%s", actual)
  6792  	}
  6793  }
  6794  
  6795  func TestContext2Apply_taintDepRequiresNew(t *testing.T) {
  6796  	m := testModule(t, "apply-taint-dep-requires-new")
  6797  	p := testProvider("aws")
  6798  	p.PlanResourceChangeFn = testDiffFn
  6799  	p.ApplyResourceChangeFn = testApplyFn
  6800  
  6801  	state := states.NewState()
  6802  	root := state.EnsureModule(addrs.RootModuleInstance)
  6803  	root.SetResourceInstanceCurrent(
  6804  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6805  		&states.ResourceInstanceObjectSrc{
  6806  			Status:    states.ObjectTainted,
  6807  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6808  		},
  6809  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6810  	)
  6811  	root.SetResourceInstanceCurrent(
  6812  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6813  		&states.ResourceInstanceObjectSrc{
  6814  			Status:       states.ObjectReady,
  6815  			AttrsJSON:    []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`),
  6816  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  6817  		},
  6818  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6819  	)
  6820  
  6821  	ctx := testContext2(t, &ContextOpts{
  6822  		Providers: map[addrs.Provider]providers.Factory{
  6823  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6824  		},
  6825  	})
  6826  
  6827  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6828  	if diags.HasErrors() {
  6829  		t.Fatalf("diags: %s", diags.Err())
  6830  	} else {
  6831  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6832  	}
  6833  
  6834  	s, diags := ctx.Apply(plan, m)
  6835  	if diags.HasErrors() {
  6836  		t.Fatalf("diags: %s", diags.Err())
  6837  	}
  6838  
  6839  	actual := strings.TrimSpace(s.String())
  6840  	expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr)
  6841  	if actual != expected {
  6842  		t.Fatalf("bad:\n%s", actual)
  6843  	}
  6844  }
  6845  
  6846  func TestContext2Apply_targeted(t *testing.T) {
  6847  	m := testModule(t, "apply-targeted")
  6848  	p := testProvider("aws")
  6849  	p.PlanResourceChangeFn = testDiffFn
  6850  	p.ApplyResourceChangeFn = testApplyFn
  6851  	ctx := testContext2(t, &ContextOpts{
  6852  		Providers: map[addrs.Provider]providers.Factory{
  6853  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6854  		},
  6855  	})
  6856  
  6857  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  6858  		Mode: plans.NormalMode,
  6859  		Targets: []addrs.Targetable{
  6860  			addrs.RootModuleInstance.Resource(
  6861  				addrs.ManagedResourceMode, "aws_instance", "foo",
  6862  			),
  6863  		},
  6864  	})
  6865  	assertNoErrors(t, diags)
  6866  
  6867  	state, diags := ctx.Apply(plan, m)
  6868  	if diags.HasErrors() {
  6869  		t.Fatalf("diags: %s", diags.Err())
  6870  	}
  6871  
  6872  	mod := state.RootModule()
  6873  	if len(mod.Resources) != 1 {
  6874  		t.Fatalf("expected 1 resource, got: %#v", mod.Resources)
  6875  	}
  6876  
  6877  	checkStateString(t, state, `
  6878  aws_instance.foo:
  6879    ID = foo
  6880    provider = provider["registry.terraform.io/hashicorp/aws"]
  6881    num = 2
  6882    type = aws_instance
  6883  	`)
  6884  }
  6885  
  6886  func TestContext2Apply_targetedCount(t *testing.T) {
  6887  	m := testModule(t, "apply-targeted-count")
  6888  	p := testProvider("aws")
  6889  	p.PlanResourceChangeFn = testDiffFn
  6890  	p.ApplyResourceChangeFn = testApplyFn
  6891  	ctx := testContext2(t, &ContextOpts{
  6892  		Providers: map[addrs.Provider]providers.Factory{
  6893  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6894  		},
  6895  	})
  6896  
  6897  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  6898  		Mode: plans.NormalMode,
  6899  		Targets: []addrs.Targetable{
  6900  			addrs.RootModuleInstance.Resource(
  6901  				addrs.ManagedResourceMode, "aws_instance", "foo",
  6902  			),
  6903  		},
  6904  	})
  6905  	assertNoErrors(t, diags)
  6906  
  6907  	state, diags := ctx.Apply(plan, m)
  6908  	if diags.HasErrors() {
  6909  		t.Fatalf("diags: %s", diags.Err())
  6910  	}
  6911  
  6912  	checkStateString(t, state, `
  6913  aws_instance.foo.0:
  6914    ID = foo
  6915    provider = provider["registry.terraform.io/hashicorp/aws"]
  6916    type = aws_instance
  6917  aws_instance.foo.1:
  6918    ID = foo
  6919    provider = provider["registry.terraform.io/hashicorp/aws"]
  6920    type = aws_instance
  6921  aws_instance.foo.2:
  6922    ID = foo
  6923    provider = provider["registry.terraform.io/hashicorp/aws"]
  6924    type = aws_instance
  6925  	`)
  6926  }
  6927  
  6928  func TestContext2Apply_targetedCountIndex(t *testing.T) {
  6929  	m := testModule(t, "apply-targeted-count")
  6930  	p := testProvider("aws")
  6931  	p.PlanResourceChangeFn = testDiffFn
  6932  	p.ApplyResourceChangeFn = testApplyFn
  6933  	ctx := testContext2(t, &ContextOpts{
  6934  		Providers: map[addrs.Provider]providers.Factory{
  6935  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6936  		},
  6937  	})
  6938  
  6939  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  6940  		Mode: plans.NormalMode,
  6941  		Targets: []addrs.Targetable{
  6942  			addrs.RootModuleInstance.ResourceInstance(
  6943  				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(1),
  6944  			),
  6945  		},
  6946  	})
  6947  	assertNoErrors(t, diags)
  6948  
  6949  	state, diags := ctx.Apply(plan, m)
  6950  	if diags.HasErrors() {
  6951  		t.Fatalf("diags: %s", diags.Err())
  6952  	}
  6953  
  6954  	checkStateString(t, state, `
  6955  aws_instance.foo.1:
  6956    ID = foo
  6957    provider = provider["registry.terraform.io/hashicorp/aws"]
  6958    type = aws_instance
  6959  	`)
  6960  }
  6961  
  6962  func TestContext2Apply_targetedDestroy(t *testing.T) {
  6963  	m := testModule(t, "destroy-targeted")
  6964  	p := testProvider("aws")
  6965  	p.PlanResourceChangeFn = testDiffFn
  6966  
  6967  	state := states.NewState()
  6968  	root := state.EnsureModule(addrs.RootModuleInstance)
  6969  	root.SetResourceInstanceCurrent(
  6970  		mustResourceInstanceAddr("aws_instance.a").Resource,
  6971  		&states.ResourceInstanceObjectSrc{
  6972  			Status:    states.ObjectReady,
  6973  			AttrsJSON: []byte(`{"id":"bar"}`),
  6974  		},
  6975  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6976  	)
  6977  	root.SetOutputValue("out", cty.StringVal("bar"), false)
  6978  
  6979  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  6980  	child.SetResourceInstanceCurrent(
  6981  		mustResourceInstanceAddr("aws_instance.b").Resource,
  6982  		&states.ResourceInstanceObjectSrc{
  6983  			Status:    states.ObjectReady,
  6984  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  6985  		},
  6986  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6987  	)
  6988  
  6989  	ctx := testContext2(t, &ContextOpts{
  6990  		Providers: map[addrs.Provider]providers.Factory{
  6991  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6992  		},
  6993  	})
  6994  
  6995  	if diags := ctx.Validate(m); diags.HasErrors() {
  6996  		t.Fatalf("validate errors: %s", diags.Err())
  6997  	}
  6998  
  6999  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7000  		Mode: plans.DestroyMode,
  7001  		Targets: []addrs.Targetable{
  7002  			addrs.RootModuleInstance.Resource(
  7003  				addrs.ManagedResourceMode, "aws_instance", "a",
  7004  			),
  7005  		},
  7006  	})
  7007  	assertNoErrors(t, diags)
  7008  
  7009  	state, diags = ctx.Apply(plan, m)
  7010  	if diags.HasErrors() {
  7011  		t.Fatalf("diags: %s", diags.Err())
  7012  	}
  7013  
  7014  	mod := state.RootModule()
  7015  	if len(mod.Resources) != 0 {
  7016  		t.Fatalf("expected 0 resources, got: %#v", mod.Resources)
  7017  	}
  7018  
  7019  	// the root output should not get removed; only the targeted resource.
  7020  	//
  7021  	// Note: earlier versions of this test expected 0 outputs, but it turns out
  7022  	// that was because Validate - not apply or destroy - removed the output
  7023  	// (which depends on the targeted resource) from state. That version of this
  7024  	// test did not match actual terraform behavior: the output remains in
  7025  	// state.
  7026  	//
  7027  	// TODO: Future refactoring may enable us to remove the output from state in
  7028  	// this case, and that would be Just Fine - this test can be modified to
  7029  	// expect 0 outputs.
  7030  	if len(mod.OutputValues) != 1 {
  7031  		t.Fatalf("expected 1 outputs, got: %#v", mod.OutputValues)
  7032  	}
  7033  
  7034  	// the module instance should remain
  7035  	mod = state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7036  	if len(mod.Resources) != 1 {
  7037  		t.Fatalf("expected 1 resources, got: %#v", mod.Resources)
  7038  	}
  7039  }
  7040  
  7041  func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) {
  7042  	m := testModule(t, "apply-destroy-targeted-count")
  7043  	p := testProvider("aws")
  7044  	p.PlanResourceChangeFn = testDiffFn
  7045  
  7046  	state := states.NewState()
  7047  	root := state.EnsureModule(addrs.RootModuleInstance)
  7048  	root.SetResourceInstanceCurrent(
  7049  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7050  		&states.ResourceInstanceObjectSrc{
  7051  			Status:    states.ObjectReady,
  7052  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7053  		},
  7054  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7055  	)
  7056  	root.SetResourceInstanceCurrent(
  7057  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7058  		&states.ResourceInstanceObjectSrc{
  7059  			Status:       states.ObjectReady,
  7060  			AttrsJSON:    []byte(`{"id":"i-abc123"}`),
  7061  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  7062  		},
  7063  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7064  	)
  7065  
  7066  	ctx := testContext2(t, &ContextOpts{
  7067  		Providers: map[addrs.Provider]providers.Factory{
  7068  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7069  		},
  7070  	})
  7071  
  7072  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7073  		Mode: plans.DestroyMode,
  7074  		Targets: []addrs.Targetable{
  7075  			addrs.RootModuleInstance.Resource(
  7076  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7077  			),
  7078  		},
  7079  	})
  7080  	assertNoErrors(t, diags)
  7081  
  7082  	state, diags = ctx.Apply(plan, m)
  7083  	if diags.HasErrors() {
  7084  		t.Fatalf("diags: %s", diags.Err())
  7085  	}
  7086  
  7087  	checkStateString(t, state, `<no state>`)
  7088  }
  7089  
  7090  // https://github.com/muratcelep/terraform/issues/4462
  7091  func TestContext2Apply_targetedDestroyModule(t *testing.T) {
  7092  	m := testModule(t, "apply-targeted-module")
  7093  	p := testProvider("aws")
  7094  	p.PlanResourceChangeFn = testDiffFn
  7095  
  7096  	state := states.NewState()
  7097  	root := state.EnsureModule(addrs.RootModuleInstance)
  7098  	root.SetResourceInstanceCurrent(
  7099  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7100  		&states.ResourceInstanceObjectSrc{
  7101  			Status:    states.ObjectReady,
  7102  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7103  		},
  7104  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7105  	)
  7106  	root.SetResourceInstanceCurrent(
  7107  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7108  		&states.ResourceInstanceObjectSrc{
  7109  			Status:    states.ObjectReady,
  7110  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7111  		},
  7112  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7113  	)
  7114  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7115  	child.SetResourceInstanceCurrent(
  7116  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7117  		&states.ResourceInstanceObjectSrc{
  7118  			Status:    states.ObjectReady,
  7119  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7120  		},
  7121  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7122  	)
  7123  	child.SetResourceInstanceCurrent(
  7124  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7125  		&states.ResourceInstanceObjectSrc{
  7126  			Status:    states.ObjectReady,
  7127  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7128  		},
  7129  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7130  	)
  7131  
  7132  	ctx := testContext2(t, &ContextOpts{
  7133  		Providers: map[addrs.Provider]providers.Factory{
  7134  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7135  		},
  7136  	})
  7137  
  7138  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7139  		Mode: plans.DestroyMode,
  7140  		Targets: []addrs.Targetable{
  7141  			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
  7142  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7143  			),
  7144  		},
  7145  	})
  7146  	assertNoErrors(t, diags)
  7147  
  7148  	state, diags = ctx.Apply(plan, m)
  7149  	if diags.HasErrors() {
  7150  		t.Fatalf("diags: %s", diags.Err())
  7151  	}
  7152  
  7153  	checkStateString(t, state, `
  7154  aws_instance.bar:
  7155    ID = i-abc123
  7156    provider = provider["registry.terraform.io/hashicorp/aws"]
  7157  aws_instance.foo:
  7158    ID = i-bcd345
  7159    provider = provider["registry.terraform.io/hashicorp/aws"]
  7160  
  7161  module.child:
  7162    aws_instance.bar:
  7163      ID = i-abc123
  7164      provider = provider["registry.terraform.io/hashicorp/aws"]
  7165  	`)
  7166  }
  7167  
  7168  func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) {
  7169  	m := testModule(t, "apply-targeted-count")
  7170  	p := testProvider("aws")
  7171  	p.PlanResourceChangeFn = testDiffFn
  7172  
  7173  	foo := &states.ResourceInstanceObjectSrc{
  7174  		Status:    states.ObjectReady,
  7175  		AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7176  	}
  7177  	bar := &states.ResourceInstanceObjectSrc{
  7178  		Status:    states.ObjectReady,
  7179  		AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7180  	}
  7181  
  7182  	state := states.NewState()
  7183  	root := state.EnsureModule(addrs.RootModuleInstance)
  7184  	root.SetResourceInstanceCurrent(
  7185  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  7186  		foo,
  7187  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7188  	)
  7189  	root.SetResourceInstanceCurrent(
  7190  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  7191  		foo,
  7192  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7193  	)
  7194  	root.SetResourceInstanceCurrent(
  7195  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  7196  		foo,
  7197  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7198  	)
  7199  	root.SetResourceInstanceCurrent(
  7200  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  7201  		bar,
  7202  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7203  	)
  7204  	root.SetResourceInstanceCurrent(
  7205  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  7206  		bar,
  7207  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7208  	)
  7209  	root.SetResourceInstanceCurrent(
  7210  		mustResourceInstanceAddr("aws_instance.bar[2]").Resource,
  7211  		bar,
  7212  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7213  	)
  7214  
  7215  	ctx := testContext2(t, &ContextOpts{
  7216  		Providers: map[addrs.Provider]providers.Factory{
  7217  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7218  		},
  7219  	})
  7220  
  7221  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7222  		Mode: plans.DestroyMode,
  7223  		Targets: []addrs.Targetable{
  7224  			addrs.RootModuleInstance.ResourceInstance(
  7225  				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(2),
  7226  			),
  7227  			addrs.RootModuleInstance.ResourceInstance(
  7228  				addrs.ManagedResourceMode, "aws_instance", "bar", addrs.IntKey(1),
  7229  			),
  7230  		},
  7231  	})
  7232  	assertNoErrors(t, diags)
  7233  
  7234  	state, diags = ctx.Apply(plan, m)
  7235  	if diags.HasErrors() {
  7236  		t.Fatalf("diags: %s", diags.Err())
  7237  	}
  7238  
  7239  	checkStateString(t, state, `
  7240  aws_instance.bar.0:
  7241    ID = i-abc123
  7242    provider = provider["registry.terraform.io/hashicorp/aws"]
  7243  aws_instance.bar.2:
  7244    ID = i-abc123
  7245    provider = provider["registry.terraform.io/hashicorp/aws"]
  7246  aws_instance.foo.0:
  7247    ID = i-bcd345
  7248    provider = provider["registry.terraform.io/hashicorp/aws"]
  7249  aws_instance.foo.1:
  7250    ID = i-bcd345
  7251    provider = provider["registry.terraform.io/hashicorp/aws"]
  7252  	`)
  7253  }
  7254  
  7255  func TestContext2Apply_targetedModule(t *testing.T) {
  7256  	m := testModule(t, "apply-targeted-module")
  7257  	p := testProvider("aws")
  7258  	p.PlanResourceChangeFn = testDiffFn
  7259  	p.ApplyResourceChangeFn = testApplyFn
  7260  	ctx := testContext2(t, &ContextOpts{
  7261  		Providers: map[addrs.Provider]providers.Factory{
  7262  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7263  		},
  7264  	})
  7265  
  7266  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7267  		Mode: plans.NormalMode,
  7268  		Targets: []addrs.Targetable{
  7269  			addrs.RootModuleInstance.Child("child", addrs.NoKey),
  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  	mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7280  	if mod == nil {
  7281  		t.Fatalf("no child module found in the state!\n\n%#v", state)
  7282  	}
  7283  	if len(mod.Resources) != 2 {
  7284  		t.Fatalf("expected 2 resources, got: %#v", mod.Resources)
  7285  	}
  7286  
  7287  	checkStateString(t, state, `
  7288  <no state>
  7289  module.child:
  7290    aws_instance.bar:
  7291      ID = foo
  7292      provider = provider["registry.terraform.io/hashicorp/aws"]
  7293      num = 2
  7294      type = aws_instance
  7295    aws_instance.foo:
  7296      ID = foo
  7297      provider = provider["registry.terraform.io/hashicorp/aws"]
  7298      num = 2
  7299      type = aws_instance
  7300  	`)
  7301  }
  7302  
  7303  // GH-1858
  7304  func TestContext2Apply_targetedModuleDep(t *testing.T) {
  7305  	m := testModule(t, "apply-targeted-module-dep")
  7306  	p := testProvider("aws")
  7307  	p.PlanResourceChangeFn = testDiffFn
  7308  	p.ApplyResourceChangeFn = testApplyFn
  7309  	ctx := testContext2(t, &ContextOpts{
  7310  		Providers: map[addrs.Provider]providers.Factory{
  7311  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7312  		},
  7313  	})
  7314  
  7315  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7316  		Mode: plans.NormalMode,
  7317  		Targets: []addrs.Targetable{
  7318  			addrs.RootModuleInstance.Resource(
  7319  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7320  			),
  7321  		},
  7322  	})
  7323  	if diags.HasErrors() {
  7324  		t.Fatalf("diags: %s", diags.Err())
  7325  	} else {
  7326  		t.Logf("Diff: %s", legacyDiffComparisonString(plan.Changes))
  7327  	}
  7328  
  7329  	state, diags := ctx.Apply(plan, m)
  7330  	if diags.HasErrors() {
  7331  		t.Fatalf("diags: %s", diags.Err())
  7332  	}
  7333  
  7334  	checkStateString(t, state, `
  7335  aws_instance.foo:
  7336    ID = foo
  7337    provider = provider["registry.terraform.io/hashicorp/aws"]
  7338    foo = foo
  7339    type = aws_instance
  7340  
  7341    Dependencies:
  7342      module.child.aws_instance.mod
  7343  
  7344  module.child:
  7345    aws_instance.mod:
  7346      ID = foo
  7347      provider = provider["registry.terraform.io/hashicorp/aws"]
  7348      type = aws_instance
  7349  
  7350    Outputs:
  7351  
  7352    output = foo
  7353  	`)
  7354  }
  7355  
  7356  // GH-10911 untargeted outputs should not be in the graph, and therefore
  7357  // not execute.
  7358  func TestContext2Apply_targetedModuleUnrelatedOutputs(t *testing.T) {
  7359  	m := testModule(t, "apply-targeted-module-unrelated-outputs")
  7360  	p := testProvider("aws")
  7361  	p.PlanResourceChangeFn = testDiffFn
  7362  	p.ApplyResourceChangeFn = testApplyFn
  7363  
  7364  	state := states.NewState()
  7365  	_ = state.EnsureModule(addrs.RootModuleInstance.Child("child2", addrs.NoKey))
  7366  
  7367  	ctx := testContext2(t, &ContextOpts{
  7368  		Providers: map[addrs.Provider]providers.Factory{
  7369  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7370  		},
  7371  	})
  7372  
  7373  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7374  		Mode: plans.NormalMode,
  7375  		Targets: []addrs.Targetable{
  7376  			addrs.RootModuleInstance.Child("child2", addrs.NoKey),
  7377  		},
  7378  	})
  7379  	assertNoErrors(t, diags)
  7380  
  7381  	s, diags := ctx.Apply(plan, m)
  7382  	if diags.HasErrors() {
  7383  		t.Fatalf("diags: %s", diags.Err())
  7384  	}
  7385  
  7386  	// - module.child1's instance_id output is dropped because we don't preserve
  7387  	//   non-root module outputs between runs (they can be recalculated from config)
  7388  	// - module.child2's instance_id is updated because its dependency is updated
  7389  	// - child2_id is updated because if its transitive dependency via module.child2
  7390  	checkStateString(t, s, `
  7391  <no state>
  7392  Outputs:
  7393  
  7394  child2_id = foo
  7395  
  7396  module.child2:
  7397    aws_instance.foo:
  7398      ID = foo
  7399      provider = provider["registry.terraform.io/hashicorp/aws"]
  7400      type = aws_instance
  7401  
  7402    Outputs:
  7403  
  7404    instance_id = foo
  7405  `)
  7406  }
  7407  
  7408  func TestContext2Apply_targetedModuleResource(t *testing.T) {
  7409  	m := testModule(t, "apply-targeted-module-resource")
  7410  	p := testProvider("aws")
  7411  	p.PlanResourceChangeFn = testDiffFn
  7412  	p.ApplyResourceChangeFn = testApplyFn
  7413  	ctx := testContext2(t, &ContextOpts{
  7414  		Providers: map[addrs.Provider]providers.Factory{
  7415  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7416  		},
  7417  	})
  7418  
  7419  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7420  		Mode: plans.NormalMode,
  7421  		Targets: []addrs.Targetable{
  7422  			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
  7423  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7424  			),
  7425  		},
  7426  	})
  7427  	assertNoErrors(t, diags)
  7428  
  7429  	state, diags := ctx.Apply(plan, m)
  7430  	if diags.HasErrors() {
  7431  		t.Fatalf("diags: %s", diags.Err())
  7432  	}
  7433  
  7434  	mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7435  	if mod == nil || len(mod.Resources) != 1 {
  7436  		t.Fatalf("expected 1 resource, got: %#v", mod)
  7437  	}
  7438  
  7439  	checkStateString(t, state, `
  7440  <no state>
  7441  module.child:
  7442    aws_instance.foo:
  7443      ID = foo
  7444      provider = provider["registry.terraform.io/hashicorp/aws"]
  7445      num = 2
  7446      type = aws_instance
  7447  	`)
  7448  }
  7449  
  7450  func TestContext2Apply_targetedResourceOrphanModule(t *testing.T) {
  7451  	m := testModule(t, "apply-targeted-resource-orphan-module")
  7452  	p := testProvider("aws")
  7453  	p.PlanResourceChangeFn = testDiffFn
  7454  
  7455  	state := states.NewState()
  7456  	child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey))
  7457  	child.SetResourceInstanceCurrent(
  7458  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7459  		&states.ResourceInstanceObjectSrc{
  7460  			Status:    states.ObjectReady,
  7461  			AttrsJSON: []byte(`{"type":"aws_instance"}`),
  7462  		},
  7463  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7464  	)
  7465  
  7466  	ctx := testContext2(t, &ContextOpts{
  7467  		Providers: map[addrs.Provider]providers.Factory{
  7468  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7469  		},
  7470  	})
  7471  
  7472  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7473  		Mode: plans.NormalMode,
  7474  		Targets: []addrs.Targetable{
  7475  			addrs.RootModuleInstance.Resource(
  7476  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7477  			),
  7478  		},
  7479  	})
  7480  	assertNoErrors(t, diags)
  7481  
  7482  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  7483  		t.Fatalf("apply errors: %s", diags.Err())
  7484  	}
  7485  }
  7486  
  7487  func TestContext2Apply_unknownAttribute(t *testing.T) {
  7488  	m := testModule(t, "apply-unknown")
  7489  	p := testProvider("aws")
  7490  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  7491  		resp = testDiffFn(req)
  7492  		planned := resp.PlannedState.AsValueMap()
  7493  		planned["unknown"] = cty.UnknownVal(cty.String)
  7494  		resp.PlannedState = cty.ObjectVal(planned)
  7495  		return resp
  7496  	}
  7497  	p.ApplyResourceChangeFn = testApplyFn
  7498  
  7499  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  7500  		ResourceTypes: map[string]*configschema.Block{
  7501  			"aws_instance": {
  7502  				Attributes: map[string]*configschema.Attribute{
  7503  					"id":      {Type: cty.String, Computed: true},
  7504  					"num":     {Type: cty.Number, Optional: true},
  7505  					"unknown": {Type: cty.String, Computed: true},
  7506  					"type":    {Type: cty.String, Computed: true},
  7507  				},
  7508  			},
  7509  		},
  7510  	})
  7511  
  7512  	ctx := testContext2(t, &ContextOpts{
  7513  		Providers: map[addrs.Provider]providers.Factory{
  7514  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7515  		},
  7516  	})
  7517  
  7518  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  7519  	assertNoErrors(t, diags)
  7520  
  7521  	state, diags := ctx.Apply(plan, m)
  7522  	if !diags.HasErrors() {
  7523  		t.Error("should error, because attribute 'unknown' is still unknown after apply")
  7524  	}
  7525  
  7526  	actual := strings.TrimSpace(state.String())
  7527  	expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr)
  7528  	if actual != expected {
  7529  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  7530  	}
  7531  }
  7532  
  7533  func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) {
  7534  	m := testModule(t, "apply-unknown-interpolate")
  7535  	p := testProvider("aws")
  7536  	p.PlanResourceChangeFn = testDiffFn
  7537  	ctx := testContext2(t, &ContextOpts{
  7538  		Providers: map[addrs.Provider]providers.Factory{
  7539  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7540  		},
  7541  	})
  7542  
  7543  	if _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts); diags == nil {
  7544  		t.Fatal("should error")
  7545  	}
  7546  }
  7547  
  7548  func TestContext2Apply_vars(t *testing.T) {
  7549  	fixture := contextFixtureApplyVars(t)
  7550  	opts := fixture.ContextOpts()
  7551  	ctx := testContext2(t, opts)
  7552  	m := fixture.Config
  7553  
  7554  	diags := ctx.Validate(m)
  7555  	if len(diags) != 0 {
  7556  		t.Fatalf("bad: %s", diags.ErrWithWarnings())
  7557  	}
  7558  
  7559  	variables := InputValues{
  7560  		"foo": &InputValue{
  7561  			Value:      cty.StringVal("us-east-1"),
  7562  			SourceType: ValueFromCaller,
  7563  		},
  7564  		"test_list": &InputValue{
  7565  			Value: cty.ListVal([]cty.Value{
  7566  				cty.StringVal("Hello"),
  7567  				cty.StringVal("World"),
  7568  			}),
  7569  			SourceType: ValueFromCaller,
  7570  		},
  7571  		"test_map": &InputValue{
  7572  			Value: cty.MapVal(map[string]cty.Value{
  7573  				"Hello": cty.StringVal("World"),
  7574  				"Foo":   cty.StringVal("Bar"),
  7575  				"Baz":   cty.StringVal("Foo"),
  7576  			}),
  7577  			SourceType: ValueFromCaller,
  7578  		},
  7579  		"amis": &InputValue{
  7580  			Value: cty.MapVal(map[string]cty.Value{
  7581  				"us-east-1": cty.StringVal("override"),
  7582  			}),
  7583  			SourceType: ValueFromCaller,
  7584  		},
  7585  	}
  7586  
  7587  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7588  		Mode:         plans.NormalMode,
  7589  		SetVariables: variables,
  7590  	})
  7591  	assertNoErrors(t, diags)
  7592  
  7593  	state, diags := ctx.Apply(plan, m)
  7594  	if diags.HasErrors() {
  7595  		t.Fatalf("err: %s", diags.Err())
  7596  	}
  7597  
  7598  	got := strings.TrimSpace(state.String())
  7599  	want := strings.TrimSpace(testTerraformApplyVarsStr)
  7600  	if got != want {
  7601  		t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want)
  7602  	}
  7603  }
  7604  
  7605  func TestContext2Apply_varsEnv(t *testing.T) {
  7606  	fixture := contextFixtureApplyVarsEnv(t)
  7607  	opts := fixture.ContextOpts()
  7608  	ctx := testContext2(t, opts)
  7609  	m := fixture.Config
  7610  
  7611  	diags := ctx.Validate(m)
  7612  	if len(diags) != 0 {
  7613  		t.Fatalf("bad: %s", diags.ErrWithWarnings())
  7614  	}
  7615  
  7616  	variables := InputValues{
  7617  		"string": &InputValue{
  7618  			Value:      cty.StringVal("baz"),
  7619  			SourceType: ValueFromEnvVar,
  7620  		},
  7621  		"list": &InputValue{
  7622  			Value: cty.ListVal([]cty.Value{
  7623  				cty.StringVal("Hello"),
  7624  				cty.StringVal("World"),
  7625  			}),
  7626  			SourceType: ValueFromEnvVar,
  7627  		},
  7628  		"map": &InputValue{
  7629  			Value: cty.MapVal(map[string]cty.Value{
  7630  				"Hello": cty.StringVal("World"),
  7631  				"Foo":   cty.StringVal("Bar"),
  7632  				"Baz":   cty.StringVal("Foo"),
  7633  			}),
  7634  			SourceType: ValueFromEnvVar,
  7635  		},
  7636  	}
  7637  
  7638  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7639  		Mode:         plans.NormalMode,
  7640  		SetVariables: variables,
  7641  	})
  7642  	assertNoErrors(t, diags)
  7643  
  7644  	state, diags := ctx.Apply(plan, m)
  7645  	if diags.HasErrors() {
  7646  		t.Fatalf("err: %s", diags.Err())
  7647  	}
  7648  
  7649  	actual := strings.TrimSpace(state.String())
  7650  	expected := strings.TrimSpace(testTerraformApplyVarsEnvStr)
  7651  	if actual != expected {
  7652  		t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  7653  	}
  7654  }
  7655  
  7656  func TestContext2Apply_createBefore_depends(t *testing.T) {
  7657  	m := testModule(t, "apply-depends-create-before")
  7658  	h := new(HookRecordApplyOrder)
  7659  	p := testProvider("aws")
  7660  	p.PlanResourceChangeFn = testDiffFn
  7661  	p.ApplyResourceChangeFn = testApplyFn
  7662  	state := states.NewState()
  7663  	root := state.EnsureModule(addrs.RootModuleInstance)
  7664  	root.SetResourceInstanceCurrent(
  7665  		addrs.Resource{
  7666  			Mode: addrs.ManagedResourceMode,
  7667  			Type: "aws_instance",
  7668  			Name: "web",
  7669  		}.Instance(addrs.NoKey),
  7670  		&states.ResourceInstanceObjectSrc{
  7671  			Status:    states.ObjectReady,
  7672  			AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`),
  7673  		},
  7674  		addrs.AbsProviderConfig{
  7675  			Provider: addrs.NewDefaultProvider("aws"),
  7676  			Module:   addrs.RootModule,
  7677  		},
  7678  	)
  7679  
  7680  	root.SetResourceInstanceCurrent(
  7681  		addrs.Resource{
  7682  			Mode: addrs.ManagedResourceMode,
  7683  			Type: "aws_instance",
  7684  			Name: "lb",
  7685  		}.Instance(addrs.NoKey),
  7686  		&states.ResourceInstanceObjectSrc{
  7687  			Status:    states.ObjectReady,
  7688  			AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`),
  7689  			Dependencies: []addrs.ConfigResource{
  7690  				{
  7691  					Resource: addrs.Resource{
  7692  						Mode: addrs.ManagedResourceMode,
  7693  						Type: "aws_instance",
  7694  						Name: "web",
  7695  					},
  7696  					Module: addrs.RootModule,
  7697  				},
  7698  			},
  7699  		},
  7700  		addrs.AbsProviderConfig{
  7701  			Provider: addrs.NewDefaultProvider("aws"),
  7702  			Module:   addrs.RootModule,
  7703  		},
  7704  	)
  7705  
  7706  	ctx := testContext2(t, &ContextOpts{
  7707  		Hooks: []Hook{h},
  7708  		Providers: map[addrs.Provider]providers.Factory{
  7709  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7710  		},
  7711  	})
  7712  
  7713  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  7714  	if diags.HasErrors() {
  7715  		logDiagnostics(t, diags)
  7716  		t.Fatal("plan failed")
  7717  	} else {
  7718  		t.Logf("plan:\n%s", legacyDiffComparisonString(plan.Changes))
  7719  	}
  7720  
  7721  	h.Active = true
  7722  	state, diags = ctx.Apply(plan, m)
  7723  	if diags.HasErrors() {
  7724  		logDiagnostics(t, diags)
  7725  		t.Fatal("apply failed")
  7726  	}
  7727  
  7728  	mod := state.RootModule()
  7729  	if len(mod.Resources) < 2 {
  7730  		t.Logf("state after apply:\n%s", state.String())
  7731  		t.Fatalf("only %d resources in root module; want at least 2", len(mod.Resources))
  7732  	}
  7733  
  7734  	got := strings.TrimSpace(state.String())
  7735  	want := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr)
  7736  	if got != want {
  7737  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", got, want)
  7738  	}
  7739  
  7740  	// Test that things were managed _in the right order_
  7741  	order := h.States
  7742  
  7743  	diffs := h.Diffs
  7744  	if !order[0].IsNull() || diffs[0].Action == plans.Delete {
  7745  		t.Fatalf("should create new instance first: %#v", order)
  7746  	}
  7747  
  7748  	if order[1].GetAttr("id").AsString() != "baz" {
  7749  		t.Fatalf("update must happen after create: %#v", order[1])
  7750  	}
  7751  
  7752  	if order[2].GetAttr("id").AsString() != "bar" || diffs[2].Action != plans.Delete {
  7753  		t.Fatalf("destroy must happen after update: %#v", order[2])
  7754  	}
  7755  }
  7756  
  7757  func TestContext2Apply_singleDestroy(t *testing.T) {
  7758  	m := testModule(t, "apply-depends-create-before")
  7759  	h := new(HookRecordApplyOrder)
  7760  	p := testProvider("aws")
  7761  	invokeCount := 0
  7762  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  7763  		invokeCount++
  7764  		switch invokeCount {
  7765  		case 1:
  7766  			if req.PlannedState.IsNull() {
  7767  				t.Fatalf("should not destroy")
  7768  			}
  7769  			if id := req.PlannedState.GetAttr("id"); id.IsKnown() {
  7770  				t.Fatalf("should not have ID")
  7771  			}
  7772  		case 2:
  7773  			if req.PlannedState.IsNull() {
  7774  				t.Fatalf("should not destroy")
  7775  			}
  7776  			if id := req.PlannedState.GetAttr("id"); id.AsString() != "baz" {
  7777  				t.Fatalf("should have id")
  7778  			}
  7779  		case 3:
  7780  			if !req.PlannedState.IsNull() {
  7781  				t.Fatalf("should destroy")
  7782  			}
  7783  		default:
  7784  			t.Fatalf("bad invoke count %d", invokeCount)
  7785  		}
  7786  		return testApplyFn(req)
  7787  	}
  7788  
  7789  	p.PlanResourceChangeFn = testDiffFn
  7790  	state := states.NewState()
  7791  	root := state.EnsureModule(addrs.RootModuleInstance)
  7792  	root.SetResourceInstanceCurrent(
  7793  		addrs.Resource{
  7794  			Mode: addrs.ManagedResourceMode,
  7795  			Type: "aws_instance",
  7796  			Name: "web",
  7797  		}.Instance(addrs.NoKey),
  7798  		&states.ResourceInstanceObjectSrc{
  7799  			Status:    states.ObjectReady,
  7800  			AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`),
  7801  		},
  7802  		addrs.AbsProviderConfig{
  7803  			Provider: addrs.NewDefaultProvider("aws"),
  7804  			Module:   addrs.RootModule,
  7805  		},
  7806  	)
  7807  
  7808  	root.SetResourceInstanceCurrent(
  7809  		addrs.Resource{
  7810  			Mode: addrs.ManagedResourceMode,
  7811  			Type: "aws_instance",
  7812  			Name: "lb",
  7813  		}.Instance(addrs.NoKey),
  7814  		&states.ResourceInstanceObjectSrc{
  7815  			Status:    states.ObjectReady,
  7816  			AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`),
  7817  			Dependencies: []addrs.ConfigResource{
  7818  				{
  7819  					Resource: addrs.Resource{
  7820  						Mode: addrs.ManagedResourceMode,
  7821  						Type: "aws_instance",
  7822  						Name: "web",
  7823  					},
  7824  					Module: addrs.RootModule,
  7825  				},
  7826  			},
  7827  		},
  7828  		addrs.AbsProviderConfig{
  7829  			Provider: addrs.NewDefaultProvider("aws"),
  7830  			Module:   addrs.RootModule,
  7831  		},
  7832  	)
  7833  
  7834  	ctx := testContext2(t, &ContextOpts{
  7835  		Hooks: []Hook{h},
  7836  		Providers: map[addrs.Provider]providers.Factory{
  7837  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7838  		},
  7839  	})
  7840  
  7841  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  7842  	assertNoErrors(t, diags)
  7843  
  7844  	h.Active = true
  7845  	_, diags = ctx.Apply(plan, m)
  7846  	if diags.HasErrors() {
  7847  		t.Fatalf("diags: %s", diags.Err())
  7848  	}
  7849  
  7850  	if invokeCount != 3 {
  7851  		t.Fatalf("bad: %d", invokeCount)
  7852  	}
  7853  }
  7854  
  7855  // GH-7824
  7856  func TestContext2Apply_issue7824(t *testing.T) {
  7857  	p := testProvider("template")
  7858  	p.PlanResourceChangeFn = testDiffFn
  7859  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  7860  		ResourceTypes: map[string]*configschema.Block{
  7861  			"template_file": {
  7862  				Attributes: map[string]*configschema.Attribute{
  7863  					"template":                {Type: cty.String, Optional: true},
  7864  					"__template_requires_new": {Type: cty.Bool, Optional: true},
  7865  				},
  7866  			},
  7867  		},
  7868  	})
  7869  
  7870  	m, snap := testModuleWithSnapshot(t, "issue-7824")
  7871  
  7872  	// Apply cleanly step 0
  7873  	ctx := testContext2(t, &ContextOpts{
  7874  		Providers: map[addrs.Provider]providers.Factory{
  7875  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7876  		},
  7877  	})
  7878  
  7879  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  7880  	if diags.HasErrors() {
  7881  		t.Fatalf("err: %s", diags.Err())
  7882  	}
  7883  
  7884  	// Write / Read plan to simulate running it through a Plan file
  7885  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  7886  	if err != nil {
  7887  		t.Fatalf("failed to round-trip through planfile: %s", err)
  7888  	}
  7889  
  7890  	ctxOpts.Providers =
  7891  		map[addrs.Provider]providers.Factory{
  7892  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7893  		}
  7894  
  7895  	ctx, diags = NewContext(ctxOpts)
  7896  	if diags.HasErrors() {
  7897  		t.Fatalf("err: %s", diags.Err())
  7898  	}
  7899  
  7900  	_, diags = ctx.Apply(plan, m)
  7901  	if diags.HasErrors() {
  7902  		t.Fatalf("err: %s", diags.Err())
  7903  	}
  7904  }
  7905  
  7906  // This deals with the situation where a splat expression is used referring
  7907  // to another resource whose count is non-constant.
  7908  func TestContext2Apply_issue5254(t *testing.T) {
  7909  	// Create a provider. We use "template" here just to match the repro
  7910  	// we got from the issue itself.
  7911  	p := testProvider("template")
  7912  	p.PlanResourceChangeFn = testDiffFn
  7913  	p.ApplyResourceChangeFn = testApplyFn
  7914  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  7915  		ResourceTypes: map[string]*configschema.Block{
  7916  			"template_file": {
  7917  				Attributes: map[string]*configschema.Attribute{
  7918  					"template":                {Type: cty.String, Optional: true},
  7919  					"__template_requires_new": {Type: cty.Bool, Optional: true},
  7920  					"id":                      {Type: cty.String, Computed: true},
  7921  					"type":                    {Type: cty.String, Computed: true},
  7922  				},
  7923  			},
  7924  		},
  7925  	})
  7926  
  7927  	// Apply cleanly step 0
  7928  	m := testModule(t, "issue-5254/step-0")
  7929  	ctx := testContext2(t, &ContextOpts{
  7930  		Providers: map[addrs.Provider]providers.Factory{
  7931  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7932  		},
  7933  	})
  7934  
  7935  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  7936  	if diags.HasErrors() {
  7937  		t.Fatalf("err: %s", diags.Err())
  7938  	}
  7939  
  7940  	state, diags := ctx.Apply(plan, m)
  7941  	if diags.HasErrors() {
  7942  		t.Fatalf("err: %s", diags.Err())
  7943  	}
  7944  
  7945  	m, snap := testModuleWithSnapshot(t, "issue-5254/step-1")
  7946  
  7947  	// Application success. Now make the modification and store a plan
  7948  	ctx = testContext2(t, &ContextOpts{
  7949  		Providers: map[addrs.Provider]providers.Factory{
  7950  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7951  		},
  7952  	})
  7953  
  7954  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  7955  	if diags.HasErrors() {
  7956  		t.Fatalf("err: %s", diags.Err())
  7957  	}
  7958  
  7959  	// Write / Read plan to simulate running it through a Plan file
  7960  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  7961  	if err != nil {
  7962  		t.Fatalf("failed to round-trip through planfile: %s", err)
  7963  	}
  7964  
  7965  	ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  7966  		addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7967  	}
  7968  
  7969  	ctx, diags = NewContext(ctxOpts)
  7970  	if diags.HasErrors() {
  7971  		t.Fatalf("err: %s", diags.Err())
  7972  	}
  7973  
  7974  	state, diags = ctx.Apply(plan, m)
  7975  	if diags.HasErrors() {
  7976  		t.Fatalf("err: %s", diags.Err())
  7977  	}
  7978  
  7979  	actual := strings.TrimSpace(state.String())
  7980  	expected := strings.TrimSpace(`
  7981  template_file.child:
  7982    ID = foo
  7983    provider = provider["registry.terraform.io/hashicorp/template"]
  7984    __template_requires_new = true
  7985    template = Hi
  7986    type = template_file
  7987  
  7988    Dependencies:
  7989      template_file.parent
  7990  template_file.parent.0:
  7991    ID = foo
  7992    provider = provider["registry.terraform.io/hashicorp/template"]
  7993    template = Hi
  7994    type = template_file
  7995  `)
  7996  	if actual != expected {
  7997  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected)
  7998  	}
  7999  }
  8000  
  8001  func TestContext2Apply_targetedWithTaintedInState(t *testing.T) {
  8002  	p := testProvider("aws")
  8003  	p.PlanResourceChangeFn = testDiffFn
  8004  	p.ApplyResourceChangeFn = testApplyFn
  8005  	m, snap := testModuleWithSnapshot(t, "apply-tainted-targets")
  8006  
  8007  	state := states.NewState()
  8008  	root := state.EnsureModule(addrs.RootModuleInstance)
  8009  	root.SetResourceInstanceCurrent(
  8010  		mustResourceInstanceAddr("aws_instance.ifailedprovisioners").Resource,
  8011  		&states.ResourceInstanceObjectSrc{
  8012  			Status:    states.ObjectTainted,
  8013  			AttrsJSON: []byte(`{"id":"ifailedprovisioners"}`),
  8014  		},
  8015  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8016  	)
  8017  
  8018  	ctx := testContext2(t, &ContextOpts{
  8019  		Providers: map[addrs.Provider]providers.Factory{
  8020  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8021  		},
  8022  	})
  8023  
  8024  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8025  		Mode: plans.NormalMode,
  8026  		Targets: []addrs.Targetable{
  8027  			addrs.RootModuleInstance.Resource(
  8028  				addrs.ManagedResourceMode, "aws_instance", "iambeingadded",
  8029  			),
  8030  		},
  8031  	})
  8032  	if diags.HasErrors() {
  8033  		t.Fatalf("err: %s", diags.Err())
  8034  	}
  8035  
  8036  	// Write / Read plan to simulate running it through a Plan file
  8037  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  8038  	if err != nil {
  8039  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8040  	}
  8041  
  8042  	ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  8043  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8044  	}
  8045  
  8046  	ctx, diags = NewContext(ctxOpts)
  8047  	if diags.HasErrors() {
  8048  		t.Fatalf("err: %s", diags.Err())
  8049  	}
  8050  
  8051  	s, diags := ctx.Apply(plan, m)
  8052  	if diags.HasErrors() {
  8053  		t.Fatalf("err: %s", diags.Err())
  8054  	}
  8055  
  8056  	actual := strings.TrimSpace(s.String())
  8057  	expected := strings.TrimSpace(`
  8058  aws_instance.iambeingadded:
  8059    ID = foo
  8060    provider = provider["registry.terraform.io/hashicorp/aws"]
  8061    type = aws_instance
  8062  aws_instance.ifailedprovisioners: (tainted)
  8063    ID = ifailedprovisioners
  8064    provider = provider["registry.terraform.io/hashicorp/aws"]
  8065  		`)
  8066  	if actual != expected {
  8067  		t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual)
  8068  	}
  8069  }
  8070  
  8071  // Higher level test exposing the bug this covers in
  8072  // TestResource_ignoreChangesRequired
  8073  func TestContext2Apply_ignoreChangesCreate(t *testing.T) {
  8074  	m := testModule(t, "apply-ignore-changes-create")
  8075  	p := testProvider("aws")
  8076  	p.PlanResourceChangeFn = testDiffFn
  8077  	p.ApplyResourceChangeFn = testApplyFn
  8078  
  8079  	instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  8080  	instanceSchema.Attributes["required_field"] = &configschema.Attribute{
  8081  		Type:     cty.String,
  8082  		Required: true,
  8083  	}
  8084  
  8085  	ctx := testContext2(t, &ContextOpts{
  8086  		Providers: map[addrs.Provider]providers.Factory{
  8087  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8088  		},
  8089  	})
  8090  
  8091  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8092  	if diags.HasErrors() {
  8093  		t.Fatalf("diags: %s", diags.Err())
  8094  	} else {
  8095  		t.Logf(legacyDiffComparisonString(plan.Changes))
  8096  	}
  8097  
  8098  	state, diags := ctx.Apply(plan, m)
  8099  	if diags.HasErrors() {
  8100  		t.Fatalf("diags: %s", diags.Err())
  8101  	}
  8102  
  8103  	mod := state.RootModule()
  8104  	if len(mod.Resources) != 1 {
  8105  		t.Fatalf("bad: %s", state)
  8106  	}
  8107  
  8108  	actual := strings.TrimSpace(state.String())
  8109  	// Expect no changes from original state
  8110  	expected := strings.TrimSpace(`
  8111  aws_instance.foo:
  8112    ID = foo
  8113    provider = provider["registry.terraform.io/hashicorp/aws"]
  8114    required_field = set
  8115    type = aws_instance
  8116  `)
  8117  	if actual != expected {
  8118  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
  8119  	}
  8120  }
  8121  
  8122  func TestContext2Apply_ignoreChangesWithDep(t *testing.T) {
  8123  	m := testModule(t, "apply-ignore-changes-dep")
  8124  	p := testProvider("aws")
  8125  
  8126  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  8127  		resp.PlannedState = req.ProposedNewState
  8128  
  8129  		switch req.TypeName {
  8130  		case "aws_instance":
  8131  			resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: "ami"}})
  8132  		case "aws_eip":
  8133  			return testDiffFn(req)
  8134  		default:
  8135  			t.Fatalf("Unexpected type: %s", req.TypeName)
  8136  		}
  8137  		return
  8138  	}
  8139  
  8140  	state := states.NewState()
  8141  	root := state.EnsureModule(addrs.RootModuleInstance)
  8142  	root.SetResourceInstanceCurrent(
  8143  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  8144  		&states.ResourceInstanceObjectSrc{
  8145  			Status:    states.ObjectReady,
  8146  			AttrsJSON: []byte(`{"id":"i-abc123","ami":"ami-abcd1234"}`),
  8147  		},
  8148  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8149  	)
  8150  	root.SetResourceInstanceCurrent(
  8151  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  8152  		&states.ResourceInstanceObjectSrc{
  8153  			Status:    states.ObjectReady,
  8154  			AttrsJSON: []byte(`{"id":"i-bcd234","ami":"i-bcd234"}`),
  8155  		},
  8156  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8157  	)
  8158  	root.SetResourceInstanceCurrent(
  8159  		mustResourceInstanceAddr("aws_eip.foo[0]").Resource,
  8160  		&states.ResourceInstanceObjectSrc{
  8161  			Status:    states.ObjectReady,
  8162  			AttrsJSON: []byte(`{"id":"eip-abc123","instance":"i-abc123"}`),
  8163  			Dependencies: []addrs.ConfigResource{
  8164  				{
  8165  					Resource: addrs.Resource{
  8166  						Mode: addrs.ManagedResourceMode,
  8167  						Type: "aws_instance",
  8168  						Name: "foo",
  8169  					},
  8170  					Module: addrs.RootModule,
  8171  				},
  8172  			},
  8173  		},
  8174  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8175  	)
  8176  	root.SetResourceInstanceCurrent(
  8177  		mustResourceInstanceAddr("aws_eip.foo[1]").Resource,
  8178  		&states.ResourceInstanceObjectSrc{
  8179  			Status:    states.ObjectReady,
  8180  			AttrsJSON: []byte(`{"id":"eip-bcd234","instance":"i-bcd234"}`),
  8181  			Dependencies: []addrs.ConfigResource{
  8182  				{
  8183  					Resource: addrs.Resource{
  8184  						Mode: addrs.ManagedResourceMode,
  8185  						Type: "aws_instance",
  8186  						Name: "foo",
  8187  					},
  8188  					Module: addrs.RootModule,
  8189  				},
  8190  			},
  8191  		},
  8192  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8193  	)
  8194  
  8195  	ctx := testContext2(t, &ContextOpts{
  8196  		Providers: map[addrs.Provider]providers.Factory{
  8197  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8198  		},
  8199  	})
  8200  
  8201  	plan, diags := ctx.Plan(m, state.DeepCopy(), DefaultPlanOpts)
  8202  	assertNoErrors(t, diags)
  8203  
  8204  	s, diags := ctx.Apply(plan, m)
  8205  	assertNoErrors(t, diags)
  8206  
  8207  	actual := strings.TrimSpace(s.String())
  8208  	expected := strings.TrimSpace(state.String())
  8209  	if actual != expected {
  8210  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  8211  	}
  8212  }
  8213  
  8214  func TestContext2Apply_ignoreChangesAll(t *testing.T) {
  8215  	m := testModule(t, "apply-ignore-changes-all")
  8216  	p := testProvider("aws")
  8217  	p.PlanResourceChangeFn = testDiffFn
  8218  	p.ApplyResourceChangeFn = testApplyFn
  8219  
  8220  	instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  8221  	instanceSchema.Attributes["required_field"] = &configschema.Attribute{
  8222  		Type:     cty.String,
  8223  		Required: true,
  8224  	}
  8225  
  8226  	ctx := testContext2(t, &ContextOpts{
  8227  		Providers: map[addrs.Provider]providers.Factory{
  8228  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8229  		},
  8230  	})
  8231  
  8232  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8233  	if diags.HasErrors() {
  8234  		logDiagnostics(t, diags)
  8235  		t.Fatal("plan failed")
  8236  	} else {
  8237  		t.Logf(legacyDiffComparisonString(plan.Changes))
  8238  	}
  8239  
  8240  	state, diags := ctx.Apply(plan, m)
  8241  	assertNoErrors(t, diags)
  8242  
  8243  	mod := state.RootModule()
  8244  	if len(mod.Resources) != 1 {
  8245  		t.Fatalf("bad: %s", state)
  8246  	}
  8247  
  8248  	actual := strings.TrimSpace(state.String())
  8249  	// Expect no changes from original state
  8250  	expected := strings.TrimSpace(`
  8251  aws_instance.foo:
  8252    ID = foo
  8253    provider = provider["registry.terraform.io/hashicorp/aws"]
  8254    required_field = set
  8255    type = aws_instance
  8256  `)
  8257  	if actual != expected {
  8258  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
  8259  	}
  8260  }
  8261  
  8262  // https://github.com/muratcelep/terraform/issues/7378
  8263  func TestContext2Apply_destroyNestedModuleWithAttrsReferencingResource(t *testing.T) {
  8264  	m, snap := testModuleWithSnapshot(t, "apply-destroy-nested-module-with-attrs")
  8265  	p := testProvider("null")
  8266  	p.PlanResourceChangeFn = testDiffFn
  8267  
  8268  	var state *states.State
  8269  	{
  8270  		ctx := testContext2(t, &ContextOpts{
  8271  			Providers: map[addrs.Provider]providers.Factory{
  8272  				addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8273  			},
  8274  		})
  8275  
  8276  		// First plan and apply a create operation
  8277  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8278  		assertNoErrors(t, diags)
  8279  
  8280  		state, diags = ctx.Apply(plan, m)
  8281  		if diags.HasErrors() {
  8282  			t.Fatalf("apply err: %s", diags.Err())
  8283  		}
  8284  	}
  8285  
  8286  	{
  8287  		ctx := testContext2(t, &ContextOpts{
  8288  			Providers: map[addrs.Provider]providers.Factory{
  8289  				addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8290  			},
  8291  		})
  8292  
  8293  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  8294  			Mode: plans.DestroyMode,
  8295  		})
  8296  		if diags.HasErrors() {
  8297  			t.Fatalf("destroy plan err: %s", diags.Err())
  8298  		}
  8299  
  8300  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  8301  		if err != nil {
  8302  			t.Fatalf("failed to round-trip through planfile: %s", err)
  8303  		}
  8304  
  8305  		ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  8306  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8307  		}
  8308  
  8309  		ctx, diags = NewContext(ctxOpts)
  8310  		if diags.HasErrors() {
  8311  			t.Fatalf("err: %s", diags.Err())
  8312  		}
  8313  
  8314  		state, diags = ctx.Apply(plan, m)
  8315  		if diags.HasErrors() {
  8316  			t.Fatalf("destroy apply err: %s", diags.Err())
  8317  		}
  8318  	}
  8319  
  8320  	if !state.Empty() {
  8321  		t.Fatalf("state after apply: %s\nwant empty state", spew.Sdump(state))
  8322  	}
  8323  }
  8324  
  8325  // If a data source explicitly depends on another resource, it's because we need
  8326  // that resource to be applied first.
  8327  func TestContext2Apply_dataDependsOn(t *testing.T) {
  8328  	p := testProvider("null")
  8329  	m := testModuleInline(t, map[string]string{
  8330  		"main.tf": `
  8331  resource "null_instance" "write" {
  8332    foo = "attribute"
  8333  }
  8334  
  8335  data "null_data_source" "read" {
  8336    count = 1
  8337    depends_on = ["null_instance.write"]
  8338  }
  8339  
  8340  resource "null_instance" "depends" {
  8341    foo = data.null_data_source.read[0].foo
  8342  }
  8343  `})
  8344  
  8345  	ctx := testContext2(t, &ContextOpts{
  8346  		Providers: map[addrs.Provider]providers.Factory{
  8347  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8348  		},
  8349  	})
  8350  
  8351  	// the "provisioner" here writes to this variable, because the intent is to
  8352  	// create a dependency which can't be viewed through the graph, and depends
  8353  	// solely on the configuration providing "depends_on"
  8354  	provisionerOutput := ""
  8355  
  8356  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  8357  		// the side effect of the resource being applied
  8358  		provisionerOutput = "APPLIED"
  8359  		return testApplyFn(req)
  8360  	}
  8361  
  8362  	p.PlanResourceChangeFn = testDiffFn
  8363  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  8364  		return providers.ReadDataSourceResponse{
  8365  			State: cty.ObjectVal(map[string]cty.Value{
  8366  				"id":  cty.StringVal("boop"),
  8367  				"foo": cty.StringVal(provisionerOutput),
  8368  			}),
  8369  		}
  8370  	}
  8371  
  8372  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8373  	assertNoErrors(t, diags)
  8374  
  8375  	state, diags := ctx.Apply(plan, m)
  8376  	assertNoErrors(t, diags)
  8377  
  8378  	root := state.Module(addrs.RootModuleInstance)
  8379  	is := root.ResourceInstance(addrs.Resource{
  8380  		Mode: addrs.DataResourceMode,
  8381  		Type: "null_data_source",
  8382  		Name: "read",
  8383  	}.Instance(addrs.IntKey(0)))
  8384  	if is == nil {
  8385  		t.Fatal("data resource instance is not present in state; should be")
  8386  	}
  8387  	var attrs map[string]interface{}
  8388  	err := json.Unmarshal(is.Current.AttrsJSON, &attrs)
  8389  	if err != nil {
  8390  		t.Fatal(err)
  8391  	}
  8392  	actual := attrs["foo"]
  8393  	expected := "APPLIED"
  8394  	if actual != expected {
  8395  		t.Fatalf("bad:\n%s", strings.TrimSpace(state.String()))
  8396  	}
  8397  
  8398  	// run another plan to make sure the data source doesn't show as a change
  8399  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  8400  	assertNoErrors(t, diags)
  8401  
  8402  	for _, c := range plan.Changes.Resources {
  8403  		if c.Action != plans.NoOp {
  8404  			t.Fatalf("unexpected change for %s", c.Addr)
  8405  		}
  8406  	}
  8407  
  8408  	// now we cause a change in the first resource, which should trigger a plan
  8409  	// in the data source, and the resource that depends on the data source
  8410  	// must plan a change as well.
  8411  	m = testModuleInline(t, map[string]string{
  8412  		"main.tf": `
  8413  resource "null_instance" "write" {
  8414    foo = "new"
  8415  }
  8416  
  8417  data "null_data_source" "read" {
  8418    depends_on = ["null_instance.write"]
  8419  }
  8420  
  8421  resource "null_instance" "depends" {
  8422    foo = data.null_data_source.read.foo
  8423  }
  8424  `})
  8425  
  8426  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  8427  		// the side effect of the resource being applied
  8428  		provisionerOutput = "APPLIED_AGAIN"
  8429  		return testApplyFn(req)
  8430  	}
  8431  
  8432  	ctx = testContext2(t, &ContextOpts{
  8433  		Providers: map[addrs.Provider]providers.Factory{
  8434  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8435  		},
  8436  	})
  8437  
  8438  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  8439  	assertNoErrors(t, diags)
  8440  
  8441  	expectedChanges := map[string]plans.Action{
  8442  		"null_instance.write":        plans.Update,
  8443  		"data.null_data_source.read": plans.Read,
  8444  		"null_instance.depends":      plans.Update,
  8445  	}
  8446  
  8447  	for _, c := range plan.Changes.Resources {
  8448  		if c.Action != expectedChanges[c.Addr.String()] {
  8449  			t.Errorf("unexpected %s for %s", c.Action, c.Addr)
  8450  		}
  8451  	}
  8452  }
  8453  
  8454  func TestContext2Apply_terraformWorkspace(t *testing.T) {
  8455  	m := testModule(t, "apply-terraform-workspace")
  8456  	p := testProvider("aws")
  8457  	p.PlanResourceChangeFn = testDiffFn
  8458  
  8459  	ctx := testContext2(t, &ContextOpts{
  8460  		Meta: &ContextMeta{Env: "foo"},
  8461  		Providers: map[addrs.Provider]providers.Factory{
  8462  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8463  		},
  8464  	})
  8465  
  8466  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8467  	assertNoErrors(t, diags)
  8468  
  8469  	state, diags := ctx.Apply(plan, m)
  8470  	if diags.HasErrors() {
  8471  		t.Fatalf("diags: %s", diags.Err())
  8472  	}
  8473  
  8474  	actual := state.RootModule().OutputValues["output"]
  8475  	expected := cty.StringVal("foo")
  8476  	if actual == nil || actual.Value != expected {
  8477  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  8478  	}
  8479  }
  8480  
  8481  // verify that multiple config references only create a single depends_on entry
  8482  func TestContext2Apply_multiRef(t *testing.T) {
  8483  	m := testModule(t, "apply-multi-ref")
  8484  	p := testProvider("aws")
  8485  	p.PlanResourceChangeFn = testDiffFn
  8486  	ctx := testContext2(t, &ContextOpts{
  8487  		Providers: map[addrs.Provider]providers.Factory{
  8488  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8489  		},
  8490  	})
  8491  
  8492  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8493  	assertNoErrors(t, diags)
  8494  
  8495  	state, diags := ctx.Apply(plan, m)
  8496  	if diags.HasErrors() {
  8497  		t.Fatalf("err: %s", diags.Err())
  8498  	}
  8499  
  8500  	deps := state.Modules[""].Resources["aws_instance.other"].Instances[addrs.NoKey].Current.Dependencies
  8501  	if len(deps) != 1 || deps[0].String() != "aws_instance.create" {
  8502  		t.Fatalf("expected 1 depends_on entry for aws_instance.create, got %q", deps)
  8503  	}
  8504  }
  8505  
  8506  func TestContext2Apply_targetedModuleRecursive(t *testing.T) {
  8507  	m := testModule(t, "apply-targeted-module-recursive")
  8508  	p := testProvider("aws")
  8509  	p.PlanResourceChangeFn = testDiffFn
  8510  	p.ApplyResourceChangeFn = testApplyFn
  8511  	ctx := testContext2(t, &ContextOpts{
  8512  		Providers: map[addrs.Provider]providers.Factory{
  8513  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8514  		},
  8515  	})
  8516  
  8517  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  8518  		Mode: plans.NormalMode,
  8519  		Targets: []addrs.Targetable{
  8520  			addrs.RootModuleInstance.Child("child", addrs.NoKey),
  8521  		},
  8522  	})
  8523  	assertNoErrors(t, diags)
  8524  
  8525  	state, diags := ctx.Apply(plan, m)
  8526  	if diags.HasErrors() {
  8527  		t.Fatalf("err: %s", diags.Err())
  8528  	}
  8529  
  8530  	mod := state.Module(
  8531  		addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("subchild", addrs.NoKey),
  8532  	)
  8533  	if mod == nil {
  8534  		t.Fatalf("no subchild module found in the state!\n\n%#v", state)
  8535  	}
  8536  	if len(mod.Resources) != 1 {
  8537  		t.Fatalf("expected 1 resources, got: %#v", mod.Resources)
  8538  	}
  8539  
  8540  	checkStateString(t, state, `
  8541  <no state>
  8542  module.child.subchild:
  8543    aws_instance.foo:
  8544      ID = foo
  8545      provider = provider["registry.terraform.io/hashicorp/aws"]
  8546      num = 2
  8547      type = aws_instance
  8548  	`)
  8549  }
  8550  
  8551  func TestContext2Apply_localVal(t *testing.T) {
  8552  	m := testModule(t, "apply-local-val")
  8553  	ctx := testContext2(t, &ContextOpts{
  8554  		Providers: map[addrs.Provider]providers.Factory{},
  8555  	})
  8556  
  8557  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8558  	assertNoErrors(t, diags)
  8559  
  8560  	state, diags := ctx.Apply(plan, m)
  8561  	if diags.HasErrors() {
  8562  		t.Fatalf("error during apply: %s", diags.Err())
  8563  	}
  8564  
  8565  	got := strings.TrimSpace(state.String())
  8566  	want := strings.TrimSpace(`
  8567  <no state>
  8568  Outputs:
  8569  
  8570  result_1 = hello
  8571  result_3 = hello world
  8572  `)
  8573  	if got != want {
  8574  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8575  	}
  8576  }
  8577  
  8578  func TestContext2Apply_destroyWithLocals(t *testing.T) {
  8579  	m := testModule(t, "apply-destroy-with-locals")
  8580  	p := testProvider("aws")
  8581  	p.PlanResourceChangeFn = testDiffFn
  8582  
  8583  	state := states.NewState()
  8584  	root := state.EnsureModule(addrs.RootModuleInstance)
  8585  	root.SetResourceInstanceCurrent(
  8586  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  8587  		&states.ResourceInstanceObjectSrc{
  8588  			Status:    states.ObjectReady,
  8589  			AttrsJSON: []byte(`{"id":"foo"}`),
  8590  		},
  8591  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8592  	)
  8593  	root.SetOutputValue("name", cty.StringVal("test-bar"), false)
  8594  
  8595  	ctx := testContext2(t, &ContextOpts{
  8596  		Providers: map[addrs.Provider]providers.Factory{
  8597  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8598  		},
  8599  	})
  8600  
  8601  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8602  		Mode: plans.DestroyMode,
  8603  	})
  8604  	assertNoErrors(t, diags)
  8605  
  8606  	s, diags := ctx.Apply(plan, m)
  8607  	if diags.HasErrors() {
  8608  		t.Fatalf("error during apply: %s", diags.Err())
  8609  	}
  8610  
  8611  	got := strings.TrimSpace(s.String())
  8612  	want := strings.TrimSpace(`<no state>`)
  8613  	if got != want {
  8614  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8615  	}
  8616  }
  8617  
  8618  func TestContext2Apply_providerWithLocals(t *testing.T) {
  8619  	m := testModule(t, "provider-with-locals")
  8620  	p := testProvider("aws")
  8621  
  8622  	providerRegion := ""
  8623  	// this should not be overridden during destroy
  8624  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  8625  		val := req.Config.GetAttr("region")
  8626  		if !val.IsNull() {
  8627  			providerRegion = val.AsString()
  8628  		}
  8629  
  8630  		return
  8631  	}
  8632  
  8633  	p.PlanResourceChangeFn = testDiffFn
  8634  	ctx := testContext2(t, &ContextOpts{
  8635  		Providers: map[addrs.Provider]providers.Factory{
  8636  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8637  		},
  8638  	})
  8639  
  8640  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8641  	assertNoErrors(t, diags)
  8642  
  8643  	state, diags := ctx.Apply(plan, m)
  8644  	if diags.HasErrors() {
  8645  		t.Fatalf("err: %s", diags.Err())
  8646  	}
  8647  
  8648  	ctx = testContext2(t, &ContextOpts{
  8649  		Providers: map[addrs.Provider]providers.Factory{
  8650  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8651  		},
  8652  	})
  8653  
  8654  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  8655  		Mode: plans.DestroyMode,
  8656  	})
  8657  	assertNoErrors(t, diags)
  8658  
  8659  	state, diags = ctx.Apply(plan, m)
  8660  	if diags.HasErrors() {
  8661  		t.Fatalf("err: %s", diags.Err())
  8662  	}
  8663  
  8664  	if state.HasManagedResourceInstanceObjects() {
  8665  		t.Fatal("expected no state, got:", state)
  8666  	}
  8667  
  8668  	if providerRegion != "bar" {
  8669  		t.Fatalf("expected region %q, got: %q", "bar", providerRegion)
  8670  	}
  8671  }
  8672  
  8673  func TestContext2Apply_destroyWithProviders(t *testing.T) {
  8674  	m := testModule(t, "destroy-module-with-provider")
  8675  	p := testProvider("aws")
  8676  	p.PlanResourceChangeFn = testDiffFn
  8677  
  8678  	state := states.NewState()
  8679  	removed := state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.NoKey).Child("removed", addrs.NoKey))
  8680  	removed.SetResourceInstanceCurrent(
  8681  		mustResourceInstanceAddr("aws_instance.child").Resource,
  8682  		&states.ResourceInstanceObjectSrc{
  8683  			Status:    states.ObjectReady,
  8684  			AttrsJSON: []byte(`{"id":"bar"}`),
  8685  		},
  8686  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].baz`),
  8687  	)
  8688  
  8689  	ctx := testContext2(t, &ContextOpts{
  8690  		Providers: map[addrs.Provider]providers.Factory{
  8691  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8692  		},
  8693  	})
  8694  
  8695  	// test that we can't destroy if the provider is missing
  8696  	if _, diags := ctx.Plan(m, state, &PlanOpts{Mode: plans.DestroyMode}); diags == nil {
  8697  		t.Fatal("expected plan error, provider.aws.baz doesn't exist")
  8698  	}
  8699  
  8700  	// correct the state
  8701  	state.Modules["module.mod.module.removed"].Resources["aws_instance.child"].ProviderConfig = mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].bar`)
  8702  
  8703  	ctx = testContext2(t, &ContextOpts{
  8704  		Providers: map[addrs.Provider]providers.Factory{
  8705  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8706  		},
  8707  	})
  8708  
  8709  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8710  		Mode: plans.DestroyMode,
  8711  	})
  8712  	assertNoErrors(t, diags)
  8713  
  8714  	state, diags = ctx.Apply(plan, m)
  8715  	if diags.HasErrors() {
  8716  		t.Fatalf("error during apply: %s", diags.Err())
  8717  	}
  8718  
  8719  	got := strings.TrimSpace(state.String())
  8720  
  8721  	want := strings.TrimSpace("<no state>")
  8722  	if got != want {
  8723  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8724  	}
  8725  }
  8726  
  8727  func TestContext2Apply_providersFromState(t *testing.T) {
  8728  	m := configs.NewEmptyConfig()
  8729  	p := testProvider("aws")
  8730  	p.PlanResourceChangeFn = testDiffFn
  8731  
  8732  	implicitProviderState := states.NewState()
  8733  	impRoot := implicitProviderState.EnsureModule(addrs.RootModuleInstance)
  8734  	impRoot.SetResourceInstanceCurrent(
  8735  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8736  		&states.ResourceInstanceObjectSrc{
  8737  			Status:    states.ObjectReady,
  8738  			AttrsJSON: []byte(`{"id":"bar"}`),
  8739  		},
  8740  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8741  	)
  8742  
  8743  	aliasedProviderState := states.NewState()
  8744  	aliasRoot := aliasedProviderState.EnsureModule(addrs.RootModuleInstance)
  8745  	aliasRoot.SetResourceInstanceCurrent(
  8746  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8747  		&states.ResourceInstanceObjectSrc{
  8748  			Status:    states.ObjectReady,
  8749  			AttrsJSON: []byte(`{"id":"bar"}`),
  8750  		},
  8751  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].bar`),
  8752  	)
  8753  
  8754  	moduleProviderState := states.NewState()
  8755  	moduleProviderRoot := moduleProviderState.EnsureModule(addrs.RootModuleInstance)
  8756  	moduleProviderRoot.SetResourceInstanceCurrent(
  8757  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8758  		&states.ResourceInstanceObjectSrc{
  8759  			Status:    states.ObjectReady,
  8760  			AttrsJSON: []byte(`{"id":"bar"}`),
  8761  		},
  8762  		mustProviderConfig(`module.child.provider["registry.terraform.io/hashicorp/aws"]`),
  8763  	)
  8764  
  8765  	for _, tc := range []struct {
  8766  		name   string
  8767  		state  *states.State
  8768  		output string
  8769  		err    bool
  8770  	}{
  8771  		{
  8772  			name:   "add implicit provider",
  8773  			state:  implicitProviderState,
  8774  			err:    false,
  8775  			output: "<no state>",
  8776  		},
  8777  
  8778  		// an aliased provider must be in the config to remove a resource
  8779  		{
  8780  			name:  "add aliased provider",
  8781  			state: aliasedProviderState,
  8782  			err:   true,
  8783  		},
  8784  
  8785  		// a provider in a module implies some sort of config, so this isn't
  8786  		// allowed even without an alias
  8787  		{
  8788  			name:  "add unaliased module provider",
  8789  			state: moduleProviderState,
  8790  			err:   true,
  8791  		},
  8792  	} {
  8793  		t.Run(tc.name, func(t *testing.T) {
  8794  			ctx := testContext2(t, &ContextOpts{
  8795  				Providers: map[addrs.Provider]providers.Factory{
  8796  					addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8797  				},
  8798  			})
  8799  
  8800  			plan, diags := ctx.Plan(m, tc.state, DefaultPlanOpts)
  8801  			if tc.err {
  8802  				if diags == nil {
  8803  					t.Fatal("expected error")
  8804  				} else {
  8805  					return
  8806  				}
  8807  			}
  8808  			if !tc.err && diags.HasErrors() {
  8809  				t.Fatal(diags.Err())
  8810  			}
  8811  
  8812  			state, diags := ctx.Apply(plan, m)
  8813  			if diags.HasErrors() {
  8814  				t.Fatalf("diags: %s", diags.Err())
  8815  			}
  8816  
  8817  			checkStateString(t, state, "<no state>")
  8818  
  8819  		})
  8820  	}
  8821  }
  8822  
  8823  func TestContext2Apply_plannedInterpolatedCount(t *testing.T) {
  8824  	m, snap := testModuleWithSnapshot(t, "apply-interpolated-count")
  8825  
  8826  	p := testProvider("aws")
  8827  	p.PlanResourceChangeFn = testDiffFn
  8828  
  8829  	Providers := map[addrs.Provider]providers.Factory{
  8830  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8831  	}
  8832  
  8833  	state := states.NewState()
  8834  	root := state.EnsureModule(addrs.RootModuleInstance)
  8835  	root.SetResourceInstanceCurrent(
  8836  		mustResourceInstanceAddr("aws_instance.test").Resource,
  8837  		&states.ResourceInstanceObjectSrc{
  8838  			Status:    states.ObjectReady,
  8839  			AttrsJSON: []byte(`{"id":"foo"}`),
  8840  		},
  8841  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8842  	)
  8843  
  8844  	ctx := testContext2(t, &ContextOpts{
  8845  		Providers: Providers,
  8846  	})
  8847  
  8848  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  8849  	if diags.HasErrors() {
  8850  		t.Fatalf("plan failed: %s", diags.Err())
  8851  	}
  8852  
  8853  	// We'll marshal and unmarshal the plan here, to ensure that we have
  8854  	// a clean new context as would be created if we separately ran
  8855  	// terraform plan -out=tfplan && terraform apply tfplan
  8856  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  8857  	if err != nil {
  8858  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8859  	}
  8860  
  8861  	ctxOpts.Providers = Providers
  8862  	ctx, diags = NewContext(ctxOpts)
  8863  	if diags.HasErrors() {
  8864  		t.Fatalf("err: %s", diags.Err())
  8865  	}
  8866  
  8867  	// Applying the plan should now succeed
  8868  	_, diags = ctx.Apply(plan, m)
  8869  	if diags.HasErrors() {
  8870  		t.Fatalf("apply failed: %s", diags.Err())
  8871  	}
  8872  }
  8873  
  8874  func TestContext2Apply_plannedDestroyInterpolatedCount(t *testing.T) {
  8875  	m, snap := testModuleWithSnapshot(t, "plan-destroy-interpolated-count")
  8876  
  8877  	p := testProvider("aws")
  8878  	p.PlanResourceChangeFn = testDiffFn
  8879  	providers := map[addrs.Provider]providers.Factory{
  8880  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8881  	}
  8882  
  8883  	state := states.NewState()
  8884  	root := state.EnsureModule(addrs.RootModuleInstance)
  8885  	root.SetResourceInstanceCurrent(
  8886  		mustResourceInstanceAddr("aws_instance.a[0]").Resource,
  8887  		&states.ResourceInstanceObjectSrc{
  8888  			Status:    states.ObjectReady,
  8889  			AttrsJSON: []byte(`{"id":"foo"}`),
  8890  		},
  8891  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8892  	)
  8893  	root.SetResourceInstanceCurrent(
  8894  		mustResourceInstanceAddr("aws_instance.a[1]").Resource,
  8895  		&states.ResourceInstanceObjectSrc{
  8896  			Status:    states.ObjectReady,
  8897  			AttrsJSON: []byte(`{"id":"foo"}`),
  8898  		},
  8899  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8900  	)
  8901  	root.SetOutputValue("out", cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("foo")}), false)
  8902  
  8903  	ctx := testContext2(t, &ContextOpts{
  8904  		Providers: providers,
  8905  	})
  8906  
  8907  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8908  		Mode: plans.DestroyMode,
  8909  	})
  8910  	if diags.HasErrors() {
  8911  		t.Fatalf("plan failed: %s", diags.Err())
  8912  	}
  8913  
  8914  	// We'll marshal and unmarshal the plan here, to ensure that we have
  8915  	// a clean new context as would be created if we separately ran
  8916  	// terraform plan -out=tfplan && terraform apply tfplan
  8917  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  8918  	if err != nil {
  8919  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8920  	}
  8921  
  8922  	ctxOpts.Providers = providers
  8923  	ctx, diags = NewContext(ctxOpts)
  8924  	if diags.HasErrors() {
  8925  		t.Fatalf("err: %s", diags.Err())
  8926  	}
  8927  
  8928  	// Applying the plan should now succeed
  8929  	state, diags = ctx.Apply(plan, m)
  8930  	if diags.HasErrors() {
  8931  		t.Fatalf("apply failed: %s", diags.Err())
  8932  	}
  8933  	if !state.Empty() {
  8934  		t.Fatalf("state not empty: %s\n", state)
  8935  	}
  8936  }
  8937  
  8938  func TestContext2Apply_scaleInMultivarRef(t *testing.T) {
  8939  	m := testModule(t, "apply-resource-scale-in")
  8940  
  8941  	p := testProvider("aws")
  8942  	p.PlanResourceChangeFn = testDiffFn
  8943  
  8944  	Providers := map[addrs.Provider]providers.Factory{
  8945  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8946  	}
  8947  
  8948  	state := states.NewState()
  8949  	root := state.EnsureModule(addrs.RootModuleInstance)
  8950  	root.SetResourceInstanceCurrent(
  8951  		mustResourceInstanceAddr("aws_instance.one").Resource,
  8952  		&states.ResourceInstanceObjectSrc{
  8953  			Status:    states.ObjectReady,
  8954  			AttrsJSON: []byte(`{"id":"foo"}`),
  8955  		},
  8956  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8957  	)
  8958  	root.SetResourceInstanceCurrent(
  8959  		mustResourceInstanceAddr("aws_instance.two").Resource,
  8960  		&states.ResourceInstanceObjectSrc{
  8961  			Status:    states.ObjectReady,
  8962  			AttrsJSON: []byte(`{"id":"foo"}`),
  8963  		},
  8964  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8965  	)
  8966  
  8967  	ctx := testContext2(t, &ContextOpts{
  8968  		Providers: Providers,
  8969  	})
  8970  
  8971  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8972  		Mode: plans.NormalMode,
  8973  		SetVariables: InputValues{
  8974  			"instance_count": {
  8975  				Value:      cty.NumberIntVal(0),
  8976  				SourceType: ValueFromCaller,
  8977  			},
  8978  		},
  8979  	})
  8980  	assertNoErrors(t, diags)
  8981  	{
  8982  		addr := mustResourceInstanceAddr("aws_instance.one[0]")
  8983  		change := plan.Changes.ResourceInstance(addr)
  8984  		if change == nil {
  8985  			t.Fatalf("no planned change for %s", addr)
  8986  		}
  8987  		// This test was originally written with Terraform v0.11 and earlier
  8988  		// in mind, so it declares a no-key instance of aws_instance.one,
  8989  		// but its configuration sets count (to zero) and so we end up first
  8990  		// moving the no-key instance to the zero key and then planning to
  8991  		// destroy the zero key.
  8992  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("aws_instance.one"); !want.Equal(got) {
  8993  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
  8994  		}
  8995  		if got, want := change.Action, plans.Delete; got != want {
  8996  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  8997  		}
  8998  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
  8999  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
  9000  		}
  9001  	}
  9002  	{
  9003  		addr := mustResourceInstanceAddr("aws_instance.two")
  9004  		change := plan.Changes.ResourceInstance(addr)
  9005  		if change == nil {
  9006  			t.Fatalf("no planned change for %s", addr)
  9007  		}
  9008  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("aws_instance.two"); !want.Equal(got) {
  9009  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
  9010  		}
  9011  		if got, want := change.Action, plans.Update; got != want {
  9012  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  9013  		}
  9014  		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
  9015  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
  9016  		}
  9017  	}
  9018  
  9019  	// Applying the plan should now succeed
  9020  	_, diags = ctx.Apply(plan, m)
  9021  	assertNoErrors(t, diags)
  9022  }
  9023  
  9024  func TestContext2Apply_inconsistentWithPlan(t *testing.T) {
  9025  	m := testModule(t, "apply-inconsistent-with-plan")
  9026  	p := testProvider("test")
  9027  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9028  		ResourceTypes: map[string]*configschema.Block{
  9029  			"test": {
  9030  				Attributes: map[string]*configschema.Attribute{
  9031  					"id": {Type: cty.String, Computed: true},
  9032  				},
  9033  			},
  9034  		},
  9035  	})
  9036  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  9037  		return providers.PlanResourceChangeResponse{
  9038  			PlannedState: cty.ObjectVal(map[string]cty.Value{
  9039  				"id": cty.StringVal("before"),
  9040  			}),
  9041  		}
  9042  	}
  9043  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9044  		return providers.ApplyResourceChangeResponse{
  9045  			NewState: cty.ObjectVal(map[string]cty.Value{
  9046  				// This is intentionally incorrect: because id was fixed at "before"
  9047  				// during plan, it must not change during apply.
  9048  				"id": cty.StringVal("after"),
  9049  			}),
  9050  		}
  9051  	}
  9052  	ctx := testContext2(t, &ContextOpts{
  9053  		Providers: map[addrs.Provider]providers.Factory{
  9054  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9055  		},
  9056  	})
  9057  
  9058  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9059  	assertNoErrors(t, diags)
  9060  
  9061  	_, diags = ctx.Apply(plan, m)
  9062  	if !diags.HasErrors() {
  9063  		t.Fatalf("apply succeeded; want error")
  9064  	}
  9065  	if got, want := diags.Err().Error(), "Provider produced inconsistent result after apply"; !strings.Contains(got, want) {
  9066  		t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want)
  9067  	}
  9068  }
  9069  
  9070  // Issue 19908 was about retaining an existing object in the state when an
  9071  // update to it fails and the provider does not return a partially-updated
  9072  // value for it. Previously we were incorrectly removing it from the state
  9073  // in that case, but instead it should be retained so the update can be
  9074  // retried.
  9075  func TestContext2Apply_issue19908(t *testing.T) {
  9076  	m := testModule(t, "apply-issue19908")
  9077  	p := testProvider("test")
  9078  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9079  		ResourceTypes: map[string]*configschema.Block{
  9080  			"test": {
  9081  				Attributes: map[string]*configschema.Attribute{
  9082  					"baz": {Type: cty.String, Required: true},
  9083  				},
  9084  			},
  9085  		},
  9086  	})
  9087  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  9088  		return providers.PlanResourceChangeResponse{
  9089  			PlannedState: req.ProposedNewState,
  9090  		}
  9091  	}
  9092  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9093  		var diags tfdiags.Diagnostics
  9094  		diags = diags.Append(fmt.Errorf("update failed"))
  9095  		return providers.ApplyResourceChangeResponse{
  9096  			Diagnostics: diags,
  9097  		}
  9098  	}
  9099  	ctx := testContext2(t, &ContextOpts{
  9100  		Providers: map[addrs.Provider]providers.Factory{
  9101  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9102  		},
  9103  	})
  9104  
  9105  	state := states.BuildState(func(s *states.SyncState) {
  9106  		s.SetResourceInstanceCurrent(
  9107  			addrs.Resource{
  9108  				Mode: addrs.ManagedResourceMode,
  9109  				Type: "test",
  9110  				Name: "foo",
  9111  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  9112  			&states.ResourceInstanceObjectSrc{
  9113  				AttrsJSON: []byte(`{"baz":"old"}`),
  9114  				Status:    states.ObjectReady,
  9115  			},
  9116  			addrs.AbsProviderConfig{
  9117  				Provider: addrs.NewDefaultProvider("test"),
  9118  				Module:   addrs.RootModule,
  9119  			},
  9120  		)
  9121  	})
  9122  
  9123  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9124  	assertNoErrors(t, diags)
  9125  
  9126  	state, diags = ctx.Apply(plan, m)
  9127  	if !diags.HasErrors() {
  9128  		t.Fatalf("apply succeeded; want error")
  9129  	}
  9130  	if got, want := diags.Err().Error(), "update failed"; !strings.Contains(got, want) {
  9131  		t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want)
  9132  	}
  9133  
  9134  	mod := state.RootModule()
  9135  	rs := mod.Resources["test.foo"]
  9136  	if rs == nil {
  9137  		t.Fatalf("test.foo not in state after apply, but should be")
  9138  	}
  9139  	is := rs.Instances[addrs.NoKey]
  9140  	if is == nil {
  9141  		t.Fatalf("test.foo not in state after apply, but should be")
  9142  	}
  9143  	obj := is.Current
  9144  	if obj == nil {
  9145  		t.Fatalf("test.foo has no current object in state after apply, but should do")
  9146  	}
  9147  
  9148  	if got, want := obj.Status, states.ObjectReady; got != want {
  9149  		t.Errorf("test.foo has wrong status %s after apply; want %s", got, want)
  9150  	}
  9151  	if got, want := obj.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) {
  9152  		t.Errorf("test.foo attributes JSON doesn't contain %s after apply\ngot: %s", want, got)
  9153  	}
  9154  }
  9155  
  9156  func TestContext2Apply_invalidIndexRef(t *testing.T) {
  9157  	p := testProvider("test")
  9158  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9159  		ResourceTypes: map[string]*configschema.Block{
  9160  			"test_instance": {
  9161  				Attributes: map[string]*configschema.Attribute{
  9162  					"value": {Type: cty.String, Optional: true, Computed: true},
  9163  				},
  9164  			},
  9165  		},
  9166  	})
  9167  	p.PlanResourceChangeFn = testDiffFn
  9168  
  9169  	m := testModule(t, "apply-invalid-index")
  9170  	c := testContext2(t, &ContextOpts{
  9171  		Providers: map[addrs.Provider]providers.Factory{
  9172  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9173  		},
  9174  	})
  9175  	diags := c.Validate(m)
  9176  	if diags.HasErrors() {
  9177  		t.Fatalf("unexpected validation failure: %s", diags.Err())
  9178  	}
  9179  
  9180  	wantErr := `The given key does not identify an element in this collection value`
  9181  	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
  9182  
  9183  	if !diags.HasErrors() {
  9184  		t.Fatalf("plan succeeded; want error")
  9185  	}
  9186  	gotErr := diags.Err().Error()
  9187  
  9188  	if !strings.Contains(gotErr, wantErr) {
  9189  		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErr, wantErr)
  9190  	}
  9191  }
  9192  
  9193  func TestContext2Apply_moduleReplaceCycle(t *testing.T) {
  9194  	for _, mode := range []string{"normal", "cbd"} {
  9195  		var m *configs.Config
  9196  
  9197  		switch mode {
  9198  		case "normal":
  9199  			m = testModule(t, "apply-module-replace-cycle")
  9200  		case "cbd":
  9201  			m = testModule(t, "apply-module-replace-cycle-cbd")
  9202  		}
  9203  
  9204  		p := testProvider("aws")
  9205  		p.PlanResourceChangeFn = testDiffFn
  9206  
  9207  		instanceSchema := &configschema.Block{
  9208  			Attributes: map[string]*configschema.Attribute{
  9209  				"id":          {Type: cty.String, Computed: true},
  9210  				"require_new": {Type: cty.String, Optional: true},
  9211  			},
  9212  		}
  9213  
  9214  		p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9215  			ResourceTypes: map[string]*configschema.Block{
  9216  				"aws_instance": instanceSchema,
  9217  			},
  9218  		})
  9219  
  9220  		state := states.NewState()
  9221  		modA := state.EnsureModule(addrs.RootModuleInstance.Child("a", addrs.NoKey))
  9222  		modA.SetResourceInstanceCurrent(
  9223  			addrs.Resource{
  9224  				Mode: addrs.ManagedResourceMode,
  9225  				Type: "aws_instance",
  9226  				Name: "a",
  9227  			}.Instance(addrs.NoKey),
  9228  			&states.ResourceInstanceObjectSrc{
  9229  				Status:              states.ObjectReady,
  9230  				AttrsJSON:           []byte(`{"id":"a","require_new":"old"}`),
  9231  				CreateBeforeDestroy: mode == "cbd",
  9232  			},
  9233  			addrs.AbsProviderConfig{
  9234  				Provider: addrs.NewDefaultProvider("aws"),
  9235  				Module:   addrs.RootModule,
  9236  			},
  9237  		)
  9238  
  9239  		modB := state.EnsureModule(addrs.RootModuleInstance.Child("b", addrs.NoKey))
  9240  		modB.SetResourceInstanceCurrent(
  9241  			addrs.Resource{
  9242  				Mode: addrs.ManagedResourceMode,
  9243  				Type: "aws_instance",
  9244  				Name: "b",
  9245  			}.Instance(addrs.IntKey(0)),
  9246  			&states.ResourceInstanceObjectSrc{
  9247  				Status:    states.ObjectReady,
  9248  				AttrsJSON: []byte(`{"id":"b","require_new":"old"}`),
  9249  			},
  9250  			addrs.AbsProviderConfig{
  9251  				Provider: addrs.NewDefaultProvider("aws"),
  9252  				Module:   addrs.RootModule,
  9253  			},
  9254  		)
  9255  
  9256  		aBefore, _ := plans.NewDynamicValue(
  9257  			cty.ObjectVal(map[string]cty.Value{
  9258  				"id":          cty.StringVal("a"),
  9259  				"require_new": cty.StringVal("old"),
  9260  			}), instanceSchema.ImpliedType())
  9261  		aAfter, _ := plans.NewDynamicValue(
  9262  			cty.ObjectVal(map[string]cty.Value{
  9263  				"id":          cty.UnknownVal(cty.String),
  9264  				"require_new": cty.StringVal("new"),
  9265  			}), instanceSchema.ImpliedType())
  9266  		bBefore, _ := plans.NewDynamicValue(
  9267  			cty.ObjectVal(map[string]cty.Value{
  9268  				"id":          cty.StringVal("b"),
  9269  				"require_new": cty.StringVal("old"),
  9270  			}), instanceSchema.ImpliedType())
  9271  		bAfter, _ := plans.NewDynamicValue(
  9272  			cty.ObjectVal(map[string]cty.Value{
  9273  				"id":          cty.UnknownVal(cty.String),
  9274  				"require_new": cty.UnknownVal(cty.String),
  9275  			}), instanceSchema.ImpliedType())
  9276  
  9277  		var aAction plans.Action
  9278  		switch mode {
  9279  		case "normal":
  9280  			aAction = plans.DeleteThenCreate
  9281  		case "cbd":
  9282  			aAction = plans.CreateThenDelete
  9283  		}
  9284  
  9285  		ctx := testContext2(t, &ContextOpts{
  9286  			Providers: map[addrs.Provider]providers.Factory{
  9287  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  9288  			},
  9289  		})
  9290  
  9291  		changes := &plans.Changes{
  9292  			Resources: []*plans.ResourceInstanceChangeSrc{
  9293  				{
  9294  					Addr: addrs.Resource{
  9295  						Mode: addrs.ManagedResourceMode,
  9296  						Type: "aws_instance",
  9297  						Name: "a",
  9298  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("a", addrs.NoKey)),
  9299  					ProviderAddr: addrs.AbsProviderConfig{
  9300  						Provider: addrs.NewDefaultProvider("aws"),
  9301  						Module:   addrs.RootModule,
  9302  					},
  9303  					ChangeSrc: plans.ChangeSrc{
  9304  						Action: aAction,
  9305  						Before: aBefore,
  9306  						After:  aAfter,
  9307  					},
  9308  				},
  9309  				{
  9310  					Addr: addrs.Resource{
  9311  						Mode: addrs.ManagedResourceMode,
  9312  						Type: "aws_instance",
  9313  						Name: "b",
  9314  					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("b", addrs.NoKey)),
  9315  					ProviderAddr: addrs.AbsProviderConfig{
  9316  						Provider: addrs.NewDefaultProvider("aws"),
  9317  						Module:   addrs.RootModule,
  9318  					},
  9319  					ChangeSrc: plans.ChangeSrc{
  9320  						Action: plans.DeleteThenCreate,
  9321  						Before: bBefore,
  9322  						After:  bAfter,
  9323  					},
  9324  				},
  9325  			},
  9326  		}
  9327  
  9328  		plan := &plans.Plan{
  9329  			UIMode:       plans.NormalMode,
  9330  			Changes:      changes,
  9331  			PriorState:   state.DeepCopy(),
  9332  			PrevRunState: state.DeepCopy(),
  9333  		}
  9334  
  9335  		t.Run(mode, func(t *testing.T) {
  9336  			_, diags := ctx.Apply(plan, m)
  9337  			if diags.HasErrors() {
  9338  				t.Fatal(diags.Err())
  9339  			}
  9340  		})
  9341  	}
  9342  }
  9343  
  9344  func TestContext2Apply_destroyDataCycle(t *testing.T) {
  9345  	m, snap := testModuleWithSnapshot(t, "apply-destroy-data-cycle")
  9346  	p := testProvider("null")
  9347  	p.PlanResourceChangeFn = testDiffFn
  9348  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  9349  		return providers.ReadDataSourceResponse{
  9350  			State: cty.ObjectVal(map[string]cty.Value{
  9351  				"id":  cty.StringVal("new"),
  9352  				"foo": cty.NullVal(cty.String),
  9353  			}),
  9354  		}
  9355  	}
  9356  
  9357  	tp := testProvider("test")
  9358  	tp.PlanResourceChangeFn = testDiffFn
  9359  
  9360  	state := states.NewState()
  9361  	root := state.EnsureModule(addrs.RootModuleInstance)
  9362  	root.SetResourceInstanceCurrent(
  9363  		addrs.Resource{
  9364  			Mode: addrs.ManagedResourceMode,
  9365  			Type: "null_resource",
  9366  			Name: "a",
  9367  		}.Instance(addrs.IntKey(0)),
  9368  		&states.ResourceInstanceObjectSrc{
  9369  			Status:    states.ObjectReady,
  9370  			AttrsJSON: []byte(`{"id":"a"}`),
  9371  		},
  9372  		addrs.AbsProviderConfig{
  9373  			Provider: addrs.NewDefaultProvider("null"),
  9374  			Module:   addrs.RootModule,
  9375  		},
  9376  	)
  9377  	root.SetResourceInstanceCurrent(
  9378  		addrs.Resource{
  9379  			Mode: addrs.ManagedResourceMode,
  9380  			Type: "test_resource",
  9381  			Name: "a",
  9382  		}.Instance(addrs.IntKey(0)),
  9383  		&states.ResourceInstanceObjectSrc{
  9384  			Status:    states.ObjectReady,
  9385  			AttrsJSON: []byte(`{"id":"a"}`),
  9386  			Dependencies: []addrs.ConfigResource{
  9387  				{
  9388  					Resource: addrs.Resource{
  9389  						Mode: addrs.DataResourceMode,
  9390  						Type: "null_data_source",
  9391  						Name: "d",
  9392  					},
  9393  					Module: addrs.RootModule,
  9394  				},
  9395  			},
  9396  		},
  9397  		addrs.AbsProviderConfig{
  9398  			Provider: addrs.NewDefaultProvider("test"),
  9399  			Module:   addrs.RootModule,
  9400  		},
  9401  	)
  9402  	root.SetResourceInstanceCurrent(
  9403  		addrs.Resource{
  9404  			Mode: addrs.DataResourceMode,
  9405  			Type: "null_data_source",
  9406  			Name: "d",
  9407  		}.Instance(addrs.NoKey),
  9408  		&states.ResourceInstanceObjectSrc{
  9409  			Status:    states.ObjectReady,
  9410  			AttrsJSON: []byte(`{"id":"old"}`),
  9411  		},
  9412  		addrs.AbsProviderConfig{
  9413  			Provider: addrs.NewDefaultProvider("null"),
  9414  			Module:   addrs.RootModule,
  9415  		},
  9416  	)
  9417  
  9418  	Providers := map[addrs.Provider]providers.Factory{
  9419  		addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  9420  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(tp),
  9421  	}
  9422  
  9423  	ctx := testContext2(t, &ContextOpts{
  9424  		Providers: Providers,
  9425  	})
  9426  
  9427  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  9428  		Mode: plans.DestroyMode,
  9429  	})
  9430  	diags.HasErrors()
  9431  	if diags.HasErrors() {
  9432  		t.Fatalf("diags: %s", diags.Err())
  9433  	}
  9434  
  9435  	// We'll marshal and unmarshal the plan here, to ensure that we have
  9436  	// a clean new context as would be created if we separately ran
  9437  	// terraform plan -out=tfplan && terraform apply tfplan
  9438  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  9439  	if err != nil {
  9440  		t.Fatal(err)
  9441  	}
  9442  	ctxOpts.Providers = Providers
  9443  	ctx, diags = NewContext(ctxOpts)
  9444  	if diags.HasErrors() {
  9445  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  9446  	}
  9447  
  9448  	tp.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  9449  		foo := req.Config.GetAttr("foo")
  9450  		if !foo.IsKnown() {
  9451  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown config value foo"))
  9452  			return resp
  9453  		}
  9454  
  9455  		if foo.AsString() != "new" {
  9456  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("wrong config value: %q", foo.AsString()))
  9457  		}
  9458  		return resp
  9459  	}
  9460  
  9461  	_, diags = ctx.Apply(plan, m)
  9462  	if diags.HasErrors() {
  9463  		t.Fatalf("diags: %s", diags.Err())
  9464  	}
  9465  }
  9466  
  9467  func TestContext2Apply_taintedDestroyFailure(t *testing.T) {
  9468  	m := testModule(t, "apply-destroy-tainted")
  9469  	p := testProvider("test")
  9470  	p.PlanResourceChangeFn = testDiffFn
  9471  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  9472  		// All destroys fail.
  9473  		if req.PlannedState.IsNull() {
  9474  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure"))
  9475  			return
  9476  		}
  9477  
  9478  		// c will also fail to create, meaning the existing tainted instance
  9479  		// becomes deposed, ans is then promoted back to current.
  9480  		// only C has a foo attribute
  9481  		planned := req.PlannedState.AsValueMap()
  9482  		foo, ok := planned["foo"]
  9483  		if ok && !foo.IsNull() && foo.AsString() == "c" {
  9484  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure"))
  9485  			return
  9486  		}
  9487  
  9488  		return testApplyFn(req)
  9489  	}
  9490  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9491  		ResourceTypes: map[string]*configschema.Block{
  9492  			"test_instance": {
  9493  				Attributes: map[string]*configschema.Attribute{
  9494  					"id": {
  9495  						Type:     cty.String,
  9496  						Computed: true,
  9497  					},
  9498  					"foo": {
  9499  						Type:     cty.String,
  9500  						Optional: true,
  9501  					},
  9502  				},
  9503  			},
  9504  		},
  9505  	})
  9506  
  9507  	state := states.NewState()
  9508  	root := state.EnsureModule(addrs.RootModuleInstance)
  9509  	root.SetResourceInstanceCurrent(
  9510  		addrs.Resource{
  9511  			Mode: addrs.ManagedResourceMode,
  9512  			Type: "test_instance",
  9513  			Name: "a",
  9514  		}.Instance(addrs.NoKey),
  9515  		&states.ResourceInstanceObjectSrc{
  9516  			Status:    states.ObjectTainted,
  9517  			AttrsJSON: []byte(`{"id":"a","foo":"a"}`),
  9518  		},
  9519  		addrs.AbsProviderConfig{
  9520  			Provider: addrs.NewDefaultProvider("test"),
  9521  			Module:   addrs.RootModule,
  9522  		},
  9523  	)
  9524  	root.SetResourceInstanceCurrent(
  9525  		addrs.Resource{
  9526  			Mode: addrs.ManagedResourceMode,
  9527  			Type: "test_instance",
  9528  			Name: "b",
  9529  		}.Instance(addrs.NoKey),
  9530  		&states.ResourceInstanceObjectSrc{
  9531  			Status:    states.ObjectTainted,
  9532  			AttrsJSON: []byte(`{"id":"b","foo":"b"}`),
  9533  		},
  9534  		addrs.AbsProviderConfig{
  9535  			Provider: addrs.NewDefaultProvider("test"),
  9536  			Module:   addrs.RootModule,
  9537  		},
  9538  	)
  9539  	root.SetResourceInstanceCurrent(
  9540  		addrs.Resource{
  9541  			Mode: addrs.ManagedResourceMode,
  9542  			Type: "test_instance",
  9543  			Name: "c",
  9544  		}.Instance(addrs.NoKey),
  9545  		&states.ResourceInstanceObjectSrc{
  9546  			Status:    states.ObjectTainted,
  9547  			AttrsJSON: []byte(`{"id":"c","foo":"old"}`),
  9548  		},
  9549  		addrs.AbsProviderConfig{
  9550  			Provider: addrs.NewDefaultProvider("test"),
  9551  			Module:   addrs.RootModule,
  9552  		},
  9553  	)
  9554  
  9555  	Providers := map[addrs.Provider]providers.Factory{
  9556  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9557  	}
  9558  
  9559  	ctx := testContext2(t, &ContextOpts{
  9560  		Providers: Providers,
  9561  		Hooks:     []Hook{&testHook{}},
  9562  	})
  9563  
  9564  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9565  	diags.HasErrors()
  9566  	if diags.HasErrors() {
  9567  		t.Fatalf("diags: %s", diags.Err())
  9568  	}
  9569  
  9570  	state, diags = ctx.Apply(plan, m)
  9571  	if !diags.HasErrors() {
  9572  		t.Fatal("expected error")
  9573  	}
  9574  
  9575  	root = state.Module(addrs.RootModuleInstance)
  9576  
  9577  	// the instance that failed to destroy should remain tainted
  9578  	a := root.ResourceInstance(addrs.Resource{
  9579  		Mode: addrs.ManagedResourceMode,
  9580  		Type: "test_instance",
  9581  		Name: "a",
  9582  	}.Instance(addrs.NoKey))
  9583  
  9584  	if a.Current.Status != states.ObjectTainted {
  9585  		t.Fatal("test_instance.a should be tainted")
  9586  	}
  9587  
  9588  	// b is create_before_destroy, and the destroy failed, so there should be 1
  9589  	// deposed instance.
  9590  	b := root.ResourceInstance(addrs.Resource{
  9591  		Mode: addrs.ManagedResourceMode,
  9592  		Type: "test_instance",
  9593  		Name: "b",
  9594  	}.Instance(addrs.NoKey))
  9595  
  9596  	if b.Current.Status != states.ObjectReady {
  9597  		t.Fatal("test_instance.b should be Ready")
  9598  	}
  9599  
  9600  	if len(b.Deposed) != 1 {
  9601  		t.Fatal("test_instance.b failed to keep deposed instance")
  9602  	}
  9603  
  9604  	// the desposed c instance should be promoted back to Current, and remain
  9605  	// tainted
  9606  	c := root.ResourceInstance(addrs.Resource{
  9607  		Mode: addrs.ManagedResourceMode,
  9608  		Type: "test_instance",
  9609  		Name: "c",
  9610  	}.Instance(addrs.NoKey))
  9611  
  9612  	if c.Current == nil {
  9613  		t.Fatal("test_instance.c has no current instance, but it should")
  9614  	}
  9615  
  9616  	if c.Current.Status != states.ObjectTainted {
  9617  		t.Fatal("test_instance.c should be tainted")
  9618  	}
  9619  
  9620  	if len(c.Deposed) != 0 {
  9621  		t.Fatal("test_instance.c should have no deposed instances")
  9622  	}
  9623  
  9624  	if string(c.Current.AttrsJSON) != `{"foo":"old","id":"c"}` {
  9625  		t.Fatalf("unexpected attrs for c: %q\n", c.Current.AttrsJSON)
  9626  	}
  9627  }
  9628  
  9629  func TestContext2Apply_plannedConnectionRefs(t *testing.T) {
  9630  	m := testModule(t, "apply-plan-connection-refs")
  9631  	p := testProvider("test")
  9632  	p.PlanResourceChangeFn = testDiffFn
  9633  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  9634  		s := req.PlannedState.AsValueMap()
  9635  		// delay "a" slightly, so if the reference edge is missing the "b"
  9636  		// provisioner will see an unknown value.
  9637  		if s["foo"].AsString() == "a" {
  9638  			time.Sleep(500 * time.Millisecond)
  9639  		}
  9640  
  9641  		s["id"] = cty.StringVal("ID")
  9642  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
  9643  			s["type"] = cty.StringVal(req.TypeName)
  9644  		}
  9645  		resp.NewState = cty.ObjectVal(s)
  9646  		return resp
  9647  	}
  9648  
  9649  	provisionerFactory := func() (provisioners.Interface, error) {
  9650  		pr := testProvisioner()
  9651  		pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  9652  			host := req.Connection.GetAttr("host")
  9653  			if host.IsNull() || !host.IsKnown() {
  9654  				resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("invalid host value: %#v", host))
  9655  			}
  9656  
  9657  			return resp
  9658  		}
  9659  		return pr, nil
  9660  	}
  9661  
  9662  	Providers := map[addrs.Provider]providers.Factory{
  9663  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9664  	}
  9665  
  9666  	provisioners := map[string]provisioners.Factory{
  9667  		"shell": provisionerFactory,
  9668  	}
  9669  
  9670  	hook := &testHook{}
  9671  	ctx := testContext2(t, &ContextOpts{
  9672  		Providers:    Providers,
  9673  		Provisioners: provisioners,
  9674  		Hooks:        []Hook{hook},
  9675  	})
  9676  
  9677  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9678  	diags.HasErrors()
  9679  	if diags.HasErrors() {
  9680  		t.Fatalf("diags: %s", diags.Err())
  9681  	}
  9682  
  9683  	_, diags = ctx.Apply(plan, m)
  9684  	if diags.HasErrors() {
  9685  		t.Fatalf("diags: %s", diags.Err())
  9686  	}
  9687  }
  9688  
  9689  func TestContext2Apply_cbdCycle(t *testing.T) {
  9690  	m, snap := testModuleWithSnapshot(t, "apply-cbd-cycle")
  9691  	p := testProvider("test")
  9692  	p.PlanResourceChangeFn = testDiffFn
  9693  
  9694  	state := states.NewState()
  9695  	root := state.EnsureModule(addrs.RootModuleInstance)
  9696  	root.SetResourceInstanceCurrent(
  9697  		addrs.Resource{
  9698  			Mode: addrs.ManagedResourceMode,
  9699  			Type: "test_instance",
  9700  			Name: "a",
  9701  		}.Instance(addrs.NoKey),
  9702  		&states.ResourceInstanceObjectSrc{
  9703  			Status:    states.ObjectReady,
  9704  			AttrsJSON: []byte(`{"id":"a","require_new":"old","foo":"b"}`),
  9705  			Dependencies: []addrs.ConfigResource{
  9706  				{
  9707  					Resource: addrs.Resource{
  9708  						Mode: addrs.ManagedResourceMode,
  9709  						Type: "test_instance",
  9710  						Name: "b",
  9711  					},
  9712  					Module: addrs.RootModule,
  9713  				},
  9714  				{
  9715  					Resource: addrs.Resource{
  9716  						Mode: addrs.ManagedResourceMode,
  9717  						Type: "test_instance",
  9718  						Name: "c",
  9719  					},
  9720  					Module: addrs.RootModule,
  9721  				},
  9722  			},
  9723  		},
  9724  		addrs.AbsProviderConfig{
  9725  			Provider: addrs.NewDefaultProvider("test"),
  9726  			Module:   addrs.RootModule,
  9727  		},
  9728  	)
  9729  	root.SetResourceInstanceCurrent(
  9730  		addrs.Resource{
  9731  			Mode: addrs.ManagedResourceMode,
  9732  			Type: "test_instance",
  9733  			Name: "b",
  9734  		}.Instance(addrs.NoKey),
  9735  		&states.ResourceInstanceObjectSrc{
  9736  			Status:    states.ObjectReady,
  9737  			AttrsJSON: []byte(`{"id":"b","require_new":"old","foo":"c"}`),
  9738  			Dependencies: []addrs.ConfigResource{
  9739  				{
  9740  					Resource: addrs.Resource{
  9741  						Mode: addrs.ManagedResourceMode,
  9742  						Type: "test_instance",
  9743  						Name: "c",
  9744  					},
  9745  					Module: addrs.RootModule,
  9746  				},
  9747  			},
  9748  		},
  9749  		addrs.AbsProviderConfig{
  9750  			Provider: addrs.NewDefaultProvider("test"),
  9751  			Module:   addrs.RootModule,
  9752  		},
  9753  	)
  9754  	root.SetResourceInstanceCurrent(
  9755  		addrs.Resource{
  9756  			Mode: addrs.ManagedResourceMode,
  9757  			Type: "test_instance",
  9758  			Name: "c",
  9759  		}.Instance(addrs.NoKey),
  9760  		&states.ResourceInstanceObjectSrc{
  9761  			Status:    states.ObjectReady,
  9762  			AttrsJSON: []byte(`{"id":"c","require_new":"old"}`),
  9763  		},
  9764  		addrs.AbsProviderConfig{
  9765  			Provider: addrs.NewDefaultProvider("test"),
  9766  			Module:   addrs.RootModule,
  9767  		},
  9768  	)
  9769  
  9770  	Providers := map[addrs.Provider]providers.Factory{
  9771  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9772  	}
  9773  
  9774  	hook := &testHook{}
  9775  	ctx := testContext2(t, &ContextOpts{
  9776  		Providers: Providers,
  9777  		Hooks:     []Hook{hook},
  9778  	})
  9779  
  9780  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9781  	diags.HasErrors()
  9782  	if diags.HasErrors() {
  9783  		t.Fatalf("diags: %s", diags.Err())
  9784  	}
  9785  
  9786  	// We'll marshal and unmarshal the plan here, to ensure that we have
  9787  	// a clean new context as would be created if we separately ran
  9788  	// terraform plan -out=tfplan && terraform apply tfplan
  9789  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  9790  	if err != nil {
  9791  		t.Fatal(err)
  9792  	}
  9793  	ctxOpts.Providers = Providers
  9794  	ctx, diags = NewContext(ctxOpts)
  9795  	if diags.HasErrors() {
  9796  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  9797  	}
  9798  
  9799  	_, diags = ctx.Apply(plan, m)
  9800  	if diags.HasErrors() {
  9801  		t.Fatalf("diags: %s", diags.Err())
  9802  	}
  9803  }
  9804  
  9805  func TestContext2Apply_ProviderMeta_apply_set(t *testing.T) {
  9806  	m := testModule(t, "provider-meta-set")
  9807  	p := testProvider("test")
  9808  	p.PlanResourceChangeFn = testDiffFn
  9809  	schema := p.ProviderSchema()
  9810  	schema.ProviderMeta = &configschema.Block{
  9811  		Attributes: map[string]*configschema.Attribute{
  9812  			"baz": {
  9813  				Type:     cty.String,
  9814  				Required: true,
  9815  			},
  9816  		},
  9817  	}
  9818  
  9819  	var pmMu sync.Mutex
  9820  	arcPMs := map[string]cty.Value{}
  9821  
  9822  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9823  		pmMu.Lock()
  9824  		defer pmMu.Unlock()
  9825  		arcPMs[req.TypeName] = req.ProviderMeta
  9826  
  9827  		s := req.PlannedState.AsValueMap()
  9828  		s["id"] = cty.StringVal("ID")
  9829  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
  9830  			s["type"] = cty.StringVal(req.TypeName)
  9831  		}
  9832  		return providers.ApplyResourceChangeResponse{
  9833  			NewState: cty.ObjectVal(s),
  9834  		}
  9835  	}
  9836  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9837  	ctx := testContext2(t, &ContextOpts{
  9838  		Providers: map[addrs.Provider]providers.Factory{
  9839  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9840  		},
  9841  	})
  9842  
  9843  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9844  	assertNoErrors(t, diags)
  9845  
  9846  	_, diags = ctx.Apply(plan, m)
  9847  	assertNoErrors(t, diags)
  9848  
  9849  	if !p.ApplyResourceChangeCalled {
  9850  		t.Fatalf("ApplyResourceChange not called")
  9851  	}
  9852  
  9853  	expectations := map[string]cty.Value{}
  9854  
  9855  	if pm, ok := arcPMs["test_resource"]; !ok {
  9856  		t.Fatalf("sub-module ApplyResourceChange not called")
  9857  	} else if pm.IsNull() {
  9858  		t.Fatalf("null ProviderMeta in sub-module ApplyResourceChange")
  9859  	} else {
  9860  		expectations["quux-submodule"] = pm
  9861  	}
  9862  
  9863  	if pm, ok := arcPMs["test_instance"]; !ok {
  9864  		t.Fatalf("root module ApplyResourceChange not called")
  9865  	} else if pm.IsNull() {
  9866  		t.Fatalf("null ProviderMeta in root module ApplyResourceChange")
  9867  	} else {
  9868  		expectations["quux"] = pm
  9869  	}
  9870  
  9871  	type metaStruct struct {
  9872  		Baz string `cty:"baz"`
  9873  	}
  9874  
  9875  	for expected, v := range expectations {
  9876  		var meta metaStruct
  9877  		err := gocty.FromCtyValue(v, &meta)
  9878  		if err != nil {
  9879  			t.Fatalf("Error parsing cty value: %s", err)
  9880  		}
  9881  		if meta.Baz != expected {
  9882  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
  9883  		}
  9884  	}
  9885  }
  9886  
  9887  func TestContext2Apply_ProviderMeta_apply_unset(t *testing.T) {
  9888  	m := testModule(t, "provider-meta-unset")
  9889  	p := testProvider("test")
  9890  	p.PlanResourceChangeFn = testDiffFn
  9891  	schema := p.ProviderSchema()
  9892  	schema.ProviderMeta = &configschema.Block{
  9893  		Attributes: map[string]*configschema.Attribute{
  9894  			"baz": {
  9895  				Type:     cty.String,
  9896  				Required: true,
  9897  			},
  9898  		},
  9899  	}
  9900  	var pmMu sync.Mutex
  9901  	arcPMs := map[string]cty.Value{}
  9902  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9903  		pmMu.Lock()
  9904  		defer pmMu.Unlock()
  9905  		arcPMs[req.TypeName] = req.ProviderMeta
  9906  
  9907  		s := req.PlannedState.AsValueMap()
  9908  		s["id"] = cty.StringVal("ID")
  9909  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
  9910  			s["type"] = cty.StringVal(req.TypeName)
  9911  		}
  9912  		return providers.ApplyResourceChangeResponse{
  9913  			NewState: cty.ObjectVal(s),
  9914  		}
  9915  	}
  9916  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9917  	ctx := testContext2(t, &ContextOpts{
  9918  		Providers: map[addrs.Provider]providers.Factory{
  9919  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9920  		},
  9921  	})
  9922  
  9923  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9924  	assertNoErrors(t, diags)
  9925  
  9926  	_, diags = ctx.Apply(plan, m)
  9927  	assertNoErrors(t, diags)
  9928  
  9929  	if !p.ApplyResourceChangeCalled {
  9930  		t.Fatalf("ApplyResourceChange not called")
  9931  	}
  9932  
  9933  	if pm, ok := arcPMs["test_resource"]; !ok {
  9934  		t.Fatalf("sub-module ApplyResourceChange not called")
  9935  	} else if !pm.IsNull() {
  9936  		t.Fatalf("non-null ProviderMeta in sub-module ApplyResourceChange: %+v", pm)
  9937  	}
  9938  
  9939  	if pm, ok := arcPMs["test_instance"]; !ok {
  9940  		t.Fatalf("root module ApplyResourceChange not called")
  9941  	} else if !pm.IsNull() {
  9942  		t.Fatalf("non-null ProviderMeta in root module ApplyResourceChange: %+v", pm)
  9943  	}
  9944  }
  9945  
  9946  func TestContext2Apply_ProviderMeta_plan_set(t *testing.T) {
  9947  	m := testModule(t, "provider-meta-set")
  9948  	p := testProvider("test")
  9949  	schema := p.ProviderSchema()
  9950  	schema.ProviderMeta = &configschema.Block{
  9951  		Attributes: map[string]*configschema.Attribute{
  9952  			"baz": {
  9953  				Type:     cty.String,
  9954  				Required: true,
  9955  			},
  9956  		},
  9957  	}
  9958  	prcPMs := map[string]cty.Value{}
  9959  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  9960  		prcPMs[req.TypeName] = req.ProviderMeta
  9961  		return providers.PlanResourceChangeResponse{
  9962  			PlannedState: req.ProposedNewState,
  9963  		}
  9964  	}
  9965  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9966  	ctx := testContext2(t, &ContextOpts{
  9967  		Providers: map[addrs.Provider]providers.Factory{
  9968  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9969  		},
  9970  	})
  9971  
  9972  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9973  	assertNoErrors(t, diags)
  9974  
  9975  	if !p.PlanResourceChangeCalled {
  9976  		t.Fatalf("PlanResourceChange not called")
  9977  	}
  9978  
  9979  	expectations := map[string]cty.Value{}
  9980  
  9981  	if pm, ok := prcPMs["test_resource"]; !ok {
  9982  		t.Fatalf("sub-module PlanResourceChange not called")
  9983  	} else if pm.IsNull() {
  9984  		t.Fatalf("null ProviderMeta in sub-module PlanResourceChange")
  9985  	} else {
  9986  		expectations["quux-submodule"] = pm
  9987  	}
  9988  
  9989  	if pm, ok := prcPMs["test_instance"]; !ok {
  9990  		t.Fatalf("root module PlanResourceChange not called")
  9991  	} else if pm.IsNull() {
  9992  		t.Fatalf("null ProviderMeta in root module PlanResourceChange")
  9993  	} else {
  9994  		expectations["quux"] = pm
  9995  	}
  9996  
  9997  	type metaStruct struct {
  9998  		Baz string `cty:"baz"`
  9999  	}
 10000  
 10001  	for expected, v := range expectations {
 10002  		var meta metaStruct
 10003  		err := gocty.FromCtyValue(v, &meta)
 10004  		if err != nil {
 10005  			t.Fatalf("Error parsing cty value: %s", err)
 10006  		}
 10007  		if meta.Baz != expected {
 10008  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10009  		}
 10010  	}
 10011  }
 10012  
 10013  func TestContext2Apply_ProviderMeta_plan_unset(t *testing.T) {
 10014  	m := testModule(t, "provider-meta-unset")
 10015  	p := testProvider("test")
 10016  	schema := p.ProviderSchema()
 10017  	schema.ProviderMeta = &configschema.Block{
 10018  		Attributes: map[string]*configschema.Attribute{
 10019  			"baz": {
 10020  				Type:     cty.String,
 10021  				Required: true,
 10022  			},
 10023  		},
 10024  	}
 10025  	prcPMs := map[string]cty.Value{}
 10026  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
 10027  		prcPMs[req.TypeName] = req.ProviderMeta
 10028  		return providers.PlanResourceChangeResponse{
 10029  			PlannedState: req.ProposedNewState,
 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  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10040  	assertNoErrors(t, diags)
 10041  
 10042  	if !p.PlanResourceChangeCalled {
 10043  		t.Fatalf("PlanResourceChange not called")
 10044  	}
 10045  
 10046  	if pm, ok := prcPMs["test_resource"]; !ok {
 10047  		t.Fatalf("sub-module PlanResourceChange not called")
 10048  	} else if !pm.IsNull() {
 10049  		t.Fatalf("non-null ProviderMeta in sub-module PlanResourceChange: %+v", pm)
 10050  	}
 10051  
 10052  	if pm, ok := prcPMs["test_instance"]; !ok {
 10053  		t.Fatalf("root module PlanResourceChange not called")
 10054  	} else if !pm.IsNull() {
 10055  		t.Fatalf("non-null ProviderMeta in root module PlanResourceChange: %+v", pm)
 10056  	}
 10057  }
 10058  
 10059  func TestContext2Apply_ProviderMeta_plan_setNoSchema(t *testing.T) {
 10060  	m := testModule(t, "provider-meta-set")
 10061  	p := testProvider("test")
 10062  	p.PlanResourceChangeFn = testDiffFn
 10063  	ctx := testContext2(t, &ContextOpts{
 10064  		Providers: map[addrs.Provider]providers.Factory{
 10065  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10066  		},
 10067  	})
 10068  
 10069  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10070  	if !diags.HasErrors() {
 10071  		t.Fatalf("plan supposed to error, has no errors")
 10072  	}
 10073  
 10074  	var rootErr, subErr bool
 10075  	errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks"
 10076  	for _, diag := range diags {
 10077  		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
 10078  			t.Errorf("Unexpected error: %+v", diag.Description())
 10079  		}
 10080  		switch diag.Description().Detail {
 10081  		case fmt.Sprintf(errorSummary, "instance"):
 10082  			rootErr = true
 10083  		case fmt.Sprintf(errorSummary, "resource"):
 10084  			subErr = true
 10085  		default:
 10086  			t.Errorf("Unexpected error: %s", diag.Description())
 10087  		}
 10088  	}
 10089  	if !rootErr {
 10090  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10091  	}
 10092  	if !subErr {
 10093  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10094  	}
 10095  }
 10096  
 10097  func TestContext2Apply_ProviderMeta_plan_setInvalid(t *testing.T) {
 10098  	m := testModule(t, "provider-meta-set")
 10099  	p := testProvider("test")
 10100  	p.PlanResourceChangeFn = testDiffFn
 10101  	schema := p.ProviderSchema()
 10102  	schema.ProviderMeta = &configschema.Block{
 10103  		Attributes: map[string]*configschema.Attribute{
 10104  			"quux": {
 10105  				Type:     cty.String,
 10106  				Required: true,
 10107  			},
 10108  		},
 10109  	}
 10110  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10111  	ctx := testContext2(t, &ContextOpts{
 10112  		Providers: map[addrs.Provider]providers.Factory{
 10113  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10114  		},
 10115  	})
 10116  
 10117  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10118  	if !diags.HasErrors() {
 10119  		t.Fatalf("plan supposed to error, has no errors")
 10120  	}
 10121  
 10122  	var reqErr, invalidErr bool
 10123  	for _, diag := range diags {
 10124  		switch diag.Description().Summary {
 10125  		case "Missing required argument":
 10126  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10127  				reqErr = true
 10128  			} else {
 10129  				t.Errorf("Unexpected error %+v", diag.Description())
 10130  			}
 10131  		case "Unsupported argument":
 10132  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10133  				invalidErr = true
 10134  			} else {
 10135  				t.Errorf("Unexpected error %+v", diag.Description())
 10136  			}
 10137  		default:
 10138  			t.Errorf("Unexpected error %+v", diag.Description())
 10139  		}
 10140  	}
 10141  	if !reqErr {
 10142  		t.Errorf("Expected missing required argument error, none received")
 10143  	}
 10144  	if !invalidErr {
 10145  		t.Errorf("Expected unsupported argument error, none received")
 10146  	}
 10147  }
 10148  
 10149  func TestContext2Apply_ProviderMeta_refresh_set(t *testing.T) {
 10150  	m := testModule(t, "provider-meta-set")
 10151  	p := testProvider("test")
 10152  	p.PlanResourceChangeFn = testDiffFn
 10153  	schema := p.ProviderSchema()
 10154  	schema.ProviderMeta = &configschema.Block{
 10155  		Attributes: map[string]*configschema.Attribute{
 10156  			"baz": {
 10157  				Type:     cty.String,
 10158  				Required: true,
 10159  			},
 10160  		},
 10161  	}
 10162  	rrcPMs := map[string]cty.Value{}
 10163  	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
 10164  		rrcPMs[req.TypeName] = req.ProviderMeta
 10165  		newState, err := p.GetProviderSchemaResponse.ResourceTypes[req.TypeName].Block.CoerceValue(req.PriorState)
 10166  		if err != nil {
 10167  			panic(err)
 10168  		}
 10169  		resp.NewState = newState
 10170  		return resp
 10171  	}
 10172  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10173  	ctx := testContext2(t, &ContextOpts{
 10174  		Providers: map[addrs.Provider]providers.Factory{
 10175  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10176  		},
 10177  	})
 10178  
 10179  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10180  	assertNoErrors(t, diags)
 10181  
 10182  	state, diags := ctx.Apply(plan, m)
 10183  	assertNoErrors(t, diags)
 10184  
 10185  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10186  	assertNoErrors(t, diags)
 10187  
 10188  	if !p.ReadResourceCalled {
 10189  		t.Fatalf("ReadResource not called")
 10190  	}
 10191  
 10192  	expectations := map[string]cty.Value{}
 10193  
 10194  	if pm, ok := rrcPMs["test_resource"]; !ok {
 10195  		t.Fatalf("sub-module ReadResource not called")
 10196  	} else if pm.IsNull() {
 10197  		t.Fatalf("null ProviderMeta in sub-module ReadResource")
 10198  	} else {
 10199  		expectations["quux-submodule"] = pm
 10200  	}
 10201  
 10202  	if pm, ok := rrcPMs["test_instance"]; !ok {
 10203  		t.Fatalf("root module ReadResource not called")
 10204  	} else if pm.IsNull() {
 10205  		t.Fatalf("null ProviderMeta in root module ReadResource")
 10206  	} else {
 10207  		expectations["quux"] = pm
 10208  	}
 10209  
 10210  	type metaStruct struct {
 10211  		Baz string `cty:"baz"`
 10212  	}
 10213  
 10214  	for expected, v := range expectations {
 10215  		var meta metaStruct
 10216  		err := gocty.FromCtyValue(v, &meta)
 10217  		if err != nil {
 10218  			t.Fatalf("Error parsing cty value: %s", err)
 10219  		}
 10220  		if meta.Baz != expected {
 10221  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10222  		}
 10223  	}
 10224  }
 10225  
 10226  func TestContext2Apply_ProviderMeta_refresh_setNoSchema(t *testing.T) {
 10227  	m := testModule(t, "provider-meta-set")
 10228  	p := testProvider("test")
 10229  	p.PlanResourceChangeFn = testDiffFn
 10230  
 10231  	// we need a schema for plan/apply so they don't error
 10232  	schema := p.ProviderSchema()
 10233  	schema.ProviderMeta = &configschema.Block{
 10234  		Attributes: map[string]*configschema.Attribute{
 10235  			"baz": {
 10236  				Type:     cty.String,
 10237  				Required: true,
 10238  			},
 10239  		},
 10240  	}
 10241  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10242  	ctx := testContext2(t, &ContextOpts{
 10243  		Providers: map[addrs.Provider]providers.Factory{
 10244  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10245  		},
 10246  	})
 10247  
 10248  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10249  	assertNoErrors(t, diags)
 10250  
 10251  	state, diags := ctx.Apply(plan, m)
 10252  	assertNoErrors(t, diags)
 10253  
 10254  	// drop the schema before refresh, to test that it errors
 10255  	schema.ProviderMeta = nil
 10256  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10257  	ctx = testContext2(t, &ContextOpts{
 10258  		Providers: map[addrs.Provider]providers.Factory{
 10259  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10260  		},
 10261  	})
 10262  
 10263  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10264  	if !diags.HasErrors() {
 10265  		t.Fatalf("refresh supposed to error, has no errors")
 10266  	}
 10267  
 10268  	var rootErr, subErr bool
 10269  	errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks"
 10270  	for _, diag := range diags {
 10271  		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
 10272  			t.Errorf("Unexpected error: %+v", diag.Description())
 10273  		}
 10274  		switch diag.Description().Detail {
 10275  		case fmt.Sprintf(errorSummary, "instance"):
 10276  			rootErr = true
 10277  		case fmt.Sprintf(errorSummary, "resource"):
 10278  			subErr = true
 10279  		default:
 10280  			t.Errorf("Unexpected error: %s", diag.Description())
 10281  		}
 10282  	}
 10283  	if !rootErr {
 10284  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10285  	}
 10286  	if !subErr {
 10287  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10288  	}
 10289  }
 10290  
 10291  func TestContext2Apply_ProviderMeta_refresh_setInvalid(t *testing.T) {
 10292  	m := testModule(t, "provider-meta-set")
 10293  	p := testProvider("test")
 10294  	p.PlanResourceChangeFn = testDiffFn
 10295  
 10296  	// we need a matching schema for plan/apply so they don't error
 10297  	schema := p.ProviderSchema()
 10298  	schema.ProviderMeta = &configschema.Block{
 10299  		Attributes: map[string]*configschema.Attribute{
 10300  			"baz": {
 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  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10314  	assertNoErrors(t, diags)
 10315  
 10316  	state, diags := ctx.Apply(plan, m)
 10317  	assertNoErrors(t, diags)
 10318  
 10319  	// change the schema before refresh, to test that it errors
 10320  	schema.ProviderMeta = &configschema.Block{
 10321  		Attributes: map[string]*configschema.Attribute{
 10322  			"quux": {
 10323  				Type:     cty.String,
 10324  				Required: true,
 10325  			},
 10326  		},
 10327  	}
 10328  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10329  	ctx = testContext2(t, &ContextOpts{
 10330  		Providers: map[addrs.Provider]providers.Factory{
 10331  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10332  		},
 10333  	})
 10334  
 10335  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10336  	if !diags.HasErrors() {
 10337  		t.Fatalf("refresh supposed to error, has no errors")
 10338  	}
 10339  
 10340  	var reqErr, invalidErr bool
 10341  	for _, diag := range diags {
 10342  		switch diag.Description().Summary {
 10343  		case "Missing required argument":
 10344  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10345  				reqErr = true
 10346  			} else {
 10347  				t.Errorf("Unexpected error %+v", diag.Description())
 10348  			}
 10349  		case "Unsupported argument":
 10350  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10351  				invalidErr = true
 10352  			} else {
 10353  				t.Errorf("Unexpected error %+v", diag.Description())
 10354  			}
 10355  		default:
 10356  			t.Errorf("Unexpected error %+v", diag.Description())
 10357  		}
 10358  	}
 10359  	if !reqErr {
 10360  		t.Errorf("Expected missing required argument error, none received")
 10361  	}
 10362  	if !invalidErr {
 10363  		t.Errorf("Expected unsupported argument error, none received")
 10364  	}
 10365  }
 10366  
 10367  func TestContext2Apply_ProviderMeta_refreshdata_set(t *testing.T) {
 10368  	m := testModule(t, "provider-meta-data-set")
 10369  	p := testProvider("test")
 10370  	p.PlanResourceChangeFn = testDiffFn
 10371  	schema := p.ProviderSchema()
 10372  	schema.ProviderMeta = &configschema.Block{
 10373  		Attributes: map[string]*configschema.Attribute{
 10374  			"baz": {
 10375  				Type:     cty.String,
 10376  				Required: true,
 10377  			},
 10378  		},
 10379  	}
 10380  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10381  	ctx := testContext2(t, &ContextOpts{
 10382  		Providers: map[addrs.Provider]providers.Factory{
 10383  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10384  		},
 10385  	})
 10386  	rdsPMs := map[string]cty.Value{}
 10387  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10388  		rdsPMs[req.TypeName] = req.ProviderMeta
 10389  		switch req.TypeName {
 10390  		case "test_data_source":
 10391  			log.Printf("[TRACE] test_data_source RDSR returning")
 10392  			return providers.ReadDataSourceResponse{
 10393  				State: cty.ObjectVal(map[string]cty.Value{
 10394  					"id":  cty.StringVal("yo"),
 10395  					"foo": cty.StringVal("bar"),
 10396  				}),
 10397  			}
 10398  		case "test_file":
 10399  			log.Printf("[TRACE] test_file RDSR returning")
 10400  			return providers.ReadDataSourceResponse{
 10401  				State: cty.ObjectVal(map[string]cty.Value{
 10402  					"id":       cty.StringVal("bar"),
 10403  					"rendered": cty.StringVal("baz"),
 10404  					"template": cty.StringVal(""),
 10405  				}),
 10406  			}
 10407  		default:
 10408  			// config drift, oops
 10409  			log.Printf("[TRACE] unknown request TypeName: %q", req.TypeName)
 10410  			return providers.ReadDataSourceResponse{}
 10411  		}
 10412  	}
 10413  
 10414  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10415  	assertNoErrors(t, diags)
 10416  
 10417  	state, diags := ctx.Apply(plan, m)
 10418  	assertNoErrors(t, diags)
 10419  
 10420  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10421  	assertNoErrors(t, diags)
 10422  
 10423  	if !p.ReadDataSourceCalled {
 10424  		t.Fatalf("ReadDataSource not called")
 10425  	}
 10426  
 10427  	expectations := map[string]cty.Value{}
 10428  
 10429  	if pm, ok := rdsPMs["test_file"]; !ok {
 10430  		t.Fatalf("sub-module ReadDataSource not called")
 10431  	} else if pm.IsNull() {
 10432  		t.Fatalf("null ProviderMeta in sub-module ReadDataSource")
 10433  	} else {
 10434  		expectations["quux-submodule"] = pm
 10435  	}
 10436  
 10437  	if pm, ok := rdsPMs["test_data_source"]; !ok {
 10438  		t.Fatalf("root module ReadDataSource not called")
 10439  	} else if pm.IsNull() {
 10440  		t.Fatalf("null ProviderMeta in root module ReadDataSource")
 10441  	} else {
 10442  		expectations["quux"] = pm
 10443  	}
 10444  
 10445  	type metaStruct struct {
 10446  		Baz string `cty:"baz"`
 10447  	}
 10448  
 10449  	for expected, v := range expectations {
 10450  		var meta metaStruct
 10451  		err := gocty.FromCtyValue(v, &meta)
 10452  		if err != nil {
 10453  			t.Fatalf("Error parsing cty value: %s", err)
 10454  		}
 10455  		if meta.Baz != expected {
 10456  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10457  		}
 10458  	}
 10459  }
 10460  
 10461  func TestContext2Apply_ProviderMeta_refreshdata_unset(t *testing.T) {
 10462  	m := testModule(t, "provider-meta-data-unset")
 10463  	p := testProvider("test")
 10464  	p.PlanResourceChangeFn = testDiffFn
 10465  	schema := p.ProviderSchema()
 10466  	schema.ProviderMeta = &configschema.Block{
 10467  		Attributes: map[string]*configschema.Attribute{
 10468  			"baz": {
 10469  				Type:     cty.String,
 10470  				Required: true,
 10471  			},
 10472  		},
 10473  	}
 10474  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10475  	ctx := testContext2(t, &ContextOpts{
 10476  		Providers: map[addrs.Provider]providers.Factory{
 10477  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10478  		},
 10479  	})
 10480  	rdsPMs := map[string]cty.Value{}
 10481  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10482  		rdsPMs[req.TypeName] = req.ProviderMeta
 10483  		switch req.TypeName {
 10484  		case "test_data_source":
 10485  			return providers.ReadDataSourceResponse{
 10486  				State: cty.ObjectVal(map[string]cty.Value{
 10487  					"id":  cty.StringVal("yo"),
 10488  					"foo": cty.StringVal("bar"),
 10489  				}),
 10490  			}
 10491  		case "test_file":
 10492  			return providers.ReadDataSourceResponse{
 10493  				State: cty.ObjectVal(map[string]cty.Value{
 10494  					"id":       cty.StringVal("bar"),
 10495  					"rendered": cty.StringVal("baz"),
 10496  					"template": cty.StringVal(""),
 10497  				}),
 10498  			}
 10499  		default:
 10500  			// config drift, oops
 10501  			return providers.ReadDataSourceResponse{}
 10502  		}
 10503  	}
 10504  
 10505  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10506  	assertNoErrors(t, diags)
 10507  
 10508  	_, diags = ctx.Apply(plan, m)
 10509  	assertNoErrors(t, diags)
 10510  
 10511  	if !p.ReadDataSourceCalled {
 10512  		t.Fatalf("ReadDataSource not called")
 10513  	}
 10514  
 10515  	if pm, ok := rdsPMs["test_file"]; !ok {
 10516  		t.Fatalf("sub-module ReadDataSource not called")
 10517  	} else if !pm.IsNull() {
 10518  		t.Fatalf("non-null ProviderMeta in sub-module ReadDataSource")
 10519  	}
 10520  
 10521  	if pm, ok := rdsPMs["test_data_source"]; !ok {
 10522  		t.Fatalf("root module ReadDataSource not called")
 10523  	} else if !pm.IsNull() {
 10524  		t.Fatalf("non-null ProviderMeta in root module ReadDataSource")
 10525  	}
 10526  }
 10527  
 10528  func TestContext2Apply_ProviderMeta_refreshdata_setNoSchema(t *testing.T) {
 10529  	m := testModule(t, "provider-meta-data-set")
 10530  	p := testProvider("test")
 10531  	p.PlanResourceChangeFn = testDiffFn
 10532  	ctx := testContext2(t, &ContextOpts{
 10533  		Providers: map[addrs.Provider]providers.Factory{
 10534  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10535  		},
 10536  	})
 10537  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 10538  		State: cty.ObjectVal(map[string]cty.Value{
 10539  			"id":  cty.StringVal("yo"),
 10540  			"foo": cty.StringVal("bar"),
 10541  		}),
 10542  	}
 10543  
 10544  	_, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts)
 10545  	if !diags.HasErrors() {
 10546  		t.Fatalf("refresh supposed to error, has no errors")
 10547  	}
 10548  
 10549  	var rootErr, subErr bool
 10550  	errorSummary := "The resource data.test_%s.foo belongs to a provider that doesn't support provider_meta blocks"
 10551  	for _, diag := range diags {
 10552  		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
 10553  			t.Errorf("Unexpected error: %+v", diag.Description())
 10554  		}
 10555  		switch diag.Description().Detail {
 10556  		case fmt.Sprintf(errorSummary, "data_source"):
 10557  			rootErr = true
 10558  		case fmt.Sprintf(errorSummary, "file"):
 10559  			subErr = true
 10560  		default:
 10561  			t.Errorf("Unexpected error: %s", diag.Description())
 10562  		}
 10563  	}
 10564  	if !rootErr {
 10565  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10566  	}
 10567  	if !subErr {
 10568  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10569  	}
 10570  }
 10571  
 10572  func TestContext2Apply_ProviderMeta_refreshdata_setInvalid(t *testing.T) {
 10573  	m := testModule(t, "provider-meta-data-set")
 10574  	p := testProvider("test")
 10575  	p.PlanResourceChangeFn = testDiffFn
 10576  	schema := p.ProviderSchema()
 10577  	schema.ProviderMeta = &configschema.Block{
 10578  		Attributes: map[string]*configschema.Attribute{
 10579  			"quux": {
 10580  				Type:     cty.String,
 10581  				Required: true,
 10582  			},
 10583  		},
 10584  	}
 10585  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10586  	ctx := testContext2(t, &ContextOpts{
 10587  		Providers: map[addrs.Provider]providers.Factory{
 10588  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10589  		},
 10590  	})
 10591  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 10592  		State: cty.ObjectVal(map[string]cty.Value{
 10593  			"id":  cty.StringVal("yo"),
 10594  			"foo": cty.StringVal("bar"),
 10595  		}),
 10596  	}
 10597  
 10598  	_, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts)
 10599  	if !diags.HasErrors() {
 10600  		t.Fatalf("refresh supposed to error, has no errors")
 10601  	}
 10602  
 10603  	var reqErr, invalidErr bool
 10604  	for _, diag := range diags {
 10605  		switch diag.Description().Summary {
 10606  		case "Missing required argument":
 10607  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10608  				reqErr = true
 10609  			} else {
 10610  				t.Errorf("Unexpected error %+v", diag.Description())
 10611  			}
 10612  		case "Unsupported argument":
 10613  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10614  				invalidErr = true
 10615  			} else {
 10616  				t.Errorf("Unexpected error %+v", diag.Description())
 10617  			}
 10618  		default:
 10619  			t.Errorf("Unexpected error %+v", diag.Description())
 10620  		}
 10621  	}
 10622  	if !reqErr {
 10623  		t.Errorf("Expected missing required argument error, none received")
 10624  	}
 10625  	if !invalidErr {
 10626  		t.Errorf("Expected unsupported argument error, none received")
 10627  	}
 10628  }
 10629  
 10630  func TestContext2Apply_expandModuleVariables(t *testing.T) {
 10631  	m := testModuleInline(t, map[string]string{
 10632  		"main.tf": `
 10633  module "mod1" {
 10634    for_each = toset(["a"])
 10635    source = "./mod"
 10636  }
 10637  
 10638  module "mod2" {
 10639    source = "./mod"
 10640    in = module.mod1["a"].out
 10641  }
 10642  `,
 10643  		"mod/main.tf": `
 10644  resource "aws_instance" "foo" {
 10645    foo = var.in
 10646  }
 10647  
 10648  variable "in" {
 10649    type = string
 10650    default = "default"
 10651  }
 10652  
 10653  output "out" {
 10654    value = aws_instance.foo.id
 10655  }
 10656  `,
 10657  	})
 10658  
 10659  	p := testProvider("aws")
 10660  	p.PlanResourceChangeFn = testDiffFn
 10661  	p.ApplyResourceChangeFn = testApplyFn
 10662  	ctx := testContext2(t, &ContextOpts{
 10663  		Providers: map[addrs.Provider]providers.Factory{
 10664  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 10665  		},
 10666  	})
 10667  
 10668  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10669  	if diags.HasErrors() {
 10670  		t.Fatal(diags.ErrWithWarnings())
 10671  	}
 10672  
 10673  	state, diags := ctx.Apply(plan, m)
 10674  	if diags.HasErrors() {
 10675  		t.Fatal(diags.ErrWithWarnings())
 10676  	}
 10677  
 10678  	expected := `<no state>
 10679  module.mod1["a"]:
 10680    aws_instance.foo:
 10681      ID = foo
 10682      provider = provider["registry.terraform.io/hashicorp/aws"]
 10683      foo = default
 10684      type = aws_instance
 10685  
 10686    Outputs:
 10687  
 10688    out = foo
 10689  module.mod2:
 10690    aws_instance.foo:
 10691      ID = foo
 10692      provider = provider["registry.terraform.io/hashicorp/aws"]
 10693      foo = foo
 10694      type = aws_instance
 10695  
 10696      Dependencies:
 10697        module.mod1.aws_instance.foo`
 10698  
 10699  	if state.String() != expected {
 10700  		t.Fatalf("expected:\n%s\ngot:\n%s\n", expected, state)
 10701  	}
 10702  }
 10703  
 10704  func TestContext2Apply_inheritAndStoreCBD(t *testing.T) {
 10705  	m := testModuleInline(t, map[string]string{
 10706  		"main.tf": `
 10707  resource "aws_instance" "foo" {
 10708  }
 10709  
 10710  resource "aws_instance" "cbd" {
 10711    foo = aws_instance.foo.id
 10712    lifecycle {
 10713      create_before_destroy = true
 10714    }
 10715  }
 10716  `,
 10717  	})
 10718  
 10719  	p := testProvider("aws")
 10720  	p.PlanResourceChangeFn = testDiffFn
 10721  	ctx := testContext2(t, &ContextOpts{
 10722  		Providers: map[addrs.Provider]providers.Factory{
 10723  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 10724  		},
 10725  	})
 10726  
 10727  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10728  	if diags.HasErrors() {
 10729  		t.Fatal(diags.ErrWithWarnings())
 10730  	}
 10731  
 10732  	state, diags := ctx.Apply(plan, m)
 10733  	if diags.HasErrors() {
 10734  		t.Fatal(diags.ErrWithWarnings())
 10735  	}
 10736  
 10737  	foo := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo"))
 10738  	if !foo.Current.CreateBeforeDestroy {
 10739  		t.Fatal("aws_instance.foo should also be create_before_destroy")
 10740  	}
 10741  }
 10742  
 10743  func TestContext2Apply_moduleDependsOn(t *testing.T) {
 10744  	m := testModule(t, "apply-module-depends-on")
 10745  
 10746  	p := testProvider("test")
 10747  
 10748  	// each instance being applied should happen in sequential order
 10749  	applied := int64(0)
 10750  
 10751  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10752  		cfg := req.Config.AsValueMap()
 10753  		foo := cfg["foo"].AsString()
 10754  		ord := atomic.LoadInt64(&applied)
 10755  
 10756  		resp := providers.ReadDataSourceResponse{
 10757  			State: cty.ObjectVal(map[string]cty.Value{
 10758  				"id":  cty.StringVal("data"),
 10759  				"foo": cfg["foo"],
 10760  			}),
 10761  		}
 10762  
 10763  		if foo == "a" && ord < 4 {
 10764  			// due to data source "a"'s module depending on instance 4, this
 10765  			// should not be less than 4
 10766  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source a read too early"))
 10767  		}
 10768  		if foo == "b" && ord < 1 {
 10769  			// due to data source "b"'s module depending on instance 1, this
 10770  			// should not be less than 1
 10771  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source b read too early"))
 10772  		}
 10773  		return resp
 10774  	}
 10775  	p.PlanResourceChangeFn = testDiffFn
 10776  
 10777  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 10778  		state := req.PlannedState.AsValueMap()
 10779  		num, _ := state["num"].AsBigFloat().Float64()
 10780  		ord := int64(num)
 10781  		if !atomic.CompareAndSwapInt64(&applied, ord-1, ord) {
 10782  			actual := atomic.LoadInt64(&applied)
 10783  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("instance %d was applied after %d", ord, actual))
 10784  		}
 10785  
 10786  		state["id"] = cty.StringVal(fmt.Sprintf("test_%d", ord))
 10787  		state["type"] = cty.StringVal("test_instance")
 10788  		resp.NewState = cty.ObjectVal(state)
 10789  
 10790  		return resp
 10791  	}
 10792  
 10793  	ctx := testContext2(t, &ContextOpts{
 10794  		Providers: map[addrs.Provider]providers.Factory{
 10795  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10796  		},
 10797  	})
 10798  
 10799  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10800  	if diags.HasErrors() {
 10801  		t.Fatal(diags.ErrWithWarnings())
 10802  	}
 10803  
 10804  	state, diags := ctx.Apply(plan, m)
 10805  	if diags.HasErrors() {
 10806  		t.Fatal(diags.ErrWithWarnings())
 10807  	}
 10808  
 10809  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
 10810  	if diags.HasErrors() {
 10811  		t.Fatal(diags.ErrWithWarnings())
 10812  	}
 10813  
 10814  	for _, res := range plan.Changes.Resources {
 10815  		if res.Action != plans.NoOp {
 10816  			t.Fatalf("expected NoOp, got %s for %s", res.Action, res.Addr)
 10817  		}
 10818  	}
 10819  }
 10820  
 10821  func TestContext2Apply_moduleSelfReference(t *testing.T) {
 10822  	m := testModuleInline(t, map[string]string{
 10823  		"main.tf": `
 10824  module "test" {
 10825    source = "./test"
 10826  
 10827    a = module.test.b
 10828  }
 10829  
 10830  output "c" {
 10831    value = module.test.c
 10832  }
 10833  `,
 10834  		"test/main.tf": `
 10835  variable "a" {}
 10836  
 10837  resource "test_instance" "test" {
 10838  }
 10839  
 10840  output "b" {
 10841    value = test_instance.test.id
 10842  }
 10843  
 10844  output "c" {
 10845    value = var.a
 10846  }`})
 10847  
 10848  	p := testProvider("test")
 10849  	p.PlanResourceChangeFn = testDiffFn
 10850  	ctx := testContext2(t, &ContextOpts{
 10851  		Providers: map[addrs.Provider]providers.Factory{
 10852  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10853  		},
 10854  	})
 10855  
 10856  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10857  	if diags.HasErrors() {
 10858  		t.Fatal(diags.ErrWithWarnings())
 10859  	}
 10860  
 10861  	state, diags := ctx.Apply(plan, m)
 10862  	if diags.HasErrors() {
 10863  		t.Fatal(diags.ErrWithWarnings())
 10864  	}
 10865  
 10866  	ctx = testContext2(t, &ContextOpts{
 10867  		Providers: map[addrs.Provider]providers.Factory{
 10868  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10869  		},
 10870  	})
 10871  
 10872  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 10873  		Mode: plans.DestroyMode,
 10874  	})
 10875  	if diags.HasErrors() {
 10876  		t.Fatal(diags.ErrWithWarnings())
 10877  	}
 10878  
 10879  	state, diags = ctx.Apply(plan, m)
 10880  	if diags.HasErrors() {
 10881  		t.Fatal(diags.ErrWithWarnings())
 10882  	}
 10883  
 10884  	if !state.Empty() {
 10885  		t.Fatal("expected empty state, got:", state)
 10886  	}
 10887  }
 10888  
 10889  func TestContext2Apply_moduleExpandDependsOn(t *testing.T) {
 10890  	m := testModuleInline(t, map[string]string{
 10891  		"main.tf": `
 10892  module "child" {
 10893    count = 1
 10894    source = "./child"
 10895  
 10896    depends_on = [test_instance.a, test_instance.b]
 10897  }
 10898  
 10899  resource "test_instance" "a" {
 10900  }
 10901  
 10902  
 10903  resource "test_instance" "b" {
 10904  }
 10905  `,
 10906  		"child/main.tf": `
 10907  resource "test_instance" "foo" {
 10908  }
 10909  
 10910  output "myoutput" {
 10911    value = "literal string"
 10912  }
 10913  `})
 10914  
 10915  	p := testProvider("test")
 10916  	p.PlanResourceChangeFn = testDiffFn
 10917  	ctx := testContext2(t, &ContextOpts{
 10918  		Providers: map[addrs.Provider]providers.Factory{
 10919  			addrs.NewDefaultProvider("test"): 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  	ctx = testContext2(t, &ContextOpts{
 10934  		Providers: map[addrs.Provider]providers.Factory{
 10935  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10936  		},
 10937  	})
 10938  
 10939  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 10940  		Mode: plans.DestroyMode,
 10941  	})
 10942  	if diags.HasErrors() {
 10943  		t.Fatal(diags.ErrWithWarnings())
 10944  	}
 10945  
 10946  	state, diags = ctx.Apply(plan, m)
 10947  	if diags.HasErrors() {
 10948  		t.Fatal(diags.ErrWithWarnings())
 10949  	}
 10950  
 10951  	if !state.Empty() {
 10952  		t.Fatal("expected empty state, got:", state)
 10953  	}
 10954  }
 10955  
 10956  func TestContext2Apply_scaleInCBD(t *testing.T) {
 10957  	m := testModuleInline(t, map[string]string{
 10958  		"main.tf": `
 10959  variable "ct" {
 10960    type = number
 10961  }
 10962  
 10963  resource "test_instance" "a" {
 10964    count = var.ct
 10965  }
 10966  
 10967  resource "test_instance" "b" {
 10968    require_new = local.removable
 10969    lifecycle {
 10970  	create_before_destroy = true
 10971    }
 10972  }
 10973  
 10974  resource "test_instance" "c" {
 10975    require_new = test_instance.b.id
 10976    lifecycle {
 10977  	create_before_destroy = true
 10978    }
 10979  }
 10980  
 10981  output "out" {
 10982    value = join(".", test_instance.a[*].id)
 10983  }
 10984  
 10985  locals {
 10986    removable = join(".", test_instance.a[*].id)
 10987  }
 10988  `})
 10989  
 10990  	state := states.NewState()
 10991  	root := state.EnsureModule(addrs.RootModuleInstance)
 10992  	root.SetResourceInstanceCurrent(
 10993  		mustResourceInstanceAddr("test_instance.a[0]").Resource,
 10994  		&states.ResourceInstanceObjectSrc{
 10995  			Status:              states.ObjectReady,
 10996  			AttrsJSON:           []byte(`{"id":"a0"}`),
 10997  			Dependencies:        []addrs.ConfigResource{},
 10998  			CreateBeforeDestroy: true,
 10999  		},
 11000  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 11001  	)
 11002  	root.SetResourceInstanceCurrent(
 11003  		mustResourceInstanceAddr("test_instance.a[1]").Resource,
 11004  		&states.ResourceInstanceObjectSrc{
 11005  			Status:              states.ObjectReady,
 11006  			AttrsJSON:           []byte(`{"id":"a1"}`),
 11007  			Dependencies:        []addrs.ConfigResource{},
 11008  			CreateBeforeDestroy: true,
 11009  		},
 11010  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 11011  	)
 11012  	root.SetResourceInstanceCurrent(
 11013  		mustResourceInstanceAddr("test_instance.b").Resource,
 11014  		&states.ResourceInstanceObjectSrc{
 11015  			Status:              states.ObjectReady,
 11016  			AttrsJSON:           []byte(`{"id":"b", "require_new":"old.old"}`),
 11017  			Dependencies:        []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")},
 11018  			CreateBeforeDestroy: true,
 11019  		},
 11020  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 11021  	)
 11022  	root.SetResourceInstanceCurrent(
 11023  		mustResourceInstanceAddr("test_instance.c").Resource,
 11024  		&states.ResourceInstanceObjectSrc{
 11025  			Status:    states.ObjectReady,
 11026  			AttrsJSON: []byte(`{"id":"c", "require_new":"b"}`),
 11027  			Dependencies: []addrs.ConfigResource{
 11028  				mustConfigResourceAddr("test_instance.a"),
 11029  				mustConfigResourceAddr("test_instance.b"),
 11030  			},
 11031  			CreateBeforeDestroy: true,
 11032  		},
 11033  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 11034  	)
 11035  
 11036  	p := testProvider("test")
 11037  
 11038  	p.PlanResourceChangeFn = func(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
 11039  		n := r.ProposedNewState.AsValueMap()
 11040  
 11041  		if r.PriorState.IsNull() {
 11042  			n["id"] = cty.UnknownVal(cty.String)
 11043  			resp.PlannedState = cty.ObjectVal(n)
 11044  			return resp
 11045  		}
 11046  
 11047  		p := r.PriorState.AsValueMap()
 11048  
 11049  		priorRN := p["require_new"]
 11050  		newRN := n["require_new"]
 11051  
 11052  		if eq := priorRN.Equals(newRN); !eq.IsKnown() || eq.False() {
 11053  			resp.RequiresReplace = []cty.Path{{cty.GetAttrStep{Name: "require_new"}}}
 11054  			n["id"] = cty.UnknownVal(cty.String)
 11055  		}
 11056  
 11057  		resp.PlannedState = cty.ObjectVal(n)
 11058  		return resp
 11059  	}
 11060  
 11061  	// reduce the count to 1
 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.NormalMode,
 11070  		SetVariables: InputValues{
 11071  			"ct": &InputValue{
 11072  				Value:      cty.NumberIntVal(1),
 11073  				SourceType: ValueFromCaller,
 11074  			},
 11075  		},
 11076  	})
 11077  	if diags.HasErrors() {
 11078  		t.Fatal(diags.ErrWithWarnings())
 11079  	}
 11080  	{
 11081  		addr := mustResourceInstanceAddr("test_instance.a[0]")
 11082  		change := plan.Changes.ResourceInstance(addr)
 11083  		if change == nil {
 11084  			t.Fatalf("no planned change for %s", addr)
 11085  		}
 11086  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[0]"); !want.Equal(got) {
 11087  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
 11088  		}
 11089  		if got, want := change.Action, plans.NoOp; got != want {
 11090  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
 11091  		}
 11092  		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
 11093  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
 11094  		}
 11095  	}
 11096  	{
 11097  		addr := mustResourceInstanceAddr("test_instance.a[1]")
 11098  		change := plan.Changes.ResourceInstance(addr)
 11099  		if change == nil {
 11100  			t.Fatalf("no planned change for %s", addr)
 11101  		}
 11102  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[1]"); !want.Equal(got) {
 11103  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
 11104  		}
 11105  		if got, want := change.Action, plans.Delete; got != want {
 11106  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
 11107  		}
 11108  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
 11109  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
 11110  		}
 11111  	}
 11112  
 11113  	state, diags = ctx.Apply(plan, m)
 11114  	if diags.HasErrors() {
 11115  		log.Fatal(diags.ErrWithWarnings())
 11116  	}
 11117  
 11118  	// check the output, as those can't cause an error planning the value
 11119  	out := state.RootModule().OutputValues["out"].Value.AsString()
 11120  	if out != "a0" {
 11121  		t.Fatalf(`expected output "a0", got: %q`, out)
 11122  	}
 11123  
 11124  	// reduce the count to 0
 11125  	ctx = testContext2(t, &ContextOpts{
 11126  		Providers: map[addrs.Provider]providers.Factory{
 11127  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11128  		},
 11129  	})
 11130  
 11131  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11132  		Mode: plans.NormalMode,
 11133  		SetVariables: InputValues{
 11134  			"ct": &InputValue{
 11135  				Value:      cty.NumberIntVal(0),
 11136  				SourceType: ValueFromCaller,
 11137  			},
 11138  		},
 11139  	})
 11140  	if diags.HasErrors() {
 11141  		t.Fatal(diags.ErrWithWarnings())
 11142  	}
 11143  	{
 11144  		addr := mustResourceInstanceAddr("test_instance.a[0]")
 11145  		change := plan.Changes.ResourceInstance(addr)
 11146  		if change == nil {
 11147  			t.Fatalf("no planned change for %s", addr)
 11148  		}
 11149  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[0]"); !want.Equal(got) {
 11150  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
 11151  		}
 11152  		if got, want := change.Action, plans.Delete; got != want {
 11153  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
 11154  		}
 11155  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
 11156  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
 11157  		}
 11158  	}
 11159  	{
 11160  		addr := mustResourceInstanceAddr("test_instance.a[1]")
 11161  		change := plan.Changes.ResourceInstance(addr)
 11162  		if change != nil {
 11163  			// It was already removed in the previous plan/apply
 11164  			t.Errorf("unexpected planned change for %s", addr)
 11165  		}
 11166  	}
 11167  
 11168  	state, diags = ctx.Apply(plan, m)
 11169  	if diags.HasErrors() {
 11170  		t.Fatal(diags.ErrWithWarnings())
 11171  	}
 11172  
 11173  	// check the output, as those can't cause an error planning the value
 11174  	out = state.RootModule().OutputValues["out"].Value.AsString()
 11175  	if out != "" {
 11176  		t.Fatalf(`expected output "", got: %q`, out)
 11177  	}
 11178  }
 11179  
 11180  // Ensure that we can destroy when a provider references a resource that will
 11181  // also be destroyed
 11182  func TestContext2Apply_destroyProviderReference(t *testing.T) {
 11183  	m := testModuleInline(t, map[string]string{
 11184  		"main.tf": `
 11185  provider "null" {
 11186    value = ""
 11187  }
 11188  
 11189  module "mod" {
 11190    source = "./mod"
 11191  }
 11192  
 11193  provider "test" {
 11194    value = module.mod.output
 11195  }
 11196  
 11197  resource "test_instance" "bar" {
 11198  }
 11199  `,
 11200  		"mod/main.tf": `
 11201  data "null_data_source" "foo" {
 11202         count = 1
 11203  }
 11204  
 11205  
 11206  output "output" {
 11207    value = data.null_data_source.foo[0].output
 11208  }
 11209  `})
 11210  
 11211  	schemaFn := func(name string) *ProviderSchema {
 11212  		return &ProviderSchema{
 11213  			Provider: &configschema.Block{
 11214  				Attributes: map[string]*configschema.Attribute{
 11215  					"value": {
 11216  						Type:     cty.String,
 11217  						Required: true,
 11218  					},
 11219  				},
 11220  			},
 11221  			ResourceTypes: map[string]*configschema.Block{
 11222  				name + "_instance": {
 11223  					Attributes: map[string]*configschema.Attribute{
 11224  						"id": {
 11225  							Type:     cty.String,
 11226  							Computed: true,
 11227  						},
 11228  						"foo": {
 11229  							Type:     cty.String,
 11230  							Optional: true,
 11231  						},
 11232  					},
 11233  				},
 11234  			},
 11235  			DataSources: map[string]*configschema.Block{
 11236  				name + "_data_source": {
 11237  					Attributes: map[string]*configschema.Attribute{
 11238  						"id": {
 11239  							Type:     cty.String,
 11240  							Computed: true,
 11241  						},
 11242  						"output": {
 11243  							Type:     cty.String,
 11244  							Computed: true,
 11245  						},
 11246  					},
 11247  				},
 11248  			},
 11249  		}
 11250  	}
 11251  
 11252  	testP := new(MockProvider)
 11253  	testP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11254  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11255  	}
 11256  	testP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("test"))
 11257  
 11258  	providerConfig := ""
 11259  	testP.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
 11260  		value := req.Config.GetAttr("value")
 11261  		if value.IsKnown() && !value.IsNull() {
 11262  			providerConfig = value.AsString()
 11263  		} else {
 11264  			providerConfig = ""
 11265  		}
 11266  		return resp
 11267  	}
 11268  	testP.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 11269  		if providerConfig != "valid" {
 11270  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provider config is %q", providerConfig))
 11271  			return
 11272  		}
 11273  		return testApplyFn(req)
 11274  	}
 11275  	testP.PlanResourceChangeFn = testDiffFn
 11276  
 11277  	nullP := new(MockProvider)
 11278  	nullP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11279  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11280  	}
 11281  	nullP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("null"))
 11282  
 11283  	nullP.ApplyResourceChangeFn = testApplyFn
 11284  	nullP.PlanResourceChangeFn = testDiffFn
 11285  
 11286  	nullP.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 11287  		State: cty.ObjectVal(map[string]cty.Value{
 11288  			"id":     cty.StringVal("ID"),
 11289  			"output": cty.StringVal("valid"),
 11290  		}),
 11291  	}
 11292  
 11293  	ctx := testContext2(t, &ContextOpts{
 11294  		Providers: map[addrs.Provider]providers.Factory{
 11295  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP),
 11296  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP),
 11297  		},
 11298  	})
 11299  
 11300  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11301  	assertNoErrors(t, diags)
 11302  
 11303  	state, diags := ctx.Apply(plan, m)
 11304  	if diags.HasErrors() {
 11305  		t.Fatalf("apply errors: %s", diags.Err())
 11306  	}
 11307  
 11308  	ctx = testContext2(t, &ContextOpts{
 11309  		Providers: map[addrs.Provider]providers.Factory{
 11310  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP),
 11311  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP),
 11312  		},
 11313  	})
 11314  
 11315  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11316  		Mode: plans.DestroyMode,
 11317  	})
 11318  	assertNoErrors(t, diags)
 11319  
 11320  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
 11321  		t.Fatalf("destroy apply errors: %s", diags.Err())
 11322  	}
 11323  }
 11324  
 11325  // Destroying properly requires pruning out all unneeded config nodes to
 11326  // prevent incorrect expansion evaluation.
 11327  func TestContext2Apply_destroyInterModuleExpansion(t *testing.T) {
 11328  	m := testModuleInline(t, map[string]string{
 11329  		"main.tf": `
 11330  data "test_data_source" "a" {
 11331    for_each = {
 11332      one = "thing"
 11333    }
 11334  }
 11335  
 11336  locals {
 11337    module_input = {
 11338      for k, v in data.test_data_source.a : k => v.id
 11339    }
 11340  }
 11341  
 11342  module "mod1" {
 11343    source = "./mod"
 11344    input = local.module_input
 11345  }
 11346  
 11347  module "mod2" {
 11348    source = "./mod"
 11349    input = module.mod1.outputs
 11350  }
 11351  
 11352  resource "test_instance" "bar" {
 11353    for_each = module.mod2.outputs
 11354  }
 11355  
 11356  output "module_output" {
 11357    value = module.mod2.outputs
 11358  }
 11359  output "test_instances" {
 11360    value = test_instance.bar
 11361  }
 11362  `,
 11363  		"mod/main.tf": `
 11364  variable "input" {
 11365  }
 11366  
 11367  data "test_data_source" "foo" {
 11368    for_each = var.input
 11369  }
 11370  
 11371  output "outputs" {
 11372    value = data.test_data_source.foo
 11373  }
 11374  `})
 11375  
 11376  	p := testProvider("test")
 11377  	p.PlanResourceChangeFn = testDiffFn
 11378  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 11379  		return providers.ReadDataSourceResponse{
 11380  			State: cty.ObjectVal(map[string]cty.Value{
 11381  				"id":  cty.StringVal("data_source"),
 11382  				"foo": cty.StringVal("output"),
 11383  			}),
 11384  		}
 11385  	}
 11386  
 11387  	ctx := testContext2(t, &ContextOpts{
 11388  		Providers: map[addrs.Provider]providers.Factory{
 11389  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11390  		},
 11391  	})
 11392  
 11393  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11394  	assertNoErrors(t, diags)
 11395  
 11396  	state, diags := ctx.Apply(plan, m)
 11397  	if diags.HasErrors() {
 11398  		t.Fatalf("apply errors: %s", diags.Err())
 11399  	}
 11400  
 11401  	destroy := func() {
 11402  		ctx = testContext2(t, &ContextOpts{
 11403  			Providers: map[addrs.Provider]providers.Factory{
 11404  				addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11405  			},
 11406  		})
 11407  
 11408  		plan, diags = ctx.Plan(m, state, &PlanOpts{
 11409  			Mode: plans.DestroyMode,
 11410  		})
 11411  		assertNoErrors(t, diags)
 11412  
 11413  		state, diags = ctx.Apply(plan, m)
 11414  		if diags.HasErrors() {
 11415  			t.Fatalf("destroy apply errors: %s", diags.Err())
 11416  		}
 11417  	}
 11418  
 11419  	destroy()
 11420  	// Destroying again from the empty state should not cause any errors either
 11421  	destroy()
 11422  }
 11423  
 11424  func TestContext2Apply_createBeforeDestroyWithModule(t *testing.T) {
 11425  	m := testModuleInline(t, map[string]string{
 11426  		"main.tf": `
 11427  variable "v" {}
 11428  
 11429  module "mod" {
 11430      source = "./mod"
 11431      in = var.v
 11432  }
 11433  
 11434  resource "test_resource" "a" {
 11435    value = var.v
 11436    depends_on = [module.mod]
 11437    lifecycle {
 11438      create_before_destroy = true
 11439    }
 11440  }
 11441  `,
 11442  		"mod/main.tf": `
 11443  variable "in" {}
 11444  
 11445  resource "test_resource" "a" {
 11446    value = var.in
 11447  }
 11448  `})
 11449  
 11450  	p := testProvider("test")
 11451  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
 11452  		proposed := req.ProposedNewState.AsValueMap()
 11453  		proposed["id"] = cty.UnknownVal(cty.String)
 11454  		return providers.PlanResourceChangeResponse{
 11455  			PlannedState:    cty.ObjectVal(proposed),
 11456  			RequiresReplace: []cty.Path{{cty.GetAttrStep{Name: "value"}}},
 11457  		}
 11458  	}
 11459  
 11460  	ctx := testContext2(t, &ContextOpts{
 11461  		Providers: map[addrs.Provider]providers.Factory{
 11462  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11463  		},
 11464  	})
 11465  
 11466  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11467  		Mode: plans.NormalMode,
 11468  		SetVariables: InputValues{
 11469  			"v": &InputValue{
 11470  				Value: cty.StringVal("A"),
 11471  			},
 11472  		},
 11473  	})
 11474  	assertNoErrors(t, diags)
 11475  
 11476  	state, diags := ctx.Apply(plan, m)
 11477  	if diags.HasErrors() {
 11478  		t.Fatalf("apply errors: %s", diags.Err())
 11479  	}
 11480  
 11481  	ctx = testContext2(t, &ContextOpts{
 11482  		Providers: map[addrs.Provider]providers.Factory{
 11483  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11484  		},
 11485  	})
 11486  
 11487  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11488  		Mode: plans.NormalMode,
 11489  		SetVariables: InputValues{
 11490  			"v": &InputValue{
 11491  				Value: cty.StringVal("B"),
 11492  			},
 11493  		},
 11494  	})
 11495  	assertNoErrors(t, diags)
 11496  
 11497  	_, diags = ctx.Apply(plan, m)
 11498  	if diags.HasErrors() {
 11499  		t.Fatalf("apply errors: %s", diags.Err())
 11500  	}
 11501  }
 11502  
 11503  func TestContext2Apply_forcedCBD(t *testing.T) {
 11504  	m := testModuleInline(t, map[string]string{
 11505  		"main.tf": `
 11506  variable "v" {}
 11507  
 11508  resource "test_instance" "a" {
 11509    require_new = var.v
 11510  }
 11511  
 11512  resource "test_instance" "b" {
 11513    depends_on = [test_instance.a]
 11514    lifecycle {
 11515      create_before_destroy = true
 11516    }
 11517  }
 11518  `})
 11519  
 11520  	p := testProvider("test")
 11521  	p.PlanResourceChangeFn = testDiffFn
 11522  
 11523  	ctx := testContext2(t, &ContextOpts{
 11524  		Providers: map[addrs.Provider]providers.Factory{
 11525  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11526  		},
 11527  	})
 11528  
 11529  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11530  		Mode: plans.NormalMode,
 11531  		SetVariables: InputValues{
 11532  			"v": &InputValue{
 11533  				Value: cty.StringVal("A"),
 11534  			},
 11535  		},
 11536  	})
 11537  	assertNoErrors(t, diags)
 11538  
 11539  	state, diags := ctx.Apply(plan, m)
 11540  	if diags.HasErrors() {
 11541  		t.Fatalf("apply errors: %s", diags.Err())
 11542  	}
 11543  
 11544  	ctx = testContext2(t, &ContextOpts{
 11545  		Providers: map[addrs.Provider]providers.Factory{
 11546  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11547  		},
 11548  	})
 11549  
 11550  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11551  		Mode: plans.NormalMode,
 11552  		SetVariables: InputValues{
 11553  			"v": &InputValue{
 11554  				Value: cty.StringVal("B"),
 11555  			},
 11556  		},
 11557  	})
 11558  	assertNoErrors(t, diags)
 11559  
 11560  	_, diags = ctx.Apply(plan, m)
 11561  	if diags.HasErrors() {
 11562  		t.Fatalf("apply errors: %s", diags.Err())
 11563  	}
 11564  }
 11565  
 11566  func TestContext2Apply_removeReferencedResource(t *testing.T) {
 11567  	m := testModuleInline(t, map[string]string{
 11568  		"main.tf": `
 11569  variable "ct" {
 11570  }
 11571  
 11572  resource "test_resource" "to_remove" {
 11573    count = var.ct
 11574  }
 11575  
 11576  resource "test_resource" "c" {
 11577    value = join("", test_resource.to_remove[*].id)
 11578  }
 11579  `})
 11580  
 11581  	p := testProvider("test")
 11582  	p.PlanResourceChangeFn = testDiffFn
 11583  
 11584  	ctx := testContext2(t, &ContextOpts{
 11585  		Providers: map[addrs.Provider]providers.Factory{
 11586  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11587  		},
 11588  	})
 11589  
 11590  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11591  		Mode: plans.NormalMode,
 11592  		SetVariables: InputValues{
 11593  			"ct": &InputValue{
 11594  				Value: cty.NumberIntVal(1),
 11595  			},
 11596  		},
 11597  	})
 11598  	assertNoErrors(t, diags)
 11599  
 11600  	state, diags := ctx.Apply(plan, m)
 11601  	if diags.HasErrors() {
 11602  		t.Fatalf("apply errors: %s", diags.Err())
 11603  	}
 11604  
 11605  	ctx = testContext2(t, &ContextOpts{
 11606  		Providers: map[addrs.Provider]providers.Factory{
 11607  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11608  		},
 11609  	})
 11610  
 11611  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11612  		Mode: plans.NormalMode,
 11613  		SetVariables: InputValues{
 11614  			"ct": &InputValue{
 11615  				Value: cty.NumberIntVal(0),
 11616  			},
 11617  		},
 11618  	})
 11619  	assertNoErrors(t, diags)
 11620  
 11621  	_, diags = ctx.Apply(plan, m)
 11622  	if diags.HasErrors() {
 11623  		t.Fatalf("apply errors: %s", diags.Err())
 11624  	}
 11625  }
 11626  
 11627  func TestContext2Apply_variableSensitivity(t *testing.T) {
 11628  	m := testModuleInline(t, map[string]string{
 11629  		"main.tf": `
 11630  variable "sensitive_var" {
 11631  	default = "foo"
 11632  	sensitive = true
 11633  }
 11634  
 11635  variable "sensitive_id" {
 11636  	default = "secret id"
 11637  	sensitive = true
 11638  }
 11639  
 11640  resource "test_resource" "foo" {
 11641  	value   = var.sensitive_var
 11642  
 11643  	network_interface {
 11644  		network_interface_id = var.sensitive_id
 11645  	}
 11646  }`,
 11647  	})
 11648  
 11649  	p := new(MockProvider)
 11650  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11651  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11652  	}
 11653  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
 11654  		Provider: &configschema.Block{},
 11655  		ResourceTypes: map[string]*configschema.Block{
 11656  			"test_resource": {
 11657  				Attributes: map[string]*configschema.Attribute{
 11658  					"id": {
 11659  						Type:     cty.String,
 11660  						Computed: true,
 11661  					},
 11662  					"value": {
 11663  						Type:     cty.String,
 11664  						Optional: true,
 11665  						Computed: true,
 11666  					},
 11667  				},
 11668  				BlockTypes: map[string]*configschema.NestedBlock{
 11669  					"network_interface": {
 11670  						Block: configschema.Block{
 11671  							Attributes: map[string]*configschema.Attribute{
 11672  								"network_interface_id": {Type: cty.String, Optional: true},
 11673  								"device_index":         {Type: cty.Number, Optional: true},
 11674  							},
 11675  						},
 11676  						Nesting: configschema.NestingSet,
 11677  					},
 11678  				},
 11679  			},
 11680  		},
 11681  	})
 11682  	p.PlanResourceChangeFn = testDiffFn
 11683  
 11684  	ctx := testContext2(t, &ContextOpts{
 11685  		Providers: map[addrs.Provider]providers.Factory{
 11686  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11687  		},
 11688  	})
 11689  
 11690  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11691  	assertNoErrors(t, diags)
 11692  
 11693  	state, diags := ctx.Apply(plan, m)
 11694  	if diags.HasErrors() {
 11695  		t.Fatalf("apply errors: %s", diags.Err())
 11696  	}
 11697  
 11698  	// Run a second apply with no changes
 11699  	ctx = testContext2(t, &ContextOpts{
 11700  		Providers: map[addrs.Provider]providers.Factory{
 11701  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11702  		},
 11703  	})
 11704  
 11705  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
 11706  	assertNoErrors(t, diags)
 11707  
 11708  	state, diags = ctx.Apply(plan, m)
 11709  	if diags.HasErrors() {
 11710  		t.Fatalf("apply errors: %s", diags.Err())
 11711  	}
 11712  
 11713  	// Now change the variable value for sensitive_var
 11714  	ctx = testContext2(t, &ContextOpts{
 11715  		Providers: map[addrs.Provider]providers.Factory{
 11716  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11717  		},
 11718  	})
 11719  
 11720  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11721  		Mode: plans.NormalMode,
 11722  		SetVariables: InputValues{
 11723  			"sensitive_var": &InputValue{
 11724  				Value: cty.StringVal("bar"),
 11725  			},
 11726  		},
 11727  	})
 11728  	assertNoErrors(t, diags)
 11729  
 11730  	_, diags = ctx.Apply(plan, m)
 11731  	if diags.HasErrors() {
 11732  		t.Fatalf("apply errors: %s", diags.Err())
 11733  	}
 11734  }
 11735  
 11736  func TestContext2Apply_variableSensitivityPropagation(t *testing.T) {
 11737  	m := testModuleInline(t, map[string]string{
 11738  		"main.tf": `
 11739  variable "sensitive_map" {
 11740  	type = map(string)
 11741  	default = {
 11742  		"x" = "foo"
 11743  	}
 11744  	sensitive = true
 11745  }
 11746  
 11747  resource "test_resource" "foo" {
 11748  	value = var.sensitive_map.x
 11749  }
 11750  `,
 11751  	})
 11752  
 11753  	p := testProvider("test")
 11754  	p.PlanResourceChangeFn = testDiffFn
 11755  
 11756  	ctx := testContext2(t, &ContextOpts{
 11757  		Providers: map[addrs.Provider]providers.Factory{
 11758  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11759  		},
 11760  	})
 11761  
 11762  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11763  	if diags.HasErrors() {
 11764  		t.Fatalf("plan errors: %s", diags.Err())
 11765  	}
 11766  
 11767  	verifySensitiveValue := func(pvms []cty.PathValueMarks) {
 11768  		if len(pvms) != 1 {
 11769  			t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 11770  		}
 11771  		pvm := pvms[0]
 11772  		if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) {
 11773  			t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 11774  		}
 11775  		if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 11776  			t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 11777  		}
 11778  	}
 11779  
 11780  	addr := mustResourceInstanceAddr("test_resource.foo")
 11781  	fooChangeSrc := plan.Changes.ResourceInstance(addr)
 11782  	verifySensitiveValue(fooChangeSrc.AfterValMarks)
 11783  
 11784  	state, diags := ctx.Apply(plan, m)
 11785  	if diags.HasErrors() {
 11786  		t.Fatalf("apply errors: %s", diags.Err())
 11787  	}
 11788  
 11789  	fooState := state.ResourceInstance(addr)
 11790  	verifySensitiveValue(fooState.Current.AttrSensitivePaths)
 11791  }
 11792  
 11793  func TestContext2Apply_variableSensitivityProviders(t *testing.T) {
 11794  	m := testModuleInline(t, map[string]string{
 11795  		"main.tf": `
 11796  resource "test_resource" "foo" {
 11797  	sensitive_value = "should get marked"
 11798  }
 11799  
 11800  resource "test_resource" "bar" {
 11801  	value  = test_resource.foo.sensitive_value
 11802  	random = test_resource.foo.id # not sensitive
 11803  
 11804  	nesting_single {
 11805  		value           = "abc"
 11806  		sensitive_value = "xyz"
 11807  	}
 11808  }
 11809  
 11810  resource "test_resource" "baz" {
 11811  	value = test_resource.bar.nesting_single.sensitive_value
 11812  }
 11813  `,
 11814  	})
 11815  
 11816  	p := testProvider("test")
 11817  	p.PlanResourceChangeFn = testDiffFn
 11818  
 11819  	ctx := testContext2(t, &ContextOpts{
 11820  		Providers: map[addrs.Provider]providers.Factory{
 11821  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11822  		},
 11823  	})
 11824  
 11825  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11826  	if diags.HasErrors() {
 11827  		t.Fatalf("plan errors: %s", diags.Err())
 11828  	}
 11829  
 11830  	verifySensitiveValue := func(pvms []cty.PathValueMarks) {
 11831  		if len(pvms) != 1 {
 11832  			t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 11833  		}
 11834  		pvm := pvms[0]
 11835  		if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) {
 11836  			t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 11837  		}
 11838  		if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 11839  			t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 11840  		}
 11841  	}
 11842  
 11843  	// Sensitive attributes (defined by the provider) are marked
 11844  	// as sensitive when referenced from another resource
 11845  	// "bar" references sensitive resources in "foo"
 11846  	barAddr := mustResourceInstanceAddr("test_resource.bar")
 11847  	barChangeSrc := plan.Changes.ResourceInstance(barAddr)
 11848  	verifySensitiveValue(barChangeSrc.AfterValMarks)
 11849  
 11850  	bazAddr := mustResourceInstanceAddr("test_resource.baz")
 11851  	bazChangeSrc := plan.Changes.ResourceInstance(bazAddr)
 11852  	verifySensitiveValue(bazChangeSrc.AfterValMarks)
 11853  
 11854  	state, diags := ctx.Apply(plan, m)
 11855  	if diags.HasErrors() {
 11856  		t.Fatalf("apply errors: %s", diags.Err())
 11857  	}
 11858  
 11859  	barState := state.ResourceInstance(barAddr)
 11860  	verifySensitiveValue(barState.Current.AttrSensitivePaths)
 11861  
 11862  	bazState := state.ResourceInstance(bazAddr)
 11863  	verifySensitiveValue(bazState.Current.AttrSensitivePaths)
 11864  }
 11865  
 11866  func TestContext2Apply_variableSensitivityChange(t *testing.T) {
 11867  	m := testModuleInline(t, map[string]string{
 11868  		"main.tf": `
 11869  variable "sensitive_var" {
 11870  	default = "hello"
 11871  	sensitive = true
 11872  }
 11873  
 11874  resource "test_resource" "foo" {
 11875  	value = var.sensitive_var
 11876  }`,
 11877  	})
 11878  
 11879  	p := testProvider("test")
 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  	state := states.BuildState(func(s *states.SyncState) {
 11889  		s.SetResourceInstanceCurrent(
 11890  			addrs.Resource{
 11891  				Mode: addrs.ManagedResourceMode,
 11892  				Type: "test_resource",
 11893  				Name: "foo",
 11894  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
 11895  			&states.ResourceInstanceObjectSrc{
 11896  				Status:    states.ObjectReady,
 11897  				AttrsJSON: []byte(`{"id":"foo", "value":"hello"}`),
 11898  				// No AttrSensitivePaths present
 11899  			},
 11900  			addrs.AbsProviderConfig{
 11901  				Provider: addrs.NewDefaultProvider("test"),
 11902  				Module:   addrs.RootModule,
 11903  			},
 11904  		)
 11905  	})
 11906  
 11907  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
 11908  	assertNoErrors(t, diags)
 11909  
 11910  	addr := mustResourceInstanceAddr("test_resource.foo")
 11911  
 11912  	state, diags = ctx.Apply(plan, m)
 11913  	assertNoErrors(t, diags)
 11914  
 11915  	fooState := state.ResourceInstance(addr)
 11916  
 11917  	if len(fooState.Current.AttrSensitivePaths) != 1 {
 11918  		t.Fatalf("wrong number of sensitive paths, expected 1, got, %v", len(fooState.Current.AttrSensitivePaths))
 11919  	}
 11920  	got := fooState.Current.AttrSensitivePaths[0]
 11921  	want := cty.PathValueMarks{
 11922  		Path:  cty.GetAttrPath("value"),
 11923  		Marks: cty.NewValueMarks(marks.Sensitive),
 11924  	}
 11925  
 11926  	if !got.Equal(want) {
 11927  		t.Fatalf("wrong value marks; got:\n%#v\n\nwant:\n%#v\n", got, want)
 11928  	}
 11929  
 11930  	m2 := testModuleInline(t, map[string]string{
 11931  		"main.tf": `
 11932  variable "sensitive_var" {
 11933  	default = "hello"
 11934  	sensitive = false
 11935  }
 11936  
 11937  resource "test_resource" "foo" {
 11938  	value = var.sensitive_var
 11939  }`,
 11940  	})
 11941  
 11942  	ctx2 := testContext2(t, &ContextOpts{
 11943  		Providers: map[addrs.Provider]providers.Factory{
 11944  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11945  		},
 11946  	})
 11947  
 11948  	// NOTE: Prior to our refactoring to make the state an explicit argument
 11949  	// of Plan, as opposed to hidden state inside Context, this test was
 11950  	// calling ctx.Apply instead of ctx2.Apply and thus using the previous
 11951  	// plan instead of this new plan. "Fixing" it to use the new plan seems
 11952  	// to break the test, so we've preserved that oddity here by saving the
 11953  	// old plan as oldPlan and essentially discarding the new plan entirely,
 11954  	// but this seems rather suspicious and we should ideally figure out what
 11955  	// this test was originally intending to do and make it do that.
 11956  	oldPlan := plan
 11957  	_, diags = ctx2.Plan(m2, state, DefaultPlanOpts)
 11958  	assertNoErrors(t, diags)
 11959  	stateWithoutSensitive, diags := ctx.Apply(oldPlan, m)
 11960  	assertNoErrors(t, diags)
 11961  
 11962  	fooState2 := stateWithoutSensitive.ResourceInstance(addr)
 11963  	if len(fooState2.Current.AttrSensitivePaths) > 0 {
 11964  		t.Fatalf(
 11965  			"wrong number of sensitive paths, expected 0, got, %v\n%s",
 11966  			len(fooState2.Current.AttrSensitivePaths),
 11967  			spew.Sdump(fooState2.Current.AttrSensitivePaths),
 11968  		)
 11969  	}
 11970  }
 11971  
 11972  func TestContext2Apply_moduleVariableOptionalAttributes(t *testing.T) {
 11973  	m := testModuleInline(t, map[string]string{
 11974  		"main.tf": `
 11975  terraform {
 11976    experiments = [module_variable_optional_attrs]
 11977  }
 11978  
 11979  variable "in" {
 11980    type = object({
 11981  	required = string
 11982  	optional = optional(string)
 11983    })
 11984  }
 11985  
 11986  output "out" {
 11987    value = var.in
 11988  }
 11989  `})
 11990  
 11991  	ctx := testContext2(t, &ContextOpts{})
 11992  
 11993  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11994  		Mode: plans.NormalMode,
 11995  		SetVariables: InputValues{
 11996  			"in": &InputValue{
 11997  				Value: cty.MapVal(map[string]cty.Value{
 11998  					"required": cty.StringVal("boop"),
 11999  				}),
 12000  				SourceType: ValueFromCaller,
 12001  			},
 12002  		},
 12003  	})
 12004  	if diags.HasErrors() {
 12005  		t.Fatal(diags.ErrWithWarnings())
 12006  	}
 12007  
 12008  	state, diags := ctx.Apply(plan, m)
 12009  	if diags.HasErrors() {
 12010  		t.Fatal(diags.ErrWithWarnings())
 12011  	}
 12012  
 12013  	got := state.RootModule().OutputValues["out"].Value
 12014  	want := cty.ObjectVal(map[string]cty.Value{
 12015  		"required": cty.StringVal("boop"),
 12016  
 12017  		// Because "optional" was marked as optional, it got silently filled
 12018  		// in as a null value of string type rather than returning an error.
 12019  		"optional": cty.NullVal(cty.String),
 12020  	})
 12021  	if !want.RawEquals(got) {
 12022  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
 12023  	}
 12024  }
 12025  
 12026  func TestContext2Apply_provisionerSensitive(t *testing.T) {
 12027  	m := testModule(t, "apply-provisioner-sensitive")
 12028  	p := testProvider("aws")
 12029  
 12030  	pr := testProvisioner()
 12031  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
 12032  		if req.Config.ContainsMarked() {
 12033  			t.Fatalf("unexpectedly marked config value: %#v", req.Config)
 12034  		}
 12035  		command := req.Config.GetAttr("command")
 12036  		if command.IsMarked() {
 12037  			t.Fatalf("unexpectedly marked command argument: %#v", command.Marks())
 12038  		}
 12039  		req.UIOutput.Output(fmt.Sprintf("Executing: %q", command.AsString()))
 12040  		return
 12041  	}
 12042  	p.PlanResourceChangeFn = testDiffFn
 12043  	p.ApplyResourceChangeFn = testApplyFn
 12044  
 12045  	h := new(MockHook)
 12046  	ctx := testContext2(t, &ContextOpts{
 12047  		Hooks: []Hook{h},
 12048  		Providers: map[addrs.Provider]providers.Factory{
 12049  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 12050  		},
 12051  		Provisioners: map[string]provisioners.Factory{
 12052  			"shell": testProvisionerFuncFixed(pr),
 12053  		},
 12054  	})
 12055  
 12056  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 12057  		Mode: plans.NormalMode,
 12058  		SetVariables: InputValues{
 12059  			"password": &InputValue{
 12060  				Value:      cty.StringVal("secret"),
 12061  				SourceType: ValueFromCaller,
 12062  			},
 12063  		},
 12064  	})
 12065  	assertNoErrors(t, diags)
 12066  
 12067  	// "restart" provisioner
 12068  	pr.CloseCalled = false
 12069  
 12070  	state, diags := ctx.Apply(plan, m)
 12071  	if diags.HasErrors() {
 12072  		logDiagnostics(t, diags)
 12073  		t.Fatal("apply failed")
 12074  	}
 12075  
 12076  	actual := strings.TrimSpace(state.String())
 12077  	expected := strings.TrimSpace(testTerraformApplyProvisionerSensitiveStr)
 12078  	if actual != expected {
 12079  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
 12080  	}
 12081  
 12082  	// Verify apply was invoked
 12083  	if !pr.ProvisionResourceCalled {
 12084  		t.Fatalf("provisioner was not called on apply")
 12085  	}
 12086  
 12087  	// Verify output was suppressed
 12088  	if !h.ProvisionOutputCalled {
 12089  		t.Fatalf("ProvisionOutput hook not called")
 12090  	}
 12091  	if got, doNotWant := h.ProvisionOutputMessage, "secret"; strings.Contains(got, doNotWant) {
 12092  		t.Errorf("sensitive value %q included in output:\n%s", doNotWant, got)
 12093  	}
 12094  	if got, want := h.ProvisionOutputMessage, "output suppressed"; !strings.Contains(got, want) {
 12095  		t.Errorf("expected hook to be called with %q, but was:\n%s", want, got)
 12096  	}
 12097  }
 12098  
 12099  func TestContext2Apply_warnings(t *testing.T) {
 12100  	m := testModuleInline(t, map[string]string{
 12101  		"main.tf": `
 12102  resource "test_resource" "foo" {
 12103  }`,
 12104  	})
 12105  
 12106  	p := testProvider("test")
 12107  	p.PlanResourceChangeFn = testDiffFn
 12108  
 12109  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
 12110  		resp := testApplyFn(req)
 12111  
 12112  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warning"))
 12113  		return resp
 12114  	}
 12115  
 12116  	ctx := testContext2(t, &ContextOpts{
 12117  		Providers: map[addrs.Provider]providers.Factory{
 12118  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12119  		},
 12120  	})
 12121  
 12122  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12123  	assertNoErrors(t, diags)
 12124  
 12125  	state, diags := ctx.Apply(plan, m)
 12126  	if diags.HasErrors() {
 12127  		t.Fatalf("diags: %s", diags.Err())
 12128  	}
 12129  
 12130  	inst := state.ResourceInstance(mustResourceInstanceAddr("test_resource.foo"))
 12131  	if inst == nil {
 12132  		t.Fatal("missing 'test_resource.foo' in state:", state)
 12133  	}
 12134  }
 12135  
 12136  func TestContext2Apply_rpcDiagnostics(t *testing.T) {
 12137  	m := testModuleInline(t, map[string]string{
 12138  		"main.tf": `
 12139  resource "test_instance" "a" {
 12140  }
 12141  `,
 12142  	})
 12143  
 12144  	p := testProvider("test")
 12145  	p.PlanResourceChangeFn = testDiffFn
 12146  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 12147  		resp = testApplyFn(req)
 12148  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("don't frobble"))
 12149  		return resp
 12150  	}
 12151  
 12152  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
 12153  		ResourceTypes: map[string]*configschema.Block{
 12154  			"test_instance": {
 12155  				Attributes: map[string]*configschema.Attribute{
 12156  					"id": {Type: cty.String, Computed: true},
 12157  				},
 12158  			},
 12159  		},
 12160  	})
 12161  
 12162  	ctx := testContext2(t, &ContextOpts{
 12163  		Providers: map[addrs.Provider]providers.Factory{
 12164  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12165  		},
 12166  	})
 12167  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12168  	if diags.HasErrors() {
 12169  		t.Fatal(diags.Err())
 12170  	}
 12171  
 12172  	_, diags = ctx.Apply(plan, m)
 12173  	if diags.HasErrors() {
 12174  		t.Fatal(diags.Err())
 12175  	}
 12176  
 12177  	if len(diags) == 0 {
 12178  		t.Fatal("expected warnings")
 12179  	}
 12180  
 12181  	for _, d := range diags {
 12182  		des := d.Description().Summary
 12183  		if !strings.Contains(des, "frobble") {
 12184  			t.Fatalf(`expected frobble, got %q`, des)
 12185  		}
 12186  	}
 12187  }
 12188  
 12189  func TestContext2Apply_dataSensitive(t *testing.T) {
 12190  	m := testModule(t, "apply-data-sensitive")
 12191  	p := testProvider("null")
 12192  	p.PlanResourceChangeFn = testDiffFn
 12193  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 12194  		// add the required id
 12195  		m := req.Config.AsValueMap()
 12196  		m["id"] = cty.StringVal("foo")
 12197  
 12198  		return providers.ReadDataSourceResponse{
 12199  			State: cty.ObjectVal(m),
 12200  		}
 12201  	}
 12202  
 12203  	ctx := testContext2(t, &ContextOpts{
 12204  		Providers: map[addrs.Provider]providers.Factory{
 12205  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
 12206  		},
 12207  	})
 12208  
 12209  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12210  	if diags.HasErrors() {
 12211  		t.Fatalf("diags: %s", diags.Err())
 12212  	} else {
 12213  		t.Logf(legacyDiffComparisonString(plan.Changes))
 12214  	}
 12215  
 12216  	state, diags := ctx.Apply(plan, m)
 12217  	assertNoErrors(t, diags)
 12218  
 12219  	addr := mustResourceInstanceAddr("data.null_data_source.testing")
 12220  
 12221  	dataSourceState := state.ResourceInstance(addr)
 12222  	pvms := dataSourceState.Current.AttrSensitivePaths
 12223  	if len(pvms) != 1 {
 12224  		t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 12225  	}
 12226  	pvm := pvms[0]
 12227  	if gotPath, wantPath := pvm.Path, cty.GetAttrPath("foo"); !gotPath.Equals(wantPath) {
 12228  		t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 12229  	}
 12230  	if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 12231  		t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 12232  	}
 12233  }
 12234  
 12235  func TestContext2Apply_errorRestorePrivateData(t *testing.T) {
 12236  	// empty config to remove our resource
 12237  	m := testModuleInline(t, map[string]string{
 12238  		"main.tf": "",
 12239  	})
 12240  
 12241  	p := simpleMockProvider()
 12242  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
 12243  		// we error during apply, which will trigger core to preserve the last
 12244  		// known state, including private data
 12245  		Diagnostics: tfdiags.Diagnostics(nil).Append(errors.New("oops")),
 12246  	}
 12247  
 12248  	addr := mustResourceInstanceAddr("test_object.a")
 12249  
 12250  	state := states.BuildState(func(s *states.SyncState) {
 12251  		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
 12252  			Status:    states.ObjectReady,
 12253  			AttrsJSON: []byte(`{"id":"foo"}`),
 12254  			Private:   []byte("private"),
 12255  		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
 12256  	})
 12257  
 12258  	ctx := testContext2(t, &ContextOpts{
 12259  		Providers: map[addrs.Provider]providers.Factory{
 12260  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12261  		},
 12262  	})
 12263  
 12264  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
 12265  	if diags.HasErrors() {
 12266  		t.Fatal(diags.Err())
 12267  	}
 12268  
 12269  	state, _ = ctx.Apply(plan, m)
 12270  	if string(state.ResourceInstance(addr).Current.Private) != "private" {
 12271  		t.Fatal("missing private data in state")
 12272  	}
 12273  }
 12274  
 12275  func TestContext2Apply_errorRestoreStatus(t *testing.T) {
 12276  	// empty config to remove our resource
 12277  	m := testModuleInline(t, map[string]string{
 12278  		"main.tf": "",
 12279  	})
 12280  
 12281  	p := simpleMockProvider()
 12282  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 12283  		// We error during apply, but return the current object state.
 12284  		resp.Diagnostics = resp.Diagnostics.Append(errors.New("oops"))
 12285  		// return a warning too to make sure it isn't dropped
 12286  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warned"))
 12287  		resp.NewState = req.PriorState
 12288  		resp.Private = req.PlannedPrivate
 12289  		return resp
 12290  	}
 12291  
 12292  	addr := mustResourceInstanceAddr("test_object.a")
 12293  
 12294  	state := states.BuildState(func(s *states.SyncState) {
 12295  		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
 12296  			Status:       states.ObjectTainted,
 12297  			AttrsJSON:    []byte(`{"test_string":"foo"}`),
 12298  			Private:      []byte("private"),
 12299  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.b")},
 12300  		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
 12301  	})
 12302  
 12303  	ctx := testContext2(t, &ContextOpts{
 12304  		Providers: map[addrs.Provider]providers.Factory{
 12305  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12306  		},
 12307  	})
 12308  
 12309  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
 12310  	if diags.HasErrors() {
 12311  		t.Fatal(diags.Err())
 12312  	}
 12313  
 12314  	state, diags = ctx.Apply(plan, m)
 12315  
 12316  	errString := diags.ErrWithWarnings().Error()
 12317  	if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") {
 12318  		t.Fatalf("error missing expected info: %q", errString)
 12319  	}
 12320  
 12321  	if len(diags) != 2 {
 12322  		t.Fatalf("expected 1 error and 1 warning, got: %q", errString)
 12323  	}
 12324  
 12325  	res := state.ResourceInstance(addr)
 12326  	if res == nil {
 12327  		t.Fatal("resource was removed from state")
 12328  	}
 12329  
 12330  	if res.Current.Status != states.ObjectTainted {
 12331  		t.Fatal("resource should still be tainted in the state")
 12332  	}
 12333  
 12334  	if len(res.Current.Dependencies) != 1 || !res.Current.Dependencies[0].Equal(mustConfigResourceAddr("test_object.b")) {
 12335  		t.Fatalf("incorrect dependencies, got %q", res.Current.Dependencies)
 12336  	}
 12337  
 12338  	if string(res.Current.Private) != "private" {
 12339  		t.Fatalf("incorrect private data, got %q", res.Current.Private)
 12340  	}
 12341  }
 12342  
 12343  func TestContext2Apply_nonConformingResponse(t *testing.T) {
 12344  	// empty config to remove our resource
 12345  	m := testModuleInline(t, map[string]string{
 12346  		"main.tf": `
 12347  resource "test_object" "a" {
 12348    test_string = "x"
 12349  }
 12350  `,
 12351  	})
 12352  
 12353  	p := simpleMockProvider()
 12354  	respDiags := tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("warned"))
 12355  	respDiags = respDiags.Append(errors.New("oops"))
 12356  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
 12357  		// Don't lose these diagnostics
 12358  		Diagnostics: respDiags,
 12359  		// This state is missing required attributes, and should produce an error
 12360  		NewState: cty.ObjectVal(map[string]cty.Value{
 12361  			"test_string": cty.StringVal("x"),
 12362  		}),
 12363  	}
 12364  
 12365  	ctx := testContext2(t, &ContextOpts{
 12366  		Providers: map[addrs.Provider]providers.Factory{
 12367  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12368  		},
 12369  	})
 12370  
 12371  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12372  	if diags.HasErrors() {
 12373  		t.Fatal(diags.Err())
 12374  	}
 12375  
 12376  	_, diags = ctx.Apply(plan, m)
 12377  	errString := diags.ErrWithWarnings().Error()
 12378  	if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") {
 12379  		t.Fatalf("error missing expected info: %q", errString)
 12380  	}
 12381  
 12382  	// we should have more than the ones returned from the provider, and they
 12383  	// should not be coalesced into a single value
 12384  	if len(diags) < 3 {
 12385  		t.Fatalf("incorrect diagnostics, got %d values with %s", len(diags), diags.ErrWithWarnings())
 12386  	}
 12387  }
 12388  
 12389  func TestContext2Apply_nilResponse(t *testing.T) {
 12390  	// empty config to remove our resource
 12391  	m := testModuleInline(t, map[string]string{
 12392  		"main.tf": `
 12393  resource "test_object" "a" {
 12394  }
 12395  `,
 12396  	})
 12397  
 12398  	p := simpleMockProvider()
 12399  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{}
 12400  
 12401  	ctx := testContext2(t, &ContextOpts{
 12402  		Providers: map[addrs.Provider]providers.Factory{
 12403  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12404  		},
 12405  	})
 12406  
 12407  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12408  	if diags.HasErrors() {
 12409  		t.Fatal(diags.Err())
 12410  	}
 12411  
 12412  	_, diags = ctx.Apply(plan, m)
 12413  	if !diags.HasErrors() {
 12414  		t.Fatal("expected and error")
 12415  	}
 12416  
 12417  	errString := diags.ErrWithWarnings().Error()
 12418  	if !strings.Contains(errString, "invalid nil value") {
 12419  		t.Fatalf("error missing expected info: %q", errString)
 12420  	}
 12421  }
 12422  
 12423  ////////////////////////////////////////////////////////////////////////////////
 12424  // NOTE: Due to the size of this file, new tests should be added to
 12425  // context_apply2_test.go.
 12426  ////////////////////////////////////////////////////////////////////////////////