github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/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/zclconf/go-cty/cty"
    22  	"github.com/zclconf/go-cty/cty/gocty"
    23  
    24  	"github.com/hashicorp/terraform/internal/addrs"
    25  	"github.com/hashicorp/terraform/internal/configs"
    26  	"github.com/hashicorp/terraform/internal/configs/configschema"
    27  	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
    28  	"github.com/hashicorp/terraform/internal/lang/marks"
    29  	"github.com/hashicorp/terraform/internal/plans"
    30  	"github.com/hashicorp/terraform/internal/providers"
    31  	"github.com/hashicorp/terraform/internal/provisioners"
    32  	"github.com/hashicorp/terraform/internal/states"
    33  	"github.com/hashicorp/terraform/internal/tfdiags"
    34  )
    35  
    36  func TestContext2Apply_basic(t *testing.T) {
    37  	m := testModule(t, "apply-good")
    38  	p := testProvider("aws")
    39  	p.PlanResourceChangeFn = testDiffFn
    40  	p.ApplyResourceChangeFn = testApplyFn
    41  	ctx := testContext2(t, &ContextOpts{
    42  		Providers: map[addrs.Provider]providers.Factory{
    43  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
    44  		},
    45  	})
    46  
    47  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
    48  	assertNoErrors(t, diags)
    49  
    50  	state, diags := ctx.Apply(plan, m)
    51  	if diags.HasErrors() {
    52  		t.Fatalf("diags: %s", diags.Err())
    53  	}
    54  
    55  	mod := state.RootModule()
    56  	if len(mod.Resources) < 2 {
    57  		t.Fatalf("bad: %#v", mod.Resources)
    58  	}
    59  
    60  	actual := strings.TrimSpace(state.String())
    61  	expected := strings.TrimSpace(testTerraformApplyStr)
    62  	if actual != expected {
    63  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
    64  	}
    65  }
    66  
    67  func TestContext2Apply_unstable(t *testing.T) {
    68  	// This tests behavior when the configuration contains an unstable value,
    69  	// such as the result of uuid() or timestamp(), where each call produces
    70  	// a different result.
    71  	//
    72  	// This is an important case to test because we need to ensure that
    73  	// we don't re-call the function during the apply phase: the value should
    74  	// be fixed during plan
    75  
    76  	m := testModule(t, "apply-unstable")
    77  	p := testProvider("test")
    78  	p.PlanResourceChangeFn = testDiffFn
    79  	ctx := testContext2(t, &ContextOpts{
    80  		Providers: map[addrs.Provider]providers.Factory{
    81  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
    82  		},
    83  	})
    84  
    85  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
    86  	if diags.HasErrors() {
    87  		t.Fatalf("unexpected error during Plan: %s", diags.Err())
    88  	}
    89  
    90  	addr := addrs.Resource{
    91  		Mode: addrs.ManagedResourceMode,
    92  		Type: "test_resource",
    93  		Name: "foo",
    94  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
    95  	schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
    96  	rds := plan.Changes.ResourceInstance(addr)
    97  	rd, err := rds.Decode(schema.ImpliedType())
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  	if rd.After.GetAttr("random").IsKnown() {
   102  		t.Fatalf("Attribute 'random' has known value %#v; should be unknown in plan", rd.After.GetAttr("random"))
   103  	}
   104  
   105  	state, diags := ctx.Apply(plan, m)
   106  	if diags.HasErrors() {
   107  		t.Fatalf("unexpected error during Apply: %s", diags.Err())
   108  	}
   109  
   110  	mod := state.Module(addr.Module)
   111  	rss := state.ResourceInstance(addr)
   112  
   113  	if len(mod.Resources) != 1 {
   114  		t.Fatalf("wrong number of resources %d; want 1", len(mod.Resources))
   115  	}
   116  
   117  	rs, err := rss.Current.Decode(schema.ImpliedType())
   118  	if err != nil {
   119  		t.Fatalf("decode error: %v", err)
   120  	}
   121  	got := rs.Value.GetAttr("random")
   122  	if !got.IsKnown() {
   123  		t.Fatalf("random is still unknown after apply")
   124  	}
   125  	if got, want := len(got.AsString()), 36; got != want {
   126  		t.Fatalf("random string has wrong length %d; want %d", got, want)
   127  	}
   128  }
   129  
   130  func TestContext2Apply_escape(t *testing.T) {
   131  	m := testModule(t, "apply-escape")
   132  	p := testProvider("aws")
   133  	p.PlanResourceChangeFn = testDiffFn
   134  	p.ApplyResourceChangeFn = testApplyFn
   135  	ctx := testContext2(t, &ContextOpts{
   136  		Providers: map[addrs.Provider]providers.Factory{
   137  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   138  		},
   139  	})
   140  
   141  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   142  	assertNoErrors(t, diags)
   143  
   144  	state, diags := ctx.Apply(plan, m)
   145  	if diags.HasErrors() {
   146  		t.Fatalf("diags: %s", diags.Err())
   147  	}
   148  
   149  	checkStateString(t, state, `
   150  aws_instance.bar:
   151    ID = foo
   152    provider = provider["registry.terraform.io/hashicorp/aws"]
   153    foo = "bar"
   154    type = aws_instance
   155  `)
   156  }
   157  
   158  func TestContext2Apply_resourceCountOneList(t *testing.T) {
   159  	m := testModule(t, "apply-resource-count-one-list")
   160  	p := testProvider("null")
   161  	p.PlanResourceChangeFn = testDiffFn
   162  	p.ApplyResourceChangeFn = testApplyFn
   163  	ctx := testContext2(t, &ContextOpts{
   164  		Providers: map[addrs.Provider]providers.Factory{
   165  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   166  		},
   167  	})
   168  
   169  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   170  	assertNoErrors(t, diags)
   171  
   172  	state, diags := ctx.Apply(plan, m)
   173  	assertNoDiagnostics(t, diags)
   174  
   175  	got := strings.TrimSpace(state.String())
   176  	want := strings.TrimSpace(`null_resource.foo.0:
   177    ID = foo
   178    provider = provider["registry.terraform.io/hashicorp/null"]
   179  
   180  Outputs:
   181  
   182  test = [foo]`)
   183  	if got != want {
   184  		t.Fatalf("got:\n%s\n\nwant:\n%s\n", got, want)
   185  	}
   186  }
   187  func TestContext2Apply_resourceCountZeroList(t *testing.T) {
   188  	m := testModule(t, "apply-resource-count-zero-list")
   189  	p := testProvider("null")
   190  	p.PlanResourceChangeFn = testDiffFn
   191  	ctx := testContext2(t, &ContextOpts{
   192  		Providers: map[addrs.Provider]providers.Factory{
   193  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   194  		},
   195  	})
   196  
   197  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   198  	assertNoErrors(t, diags)
   199  
   200  	state, diags := ctx.Apply(plan, m)
   201  	if diags.HasErrors() {
   202  		t.Fatalf("diags: %s", diags.Err())
   203  	}
   204  
   205  	got := strings.TrimSpace(state.String())
   206  	want := strings.TrimSpace(`<no state>
   207  Outputs:
   208  
   209  test = []`)
   210  	if got != want {
   211  		t.Fatalf("wrong state\n\ngot:\n%s\n\nwant:\n%s\n", got, want)
   212  	}
   213  }
   214  
   215  func TestContext2Apply_resourceDependsOnModule(t *testing.T) {
   216  	m := testModule(t, "apply-resource-depends-on-module")
   217  	p := testProvider("aws")
   218  	p.PlanResourceChangeFn = testDiffFn
   219  
   220  	// verify the apply happens in the correct order
   221  	var mu sync.Mutex
   222  	var order []string
   223  
   224  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   225  		ami := req.PlannedState.GetAttr("ami").AsString()
   226  		switch ami {
   227  		case "child":
   228  
   229  			// make the child slower than the parent
   230  			time.Sleep(50 * time.Millisecond)
   231  
   232  			mu.Lock()
   233  			order = append(order, "child")
   234  			mu.Unlock()
   235  		case "parent":
   236  			mu.Lock()
   237  			order = append(order, "parent")
   238  			mu.Unlock()
   239  		}
   240  
   241  		return testApplyFn(req)
   242  	}
   243  
   244  	ctx := testContext2(t, &ContextOpts{
   245  		Providers: map[addrs.Provider]providers.Factory{
   246  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   247  		},
   248  	})
   249  
   250  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   251  	assertNoErrors(t, diags)
   252  
   253  	state, diags := ctx.Apply(plan, m)
   254  	if diags.HasErrors() {
   255  		t.Fatalf("diags: %s", diags.Err())
   256  	}
   257  
   258  	if !reflect.DeepEqual(order, []string{"child", "parent"}) {
   259  		t.Fatal("resources applied out of order")
   260  	}
   261  
   262  	checkStateString(t, state, testTerraformApplyResourceDependsOnModuleStr)
   263  }
   264  
   265  // Test that without a config, the Dependencies in the state are enough
   266  // to maintain proper ordering.
   267  func TestContext2Apply_resourceDependsOnModuleStateOnly(t *testing.T) {
   268  	m := testModule(t, "apply-resource-depends-on-module-empty")
   269  	p := testProvider("aws")
   270  	p.PlanResourceChangeFn = testDiffFn
   271  
   272  	state := states.NewState()
   273  	root := state.EnsureModule(addrs.RootModuleInstance)
   274  	root.SetResourceInstanceCurrent(
   275  		mustResourceInstanceAddr("aws_instance.a").Resource,
   276  		&states.ResourceInstanceObjectSrc{
   277  			Status:       states.ObjectReady,
   278  			AttrsJSON:    []byte(`{"id":"parent"}`),
   279  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.child")},
   280  		},
   281  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   282  	)
   283  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
   284  	child.SetResourceInstanceCurrent(
   285  		mustResourceInstanceAddr("aws_instance.child").Resource,
   286  		&states.ResourceInstanceObjectSrc{
   287  			Status:    states.ObjectReady,
   288  			AttrsJSON: []byte(`{"id":"child"}`),
   289  		},
   290  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   291  	)
   292  
   293  	{
   294  		// verify the apply happens in the correct order
   295  		var mu sync.Mutex
   296  		var order []string
   297  
   298  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   299  			id := req.PriorState.GetAttr("id")
   300  			if id.IsKnown() && id.AsString() == "parent" {
   301  				// make the dep slower than the parent
   302  				time.Sleep(50 * time.Millisecond)
   303  
   304  				mu.Lock()
   305  				order = append(order, "child")
   306  				mu.Unlock()
   307  			} else {
   308  				mu.Lock()
   309  				order = append(order, "parent")
   310  				mu.Unlock()
   311  			}
   312  
   313  			return testApplyFn(req)
   314  		}
   315  
   316  		ctx := testContext2(t, &ContextOpts{
   317  			Providers: map[addrs.Provider]providers.Factory{
   318  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   319  			},
   320  		})
   321  
   322  		plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   323  		assertNoErrors(t, diags)
   324  
   325  		state, diags := ctx.Apply(plan, m)
   326  		assertNoErrors(t, diags)
   327  
   328  		if !reflect.DeepEqual(order, []string{"child", "parent"}) {
   329  			t.Fatal("resources applied out of order")
   330  		}
   331  
   332  		checkStateString(t, state, "<no state>")
   333  	}
   334  }
   335  
   336  func TestContext2Apply_resourceDependsOnModuleDestroy(t *testing.T) {
   337  	m := testModule(t, "apply-resource-depends-on-module")
   338  	p := testProvider("aws")
   339  	p.PlanResourceChangeFn = testDiffFn
   340  
   341  	var globalState *states.State
   342  	{
   343  		ctx := testContext2(t, &ContextOpts{
   344  			Providers: map[addrs.Provider]providers.Factory{
   345  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   346  			},
   347  		})
   348  
   349  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   350  		assertNoErrors(t, diags)
   351  
   352  		state, diags := ctx.Apply(plan, m)
   353  		if diags.HasErrors() {
   354  			t.Fatalf("diags: %s", diags.Err())
   355  		}
   356  
   357  		globalState = state
   358  	}
   359  
   360  	{
   361  		// Wait for the dependency, sleep, and verify the graph never
   362  		// called a child.
   363  		var called int32
   364  		var checked bool
   365  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   366  			ami := req.PriorState.GetAttr("ami").AsString()
   367  			if ami == "parent" {
   368  				checked = true
   369  
   370  				// Sleep to allow parallel execution
   371  				time.Sleep(50 * time.Millisecond)
   372  
   373  				// Verify that called is 0 (dep not called)
   374  				if atomic.LoadInt32(&called) != 0 {
   375  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("module child should not be called"))
   376  					return resp
   377  				}
   378  			}
   379  
   380  			atomic.AddInt32(&called, 1)
   381  			return testApplyFn(req)
   382  		}
   383  
   384  		ctx := testContext2(t, &ContextOpts{
   385  			Providers: map[addrs.Provider]providers.Factory{
   386  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   387  			},
   388  		})
   389  
   390  		plan, diags := ctx.Plan(m, globalState, &PlanOpts{
   391  			Mode: plans.DestroyMode,
   392  		})
   393  		assertNoErrors(t, diags)
   394  
   395  		state, diags := ctx.Apply(plan, m)
   396  		if diags.HasErrors() {
   397  			t.Fatalf("diags: %s", diags.Err())
   398  		}
   399  
   400  		if !checked {
   401  			t.Fatal("should check")
   402  		}
   403  
   404  		checkStateString(t, state, `<no state>`)
   405  	}
   406  }
   407  
   408  func TestContext2Apply_resourceDependsOnModuleGrandchild(t *testing.T) {
   409  	m := testModule(t, "apply-resource-depends-on-module-deep")
   410  	p := testProvider("aws")
   411  	p.PlanResourceChangeFn = testDiffFn
   412  
   413  	{
   414  		// Wait for the dependency, sleep, and verify the graph never
   415  		// called a child.
   416  		var called int32
   417  		var checked bool
   418  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   419  			planned := req.PlannedState.AsValueMap()
   420  			if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" {
   421  				checked = true
   422  
   423  				// Sleep to allow parallel execution
   424  				time.Sleep(50 * time.Millisecond)
   425  
   426  				// Verify that called is 0 (dep not called)
   427  				if atomic.LoadInt32(&called) != 0 {
   428  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("aws_instance.a should not be called"))
   429  					return resp
   430  				}
   431  			}
   432  
   433  			atomic.AddInt32(&called, 1)
   434  			return testApplyFn(req)
   435  		}
   436  
   437  		ctx := testContext2(t, &ContextOpts{
   438  			Providers: map[addrs.Provider]providers.Factory{
   439  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   440  			},
   441  		})
   442  
   443  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   444  		assertNoErrors(t, diags)
   445  
   446  		state, diags := ctx.Apply(plan, m)
   447  		if diags.HasErrors() {
   448  			t.Fatalf("diags: %s", diags.Err())
   449  		}
   450  
   451  		if !checked {
   452  			t.Fatal("should check")
   453  		}
   454  
   455  		checkStateString(t, state, testTerraformApplyResourceDependsOnModuleDeepStr)
   456  	}
   457  }
   458  
   459  func TestContext2Apply_resourceDependsOnModuleInModule(t *testing.T) {
   460  	m := testModule(t, "apply-resource-depends-on-module-in-module")
   461  	p := testProvider("aws")
   462  	p.PlanResourceChangeFn = testDiffFn
   463  
   464  	{
   465  		// Wait for the dependency, sleep, and verify the graph never
   466  		// called a child.
   467  		var called int32
   468  		var checked bool
   469  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   470  			planned := req.PlannedState.AsValueMap()
   471  			if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" {
   472  				checked = true
   473  
   474  				// Sleep to allow parallel execution
   475  				time.Sleep(50 * time.Millisecond)
   476  
   477  				// Verify that called is 0 (dep not called)
   478  				if atomic.LoadInt32(&called) != 0 {
   479  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("something else was applied before grandchild; grandchild should be first"))
   480  					return resp
   481  				}
   482  			}
   483  
   484  			atomic.AddInt32(&called, 1)
   485  			return testApplyFn(req)
   486  		}
   487  
   488  		ctx := testContext2(t, &ContextOpts{
   489  			Providers: map[addrs.Provider]providers.Factory{
   490  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   491  			},
   492  		})
   493  
   494  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   495  		assertNoErrors(t, diags)
   496  
   497  		state, diags := ctx.Apply(plan, m)
   498  		if diags.HasErrors() {
   499  			t.Fatalf("diags: %s", diags.Err())
   500  		}
   501  
   502  		if !checked {
   503  			t.Fatal("should check")
   504  		}
   505  
   506  		checkStateString(t, state, testTerraformApplyResourceDependsOnModuleInModuleStr)
   507  	}
   508  }
   509  
   510  func TestContext2Apply_mapVarBetweenModules(t *testing.T) {
   511  	m := testModule(t, "apply-map-var-through-module")
   512  	p := testProvider("null")
   513  	p.PlanResourceChangeFn = testDiffFn
   514  	p.ApplyResourceChangeFn = testApplyFn
   515  	ctx := testContext2(t, &ContextOpts{
   516  		Providers: map[addrs.Provider]providers.Factory{
   517  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   518  		},
   519  	})
   520  
   521  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
   522  	assertNoErrors(t, diags)
   523  
   524  	state, diags := ctx.Apply(plan, m)
   525  	if diags.HasErrors() {
   526  		t.Fatalf("diags: %s", diags.Err())
   527  	}
   528  
   529  	actual := strings.TrimSpace(state.String())
   530  	expected := strings.TrimSpace(`<no state>
   531  Outputs:
   532  
   533  amis_from_module = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }
   534  
   535  module.test:
   536    null_resource.noop:
   537      ID = foo
   538      provider = provider["registry.terraform.io/hashicorp/null"]
   539  
   540    Outputs:
   541  
   542    amis_out = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }`)
   543  	if actual != expected {
   544  		t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual)
   545  	}
   546  }
   547  
   548  func TestContext2Apply_refCount(t *testing.T) {
   549  	m := testModule(t, "apply-ref-count")
   550  	p := testProvider("aws")
   551  	p.PlanResourceChangeFn = testDiffFn
   552  	p.ApplyResourceChangeFn = testApplyFn
   553  	ctx := testContext2(t, &ContextOpts{
   554  		Providers: map[addrs.Provider]providers.Factory{
   555  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   556  		},
   557  	})
   558  
   559  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   560  	assertNoErrors(t, diags)
   561  
   562  	state, diags := ctx.Apply(plan, m)
   563  	if diags.HasErrors() {
   564  		t.Fatalf("diags: %s", diags.Err())
   565  	}
   566  
   567  	mod := state.RootModule()
   568  	if len(mod.Resources) < 2 {
   569  		t.Fatalf("bad: %#v", mod.Resources)
   570  	}
   571  
   572  	actual := strings.TrimSpace(state.String())
   573  	expected := strings.TrimSpace(testTerraformApplyRefCountStr)
   574  	if actual != expected {
   575  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   576  	}
   577  }
   578  
   579  func TestContext2Apply_providerAlias(t *testing.T) {
   580  	m := testModule(t, "apply-provider-alias")
   581  
   582  	// Each provider instance must be completely independent to ensure that we
   583  	// are verifying the correct state of each.
   584  	p := func() (providers.Interface, error) {
   585  		p := testProvider("aws")
   586  		p.PlanResourceChangeFn = testDiffFn
   587  		p.ApplyResourceChangeFn = testApplyFn
   588  		return p, nil
   589  	}
   590  	ctx := testContext2(t, &ContextOpts{
   591  		Providers: map[addrs.Provider]providers.Factory{
   592  			addrs.NewDefaultProvider("aws"): p,
   593  		},
   594  	})
   595  
   596  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   597  	assertNoErrors(t, diags)
   598  
   599  	state, diags := ctx.Apply(plan, m)
   600  	if diags.HasErrors() {
   601  		t.Fatalf("diags: %s", diags.Err())
   602  	}
   603  
   604  	mod := state.RootModule()
   605  	if len(mod.Resources) < 2 {
   606  		t.Fatalf("bad: %#v", mod.Resources)
   607  	}
   608  
   609  	actual := strings.TrimSpace(state.String())
   610  	expected := strings.TrimSpace(testTerraformApplyProviderAliasStr)
   611  	if actual != expected {
   612  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   613  	}
   614  }
   615  
   616  // Two providers that are configured should both be configured prior to apply
   617  func TestContext2Apply_providerAliasConfigure(t *testing.T) {
   618  	m := testModule(t, "apply-provider-alias-configure")
   619  
   620  	// Each provider instance must be completely independent to ensure that we
   621  	// are verifying the correct state of each.
   622  	p := func() (providers.Interface, error) {
   623  		p := testProvider("another")
   624  		p.ApplyResourceChangeFn = testApplyFn
   625  		p.PlanResourceChangeFn = testDiffFn
   626  		return p, nil
   627  	}
   628  
   629  	ctx := testContext2(t, &ContextOpts{
   630  		Providers: map[addrs.Provider]providers.Factory{
   631  			addrs.NewDefaultProvider("another"): p,
   632  		},
   633  	})
   634  
   635  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   636  	if diags.HasErrors() {
   637  		t.Fatalf("diags: %s", diags.Err())
   638  	} else {
   639  		t.Logf(legacyDiffComparisonString(plan.Changes))
   640  	}
   641  
   642  	// Configure to record calls AFTER Plan above
   643  	var configCount int32
   644  	p = func() (providers.Interface, error) {
   645  		p := testProvider("another")
   646  		p.ApplyResourceChangeFn = testApplyFn
   647  		p.PlanResourceChangeFn = testDiffFn
   648  		p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
   649  			atomic.AddInt32(&configCount, 1)
   650  
   651  			foo := req.Config.GetAttr("foo").AsString()
   652  			if foo != "bar" {
   653  				resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("foo: %#v", foo))
   654  			}
   655  
   656  			return
   657  		}
   658  		return p, nil
   659  	}
   660  
   661  	ctx = testContext2(t, &ContextOpts{
   662  		Providers: map[addrs.Provider]providers.Factory{
   663  			addrs.NewDefaultProvider("another"): p,
   664  		},
   665  	})
   666  
   667  	state, diags := ctx.Apply(plan, m)
   668  	if diags.HasErrors() {
   669  		t.Fatalf("diags: %s", diags.Err())
   670  	}
   671  
   672  	if configCount != 2 {
   673  		t.Fatalf("provider config expected 2 calls, got: %d", configCount)
   674  	}
   675  
   676  	actual := strings.TrimSpace(state.String())
   677  	expected := strings.TrimSpace(testTerraformApplyProviderAliasConfigStr)
   678  	if actual != expected {
   679  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   680  	}
   681  }
   682  
   683  // GH-2870
   684  func TestContext2Apply_providerWarning(t *testing.T) {
   685  	m := testModule(t, "apply-provider-warning")
   686  	p := testProvider("aws")
   687  	p.PlanResourceChangeFn = testDiffFn
   688  	p.ApplyResourceChangeFn = testApplyFn
   689  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
   690  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("just a warning"))
   691  		return
   692  	}
   693  	ctx := testContext2(t, &ContextOpts{
   694  		Providers: map[addrs.Provider]providers.Factory{
   695  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   696  		},
   697  	})
   698  
   699  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   700  	assertNoErrors(t, diags)
   701  
   702  	state, diags := ctx.Apply(plan, m)
   703  	if diags.HasErrors() {
   704  		t.Fatalf("diags: %s", diags.Err())
   705  	}
   706  
   707  	actual := strings.TrimSpace(state.String())
   708  	expected := strings.TrimSpace(`
   709  aws_instance.foo:
   710    ID = foo
   711    provider = provider["registry.terraform.io/hashicorp/aws"]
   712    type = aws_instance
   713  	`)
   714  	if actual != expected {
   715  		t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected)
   716  	}
   717  
   718  	if !p.ConfigureProviderCalled {
   719  		t.Fatalf("provider Configure() was never called!")
   720  	}
   721  }
   722  
   723  func TestContext2Apply_emptyModule(t *testing.T) {
   724  	// A module with only outputs (no resources)
   725  	m := testModule(t, "apply-empty-module")
   726  	p := testProvider("aws")
   727  	p.PlanResourceChangeFn = testDiffFn
   728  	ctx := testContext2(t, &ContextOpts{
   729  		Providers: map[addrs.Provider]providers.Factory{
   730  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   731  		},
   732  	})
   733  
   734  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   735  	assertNoErrors(t, diags)
   736  
   737  	state, diags := ctx.Apply(plan, m)
   738  	if diags.HasErrors() {
   739  		t.Fatalf("diags: %s", diags.Err())
   740  	}
   741  
   742  	actual := strings.TrimSpace(state.String())
   743  	actual = strings.Replace(actual, "  ", "", -1)
   744  	expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr)
   745  	if actual != expected {
   746  		t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected)
   747  	}
   748  }
   749  
   750  func TestContext2Apply_createBeforeDestroy(t *testing.T) {
   751  	m := testModule(t, "apply-good-create-before")
   752  	p := testProvider("aws")
   753  	p.PlanResourceChangeFn = testDiffFn
   754  	p.ApplyResourceChangeFn = testApplyFn
   755  	state := states.NewState()
   756  	root := state.EnsureModule(addrs.RootModuleInstance)
   757  	root.SetResourceInstanceCurrent(
   758  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   759  		&states.ResourceInstanceObjectSrc{
   760  			Status:    states.ObjectReady,
   761  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
   762  		},
   763  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   764  	)
   765  	ctx := testContext2(t, &ContextOpts{
   766  		Providers: map[addrs.Provider]providers.Factory{
   767  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   768  		},
   769  	})
   770  
   771  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   772  	if diags.HasErrors() {
   773  		t.Fatalf("diags: %s", diags.Err())
   774  	} else {
   775  		t.Logf(legacyDiffComparisonString(plan.Changes))
   776  	}
   777  
   778  	state, diags = ctx.Apply(plan, m)
   779  	if diags.HasErrors() {
   780  		t.Fatalf("diags: %s", diags.Err())
   781  	}
   782  
   783  	mod := state.RootModule()
   784  	if got, want := len(mod.Resources), 1; got != want {
   785  		t.Logf("state:\n%s", state)
   786  		t.Fatalf("wrong number of resources %d; want %d", got, want)
   787  	}
   788  
   789  	actual := strings.TrimSpace(state.String())
   790  	expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr)
   791  	if actual != expected {
   792  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
   793  	}
   794  }
   795  
   796  func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) {
   797  	m := testModule(t, "apply-good-create-before-update")
   798  	p := testProvider("aws")
   799  	p.PlanResourceChangeFn = testDiffFn
   800  
   801  	// signal that resource foo has started applying
   802  	fooChan := make(chan struct{})
   803  
   804  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   805  		id := req.PriorState.GetAttr("id").AsString()
   806  		switch id {
   807  		case "bar":
   808  			select {
   809  			case <-fooChan:
   810  				resp.Diagnostics = resp.Diagnostics.Append(errors.New("bar must be updated before foo is destroyed"))
   811  				return resp
   812  			case <-time.After(100 * time.Millisecond):
   813  				// wait a moment to ensure that foo is not going to be destroyed first
   814  			}
   815  		case "foo":
   816  			close(fooChan)
   817  		}
   818  
   819  		return testApplyFn(req)
   820  	}
   821  
   822  	state := states.NewState()
   823  	root := state.EnsureModule(addrs.RootModuleInstance)
   824  	fooAddr := mustResourceInstanceAddr("aws_instance.foo")
   825  	root.SetResourceInstanceCurrent(
   826  		fooAddr.Resource,
   827  		&states.ResourceInstanceObjectSrc{
   828  			Status:              states.ObjectReady,
   829  			AttrsJSON:           []byte(`{"id":"foo","foo":"bar"}`),
   830  			CreateBeforeDestroy: true,
   831  		},
   832  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   833  	)
   834  	root.SetResourceInstanceCurrent(
   835  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   836  		&states.ResourceInstanceObjectSrc{
   837  			Status:              states.ObjectReady,
   838  			AttrsJSON:           []byte(`{"id":"bar","foo":"bar"}`),
   839  			CreateBeforeDestroy: true,
   840  			Dependencies:        []addrs.ConfigResource{fooAddr.ContainingResource().Config()},
   841  		},
   842  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   843  	)
   844  
   845  	ctx := testContext2(t, &ContextOpts{
   846  		Providers: map[addrs.Provider]providers.Factory{
   847  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   848  		},
   849  	})
   850  
   851  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   852  	if diags.HasErrors() {
   853  		t.Fatalf("diags: %s", diags.Err())
   854  	} else {
   855  		t.Logf(legacyDiffComparisonString(plan.Changes))
   856  	}
   857  
   858  	state, diags = ctx.Apply(plan, m)
   859  	if diags.HasErrors() {
   860  		t.Fatalf("diags: %s", diags.Err())
   861  	}
   862  
   863  	mod := state.RootModule()
   864  	if len(mod.Resources) != 1 {
   865  		t.Fatalf("bad: %s", state)
   866  	}
   867  
   868  	actual := strings.TrimSpace(state.String())
   869  	expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr)
   870  	if actual != expected {
   871  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   872  	}
   873  }
   874  
   875  // This tests that when a CBD resource depends on a non-CBD resource,
   876  // we can still properly apply changes that require new for both.
   877  func TestContext2Apply_createBeforeDestroy_dependsNonCBD(t *testing.T) {
   878  	m := testModule(t, "apply-cbd-depends-non-cbd")
   879  	p := testProvider("aws")
   880  	p.PlanResourceChangeFn = testDiffFn
   881  	p.ApplyResourceChangeFn = testApplyFn
   882  
   883  	state := states.NewState()
   884  	root := state.EnsureModule(addrs.RootModuleInstance)
   885  	root.SetResourceInstanceCurrent(
   886  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   887  		&states.ResourceInstanceObjectSrc{
   888  			Status:    states.ObjectReady,
   889  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
   890  		},
   891  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   892  	)
   893  	root.SetResourceInstanceCurrent(
   894  		mustResourceInstanceAddr("aws_instance.foo").Resource,
   895  		&states.ResourceInstanceObjectSrc{
   896  			Status:    states.ObjectReady,
   897  			AttrsJSON: []byte(`{"id":"foo", "require_new": "abc"}`),
   898  		},
   899  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   900  	)
   901  
   902  	ctx := testContext2(t, &ContextOpts{
   903  		Providers: map[addrs.Provider]providers.Factory{
   904  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   905  		},
   906  	})
   907  
   908  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   909  	if diags.HasErrors() {
   910  		t.Fatalf("diags: %s", diags.Err())
   911  	} else {
   912  		t.Logf(legacyDiffComparisonString(plan.Changes))
   913  	}
   914  
   915  	state, diags = ctx.Apply(plan, m)
   916  	if diags.HasErrors() {
   917  		t.Fatalf("diags: %s", diags.Err())
   918  	}
   919  
   920  	checkStateString(t, state, `
   921  aws_instance.bar:
   922    ID = foo
   923    provider = provider["registry.terraform.io/hashicorp/aws"]
   924    require_new = yes
   925    type = aws_instance
   926    value = foo
   927  
   928    Dependencies:
   929      aws_instance.foo
   930  aws_instance.foo:
   931    ID = foo
   932    provider = provider["registry.terraform.io/hashicorp/aws"]
   933    require_new = yes
   934    type = aws_instance
   935  	`)
   936  }
   937  
   938  func TestContext2Apply_createBeforeDestroy_hook(t *testing.T) {
   939  	h := new(MockHook)
   940  	m := testModule(t, "apply-good-create-before")
   941  	p := testProvider("aws")
   942  	p.PlanResourceChangeFn = testDiffFn
   943  	p.ApplyResourceChangeFn = testApplyFn
   944  	state := states.NewState()
   945  	root := state.EnsureModule(addrs.RootModuleInstance)
   946  	root.SetResourceInstanceCurrent(
   947  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   948  		&states.ResourceInstanceObjectSrc{
   949  			Status:    states.ObjectReady,
   950  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
   951  		},
   952  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   953  	)
   954  
   955  	var actual []cty.Value
   956  	var actualLock sync.Mutex
   957  	h.PostApplyFn = func(addr addrs.AbsResourceInstance, gen states.Generation, sv cty.Value, e error) (HookAction, error) {
   958  		actualLock.Lock()
   959  
   960  		defer actualLock.Unlock()
   961  		actual = append(actual, sv)
   962  		return HookActionContinue, nil
   963  	}
   964  
   965  	ctx := testContext2(t, &ContextOpts{
   966  		Hooks: []Hook{h},
   967  		Providers: map[addrs.Provider]providers.Factory{
   968  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   969  		},
   970  	})
   971  
   972  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   973  	if diags.HasErrors() {
   974  		t.Fatalf("diags: %s", diags.Err())
   975  	} else {
   976  		t.Logf(legacyDiffComparisonString(plan.Changes))
   977  	}
   978  
   979  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
   980  		t.Fatalf("apply errors: %s", diags.Err())
   981  	}
   982  
   983  	expected := []cty.Value{
   984  		cty.ObjectVal(map[string]cty.Value{
   985  			"id":          cty.StringVal("foo"),
   986  			"require_new": cty.StringVal("xyz"),
   987  			"type":        cty.StringVal("aws_instance"),
   988  		}),
   989  		cty.NullVal(cty.DynamicPseudoType),
   990  	}
   991  
   992  	cmpOpt := cmp.Transformer("ctyshim", hcl2shim.ConfigValueFromHCL2)
   993  	if !cmp.Equal(actual, expected, cmpOpt) {
   994  		t.Fatalf("wrong state snapshot sequence\n%s", cmp.Diff(expected, actual, cmpOpt))
   995  	}
   996  }
   997  
   998  // Test that we can perform an apply with CBD in a count with deposed instances.
   999  func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) {
  1000  	m := testModule(t, "apply-cbd-count")
  1001  	p := testProvider("aws")
  1002  	p.PlanResourceChangeFn = testDiffFn
  1003  	p.ApplyResourceChangeFn = testApplyFn
  1004  
  1005  	state := states.NewState()
  1006  	root := state.EnsureModule(addrs.RootModuleInstance)
  1007  	root.SetResourceInstanceCurrent(
  1008  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  1009  		&states.ResourceInstanceObjectSrc{
  1010  			Status:    states.ObjectTainted,
  1011  			AttrsJSON: []byte(`{"id":"bar"}`),
  1012  		},
  1013  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1014  	)
  1015  	root.SetResourceInstanceDeposed(
  1016  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  1017  		states.NewDeposedKey(),
  1018  		&states.ResourceInstanceObjectSrc{
  1019  			Status:    states.ObjectTainted,
  1020  			AttrsJSON: []byte(`{"id":"foo"}`),
  1021  		},
  1022  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1023  	)
  1024  	root.SetResourceInstanceCurrent(
  1025  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  1026  		&states.ResourceInstanceObjectSrc{
  1027  			Status:    states.ObjectTainted,
  1028  			AttrsJSON: []byte(`{"id":"bar"}`),
  1029  		},
  1030  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1031  	)
  1032  	root.SetResourceInstanceDeposed(
  1033  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  1034  		states.NewDeposedKey(),
  1035  		&states.ResourceInstanceObjectSrc{
  1036  			Status:    states.ObjectTainted,
  1037  			AttrsJSON: []byte(`{"id":"bar"}`),
  1038  		},
  1039  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1040  	)
  1041  
  1042  	ctx := testContext2(t, &ContextOpts{
  1043  		Providers: map[addrs.Provider]providers.Factory{
  1044  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1045  		},
  1046  	})
  1047  
  1048  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1049  	if diags.HasErrors() {
  1050  		t.Fatalf("diags: %s", diags.Err())
  1051  	} else {
  1052  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1053  	}
  1054  
  1055  	state, diags = ctx.Apply(plan, m)
  1056  	if diags.HasErrors() {
  1057  		t.Fatalf("diags: %s", diags.Err())
  1058  	}
  1059  
  1060  	checkStateString(t, state, `
  1061  aws_instance.bar.0:
  1062    ID = foo
  1063    provider = provider["registry.terraform.io/hashicorp/aws"]
  1064    foo = bar
  1065    type = aws_instance
  1066  aws_instance.bar.1:
  1067    ID = foo
  1068    provider = provider["registry.terraform.io/hashicorp/aws"]
  1069    foo = bar
  1070    type = aws_instance
  1071  	`)
  1072  }
  1073  
  1074  // Test that when we have a deposed instance but a good primary, we still
  1075  // destroy the deposed instance.
  1076  func TestContext2Apply_createBeforeDestroy_deposedOnly(t *testing.T) {
  1077  	m := testModule(t, "apply-cbd-deposed-only")
  1078  	p := testProvider("aws")
  1079  	p.PlanResourceChangeFn = testDiffFn
  1080  	p.ApplyResourceChangeFn = testApplyFn
  1081  
  1082  	state := states.NewState()
  1083  	root := state.EnsureModule(addrs.RootModuleInstance)
  1084  	root.SetResourceInstanceCurrent(
  1085  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1086  		&states.ResourceInstanceObjectSrc{
  1087  			Status:    states.ObjectReady,
  1088  			AttrsJSON: []byte(`{"id":"bar"}`),
  1089  		},
  1090  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1091  	)
  1092  	root.SetResourceInstanceDeposed(
  1093  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1094  		states.NewDeposedKey(),
  1095  		&states.ResourceInstanceObjectSrc{
  1096  			Status:    states.ObjectTainted,
  1097  			AttrsJSON: []byte(`{"id":"foo"}`),
  1098  		},
  1099  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1100  	)
  1101  
  1102  	ctx := testContext2(t, &ContextOpts{
  1103  		Providers: map[addrs.Provider]providers.Factory{
  1104  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1105  		},
  1106  	})
  1107  
  1108  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1109  	if diags.HasErrors() {
  1110  		t.Fatalf("diags: %s", diags.Err())
  1111  	} else {
  1112  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1113  	}
  1114  
  1115  	state, diags = ctx.Apply(plan, m)
  1116  	if diags.HasErrors() {
  1117  		t.Fatalf("diags: %s", diags.Err())
  1118  	}
  1119  
  1120  	checkStateString(t, state, `
  1121  aws_instance.bar:
  1122    ID = bar
  1123    provider = provider["registry.terraform.io/hashicorp/aws"]
  1124    type = aws_instance
  1125  	`)
  1126  }
  1127  
  1128  func TestContext2Apply_destroyComputed(t *testing.T) {
  1129  	m := testModule(t, "apply-destroy-computed")
  1130  	p := testProvider("aws")
  1131  	p.PlanResourceChangeFn = testDiffFn
  1132  	state := states.NewState()
  1133  	root := state.EnsureModule(addrs.RootModuleInstance)
  1134  	root.SetResourceInstanceCurrent(
  1135  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1136  		&states.ResourceInstanceObjectSrc{
  1137  			Status:    states.ObjectReady,
  1138  			AttrsJSON: []byte(`{"id":"foo", "output": "value"}`),
  1139  		},
  1140  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1141  	)
  1142  	ctx := testContext2(t, &ContextOpts{
  1143  		Providers: map[addrs.Provider]providers.Factory{
  1144  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1145  		},
  1146  	})
  1147  
  1148  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1149  		Mode: plans.DestroyMode,
  1150  	})
  1151  	if diags.HasErrors() {
  1152  		logDiagnostics(t, diags)
  1153  		t.Fatal("plan failed")
  1154  	} else {
  1155  		t.Logf("plan:\n\n%s", legacyDiffComparisonString(plan.Changes))
  1156  	}
  1157  
  1158  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1159  		logDiagnostics(t, diags)
  1160  		t.Fatal("apply failed")
  1161  	}
  1162  }
  1163  
  1164  // Test that the destroy operation uses depends_on as a source of ordering.
  1165  func TestContext2Apply_destroyDependsOn(t *testing.T) {
  1166  	// It is possible for this to be racy, so we loop a number of times
  1167  	// just to check.
  1168  	for i := 0; i < 10; i++ {
  1169  		testContext2Apply_destroyDependsOn(t)
  1170  	}
  1171  }
  1172  
  1173  func testContext2Apply_destroyDependsOn(t *testing.T) {
  1174  	m := testModule(t, "apply-destroy-depends-on")
  1175  	p := testProvider("aws")
  1176  	p.PlanResourceChangeFn = testDiffFn
  1177  
  1178  	state := states.NewState()
  1179  	root := state.EnsureModule(addrs.RootModuleInstance)
  1180  	root.SetResourceInstanceCurrent(
  1181  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1182  		&states.ResourceInstanceObjectSrc{
  1183  			Status:    states.ObjectReady,
  1184  			AttrsJSON: []byte(`{"id":"bar"}`),
  1185  		},
  1186  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1187  	)
  1188  	root.SetResourceInstanceCurrent(
  1189  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1190  		&states.ResourceInstanceObjectSrc{
  1191  			Status:       states.ObjectReady,
  1192  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1193  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
  1194  		},
  1195  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1196  	)
  1197  
  1198  	// Record the order we see Apply
  1199  	var actual []string
  1200  	var actualLock sync.Mutex
  1201  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1202  		actualLock.Lock()
  1203  		defer actualLock.Unlock()
  1204  		id := req.PriorState.GetAttr("id").AsString()
  1205  		actual = append(actual, id)
  1206  
  1207  		return testApplyFn(req)
  1208  	}
  1209  
  1210  	ctx := testContext2(t, &ContextOpts{
  1211  		Providers: map[addrs.Provider]providers.Factory{
  1212  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1213  		},
  1214  		Parallelism: 1, // To check ordering
  1215  	})
  1216  
  1217  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1218  		Mode: plans.DestroyMode,
  1219  	})
  1220  	assertNoErrors(t, diags)
  1221  
  1222  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1223  		t.Fatalf("apply errors: %s", diags.Err())
  1224  	}
  1225  
  1226  	expected := []string{"foo", "bar"}
  1227  	if !reflect.DeepEqual(actual, expected) {
  1228  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1229  	}
  1230  }
  1231  
  1232  // Test that destroy ordering is correct with dependencies only
  1233  // in the state.
  1234  func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) {
  1235  	newState := states.NewState()
  1236  	root := newState.EnsureModule(addrs.RootModuleInstance)
  1237  	root.SetResourceInstanceCurrent(
  1238  		addrs.Resource{
  1239  			Mode: addrs.ManagedResourceMode,
  1240  			Type: "aws_instance",
  1241  			Name: "foo",
  1242  		}.Instance(addrs.NoKey),
  1243  		&states.ResourceInstanceObjectSrc{
  1244  			Status:       states.ObjectReady,
  1245  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1246  			Dependencies: []addrs.ConfigResource{},
  1247  		},
  1248  		addrs.AbsProviderConfig{
  1249  			Provider: addrs.NewDefaultProvider("aws"),
  1250  			Module:   addrs.RootModule,
  1251  		},
  1252  	)
  1253  	root.SetResourceInstanceCurrent(
  1254  		addrs.Resource{
  1255  			Mode: addrs.ManagedResourceMode,
  1256  			Type: "aws_instance",
  1257  			Name: "bar",
  1258  		}.Instance(addrs.NoKey),
  1259  		&states.ResourceInstanceObjectSrc{
  1260  			Status:    states.ObjectReady,
  1261  			AttrsJSON: []byte(`{"id":"bar"}`),
  1262  			Dependencies: []addrs.ConfigResource{
  1263  				{
  1264  					Resource: addrs.Resource{
  1265  						Mode: addrs.ManagedResourceMode,
  1266  						Type: "aws_instance",
  1267  						Name: "foo",
  1268  					},
  1269  					Module: root.Addr.Module(),
  1270  				},
  1271  			},
  1272  		},
  1273  		addrs.AbsProviderConfig{
  1274  			Provider: addrs.NewDefaultProvider("aws"),
  1275  			Module:   addrs.RootModule,
  1276  		},
  1277  	)
  1278  
  1279  	// It is possible for this to be racy, so we loop a number of times
  1280  	// just to check.
  1281  	for i := 0; i < 10; i++ {
  1282  		t.Run("new", func(t *testing.T) {
  1283  			testContext2Apply_destroyDependsOnStateOnly(t, newState)
  1284  		})
  1285  	}
  1286  }
  1287  
  1288  func testContext2Apply_destroyDependsOnStateOnly(t *testing.T, state *states.State) {
  1289  	state = state.DeepCopy()
  1290  	m := testModule(t, "empty")
  1291  	p := testProvider("aws")
  1292  	p.PlanResourceChangeFn = testDiffFn
  1293  	// Record the order we see Apply
  1294  	var actual []string
  1295  	var actualLock sync.Mutex
  1296  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1297  		actualLock.Lock()
  1298  		defer actualLock.Unlock()
  1299  		id := req.PriorState.GetAttr("id").AsString()
  1300  		actual = append(actual, id)
  1301  		return testApplyFn(req)
  1302  	}
  1303  
  1304  	ctx := testContext2(t, &ContextOpts{
  1305  		Providers: map[addrs.Provider]providers.Factory{
  1306  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1307  		},
  1308  		Parallelism: 1, // To check ordering
  1309  	})
  1310  
  1311  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1312  		Mode: plans.DestroyMode,
  1313  	})
  1314  	assertNoErrors(t, diags)
  1315  
  1316  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1317  		t.Fatalf("apply errors: %s", diags.Err())
  1318  	}
  1319  
  1320  	expected := []string{"bar", "foo"}
  1321  	if !reflect.DeepEqual(actual, expected) {
  1322  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1323  	}
  1324  }
  1325  
  1326  // Test that destroy ordering is correct with dependencies only
  1327  // in the state within a module (GH-11749)
  1328  func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) {
  1329  	newState := states.NewState()
  1330  	child := newState.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1331  	child.SetResourceInstanceCurrent(
  1332  		addrs.Resource{
  1333  			Mode: addrs.ManagedResourceMode,
  1334  			Type: "aws_instance",
  1335  			Name: "foo",
  1336  		}.Instance(addrs.NoKey),
  1337  		&states.ResourceInstanceObjectSrc{
  1338  			Status:       states.ObjectReady,
  1339  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1340  			Dependencies: []addrs.ConfigResource{},
  1341  		},
  1342  		addrs.AbsProviderConfig{
  1343  			Provider: addrs.NewDefaultProvider("aws"),
  1344  			Module:   addrs.RootModule,
  1345  		},
  1346  	)
  1347  	child.SetResourceInstanceCurrent(
  1348  		addrs.Resource{
  1349  			Mode: addrs.ManagedResourceMode,
  1350  			Type: "aws_instance",
  1351  			Name: "bar",
  1352  		}.Instance(addrs.NoKey),
  1353  		&states.ResourceInstanceObjectSrc{
  1354  			Status:    states.ObjectReady,
  1355  			AttrsJSON: []byte(`{"id":"bar"}`),
  1356  			Dependencies: []addrs.ConfigResource{
  1357  				{
  1358  					Resource: addrs.Resource{
  1359  						Mode: addrs.ManagedResourceMode,
  1360  						Type: "aws_instance",
  1361  						Name: "foo",
  1362  					},
  1363  					Module: child.Addr.Module(),
  1364  				},
  1365  			},
  1366  		},
  1367  		addrs.AbsProviderConfig{
  1368  			Provider: addrs.NewDefaultProvider("aws"),
  1369  			Module:   addrs.RootModule,
  1370  		},
  1371  	)
  1372  
  1373  	// It is possible for this to be racy, so we loop a number of times
  1374  	// just to check.
  1375  	for i := 0; i < 10; i++ {
  1376  		t.Run("new", func(t *testing.T) {
  1377  			testContext2Apply_destroyDependsOnStateOnlyModule(t, newState)
  1378  		})
  1379  	}
  1380  }
  1381  
  1382  func testContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T, state *states.State) {
  1383  	state = state.DeepCopy()
  1384  	m := testModule(t, "empty")
  1385  	p := testProvider("aws")
  1386  	p.PlanResourceChangeFn = testDiffFn
  1387  
  1388  	// Record the order we see Apply
  1389  	var actual []string
  1390  	var actualLock sync.Mutex
  1391  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1392  		actualLock.Lock()
  1393  		defer actualLock.Unlock()
  1394  		id := req.PriorState.GetAttr("id").AsString()
  1395  		actual = append(actual, id)
  1396  		return testApplyFn(req)
  1397  	}
  1398  
  1399  	ctx := testContext2(t, &ContextOpts{
  1400  		Providers: map[addrs.Provider]providers.Factory{
  1401  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1402  		},
  1403  		Parallelism: 1, // To check ordering
  1404  	})
  1405  
  1406  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1407  		Mode: plans.DestroyMode,
  1408  	})
  1409  	assertNoErrors(t, diags)
  1410  
  1411  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1412  		t.Fatalf("apply errors: %s", diags.Err())
  1413  	}
  1414  
  1415  	expected := []string{"bar", "foo"}
  1416  	if !reflect.DeepEqual(actual, expected) {
  1417  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1418  	}
  1419  }
  1420  
  1421  func TestContext2Apply_dataBasic(t *testing.T) {
  1422  	m := testModule(t, "apply-data-basic")
  1423  	p := testProvider("null")
  1424  	p.PlanResourceChangeFn = testDiffFn
  1425  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  1426  		State: cty.ObjectVal(map[string]cty.Value{
  1427  			"id":  cty.StringVal("yo"),
  1428  			"foo": cty.NullVal(cty.String),
  1429  		}),
  1430  	}
  1431  
  1432  	hook := new(MockHook)
  1433  	ctx := testContext2(t, &ContextOpts{
  1434  		Hooks: []Hook{hook},
  1435  		Providers: map[addrs.Provider]providers.Factory{
  1436  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  1437  		},
  1438  	})
  1439  
  1440  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1441  	if diags.HasErrors() {
  1442  		t.Fatalf("diags: %s", diags.Err())
  1443  	} else {
  1444  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1445  	}
  1446  
  1447  	state, diags := ctx.Apply(plan, m)
  1448  	assertNoErrors(t, diags)
  1449  
  1450  	actual := strings.TrimSpace(state.String())
  1451  	expected := strings.TrimSpace(testTerraformApplyDataBasicStr)
  1452  	if actual != expected {
  1453  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1454  	}
  1455  
  1456  	if !hook.PreApplyCalled {
  1457  		t.Fatal("PreApply not called for data source read")
  1458  	}
  1459  	if !hook.PostApplyCalled {
  1460  		t.Fatal("PostApply not called for data source read")
  1461  	}
  1462  }
  1463  
  1464  func TestContext2Apply_destroyData(t *testing.T) {
  1465  	m := testModule(t, "apply-destroy-data-resource")
  1466  	p := testProvider("null")
  1467  	p.PlanResourceChangeFn = testDiffFn
  1468  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  1469  		return providers.ReadDataSourceResponse{
  1470  			State: req.Config,
  1471  		}
  1472  	}
  1473  
  1474  	state := states.NewState()
  1475  	root := state.EnsureModule(addrs.RootModuleInstance)
  1476  	root.SetResourceInstanceCurrent(
  1477  		mustResourceInstanceAddr("data.null_data_source.testing").Resource,
  1478  		&states.ResourceInstanceObjectSrc{
  1479  			Status:    states.ObjectReady,
  1480  			AttrsJSON: []byte(`{"id":"-"}`),
  1481  		},
  1482  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/null"]`),
  1483  	)
  1484  
  1485  	hook := &testHook{}
  1486  	ctx := testContext2(t, &ContextOpts{
  1487  		Providers: map[addrs.Provider]providers.Factory{
  1488  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  1489  		},
  1490  		Hooks: []Hook{hook},
  1491  	})
  1492  
  1493  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1494  		Mode: plans.DestroyMode,
  1495  	})
  1496  	if diags.HasErrors() {
  1497  		t.Fatalf("diags: %s", diags.Err())
  1498  	} else {
  1499  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1500  	}
  1501  
  1502  	newState, diags := ctx.Apply(plan, m)
  1503  	if diags.HasErrors() {
  1504  		t.Fatalf("diags: %s", diags.Err())
  1505  	}
  1506  
  1507  	if got := len(newState.Modules); got != 1 {
  1508  		t.Fatalf("state has %d modules after destroy; want 1", got)
  1509  	}
  1510  
  1511  	if got := len(newState.RootModule().Resources); got != 0 {
  1512  		t.Fatalf("state has %d resources after destroy; want 0", got)
  1513  	}
  1514  
  1515  	wantHookCalls := []*testHookCall{
  1516  		{"PreApply", "data.null_data_source.testing"},
  1517  		{"PostApply", "data.null_data_source.testing"},
  1518  		{"PostStateUpdate", ""},
  1519  	}
  1520  	if !reflect.DeepEqual(hook.Calls, wantHookCalls) {
  1521  		t.Errorf("wrong hook calls\ngot: %swant: %s", spew.Sdump(hook.Calls), spew.Sdump(wantHookCalls))
  1522  	}
  1523  }
  1524  
  1525  // https://github.com/hashicorp/terraform/pull/5096
  1526  func TestContext2Apply_destroySkipsCBD(t *testing.T) {
  1527  	// Config contains CBD resource depending on non-CBD resource, which triggers
  1528  	// a cycle if they are both replaced, but should _not_ trigger a cycle when
  1529  	// just doing a `terraform destroy`.
  1530  	m := testModule(t, "apply-destroy-cbd")
  1531  	p := testProvider("aws")
  1532  	p.PlanResourceChangeFn = testDiffFn
  1533  	state := states.NewState()
  1534  	root := state.EnsureModule(addrs.RootModuleInstance)
  1535  	root.SetResourceInstanceCurrent(
  1536  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1537  		&states.ResourceInstanceObjectSrc{
  1538  			Status:    states.ObjectReady,
  1539  			AttrsJSON: []byte(`{"id":"foo"}`),
  1540  		},
  1541  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1542  	)
  1543  	root.SetResourceInstanceCurrent(
  1544  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1545  		&states.ResourceInstanceObjectSrc{
  1546  			Status:    states.ObjectReady,
  1547  			AttrsJSON: []byte(`{"id":"foo"}`),
  1548  		},
  1549  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1550  	)
  1551  
  1552  	ctx := testContext2(t, &ContextOpts{
  1553  		Providers: map[addrs.Provider]providers.Factory{
  1554  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1555  		},
  1556  	})
  1557  
  1558  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1559  		Mode: plans.DestroyMode,
  1560  	})
  1561  	if diags.HasErrors() {
  1562  		t.Fatalf("diags: %s", diags.Err())
  1563  	} else {
  1564  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1565  	}
  1566  
  1567  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1568  		t.Fatalf("apply errors: %s", diags.Err())
  1569  	}
  1570  }
  1571  
  1572  func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) {
  1573  	m := testModule(t, "apply-destroy-mod-var-provider-config")
  1574  	p := func() (providers.Interface, error) {
  1575  		p := testProvider("aws")
  1576  		p.PlanResourceChangeFn = testDiffFn
  1577  		return p, nil
  1578  	}
  1579  	state := states.NewState()
  1580  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1581  	child.SetResourceInstanceCurrent(
  1582  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1583  		&states.ResourceInstanceObjectSrc{
  1584  			Status:    states.ObjectReady,
  1585  			AttrsJSON: []byte(`{"id":"foo"}`),
  1586  		},
  1587  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1588  	)
  1589  	ctx := testContext2(t, &ContextOpts{
  1590  		Providers: map[addrs.Provider]providers.Factory{
  1591  			addrs.NewDefaultProvider("aws"): p,
  1592  		},
  1593  	})
  1594  
  1595  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1596  		Mode: plans.DestroyMode,
  1597  	})
  1598  	assertNoErrors(t, diags)
  1599  
  1600  	_, diags = ctx.Apply(plan, m)
  1601  	if diags.HasErrors() {
  1602  		t.Fatalf("diags: %s", diags.Err())
  1603  	}
  1604  }
  1605  
  1606  func TestContext2Apply_destroyCrossProviders(t *testing.T) {
  1607  	m := testModule(t, "apply-destroy-cross-providers")
  1608  
  1609  	p_aws := testProvider("aws")
  1610  	p_aws.ApplyResourceChangeFn = testApplyFn
  1611  	p_aws.PlanResourceChangeFn = testDiffFn
  1612  	p_aws.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1613  		ResourceTypes: map[string]*configschema.Block{
  1614  			"aws_instance": {
  1615  				Attributes: map[string]*configschema.Attribute{
  1616  					"id": {
  1617  						Type:     cty.String,
  1618  						Computed: true,
  1619  					},
  1620  				},
  1621  			},
  1622  			"aws_vpc": {
  1623  				Attributes: map[string]*configschema.Attribute{
  1624  					"id": {
  1625  						Type:     cty.String,
  1626  						Computed: true,
  1627  					},
  1628  					"value": {
  1629  						Type:     cty.String,
  1630  						Optional: true,
  1631  					},
  1632  				},
  1633  			},
  1634  		},
  1635  	})
  1636  
  1637  	providers := map[addrs.Provider]providers.Factory{
  1638  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p_aws),
  1639  	}
  1640  
  1641  	ctx, m, state := getContextForApply_destroyCrossProviders(t, m, providers)
  1642  
  1643  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1644  		Mode: plans.DestroyMode,
  1645  	})
  1646  	assertNoErrors(t, diags)
  1647  
  1648  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1649  		logDiagnostics(t, diags)
  1650  		t.Fatal("apply failed")
  1651  	}
  1652  }
  1653  
  1654  func getContextForApply_destroyCrossProviders(t *testing.T, m *configs.Config, providerFactories map[addrs.Provider]providers.Factory) (*Context, *configs.Config, *states.State) {
  1655  	state := states.NewState()
  1656  	root := state.EnsureModule(addrs.RootModuleInstance)
  1657  	root.SetResourceInstanceCurrent(
  1658  		mustResourceInstanceAddr("aws_instance.shared").Resource,
  1659  		&states.ResourceInstanceObjectSrc{
  1660  			Status:    states.ObjectReady,
  1661  			AttrsJSON: []byte(`{"id":"test"}`),
  1662  		},
  1663  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1664  	)
  1665  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1666  	child.SetResourceInstanceCurrent(
  1667  		mustResourceInstanceAddr("aws_vpc.bar").Resource,
  1668  		&states.ResourceInstanceObjectSrc{
  1669  			Status:    states.ObjectReady,
  1670  			AttrsJSON: []byte(`{"id": "vpc-aaabbb12", "value":"test"}`),
  1671  		},
  1672  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1673  	)
  1674  
  1675  	ctx := testContext2(t, &ContextOpts{
  1676  		Providers: providerFactories,
  1677  	})
  1678  
  1679  	return ctx, m, state
  1680  }
  1681  
  1682  func TestContext2Apply_minimal(t *testing.T) {
  1683  	m := testModule(t, "apply-minimal")
  1684  	p := testProvider("aws")
  1685  	p.PlanResourceChangeFn = testDiffFn
  1686  	p.ApplyResourceChangeFn = testApplyFn
  1687  	ctx := testContext2(t, &ContextOpts{
  1688  		Providers: map[addrs.Provider]providers.Factory{
  1689  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1690  		},
  1691  	})
  1692  
  1693  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1694  	assertNoErrors(t, diags)
  1695  
  1696  	state, diags := ctx.Apply(plan, m)
  1697  	if diags.HasErrors() {
  1698  		t.Fatalf("diags: %s", diags.Err())
  1699  	}
  1700  
  1701  	actual := strings.TrimSpace(state.String())
  1702  	expected := strings.TrimSpace(testTerraformApplyMinimalStr)
  1703  	if actual != expected {
  1704  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1705  	}
  1706  }
  1707  
  1708  func TestContext2Apply_cancel(t *testing.T) {
  1709  	stopped := false
  1710  
  1711  	m := testModule(t, "apply-cancel")
  1712  	p := testProvider("aws")
  1713  	ctx := testContext2(t, &ContextOpts{
  1714  		Providers: map[addrs.Provider]providers.Factory{
  1715  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1716  		},
  1717  	})
  1718  
  1719  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1720  		if !stopped {
  1721  			stopped = true
  1722  			go ctx.Stop()
  1723  
  1724  			for {
  1725  				if ctx.sh.Stopped() {
  1726  					break
  1727  				}
  1728  				time.Sleep(10 * time.Millisecond)
  1729  			}
  1730  		}
  1731  		return testApplyFn(req)
  1732  	}
  1733  	p.PlanResourceChangeFn = testDiffFn
  1734  
  1735  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1736  	assertNoErrors(t, diags)
  1737  
  1738  	// Start the Apply in a goroutine
  1739  	var applyDiags tfdiags.Diagnostics
  1740  	stateCh := make(chan *states.State)
  1741  	go func() {
  1742  		state, diags := ctx.Apply(plan, m)
  1743  		applyDiags = diags
  1744  
  1745  		stateCh <- state
  1746  	}()
  1747  
  1748  	state := <-stateCh
  1749  	// only expecting an early exit error
  1750  	if !applyDiags.HasErrors() {
  1751  		t.Fatal("expected early exit error")
  1752  	}
  1753  
  1754  	for _, d := range applyDiags {
  1755  		desc := d.Description()
  1756  		if desc.Summary != "execution halted" {
  1757  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  1758  		}
  1759  	}
  1760  
  1761  	actual := strings.TrimSpace(state.String())
  1762  	expected := strings.TrimSpace(testTerraformApplyCancelStr)
  1763  	if actual != expected {
  1764  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1765  	}
  1766  
  1767  	if !p.StopCalled {
  1768  		t.Fatal("stop should be called")
  1769  	}
  1770  }
  1771  
  1772  func TestContext2Apply_cancelBlock(t *testing.T) {
  1773  	m := testModule(t, "apply-cancel-block")
  1774  	p := testProvider("aws")
  1775  	ctx := testContext2(t, &ContextOpts{
  1776  		Providers: map[addrs.Provider]providers.Factory{
  1777  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1778  		},
  1779  	})
  1780  
  1781  	applyCh := make(chan struct{})
  1782  	p.PlanResourceChangeFn = testDiffFn
  1783  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1784  		close(applyCh)
  1785  
  1786  		for !ctx.sh.Stopped() {
  1787  			// Wait for stop to be called. We call Gosched here so that
  1788  			// the other goroutines can always be scheduled to set Stopped.
  1789  			runtime.Gosched()
  1790  		}
  1791  
  1792  		// Sleep
  1793  		time.Sleep(100 * time.Millisecond)
  1794  		return testApplyFn(req)
  1795  	}
  1796  
  1797  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1798  	assertNoErrors(t, diags)
  1799  
  1800  	// Start the Apply in a goroutine
  1801  	var applyDiags tfdiags.Diagnostics
  1802  	stateCh := make(chan *states.State)
  1803  	go func() {
  1804  		state, diags := ctx.Apply(plan, m)
  1805  		applyDiags = diags
  1806  
  1807  		stateCh <- state
  1808  	}()
  1809  
  1810  	stopDone := make(chan struct{})
  1811  	go func() {
  1812  		defer close(stopDone)
  1813  		<-applyCh
  1814  		ctx.Stop()
  1815  	}()
  1816  
  1817  	// Make sure that stop blocks
  1818  	select {
  1819  	case <-stopDone:
  1820  		t.Fatal("stop should block")
  1821  	case <-time.After(10 * time.Millisecond):
  1822  	}
  1823  
  1824  	// Wait for stop
  1825  	select {
  1826  	case <-stopDone:
  1827  	case <-time.After(500 * time.Millisecond):
  1828  		t.Fatal("stop should be done")
  1829  	}
  1830  
  1831  	// Wait for apply to complete
  1832  	state := <-stateCh
  1833  	// only expecting an early exit error
  1834  	if !applyDiags.HasErrors() {
  1835  		t.Fatal("expected early exit error")
  1836  	}
  1837  
  1838  	for _, d := range applyDiags {
  1839  		desc := d.Description()
  1840  		if desc.Summary != "execution halted" {
  1841  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  1842  		}
  1843  	}
  1844  
  1845  	checkStateString(t, state, `
  1846  aws_instance.foo:
  1847    ID = foo
  1848    provider = provider["registry.terraform.io/hashicorp/aws"]
  1849    num = 2
  1850    type = aws_instance
  1851  	`)
  1852  }
  1853  
  1854  func TestContext2Apply_cancelProvisioner(t *testing.T) {
  1855  	m := testModule(t, "apply-cancel-provisioner")
  1856  	p := testProvider("aws")
  1857  	p.PlanResourceChangeFn = testDiffFn
  1858  	p.ApplyResourceChangeFn = testApplyFn
  1859  
  1860  	pr := testProvisioner()
  1861  	pr.GetSchemaResponse = provisioners.GetSchemaResponse{
  1862  		Provisioner: &configschema.Block{
  1863  			Attributes: map[string]*configschema.Attribute{
  1864  				"foo": {
  1865  					Type:     cty.String,
  1866  					Optional: true,
  1867  				},
  1868  			},
  1869  		},
  1870  	}
  1871  
  1872  	ctx := testContext2(t, &ContextOpts{
  1873  		Providers: map[addrs.Provider]providers.Factory{
  1874  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1875  		},
  1876  		Provisioners: map[string]provisioners.Factory{
  1877  			"shell": testProvisionerFuncFixed(pr),
  1878  		},
  1879  	})
  1880  
  1881  	prStopped := make(chan struct{})
  1882  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  1883  		// Start the stop process
  1884  		go ctx.Stop()
  1885  
  1886  		<-prStopped
  1887  		return
  1888  	}
  1889  	pr.StopFn = func() error {
  1890  		close(prStopped)
  1891  		return nil
  1892  	}
  1893  
  1894  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1895  	assertNoErrors(t, diags)
  1896  
  1897  	// Start the Apply in a goroutine
  1898  	var applyDiags tfdiags.Diagnostics
  1899  	stateCh := make(chan *states.State)
  1900  	go func() {
  1901  		state, diags := ctx.Apply(plan, m)
  1902  		applyDiags = diags
  1903  
  1904  		stateCh <- state
  1905  	}()
  1906  
  1907  	// Wait for completion
  1908  	state := <-stateCh
  1909  
  1910  	// we are expecting only an early exit error
  1911  	if !applyDiags.HasErrors() {
  1912  		t.Fatal("expected early exit error")
  1913  	}
  1914  
  1915  	for _, d := range applyDiags {
  1916  		desc := d.Description()
  1917  		if desc.Summary != "execution halted" {
  1918  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  1919  		}
  1920  	}
  1921  
  1922  	checkStateString(t, state, `
  1923  aws_instance.foo: (tainted)
  1924    ID = foo
  1925    provider = provider["registry.terraform.io/hashicorp/aws"]
  1926    num = 2
  1927    type = aws_instance
  1928  	`)
  1929  
  1930  	if !pr.StopCalled {
  1931  		t.Fatal("stop should be called")
  1932  	}
  1933  }
  1934  
  1935  func TestContext2Apply_compute(t *testing.T) {
  1936  	m := testModule(t, "apply-compute")
  1937  	p := testProvider("aws")
  1938  	p.PlanResourceChangeFn = testDiffFn
  1939  	p.ApplyResourceChangeFn = testApplyFn
  1940  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1941  		ResourceTypes: map[string]*configschema.Block{
  1942  			"aws_instance": {
  1943  				Attributes: map[string]*configschema.Attribute{
  1944  					"num": {
  1945  						Type:     cty.Number,
  1946  						Optional: true,
  1947  					},
  1948  					"compute": {
  1949  						Type:     cty.String,
  1950  						Optional: true,
  1951  					},
  1952  					"compute_value": {
  1953  						Type:     cty.String,
  1954  						Optional: true,
  1955  					},
  1956  					"foo": {
  1957  						Type:     cty.String,
  1958  						Optional: true,
  1959  					},
  1960  					"id": {
  1961  						Type:     cty.String,
  1962  						Computed: true,
  1963  					},
  1964  					"type": {
  1965  						Type:     cty.String,
  1966  						Computed: true,
  1967  					},
  1968  					"value": { // Populated from compute_value because compute = "value" in the config fixture
  1969  						Type:     cty.String,
  1970  						Computed: true,
  1971  					},
  1972  				},
  1973  			},
  1974  		},
  1975  	})
  1976  
  1977  	ctx := testContext2(t, &ContextOpts{
  1978  		Providers: map[addrs.Provider]providers.Factory{
  1979  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1980  		},
  1981  	})
  1982  
  1983  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  1984  		SetVariables: InputValues{
  1985  			"value": &InputValue{
  1986  				Value:      cty.NumberIntVal(1),
  1987  				SourceType: ValueFromCaller,
  1988  			},
  1989  		},
  1990  	})
  1991  	assertNoErrors(t, diags)
  1992  
  1993  	state, diags := ctx.Apply(plan, m)
  1994  	if diags.HasErrors() {
  1995  		t.Fatalf("unexpected errors: %s", diags.Err())
  1996  	}
  1997  
  1998  	actual := strings.TrimSpace(state.String())
  1999  	expected := strings.TrimSpace(testTerraformApplyComputeStr)
  2000  	if actual != expected {
  2001  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2002  	}
  2003  }
  2004  
  2005  func TestContext2Apply_countDecrease(t *testing.T) {
  2006  	m := testModule(t, "apply-count-dec")
  2007  	p := testProvider("aws")
  2008  	p.PlanResourceChangeFn = testDiffFn
  2009  	p.ApplyResourceChangeFn = testApplyFn
  2010  	state := states.NewState()
  2011  	root := state.EnsureModule(addrs.RootModuleInstance)
  2012  	root.SetResourceInstanceCurrent(
  2013  		mustResourceInstanceAddr("aws_instance.foo[0]").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[1]").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  	root.SetResourceInstanceCurrent(
  2029  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  2030  		&states.ResourceInstanceObjectSrc{
  2031  			Status:    states.ObjectReady,
  2032  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  2033  		},
  2034  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2035  	)
  2036  
  2037  	ctx := testContext2(t, &ContextOpts{
  2038  		Providers: map[addrs.Provider]providers.Factory{
  2039  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2040  		},
  2041  	})
  2042  
  2043  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2044  	assertNoErrors(t, diags)
  2045  
  2046  	s, diags := ctx.Apply(plan, m)
  2047  	assertNoErrors(t, diags)
  2048  
  2049  	actual := strings.TrimSpace(s.String())
  2050  	expected := strings.TrimSpace(testTerraformApplyCountDecStr)
  2051  	if actual != expected {
  2052  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2053  	}
  2054  }
  2055  
  2056  func TestContext2Apply_countDecreaseToOneX(t *testing.T) {
  2057  	m := testModule(t, "apply-count-dec-one")
  2058  	p := testProvider("aws")
  2059  	p.PlanResourceChangeFn = testDiffFn
  2060  	state := states.NewState()
  2061  	root := state.EnsureModule(addrs.RootModuleInstance)
  2062  	root.SetResourceInstanceCurrent(
  2063  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2064  		&states.ResourceInstanceObjectSrc{
  2065  			Status:    states.ObjectReady,
  2066  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  2067  		},
  2068  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2069  	)
  2070  	root.SetResourceInstanceCurrent(
  2071  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  2072  		&states.ResourceInstanceObjectSrc{
  2073  			Status:    states.ObjectReady,
  2074  			AttrsJSON: []byte(`{"id":"bar"}`),
  2075  		},
  2076  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2077  	)
  2078  	root.SetResourceInstanceCurrent(
  2079  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  2080  		&states.ResourceInstanceObjectSrc{
  2081  			Status:    states.ObjectReady,
  2082  			AttrsJSON: []byte(`{"id":"bar"}`),
  2083  		},
  2084  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2085  	)
  2086  
  2087  	ctx := testContext2(t, &ContextOpts{
  2088  		Providers: map[addrs.Provider]providers.Factory{
  2089  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2090  		},
  2091  	})
  2092  
  2093  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2094  	assertNoErrors(t, diags)
  2095  
  2096  	s, diags := ctx.Apply(plan, m)
  2097  	if diags.HasErrors() {
  2098  		t.Fatalf("diags: %s", diags.Err())
  2099  	}
  2100  
  2101  	actual := strings.TrimSpace(s.String())
  2102  	expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr)
  2103  	if actual != expected {
  2104  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2105  	}
  2106  }
  2107  
  2108  // https://github.com/PeoplePerHour/terraform/pull/11
  2109  //
  2110  // This tests a rare but possible situation where we have both a no-key and
  2111  // a zero-key instance of the same resource in the configuration when we
  2112  // disable count.
  2113  //
  2114  // The main way to get here is for a provider to fail to destroy the zero-key
  2115  // instance but succeed in creating the no-key instance, since those two
  2116  // can typically happen concurrently. There are various other ways to get here
  2117  // that might be considered user error, such as using "terraform state mv"
  2118  // to create a strange combination of different key types on the same resource.
  2119  //
  2120  // This test indirectly exercises an intentional interaction between
  2121  // refactoring.ImpliedMoveStatements and refactoring.ApplyMoves: we'll first
  2122  // generate an implied move statement from aws_instance.foo[0] to
  2123  // aws_instance.foo, but then refactoring.ApplyMoves should notice that and
  2124  // ignore the statement, in the same way as it would if an explicit move
  2125  // statement specified the same situation.
  2126  func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) {
  2127  	m := testModule(t, "apply-count-dec-one")
  2128  	p := testProvider("aws")
  2129  	p.PlanResourceChangeFn = testDiffFn
  2130  	state := states.NewState()
  2131  	root := state.EnsureModule(addrs.RootModuleInstance)
  2132  	root.SetResourceInstanceCurrent(
  2133  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2134  		&states.ResourceInstanceObjectSrc{
  2135  			Status:    states.ObjectReady,
  2136  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  2137  		},
  2138  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2139  	)
  2140  	root.SetResourceInstanceCurrent(
  2141  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2142  		&states.ResourceInstanceObjectSrc{
  2143  			Status:    states.ObjectReady,
  2144  			AttrsJSON: []byte(`{"id":"baz", "type": "aws_instance"}`),
  2145  		},
  2146  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2147  	)
  2148  
  2149  	ctx := testContext2(t, &ContextOpts{
  2150  		Providers: map[addrs.Provider]providers.Factory{
  2151  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2152  		},
  2153  	})
  2154  
  2155  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2156  	assertNoErrors(t, diags)
  2157  	{
  2158  		got := strings.TrimSpace(legacyPlanComparisonString(state, plan.Changes))
  2159  		want := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedPlanStr)
  2160  		if got != want {
  2161  			t.Fatalf("wrong plan result\ngot:\n%s\nwant:\n%s", got, want)
  2162  		}
  2163  	}
  2164  	{
  2165  		change := plan.Changes.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo[0]"))
  2166  		if change == nil {
  2167  			t.Fatalf("no planned change for instance zero")
  2168  		}
  2169  		if got, want := change.Action, plans.Delete; got != want {
  2170  			t.Errorf("wrong action for instance zero %s; want %s", got, want)
  2171  		}
  2172  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want {
  2173  			t.Errorf("wrong action reason for instance zero %s; want %s", got, want)
  2174  		}
  2175  	}
  2176  	{
  2177  		change := plan.Changes.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo"))
  2178  		if change == nil {
  2179  			t.Fatalf("no planned change for no-key instance")
  2180  		}
  2181  		if got, want := change.Action, plans.NoOp; got != want {
  2182  			t.Errorf("wrong action for no-key instance %s; want %s", got, want)
  2183  		}
  2184  		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
  2185  			t.Errorf("wrong action reason for no-key instance %s; want %s", got, want)
  2186  		}
  2187  	}
  2188  
  2189  	s, diags := ctx.Apply(plan, m)
  2190  	if diags.HasErrors() {
  2191  		t.Fatalf("diags: %s", diags.Err())
  2192  	}
  2193  
  2194  	actual := strings.TrimSpace(s.String())
  2195  	expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr)
  2196  	if actual != expected {
  2197  		t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2198  	}
  2199  }
  2200  
  2201  func TestContext2Apply_countTainted(t *testing.T) {
  2202  	m := testModule(t, "apply-count-tainted")
  2203  	p := testProvider("aws")
  2204  	p.PlanResourceChangeFn = testDiffFn
  2205  	p.ApplyResourceChangeFn = testApplyFn
  2206  	state := states.NewState()
  2207  	root := state.EnsureModule(addrs.RootModuleInstance)
  2208  	root.SetResourceInstanceCurrent(
  2209  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2210  		&states.ResourceInstanceObjectSrc{
  2211  			Status:    states.ObjectTainted,
  2212  			AttrsJSON: []byte(`{"id":"bar", "type": "aws_instance", "foo": "foo"}`),
  2213  		},
  2214  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2215  	)
  2216  	ctx := testContext2(t, &ContextOpts{
  2217  		Providers: map[addrs.Provider]providers.Factory{
  2218  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2219  		},
  2220  	})
  2221  
  2222  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2223  	assertNoErrors(t, diags)
  2224  	{
  2225  		got := strings.TrimSpace(legacyDiffComparisonString(plan.Changes))
  2226  		want := strings.TrimSpace(`
  2227  DESTROY/CREATE: aws_instance.foo[0]
  2228    foo:  "foo" => "foo"
  2229    id:   "bar" => "<computed>"
  2230    type: "aws_instance" => "<computed>"
  2231  CREATE: aws_instance.foo[1]
  2232    foo:  "" => "foo"
  2233    id:   "" => "<computed>"
  2234    type: "" => "<computed>"
  2235  `)
  2236  		if got != want {
  2237  			t.Fatalf("wrong plan\n\ngot:\n%s\n\nwant:\n%s", got, want)
  2238  		}
  2239  	}
  2240  
  2241  	s, diags := ctx.Apply(plan, m)
  2242  	assertNoErrors(t, diags)
  2243  
  2244  	got := strings.TrimSpace(s.String())
  2245  	want := strings.TrimSpace(`
  2246  aws_instance.foo.0:
  2247    ID = foo
  2248    provider = provider["registry.terraform.io/hashicorp/aws"]
  2249    foo = foo
  2250    type = aws_instance
  2251  aws_instance.foo.1:
  2252    ID = foo
  2253    provider = provider["registry.terraform.io/hashicorp/aws"]
  2254    foo = foo
  2255    type = aws_instance
  2256  `)
  2257  	if got != want {
  2258  		t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", got, want)
  2259  	}
  2260  }
  2261  
  2262  func TestContext2Apply_countVariable(t *testing.T) {
  2263  	m := testModule(t, "apply-count-variable")
  2264  	p := testProvider("aws")
  2265  	p.PlanResourceChangeFn = testDiffFn
  2266  	p.ApplyResourceChangeFn = testApplyFn
  2267  	ctx := testContext2(t, &ContextOpts{
  2268  		Providers: map[addrs.Provider]providers.Factory{
  2269  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2270  		},
  2271  	})
  2272  
  2273  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  2274  	assertNoErrors(t, diags)
  2275  
  2276  	state, diags := ctx.Apply(plan, m)
  2277  	if diags.HasErrors() {
  2278  		t.Fatalf("diags: %s", diags.Err())
  2279  	}
  2280  
  2281  	actual := strings.TrimSpace(state.String())
  2282  	expected := strings.TrimSpace(testTerraformApplyCountVariableStr)
  2283  	if actual != expected {
  2284  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2285  	}
  2286  }
  2287  
  2288  func TestContext2Apply_countVariableRef(t *testing.T) {
  2289  	m := testModule(t, "apply-count-variable-ref")
  2290  	p := testProvider("aws")
  2291  	p.PlanResourceChangeFn = testDiffFn
  2292  	p.ApplyResourceChangeFn = testApplyFn
  2293  	ctx := testContext2(t, &ContextOpts{
  2294  		Providers: map[addrs.Provider]providers.Factory{
  2295  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2296  		},
  2297  	})
  2298  
  2299  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  2300  	assertNoErrors(t, diags)
  2301  
  2302  	state, diags := ctx.Apply(plan, m)
  2303  	if diags.HasErrors() {
  2304  		t.Fatalf("diags: %s", diags.Err())
  2305  	}
  2306  
  2307  	actual := strings.TrimSpace(state.String())
  2308  	expected := strings.TrimSpace(testTerraformApplyCountVariableRefStr)
  2309  	if actual != expected {
  2310  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2311  	}
  2312  }
  2313  
  2314  func TestContext2Apply_provisionerInterpCount(t *testing.T) {
  2315  	// This test ensures that a provisioner can interpolate a resource count
  2316  	// even though the provisioner expression is evaluated during the plan
  2317  	// walk. https://github.com/hashicorp/terraform/issues/16840
  2318  
  2319  	m, snap := testModuleWithSnapshot(t, "apply-provisioner-interp-count")
  2320  
  2321  	p := testProvider("aws")
  2322  	p.PlanResourceChangeFn = testDiffFn
  2323  
  2324  	pr := testProvisioner()
  2325  
  2326  	Providers := map[addrs.Provider]providers.Factory{
  2327  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2328  	}
  2329  
  2330  	provisioners := map[string]provisioners.Factory{
  2331  		"local-exec": testProvisionerFuncFixed(pr),
  2332  	}
  2333  	ctx := testContext2(t, &ContextOpts{
  2334  		Providers:    Providers,
  2335  		Provisioners: provisioners,
  2336  	})
  2337  
  2338  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  2339  	assertNoErrors(t, diags)
  2340  
  2341  	// We'll marshal and unmarshal the plan here, to ensure that we have
  2342  	// a clean new context as would be created if we separately ran
  2343  	// terraform plan -out=tfplan && terraform apply tfplan
  2344  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  2345  	if err != nil {
  2346  		t.Fatal(err)
  2347  	}
  2348  	ctxOpts.Providers = Providers
  2349  	ctxOpts.Provisioners = provisioners
  2350  	ctx, diags = NewContext(ctxOpts)
  2351  	if diags.HasErrors() {
  2352  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  2353  	}
  2354  
  2355  	// Applying the plan should now succeed
  2356  	_, diags = ctx.Apply(plan, m)
  2357  	if diags.HasErrors() {
  2358  		t.Fatalf("apply failed unexpectedly: %s", diags.Err())
  2359  	}
  2360  
  2361  	// Verify apply was invoked
  2362  	if !pr.ProvisionResourceCalled {
  2363  		t.Fatalf("provisioner was not called")
  2364  	}
  2365  }
  2366  
  2367  func TestContext2Apply_foreachVariable(t *testing.T) {
  2368  	m := testModule(t, "plan-for-each-unknown-value")
  2369  	p := testProvider("aws")
  2370  	p.PlanResourceChangeFn = testDiffFn
  2371  	p.ApplyResourceChangeFn = testApplyFn
  2372  	ctx := testContext2(t, &ContextOpts{
  2373  		Providers: map[addrs.Provider]providers.Factory{
  2374  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2375  		},
  2376  	})
  2377  
  2378  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2379  		Mode: plans.NormalMode,
  2380  		SetVariables: InputValues{
  2381  			"foo": &InputValue{
  2382  				Value: cty.StringVal("hello"),
  2383  			},
  2384  		},
  2385  	})
  2386  	assertNoErrors(t, diags)
  2387  
  2388  	state, diags := ctx.Apply(plan, m)
  2389  	if diags.HasErrors() {
  2390  		t.Fatalf("diags: %s", diags.Err())
  2391  	}
  2392  
  2393  	actual := strings.TrimSpace(state.String())
  2394  	expected := strings.TrimSpace(testTerraformApplyForEachVariableStr)
  2395  	if actual != expected {
  2396  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2397  	}
  2398  }
  2399  
  2400  func TestContext2Apply_moduleBasic(t *testing.T) {
  2401  	m := testModule(t, "apply-module")
  2402  	p := testProvider("aws")
  2403  	p.PlanResourceChangeFn = testDiffFn
  2404  	p.ApplyResourceChangeFn = testApplyFn
  2405  	ctx := testContext2(t, &ContextOpts{
  2406  		Providers: map[addrs.Provider]providers.Factory{
  2407  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2408  		},
  2409  	})
  2410  
  2411  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2412  	assertNoErrors(t, diags)
  2413  
  2414  	state, diags := ctx.Apply(plan, m)
  2415  	if diags.HasErrors() {
  2416  		t.Fatalf("diags: %s", diags.Err())
  2417  	}
  2418  
  2419  	actual := strings.TrimSpace(state.String())
  2420  	expected := strings.TrimSpace(testTerraformApplyModuleStr)
  2421  	if actual != expected {
  2422  		t.Fatalf("bad, expected:\n%s\n\nactual:\n%s", expected, actual)
  2423  	}
  2424  }
  2425  
  2426  func TestContext2Apply_moduleDestroyOrder(t *testing.T) {
  2427  	m := testModule(t, "apply-module-destroy-order")
  2428  	p := testProvider("aws")
  2429  	p.PlanResourceChangeFn = testDiffFn
  2430  
  2431  	// Create a custom apply function to track the order they were destroyed
  2432  	var order []string
  2433  	var orderLock sync.Mutex
  2434  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  2435  		id := req.PriorState.GetAttr("id").AsString()
  2436  
  2437  		if id == "b" {
  2438  			// Pause briefly to make any race conditions more visible, since
  2439  			// missing edges here can cause undeterministic ordering.
  2440  			time.Sleep(100 * time.Millisecond)
  2441  		}
  2442  
  2443  		orderLock.Lock()
  2444  		defer orderLock.Unlock()
  2445  
  2446  		order = append(order, id)
  2447  		resp.NewState = req.PlannedState
  2448  		return resp
  2449  	}
  2450  
  2451  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2452  		ResourceTypes: map[string]*configschema.Block{
  2453  			"aws_instance": {
  2454  				Attributes: map[string]*configschema.Attribute{
  2455  					"id":    {Type: cty.String, Required: true},
  2456  					"blah":  {Type: cty.String, Optional: true},
  2457  					"value": {Type: cty.String, Optional: true},
  2458  				},
  2459  			},
  2460  		},
  2461  	})
  2462  
  2463  	state := states.NewState()
  2464  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2465  	child.SetResourceInstanceCurrent(
  2466  		mustResourceInstanceAddr("aws_instance.a").Resource,
  2467  		&states.ResourceInstanceObjectSrc{
  2468  			Status:    states.ObjectReady,
  2469  			AttrsJSON: []byte(`{"id":"a"}`),
  2470  		},
  2471  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2472  	)
  2473  	root := state.EnsureModule(addrs.RootModuleInstance)
  2474  	root.SetResourceInstanceCurrent(
  2475  		mustResourceInstanceAddr("aws_instance.b").Resource,
  2476  		&states.ResourceInstanceObjectSrc{
  2477  			Status:       states.ObjectReady,
  2478  			AttrsJSON:    []byte(`{"id":"b"}`),
  2479  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.a")},
  2480  		},
  2481  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2482  	)
  2483  
  2484  	ctx := testContext2(t, &ContextOpts{
  2485  		Providers: map[addrs.Provider]providers.Factory{
  2486  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2487  		},
  2488  	})
  2489  
  2490  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  2491  		Mode: plans.DestroyMode,
  2492  	})
  2493  	assertNoErrors(t, diags)
  2494  
  2495  	state, diags = ctx.Apply(plan, m)
  2496  	if diags.HasErrors() {
  2497  		t.Fatalf("diags: %s", diags.Err())
  2498  	}
  2499  
  2500  	expected := []string{"b", "a"}
  2501  	if !reflect.DeepEqual(order, expected) {
  2502  		t.Errorf("wrong order\ngot: %#v\nwant: %#v", order, expected)
  2503  	}
  2504  
  2505  	{
  2506  		actual := strings.TrimSpace(state.String())
  2507  		expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr)
  2508  		if actual != expected {
  2509  			t.Errorf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2510  		}
  2511  	}
  2512  }
  2513  
  2514  func TestContext2Apply_moduleInheritAlias(t *testing.T) {
  2515  	m := testModule(t, "apply-module-provider-inherit-alias")
  2516  	p := testProvider("aws")
  2517  	p.PlanResourceChangeFn = testDiffFn
  2518  	p.ApplyResourceChangeFn = testApplyFn
  2519  
  2520  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2521  		val := req.Config.GetAttr("value")
  2522  		if val.IsNull() {
  2523  			return
  2524  		}
  2525  
  2526  		root := req.Config.GetAttr("root")
  2527  		if !root.IsNull() {
  2528  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root"))
  2529  		}
  2530  
  2531  		return
  2532  	}
  2533  
  2534  	ctx := testContext2(t, &ContextOpts{
  2535  		Providers: map[addrs.Provider]providers.Factory{
  2536  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2537  		},
  2538  	})
  2539  
  2540  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2541  	assertNoErrors(t, diags)
  2542  
  2543  	state, diags := ctx.Apply(plan, m)
  2544  	if diags.HasErrors() {
  2545  		t.Fatalf("diags: %s", diags.Err())
  2546  	}
  2547  
  2548  	checkStateString(t, state, `
  2549  <no state>
  2550  module.child:
  2551    aws_instance.foo:
  2552      ID = foo
  2553      provider = provider["registry.terraform.io/hashicorp/aws"].eu
  2554      type = aws_instance
  2555  	`)
  2556  }
  2557  
  2558  func TestContext2Apply_orphanResource(t *testing.T) {
  2559  	// This is a two-step test:
  2560  	// 1. Apply a configuration with resources that have count set.
  2561  	//    This should place the empty resource object in the state to record
  2562  	//    that each exists, and record any instances.
  2563  	// 2. Apply an empty configuration against the same state, which should
  2564  	//    then clean up both the instances and the containing resource objects.
  2565  	p := testProvider("test")
  2566  	p.PlanResourceChangeFn = testDiffFn
  2567  	p.ApplyResourceChangeFn = testApplyFn
  2568  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2569  		ResourceTypes: map[string]*configschema.Block{
  2570  			"test_thing": {
  2571  				Attributes: map[string]*configschema.Attribute{
  2572  					"id":  {Type: cty.String, Computed: true},
  2573  					"foo": {Type: cty.String, Optional: true},
  2574  				},
  2575  			},
  2576  		},
  2577  	})
  2578  
  2579  	// Step 1: create the resources and instances
  2580  	m := testModule(t, "apply-orphan-resource")
  2581  	ctx := testContext2(t, &ContextOpts{
  2582  		Providers: map[addrs.Provider]providers.Factory{
  2583  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  2584  		},
  2585  	})
  2586  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2587  	assertNoErrors(t, diags)
  2588  	state, diags := ctx.Apply(plan, m)
  2589  	assertNoErrors(t, diags)
  2590  
  2591  	// At this point both resources should be recorded in the state, along
  2592  	// with the single instance associated with test_thing.one.
  2593  	want := states.BuildState(func(s *states.SyncState) {
  2594  		providerAddr := addrs.AbsProviderConfig{
  2595  			Provider: addrs.NewDefaultProvider("test"),
  2596  			Module:   addrs.RootModule,
  2597  		}
  2598  		oneAddr := addrs.Resource{
  2599  			Mode: addrs.ManagedResourceMode,
  2600  			Type: "test_thing",
  2601  			Name: "one",
  2602  		}.Absolute(addrs.RootModuleInstance)
  2603  		s.SetResourceProvider(oneAddr, providerAddr)
  2604  		s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{
  2605  			Status:    states.ObjectReady,
  2606  			AttrsJSON: []byte(`{"id":"foo"}`),
  2607  		}, providerAddr)
  2608  	})
  2609  
  2610  	if state.String() != want.String() {
  2611  		t.Fatalf("wrong state after step 1\n%s", cmp.Diff(want, state))
  2612  	}
  2613  
  2614  	// Step 2: update with an empty config, to destroy everything
  2615  	m = testModule(t, "empty")
  2616  	ctx = testContext2(t, &ContextOpts{
  2617  		Providers: map[addrs.Provider]providers.Factory{
  2618  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  2619  		},
  2620  	})
  2621  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  2622  	assertNoErrors(t, diags)
  2623  	{
  2624  		addr := mustResourceInstanceAddr("test_thing.one[0]")
  2625  		change := plan.Changes.ResourceInstance(addr)
  2626  		if change == nil {
  2627  			t.Fatalf("no planned change for %s", addr)
  2628  		}
  2629  		if got, want := change.Action, plans.Delete; got != want {
  2630  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2631  		}
  2632  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want {
  2633  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2634  		}
  2635  	}
  2636  
  2637  	state, diags = ctx.Apply(plan, m)
  2638  	assertNoErrors(t, diags)
  2639  
  2640  	// The state should now be _totally_ empty, with just an empty root module
  2641  	// (since that always exists) and no resources at all.
  2642  	want = states.NewState()
  2643  	want.CheckResults = &states.CheckResults{}
  2644  	if !cmp.Equal(state, want) {
  2645  		t.Fatalf("wrong state after step 2\ngot: %swant: %s", spew.Sdump(state), spew.Sdump(want))
  2646  	}
  2647  
  2648  }
  2649  
  2650  func TestContext2Apply_moduleOrphanInheritAlias(t *testing.T) {
  2651  	m := testModule(t, "apply-module-provider-inherit-alias-orphan")
  2652  	p := testProvider("aws")
  2653  	p.PlanResourceChangeFn = testDiffFn
  2654  
  2655  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2656  		val := req.Config.GetAttr("value")
  2657  		if val.IsNull() {
  2658  			return
  2659  		}
  2660  
  2661  		root := req.Config.GetAttr("root")
  2662  		if !root.IsNull() {
  2663  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root"))
  2664  		}
  2665  
  2666  		return
  2667  	}
  2668  
  2669  	// Create a state with an orphan module
  2670  	state := states.NewState()
  2671  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2672  	child.SetResourceInstanceCurrent(
  2673  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2674  		&states.ResourceInstanceObjectSrc{
  2675  			Status:    states.ObjectReady,
  2676  			AttrsJSON: []byte(`{"id":"bar"}`),
  2677  		},
  2678  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2679  	)
  2680  
  2681  	ctx := testContext2(t, &ContextOpts{
  2682  		Providers: map[addrs.Provider]providers.Factory{
  2683  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2684  		},
  2685  	})
  2686  
  2687  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2688  	assertNoErrors(t, diags)
  2689  	{
  2690  		addr := mustResourceInstanceAddr("module.child.aws_instance.bar")
  2691  		change := plan.Changes.ResourceInstance(addr)
  2692  		if change == nil {
  2693  			t.Fatalf("no planned change for %s", addr)
  2694  		}
  2695  		if got, want := change.Action, plans.Delete; got != want {
  2696  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2697  		}
  2698  		// This should ideally be ResourceInstanceDeleteBecauseNoModule, but
  2699  		// the codepath deciding this doesn't currently have enough information
  2700  		// to differentiate, and so this is a compromise.
  2701  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want {
  2702  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  2703  		}
  2704  	}
  2705  
  2706  	state, diags = ctx.Apply(plan, m)
  2707  	if diags.HasErrors() {
  2708  		t.Fatalf("diags: %s", diags.Err())
  2709  	}
  2710  
  2711  	if !p.ConfigureProviderCalled {
  2712  		t.Fatal("must call configure")
  2713  	}
  2714  
  2715  	checkStateString(t, state, "<no state>")
  2716  }
  2717  
  2718  func TestContext2Apply_moduleOrphanProvider(t *testing.T) {
  2719  	m := testModule(t, "apply-module-orphan-provider-inherit")
  2720  	p := testProvider("aws")
  2721  	p.PlanResourceChangeFn = testDiffFn
  2722  
  2723  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2724  		val := req.Config.GetAttr("value")
  2725  		if val.IsNull() {
  2726  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2727  		}
  2728  
  2729  		return
  2730  	}
  2731  
  2732  	// Create a state with an orphan module
  2733  	state := states.NewState()
  2734  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2735  	child.SetResourceInstanceCurrent(
  2736  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2737  		&states.ResourceInstanceObjectSrc{
  2738  			Status:    states.ObjectReady,
  2739  			AttrsJSON: []byte(`{"id":"bar"}`),
  2740  		},
  2741  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2742  	)
  2743  
  2744  	ctx := testContext2(t, &ContextOpts{
  2745  		Providers: map[addrs.Provider]providers.Factory{
  2746  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2747  		},
  2748  	})
  2749  
  2750  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2751  	assertNoErrors(t, diags)
  2752  
  2753  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2754  		t.Fatalf("apply errors: %s", diags.Err())
  2755  	}
  2756  }
  2757  
  2758  func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) {
  2759  	m := testModule(t, "apply-module-orphan-provider-inherit")
  2760  	p := testProvider("aws")
  2761  	p.PlanResourceChangeFn = testDiffFn
  2762  
  2763  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2764  		val := req.Config.GetAttr("value")
  2765  		if val.IsNull() {
  2766  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2767  		}
  2768  
  2769  		return
  2770  	}
  2771  
  2772  	// Create a state with an orphan module that is nested (grandchild)
  2773  	state := states.NewState()
  2774  	child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child", addrs.NoKey))
  2775  	child.SetResourceInstanceCurrent(
  2776  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2777  		&states.ResourceInstanceObjectSrc{
  2778  			Status:    states.ObjectReady,
  2779  			AttrsJSON: []byte(`{"id":"bar"}`),
  2780  		},
  2781  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2782  	)
  2783  
  2784  	ctx := testContext2(t, &ContextOpts{
  2785  		Providers: map[addrs.Provider]providers.Factory{
  2786  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2787  		},
  2788  	})
  2789  
  2790  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2791  	assertNoErrors(t, diags)
  2792  
  2793  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2794  		t.Fatalf("apply errors: %s", diags.Err())
  2795  	}
  2796  }
  2797  
  2798  func TestContext2Apply_moduleGrandchildProvider(t *testing.T) {
  2799  	m := testModule(t, "apply-module-grandchild-provider-inherit")
  2800  	p := testProvider("aws")
  2801  	p.PlanResourceChangeFn = testDiffFn
  2802  
  2803  	var callLock sync.Mutex
  2804  	called := false
  2805  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2806  		val := req.Config.GetAttr("value")
  2807  		if val.IsNull() {
  2808  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2809  		}
  2810  
  2811  		callLock.Lock()
  2812  		called = true
  2813  		callLock.Unlock()
  2814  
  2815  		return
  2816  	}
  2817  
  2818  	ctx := testContext2(t, &ContextOpts{
  2819  		Providers: map[addrs.Provider]providers.Factory{
  2820  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2821  		},
  2822  	})
  2823  
  2824  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2825  	assertNoErrors(t, diags)
  2826  
  2827  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2828  		t.Fatalf("apply errors: %s", diags.Err())
  2829  	}
  2830  
  2831  	callLock.Lock()
  2832  	defer callLock.Unlock()
  2833  	if called != true {
  2834  		t.Fatalf("err: configure never called")
  2835  	}
  2836  }
  2837  
  2838  // This tests an issue where all the providers in a module but not
  2839  // in the root weren't being added to the root properly. In this test
  2840  // case: aws is explicitly added to root, but "test" should be added to.
  2841  // With the bug, it wasn't.
  2842  func TestContext2Apply_moduleOnlyProvider(t *testing.T) {
  2843  	m := testModule(t, "apply-module-only-provider")
  2844  	p := testProvider("aws")
  2845  	p.PlanResourceChangeFn = testDiffFn
  2846  	p.ApplyResourceChangeFn = testApplyFn
  2847  	pTest := testProvider("test")
  2848  	pTest.ApplyResourceChangeFn = testApplyFn
  2849  	pTest.PlanResourceChangeFn = testDiffFn
  2850  
  2851  	ctx := testContext2(t, &ContextOpts{
  2852  		Providers: map[addrs.Provider]providers.Factory{
  2853  			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
  2854  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
  2855  		},
  2856  	})
  2857  
  2858  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2859  	assertNoErrors(t, diags)
  2860  
  2861  	state, diags := ctx.Apply(plan, m)
  2862  	if diags.HasErrors() {
  2863  		t.Fatalf("diags: %s", diags.Err())
  2864  	}
  2865  
  2866  	actual := strings.TrimSpace(state.String())
  2867  	expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr)
  2868  	if actual != expected {
  2869  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2870  	}
  2871  }
  2872  
  2873  func TestContext2Apply_moduleProviderAlias(t *testing.T) {
  2874  	m := testModule(t, "apply-module-provider-alias")
  2875  	p := testProvider("aws")
  2876  	p.PlanResourceChangeFn = testDiffFn
  2877  	p.ApplyResourceChangeFn = testApplyFn
  2878  	ctx := testContext2(t, &ContextOpts{
  2879  		Providers: map[addrs.Provider]providers.Factory{
  2880  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2881  		},
  2882  	})
  2883  
  2884  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2885  	assertNoErrors(t, diags)
  2886  
  2887  	state, diags := ctx.Apply(plan, m)
  2888  	if diags.HasErrors() {
  2889  		t.Fatalf("diags: %s", diags.Err())
  2890  	}
  2891  
  2892  	actual := strings.TrimSpace(state.String())
  2893  	expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr)
  2894  	if actual != expected {
  2895  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2896  	}
  2897  }
  2898  
  2899  func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) {
  2900  	m := testModule(t, "apply-module-provider-alias")
  2901  	p := testProvider("aws")
  2902  	p.PlanResourceChangeFn = testDiffFn
  2903  	ctx := testContext2(t, &ContextOpts{
  2904  		Providers: map[addrs.Provider]providers.Factory{
  2905  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2906  		},
  2907  	})
  2908  
  2909  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2910  		Mode: plans.NormalMode,
  2911  		Targets: []addrs.Targetable{
  2912  			addrs.ConfigResource{
  2913  				Module: addrs.RootModule,
  2914  				Resource: addrs.Resource{
  2915  					Mode: addrs.ManagedResourceMode,
  2916  					Type: "nonexistent",
  2917  					Name: "thing",
  2918  				},
  2919  			},
  2920  		},
  2921  	})
  2922  	assertNoErrors(t, diags)
  2923  
  2924  	state, diags := ctx.Apply(plan, m)
  2925  	if diags.HasErrors() {
  2926  		t.Fatalf("diags: %s", diags.Err())
  2927  	}
  2928  
  2929  	actual := strings.TrimSpace(state.String())
  2930  	expected := strings.TrimSpace(`
  2931  <no state>
  2932  	`)
  2933  	if actual != expected {
  2934  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2935  	}
  2936  }
  2937  
  2938  func TestContext2Apply_moduleProviderCloseNested(t *testing.T) {
  2939  	m := testModule(t, "apply-module-provider-close-nested")
  2940  	p := testProvider("aws")
  2941  	p.PlanResourceChangeFn = testDiffFn
  2942  	state := states.NewState()
  2943  	root := state.EnsureModule(addrs.RootModuleInstance)
  2944  	root.SetResourceInstanceCurrent(
  2945  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2946  		&states.ResourceInstanceObjectSrc{
  2947  			Status:    states.ObjectReady,
  2948  			AttrsJSON: []byte(`{"id":"bar"}`),
  2949  		},
  2950  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2951  	)
  2952  
  2953  	ctx := testContext2(t, &ContextOpts{
  2954  		Providers: map[addrs.Provider]providers.Factory{
  2955  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2956  		},
  2957  	})
  2958  
  2959  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  2960  		Mode: plans.DestroyMode,
  2961  	})
  2962  	assertNoErrors(t, diags)
  2963  
  2964  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2965  		t.Fatalf("apply errors: %s", diags.Err())
  2966  	}
  2967  }
  2968  
  2969  // Tests that variables used as module vars that reference data that
  2970  // already exists in the state and requires no diff works properly. This
  2971  // fixes an issue faced where module variables were pruned because they were
  2972  // accessing "non-existent" resources (they existed, just not in the graph
  2973  // cause they weren't in the diff).
  2974  func TestContext2Apply_moduleVarRefExisting(t *testing.T) {
  2975  	m := testModule(t, "apply-ref-existing")
  2976  	p := testProvider("aws")
  2977  	p.PlanResourceChangeFn = testDiffFn
  2978  	p.ApplyResourceChangeFn = testApplyFn
  2979  	state := states.NewState()
  2980  	root := state.EnsureModule(addrs.RootModuleInstance)
  2981  	root.SetResourceInstanceCurrent(
  2982  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2983  		&states.ResourceInstanceObjectSrc{
  2984  			Status:    states.ObjectReady,
  2985  			AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`),
  2986  		},
  2987  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2988  	)
  2989  
  2990  	ctx := testContext2(t, &ContextOpts{
  2991  		Providers: map[addrs.Provider]providers.Factory{
  2992  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2993  		},
  2994  	})
  2995  
  2996  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2997  	assertNoErrors(t, diags)
  2998  
  2999  	state, diags = ctx.Apply(plan, m)
  3000  	if diags.HasErrors() {
  3001  		t.Fatalf("diags: %s", diags.Err())
  3002  	}
  3003  
  3004  	actual := strings.TrimSpace(state.String())
  3005  	expected := strings.TrimSpace(testTerraformApplyModuleVarRefExistingStr)
  3006  	if actual != expected {
  3007  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3008  	}
  3009  }
  3010  
  3011  func TestContext2Apply_moduleVarResourceCount(t *testing.T) {
  3012  	m := testModule(t, "apply-module-var-resource-count")
  3013  	p := testProvider("aws")
  3014  	p.PlanResourceChangeFn = testDiffFn
  3015  	ctx := testContext2(t, &ContextOpts{
  3016  		Providers: map[addrs.Provider]providers.Factory{
  3017  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3018  		},
  3019  	})
  3020  
  3021  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3022  		Mode: plans.DestroyMode,
  3023  		SetVariables: InputValues{
  3024  			"num": &InputValue{
  3025  				Value:      cty.NumberIntVal(2),
  3026  				SourceType: ValueFromCaller,
  3027  			},
  3028  		},
  3029  	})
  3030  	assertNoErrors(t, diags)
  3031  
  3032  	state, diags := ctx.Apply(plan, m)
  3033  	assertNoErrors(t, diags)
  3034  
  3035  	ctx = testContext2(t, &ContextOpts{
  3036  		Providers: map[addrs.Provider]providers.Factory{
  3037  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3038  		},
  3039  	})
  3040  
  3041  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  3042  		Mode: plans.NormalMode,
  3043  		SetVariables: InputValues{
  3044  			"num": &InputValue{
  3045  				Value:      cty.NumberIntVal(5),
  3046  				SourceType: ValueFromCaller,
  3047  			},
  3048  		},
  3049  	})
  3050  	assertNoErrors(t, diags)
  3051  
  3052  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3053  		t.Fatalf("apply errors: %s", diags.Err())
  3054  	}
  3055  }
  3056  
  3057  // GH-819
  3058  func TestContext2Apply_moduleBool(t *testing.T) {
  3059  	m := testModule(t, "apply-module-bool")
  3060  	p := testProvider("aws")
  3061  	p.PlanResourceChangeFn = testDiffFn
  3062  	p.ApplyResourceChangeFn = testApplyFn
  3063  	ctx := testContext2(t, &ContextOpts{
  3064  		Providers: map[addrs.Provider]providers.Factory{
  3065  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3066  		},
  3067  	})
  3068  
  3069  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3070  	assertNoErrors(t, diags)
  3071  
  3072  	state, diags := ctx.Apply(plan, m)
  3073  	if diags.HasErrors() {
  3074  		t.Fatalf("diags: %s", diags.Err())
  3075  	}
  3076  
  3077  	actual := strings.TrimSpace(state.String())
  3078  	expected := strings.TrimSpace(testTerraformApplyModuleBoolStr)
  3079  	if actual != expected {
  3080  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3081  	}
  3082  }
  3083  
  3084  // Tests that a module can be targeted and everything is properly created.
  3085  // This adds to the plan test to also just verify that apply works.
  3086  func TestContext2Apply_moduleTarget(t *testing.T) {
  3087  	m := testModule(t, "plan-targeted-cross-module")
  3088  	p := testProvider("aws")
  3089  	p.PlanResourceChangeFn = testDiffFn
  3090  	p.ApplyResourceChangeFn = testApplyFn
  3091  	ctx := testContext2(t, &ContextOpts{
  3092  		Providers: map[addrs.Provider]providers.Factory{
  3093  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3094  		},
  3095  	})
  3096  
  3097  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3098  		Mode: plans.NormalMode,
  3099  		Targets: []addrs.Targetable{
  3100  			addrs.RootModuleInstance.Child("B", addrs.NoKey),
  3101  		},
  3102  	})
  3103  	assertNoErrors(t, diags)
  3104  
  3105  	state, diags := ctx.Apply(plan, m)
  3106  	if diags.HasErrors() {
  3107  		t.Fatalf("diags: %s", diags.Err())
  3108  	}
  3109  
  3110  	checkStateString(t, state, `
  3111  <no state>
  3112  module.A:
  3113    aws_instance.foo:
  3114      ID = foo
  3115      provider = provider["registry.terraform.io/hashicorp/aws"]
  3116      foo = bar
  3117      type = aws_instance
  3118  
  3119    Outputs:
  3120  
  3121    value = foo
  3122  module.B:
  3123    aws_instance.bar:
  3124      ID = foo
  3125      provider = provider["registry.terraform.io/hashicorp/aws"]
  3126      foo = foo
  3127      type = aws_instance
  3128  
  3129      Dependencies:
  3130        module.A.aws_instance.foo
  3131  	`)
  3132  }
  3133  
  3134  func TestContext2Apply_multiProvider(t *testing.T) {
  3135  	m := testModule(t, "apply-multi-provider")
  3136  	p := testProvider("aws")
  3137  	p.PlanResourceChangeFn = testDiffFn
  3138  	p.ApplyResourceChangeFn = testApplyFn
  3139  
  3140  	pDO := testProvider("do")
  3141  	pDO.ApplyResourceChangeFn = testApplyFn
  3142  	pDO.PlanResourceChangeFn = testDiffFn
  3143  
  3144  	ctx := testContext2(t, &ContextOpts{
  3145  		Providers: map[addrs.Provider]providers.Factory{
  3146  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3147  			addrs.NewDefaultProvider("do"):  testProviderFuncFixed(pDO),
  3148  		},
  3149  	})
  3150  
  3151  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3152  	assertNoErrors(t, diags)
  3153  
  3154  	state, diags := ctx.Apply(plan, m)
  3155  	if diags.HasErrors() {
  3156  		t.Fatalf("diags: %s", diags.Err())
  3157  	}
  3158  
  3159  	mod := state.RootModule()
  3160  	if len(mod.Resources) < 2 {
  3161  		t.Fatalf("bad: %#v", mod.Resources)
  3162  	}
  3163  
  3164  	actual := strings.TrimSpace(state.String())
  3165  	expected := strings.TrimSpace(testTerraformApplyMultiProviderStr)
  3166  	if actual != expected {
  3167  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3168  	}
  3169  }
  3170  
  3171  func TestContext2Apply_multiProviderDestroy(t *testing.T) {
  3172  	m := testModule(t, "apply-multi-provider-destroy")
  3173  	p := testProvider("aws")
  3174  	p.PlanResourceChangeFn = testDiffFn
  3175  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3176  		Provider: &configschema.Block{
  3177  			Attributes: map[string]*configschema.Attribute{
  3178  				"addr": {Type: cty.String, Optional: true},
  3179  			},
  3180  		},
  3181  		ResourceTypes: map[string]*configschema.Block{
  3182  			"aws_instance": {
  3183  				Attributes: map[string]*configschema.Attribute{
  3184  					"id":  {Type: cty.String, Computed: true},
  3185  					"foo": {Type: cty.String, Optional: true},
  3186  				},
  3187  			},
  3188  		},
  3189  	})
  3190  
  3191  	p2 := testProvider("vault")
  3192  	p2.ApplyResourceChangeFn = testApplyFn
  3193  	p2.PlanResourceChangeFn = testDiffFn
  3194  	p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3195  		ResourceTypes: map[string]*configschema.Block{
  3196  			"vault_instance": {
  3197  				Attributes: map[string]*configschema.Attribute{
  3198  					"id": {Type: cty.String, Computed: true},
  3199  				},
  3200  			},
  3201  		},
  3202  	})
  3203  
  3204  	var state *states.State
  3205  
  3206  	// First, create the instances
  3207  	{
  3208  		ctx := testContext2(t, &ContextOpts{
  3209  			Providers: map[addrs.Provider]providers.Factory{
  3210  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3211  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3212  			},
  3213  		})
  3214  
  3215  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3216  		assertNoErrors(t, diags)
  3217  
  3218  		s, diags := ctx.Apply(plan, m)
  3219  		assertNoErrors(t, diags)
  3220  
  3221  		state = s
  3222  	}
  3223  
  3224  	// Destroy them
  3225  	{
  3226  		// Verify that aws_instance.bar is destroyed first
  3227  		var checked bool
  3228  		var called int32
  3229  		var lock sync.Mutex
  3230  		applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3231  			lock.Lock()
  3232  			defer lock.Unlock()
  3233  
  3234  			if req.TypeName == "aws_instance" {
  3235  				checked = true
  3236  
  3237  				// Sleep to allow parallel execution
  3238  				time.Sleep(50 * time.Millisecond)
  3239  
  3240  				// Verify that called is 0 (dep not called)
  3241  				if atomic.LoadInt32(&called) != 0 {
  3242  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3243  					return resp
  3244  				}
  3245  			}
  3246  
  3247  			atomic.AddInt32(&called, 1)
  3248  			return testApplyFn(req)
  3249  		}
  3250  
  3251  		// Set the apply functions
  3252  		p.ApplyResourceChangeFn = applyFn
  3253  		p2.ApplyResourceChangeFn = applyFn
  3254  
  3255  		ctx := testContext2(t, &ContextOpts{
  3256  			Providers: map[addrs.Provider]providers.Factory{
  3257  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3258  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3259  			},
  3260  		})
  3261  
  3262  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3263  			Mode: plans.DestroyMode,
  3264  		})
  3265  		assertNoErrors(t, diags)
  3266  
  3267  		s, diags := ctx.Apply(plan, m)
  3268  		assertNoErrors(t, diags)
  3269  
  3270  		if !checked {
  3271  			t.Fatal("should be checked")
  3272  		}
  3273  
  3274  		state = s
  3275  	}
  3276  
  3277  	checkStateString(t, state, `<no state>`)
  3278  }
  3279  
  3280  // This is like the multiProviderDestroy test except it tests that
  3281  // dependent resources within a child module that inherit provider
  3282  // configuration are still destroyed first.
  3283  func TestContext2Apply_multiProviderDestroyChild(t *testing.T) {
  3284  	m := testModule(t, "apply-multi-provider-destroy-child")
  3285  	p := testProvider("aws")
  3286  	p.PlanResourceChangeFn = testDiffFn
  3287  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3288  		Provider: &configschema.Block{
  3289  			Attributes: map[string]*configschema.Attribute{
  3290  				"value": {Type: cty.String, Optional: true},
  3291  			},
  3292  		},
  3293  		ResourceTypes: map[string]*configschema.Block{
  3294  			"aws_instance": {
  3295  				Attributes: map[string]*configschema.Attribute{
  3296  					"id":  {Type: cty.String, Computed: true},
  3297  					"foo": {Type: cty.String, Optional: true},
  3298  				},
  3299  			},
  3300  		},
  3301  	})
  3302  
  3303  	p2 := testProvider("vault")
  3304  	p2.ApplyResourceChangeFn = testApplyFn
  3305  	p2.PlanResourceChangeFn = testDiffFn
  3306  	p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3307  		Provider: &configschema.Block{},
  3308  		ResourceTypes: map[string]*configschema.Block{
  3309  			"vault_instance": {
  3310  				Attributes: map[string]*configschema.Attribute{
  3311  					"id": {Type: cty.String, Computed: true},
  3312  				},
  3313  			},
  3314  		},
  3315  	})
  3316  
  3317  	var state *states.State
  3318  
  3319  	// First, create the instances
  3320  	{
  3321  		ctx := testContext2(t, &ContextOpts{
  3322  			Providers: map[addrs.Provider]providers.Factory{
  3323  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3324  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3325  			},
  3326  		})
  3327  
  3328  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3329  		assertNoErrors(t, diags)
  3330  
  3331  		s, diags := ctx.Apply(plan, m)
  3332  		if diags.HasErrors() {
  3333  			t.Fatalf("diags: %s", diags.Err())
  3334  		}
  3335  
  3336  		state = s
  3337  	}
  3338  
  3339  	// Destroy them
  3340  	{
  3341  		// Verify that aws_instance.bar is destroyed first
  3342  		var checked bool
  3343  		var called int32
  3344  		var lock sync.Mutex
  3345  		applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3346  			lock.Lock()
  3347  			defer lock.Unlock()
  3348  
  3349  			if req.TypeName == "aws_instance" {
  3350  				checked = true
  3351  
  3352  				// Sleep to allow parallel execution
  3353  				time.Sleep(50 * time.Millisecond)
  3354  
  3355  				// Verify that called is 0 (dep not called)
  3356  				if atomic.LoadInt32(&called) != 0 {
  3357  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3358  					return resp
  3359  				}
  3360  			}
  3361  
  3362  			atomic.AddInt32(&called, 1)
  3363  			return testApplyFn(req)
  3364  		}
  3365  
  3366  		// Set the apply functions
  3367  		p.ApplyResourceChangeFn = applyFn
  3368  		p2.ApplyResourceChangeFn = applyFn
  3369  
  3370  		ctx := testContext2(t, &ContextOpts{
  3371  			Providers: map[addrs.Provider]providers.Factory{
  3372  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3373  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3374  			},
  3375  		})
  3376  
  3377  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3378  			Mode: plans.DestroyMode,
  3379  		})
  3380  		assertNoErrors(t, diags)
  3381  
  3382  		s, diags := ctx.Apply(plan, m)
  3383  		if diags.HasErrors() {
  3384  			t.Fatalf("diags: %s", diags.Err())
  3385  		}
  3386  
  3387  		if !checked {
  3388  			t.Fatal("should be checked")
  3389  		}
  3390  
  3391  		state = s
  3392  	}
  3393  
  3394  	checkStateString(t, state, `
  3395  <no state>
  3396  `)
  3397  }
  3398  
  3399  func TestContext2Apply_multiVar(t *testing.T) {
  3400  	m := testModule(t, "apply-multi-var")
  3401  	p := testProvider("aws")
  3402  	p.PlanResourceChangeFn = testDiffFn
  3403  
  3404  	// First, apply with a count of 3
  3405  	ctx := testContext2(t, &ContextOpts{
  3406  		Providers: map[addrs.Provider]providers.Factory{
  3407  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3408  		},
  3409  	})
  3410  
  3411  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3412  		Mode: plans.NormalMode,
  3413  		SetVariables: InputValues{
  3414  			"num": &InputValue{
  3415  				Value:      cty.NumberIntVal(3),
  3416  				SourceType: ValueFromCaller,
  3417  			},
  3418  		},
  3419  	})
  3420  	assertNoErrors(t, diags)
  3421  
  3422  	state, diags := ctx.Apply(plan, m)
  3423  	if diags.HasErrors() {
  3424  		t.Fatalf("diags: %s", diags.Err())
  3425  	}
  3426  
  3427  	actual := state.RootModule().OutputValues["output"]
  3428  	expected := cty.StringVal("bar0,bar1,bar2")
  3429  	if actual == nil || actual.Value != expected {
  3430  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3431  	}
  3432  
  3433  	t.Logf("Initial state: %s", state.String())
  3434  
  3435  	// Apply again, reduce the count to 1
  3436  	{
  3437  		ctx := testContext2(t, &ContextOpts{
  3438  			Providers: map[addrs.Provider]providers.Factory{
  3439  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3440  			},
  3441  		})
  3442  
  3443  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3444  			Mode: plans.NormalMode,
  3445  			SetVariables: InputValues{
  3446  				"num": &InputValue{
  3447  					Value:      cty.NumberIntVal(1),
  3448  					SourceType: ValueFromCaller,
  3449  				},
  3450  			},
  3451  		})
  3452  		assertNoErrors(t, diags)
  3453  
  3454  		state, diags := ctx.Apply(plan, m)
  3455  		if diags.HasErrors() {
  3456  			t.Fatalf("diags: %s", diags.Err())
  3457  		}
  3458  
  3459  		t.Logf("End state: %s", state.String())
  3460  
  3461  		actual := state.RootModule().OutputValues["output"]
  3462  		if actual == nil {
  3463  			t.Fatal("missing output")
  3464  		}
  3465  
  3466  		expected := cty.StringVal("bar0")
  3467  		if actual.Value != expected {
  3468  			t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3469  		}
  3470  	}
  3471  }
  3472  
  3473  // This is a holistic test of multi-var (aka "splat variable") handling
  3474  // across several different Terraform subsystems. This is here because
  3475  // historically there were quirky differences in handling across different
  3476  // parts of Terraform and so here we want to assert the expected behavior and
  3477  // ensure that it remains consistent in future.
  3478  func TestContext2Apply_multiVarComprehensive(t *testing.T) {
  3479  	m := testModule(t, "apply-multi-var-comprehensive")
  3480  	p := testProvider("test")
  3481  
  3482  	configs := map[string]cty.Value{}
  3483  	var configsLock sync.Mutex
  3484  
  3485  	p.ApplyResourceChangeFn = testApplyFn
  3486  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  3487  		proposed := req.ProposedNewState
  3488  		configsLock.Lock()
  3489  		defer configsLock.Unlock()
  3490  		key := proposed.GetAttr("key").AsString()
  3491  		// This test was originally written using the legacy p.PlanResourceChangeFn interface,
  3492  		// and so the assertions below expect an old-style ResourceConfig, which
  3493  		// we'll construct via our shim for now to avoid rewriting all of the
  3494  		// assertions.
  3495  		configs[key] = req.ProposedNewState
  3496  
  3497  		retVals := make(map[string]cty.Value)
  3498  		for it := proposed.ElementIterator(); it.Next(); {
  3499  			idxVal, val := it.Element()
  3500  			idx := idxVal.AsString()
  3501  
  3502  			switch idx {
  3503  			case "id":
  3504  				retVals[idx] = cty.UnknownVal(cty.String)
  3505  			case "name":
  3506  				retVals[idx] = cty.StringVal(key)
  3507  			default:
  3508  				retVals[idx] = val
  3509  			}
  3510  		}
  3511  
  3512  		return providers.PlanResourceChangeResponse{
  3513  			PlannedState: cty.ObjectVal(retVals),
  3514  		}
  3515  	}
  3516  
  3517  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3518  		ResourceTypes: map[string]*configschema.Block{
  3519  			"test_thing": {
  3520  				Attributes: map[string]*configschema.Attribute{
  3521  					"key": {Type: cty.String, Required: true},
  3522  
  3523  					"source_id":              {Type: cty.String, Optional: true},
  3524  					"source_name":            {Type: cty.String, Optional: true},
  3525  					"first_source_id":        {Type: cty.String, Optional: true},
  3526  					"first_source_name":      {Type: cty.String, Optional: true},
  3527  					"source_ids":             {Type: cty.List(cty.String), Optional: true},
  3528  					"source_names":           {Type: cty.List(cty.String), Optional: true},
  3529  					"source_ids_from_func":   {Type: cty.List(cty.String), Optional: true},
  3530  					"source_names_from_func": {Type: cty.List(cty.String), Optional: true},
  3531  					"source_ids_wrapped":     {Type: cty.List(cty.List(cty.String)), Optional: true},
  3532  					"source_names_wrapped":   {Type: cty.List(cty.List(cty.String)), Optional: true},
  3533  
  3534  					"id":   {Type: cty.String, Computed: true},
  3535  					"name": {Type: cty.String, Computed: true},
  3536  				},
  3537  			},
  3538  		},
  3539  	})
  3540  
  3541  	// First, apply with a count of 3
  3542  	ctx := testContext2(t, &ContextOpts{
  3543  		Providers: map[addrs.Provider]providers.Factory{
  3544  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  3545  		},
  3546  	})
  3547  
  3548  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3549  		Mode: plans.NormalMode,
  3550  		SetVariables: InputValues{
  3551  			"num": &InputValue{
  3552  				Value:      cty.NumberIntVal(3),
  3553  				SourceType: ValueFromCaller,
  3554  			},
  3555  		},
  3556  	})
  3557  	assertNoErrors(t, diags)
  3558  
  3559  	checkConfig := func(key string, want cty.Value) {
  3560  		configsLock.Lock()
  3561  		defer configsLock.Unlock()
  3562  
  3563  		got, ok := configs[key]
  3564  		if !ok {
  3565  			t.Errorf("no config recorded for %s; expected a configuration", key)
  3566  			return
  3567  		}
  3568  
  3569  		t.Run("config for "+key, func(t *testing.T) {
  3570  			for _, problem := range deep.Equal(got, want) {
  3571  				t.Errorf(problem)
  3572  			}
  3573  		})
  3574  	}
  3575  
  3576  	checkConfig("multi_count_var.0", cty.ObjectVal(map[string]cty.Value{
  3577  		"source_id":   cty.UnknownVal(cty.String),
  3578  		"source_name": cty.StringVal("source.0"),
  3579  	}))
  3580  	checkConfig("multi_count_var.2", cty.ObjectVal(map[string]cty.Value{
  3581  		"source_id":   cty.UnknownVal(cty.String),
  3582  		"source_name": cty.StringVal("source.2"),
  3583  	}))
  3584  	checkConfig("multi_count_derived.0", cty.ObjectVal(map[string]cty.Value{
  3585  		"source_id":   cty.UnknownVal(cty.String),
  3586  		"source_name": cty.StringVal("source.0"),
  3587  	}))
  3588  	checkConfig("multi_count_derived.2", cty.ObjectVal(map[string]cty.Value{
  3589  		"source_id":   cty.UnknownVal(cty.String),
  3590  		"source_name": cty.StringVal("source.2"),
  3591  	}))
  3592  	checkConfig("whole_splat", cty.ObjectVal(map[string]cty.Value{
  3593  		"source_ids": cty.ListVal([]cty.Value{
  3594  			cty.UnknownVal(cty.String),
  3595  			cty.UnknownVal(cty.String),
  3596  			cty.UnknownVal(cty.String),
  3597  		}),
  3598  		"source_names": cty.ListVal([]cty.Value{
  3599  			cty.StringVal("source.0"),
  3600  			cty.StringVal("source.1"),
  3601  			cty.StringVal("source.2"),
  3602  		}),
  3603  		"source_ids_from_func": cty.UnknownVal(cty.String),
  3604  		"source_names_from_func": cty.ListVal([]cty.Value{
  3605  			cty.StringVal("source.0"),
  3606  			cty.StringVal("source.1"),
  3607  			cty.StringVal("source.2"),
  3608  		}),
  3609  		"source_ids_wrapped": cty.ListVal([]cty.Value{
  3610  			cty.ListVal([]cty.Value{
  3611  				cty.UnknownVal(cty.String),
  3612  				cty.UnknownVal(cty.String),
  3613  				cty.UnknownVal(cty.String),
  3614  			}),
  3615  		}),
  3616  		"source_names_wrapped": cty.ListVal([]cty.Value{
  3617  			cty.ListVal([]cty.Value{
  3618  				cty.StringVal("source.0"),
  3619  				cty.StringVal("source.1"),
  3620  				cty.StringVal("source.2"),
  3621  			}),
  3622  		}),
  3623  		"first_source_id":   cty.UnknownVal(cty.String),
  3624  		"first_source_name": cty.StringVal("source.0"),
  3625  	}))
  3626  	checkConfig("child.whole_splat", cty.ObjectVal(map[string]cty.Value{
  3627  		"source_ids": cty.ListVal([]cty.Value{
  3628  			cty.UnknownVal(cty.String),
  3629  			cty.UnknownVal(cty.String),
  3630  			cty.UnknownVal(cty.String),
  3631  		}),
  3632  		"source_names": cty.ListVal([]cty.Value{
  3633  			cty.StringVal("source.0"),
  3634  			cty.StringVal("source.1"),
  3635  			cty.StringVal("source.2"),
  3636  		}),
  3637  		"source_ids_wrapped": cty.ListVal([]cty.Value{
  3638  			cty.ListVal([]cty.Value{
  3639  				cty.UnknownVal(cty.String),
  3640  				cty.UnknownVal(cty.String),
  3641  				cty.UnknownVal(cty.String),
  3642  			}),
  3643  		}),
  3644  		"source_names_wrapped": cty.ListVal([]cty.Value{
  3645  			cty.ListVal([]cty.Value{
  3646  				cty.StringVal("source.0"),
  3647  				cty.StringVal("source.1"),
  3648  				cty.StringVal("source.2"),
  3649  			}),
  3650  		}),
  3651  	}))
  3652  
  3653  	t.Run("apply", func(t *testing.T) {
  3654  		state, diags := ctx.Apply(plan, m)
  3655  		if diags.HasErrors() {
  3656  			t.Fatalf("error during apply: %s", diags.Err())
  3657  		}
  3658  
  3659  		want := map[string]interface{}{
  3660  			"source_ids": []interface{}{"foo", "foo", "foo"},
  3661  			"source_names": []interface{}{
  3662  				"source.0",
  3663  				"source.1",
  3664  				"source.2",
  3665  			},
  3666  		}
  3667  		got := map[string]interface{}{}
  3668  		for k, s := range state.RootModule().OutputValues {
  3669  			got[k] = hcl2shim.ConfigValueFromHCL2(s.Value)
  3670  		}
  3671  		if !reflect.DeepEqual(got, want) {
  3672  			t.Errorf(
  3673  				"wrong outputs\ngot:  %s\nwant: %s",
  3674  				spew.Sdump(got), spew.Sdump(want),
  3675  			)
  3676  		}
  3677  	})
  3678  }
  3679  
  3680  // Test that multi-var (splat) access is ordered by count, not by
  3681  // value.
  3682  func TestContext2Apply_multiVarOrder(t *testing.T) {
  3683  	m := testModule(t, "apply-multi-var-order")
  3684  	p := testProvider("aws")
  3685  	p.PlanResourceChangeFn = testDiffFn
  3686  
  3687  	// First, apply with a count of 3
  3688  	ctx := testContext2(t, &ContextOpts{
  3689  		Providers: map[addrs.Provider]providers.Factory{
  3690  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3691  		},
  3692  	})
  3693  
  3694  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  3695  	assertNoErrors(t, diags)
  3696  
  3697  	state, diags := ctx.Apply(plan, m)
  3698  	if diags.HasErrors() {
  3699  		t.Fatalf("diags: %s", diags.Err())
  3700  	}
  3701  
  3702  	t.Logf("State: %s", state.String())
  3703  
  3704  	actual := state.RootModule().OutputValues["should-be-11"]
  3705  	expected := cty.StringVal("index-11")
  3706  	if actual == nil || actual.Value != expected {
  3707  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3708  	}
  3709  }
  3710  
  3711  // Test that multi-var (splat) access is ordered by count, not by
  3712  // value, through interpolations.
  3713  func TestContext2Apply_multiVarOrderInterp(t *testing.T) {
  3714  	m := testModule(t, "apply-multi-var-order-interp")
  3715  	p := testProvider("aws")
  3716  	p.PlanResourceChangeFn = testDiffFn
  3717  
  3718  	// First, apply with a count of 3
  3719  	ctx := testContext2(t, &ContextOpts{
  3720  		Providers: map[addrs.Provider]providers.Factory{
  3721  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3722  		},
  3723  	})
  3724  
  3725  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  3726  	assertNoErrors(t, diags)
  3727  
  3728  	state, diags := ctx.Apply(plan, m)
  3729  	if diags.HasErrors() {
  3730  		t.Fatalf("diags: %s", diags.Err())
  3731  	}
  3732  
  3733  	t.Logf("State: %s", state.String())
  3734  
  3735  	actual := state.RootModule().OutputValues["should-be-11"]
  3736  	expected := cty.StringVal("baz-index-11")
  3737  	if actual == nil || actual.Value != expected {
  3738  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3739  	}
  3740  }
  3741  
  3742  // Based on GH-10440 where a graph edge wasn't properly being created
  3743  // between a modified resource and a count instance being destroyed.
  3744  func TestContext2Apply_multiVarCountDec(t *testing.T) {
  3745  	var s *states.State
  3746  
  3747  	// First create resources. Nothing sneaky here.
  3748  	{
  3749  		m := testModule(t, "apply-multi-var-count-dec")
  3750  		p := testProvider("aws")
  3751  		p.PlanResourceChangeFn = testDiffFn
  3752  		p.ApplyResourceChangeFn = testApplyFn
  3753  		ctx := testContext2(t, &ContextOpts{
  3754  			Providers: map[addrs.Provider]providers.Factory{
  3755  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3756  			},
  3757  		})
  3758  
  3759  		log.Print("\n========\nStep 1 Plan\n========")
  3760  		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3761  			Mode: plans.NormalMode,
  3762  			SetVariables: InputValues{
  3763  				"num": &InputValue{
  3764  					Value:      cty.NumberIntVal(2),
  3765  					SourceType: ValueFromCaller,
  3766  				},
  3767  			},
  3768  		})
  3769  		assertNoErrors(t, diags)
  3770  
  3771  		log.Print("\n========\nStep 1 Apply\n========")
  3772  		state, diags := ctx.Apply(plan, m)
  3773  		if diags.HasErrors() {
  3774  			t.Fatalf("diags: %s", diags.Err())
  3775  		}
  3776  
  3777  		t.Logf("Step 1 state:\n%s", state)
  3778  
  3779  		s = state
  3780  	}
  3781  
  3782  	// Decrease the count by 1 and verify that everything happens in the
  3783  	// right order.
  3784  	m := testModule(t, "apply-multi-var-count-dec")
  3785  	p := testProvider("aws")
  3786  	p.PlanResourceChangeFn = testDiffFn
  3787  
  3788  	// Verify that aws_instance.bar is modified first and nothing
  3789  	// else happens at the same time.
  3790  	{
  3791  		var checked bool
  3792  		var called int32
  3793  		var lock sync.Mutex
  3794  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3795  			lock.Lock()
  3796  			defer lock.Unlock()
  3797  
  3798  			if !req.PlannedState.IsNull() {
  3799  				s := req.PlannedState.AsValueMap()
  3800  				if ami, ok := s["ami"]; ok && !ami.IsNull() && ami.AsString() == "special" {
  3801  					checked = true
  3802  
  3803  					// Sleep to allow parallel execution
  3804  					time.Sleep(50 * time.Millisecond)
  3805  
  3806  					// Verify that called is 0 (dep not called)
  3807  					if atomic.LoadInt32(&called) != 1 {
  3808  						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3809  						return
  3810  					}
  3811  				}
  3812  			}
  3813  			atomic.AddInt32(&called, 1)
  3814  			return testApplyFn(req)
  3815  		}
  3816  
  3817  		ctx := testContext2(t, &ContextOpts{
  3818  			Providers: map[addrs.Provider]providers.Factory{
  3819  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3820  			},
  3821  		})
  3822  
  3823  		log.Print("\n========\nStep 2 Plan\n========")
  3824  		plan, diags := ctx.Plan(m, s, &PlanOpts{
  3825  			Mode: plans.NormalMode,
  3826  			SetVariables: InputValues{
  3827  				"num": &InputValue{
  3828  					Value:      cty.NumberIntVal(1),
  3829  					SourceType: ValueFromCaller,
  3830  				},
  3831  			},
  3832  		})
  3833  		assertNoErrors(t, diags)
  3834  
  3835  		t.Logf("Step 2 plan:\n%s", legacyDiffComparisonString(plan.Changes))
  3836  
  3837  		log.Print("\n========\nStep 2 Apply\n========")
  3838  		_, diags = ctx.Apply(plan, m)
  3839  		if diags.HasErrors() {
  3840  			t.Fatalf("apply errors: %s", diags.Err())
  3841  		}
  3842  
  3843  		if !checked {
  3844  			t.Error("apply never called")
  3845  		}
  3846  	}
  3847  }
  3848  
  3849  // Test that we can resolve a multi-var (splat) for the first resource
  3850  // created in a non-root module, which happens when the module state doesn't
  3851  // exist yet.
  3852  // https://github.com/hashicorp/terraform/issues/14438
  3853  func TestContext2Apply_multiVarMissingState(t *testing.T) {
  3854  	m := testModule(t, "apply-multi-var-missing-state")
  3855  	p := testProvider("test")
  3856  	p.PlanResourceChangeFn = testDiffFn
  3857  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3858  		ResourceTypes: map[string]*configschema.Block{
  3859  			"test_thing": {
  3860  				Attributes: map[string]*configschema.Attribute{
  3861  					"a_ids": {Type: cty.String, Optional: true},
  3862  					"id":    {Type: cty.String, Computed: true},
  3863  				},
  3864  			},
  3865  		},
  3866  	})
  3867  
  3868  	// First, apply with a count of 3
  3869  	ctx := testContext2(t, &ContextOpts{
  3870  		Providers: map[addrs.Provider]providers.Factory{
  3871  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  3872  		},
  3873  	})
  3874  
  3875  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3876  	assertNoErrors(t, diags)
  3877  
  3878  	// Before the relevant bug was fixed, Terraform would panic during apply.
  3879  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3880  		t.Fatalf("apply failed: %s", diags.Err())
  3881  	}
  3882  
  3883  	// If we get here with no errors or panics then our test was successful.
  3884  }
  3885  
  3886  func TestContext2Apply_outputOrphan(t *testing.T) {
  3887  	m := testModule(t, "apply-output-orphan")
  3888  	p := testProvider("aws")
  3889  	p.PlanResourceChangeFn = testDiffFn
  3890  
  3891  	state := states.NewState()
  3892  	root := state.EnsureModule(addrs.RootModuleInstance)
  3893  	root.SetOutputValue("foo", cty.StringVal("bar"), false)
  3894  	root.SetOutputValue("bar", cty.StringVal("baz"), false)
  3895  
  3896  	ctx := testContext2(t, &ContextOpts{
  3897  		Providers: map[addrs.Provider]providers.Factory{
  3898  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3899  		},
  3900  	})
  3901  
  3902  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3903  	assertNoErrors(t, diags)
  3904  
  3905  	state, diags = ctx.Apply(plan, m)
  3906  	if diags.HasErrors() {
  3907  		t.Fatalf("diags: %s", diags.Err())
  3908  	}
  3909  
  3910  	actual := strings.TrimSpace(state.String())
  3911  	expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr)
  3912  	if actual != expected {
  3913  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3914  	}
  3915  }
  3916  
  3917  func TestContext2Apply_outputOrphanModule(t *testing.T) {
  3918  	m := testModule(t, "apply-output-orphan-module")
  3919  	p := testProvider("aws")
  3920  	p.PlanResourceChangeFn = testDiffFn
  3921  
  3922  	state := states.NewState()
  3923  
  3924  	ctx := testContext2(t, &ContextOpts{
  3925  		Providers: map[addrs.Provider]providers.Factory{
  3926  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3927  		},
  3928  	})
  3929  
  3930  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3931  	assertNoErrors(t, diags)
  3932  
  3933  	s, diags := ctx.Apply(plan, m)
  3934  	if diags.HasErrors() {
  3935  		t.Fatalf("diags: %s", diags.Err())
  3936  	}
  3937  
  3938  	actual := strings.TrimSpace(s.String())
  3939  	expected := strings.TrimSpace(testTerraformApplyOutputOrphanModuleStr)
  3940  	if actual != expected {
  3941  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  3942  	}
  3943  
  3944  	// now apply with no module in the config, which should remove the
  3945  	// remaining output
  3946  	ctx = testContext2(t, &ContextOpts{
  3947  		Providers: map[addrs.Provider]providers.Factory{
  3948  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3949  		},
  3950  	})
  3951  
  3952  	emptyConfig := configs.NewEmptyConfig()
  3953  
  3954  	// NOTE: While updating this test to pass the state in as a Plan argument,
  3955  	// rather than into the testContext2 call above, it previously said
  3956  	// State: state.DeepCopy(), which is a little weird since we just
  3957  	// created "s" above as the result of the previous apply, but I've preserved
  3958  	// it to avoid changing the flow of this test in case that's important
  3959  	// for some reason.
  3960  	plan, diags = ctx.Plan(emptyConfig, state.DeepCopy(), DefaultPlanOpts)
  3961  	assertNoErrors(t, diags)
  3962  
  3963  	state, diags = ctx.Apply(plan, emptyConfig)
  3964  	if diags.HasErrors() {
  3965  		t.Fatalf("diags: %s", diags.Err())
  3966  	}
  3967  
  3968  	if !state.Empty() {
  3969  		t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(state))
  3970  	}
  3971  }
  3972  
  3973  func TestContext2Apply_providerComputedVar(t *testing.T) {
  3974  	m := testModule(t, "apply-provider-computed")
  3975  	p := testProvider("aws")
  3976  	p.PlanResourceChangeFn = testDiffFn
  3977  
  3978  	pTest := testProvider("test")
  3979  	pTest.ApplyResourceChangeFn = testApplyFn
  3980  	pTest.PlanResourceChangeFn = testDiffFn
  3981  
  3982  	ctx := testContext2(t, &ContextOpts{
  3983  		Providers: map[addrs.Provider]providers.Factory{
  3984  			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
  3985  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
  3986  		},
  3987  	})
  3988  
  3989  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  3990  		val := req.Config.GetAttr("value")
  3991  		if val.IsNull() {
  3992  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  3993  			return
  3994  		}
  3995  		return
  3996  	}
  3997  
  3998  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3999  	assertNoErrors(t, diags)
  4000  
  4001  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  4002  		t.Fatalf("apply errors: %s", diags.Err())
  4003  	}
  4004  }
  4005  
  4006  func TestContext2Apply_providerConfigureDisabled(t *testing.T) {
  4007  	m := testModule(t, "apply-provider-configure-disabled")
  4008  	p := testProvider("aws")
  4009  	p.PlanResourceChangeFn = testDiffFn
  4010  
  4011  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  4012  		val := req.Config.GetAttr("value")
  4013  		if val.IsNull() {
  4014  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  4015  		}
  4016  
  4017  		return
  4018  	}
  4019  
  4020  	ctx := testContext2(t, &ContextOpts{
  4021  		Providers: map[addrs.Provider]providers.Factory{
  4022  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4023  		},
  4024  	})
  4025  
  4026  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4027  	assertNoErrors(t, diags)
  4028  
  4029  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  4030  		t.Fatalf("apply errors: %s", diags.Err())
  4031  	}
  4032  
  4033  	if !p.ConfigureProviderCalled {
  4034  		t.Fatal("configure never called")
  4035  	}
  4036  }
  4037  
  4038  func TestContext2Apply_provisionerModule(t *testing.T) {
  4039  	m := testModule(t, "apply-provisioner-module")
  4040  
  4041  	p := testProvider("aws")
  4042  	p.PlanResourceChangeFn = testDiffFn
  4043  	p.ApplyResourceChangeFn = testApplyFn
  4044  
  4045  	pr := testProvisioner()
  4046  	pr.GetSchemaResponse = provisioners.GetSchemaResponse{
  4047  		Provisioner: &configschema.Block{
  4048  			Attributes: map[string]*configschema.Attribute{
  4049  				"foo": {Type: cty.String, Optional: true},
  4050  			},
  4051  		},
  4052  	}
  4053  
  4054  	ctx := testContext2(t, &ContextOpts{
  4055  		Providers: map[addrs.Provider]providers.Factory{
  4056  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4057  		},
  4058  		Provisioners: map[string]provisioners.Factory{
  4059  			"shell": testProvisionerFuncFixed(pr),
  4060  		},
  4061  	})
  4062  
  4063  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4064  	assertNoErrors(t, diags)
  4065  
  4066  	state, diags := ctx.Apply(plan, m)
  4067  	if diags.HasErrors() {
  4068  		t.Fatalf("diags: %s", diags.Err())
  4069  	}
  4070  
  4071  	actual := strings.TrimSpace(state.String())
  4072  	expected := strings.TrimSpace(testTerraformApplyProvisionerModuleStr)
  4073  	if actual != expected {
  4074  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4075  	}
  4076  
  4077  	// Verify apply was invoked
  4078  	if !pr.ProvisionResourceCalled {
  4079  		t.Fatalf("provisioner not invoked")
  4080  	}
  4081  }
  4082  
  4083  func TestContext2Apply_Provisioner_compute(t *testing.T) {
  4084  	m := testModule(t, "apply-provisioner-compute")
  4085  	p := testProvider("aws")
  4086  	pr := testProvisioner()
  4087  	p.PlanResourceChangeFn = testDiffFn
  4088  	p.ApplyResourceChangeFn = testApplyFn
  4089  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4090  
  4091  		val := req.Config.GetAttr("command").AsString()
  4092  		if val != "computed_value" {
  4093  			t.Fatalf("bad value for foo: %q", val)
  4094  		}
  4095  		req.UIOutput.Output(fmt.Sprintf("Executing: %q", val))
  4096  
  4097  		return
  4098  	}
  4099  	h := new(MockHook)
  4100  	ctx := testContext2(t, &ContextOpts{
  4101  		Hooks: []Hook{h},
  4102  		Providers: map[addrs.Provider]providers.Factory{
  4103  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4104  		},
  4105  		Provisioners: map[string]provisioners.Factory{
  4106  			"shell": testProvisionerFuncFixed(pr),
  4107  		},
  4108  	})
  4109  
  4110  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  4111  		Mode: plans.NormalMode,
  4112  		SetVariables: InputValues{
  4113  			"value": &InputValue{
  4114  				Value:      cty.NumberIntVal(1),
  4115  				SourceType: ValueFromCaller,
  4116  			},
  4117  		},
  4118  	})
  4119  	assertNoErrors(t, diags)
  4120  
  4121  	state, diags := ctx.Apply(plan, m)
  4122  	if diags.HasErrors() {
  4123  		t.Fatalf("diags: %s", diags.Err())
  4124  	}
  4125  
  4126  	actual := strings.TrimSpace(state.String())
  4127  	expected := strings.TrimSpace(testTerraformApplyProvisionerStr)
  4128  	if actual != expected {
  4129  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4130  	}
  4131  
  4132  	// Verify apply was invoked
  4133  	if !pr.ProvisionResourceCalled {
  4134  		t.Fatalf("provisioner not invoked")
  4135  	}
  4136  
  4137  	// Verify output was rendered
  4138  	if !h.ProvisionOutputCalled {
  4139  		t.Fatalf("ProvisionOutput hook not called")
  4140  	}
  4141  	if got, want := h.ProvisionOutputMessage, `Executing: "computed_value"`; got != want {
  4142  		t.Errorf("expected output to be %q, but was %q", want, got)
  4143  	}
  4144  }
  4145  
  4146  func TestContext2Apply_provisionerCreateFail(t *testing.T) {
  4147  	m := testModule(t, "apply-provisioner-fail-create")
  4148  	p := testProvider("aws")
  4149  	pr := testProvisioner()
  4150  	p.PlanResourceChangeFn = testDiffFn
  4151  
  4152  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  4153  		resp := testApplyFn(req)
  4154  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4155  
  4156  		return resp
  4157  	}
  4158  
  4159  	ctx := testContext2(t, &ContextOpts{
  4160  		Providers: map[addrs.Provider]providers.Factory{
  4161  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4162  		},
  4163  		Provisioners: map[string]provisioners.Factory{
  4164  			"shell": testProvisionerFuncFixed(pr),
  4165  		},
  4166  	})
  4167  
  4168  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4169  	assertNoErrors(t, diags)
  4170  
  4171  	state, diags := ctx.Apply(plan, m)
  4172  	if diags == nil {
  4173  		t.Fatal("should error")
  4174  	}
  4175  
  4176  	got := strings.TrimSpace(state.String())
  4177  	want := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr)
  4178  	if got != want {
  4179  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want)
  4180  	}
  4181  }
  4182  
  4183  func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) {
  4184  	m := testModule(t, "apply-provisioner-fail-create")
  4185  	p := testProvider("aws")
  4186  	pr := testProvisioner()
  4187  	p.PlanResourceChangeFn = testDiffFn
  4188  
  4189  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4190  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4191  		return
  4192  	}
  4193  
  4194  	ctx := testContext2(t, &ContextOpts{
  4195  		Providers: map[addrs.Provider]providers.Factory{
  4196  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4197  		},
  4198  		Provisioners: map[string]provisioners.Factory{
  4199  			"shell": testProvisionerFuncFixed(pr),
  4200  		},
  4201  	})
  4202  
  4203  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4204  	assertNoErrors(t, diags)
  4205  
  4206  	state, diags := ctx.Apply(plan, m)
  4207  	if diags == nil {
  4208  		t.Fatal("should error")
  4209  	}
  4210  
  4211  	actual := strings.TrimSpace(state.String())
  4212  	expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr)
  4213  	if actual != expected {
  4214  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4215  	}
  4216  }
  4217  
  4218  func TestContext2Apply_provisionerFail(t *testing.T) {
  4219  	m := testModule(t, "apply-provisioner-fail")
  4220  	p := testProvider("aws")
  4221  	p.PlanResourceChangeFn = testDiffFn
  4222  	p.ApplyResourceChangeFn = testApplyFn
  4223  	pr := testProvisioner()
  4224  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4225  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION"))
  4226  		return
  4227  	}
  4228  
  4229  	ctx := testContext2(t, &ContextOpts{
  4230  		Providers: map[addrs.Provider]providers.Factory{
  4231  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4232  		},
  4233  		Provisioners: map[string]provisioners.Factory{
  4234  			"shell": testProvisionerFuncFixed(pr),
  4235  		},
  4236  	})
  4237  
  4238  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4239  	assertNoErrors(t, diags)
  4240  
  4241  	state, diags := ctx.Apply(plan, m)
  4242  	if diags == nil {
  4243  		t.Fatal("should error")
  4244  	}
  4245  
  4246  	actual := strings.TrimSpace(state.String())
  4247  	expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr)
  4248  	if actual != expected {
  4249  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4250  	}
  4251  }
  4252  
  4253  func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) {
  4254  	m := testModule(t, "apply-provisioner-fail-create-before")
  4255  	p := testProvider("aws")
  4256  	pr := testProvisioner()
  4257  	p.PlanResourceChangeFn = testDiffFn
  4258  	p.ApplyResourceChangeFn = testApplyFn
  4259  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4260  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION"))
  4261  		return
  4262  	}
  4263  
  4264  	state := states.NewState()
  4265  	root := state.EnsureModule(addrs.RootModuleInstance)
  4266  	root.SetResourceInstanceCurrent(
  4267  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4268  		&states.ResourceInstanceObjectSrc{
  4269  			Status:    states.ObjectReady,
  4270  			AttrsJSON: []byte(`{"id":"bar","require_new":"abc"}`),
  4271  		},
  4272  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4273  	)
  4274  
  4275  	ctx := testContext2(t, &ContextOpts{
  4276  		Providers: map[addrs.Provider]providers.Factory{
  4277  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4278  		},
  4279  		Provisioners: map[string]provisioners.Factory{
  4280  			"shell": testProvisionerFuncFixed(pr),
  4281  		},
  4282  	})
  4283  
  4284  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4285  	assertNoErrors(t, diags)
  4286  
  4287  	state, diags = ctx.Apply(plan, m)
  4288  	if !diags.HasErrors() {
  4289  		t.Fatal("should error")
  4290  	}
  4291  
  4292  	actual := strings.TrimSpace(state.String())
  4293  	expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr)
  4294  	if actual != expected {
  4295  		t.Fatalf("expected:\n%s\n:got\n%s", expected, actual)
  4296  	}
  4297  }
  4298  
  4299  func TestContext2Apply_error_createBeforeDestroy(t *testing.T) {
  4300  	m := testModule(t, "apply-error-create-before")
  4301  	p := testProvider("aws")
  4302  
  4303  	state := states.NewState()
  4304  	root := state.EnsureModule(addrs.RootModuleInstance)
  4305  	root.SetResourceInstanceCurrent(
  4306  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4307  		&states.ResourceInstanceObjectSrc{
  4308  			Status:    states.ObjectReady,
  4309  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc","type":"aws_instance"}`),
  4310  		},
  4311  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4312  	)
  4313  
  4314  	ctx := testContext2(t, &ContextOpts{
  4315  		Providers: map[addrs.Provider]providers.Factory{
  4316  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4317  		},
  4318  	})
  4319  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4320  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("placeholder error from ApplyFn"))
  4321  		return
  4322  	}
  4323  	p.PlanResourceChangeFn = testDiffFn
  4324  
  4325  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4326  	assertNoErrors(t, diags)
  4327  
  4328  	state, diags = ctx.Apply(plan, m)
  4329  	if !diags.HasErrors() {
  4330  		t.Fatal("should have error")
  4331  	}
  4332  	if got, want := diags.Err().Error(), "placeholder error from ApplyFn"; got != want {
  4333  		// We're looking for our artificial error from ApplyFn above, whose
  4334  		// message is literally "placeholder error from ApplyFn".
  4335  		t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
  4336  	}
  4337  
  4338  	actual := strings.TrimSpace(state.String())
  4339  	expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr)
  4340  	if actual != expected {
  4341  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4342  	}
  4343  }
  4344  
  4345  func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) {
  4346  	m := testModule(t, "apply-error-create-before")
  4347  	p := testProvider("aws")
  4348  
  4349  	state := states.NewState()
  4350  	root := state.EnsureModule(addrs.RootModuleInstance)
  4351  	root.SetResourceInstanceCurrent(
  4352  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4353  		&states.ResourceInstanceObjectSrc{
  4354  			Status:    states.ObjectReady,
  4355  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
  4356  		},
  4357  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4358  	)
  4359  
  4360  	ctx := testContext2(t, &ContextOpts{
  4361  		Providers: map[addrs.Provider]providers.Factory{
  4362  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4363  		},
  4364  	})
  4365  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4366  		// Fail the destroy!
  4367  		if req.PlannedState.IsNull() {
  4368  			resp.NewState = req.PriorState
  4369  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4370  			return
  4371  		}
  4372  
  4373  		return testApplyFn(req)
  4374  	}
  4375  	p.PlanResourceChangeFn = testDiffFn
  4376  
  4377  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4378  	assertNoErrors(t, diags)
  4379  
  4380  	state, diags = ctx.Apply(plan, m)
  4381  	if !diags.HasErrors() {
  4382  		t.Fatal("should have error")
  4383  	}
  4384  
  4385  	actual := strings.TrimSpace(state.String())
  4386  	expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr)
  4387  	if actual != expected {
  4388  		t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected)
  4389  	}
  4390  }
  4391  
  4392  func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) {
  4393  	m := testModule(t, "apply-multi-depose-create-before-destroy")
  4394  	p := testProvider("aws")
  4395  	ps := map[addrs.Provider]providers.Factory{addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p)}
  4396  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4397  		ResourceTypes: map[string]*configschema.Block{
  4398  			"aws_instance": {
  4399  				Attributes: map[string]*configschema.Attribute{
  4400  					"require_new": {Type: cty.String, Optional: true},
  4401  					"id":          {Type: cty.String, Computed: true},
  4402  				},
  4403  			},
  4404  		},
  4405  	})
  4406  
  4407  	state := states.NewState()
  4408  	root := state.EnsureModule(addrs.RootModuleInstance)
  4409  	root.SetResourceInstanceCurrent(
  4410  		mustResourceInstanceAddr("aws_instance.web").Resource,
  4411  		&states.ResourceInstanceObjectSrc{
  4412  			Status:    states.ObjectReady,
  4413  			AttrsJSON: []byte(`{"id":"foo"}`),
  4414  		},
  4415  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4416  	)
  4417  
  4418  	p.PlanResourceChangeFn = testDiffFn
  4419  
  4420  	ctx := testContext2(t, &ContextOpts{
  4421  		Providers: ps,
  4422  	})
  4423  	createdInstanceId := "bar"
  4424  	// Create works
  4425  	createFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4426  		s := req.PlannedState.AsValueMap()
  4427  		s["id"] = cty.StringVal(createdInstanceId)
  4428  		resp.NewState = cty.ObjectVal(s)
  4429  		return
  4430  	}
  4431  
  4432  	// Destroy starts broken
  4433  	destroyFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4434  		resp.NewState = req.PriorState
  4435  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy failed"))
  4436  		return
  4437  	}
  4438  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4439  		if req.PlannedState.IsNull() {
  4440  			return destroyFunc(req)
  4441  		} else {
  4442  			return createFunc(req)
  4443  		}
  4444  	}
  4445  
  4446  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4447  		Mode: plans.NormalMode,
  4448  		SetVariables: InputValues{
  4449  			"require_new": &InputValue{
  4450  				Value: cty.StringVal("yes"),
  4451  			},
  4452  		},
  4453  	})
  4454  	assertNoErrors(t, diags)
  4455  
  4456  	// Destroy is broken, so even though CBD successfully replaces the instance,
  4457  	// we'll have to save the Deposed instance to destroy later
  4458  	state, diags = ctx.Apply(plan, m)
  4459  	if !diags.HasErrors() {
  4460  		t.Fatal("should have error")
  4461  	}
  4462  
  4463  	checkStateString(t, state, `
  4464  aws_instance.web: (1 deposed)
  4465    ID = bar
  4466    provider = provider["registry.terraform.io/hashicorp/aws"]
  4467    require_new = yes
  4468    Deposed ID 1 = foo
  4469  	`)
  4470  
  4471  	createdInstanceId = "baz"
  4472  	ctx = testContext2(t, &ContextOpts{
  4473  		Providers: ps,
  4474  	})
  4475  
  4476  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4477  		Mode: plans.NormalMode,
  4478  		SetVariables: InputValues{
  4479  			"require_new": &InputValue{
  4480  				Value: cty.StringVal("baz"),
  4481  			},
  4482  		},
  4483  	})
  4484  	assertNoErrors(t, diags)
  4485  
  4486  	// We're replacing the primary instance once again. Destroy is _still_
  4487  	// broken, so the Deposed list gets longer
  4488  	state, diags = ctx.Apply(plan, m)
  4489  	if !diags.HasErrors() {
  4490  		t.Fatal("should have error")
  4491  	}
  4492  
  4493  	// For this one we can't rely on checkStateString because its result is
  4494  	// not deterministic when multiple deposed objects are present. Instead,
  4495  	// we will probe the state object directly.
  4496  	{
  4497  		is := state.RootModule().Resources["aws_instance.web"].Instances[addrs.NoKey]
  4498  		if is.Current == nil {
  4499  			t.Fatalf("no current object for aws_instance web; should have one")
  4500  		}
  4501  		if !bytes.Contains(is.Current.AttrsJSON, []byte("baz")) {
  4502  			t.Fatalf("incorrect current object attrs %s; want id=baz", is.Current.AttrsJSON)
  4503  		}
  4504  		if got, want := len(is.Deposed), 2; got != want {
  4505  			t.Fatalf("wrong number of deposed instances %d; want %d", got, want)
  4506  		}
  4507  		var foos, bars int
  4508  		for _, obj := range is.Deposed {
  4509  			if bytes.Contains(obj.AttrsJSON, []byte("foo")) {
  4510  				foos++
  4511  			}
  4512  			if bytes.Contains(obj.AttrsJSON, []byte("bar")) {
  4513  				bars++
  4514  			}
  4515  		}
  4516  		if got, want := foos, 1; got != want {
  4517  			t.Fatalf("wrong number of deposed instances with id=foo %d; want %d", got, want)
  4518  		}
  4519  		if got, want := bars, 1; got != want {
  4520  			t.Fatalf("wrong number of deposed instances with id=bar %d; want %d", got, want)
  4521  		}
  4522  	}
  4523  
  4524  	// Destroy partially fixed!
  4525  	destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4526  		s := req.PriorState.AsValueMap()
  4527  		id := s["id"].AsString()
  4528  		if id == "foo" || id == "baz" {
  4529  			resp.NewState = cty.NullVal(req.PriorState.Type())
  4530  		} else {
  4531  			resp.NewState = req.PriorState
  4532  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy partially failed"))
  4533  		}
  4534  		return
  4535  	}
  4536  
  4537  	createdInstanceId = "qux"
  4538  	ctx = testContext2(t, &ContextOpts{
  4539  		Providers: ps,
  4540  	})
  4541  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4542  		Mode: plans.NormalMode,
  4543  		SetVariables: InputValues{
  4544  			"require_new": &InputValue{
  4545  				Value: cty.StringVal("qux"),
  4546  			},
  4547  		},
  4548  	})
  4549  	assertNoErrors(t, diags)
  4550  
  4551  	state, diags = ctx.Apply(plan, m)
  4552  	// Expect error because 1/2 of Deposed destroys failed
  4553  	if !diags.HasErrors() {
  4554  		t.Fatal("should have error")
  4555  	}
  4556  
  4557  	// foo and baz are now gone, bar sticks around
  4558  	checkStateString(t, state, `
  4559  aws_instance.web: (1 deposed)
  4560    ID = qux
  4561    provider = provider["registry.terraform.io/hashicorp/aws"]
  4562    require_new = qux
  4563    Deposed ID 1 = bar
  4564  	`)
  4565  
  4566  	// Destroy working fully!
  4567  	destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4568  		resp.NewState = cty.NullVal(req.PriorState.Type())
  4569  		return
  4570  	}
  4571  
  4572  	createdInstanceId = "quux"
  4573  	ctx = testContext2(t, &ContextOpts{
  4574  		Providers: ps,
  4575  	})
  4576  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4577  		Mode: plans.NormalMode,
  4578  		SetVariables: InputValues{
  4579  			"require_new": &InputValue{
  4580  				Value: cty.StringVal("quux"),
  4581  			},
  4582  		},
  4583  	})
  4584  	assertNoErrors(t, diags)
  4585  	state, diags = ctx.Apply(plan, m)
  4586  	if diags.HasErrors() {
  4587  		t.Fatal("should not have error:", diags.Err())
  4588  	}
  4589  
  4590  	// And finally the state is clean
  4591  	checkStateString(t, state, `
  4592  aws_instance.web:
  4593    ID = quux
  4594    provider = provider["registry.terraform.io/hashicorp/aws"]
  4595    require_new = quux
  4596  	`)
  4597  }
  4598  
  4599  // Verify that a normal provisioner with on_failure "continue" set won't
  4600  // taint the resource and continues executing.
  4601  func TestContext2Apply_provisionerFailContinue(t *testing.T) {
  4602  	m := testModule(t, "apply-provisioner-fail-continue")
  4603  	p := testProvider("aws")
  4604  	pr := testProvisioner()
  4605  	p.PlanResourceChangeFn = testDiffFn
  4606  	p.ApplyResourceChangeFn = testApplyFn
  4607  
  4608  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4609  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4610  		return
  4611  	}
  4612  
  4613  	ctx := testContext2(t, &ContextOpts{
  4614  		Providers: map[addrs.Provider]providers.Factory{
  4615  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4616  		},
  4617  		Provisioners: map[string]provisioners.Factory{
  4618  			"shell": testProvisionerFuncFixed(pr),
  4619  		},
  4620  	})
  4621  
  4622  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4623  	assertNoErrors(t, diags)
  4624  
  4625  	state, diags := ctx.Apply(plan, m)
  4626  	if diags.HasErrors() {
  4627  		t.Fatalf("diags: %s", diags.Err())
  4628  	}
  4629  
  4630  	checkStateString(t, state, `
  4631  aws_instance.foo:
  4632    ID = foo
  4633    provider = provider["registry.terraform.io/hashicorp/aws"]
  4634    foo = bar
  4635    type = aws_instance
  4636    `)
  4637  
  4638  	// Verify apply was invoked
  4639  	if !pr.ProvisionResourceCalled {
  4640  		t.Fatalf("provisioner not invoked")
  4641  	}
  4642  }
  4643  
  4644  // Verify that a normal provisioner with on_failure "continue" records
  4645  // the error with the hook.
  4646  func TestContext2Apply_provisionerFailContinueHook(t *testing.T) {
  4647  	h := new(MockHook)
  4648  	m := testModule(t, "apply-provisioner-fail-continue")
  4649  	p := testProvider("aws")
  4650  	pr := testProvisioner()
  4651  	p.PlanResourceChangeFn = testDiffFn
  4652  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4653  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4654  		return
  4655  	}
  4656  
  4657  	ctx := testContext2(t, &ContextOpts{
  4658  		Hooks: []Hook{h},
  4659  		Providers: map[addrs.Provider]providers.Factory{
  4660  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4661  		},
  4662  		Provisioners: map[string]provisioners.Factory{
  4663  			"shell": testProvisionerFuncFixed(pr),
  4664  		},
  4665  	})
  4666  
  4667  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4668  	assertNoErrors(t, diags)
  4669  
  4670  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  4671  		t.Fatalf("apply errors: %s", diags.Err())
  4672  	}
  4673  
  4674  	if !h.PostProvisionInstanceStepCalled {
  4675  		t.Fatal("PostProvisionInstanceStep not called")
  4676  	}
  4677  	if h.PostProvisionInstanceStepErrorArg == nil {
  4678  		t.Fatal("should have error")
  4679  	}
  4680  }
  4681  
  4682  func TestContext2Apply_provisionerDestroy(t *testing.T) {
  4683  	m := testModule(t, "apply-provisioner-destroy")
  4684  	p := testProvider("aws")
  4685  	pr := testProvisioner()
  4686  	p.PlanResourceChangeFn = testDiffFn
  4687  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4688  		val := req.Config.GetAttr("command").AsString()
  4689  		if val != "destroy a bar" {
  4690  			t.Fatalf("bad value for foo: %q", val)
  4691  		}
  4692  
  4693  		return
  4694  	}
  4695  
  4696  	state := states.NewState()
  4697  	root := state.RootModule()
  4698  	root.SetResourceInstanceCurrent(
  4699  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4700  		&states.ResourceInstanceObjectSrc{
  4701  			Status:    states.ObjectReady,
  4702  			AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
  4703  		},
  4704  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4705  	)
  4706  
  4707  	ctx := testContext2(t, &ContextOpts{
  4708  		Providers: map[addrs.Provider]providers.Factory{
  4709  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4710  		},
  4711  		Provisioners: map[string]provisioners.Factory{
  4712  			"shell": testProvisionerFuncFixed(pr),
  4713  		},
  4714  	})
  4715  
  4716  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
  4717  	assertNoErrors(t, diags)
  4718  
  4719  	state, diags = ctx.Apply(plan, m)
  4720  	if diags.HasErrors() {
  4721  		t.Fatalf("diags: %s", diags.Err())
  4722  	}
  4723  
  4724  	checkStateString(t, state, `<no state>`)
  4725  
  4726  	// Verify apply was invoked
  4727  	if !pr.ProvisionResourceCalled {
  4728  		t.Fatalf("provisioner not invoked")
  4729  	}
  4730  }
  4731  
  4732  // Verify that on destroy provisioner failure, nothing happens to the instance
  4733  func TestContext2Apply_provisionerDestroyFail(t *testing.T) {
  4734  	m := testModule(t, "apply-provisioner-destroy")
  4735  	p := testProvider("aws")
  4736  	pr := testProvisioner()
  4737  	p.PlanResourceChangeFn = testDiffFn
  4738  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4739  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4740  		return
  4741  	}
  4742  
  4743  	state := states.NewState()
  4744  	root := state.RootModule()
  4745  	root.SetResourceInstanceCurrent(
  4746  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4747  		&states.ResourceInstanceObjectSrc{
  4748  			Status:    states.ObjectReady,
  4749  			AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
  4750  		},
  4751  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4752  	)
  4753  
  4754  	ctx := testContext2(t, &ContextOpts{
  4755  		Providers: map[addrs.Provider]providers.Factory{
  4756  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4757  		},
  4758  		Provisioners: map[string]provisioners.Factory{
  4759  			"shell": testProvisionerFuncFixed(pr),
  4760  		},
  4761  	})
  4762  
  4763  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
  4764  	assertNoErrors(t, diags)
  4765  
  4766  	state, diags = ctx.Apply(plan, m)
  4767  	if diags == nil {
  4768  		t.Fatal("should error")
  4769  	}
  4770  
  4771  	checkStateString(t, state, `
  4772  aws_instance.foo["a"]:
  4773    ID = bar
  4774    provider = provider["registry.terraform.io/hashicorp/aws"]
  4775    foo = bar
  4776  	`)
  4777  
  4778  	// Verify apply was invoked
  4779  	if !pr.ProvisionResourceCalled {
  4780  		t.Fatalf("provisioner not invoked")
  4781  	}
  4782  }
  4783  
  4784  // Verify that on destroy provisioner failure with "continue" that
  4785  // we continue to the next provisioner.
  4786  func TestContext2Apply_provisionerDestroyFailContinue(t *testing.T) {
  4787  	m := testModule(t, "apply-provisioner-destroy-continue")
  4788  	p := testProvider("aws")
  4789  	pr := testProvisioner()
  4790  	p.PlanResourceChangeFn = testDiffFn
  4791  
  4792  	var l sync.Mutex
  4793  	var calls []string
  4794  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4795  		val := req.Config.GetAttr("command")
  4796  		if val.IsNull() {
  4797  			t.Fatalf("bad value for foo: %#v", val)
  4798  		}
  4799  
  4800  		l.Lock()
  4801  		defer l.Unlock()
  4802  		calls = append(calls, val.AsString())
  4803  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4804  		return
  4805  	}
  4806  
  4807  	state := states.NewState()
  4808  	root := state.RootModule()
  4809  	root.SetResourceInstanceCurrent(
  4810  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4811  		&states.ResourceInstanceObjectSrc{
  4812  			Status:    states.ObjectReady,
  4813  			AttrsJSON: []byte(`{"id":"bar"}`),
  4814  		},
  4815  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4816  	)
  4817  
  4818  	ctx := testContext2(t, &ContextOpts{
  4819  		Providers: map[addrs.Provider]providers.Factory{
  4820  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4821  		},
  4822  		Provisioners: map[string]provisioners.Factory{
  4823  			"shell": testProvisionerFuncFixed(pr),
  4824  		},
  4825  	})
  4826  
  4827  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4828  		Mode: plans.DestroyMode,
  4829  	})
  4830  	assertNoErrors(t, diags)
  4831  
  4832  	state, diags = ctx.Apply(plan, m)
  4833  	if diags.HasErrors() {
  4834  		t.Fatalf("diags: %s", diags.Err())
  4835  	}
  4836  
  4837  	checkStateString(t, state, `<no state>`)
  4838  
  4839  	// Verify apply was invoked
  4840  	if !pr.ProvisionResourceCalled {
  4841  		t.Fatalf("provisioner not invoked")
  4842  	}
  4843  
  4844  	expected := []string{"one", "two"}
  4845  	if !reflect.DeepEqual(calls, expected) {
  4846  		t.Fatalf("wrong commands\ngot:  %#v\nwant: %#v", calls, expected)
  4847  	}
  4848  }
  4849  
  4850  // Verify that on destroy provisioner failure with "continue" that
  4851  // we continue to the next provisioner. But if the next provisioner defines
  4852  // to fail, then we fail after running it.
  4853  func TestContext2Apply_provisionerDestroyFailContinueFail(t *testing.T) {
  4854  	m := testModule(t, "apply-provisioner-destroy-fail")
  4855  	p := testProvider("aws")
  4856  	pr := testProvisioner()
  4857  	p.PlanResourceChangeFn = testDiffFn
  4858  
  4859  	var l sync.Mutex
  4860  	var calls []string
  4861  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4862  		val := req.Config.GetAttr("command")
  4863  		if val.IsNull() {
  4864  			t.Fatalf("bad value for foo: %#v", val)
  4865  		}
  4866  
  4867  		l.Lock()
  4868  		defer l.Unlock()
  4869  		calls = append(calls, val.AsString())
  4870  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4871  		return
  4872  	}
  4873  
  4874  	state := states.NewState()
  4875  	root := state.EnsureModule(addrs.RootModuleInstance)
  4876  	root.SetResourceInstanceCurrent(
  4877  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  4878  		&states.ResourceInstanceObjectSrc{
  4879  			Status:    states.ObjectReady,
  4880  			AttrsJSON: []byte(`{"id":"bar"}`),
  4881  		},
  4882  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4883  	)
  4884  
  4885  	ctx := testContext2(t, &ContextOpts{
  4886  		Providers: map[addrs.Provider]providers.Factory{
  4887  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4888  		},
  4889  		Provisioners: map[string]provisioners.Factory{
  4890  			"shell": testProvisionerFuncFixed(pr),
  4891  		},
  4892  	})
  4893  
  4894  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4895  		Mode: plans.DestroyMode,
  4896  	})
  4897  	assertNoErrors(t, diags)
  4898  
  4899  	state, diags = ctx.Apply(plan, m)
  4900  	if diags == nil {
  4901  		t.Fatal("apply succeeded; wanted error from second provisioner")
  4902  	}
  4903  
  4904  	checkStateString(t, state, `
  4905  aws_instance.foo:
  4906    ID = bar
  4907    provider = provider["registry.terraform.io/hashicorp/aws"]
  4908    `)
  4909  
  4910  	// Verify apply was invoked
  4911  	if !pr.ProvisionResourceCalled {
  4912  		t.Fatalf("provisioner not invoked")
  4913  	}
  4914  
  4915  	expected := []string{"one", "two"}
  4916  	if !reflect.DeepEqual(calls, expected) {
  4917  		t.Fatalf("bad: %#v", calls)
  4918  	}
  4919  }
  4920  
  4921  // Verify destroy provisioners are not run for tainted instances.
  4922  func TestContext2Apply_provisionerDestroyTainted(t *testing.T) {
  4923  	m := testModule(t, "apply-provisioner-destroy")
  4924  	p := testProvider("aws")
  4925  	pr := testProvisioner()
  4926  	p.PlanResourceChangeFn = testDiffFn
  4927  	p.ApplyResourceChangeFn = testApplyFn
  4928  
  4929  	destroyCalled := false
  4930  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4931  		expected := "create a b"
  4932  		val := req.Config.GetAttr("command")
  4933  		if val.AsString() != expected {
  4934  			t.Fatalf("bad value for command: %#v", val)
  4935  		}
  4936  
  4937  		return
  4938  	}
  4939  
  4940  	state := states.NewState()
  4941  	root := state.RootModule()
  4942  	root.SetResourceInstanceCurrent(
  4943  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4944  		&states.ResourceInstanceObjectSrc{
  4945  			Status:    states.ObjectTainted,
  4946  			AttrsJSON: []byte(`{"id":"bar"}`),
  4947  		},
  4948  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4949  	)
  4950  
  4951  	ctx := testContext2(t, &ContextOpts{
  4952  		Providers: map[addrs.Provider]providers.Factory{
  4953  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4954  		},
  4955  		Provisioners: map[string]provisioners.Factory{
  4956  			"shell": testProvisionerFuncFixed(pr),
  4957  		},
  4958  	})
  4959  
  4960  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4961  		Mode: plans.NormalMode,
  4962  		SetVariables: InputValues{
  4963  			"input": &InputValue{
  4964  				Value: cty.MapVal(map[string]cty.Value{
  4965  					"a": cty.StringVal("b"),
  4966  				}),
  4967  				SourceType: ValueFromInput,
  4968  			},
  4969  		},
  4970  	})
  4971  	assertNoErrors(t, diags)
  4972  
  4973  	state, diags = ctx.Apply(plan, m)
  4974  	if diags.HasErrors() {
  4975  		t.Fatalf("diags: %s", diags.Err())
  4976  	}
  4977  
  4978  	checkStateString(t, state, `
  4979  aws_instance.foo["a"]:
  4980    ID = foo
  4981    provider = provider["registry.terraform.io/hashicorp/aws"]
  4982    foo = bar
  4983    type = aws_instance
  4984  	`)
  4985  
  4986  	// Verify apply was invoked
  4987  	if !pr.ProvisionResourceCalled {
  4988  		t.Fatalf("provisioner not invoked")
  4989  	}
  4990  
  4991  	if destroyCalled {
  4992  		t.Fatal("destroy should not be called")
  4993  	}
  4994  }
  4995  
  4996  func TestContext2Apply_provisionerResourceRef(t *testing.T) {
  4997  	m := testModule(t, "apply-provisioner-resource-ref")
  4998  	p := testProvider("aws")
  4999  	p.PlanResourceChangeFn = testDiffFn
  5000  	p.ApplyResourceChangeFn = testApplyFn
  5001  
  5002  	pr := testProvisioner()
  5003  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5004  		val := req.Config.GetAttr("command")
  5005  		if val.AsString() != "2" {
  5006  			t.Fatalf("bad value for command: %#v", val)
  5007  		}
  5008  
  5009  		return
  5010  	}
  5011  
  5012  	ctx := testContext2(t, &ContextOpts{
  5013  		Providers: map[addrs.Provider]providers.Factory{
  5014  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5015  		},
  5016  		Provisioners: map[string]provisioners.Factory{
  5017  			"shell": testProvisionerFuncFixed(pr),
  5018  		},
  5019  	})
  5020  
  5021  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5022  	assertNoErrors(t, diags)
  5023  
  5024  	state, diags := ctx.Apply(plan, m)
  5025  	if diags.HasErrors() {
  5026  		t.Fatalf("diags: %s", diags.Err())
  5027  	}
  5028  
  5029  	actual := strings.TrimSpace(state.String())
  5030  	expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr)
  5031  	if actual != expected {
  5032  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5033  	}
  5034  
  5035  	// Verify apply was invoked
  5036  	if !pr.ProvisionResourceCalled {
  5037  		t.Fatalf("provisioner not invoked")
  5038  	}
  5039  }
  5040  
  5041  func TestContext2Apply_provisionerSelfRef(t *testing.T) {
  5042  	m := testModule(t, "apply-provisioner-self-ref")
  5043  	p := testProvider("aws")
  5044  	pr := testProvisioner()
  5045  	p.PlanResourceChangeFn = testDiffFn
  5046  	p.ApplyResourceChangeFn = testApplyFn
  5047  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5048  		val := req.Config.GetAttr("command")
  5049  		if val.AsString() != "bar" {
  5050  			t.Fatalf("bad value for command: %#v", val)
  5051  		}
  5052  
  5053  		return
  5054  	}
  5055  
  5056  	ctx := testContext2(t, &ContextOpts{
  5057  		Providers: map[addrs.Provider]providers.Factory{
  5058  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5059  		},
  5060  		Provisioners: map[string]provisioners.Factory{
  5061  			"shell": testProvisionerFuncFixed(pr),
  5062  		},
  5063  	})
  5064  
  5065  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5066  	assertNoErrors(t, diags)
  5067  
  5068  	state, diags := ctx.Apply(plan, m)
  5069  	if diags.HasErrors() {
  5070  		t.Fatalf("diags: %s", diags.Err())
  5071  	}
  5072  
  5073  	actual := strings.TrimSpace(state.String())
  5074  	expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr)
  5075  	if actual != expected {
  5076  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5077  	}
  5078  
  5079  	// Verify apply was invoked
  5080  	if !pr.ProvisionResourceCalled {
  5081  		t.Fatalf("provisioner not invoked")
  5082  	}
  5083  }
  5084  
  5085  func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) {
  5086  	var lock sync.Mutex
  5087  	commands := make([]string, 0, 5)
  5088  
  5089  	m := testModule(t, "apply-provisioner-multi-self-ref")
  5090  	p := testProvider("aws")
  5091  	pr := testProvisioner()
  5092  	p.PlanResourceChangeFn = testDiffFn
  5093  	p.ApplyResourceChangeFn = testApplyFn
  5094  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5095  		lock.Lock()
  5096  		defer lock.Unlock()
  5097  
  5098  		val := req.Config.GetAttr("command")
  5099  		if val.IsNull() {
  5100  			t.Fatalf("bad value for command: %#v", val)
  5101  		}
  5102  
  5103  		commands = append(commands, val.AsString())
  5104  		return
  5105  	}
  5106  
  5107  	ctx := testContext2(t, &ContextOpts{
  5108  		Providers: map[addrs.Provider]providers.Factory{
  5109  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5110  		},
  5111  		Provisioners: map[string]provisioners.Factory{
  5112  			"shell": testProvisionerFuncFixed(pr),
  5113  		},
  5114  	})
  5115  
  5116  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5117  	assertNoErrors(t, diags)
  5118  
  5119  	state, diags := ctx.Apply(plan, m)
  5120  	if diags.HasErrors() {
  5121  		t.Fatalf("diags: %s", diags.Err())
  5122  	}
  5123  
  5124  	actual := strings.TrimSpace(state.String())
  5125  	expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr)
  5126  	if actual != expected {
  5127  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5128  	}
  5129  
  5130  	// Verify apply was invoked
  5131  	if !pr.ProvisionResourceCalled {
  5132  		t.Fatalf("provisioner not invoked")
  5133  	}
  5134  
  5135  	// Verify our result
  5136  	sort.Strings(commands)
  5137  	expectedCommands := []string{"number 0", "number 1", "number 2"}
  5138  	if !reflect.DeepEqual(commands, expectedCommands) {
  5139  		t.Fatalf("bad: %#v", commands)
  5140  	}
  5141  }
  5142  
  5143  func TestContext2Apply_provisionerMultiSelfRefSingle(t *testing.T) {
  5144  	var lock sync.Mutex
  5145  	order := make([]string, 0, 5)
  5146  
  5147  	m := testModule(t, "apply-provisioner-multi-self-ref-single")
  5148  	p := testProvider("aws")
  5149  	pr := testProvisioner()
  5150  	p.PlanResourceChangeFn = testDiffFn
  5151  	p.ApplyResourceChangeFn = testApplyFn
  5152  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5153  		lock.Lock()
  5154  		defer lock.Unlock()
  5155  
  5156  		val := req.Config.GetAttr("order")
  5157  		if val.IsNull() {
  5158  			t.Fatalf("no val for order")
  5159  		}
  5160  
  5161  		order = append(order, val.AsString())
  5162  		return
  5163  	}
  5164  
  5165  	ctx := testContext2(t, &ContextOpts{
  5166  		Providers: map[addrs.Provider]providers.Factory{
  5167  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5168  		},
  5169  		Provisioners: map[string]provisioners.Factory{
  5170  			"shell": testProvisionerFuncFixed(pr),
  5171  		},
  5172  	})
  5173  
  5174  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5175  	assertNoErrors(t, diags)
  5176  
  5177  	state, diags := ctx.Apply(plan, m)
  5178  	if diags.HasErrors() {
  5179  		t.Fatalf("diags: %s", diags.Err())
  5180  	}
  5181  
  5182  	actual := strings.TrimSpace(state.String())
  5183  	expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefSingleStr)
  5184  	if actual != expected {
  5185  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5186  	}
  5187  
  5188  	// Verify apply was invoked
  5189  	if !pr.ProvisionResourceCalled {
  5190  		t.Fatalf("provisioner not invoked")
  5191  	}
  5192  
  5193  	// Verify our result
  5194  	sort.Strings(order)
  5195  	expectedOrder := []string{"0", "1", "2"}
  5196  	if !reflect.DeepEqual(order, expectedOrder) {
  5197  		t.Fatalf("bad: %#v", order)
  5198  	}
  5199  }
  5200  
  5201  func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) {
  5202  	m := testModule(t, "apply-provisioner-explicit-self-ref")
  5203  	p := testProvider("aws")
  5204  	pr := testProvisioner()
  5205  	p.PlanResourceChangeFn = testDiffFn
  5206  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5207  		val := req.Config.GetAttr("command")
  5208  		if val.IsNull() || val.AsString() != "bar" {
  5209  			t.Fatalf("bad value for command: %#v", val)
  5210  		}
  5211  
  5212  		return
  5213  	}
  5214  
  5215  	var state *states.State
  5216  	{
  5217  		ctx := testContext2(t, &ContextOpts{
  5218  			Providers: map[addrs.Provider]providers.Factory{
  5219  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5220  			},
  5221  			Provisioners: map[string]provisioners.Factory{
  5222  				"shell": testProvisionerFuncFixed(pr),
  5223  			},
  5224  		})
  5225  
  5226  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5227  		if diags.HasErrors() {
  5228  			t.Fatalf("diags: %s", diags.Err())
  5229  		}
  5230  
  5231  		state, diags = ctx.Apply(plan, m)
  5232  		if diags.HasErrors() {
  5233  			t.Fatalf("diags: %s", diags.Err())
  5234  		}
  5235  
  5236  		// Verify apply was invoked
  5237  		if !pr.ProvisionResourceCalled {
  5238  			t.Fatalf("provisioner not invoked")
  5239  		}
  5240  	}
  5241  
  5242  	{
  5243  		ctx := testContext2(t, &ContextOpts{
  5244  			Providers: map[addrs.Provider]providers.Factory{
  5245  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5246  			},
  5247  			Provisioners: map[string]provisioners.Factory{
  5248  				"shell": testProvisionerFuncFixed(pr),
  5249  			},
  5250  		})
  5251  
  5252  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5253  			Mode: plans.DestroyMode,
  5254  		})
  5255  		if diags.HasErrors() {
  5256  			t.Fatalf("diags: %s", diags.Err())
  5257  		}
  5258  
  5259  		state, diags = ctx.Apply(plan, m)
  5260  		if diags.HasErrors() {
  5261  			t.Fatalf("diags: %s", diags.Err())
  5262  		}
  5263  
  5264  		checkStateString(t, state, `<no state>`)
  5265  	}
  5266  }
  5267  
  5268  func TestContext2Apply_provisionerForEachSelfRef(t *testing.T) {
  5269  	m := testModule(t, "apply-provisioner-for-each-self")
  5270  	p := testProvider("aws")
  5271  	pr := testProvisioner()
  5272  	p.PlanResourceChangeFn = testDiffFn
  5273  
  5274  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5275  		val := req.Config.GetAttr("command")
  5276  		if val.IsNull() {
  5277  			t.Fatalf("bad value for command: %#v", val)
  5278  		}
  5279  
  5280  		return resp
  5281  	}
  5282  
  5283  	ctx := testContext2(t, &ContextOpts{
  5284  		Providers: map[addrs.Provider]providers.Factory{
  5285  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5286  		},
  5287  		Provisioners: map[string]provisioners.Factory{
  5288  			"shell": testProvisionerFuncFixed(pr),
  5289  		},
  5290  	})
  5291  
  5292  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5293  	assertNoErrors(t, diags)
  5294  
  5295  	_, diags = ctx.Apply(plan, m)
  5296  	if diags.HasErrors() {
  5297  		t.Fatalf("diags: %s", diags.Err())
  5298  	}
  5299  }
  5300  
  5301  // Provisioner should NOT run on a diff, only create
  5302  func TestContext2Apply_Provisioner_Diff(t *testing.T) {
  5303  	m := testModule(t, "apply-provisioner-diff")
  5304  	p := testProvider("aws")
  5305  	pr := testProvisioner()
  5306  	p.PlanResourceChangeFn = testDiffFn
  5307  	p.ApplyResourceChangeFn = testApplyFn
  5308  	ctx := testContext2(t, &ContextOpts{
  5309  		Providers: map[addrs.Provider]providers.Factory{
  5310  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5311  		},
  5312  		Provisioners: map[string]provisioners.Factory{
  5313  			"shell": testProvisionerFuncFixed(pr),
  5314  		},
  5315  	})
  5316  
  5317  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5318  	assertNoErrors(t, diags)
  5319  
  5320  	state, diags := ctx.Apply(plan, m)
  5321  	if diags.HasErrors() {
  5322  		logDiagnostics(t, diags)
  5323  		t.Fatal("apply failed")
  5324  	}
  5325  
  5326  	actual := strings.TrimSpace(state.String())
  5327  	expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr)
  5328  	if actual != expected {
  5329  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5330  	}
  5331  
  5332  	// Verify apply was invoked
  5333  	if !pr.ProvisionResourceCalled {
  5334  		t.Fatalf("provisioner was not called on first apply")
  5335  	}
  5336  	pr.ProvisionResourceCalled = false
  5337  
  5338  	// Change the state to force a diff
  5339  	mod := state.RootModule()
  5340  	obj := mod.Resources["aws_instance.bar"].Instances[addrs.NoKey].Current
  5341  	var attrs map[string]interface{}
  5342  	err := json.Unmarshal(obj.AttrsJSON, &attrs)
  5343  	if err != nil {
  5344  		t.Fatal(err)
  5345  	}
  5346  	attrs["foo"] = "baz"
  5347  	obj.AttrsJSON, err = json.Marshal(attrs)
  5348  	if err != nil {
  5349  		t.Fatal(err)
  5350  	}
  5351  
  5352  	// Re-create context with state
  5353  	ctx = testContext2(t, &ContextOpts{
  5354  		Providers: map[addrs.Provider]providers.Factory{
  5355  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5356  		},
  5357  		Provisioners: map[string]provisioners.Factory{
  5358  			"shell": testProvisionerFuncFixed(pr),
  5359  		},
  5360  	})
  5361  
  5362  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  5363  	assertNoErrors(t, diags)
  5364  
  5365  	state2, diags := ctx.Apply(plan, m)
  5366  	if diags.HasErrors() {
  5367  		logDiagnostics(t, diags)
  5368  		t.Fatal("apply failed")
  5369  	}
  5370  
  5371  	actual = strings.TrimSpace(state2.String())
  5372  	if actual != expected {
  5373  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5374  	}
  5375  
  5376  	// Verify apply was NOT invoked
  5377  	if pr.ProvisionResourceCalled {
  5378  		t.Fatalf("provisioner was called on second apply; should not have been")
  5379  	}
  5380  }
  5381  
  5382  func TestContext2Apply_outputDiffVars(t *testing.T) {
  5383  	m := testModule(t, "apply-good")
  5384  	p := testProvider("aws")
  5385  
  5386  	state := states.NewState()
  5387  	root := state.EnsureModule(addrs.RootModuleInstance)
  5388  	root.SetResourceInstanceCurrent(
  5389  		mustResourceInstanceAddr("aws_instance.baz").Resource,
  5390  		&states.ResourceInstanceObjectSrc{
  5391  			Status:    states.ObjectReady,
  5392  			AttrsJSON: []byte(`{"id":"bar"}`),
  5393  		},
  5394  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5395  	)
  5396  
  5397  	ctx := testContext2(t, &ContextOpts{
  5398  		Providers: map[addrs.Provider]providers.Factory{
  5399  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5400  		},
  5401  	})
  5402  
  5403  	p.PlanResourceChangeFn = testDiffFn
  5404  	//func(info *InstanceInfo, s *InstanceState, rc *ResourceConfig) (*InstanceDiff, error) {
  5405  	//    d := &InstanceDiff{
  5406  	//        Attributes: map[string]*ResourceAttrDiff{},
  5407  	//    }
  5408  	//    if new, ok := rc.Get("value"); ok {
  5409  	//        d.Attributes["value"] = &ResourceAttrDiff{
  5410  	//            New: new.(string),
  5411  	//        }
  5412  	//    }
  5413  	//    if new, ok := rc.Get("foo"); ok {
  5414  	//        d.Attributes["foo"] = &ResourceAttrDiff{
  5415  	//            New: new.(string),
  5416  	//        }
  5417  	//    } else if rc.IsComputed("foo") {
  5418  	//        d.Attributes["foo"] = &ResourceAttrDiff{
  5419  	//            NewComputed: true,
  5420  	//            Type:        DiffAttrOutput, // This doesn't actually really do anything anymore, but this test originally set it.
  5421  	//        }
  5422  	//    }
  5423  	//    if new, ok := rc.Get("num"); ok {
  5424  	//        d.Attributes["num"] = &ResourceAttrDiff{
  5425  	//            New: fmt.Sprintf("%#v", new),
  5426  	//        }
  5427  	//    }
  5428  	//    return d, nil
  5429  	//}
  5430  
  5431  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5432  	assertNoErrors(t, diags)
  5433  
  5434  	_, diags = ctx.Apply(plan, m)
  5435  	assertNoErrors(t, diags)
  5436  }
  5437  
  5438  func TestContext2Apply_destroyX(t *testing.T) {
  5439  	m := testModule(t, "apply-destroy")
  5440  	h := new(HookRecordApplyOrder)
  5441  	p := testProvider("aws")
  5442  	p.PlanResourceChangeFn = testDiffFn
  5443  	ctx := testContext2(t, &ContextOpts{
  5444  		Hooks: []Hook{h},
  5445  		Providers: map[addrs.Provider]providers.Factory{
  5446  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5447  		},
  5448  	})
  5449  
  5450  	// First plan and apply a create operation
  5451  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5452  	assertNoErrors(t, diags)
  5453  
  5454  	state, diags := ctx.Apply(plan, m)
  5455  	if diags.HasErrors() {
  5456  		t.Fatalf("diags: %s", diags.Err())
  5457  	}
  5458  
  5459  	// Next, plan and apply a destroy operation
  5460  	h.Active = true
  5461  	ctx = testContext2(t, &ContextOpts{
  5462  		Hooks: []Hook{h},
  5463  		Providers: map[addrs.Provider]providers.Factory{
  5464  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5465  		},
  5466  	})
  5467  
  5468  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5469  		Mode: plans.DestroyMode,
  5470  	})
  5471  	assertNoErrors(t, diags)
  5472  
  5473  	state, diags = ctx.Apply(plan, m)
  5474  	if diags.HasErrors() {
  5475  		t.Fatalf("diags: %s", diags.Err())
  5476  	}
  5477  
  5478  	// Test that things were destroyed
  5479  	actual := strings.TrimSpace(state.String())
  5480  	expected := strings.TrimSpace(testTerraformApplyDestroyStr)
  5481  	if actual != expected {
  5482  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5483  	}
  5484  
  5485  	// Test that things were destroyed _in the right order_
  5486  	expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
  5487  	actual2 := h.IDs
  5488  	if !reflect.DeepEqual(actual2, expected2) {
  5489  		t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
  5490  	}
  5491  }
  5492  
  5493  func TestContext2Apply_destroyOrder(t *testing.T) {
  5494  	m := testModule(t, "apply-destroy")
  5495  	h := new(HookRecordApplyOrder)
  5496  	p := testProvider("aws")
  5497  	p.PlanResourceChangeFn = testDiffFn
  5498  	ctx := testContext2(t, &ContextOpts{
  5499  		Hooks: []Hook{h},
  5500  		Providers: map[addrs.Provider]providers.Factory{
  5501  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5502  		},
  5503  	})
  5504  
  5505  	// First plan and apply a create operation
  5506  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5507  	assertNoErrors(t, diags)
  5508  
  5509  	state, diags := ctx.Apply(plan, m)
  5510  	if diags.HasErrors() {
  5511  		t.Fatalf("diags: %s", diags.Err())
  5512  	}
  5513  
  5514  	t.Logf("State 1: %s", state)
  5515  
  5516  	// Next, plan and apply a destroy
  5517  	h.Active = true
  5518  	ctx = testContext2(t, &ContextOpts{
  5519  		Hooks: []Hook{h},
  5520  		Providers: map[addrs.Provider]providers.Factory{
  5521  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5522  		},
  5523  	})
  5524  
  5525  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5526  		Mode: plans.DestroyMode,
  5527  	})
  5528  	assertNoErrors(t, diags)
  5529  
  5530  	state, diags = ctx.Apply(plan, m)
  5531  	if diags.HasErrors() {
  5532  		t.Fatalf("diags: %s", diags.Err())
  5533  	}
  5534  
  5535  	// Test that things were destroyed
  5536  	actual := strings.TrimSpace(state.String())
  5537  	expected := strings.TrimSpace(testTerraformApplyDestroyStr)
  5538  	if actual != expected {
  5539  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5540  	}
  5541  
  5542  	// Test that things were destroyed _in the right order_
  5543  	expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
  5544  	actual2 := h.IDs
  5545  	if !reflect.DeepEqual(actual2, expected2) {
  5546  		t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
  5547  	}
  5548  }
  5549  
  5550  // https://github.com/hashicorp/terraform/issues/2767
  5551  func TestContext2Apply_destroyModulePrefix(t *testing.T) {
  5552  	m := testModule(t, "apply-destroy-module-resource-prefix")
  5553  	h := new(MockHook)
  5554  	p := testProvider("aws")
  5555  	p.PlanResourceChangeFn = testDiffFn
  5556  	ctx := testContext2(t, &ContextOpts{
  5557  		Hooks: []Hook{h},
  5558  		Providers: map[addrs.Provider]providers.Factory{
  5559  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5560  		},
  5561  	})
  5562  
  5563  	// First plan and apply a create operation
  5564  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5565  	assertNoErrors(t, diags)
  5566  
  5567  	state, diags := ctx.Apply(plan, m)
  5568  	if diags.HasErrors() {
  5569  		t.Fatalf("diags: %s", diags.Err())
  5570  	}
  5571  
  5572  	// Verify that we got the apply info correct
  5573  	if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" {
  5574  		t.Fatalf("bad: %s", v)
  5575  	}
  5576  
  5577  	// Next, plan and apply a destroy operation and reset the hook
  5578  	h = new(MockHook)
  5579  	ctx = testContext2(t, &ContextOpts{
  5580  		Hooks: []Hook{h},
  5581  		Providers: map[addrs.Provider]providers.Factory{
  5582  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5583  		},
  5584  	})
  5585  
  5586  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5587  		Mode: plans.DestroyMode,
  5588  	})
  5589  	assertNoErrors(t, diags)
  5590  
  5591  	_, diags = ctx.Apply(plan, m)
  5592  	if diags.HasErrors() {
  5593  		t.Fatalf("diags: %s", diags.Err())
  5594  	}
  5595  
  5596  	// Test that things were destroyed
  5597  	if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" {
  5598  		t.Fatalf("bad: %s", v)
  5599  	}
  5600  }
  5601  
  5602  func TestContext2Apply_destroyNestedModule(t *testing.T) {
  5603  	m := testModule(t, "apply-destroy-nested-module")
  5604  	p := testProvider("aws")
  5605  	p.PlanResourceChangeFn = testDiffFn
  5606  
  5607  	state := states.NewState()
  5608  	root := state.EnsureModule(addrs.RootModuleInstance)
  5609  	root.SetResourceInstanceCurrent(
  5610  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  5611  		&states.ResourceInstanceObjectSrc{
  5612  			Status:    states.ObjectReady,
  5613  			AttrsJSON: []byte(`{"id":"bar"}`),
  5614  		},
  5615  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5616  	)
  5617  
  5618  	ctx := testContext2(t, &ContextOpts{
  5619  		Providers: map[addrs.Provider]providers.Factory{
  5620  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5621  		},
  5622  	})
  5623  
  5624  	// First plan and apply a create operation
  5625  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5626  	assertNoErrors(t, diags)
  5627  
  5628  	s, diags := ctx.Apply(plan, m)
  5629  	if diags.HasErrors() {
  5630  		t.Fatalf("diags: %s", diags.Err())
  5631  	}
  5632  
  5633  	// Test that things were destroyed
  5634  	actual := strings.TrimSpace(s.String())
  5635  	if actual != "<no state>" {
  5636  		t.Fatalf("expected no state, got: %s", actual)
  5637  	}
  5638  }
  5639  
  5640  func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) {
  5641  	m := testModule(t, "apply-destroy-deeply-nested-module")
  5642  	p := testProvider("aws")
  5643  	p.PlanResourceChangeFn = testDiffFn
  5644  
  5645  	state := states.NewState()
  5646  	root := state.EnsureModule(addrs.RootModuleInstance)
  5647  	root.SetResourceInstanceCurrent(
  5648  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  5649  		&states.ResourceInstanceObjectSrc{
  5650  			Status:    states.ObjectReady,
  5651  			AttrsJSON: []byte(`{"id":"bar"}`),
  5652  		},
  5653  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5654  	)
  5655  
  5656  	ctx := testContext2(t, &ContextOpts{
  5657  		Providers: map[addrs.Provider]providers.Factory{
  5658  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5659  		},
  5660  	})
  5661  
  5662  	// First plan and apply a create operation
  5663  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5664  	assertNoErrors(t, diags)
  5665  
  5666  	s, diags := ctx.Apply(plan, m)
  5667  	if diags.HasErrors() {
  5668  		t.Fatalf("diags: %s", diags.Err())
  5669  	}
  5670  
  5671  	// Test that things were destroyed
  5672  	if !s.Empty() {
  5673  		t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(s))
  5674  	}
  5675  }
  5676  
  5677  // https://github.com/hashicorp/terraform/issues/5440
  5678  func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) {
  5679  	m, snap := testModuleWithSnapshot(t, "apply-destroy-module-with-attrs")
  5680  	p := testProvider("aws")
  5681  	p.PlanResourceChangeFn = testDiffFn
  5682  
  5683  	var state *states.State
  5684  	{
  5685  		ctx := testContext2(t, &ContextOpts{
  5686  			Providers: map[addrs.Provider]providers.Factory{
  5687  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5688  			},
  5689  		})
  5690  
  5691  		// First plan and apply a create operation
  5692  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5693  		if diags.HasErrors() {
  5694  			t.Fatalf("plan diags: %s", diags.Err())
  5695  		} else {
  5696  			t.Logf("Step 1 plan: %s", legacyDiffComparisonString(plan.Changes))
  5697  		}
  5698  
  5699  		state, diags = ctx.Apply(plan, m)
  5700  		if diags.HasErrors() {
  5701  			t.Fatalf("apply errs: %s", diags.Err())
  5702  		}
  5703  
  5704  		t.Logf("Step 1 state: %s", state)
  5705  	}
  5706  
  5707  	h := new(HookRecordApplyOrder)
  5708  	h.Active = true
  5709  
  5710  	{
  5711  		ctx := testContext2(t, &ContextOpts{
  5712  			Hooks: []Hook{h},
  5713  			Providers: map[addrs.Provider]providers.Factory{
  5714  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5715  			},
  5716  		})
  5717  
  5718  		// First plan and apply a create operation
  5719  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5720  			Mode: plans.DestroyMode,
  5721  		})
  5722  		if diags.HasErrors() {
  5723  			t.Fatalf("destroy plan err: %s", diags.Err())
  5724  		}
  5725  
  5726  		t.Logf("Step 2 plan: %s", legacyDiffComparisonString(plan.Changes))
  5727  
  5728  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  5729  		if err != nil {
  5730  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5731  		}
  5732  
  5733  		ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  5734  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5735  		}
  5736  
  5737  		ctx, diags = NewContext(ctxOpts)
  5738  		if diags.HasErrors() {
  5739  			t.Fatalf("err: %s", diags.Err())
  5740  		}
  5741  
  5742  		state, diags = ctx.Apply(plan, m)
  5743  		if diags.HasErrors() {
  5744  			t.Fatalf("destroy apply err: %s", diags.Err())
  5745  		}
  5746  
  5747  		t.Logf("Step 2 state: %s", state)
  5748  	}
  5749  
  5750  	//Test that things were destroyed
  5751  	if state.HasManagedResourceInstanceObjects() {
  5752  		t.Fatal("expected empty state, got:", state)
  5753  	}
  5754  }
  5755  
  5756  func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) {
  5757  	m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count")
  5758  	p := testProvider("aws")
  5759  	p.PlanResourceChangeFn = testDiffFn
  5760  
  5761  	var state *states.State
  5762  	{
  5763  		ctx := testContext2(t, &ContextOpts{
  5764  			Providers: map[addrs.Provider]providers.Factory{
  5765  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5766  			},
  5767  		})
  5768  
  5769  		// First plan and apply a create operation
  5770  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5771  		assertNoErrors(t, diags)
  5772  
  5773  		state, diags = ctx.Apply(plan, m)
  5774  		if diags.HasErrors() {
  5775  			t.Fatalf("apply err: %s", diags.Err())
  5776  		}
  5777  	}
  5778  
  5779  	h := new(HookRecordApplyOrder)
  5780  	h.Active = true
  5781  
  5782  	{
  5783  		ctx := testContext2(t, &ContextOpts{
  5784  			Hooks: []Hook{h},
  5785  			Providers: map[addrs.Provider]providers.Factory{
  5786  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5787  			},
  5788  		})
  5789  
  5790  		// First plan and apply a create operation
  5791  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5792  			Mode: plans.DestroyMode,
  5793  		})
  5794  		if diags.HasErrors() {
  5795  			t.Fatalf("destroy plan err: %s", diags.Err())
  5796  		}
  5797  
  5798  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  5799  		if err != nil {
  5800  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5801  		}
  5802  
  5803  		ctxOpts.Providers =
  5804  			map[addrs.Provider]providers.Factory{
  5805  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5806  			}
  5807  
  5808  		ctx, diags = NewContext(ctxOpts)
  5809  		if diags.HasErrors() {
  5810  			t.Fatalf("err: %s", diags.Err())
  5811  		}
  5812  
  5813  		state, diags = ctx.Apply(plan, m)
  5814  		if diags.HasErrors() {
  5815  			t.Fatalf("destroy apply err: %s", diags.Err())
  5816  		}
  5817  	}
  5818  
  5819  	//Test that things were destroyed
  5820  	actual := strings.TrimSpace(state.String())
  5821  	expected := strings.TrimSpace(`
  5822  <no state>`)
  5823  	if actual != expected {
  5824  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  5825  	}
  5826  }
  5827  
  5828  func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) {
  5829  	m := testModule(t, "apply-destroy-mod-var-and-count")
  5830  	p := testProvider("aws")
  5831  	p.PlanResourceChangeFn = testDiffFn
  5832  
  5833  	var state *states.State
  5834  	{
  5835  		ctx := testContext2(t, &ContextOpts{
  5836  			Providers: map[addrs.Provider]providers.Factory{
  5837  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5838  			},
  5839  		})
  5840  
  5841  		// First plan and apply a create operation
  5842  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5843  		assertNoErrors(t, diags)
  5844  
  5845  		state, diags = ctx.Apply(plan, m)
  5846  		if diags.HasErrors() {
  5847  			t.Fatalf("apply err: %s", diags.Err())
  5848  		}
  5849  	}
  5850  
  5851  	{
  5852  		ctx := testContext2(t, &ContextOpts{
  5853  			Providers: map[addrs.Provider]providers.Factory{
  5854  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5855  			},
  5856  		})
  5857  
  5858  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5859  			Mode: plans.DestroyMode,
  5860  			Targets: []addrs.Targetable{
  5861  				addrs.RootModuleInstance.Child("child", addrs.NoKey),
  5862  			},
  5863  		})
  5864  		if diags.HasErrors() {
  5865  			t.Fatalf("plan err: %s", diags)
  5866  		}
  5867  		if len(diags) != 1 {
  5868  			// Should have one warning that -target is in effect.
  5869  			t.Fatalf("got %d diagnostics in plan; want 1", len(diags))
  5870  		}
  5871  		if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
  5872  			t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
  5873  		}
  5874  		if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want {
  5875  			t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
  5876  		}
  5877  
  5878  		// Destroy, targeting the module explicitly
  5879  		state, diags = ctx.Apply(plan, m)
  5880  		if diags.HasErrors() {
  5881  			t.Fatalf("destroy apply err: %s", diags)
  5882  		}
  5883  		if len(diags) != 1 {
  5884  			t.Fatalf("got %d diagnostics; want 1", len(diags))
  5885  		}
  5886  		if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
  5887  			t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
  5888  		}
  5889  		if got, want := diags[0].Description().Summary, "Applied changes may be incomplete"; got != want {
  5890  			t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
  5891  		}
  5892  	}
  5893  
  5894  	//Test that things were destroyed
  5895  	actual := strings.TrimSpace(state.String())
  5896  	expected := strings.TrimSpace(`<no state>`)
  5897  	if actual != expected {
  5898  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  5899  	}
  5900  }
  5901  
  5902  func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) {
  5903  	m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count-nested")
  5904  	p := testProvider("aws")
  5905  	p.PlanResourceChangeFn = testDiffFn
  5906  
  5907  	var state *states.State
  5908  	{
  5909  		ctx := testContext2(t, &ContextOpts{
  5910  			Providers: map[addrs.Provider]providers.Factory{
  5911  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5912  			},
  5913  		})
  5914  
  5915  		// First plan and apply a create operation
  5916  		plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  5917  		assertNoErrors(t, diags)
  5918  
  5919  		state, diags = ctx.Apply(plan, m)
  5920  		if diags.HasErrors() {
  5921  			t.Fatalf("apply err: %s", diags.Err())
  5922  		}
  5923  	}
  5924  
  5925  	h := new(HookRecordApplyOrder)
  5926  	h.Active = true
  5927  
  5928  	{
  5929  		ctx := testContext2(t, &ContextOpts{
  5930  			Hooks: []Hook{h},
  5931  			Providers: map[addrs.Provider]providers.Factory{
  5932  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5933  			},
  5934  		})
  5935  
  5936  		// First plan and apply a create operation
  5937  		plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
  5938  		if diags.HasErrors() {
  5939  			t.Fatalf("destroy plan err: %s", diags.Err())
  5940  		}
  5941  
  5942  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  5943  		if err != nil {
  5944  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5945  		}
  5946  
  5947  		ctxOpts.Providers =
  5948  			map[addrs.Provider]providers.Factory{
  5949  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5950  			}
  5951  
  5952  		ctx, diags = NewContext(ctxOpts)
  5953  		if diags.HasErrors() {
  5954  			t.Fatalf("err: %s", diags.Err())
  5955  		}
  5956  
  5957  		state, diags = ctx.Apply(plan, m)
  5958  		if diags.HasErrors() {
  5959  			t.Fatalf("destroy apply err: %s", diags.Err())
  5960  		}
  5961  	}
  5962  
  5963  	//Test that things were destroyed
  5964  	actual := strings.TrimSpace(state.String())
  5965  	expected := strings.TrimSpace(`
  5966  <no state>`)
  5967  	if actual != expected {
  5968  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  5969  	}
  5970  }
  5971  
  5972  func TestContext2Apply_destroyOutputs(t *testing.T) {
  5973  	m := testModule(t, "apply-destroy-outputs")
  5974  	p := testProvider("test")
  5975  	p.PlanResourceChangeFn = testDiffFn
  5976  
  5977  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  5978  		// add the required id
  5979  		m := req.Config.AsValueMap()
  5980  		m["id"] = cty.StringVal("foo")
  5981  
  5982  		return providers.ReadDataSourceResponse{
  5983  			State: cty.ObjectVal(m),
  5984  		}
  5985  	}
  5986  
  5987  	ctx := testContext2(t, &ContextOpts{
  5988  		Providers: map[addrs.Provider]providers.Factory{
  5989  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  5990  		},
  5991  	})
  5992  
  5993  	// First plan and apply a create operation
  5994  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5995  	assertNoErrors(t, diags)
  5996  
  5997  	state, diags := ctx.Apply(plan, m)
  5998  
  5999  	if diags.HasErrors() {
  6000  		t.Fatalf("diags: %s", diags.Err())
  6001  	}
  6002  
  6003  	// Next, plan and apply a destroy operation
  6004  	ctx = testContext2(t, &ContextOpts{
  6005  		Providers: map[addrs.Provider]providers.Factory{
  6006  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6007  		},
  6008  	})
  6009  
  6010  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  6011  		Mode: plans.DestroyMode,
  6012  	})
  6013  	assertNoErrors(t, diags)
  6014  
  6015  	state, diags = ctx.Apply(plan, m)
  6016  	if diags.HasErrors() {
  6017  		t.Fatalf("diags: %s", diags.Err())
  6018  	}
  6019  
  6020  	mod := state.RootModule()
  6021  	if len(mod.Resources) > 0 {
  6022  		t.Fatalf("expected no resources, got: %#v", mod)
  6023  	}
  6024  
  6025  	// destroying again should produce no errors
  6026  	ctx = testContext2(t, &ContextOpts{
  6027  		Providers: map[addrs.Provider]providers.Factory{
  6028  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6029  		},
  6030  	})
  6031  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  6032  		Mode: plans.DestroyMode,
  6033  	})
  6034  	assertNoErrors(t, diags)
  6035  
  6036  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6037  		t.Fatal(diags.Err())
  6038  	}
  6039  }
  6040  
  6041  func TestContext2Apply_destroyOrphan(t *testing.T) {
  6042  	m := testModule(t, "apply-error")
  6043  	p := testProvider("aws")
  6044  	state := states.NewState()
  6045  	root := state.EnsureModule(addrs.RootModuleInstance)
  6046  	root.SetResourceInstanceCurrent(
  6047  		mustResourceInstanceAddr("aws_instance.baz").Resource,
  6048  		&states.ResourceInstanceObjectSrc{
  6049  			Status:    states.ObjectReady,
  6050  			AttrsJSON: []byte(`{"id":"bar"}`),
  6051  		},
  6052  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6053  	)
  6054  	ctx := testContext2(t, &ContextOpts{
  6055  		Providers: map[addrs.Provider]providers.Factory{
  6056  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6057  		},
  6058  	})
  6059  
  6060  	p.PlanResourceChangeFn = testDiffFn
  6061  
  6062  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6063  	assertNoErrors(t, diags)
  6064  
  6065  	s, diags := ctx.Apply(plan, m)
  6066  	if diags.HasErrors() {
  6067  		t.Fatalf("diags: %s", diags.Err())
  6068  	}
  6069  
  6070  	mod := s.RootModule()
  6071  	if _, ok := mod.Resources["aws_instance.baz"]; ok {
  6072  		t.Fatalf("bad: %#v", mod.Resources)
  6073  	}
  6074  }
  6075  
  6076  func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) {
  6077  	m := testModule(t, "apply-destroy-provisioner")
  6078  	p := testProvider("aws")
  6079  	pr := testProvisioner()
  6080  	p.PlanResourceChangeFn = testDiffFn
  6081  
  6082  	state := states.NewState()
  6083  	root := state.EnsureModule(addrs.RootModuleInstance)
  6084  	root.SetResourceInstanceCurrent(
  6085  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6086  		&states.ResourceInstanceObjectSrc{
  6087  			Status:    states.ObjectReady,
  6088  			AttrsJSON: []byte(`{"id":"bar"}`),
  6089  		},
  6090  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6091  	)
  6092  
  6093  	ctx := testContext2(t, &ContextOpts{
  6094  		Providers: map[addrs.Provider]providers.Factory{
  6095  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6096  		},
  6097  		Provisioners: map[string]provisioners.Factory{
  6098  			"shell": testProvisionerFuncFixed(pr),
  6099  		},
  6100  	})
  6101  
  6102  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  6103  		Mode: plans.DestroyMode,
  6104  	})
  6105  	assertNoErrors(t, diags)
  6106  
  6107  	s, diags := ctx.Apply(plan, m)
  6108  	if diags.HasErrors() {
  6109  		t.Fatalf("diags: %s", diags.Err())
  6110  	}
  6111  
  6112  	if pr.ProvisionResourceCalled {
  6113  		t.Fatal("provisioner should not be called")
  6114  	}
  6115  
  6116  	actual := strings.TrimSpace(s.String())
  6117  	expected := strings.TrimSpace("<no state>")
  6118  	if actual != expected {
  6119  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6120  	}
  6121  }
  6122  
  6123  func TestContext2Apply_error(t *testing.T) {
  6124  	errored := false
  6125  
  6126  	m := testModule(t, "apply-error")
  6127  	p := testProvider("aws")
  6128  	ctx := testContext2(t, &ContextOpts{
  6129  		Providers: map[addrs.Provider]providers.Factory{
  6130  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6131  		},
  6132  	})
  6133  
  6134  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  6135  		if errored {
  6136  			resp.NewState = req.PlannedState
  6137  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  6138  			return
  6139  		}
  6140  		errored = true
  6141  
  6142  		return testApplyFn(req)
  6143  	}
  6144  	p.PlanResourceChangeFn = testDiffFn
  6145  
  6146  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6147  	assertNoErrors(t, diags)
  6148  
  6149  	state, diags := ctx.Apply(plan, m)
  6150  	if diags == nil {
  6151  		t.Fatal("should have error")
  6152  	}
  6153  
  6154  	actual := strings.TrimSpace(state.String())
  6155  	expected := strings.TrimSpace(testTerraformApplyErrorStr)
  6156  	if actual != expected {
  6157  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6158  	}
  6159  }
  6160  
  6161  func TestContext2Apply_errorDestroy(t *testing.T) {
  6162  	m := testModule(t, "empty")
  6163  	p := testProvider("test")
  6164  
  6165  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6166  		ResourceTypes: map[string]*configschema.Block{
  6167  			"test_thing": {
  6168  				Attributes: map[string]*configschema.Attribute{
  6169  					"id": {Type: cty.String, Optional: true},
  6170  				},
  6171  			},
  6172  		},
  6173  	})
  6174  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6175  		// Should actually be called for this test, because Terraform Core
  6176  		// constructs the plan for a destroy operation itself.
  6177  		return providers.PlanResourceChangeResponse{
  6178  			PlannedState: req.ProposedNewState,
  6179  		}
  6180  	}
  6181  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6182  		// The apply (in this case, a destroy) always fails, so we can verify
  6183  		// that the object stays in the state after a destroy fails even though
  6184  		// we aren't returning a new state object here.
  6185  		return providers.ApplyResourceChangeResponse{
  6186  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("failed")),
  6187  		}
  6188  	}
  6189  
  6190  	ctx := testContext2(t, &ContextOpts{
  6191  		Providers: map[addrs.Provider]providers.Factory{
  6192  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6193  		},
  6194  	})
  6195  
  6196  	state := states.BuildState(func(ss *states.SyncState) {
  6197  		ss.SetResourceInstanceCurrent(
  6198  			addrs.Resource{
  6199  				Mode: addrs.ManagedResourceMode,
  6200  				Type: "test_thing",
  6201  				Name: "foo",
  6202  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  6203  			&states.ResourceInstanceObjectSrc{
  6204  				Status:    states.ObjectReady,
  6205  				AttrsJSON: []byte(`{"id":"baz"}`),
  6206  			},
  6207  			addrs.AbsProviderConfig{
  6208  				Provider: addrs.NewDefaultProvider("test"),
  6209  				Module:   addrs.RootModule,
  6210  			},
  6211  		)
  6212  	})
  6213  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6214  	assertNoErrors(t, diags)
  6215  
  6216  	state, diags = ctx.Apply(plan, m)
  6217  	if !diags.HasErrors() {
  6218  		t.Fatal("should have error")
  6219  	}
  6220  
  6221  	actual := strings.TrimSpace(state.String())
  6222  	expected := strings.TrimSpace(`
  6223  test_thing.foo:
  6224    ID = baz
  6225    provider = provider["registry.terraform.io/hashicorp/test"]
  6226  `) // test_thing.foo is still here, even though provider returned no new state along with its error
  6227  	if actual != expected {
  6228  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6229  	}
  6230  }
  6231  
  6232  func TestContext2Apply_errorCreateInvalidNew(t *testing.T) {
  6233  	m := testModule(t, "apply-error")
  6234  
  6235  	p := testProvider("aws")
  6236  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6237  		ResourceTypes: map[string]*configschema.Block{
  6238  			"aws_instance": {
  6239  				Attributes: map[string]*configschema.Attribute{
  6240  					"value": {Type: cty.String, Optional: true},
  6241  					"foo":   {Type: cty.String, Optional: true},
  6242  				},
  6243  			},
  6244  		},
  6245  	})
  6246  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6247  		return providers.PlanResourceChangeResponse{
  6248  			PlannedState: req.ProposedNewState,
  6249  		}
  6250  	}
  6251  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6252  		// We're intentionally returning an inconsistent new state here
  6253  		// because we want to test that Terraform ignores the inconsistency
  6254  		// when accompanied by another error.
  6255  		return providers.ApplyResourceChangeResponse{
  6256  			NewState: cty.ObjectVal(map[string]cty.Value{
  6257  				"value": cty.StringVal("wrong wrong wrong wrong"),
  6258  				"foo":   cty.StringVal("absolutely brimming over with wrongability"),
  6259  			}),
  6260  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")),
  6261  		}
  6262  	}
  6263  
  6264  	ctx := testContext2(t, &ContextOpts{
  6265  		Providers: map[addrs.Provider]providers.Factory{
  6266  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6267  		},
  6268  	})
  6269  
  6270  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6271  	assertNoErrors(t, diags)
  6272  
  6273  	state, diags := ctx.Apply(plan, m)
  6274  	if diags == nil {
  6275  		t.Fatal("should have error")
  6276  	}
  6277  	if got, want := len(diags), 1; got != want {
  6278  		// There should be no additional diagnostics generated by Terraform's own eval logic,
  6279  		// because the provider's own error supersedes them.
  6280  		t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err())
  6281  	}
  6282  	if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) {
  6283  		t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err())
  6284  	}
  6285  	if got, want := len(state.RootModule().Resources), 2; got != want {
  6286  		t.Errorf("%d resources in state before prune; should have %d\n%s", got, want, spew.Sdump(state))
  6287  	}
  6288  	state.PruneResourceHusks() // aws_instance.bar with no instances gets left behind when we bail out, but that's okay
  6289  	if got, want := len(state.RootModule().Resources), 1; got != want {
  6290  		t.Errorf("%d resources in state after prune; should have only one (aws_instance.foo, tainted)\n%s", got, spew.Sdump(state))
  6291  	}
  6292  }
  6293  
  6294  func TestContext2Apply_errorUpdateNullNew(t *testing.T) {
  6295  	m := testModule(t, "apply-error")
  6296  
  6297  	p := testProvider("aws")
  6298  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6299  		ResourceTypes: map[string]*configschema.Block{
  6300  			"aws_instance": {
  6301  				Attributes: map[string]*configschema.Attribute{
  6302  					"value": {Type: cty.String, Optional: true},
  6303  					"foo":   {Type: cty.String, Optional: true},
  6304  				},
  6305  			},
  6306  		},
  6307  	})
  6308  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6309  		return providers.PlanResourceChangeResponse{
  6310  			PlannedState: req.ProposedNewState,
  6311  		}
  6312  	}
  6313  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6314  		// We're intentionally returning no NewState here because we want to
  6315  		// test that Terraform retains the prior state, rather than treating
  6316  		// the returned null as "no state" (object deleted).
  6317  		return providers.ApplyResourceChangeResponse{
  6318  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")),
  6319  		}
  6320  	}
  6321  
  6322  	ctx := testContext2(t, &ContextOpts{
  6323  		Providers: map[addrs.Provider]providers.Factory{
  6324  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6325  		},
  6326  	})
  6327  
  6328  	state := states.BuildState(func(ss *states.SyncState) {
  6329  		ss.SetResourceInstanceCurrent(
  6330  			addrs.Resource{
  6331  				Mode: addrs.ManagedResourceMode,
  6332  				Type: "aws_instance",
  6333  				Name: "foo",
  6334  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  6335  			&states.ResourceInstanceObjectSrc{
  6336  				Status:    states.ObjectReady,
  6337  				AttrsJSON: []byte(`{"value":"old"}`),
  6338  			},
  6339  			addrs.AbsProviderConfig{
  6340  				Provider: addrs.NewDefaultProvider("aws"),
  6341  				Module:   addrs.RootModule,
  6342  			},
  6343  		)
  6344  	})
  6345  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6346  	assertNoErrors(t, diags)
  6347  
  6348  	state, diags = ctx.Apply(plan, m)
  6349  	if !diags.HasErrors() {
  6350  		t.Fatal("should have error")
  6351  	}
  6352  	if got, want := len(diags), 1; got != want {
  6353  		// There should be no additional diagnostics generated by Terraform's own eval logic,
  6354  		// because the provider's own error supersedes them.
  6355  		t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err())
  6356  	}
  6357  	if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) {
  6358  		t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err())
  6359  	}
  6360  	state.PruneResourceHusks()
  6361  	if got, want := len(state.RootModule().Resources), 1; got != want {
  6362  		t.Fatalf("%d resources in state; should have only one (aws_instance.foo, unmodified)\n%s", got, spew.Sdump(state))
  6363  	}
  6364  
  6365  	is := state.ResourceInstance(addrs.Resource{
  6366  		Mode: addrs.ManagedResourceMode,
  6367  		Type: "aws_instance",
  6368  		Name: "foo",
  6369  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
  6370  	if is == nil {
  6371  		t.Fatalf("aws_instance.foo is not in the state after apply")
  6372  	}
  6373  	if got, want := is.Current.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) {
  6374  		t.Fatalf("incorrect attributes for aws_instance.foo\ngot: %s\nwant: JSON containing %s\n\n%s", got, want, spew.Sdump(is))
  6375  	}
  6376  }
  6377  
  6378  func TestContext2Apply_errorPartial(t *testing.T) {
  6379  	errored := false
  6380  
  6381  	m := testModule(t, "apply-error")
  6382  	p := testProvider("aws")
  6383  
  6384  	state := states.NewState()
  6385  	root := state.EnsureModule(addrs.RootModuleInstance)
  6386  	root.SetResourceInstanceCurrent(
  6387  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6388  		&states.ResourceInstanceObjectSrc{
  6389  			Status:    states.ObjectReady,
  6390  			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
  6391  		},
  6392  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6393  	)
  6394  
  6395  	ctx := testContext2(t, &ContextOpts{
  6396  		Providers: map[addrs.Provider]providers.Factory{
  6397  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6398  		},
  6399  	})
  6400  
  6401  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  6402  		if errored {
  6403  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  6404  			return
  6405  		}
  6406  		errored = true
  6407  
  6408  		return testApplyFn(req)
  6409  	}
  6410  	p.PlanResourceChangeFn = testDiffFn
  6411  
  6412  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6413  	assertNoErrors(t, diags)
  6414  
  6415  	s, diags := ctx.Apply(plan, m)
  6416  	if diags == nil {
  6417  		t.Fatal("should have error")
  6418  	}
  6419  
  6420  	mod := s.RootModule()
  6421  	if len(mod.Resources) != 2 {
  6422  		t.Fatalf("bad: %#v", mod.Resources)
  6423  	}
  6424  
  6425  	actual := strings.TrimSpace(s.String())
  6426  	expected := strings.TrimSpace(testTerraformApplyErrorPartialStr)
  6427  	if actual != expected {
  6428  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6429  	}
  6430  }
  6431  
  6432  func TestContext2Apply_hook(t *testing.T) {
  6433  	m := testModule(t, "apply-good")
  6434  	h := new(MockHook)
  6435  	p := testProvider("aws")
  6436  	p.PlanResourceChangeFn = testDiffFn
  6437  	ctx := testContext2(t, &ContextOpts{
  6438  		Hooks: []Hook{h},
  6439  		Providers: map[addrs.Provider]providers.Factory{
  6440  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6441  		},
  6442  	})
  6443  
  6444  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6445  	assertNoErrors(t, diags)
  6446  
  6447  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6448  		t.Fatalf("apply errors: %s", diags.Err())
  6449  	}
  6450  
  6451  	if !h.PreApplyCalled {
  6452  		t.Fatal("should be called")
  6453  	}
  6454  	if !h.PostApplyCalled {
  6455  		t.Fatal("should be called")
  6456  	}
  6457  	if !h.PostStateUpdateCalled {
  6458  		t.Fatalf("should call post state update")
  6459  	}
  6460  }
  6461  
  6462  func TestContext2Apply_hookOrphan(t *testing.T) {
  6463  	m := testModule(t, "apply-blank")
  6464  	h := new(MockHook)
  6465  	p := testProvider("aws")
  6466  	p.PlanResourceChangeFn = testDiffFn
  6467  
  6468  	state := states.NewState()
  6469  	root := state.EnsureModule(addrs.RootModuleInstance)
  6470  	root.SetResourceInstanceCurrent(
  6471  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6472  		&states.ResourceInstanceObjectSrc{
  6473  			Status:    states.ObjectReady,
  6474  			AttrsJSON: []byte(`{"id":"bar"}`),
  6475  		},
  6476  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6477  	)
  6478  
  6479  	ctx := testContext2(t, &ContextOpts{
  6480  		Hooks: []Hook{h},
  6481  		Providers: map[addrs.Provider]providers.Factory{
  6482  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6483  		},
  6484  	})
  6485  
  6486  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6487  	assertNoErrors(t, diags)
  6488  
  6489  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6490  		t.Fatalf("apply errors: %s", diags.Err())
  6491  	}
  6492  
  6493  	if !h.PreApplyCalled {
  6494  		t.Fatal("should be called")
  6495  	}
  6496  	if !h.PostApplyCalled {
  6497  		t.Fatal("should be called")
  6498  	}
  6499  	if !h.PostStateUpdateCalled {
  6500  		t.Fatalf("should call post state update")
  6501  	}
  6502  }
  6503  
  6504  func TestContext2Apply_idAttr(t *testing.T) {
  6505  	m := testModule(t, "apply-idattr")
  6506  	p := testProvider("aws")
  6507  	ctx := testContext2(t, &ContextOpts{
  6508  		Providers: map[addrs.Provider]providers.Factory{
  6509  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6510  		},
  6511  	})
  6512  
  6513  	p.PlanResourceChangeFn = testDiffFn
  6514  	p.ApplyResourceChangeFn = testApplyFn
  6515  
  6516  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6517  	assertNoErrors(t, diags)
  6518  
  6519  	state, diags := ctx.Apply(plan, m)
  6520  	if diags.HasErrors() {
  6521  		t.Fatalf("apply errors: %s", diags.Err())
  6522  	}
  6523  
  6524  	mod := state.RootModule()
  6525  	rs, ok := mod.Resources["aws_instance.foo"]
  6526  	if !ok {
  6527  		t.Fatal("not in state")
  6528  	}
  6529  	var attrs map[string]interface{}
  6530  	err := json.Unmarshal(rs.Instances[addrs.NoKey].Current.AttrsJSON, &attrs)
  6531  	if err != nil {
  6532  		t.Fatal(err)
  6533  	}
  6534  	if got, want := attrs["id"], "foo"; got != want {
  6535  		t.Fatalf("wrong id\ngot:  %#v\nwant: %#v", got, want)
  6536  	}
  6537  }
  6538  
  6539  func TestContext2Apply_outputBasic(t *testing.T) {
  6540  	m := testModule(t, "apply-output")
  6541  	p := testProvider("aws")
  6542  	p.PlanResourceChangeFn = testDiffFn
  6543  	p.ApplyResourceChangeFn = testApplyFn
  6544  	ctx := testContext2(t, &ContextOpts{
  6545  		Providers: map[addrs.Provider]providers.Factory{
  6546  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6547  		},
  6548  	})
  6549  
  6550  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6551  	assertNoErrors(t, diags)
  6552  
  6553  	state, diags := ctx.Apply(plan, m)
  6554  	if diags.HasErrors() {
  6555  		t.Fatalf("diags: %s", diags.Err())
  6556  	}
  6557  
  6558  	actual := strings.TrimSpace(state.String())
  6559  	expected := strings.TrimSpace(testTerraformApplyOutputStr)
  6560  	if actual != expected {
  6561  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6562  	}
  6563  }
  6564  
  6565  func TestContext2Apply_outputAdd(t *testing.T) {
  6566  	m1 := testModule(t, "apply-output-add-before")
  6567  	p1 := testProvider("aws")
  6568  	p1.ApplyResourceChangeFn = testApplyFn
  6569  	p1.PlanResourceChangeFn = testDiffFn
  6570  	ctx1 := testContext2(t, &ContextOpts{
  6571  		Providers: map[addrs.Provider]providers.Factory{
  6572  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p1),
  6573  		},
  6574  	})
  6575  
  6576  	plan1, diags := ctx1.Plan(m1, states.NewState(), DefaultPlanOpts)
  6577  	assertNoErrors(t, diags)
  6578  
  6579  	state1, diags := ctx1.Apply(plan1, m1)
  6580  	if diags.HasErrors() {
  6581  		t.Fatalf("diags: %s", diags.Err())
  6582  	}
  6583  
  6584  	m2 := testModule(t, "apply-output-add-after")
  6585  	p2 := testProvider("aws")
  6586  	p2.ApplyResourceChangeFn = testApplyFn
  6587  	p2.PlanResourceChangeFn = testDiffFn
  6588  	ctx2 := testContext2(t, &ContextOpts{
  6589  		Providers: map[addrs.Provider]providers.Factory{
  6590  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p2),
  6591  		},
  6592  	})
  6593  
  6594  	plan2, diags := ctx1.Plan(m2, state1, DefaultPlanOpts)
  6595  	assertNoErrors(t, diags)
  6596  
  6597  	state2, diags := ctx2.Apply(plan2, m2)
  6598  	if diags.HasErrors() {
  6599  		t.Fatalf("diags: %s", diags.Err())
  6600  	}
  6601  
  6602  	actual := strings.TrimSpace(state2.String())
  6603  	expected := strings.TrimSpace(testTerraformApplyOutputAddStr)
  6604  	if actual != expected {
  6605  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6606  	}
  6607  }
  6608  
  6609  func TestContext2Apply_outputList(t *testing.T) {
  6610  	m := testModule(t, "apply-output-list")
  6611  	p := testProvider("aws")
  6612  	p.PlanResourceChangeFn = testDiffFn
  6613  	p.ApplyResourceChangeFn = testApplyFn
  6614  	ctx := testContext2(t, &ContextOpts{
  6615  		Providers: map[addrs.Provider]providers.Factory{
  6616  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6617  		},
  6618  	})
  6619  
  6620  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6621  	assertNoErrors(t, diags)
  6622  
  6623  	state, diags := ctx.Apply(plan, m)
  6624  	if diags.HasErrors() {
  6625  		t.Fatalf("diags: %s", diags.Err())
  6626  	}
  6627  
  6628  	actual := strings.TrimSpace(state.String())
  6629  	expected := strings.TrimSpace(testTerraformApplyOutputListStr)
  6630  	if actual != expected {
  6631  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  6632  	}
  6633  }
  6634  
  6635  func TestContext2Apply_outputMulti(t *testing.T) {
  6636  	m := testModule(t, "apply-output-multi")
  6637  	p := testProvider("aws")
  6638  	p.PlanResourceChangeFn = testDiffFn
  6639  	p.ApplyResourceChangeFn = testApplyFn
  6640  	ctx := testContext2(t, &ContextOpts{
  6641  		Providers: map[addrs.Provider]providers.Factory{
  6642  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6643  		},
  6644  	})
  6645  
  6646  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6647  	assertNoErrors(t, diags)
  6648  
  6649  	state, diags := ctx.Apply(plan, m)
  6650  	if diags.HasErrors() {
  6651  		t.Fatalf("diags: %s", diags.Err())
  6652  	}
  6653  
  6654  	actual := strings.TrimSpace(state.String())
  6655  	expected := strings.TrimSpace(testTerraformApplyOutputMultiStr)
  6656  	if actual != expected {
  6657  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6658  	}
  6659  }
  6660  
  6661  func TestContext2Apply_outputMultiIndex(t *testing.T) {
  6662  	m := testModule(t, "apply-output-multi-index")
  6663  	p := testProvider("aws")
  6664  	p.PlanResourceChangeFn = testDiffFn
  6665  	p.ApplyResourceChangeFn = testApplyFn
  6666  	ctx := testContext2(t, &ContextOpts{
  6667  		Providers: map[addrs.Provider]providers.Factory{
  6668  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6669  		},
  6670  	})
  6671  
  6672  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6673  	assertNoErrors(t, diags)
  6674  
  6675  	state, diags := ctx.Apply(plan, m)
  6676  	if diags.HasErrors() {
  6677  		t.Fatalf("diags: %s", diags.Err())
  6678  	}
  6679  
  6680  	actual := strings.TrimSpace(state.String())
  6681  	expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr)
  6682  	if actual != expected {
  6683  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6684  	}
  6685  }
  6686  
  6687  func TestContext2Apply_taintX(t *testing.T) {
  6688  	m := testModule(t, "apply-taint")
  6689  	p := testProvider("aws")
  6690  	// destroyCount tests against regression of
  6691  	// https://github.com/hashicorp/terraform/issues/1056
  6692  	var destroyCount = int32(0)
  6693  	var once sync.Once
  6694  	simulateProviderDelay := func() {
  6695  		time.Sleep(10 * time.Millisecond)
  6696  	}
  6697  
  6698  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6699  		once.Do(simulateProviderDelay)
  6700  		if req.PlannedState.IsNull() {
  6701  			atomic.AddInt32(&destroyCount, 1)
  6702  		}
  6703  		return testApplyFn(req)
  6704  	}
  6705  	p.PlanResourceChangeFn = testDiffFn
  6706  
  6707  	state := states.NewState()
  6708  	root := state.EnsureModule(addrs.RootModuleInstance)
  6709  	root.SetResourceInstanceCurrent(
  6710  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6711  		&states.ResourceInstanceObjectSrc{
  6712  			Status:    states.ObjectTainted,
  6713  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6714  		},
  6715  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6716  	)
  6717  
  6718  	ctx := testContext2(t, &ContextOpts{
  6719  		Providers: map[addrs.Provider]providers.Factory{
  6720  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6721  		},
  6722  	})
  6723  
  6724  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6725  	if diags.HasErrors() {
  6726  		t.Fatalf("diags: %s", diags.Err())
  6727  	} else {
  6728  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6729  	}
  6730  
  6731  	s, diags := ctx.Apply(plan, m)
  6732  	if diags.HasErrors() {
  6733  		t.Fatalf("diags: %s", diags.Err())
  6734  	}
  6735  
  6736  	actual := strings.TrimSpace(s.String())
  6737  	expected := strings.TrimSpace(testTerraformApplyTaintStr)
  6738  	if actual != expected {
  6739  		t.Fatalf("bad:\n%s", actual)
  6740  	}
  6741  
  6742  	if destroyCount != 1 {
  6743  		t.Fatalf("Expected 1 destroy, got %d", destroyCount)
  6744  	}
  6745  }
  6746  
  6747  func TestContext2Apply_taintDep(t *testing.T) {
  6748  	m := testModule(t, "apply-taint-dep")
  6749  	p := testProvider("aws")
  6750  	p.PlanResourceChangeFn = testDiffFn
  6751  	p.ApplyResourceChangeFn = testApplyFn
  6752  
  6753  	state := states.NewState()
  6754  	root := state.EnsureModule(addrs.RootModuleInstance)
  6755  	root.SetResourceInstanceCurrent(
  6756  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6757  		&states.ResourceInstanceObjectSrc{
  6758  			Status:    states.ObjectTainted,
  6759  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6760  		},
  6761  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6762  	)
  6763  	root.SetResourceInstanceCurrent(
  6764  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6765  		&states.ResourceInstanceObjectSrc{
  6766  			Status:       states.ObjectReady,
  6767  			AttrsJSON:    []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`),
  6768  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  6769  		},
  6770  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6771  	)
  6772  
  6773  	ctx := testContext2(t, &ContextOpts{
  6774  		Providers: map[addrs.Provider]providers.Factory{
  6775  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6776  		},
  6777  	})
  6778  
  6779  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6780  	if diags.HasErrors() {
  6781  		t.Fatalf("diags: %s", diags.Err())
  6782  	} else {
  6783  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6784  	}
  6785  
  6786  	s, diags := ctx.Apply(plan, m)
  6787  	if diags.HasErrors() {
  6788  		t.Fatalf("diags: %s", diags.Err())
  6789  	}
  6790  
  6791  	actual := strings.TrimSpace(s.String())
  6792  	expected := strings.TrimSpace(testTerraformApplyTaintDepStr)
  6793  	if actual != expected {
  6794  		t.Fatalf("bad:\n%s", actual)
  6795  	}
  6796  }
  6797  
  6798  func TestContext2Apply_taintDepRequiresNew(t *testing.T) {
  6799  	m := testModule(t, "apply-taint-dep-requires-new")
  6800  	p := testProvider("aws")
  6801  	p.PlanResourceChangeFn = testDiffFn
  6802  	p.ApplyResourceChangeFn = testApplyFn
  6803  
  6804  	state := states.NewState()
  6805  	root := state.EnsureModule(addrs.RootModuleInstance)
  6806  	root.SetResourceInstanceCurrent(
  6807  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6808  		&states.ResourceInstanceObjectSrc{
  6809  			Status:    states.ObjectTainted,
  6810  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6811  		},
  6812  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6813  	)
  6814  	root.SetResourceInstanceCurrent(
  6815  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6816  		&states.ResourceInstanceObjectSrc{
  6817  			Status:       states.ObjectReady,
  6818  			AttrsJSON:    []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`),
  6819  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  6820  		},
  6821  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6822  	)
  6823  
  6824  	ctx := testContext2(t, &ContextOpts{
  6825  		Providers: map[addrs.Provider]providers.Factory{
  6826  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6827  		},
  6828  	})
  6829  
  6830  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6831  	if diags.HasErrors() {
  6832  		t.Fatalf("diags: %s", diags.Err())
  6833  	} else {
  6834  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6835  	}
  6836  
  6837  	s, diags := ctx.Apply(plan, m)
  6838  	if diags.HasErrors() {
  6839  		t.Fatalf("diags: %s", diags.Err())
  6840  	}
  6841  
  6842  	actual := strings.TrimSpace(s.String())
  6843  	expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr)
  6844  	if actual != expected {
  6845  		t.Fatalf("bad:\n%s", actual)
  6846  	}
  6847  }
  6848  
  6849  func TestContext2Apply_targeted(t *testing.T) {
  6850  	m := testModule(t, "apply-targeted")
  6851  	p := testProvider("aws")
  6852  	p.PlanResourceChangeFn = testDiffFn
  6853  	p.ApplyResourceChangeFn = testApplyFn
  6854  	ctx := testContext2(t, &ContextOpts{
  6855  		Providers: map[addrs.Provider]providers.Factory{
  6856  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6857  		},
  6858  	})
  6859  
  6860  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  6861  		Mode: plans.NormalMode,
  6862  		Targets: []addrs.Targetable{
  6863  			addrs.RootModuleInstance.Resource(
  6864  				addrs.ManagedResourceMode, "aws_instance", "foo",
  6865  			),
  6866  		},
  6867  	})
  6868  	assertNoErrors(t, diags)
  6869  
  6870  	state, diags := ctx.Apply(plan, m)
  6871  	if diags.HasErrors() {
  6872  		t.Fatalf("diags: %s", diags.Err())
  6873  	}
  6874  
  6875  	mod := state.RootModule()
  6876  	if len(mod.Resources) != 1 {
  6877  		t.Fatalf("expected 1 resource, got: %#v", mod.Resources)
  6878  	}
  6879  
  6880  	checkStateString(t, state, `
  6881  aws_instance.foo:
  6882    ID = foo
  6883    provider = provider["registry.terraform.io/hashicorp/aws"]
  6884    num = 2
  6885    type = aws_instance
  6886  	`)
  6887  }
  6888  
  6889  func TestContext2Apply_targetedCount(t *testing.T) {
  6890  	m := testModule(t, "apply-targeted-count")
  6891  	p := testProvider("aws")
  6892  	p.PlanResourceChangeFn = testDiffFn
  6893  	p.ApplyResourceChangeFn = testApplyFn
  6894  	ctx := testContext2(t, &ContextOpts{
  6895  		Providers: map[addrs.Provider]providers.Factory{
  6896  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6897  		},
  6898  	})
  6899  
  6900  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  6901  		Mode: plans.NormalMode,
  6902  		Targets: []addrs.Targetable{
  6903  			addrs.RootModuleInstance.Resource(
  6904  				addrs.ManagedResourceMode, "aws_instance", "foo",
  6905  			),
  6906  		},
  6907  	})
  6908  	assertNoErrors(t, diags)
  6909  
  6910  	state, diags := ctx.Apply(plan, m)
  6911  	if diags.HasErrors() {
  6912  		t.Fatalf("diags: %s", diags.Err())
  6913  	}
  6914  
  6915  	checkStateString(t, state, `
  6916  aws_instance.foo.0:
  6917    ID = foo
  6918    provider = provider["registry.terraform.io/hashicorp/aws"]
  6919    type = aws_instance
  6920  aws_instance.foo.1:
  6921    ID = foo
  6922    provider = provider["registry.terraform.io/hashicorp/aws"]
  6923    type = aws_instance
  6924  aws_instance.foo.2:
  6925    ID = foo
  6926    provider = provider["registry.terraform.io/hashicorp/aws"]
  6927    type = aws_instance
  6928  	`)
  6929  }
  6930  
  6931  func TestContext2Apply_targetedCountIndex(t *testing.T) {
  6932  	m := testModule(t, "apply-targeted-count")
  6933  	p := testProvider("aws")
  6934  	p.PlanResourceChangeFn = testDiffFn
  6935  	p.ApplyResourceChangeFn = testApplyFn
  6936  	ctx := testContext2(t, &ContextOpts{
  6937  		Providers: map[addrs.Provider]providers.Factory{
  6938  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6939  		},
  6940  	})
  6941  
  6942  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  6943  		Mode: plans.NormalMode,
  6944  		Targets: []addrs.Targetable{
  6945  			addrs.RootModuleInstance.ResourceInstance(
  6946  				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(1),
  6947  			),
  6948  		},
  6949  	})
  6950  	assertNoErrors(t, diags)
  6951  
  6952  	state, diags := ctx.Apply(plan, m)
  6953  	if diags.HasErrors() {
  6954  		t.Fatalf("diags: %s", diags.Err())
  6955  	}
  6956  
  6957  	checkStateString(t, state, `
  6958  aws_instance.foo.1:
  6959    ID = foo
  6960    provider = provider["registry.terraform.io/hashicorp/aws"]
  6961    type = aws_instance
  6962  	`)
  6963  }
  6964  
  6965  func TestContext2Apply_targetedDestroy(t *testing.T) {
  6966  	m := testModule(t, "destroy-targeted")
  6967  	p := testProvider("aws")
  6968  	p.PlanResourceChangeFn = testDiffFn
  6969  
  6970  	state := states.NewState()
  6971  	root := state.EnsureModule(addrs.RootModuleInstance)
  6972  	root.SetResourceInstanceCurrent(
  6973  		mustResourceInstanceAddr("aws_instance.a").Resource,
  6974  		&states.ResourceInstanceObjectSrc{
  6975  			Status:    states.ObjectReady,
  6976  			AttrsJSON: []byte(`{"id":"bar"}`),
  6977  		},
  6978  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6979  	)
  6980  	root.SetOutputValue("out", cty.StringVal("bar"), false)
  6981  
  6982  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  6983  	child.SetResourceInstanceCurrent(
  6984  		mustResourceInstanceAddr("aws_instance.b").Resource,
  6985  		&states.ResourceInstanceObjectSrc{
  6986  			Status:    states.ObjectReady,
  6987  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  6988  		},
  6989  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6990  	)
  6991  
  6992  	ctx := testContext2(t, &ContextOpts{
  6993  		Providers: map[addrs.Provider]providers.Factory{
  6994  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6995  		},
  6996  	})
  6997  
  6998  	if diags := ctx.Validate(m); diags.HasErrors() {
  6999  		t.Fatalf("validate errors: %s", diags.Err())
  7000  	}
  7001  
  7002  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7003  		Mode: plans.DestroyMode,
  7004  		Targets: []addrs.Targetable{
  7005  			addrs.RootModuleInstance.Resource(
  7006  				addrs.ManagedResourceMode, "aws_instance", "a",
  7007  			),
  7008  		},
  7009  	})
  7010  	assertNoErrors(t, diags)
  7011  
  7012  	state, diags = ctx.Apply(plan, m)
  7013  	if diags.HasErrors() {
  7014  		t.Fatalf("diags: %s", diags.Err())
  7015  	}
  7016  
  7017  	mod := state.RootModule()
  7018  	if len(mod.Resources) != 0 {
  7019  		t.Fatalf("expected 0 resources, got: %#v", mod.Resources)
  7020  	}
  7021  
  7022  	// the root output should not get removed; only the targeted resource.
  7023  	//
  7024  	// Note: earlier versions of this test expected 0 outputs, but it turns out
  7025  	// that was because Validate - not apply or destroy - removed the output
  7026  	// (which depends on the targeted resource) from state. That version of this
  7027  	// test did not match actual terraform behavior: the output remains in
  7028  	// state.
  7029  	//
  7030  	// The reason it remains in the state is that we prune out the root module
  7031  	// output values from the destroy graph as part of pruning out the "update"
  7032  	// nodes for the resources, because otherwise the root module output values
  7033  	// force the resources to stay in the graph and can therefore cause
  7034  	// unwanted dependency cycles.
  7035  	//
  7036  	// TODO: Future refactoring may enable us to remove the output from state in
  7037  	// this case, and that would be Just Fine - this test can be modified to
  7038  	// expect 0 outputs.
  7039  	if len(mod.OutputValues) != 1 {
  7040  		t.Fatalf("expected 1 outputs, got: %#v", mod.OutputValues)
  7041  	}
  7042  
  7043  	// the module instance should remain
  7044  	mod = state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7045  	if len(mod.Resources) != 1 {
  7046  		t.Fatalf("expected 1 resources, got: %#v", mod.Resources)
  7047  	}
  7048  }
  7049  
  7050  func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) {
  7051  	m := testModule(t, "apply-destroy-targeted-count")
  7052  	p := testProvider("aws")
  7053  	p.PlanResourceChangeFn = testDiffFn
  7054  
  7055  	state := states.NewState()
  7056  	root := state.EnsureModule(addrs.RootModuleInstance)
  7057  	root.SetResourceInstanceCurrent(
  7058  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7059  		&states.ResourceInstanceObjectSrc{
  7060  			Status:    states.ObjectReady,
  7061  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7062  		},
  7063  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7064  	)
  7065  	root.SetResourceInstanceCurrent(
  7066  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7067  		&states.ResourceInstanceObjectSrc{
  7068  			Status:       states.ObjectReady,
  7069  			AttrsJSON:    []byte(`{"id":"i-abc123"}`),
  7070  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  7071  		},
  7072  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7073  	)
  7074  
  7075  	ctx := testContext2(t, &ContextOpts{
  7076  		Providers: map[addrs.Provider]providers.Factory{
  7077  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7078  		},
  7079  	})
  7080  
  7081  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7082  		Mode: plans.DestroyMode,
  7083  		Targets: []addrs.Targetable{
  7084  			addrs.RootModuleInstance.Resource(
  7085  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7086  			),
  7087  		},
  7088  	})
  7089  	assertNoErrors(t, diags)
  7090  
  7091  	state, diags = ctx.Apply(plan, m)
  7092  	if diags.HasErrors() {
  7093  		t.Fatalf("diags: %s", diags.Err())
  7094  	}
  7095  
  7096  	checkStateString(t, state, `<no state>`)
  7097  }
  7098  
  7099  // https://github.com/hashicorp/terraform/issues/4462
  7100  func TestContext2Apply_targetedDestroyModule(t *testing.T) {
  7101  	m := testModule(t, "apply-targeted-module")
  7102  	p := testProvider("aws")
  7103  	p.PlanResourceChangeFn = testDiffFn
  7104  
  7105  	state := states.NewState()
  7106  	root := state.EnsureModule(addrs.RootModuleInstance)
  7107  	root.SetResourceInstanceCurrent(
  7108  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7109  		&states.ResourceInstanceObjectSrc{
  7110  			Status:    states.ObjectReady,
  7111  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7112  		},
  7113  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7114  	)
  7115  	root.SetResourceInstanceCurrent(
  7116  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7117  		&states.ResourceInstanceObjectSrc{
  7118  			Status:    states.ObjectReady,
  7119  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7120  		},
  7121  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7122  	)
  7123  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7124  	child.SetResourceInstanceCurrent(
  7125  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7126  		&states.ResourceInstanceObjectSrc{
  7127  			Status:    states.ObjectReady,
  7128  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7129  		},
  7130  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7131  	)
  7132  	child.SetResourceInstanceCurrent(
  7133  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7134  		&states.ResourceInstanceObjectSrc{
  7135  			Status:    states.ObjectReady,
  7136  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7137  		},
  7138  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7139  	)
  7140  
  7141  	ctx := testContext2(t, &ContextOpts{
  7142  		Providers: map[addrs.Provider]providers.Factory{
  7143  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7144  		},
  7145  	})
  7146  
  7147  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7148  		Mode: plans.DestroyMode,
  7149  		Targets: []addrs.Targetable{
  7150  			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
  7151  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7152  			),
  7153  		},
  7154  	})
  7155  	assertNoErrors(t, diags)
  7156  
  7157  	state, diags = ctx.Apply(plan, m)
  7158  	if diags.HasErrors() {
  7159  		t.Fatalf("diags: %s", diags.Err())
  7160  	}
  7161  
  7162  	checkStateString(t, state, `
  7163  aws_instance.bar:
  7164    ID = i-abc123
  7165    provider = provider["registry.terraform.io/hashicorp/aws"]
  7166  aws_instance.foo:
  7167    ID = i-bcd345
  7168    provider = provider["registry.terraform.io/hashicorp/aws"]
  7169  
  7170  module.child:
  7171    aws_instance.bar:
  7172      ID = i-abc123
  7173      provider = provider["registry.terraform.io/hashicorp/aws"]
  7174  	`)
  7175  }
  7176  
  7177  func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) {
  7178  	m := testModule(t, "apply-targeted-count")
  7179  	p := testProvider("aws")
  7180  	p.PlanResourceChangeFn = testDiffFn
  7181  
  7182  	foo := &states.ResourceInstanceObjectSrc{
  7183  		Status:    states.ObjectReady,
  7184  		AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7185  	}
  7186  	bar := &states.ResourceInstanceObjectSrc{
  7187  		Status:    states.ObjectReady,
  7188  		AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7189  	}
  7190  
  7191  	state := states.NewState()
  7192  	root := state.EnsureModule(addrs.RootModuleInstance)
  7193  	root.SetResourceInstanceCurrent(
  7194  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  7195  		foo,
  7196  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7197  	)
  7198  	root.SetResourceInstanceCurrent(
  7199  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  7200  		foo,
  7201  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7202  	)
  7203  	root.SetResourceInstanceCurrent(
  7204  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  7205  		foo,
  7206  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7207  	)
  7208  	root.SetResourceInstanceCurrent(
  7209  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  7210  		bar,
  7211  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7212  	)
  7213  	root.SetResourceInstanceCurrent(
  7214  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  7215  		bar,
  7216  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7217  	)
  7218  	root.SetResourceInstanceCurrent(
  7219  		mustResourceInstanceAddr("aws_instance.bar[2]").Resource,
  7220  		bar,
  7221  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7222  	)
  7223  
  7224  	ctx := testContext2(t, &ContextOpts{
  7225  		Providers: map[addrs.Provider]providers.Factory{
  7226  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7227  		},
  7228  	})
  7229  
  7230  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7231  		Mode: plans.DestroyMode,
  7232  		Targets: []addrs.Targetable{
  7233  			addrs.RootModuleInstance.ResourceInstance(
  7234  				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(2),
  7235  			),
  7236  			addrs.RootModuleInstance.ResourceInstance(
  7237  				addrs.ManagedResourceMode, "aws_instance", "bar", addrs.IntKey(1),
  7238  			),
  7239  		},
  7240  	})
  7241  	assertNoErrors(t, diags)
  7242  
  7243  	state, diags = ctx.Apply(plan, m)
  7244  	if diags.HasErrors() {
  7245  		t.Fatalf("diags: %s", diags.Err())
  7246  	}
  7247  
  7248  	checkStateString(t, state, `
  7249  aws_instance.bar.0:
  7250    ID = i-abc123
  7251    provider = provider["registry.terraform.io/hashicorp/aws"]
  7252  aws_instance.bar.2:
  7253    ID = i-abc123
  7254    provider = provider["registry.terraform.io/hashicorp/aws"]
  7255  aws_instance.foo.0:
  7256    ID = i-bcd345
  7257    provider = provider["registry.terraform.io/hashicorp/aws"]
  7258  aws_instance.foo.1:
  7259    ID = i-bcd345
  7260    provider = provider["registry.terraform.io/hashicorp/aws"]
  7261  	`)
  7262  }
  7263  
  7264  func TestContext2Apply_targetedModule(t *testing.T) {
  7265  	m := testModule(t, "apply-targeted-module")
  7266  	p := testProvider("aws")
  7267  	p.PlanResourceChangeFn = testDiffFn
  7268  	p.ApplyResourceChangeFn = testApplyFn
  7269  	ctx := testContext2(t, &ContextOpts{
  7270  		Providers: map[addrs.Provider]providers.Factory{
  7271  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7272  		},
  7273  	})
  7274  
  7275  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7276  		Mode: plans.NormalMode,
  7277  		Targets: []addrs.Targetable{
  7278  			addrs.RootModuleInstance.Child("child", addrs.NoKey),
  7279  		},
  7280  	})
  7281  	assertNoErrors(t, diags)
  7282  
  7283  	state, diags := ctx.Apply(plan, m)
  7284  	if diags.HasErrors() {
  7285  		t.Fatalf("diags: %s", diags.Err())
  7286  	}
  7287  
  7288  	mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7289  	if mod == nil {
  7290  		t.Fatalf("no child module found in the state!\n\n%#v", state)
  7291  	}
  7292  	if len(mod.Resources) != 2 {
  7293  		t.Fatalf("expected 2 resources, got: %#v", mod.Resources)
  7294  	}
  7295  
  7296  	checkStateString(t, state, `
  7297  <no state>
  7298  module.child:
  7299    aws_instance.bar:
  7300      ID = foo
  7301      provider = provider["registry.terraform.io/hashicorp/aws"]
  7302      num = 2
  7303      type = aws_instance
  7304    aws_instance.foo:
  7305      ID = foo
  7306      provider = provider["registry.terraform.io/hashicorp/aws"]
  7307      num = 2
  7308      type = aws_instance
  7309  	`)
  7310  }
  7311  
  7312  // GH-1858
  7313  func TestContext2Apply_targetedModuleDep(t *testing.T) {
  7314  	m := testModule(t, "apply-targeted-module-dep")
  7315  	p := testProvider("aws")
  7316  	p.PlanResourceChangeFn = testDiffFn
  7317  	p.ApplyResourceChangeFn = testApplyFn
  7318  	ctx := testContext2(t, &ContextOpts{
  7319  		Providers: map[addrs.Provider]providers.Factory{
  7320  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7321  		},
  7322  	})
  7323  
  7324  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7325  		Mode: plans.NormalMode,
  7326  		Targets: []addrs.Targetable{
  7327  			addrs.RootModuleInstance.Resource(
  7328  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7329  			),
  7330  		},
  7331  	})
  7332  	if diags.HasErrors() {
  7333  		t.Fatalf("diags: %s", diags.Err())
  7334  	} else {
  7335  		t.Logf("Diff: %s", legacyDiffComparisonString(plan.Changes))
  7336  	}
  7337  
  7338  	state, diags := ctx.Apply(plan, m)
  7339  	if diags.HasErrors() {
  7340  		t.Fatalf("diags: %s", diags.Err())
  7341  	}
  7342  
  7343  	checkStateString(t, state, `
  7344  aws_instance.foo:
  7345    ID = foo
  7346    provider = provider["registry.terraform.io/hashicorp/aws"]
  7347    foo = foo
  7348    type = aws_instance
  7349  
  7350    Dependencies:
  7351      module.child.aws_instance.mod
  7352  
  7353  module.child:
  7354    aws_instance.mod:
  7355      ID = foo
  7356      provider = provider["registry.terraform.io/hashicorp/aws"]
  7357      type = aws_instance
  7358  
  7359    Outputs:
  7360  
  7361    output = foo
  7362  	`)
  7363  }
  7364  
  7365  // GH-10911 untargeted outputs should not be in the graph, and therefore
  7366  // not execute.
  7367  func TestContext2Apply_targetedModuleUnrelatedOutputs(t *testing.T) {
  7368  	m := testModule(t, "apply-targeted-module-unrelated-outputs")
  7369  	p := testProvider("aws")
  7370  	p.PlanResourceChangeFn = testDiffFn
  7371  	p.ApplyResourceChangeFn = testApplyFn
  7372  
  7373  	state := states.NewState()
  7374  	_ = state.EnsureModule(addrs.RootModuleInstance.Child("child2", addrs.NoKey))
  7375  
  7376  	ctx := testContext2(t, &ContextOpts{
  7377  		Providers: map[addrs.Provider]providers.Factory{
  7378  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7379  		},
  7380  	})
  7381  
  7382  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7383  		Mode: plans.NormalMode,
  7384  		Targets: []addrs.Targetable{
  7385  			addrs.RootModuleInstance.Child("child2", addrs.NoKey),
  7386  		},
  7387  	})
  7388  	assertNoErrors(t, diags)
  7389  
  7390  	s, diags := ctx.Apply(plan, m)
  7391  	if diags.HasErrors() {
  7392  		t.Fatalf("diags: %s", diags.Err())
  7393  	}
  7394  
  7395  	// - module.child1's instance_id output is dropped because we don't preserve
  7396  	//   non-root module outputs between runs (they can be recalculated from config)
  7397  	// - module.child2's instance_id is updated because its dependency is updated
  7398  	// - child2_id is updated because if its transitive dependency via module.child2
  7399  	checkStateString(t, s, `
  7400  <no state>
  7401  Outputs:
  7402  
  7403  child2_id = foo
  7404  
  7405  module.child2:
  7406    aws_instance.foo:
  7407      ID = foo
  7408      provider = provider["registry.terraform.io/hashicorp/aws"]
  7409      type = aws_instance
  7410  
  7411    Outputs:
  7412  
  7413    instance_id = foo
  7414  `)
  7415  }
  7416  
  7417  func TestContext2Apply_targetedModuleResource(t *testing.T) {
  7418  	m := testModule(t, "apply-targeted-module-resource")
  7419  	p := testProvider("aws")
  7420  	p.PlanResourceChangeFn = testDiffFn
  7421  	p.ApplyResourceChangeFn = testApplyFn
  7422  	ctx := testContext2(t, &ContextOpts{
  7423  		Providers: map[addrs.Provider]providers.Factory{
  7424  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7425  		},
  7426  	})
  7427  
  7428  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7429  		Mode: plans.NormalMode,
  7430  		Targets: []addrs.Targetable{
  7431  			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
  7432  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7433  			),
  7434  		},
  7435  	})
  7436  	assertNoErrors(t, diags)
  7437  
  7438  	state, diags := ctx.Apply(plan, m)
  7439  	if diags.HasErrors() {
  7440  		t.Fatalf("diags: %s", diags.Err())
  7441  	}
  7442  
  7443  	mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7444  	if mod == nil || len(mod.Resources) != 1 {
  7445  		t.Fatalf("expected 1 resource, got: %#v", mod)
  7446  	}
  7447  
  7448  	checkStateString(t, state, `
  7449  <no state>
  7450  module.child:
  7451    aws_instance.foo:
  7452      ID = foo
  7453      provider = provider["registry.terraform.io/hashicorp/aws"]
  7454      num = 2
  7455      type = aws_instance
  7456  	`)
  7457  }
  7458  
  7459  func TestContext2Apply_targetedResourceOrphanModule(t *testing.T) {
  7460  	m := testModule(t, "apply-targeted-resource-orphan-module")
  7461  	p := testProvider("aws")
  7462  	p.PlanResourceChangeFn = testDiffFn
  7463  
  7464  	state := states.NewState()
  7465  	child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey))
  7466  	child.SetResourceInstanceCurrent(
  7467  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7468  		&states.ResourceInstanceObjectSrc{
  7469  			Status:    states.ObjectReady,
  7470  			AttrsJSON: []byte(`{"type":"aws_instance"}`),
  7471  		},
  7472  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7473  	)
  7474  
  7475  	ctx := testContext2(t, &ContextOpts{
  7476  		Providers: map[addrs.Provider]providers.Factory{
  7477  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7478  		},
  7479  	})
  7480  
  7481  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7482  		Mode: plans.NormalMode,
  7483  		Targets: []addrs.Targetable{
  7484  			addrs.RootModuleInstance.Resource(
  7485  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7486  			),
  7487  		},
  7488  	})
  7489  	assertNoErrors(t, diags)
  7490  
  7491  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  7492  		t.Fatalf("apply errors: %s", diags.Err())
  7493  	}
  7494  }
  7495  
  7496  func TestContext2Apply_unknownAttribute(t *testing.T) {
  7497  	m := testModule(t, "apply-unknown")
  7498  	p := testProvider("aws")
  7499  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  7500  		resp = testDiffFn(req)
  7501  		planned := resp.PlannedState.AsValueMap()
  7502  		planned["unknown"] = cty.UnknownVal(cty.String)
  7503  		resp.PlannedState = cty.ObjectVal(planned)
  7504  		return resp
  7505  	}
  7506  	p.ApplyResourceChangeFn = testApplyFn
  7507  
  7508  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  7509  		ResourceTypes: map[string]*configschema.Block{
  7510  			"aws_instance": {
  7511  				Attributes: map[string]*configschema.Attribute{
  7512  					"id":      {Type: cty.String, Computed: true},
  7513  					"num":     {Type: cty.Number, Optional: true},
  7514  					"unknown": {Type: cty.String, Computed: true},
  7515  					"type":    {Type: cty.String, Computed: true},
  7516  				},
  7517  			},
  7518  		},
  7519  	})
  7520  
  7521  	ctx := testContext2(t, &ContextOpts{
  7522  		Providers: map[addrs.Provider]providers.Factory{
  7523  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7524  		},
  7525  	})
  7526  
  7527  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  7528  	assertNoErrors(t, diags)
  7529  
  7530  	state, diags := ctx.Apply(plan, m)
  7531  	if !diags.HasErrors() {
  7532  		t.Error("should error, because attribute 'unknown' is still unknown after apply")
  7533  	}
  7534  
  7535  	actual := strings.TrimSpace(state.String())
  7536  	expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr)
  7537  	if actual != expected {
  7538  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  7539  	}
  7540  }
  7541  
  7542  func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) {
  7543  	m := testModule(t, "apply-unknown-interpolate")
  7544  	p := testProvider("aws")
  7545  	p.PlanResourceChangeFn = testDiffFn
  7546  	ctx := testContext2(t, &ContextOpts{
  7547  		Providers: map[addrs.Provider]providers.Factory{
  7548  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7549  		},
  7550  	})
  7551  
  7552  	if _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts); diags == nil {
  7553  		t.Fatal("should error")
  7554  	}
  7555  }
  7556  
  7557  func TestContext2Apply_vars(t *testing.T) {
  7558  	fixture := contextFixtureApplyVars(t)
  7559  	opts := fixture.ContextOpts()
  7560  	ctx := testContext2(t, opts)
  7561  	m := fixture.Config
  7562  
  7563  	diags := ctx.Validate(m)
  7564  	if len(diags) != 0 {
  7565  		t.Fatalf("bad: %s", diags.ErrWithWarnings())
  7566  	}
  7567  
  7568  	variables := InputValues{
  7569  		"foo": &InputValue{
  7570  			Value:      cty.StringVal("us-east-1"),
  7571  			SourceType: ValueFromCaller,
  7572  		},
  7573  		"bar": &InputValue{
  7574  			// This one is not explicitly set but that's okay because it
  7575  			// has a declared default, which Terraform Core will use instead.
  7576  			Value:      cty.NilVal,
  7577  			SourceType: ValueFromCaller,
  7578  		},
  7579  		"test_list": &InputValue{
  7580  			Value: cty.ListVal([]cty.Value{
  7581  				cty.StringVal("Hello"),
  7582  				cty.StringVal("World"),
  7583  			}),
  7584  			SourceType: ValueFromCaller,
  7585  		},
  7586  		"test_map": &InputValue{
  7587  			Value: cty.MapVal(map[string]cty.Value{
  7588  				"Hello": cty.StringVal("World"),
  7589  				"Foo":   cty.StringVal("Bar"),
  7590  				"Baz":   cty.StringVal("Foo"),
  7591  			}),
  7592  			SourceType: ValueFromCaller,
  7593  		},
  7594  		"amis": &InputValue{
  7595  			Value: cty.MapVal(map[string]cty.Value{
  7596  				"us-east-1": cty.StringVal("override"),
  7597  			}),
  7598  			SourceType: ValueFromCaller,
  7599  		},
  7600  	}
  7601  
  7602  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7603  		Mode:         plans.NormalMode,
  7604  		SetVariables: variables,
  7605  	})
  7606  	assertNoErrors(t, diags)
  7607  
  7608  	state, diags := ctx.Apply(plan, m)
  7609  	if diags.HasErrors() {
  7610  		t.Fatalf("err: %s", diags.Err())
  7611  	}
  7612  
  7613  	got := strings.TrimSpace(state.String())
  7614  	want := strings.TrimSpace(testTerraformApplyVarsStr)
  7615  	if got != want {
  7616  		t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want)
  7617  	}
  7618  }
  7619  
  7620  func TestContext2Apply_varsEnv(t *testing.T) {
  7621  	fixture := contextFixtureApplyVarsEnv(t)
  7622  	opts := fixture.ContextOpts()
  7623  	ctx := testContext2(t, opts)
  7624  	m := fixture.Config
  7625  
  7626  	diags := ctx.Validate(m)
  7627  	if len(diags) != 0 {
  7628  		t.Fatalf("bad: %s", diags.ErrWithWarnings())
  7629  	}
  7630  
  7631  	variables := InputValues{
  7632  		"string": &InputValue{
  7633  			Value:      cty.StringVal("baz"),
  7634  			SourceType: ValueFromEnvVar,
  7635  		},
  7636  		"list": &InputValue{
  7637  			Value: cty.ListVal([]cty.Value{
  7638  				cty.StringVal("Hello"),
  7639  				cty.StringVal("World"),
  7640  			}),
  7641  			SourceType: ValueFromEnvVar,
  7642  		},
  7643  		"map": &InputValue{
  7644  			Value: cty.MapVal(map[string]cty.Value{
  7645  				"Hello": cty.StringVal("World"),
  7646  				"Foo":   cty.StringVal("Bar"),
  7647  				"Baz":   cty.StringVal("Foo"),
  7648  			}),
  7649  			SourceType: ValueFromEnvVar,
  7650  		},
  7651  	}
  7652  
  7653  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7654  		Mode:         plans.NormalMode,
  7655  		SetVariables: variables,
  7656  	})
  7657  	assertNoErrors(t, diags)
  7658  
  7659  	state, diags := ctx.Apply(plan, m)
  7660  	if diags.HasErrors() {
  7661  		t.Fatalf("err: %s", diags.Err())
  7662  	}
  7663  
  7664  	actual := strings.TrimSpace(state.String())
  7665  	expected := strings.TrimSpace(testTerraformApplyVarsEnvStr)
  7666  	if actual != expected {
  7667  		t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  7668  	}
  7669  }
  7670  
  7671  func TestContext2Apply_createBefore_depends(t *testing.T) {
  7672  	m := testModule(t, "apply-depends-create-before")
  7673  	h := new(HookRecordApplyOrder)
  7674  	p := testProvider("aws")
  7675  	p.PlanResourceChangeFn = testDiffFn
  7676  	p.ApplyResourceChangeFn = testApplyFn
  7677  	state := states.NewState()
  7678  	root := state.EnsureModule(addrs.RootModuleInstance)
  7679  	root.SetResourceInstanceCurrent(
  7680  		addrs.Resource{
  7681  			Mode: addrs.ManagedResourceMode,
  7682  			Type: "aws_instance",
  7683  			Name: "web",
  7684  		}.Instance(addrs.NoKey),
  7685  		&states.ResourceInstanceObjectSrc{
  7686  			Status:    states.ObjectReady,
  7687  			AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`),
  7688  		},
  7689  		addrs.AbsProviderConfig{
  7690  			Provider: addrs.NewDefaultProvider("aws"),
  7691  			Module:   addrs.RootModule,
  7692  		},
  7693  	)
  7694  
  7695  	root.SetResourceInstanceCurrent(
  7696  		addrs.Resource{
  7697  			Mode: addrs.ManagedResourceMode,
  7698  			Type: "aws_instance",
  7699  			Name: "lb",
  7700  		}.Instance(addrs.NoKey),
  7701  		&states.ResourceInstanceObjectSrc{
  7702  			Status:    states.ObjectReady,
  7703  			AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`),
  7704  			Dependencies: []addrs.ConfigResource{
  7705  				{
  7706  					Resource: addrs.Resource{
  7707  						Mode: addrs.ManagedResourceMode,
  7708  						Type: "aws_instance",
  7709  						Name: "web",
  7710  					},
  7711  					Module: addrs.RootModule,
  7712  				},
  7713  			},
  7714  		},
  7715  		addrs.AbsProviderConfig{
  7716  			Provider: addrs.NewDefaultProvider("aws"),
  7717  			Module:   addrs.RootModule,
  7718  		},
  7719  	)
  7720  
  7721  	ctx := testContext2(t, &ContextOpts{
  7722  		Hooks: []Hook{h},
  7723  		Providers: map[addrs.Provider]providers.Factory{
  7724  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7725  		},
  7726  	})
  7727  
  7728  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  7729  	if diags.HasErrors() {
  7730  		logDiagnostics(t, diags)
  7731  		t.Fatal("plan failed")
  7732  	} else {
  7733  		t.Logf("plan:\n%s", legacyDiffComparisonString(plan.Changes))
  7734  	}
  7735  
  7736  	h.Active = true
  7737  	state, diags = ctx.Apply(plan, m)
  7738  	if diags.HasErrors() {
  7739  		logDiagnostics(t, diags)
  7740  		t.Fatal("apply failed")
  7741  	}
  7742  
  7743  	mod := state.RootModule()
  7744  	if len(mod.Resources) < 2 {
  7745  		t.Logf("state after apply:\n%s", state.String())
  7746  		t.Fatalf("only %d resources in root module; want at least 2", len(mod.Resources))
  7747  	}
  7748  
  7749  	got := strings.TrimSpace(state.String())
  7750  	want := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr)
  7751  	if got != want {
  7752  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", got, want)
  7753  	}
  7754  
  7755  	// Test that things were managed _in the right order_
  7756  	order := h.States
  7757  
  7758  	diffs := h.Diffs
  7759  	if !order[0].IsNull() || diffs[0].Action == plans.Delete {
  7760  		t.Fatalf("should create new instance first: %#v", order)
  7761  	}
  7762  
  7763  	if order[1].GetAttr("id").AsString() != "baz" {
  7764  		t.Fatalf("update must happen after create: %#v", order[1])
  7765  	}
  7766  
  7767  	if order[2].GetAttr("id").AsString() != "bar" || diffs[2].Action != plans.Delete {
  7768  		t.Fatalf("destroy must happen after update: %#v", order[2])
  7769  	}
  7770  }
  7771  
  7772  func TestContext2Apply_singleDestroy(t *testing.T) {
  7773  	m := testModule(t, "apply-depends-create-before")
  7774  	h := new(HookRecordApplyOrder)
  7775  	p := testProvider("aws")
  7776  	invokeCount := 0
  7777  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  7778  		invokeCount++
  7779  		switch invokeCount {
  7780  		case 1:
  7781  			if req.PlannedState.IsNull() {
  7782  				t.Fatalf("should not destroy")
  7783  			}
  7784  			if id := req.PlannedState.GetAttr("id"); id.IsKnown() {
  7785  				t.Fatalf("should not have ID")
  7786  			}
  7787  		case 2:
  7788  			if req.PlannedState.IsNull() {
  7789  				t.Fatalf("should not destroy")
  7790  			}
  7791  			if id := req.PlannedState.GetAttr("id"); id.AsString() != "baz" {
  7792  				t.Fatalf("should have id")
  7793  			}
  7794  		case 3:
  7795  			if !req.PlannedState.IsNull() {
  7796  				t.Fatalf("should destroy")
  7797  			}
  7798  		default:
  7799  			t.Fatalf("bad invoke count %d", invokeCount)
  7800  		}
  7801  		return testApplyFn(req)
  7802  	}
  7803  
  7804  	p.PlanResourceChangeFn = testDiffFn
  7805  	state := states.NewState()
  7806  	root := state.EnsureModule(addrs.RootModuleInstance)
  7807  	root.SetResourceInstanceCurrent(
  7808  		addrs.Resource{
  7809  			Mode: addrs.ManagedResourceMode,
  7810  			Type: "aws_instance",
  7811  			Name: "web",
  7812  		}.Instance(addrs.NoKey),
  7813  		&states.ResourceInstanceObjectSrc{
  7814  			Status:    states.ObjectReady,
  7815  			AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`),
  7816  		},
  7817  		addrs.AbsProviderConfig{
  7818  			Provider: addrs.NewDefaultProvider("aws"),
  7819  			Module:   addrs.RootModule,
  7820  		},
  7821  	)
  7822  
  7823  	root.SetResourceInstanceCurrent(
  7824  		addrs.Resource{
  7825  			Mode: addrs.ManagedResourceMode,
  7826  			Type: "aws_instance",
  7827  			Name: "lb",
  7828  		}.Instance(addrs.NoKey),
  7829  		&states.ResourceInstanceObjectSrc{
  7830  			Status:    states.ObjectReady,
  7831  			AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`),
  7832  			Dependencies: []addrs.ConfigResource{
  7833  				{
  7834  					Resource: addrs.Resource{
  7835  						Mode: addrs.ManagedResourceMode,
  7836  						Type: "aws_instance",
  7837  						Name: "web",
  7838  					},
  7839  					Module: addrs.RootModule,
  7840  				},
  7841  			},
  7842  		},
  7843  		addrs.AbsProviderConfig{
  7844  			Provider: addrs.NewDefaultProvider("aws"),
  7845  			Module:   addrs.RootModule,
  7846  		},
  7847  	)
  7848  
  7849  	ctx := testContext2(t, &ContextOpts{
  7850  		Hooks: []Hook{h},
  7851  		Providers: map[addrs.Provider]providers.Factory{
  7852  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7853  		},
  7854  	})
  7855  
  7856  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  7857  	assertNoErrors(t, diags)
  7858  
  7859  	h.Active = true
  7860  	_, diags = ctx.Apply(plan, m)
  7861  	if diags.HasErrors() {
  7862  		t.Fatalf("diags: %s", diags.Err())
  7863  	}
  7864  
  7865  	if invokeCount != 3 {
  7866  		t.Fatalf("bad: %d", invokeCount)
  7867  	}
  7868  }
  7869  
  7870  // GH-7824
  7871  func TestContext2Apply_issue7824(t *testing.T) {
  7872  	p := testProvider("template")
  7873  	p.PlanResourceChangeFn = testDiffFn
  7874  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  7875  		ResourceTypes: map[string]*configschema.Block{
  7876  			"template_file": {
  7877  				Attributes: map[string]*configschema.Attribute{
  7878  					"template":                {Type: cty.String, Optional: true},
  7879  					"__template_requires_new": {Type: cty.Bool, Optional: true},
  7880  				},
  7881  			},
  7882  		},
  7883  	})
  7884  
  7885  	m, snap := testModuleWithSnapshot(t, "issue-7824")
  7886  
  7887  	// Apply cleanly step 0
  7888  	ctx := testContext2(t, &ContextOpts{
  7889  		Providers: map[addrs.Provider]providers.Factory{
  7890  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7891  		},
  7892  	})
  7893  
  7894  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  7895  	if diags.HasErrors() {
  7896  		t.Fatalf("err: %s", diags.Err())
  7897  	}
  7898  
  7899  	// Write / Read plan to simulate running it through a Plan file
  7900  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  7901  	if err != nil {
  7902  		t.Fatalf("failed to round-trip through planfile: %s", err)
  7903  	}
  7904  
  7905  	ctxOpts.Providers =
  7906  		map[addrs.Provider]providers.Factory{
  7907  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7908  		}
  7909  
  7910  	ctx, diags = NewContext(ctxOpts)
  7911  	if diags.HasErrors() {
  7912  		t.Fatalf("err: %s", diags.Err())
  7913  	}
  7914  
  7915  	_, diags = ctx.Apply(plan, m)
  7916  	if diags.HasErrors() {
  7917  		t.Fatalf("err: %s", diags.Err())
  7918  	}
  7919  }
  7920  
  7921  // This deals with the situation where a splat expression is used referring
  7922  // to another resource whose count is non-constant.
  7923  func TestContext2Apply_issue5254(t *testing.T) {
  7924  	// Create a provider. We use "template" here just to match the repro
  7925  	// we got from the issue itself.
  7926  	p := testProvider("template")
  7927  	p.PlanResourceChangeFn = testDiffFn
  7928  	p.ApplyResourceChangeFn = testApplyFn
  7929  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  7930  		ResourceTypes: map[string]*configschema.Block{
  7931  			"template_file": {
  7932  				Attributes: map[string]*configschema.Attribute{
  7933  					"template":                {Type: cty.String, Optional: true},
  7934  					"__template_requires_new": {Type: cty.Bool, Optional: true},
  7935  					"id":                      {Type: cty.String, Computed: true},
  7936  					"type":                    {Type: cty.String, Computed: true},
  7937  				},
  7938  			},
  7939  		},
  7940  	})
  7941  
  7942  	// Apply cleanly step 0
  7943  	m := testModule(t, "issue-5254/step-0")
  7944  	ctx := testContext2(t, &ContextOpts{
  7945  		Providers: map[addrs.Provider]providers.Factory{
  7946  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7947  		},
  7948  	})
  7949  
  7950  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  7951  	if diags.HasErrors() {
  7952  		t.Fatalf("err: %s", diags.Err())
  7953  	}
  7954  
  7955  	state, diags := ctx.Apply(plan, m)
  7956  	if diags.HasErrors() {
  7957  		t.Fatalf("err: %s", diags.Err())
  7958  	}
  7959  
  7960  	m, snap := testModuleWithSnapshot(t, "issue-5254/step-1")
  7961  
  7962  	// Application success. Now make the modification and store a plan
  7963  	ctx = testContext2(t, &ContextOpts{
  7964  		Providers: map[addrs.Provider]providers.Factory{
  7965  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7966  		},
  7967  	})
  7968  
  7969  	plan, diags = ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  7970  	if diags.HasErrors() {
  7971  		t.Fatalf("err: %s", diags.Err())
  7972  	}
  7973  
  7974  	// Write / Read plan to simulate running it through a Plan file
  7975  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  7976  	if err != nil {
  7977  		t.Fatalf("failed to round-trip through planfile: %s", err)
  7978  	}
  7979  
  7980  	ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  7981  		addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7982  	}
  7983  
  7984  	ctx, diags = NewContext(ctxOpts)
  7985  	if diags.HasErrors() {
  7986  		t.Fatalf("err: %s", diags.Err())
  7987  	}
  7988  
  7989  	state, diags = ctx.Apply(plan, m)
  7990  	if diags.HasErrors() {
  7991  		t.Fatalf("err: %s", diags.Err())
  7992  	}
  7993  
  7994  	actual := strings.TrimSpace(state.String())
  7995  	expected := strings.TrimSpace(`
  7996  template_file.child:
  7997    ID = foo
  7998    provider = provider["registry.terraform.io/hashicorp/template"]
  7999    __template_requires_new = true
  8000    template = Hi
  8001    type = template_file
  8002  
  8003    Dependencies:
  8004      template_file.parent
  8005  template_file.parent.0:
  8006    ID = foo
  8007    provider = provider["registry.terraform.io/hashicorp/template"]
  8008    template = Hi
  8009    type = template_file
  8010  `)
  8011  	if actual != expected {
  8012  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected)
  8013  	}
  8014  }
  8015  
  8016  func TestContext2Apply_targetedWithTaintedInState(t *testing.T) {
  8017  	p := testProvider("aws")
  8018  	p.PlanResourceChangeFn = testDiffFn
  8019  	p.ApplyResourceChangeFn = testApplyFn
  8020  	m, snap := testModuleWithSnapshot(t, "apply-tainted-targets")
  8021  
  8022  	state := states.NewState()
  8023  	root := state.EnsureModule(addrs.RootModuleInstance)
  8024  	root.SetResourceInstanceCurrent(
  8025  		mustResourceInstanceAddr("aws_instance.ifailedprovisioners").Resource,
  8026  		&states.ResourceInstanceObjectSrc{
  8027  			Status:    states.ObjectTainted,
  8028  			AttrsJSON: []byte(`{"id":"ifailedprovisioners"}`),
  8029  		},
  8030  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8031  	)
  8032  
  8033  	ctx := testContext2(t, &ContextOpts{
  8034  		Providers: map[addrs.Provider]providers.Factory{
  8035  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8036  		},
  8037  	})
  8038  
  8039  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8040  		Mode: plans.NormalMode,
  8041  		Targets: []addrs.Targetable{
  8042  			addrs.RootModuleInstance.Resource(
  8043  				addrs.ManagedResourceMode, "aws_instance", "iambeingadded",
  8044  			),
  8045  		},
  8046  	})
  8047  	if diags.HasErrors() {
  8048  		t.Fatalf("err: %s", diags.Err())
  8049  	}
  8050  
  8051  	// Write / Read plan to simulate running it through a Plan file
  8052  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  8053  	if err != nil {
  8054  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8055  	}
  8056  
  8057  	ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  8058  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8059  	}
  8060  
  8061  	ctx, diags = NewContext(ctxOpts)
  8062  	if diags.HasErrors() {
  8063  		t.Fatalf("err: %s", diags.Err())
  8064  	}
  8065  
  8066  	s, diags := ctx.Apply(plan, m)
  8067  	if diags.HasErrors() {
  8068  		t.Fatalf("err: %s", diags.Err())
  8069  	}
  8070  
  8071  	actual := strings.TrimSpace(s.String())
  8072  	expected := strings.TrimSpace(`
  8073  aws_instance.iambeingadded:
  8074    ID = foo
  8075    provider = provider["registry.terraform.io/hashicorp/aws"]
  8076    type = aws_instance
  8077  aws_instance.ifailedprovisioners: (tainted)
  8078    ID = ifailedprovisioners
  8079    provider = provider["registry.terraform.io/hashicorp/aws"]
  8080  		`)
  8081  	if actual != expected {
  8082  		t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual)
  8083  	}
  8084  }
  8085  
  8086  // Higher level test exposing the bug this covers in
  8087  // TestResource_ignoreChangesRequired
  8088  func TestContext2Apply_ignoreChangesCreate(t *testing.T) {
  8089  	m := testModule(t, "apply-ignore-changes-create")
  8090  	p := testProvider("aws")
  8091  	p.PlanResourceChangeFn = testDiffFn
  8092  	p.ApplyResourceChangeFn = testApplyFn
  8093  
  8094  	instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  8095  	instanceSchema.Attributes["required_field"] = &configschema.Attribute{
  8096  		Type:     cty.String,
  8097  		Required: true,
  8098  	}
  8099  
  8100  	ctx := testContext2(t, &ContextOpts{
  8101  		Providers: map[addrs.Provider]providers.Factory{
  8102  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8103  		},
  8104  	})
  8105  
  8106  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8107  	if diags.HasErrors() {
  8108  		t.Fatalf("diags: %s", diags.Err())
  8109  	} else {
  8110  		t.Logf(legacyDiffComparisonString(plan.Changes))
  8111  	}
  8112  
  8113  	state, diags := ctx.Apply(plan, m)
  8114  	if diags.HasErrors() {
  8115  		t.Fatalf("diags: %s", diags.Err())
  8116  	}
  8117  
  8118  	mod := state.RootModule()
  8119  	if len(mod.Resources) != 1 {
  8120  		t.Fatalf("bad: %s", state)
  8121  	}
  8122  
  8123  	actual := strings.TrimSpace(state.String())
  8124  	// Expect no changes from original state
  8125  	expected := strings.TrimSpace(`
  8126  aws_instance.foo:
  8127    ID = foo
  8128    provider = provider["registry.terraform.io/hashicorp/aws"]
  8129    required_field = set
  8130    type = aws_instance
  8131  `)
  8132  	if actual != expected {
  8133  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
  8134  	}
  8135  }
  8136  
  8137  func TestContext2Apply_ignoreChangesWithDep(t *testing.T) {
  8138  	m := testModule(t, "apply-ignore-changes-dep")
  8139  	p := testProvider("aws")
  8140  
  8141  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  8142  		resp.PlannedState = req.ProposedNewState
  8143  
  8144  		switch req.TypeName {
  8145  		case "aws_instance":
  8146  			resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: "ami"}})
  8147  		case "aws_eip":
  8148  			return testDiffFn(req)
  8149  		default:
  8150  			t.Fatalf("Unexpected type: %s", req.TypeName)
  8151  		}
  8152  		return
  8153  	}
  8154  
  8155  	state := states.NewState()
  8156  	root := state.EnsureModule(addrs.RootModuleInstance)
  8157  	root.SetResourceInstanceCurrent(
  8158  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  8159  		&states.ResourceInstanceObjectSrc{
  8160  			Status:    states.ObjectReady,
  8161  			AttrsJSON: []byte(`{"id":"i-abc123","ami":"ami-abcd1234"}`),
  8162  		},
  8163  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8164  	)
  8165  	root.SetResourceInstanceCurrent(
  8166  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  8167  		&states.ResourceInstanceObjectSrc{
  8168  			Status:    states.ObjectReady,
  8169  			AttrsJSON: []byte(`{"id":"i-bcd234","ami":"i-bcd234"}`),
  8170  		},
  8171  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8172  	)
  8173  	root.SetResourceInstanceCurrent(
  8174  		mustResourceInstanceAddr("aws_eip.foo[0]").Resource,
  8175  		&states.ResourceInstanceObjectSrc{
  8176  			Status:    states.ObjectReady,
  8177  			AttrsJSON: []byte(`{"id":"eip-abc123","instance":"i-abc123"}`),
  8178  			Dependencies: []addrs.ConfigResource{
  8179  				{
  8180  					Resource: addrs.Resource{
  8181  						Mode: addrs.ManagedResourceMode,
  8182  						Type: "aws_instance",
  8183  						Name: "foo",
  8184  					},
  8185  					Module: addrs.RootModule,
  8186  				},
  8187  			},
  8188  		},
  8189  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8190  	)
  8191  	root.SetResourceInstanceCurrent(
  8192  		mustResourceInstanceAddr("aws_eip.foo[1]").Resource,
  8193  		&states.ResourceInstanceObjectSrc{
  8194  			Status:    states.ObjectReady,
  8195  			AttrsJSON: []byte(`{"id":"eip-bcd234","instance":"i-bcd234"}`),
  8196  			Dependencies: []addrs.ConfigResource{
  8197  				{
  8198  					Resource: addrs.Resource{
  8199  						Mode: addrs.ManagedResourceMode,
  8200  						Type: "aws_instance",
  8201  						Name: "foo",
  8202  					},
  8203  					Module: addrs.RootModule,
  8204  				},
  8205  			},
  8206  		},
  8207  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8208  	)
  8209  
  8210  	ctx := testContext2(t, &ContextOpts{
  8211  		Providers: map[addrs.Provider]providers.Factory{
  8212  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8213  		},
  8214  	})
  8215  
  8216  	plan, diags := ctx.Plan(m, state.DeepCopy(), DefaultPlanOpts)
  8217  	assertNoErrors(t, diags)
  8218  
  8219  	s, diags := ctx.Apply(plan, m)
  8220  	assertNoErrors(t, diags)
  8221  
  8222  	actual := strings.TrimSpace(s.String())
  8223  	expected := strings.TrimSpace(state.String())
  8224  	if actual != expected {
  8225  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  8226  	}
  8227  }
  8228  
  8229  func TestContext2Apply_ignoreChangesAll(t *testing.T) {
  8230  	m := testModule(t, "apply-ignore-changes-all")
  8231  	p := testProvider("aws")
  8232  	p.PlanResourceChangeFn = testDiffFn
  8233  	p.ApplyResourceChangeFn = testApplyFn
  8234  
  8235  	instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  8236  	instanceSchema.Attributes["required_field"] = &configschema.Attribute{
  8237  		Type:     cty.String,
  8238  		Required: true,
  8239  	}
  8240  
  8241  	ctx := testContext2(t, &ContextOpts{
  8242  		Providers: map[addrs.Provider]providers.Factory{
  8243  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8244  		},
  8245  	})
  8246  
  8247  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8248  	if diags.HasErrors() {
  8249  		logDiagnostics(t, diags)
  8250  		t.Fatal("plan failed")
  8251  	} else {
  8252  		t.Logf(legacyDiffComparisonString(plan.Changes))
  8253  	}
  8254  
  8255  	state, diags := ctx.Apply(plan, m)
  8256  	assertNoErrors(t, diags)
  8257  
  8258  	mod := state.RootModule()
  8259  	if len(mod.Resources) != 1 {
  8260  		t.Fatalf("bad: %s", state)
  8261  	}
  8262  
  8263  	actual := strings.TrimSpace(state.String())
  8264  	// Expect no changes from original state
  8265  	expected := strings.TrimSpace(`
  8266  aws_instance.foo:
  8267    ID = foo
  8268    provider = provider["registry.terraform.io/hashicorp/aws"]
  8269    required_field = set
  8270    type = aws_instance
  8271  `)
  8272  	if actual != expected {
  8273  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
  8274  	}
  8275  }
  8276  
  8277  // https://github.com/hashicorp/terraform/issues/7378
  8278  func TestContext2Apply_destroyNestedModuleWithAttrsReferencingResource(t *testing.T) {
  8279  	m, snap := testModuleWithSnapshot(t, "apply-destroy-nested-module-with-attrs")
  8280  	p := testProvider("null")
  8281  	p.PlanResourceChangeFn = testDiffFn
  8282  
  8283  	var state *states.State
  8284  	{
  8285  		ctx := testContext2(t, &ContextOpts{
  8286  			Providers: map[addrs.Provider]providers.Factory{
  8287  				addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8288  			},
  8289  		})
  8290  
  8291  		// First plan and apply a create operation
  8292  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8293  		assertNoErrors(t, diags)
  8294  
  8295  		state, diags = ctx.Apply(plan, m)
  8296  		if diags.HasErrors() {
  8297  			t.Fatalf("apply err: %s", diags.Err())
  8298  		}
  8299  	}
  8300  
  8301  	{
  8302  		ctx := testContext2(t, &ContextOpts{
  8303  			Providers: map[addrs.Provider]providers.Factory{
  8304  				addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8305  			},
  8306  		})
  8307  
  8308  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  8309  			Mode: plans.DestroyMode,
  8310  		})
  8311  		if diags.HasErrors() {
  8312  			t.Fatalf("destroy plan err: %s", diags.Err())
  8313  		}
  8314  
  8315  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  8316  		if err != nil {
  8317  			t.Fatalf("failed to round-trip through planfile: %s", err)
  8318  		}
  8319  
  8320  		ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  8321  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8322  		}
  8323  
  8324  		ctx, diags = NewContext(ctxOpts)
  8325  		if diags.HasErrors() {
  8326  			t.Fatalf("err: %s", diags.Err())
  8327  		}
  8328  
  8329  		state, diags = ctx.Apply(plan, m)
  8330  		if diags.HasErrors() {
  8331  			t.Fatalf("destroy apply err: %s", diags.Err())
  8332  		}
  8333  	}
  8334  
  8335  	if !state.Empty() {
  8336  		t.Fatalf("state after apply: %s\nwant empty state", spew.Sdump(state))
  8337  	}
  8338  }
  8339  
  8340  // If a data source explicitly depends on another resource, it's because we need
  8341  // that resource to be applied first.
  8342  func TestContext2Apply_dataDependsOn(t *testing.T) {
  8343  	p := testProvider("null")
  8344  	m := testModuleInline(t, map[string]string{
  8345  		"main.tf": `
  8346  resource "null_instance" "write" {
  8347    foo = "attribute"
  8348  }
  8349  
  8350  data "null_data_source" "read" {
  8351    count = 1
  8352    depends_on = ["null_instance.write"]
  8353  }
  8354  
  8355  resource "null_instance" "depends" {
  8356    foo = data.null_data_source.read[0].foo
  8357  }
  8358  `})
  8359  
  8360  	ctx := testContext2(t, &ContextOpts{
  8361  		Providers: map[addrs.Provider]providers.Factory{
  8362  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8363  		},
  8364  	})
  8365  
  8366  	// the "provisioner" here writes to this variable, because the intent is to
  8367  	// create a dependency which can't be viewed through the graph, and depends
  8368  	// solely on the configuration providing "depends_on"
  8369  	provisionerOutput := ""
  8370  
  8371  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  8372  		// the side effect of the resource being applied
  8373  		provisionerOutput = "APPLIED"
  8374  		return testApplyFn(req)
  8375  	}
  8376  
  8377  	p.PlanResourceChangeFn = testDiffFn
  8378  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  8379  		return providers.ReadDataSourceResponse{
  8380  			State: cty.ObjectVal(map[string]cty.Value{
  8381  				"id":  cty.StringVal("boop"),
  8382  				"foo": cty.StringVal(provisionerOutput),
  8383  			}),
  8384  		}
  8385  	}
  8386  
  8387  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8388  	assertNoErrors(t, diags)
  8389  
  8390  	state, diags := ctx.Apply(plan, m)
  8391  	assertNoErrors(t, diags)
  8392  
  8393  	root := state.Module(addrs.RootModuleInstance)
  8394  	is := root.ResourceInstance(addrs.Resource{
  8395  		Mode: addrs.DataResourceMode,
  8396  		Type: "null_data_source",
  8397  		Name: "read",
  8398  	}.Instance(addrs.IntKey(0)))
  8399  	if is == nil {
  8400  		t.Fatal("data resource instance is not present in state; should be")
  8401  	}
  8402  	var attrs map[string]interface{}
  8403  	err := json.Unmarshal(is.Current.AttrsJSON, &attrs)
  8404  	if err != nil {
  8405  		t.Fatal(err)
  8406  	}
  8407  	actual := attrs["foo"]
  8408  	expected := "APPLIED"
  8409  	if actual != expected {
  8410  		t.Fatalf("bad:\n%s", strings.TrimSpace(state.String()))
  8411  	}
  8412  
  8413  	// run another plan to make sure the data source doesn't show as a change
  8414  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  8415  	assertNoErrors(t, diags)
  8416  
  8417  	for _, c := range plan.Changes.Resources {
  8418  		if c.Action != plans.NoOp {
  8419  			t.Fatalf("unexpected change for %s", c.Addr)
  8420  		}
  8421  	}
  8422  
  8423  	// now we cause a change in the first resource, which should trigger a plan
  8424  	// in the data source, and the resource that depends on the data source
  8425  	// must plan a change as well.
  8426  	m = testModuleInline(t, map[string]string{
  8427  		"main.tf": `
  8428  resource "null_instance" "write" {
  8429    foo = "new"
  8430  }
  8431  
  8432  data "null_data_source" "read" {
  8433    depends_on = ["null_instance.write"]
  8434  }
  8435  
  8436  resource "null_instance" "depends" {
  8437    foo = data.null_data_source.read.foo
  8438  }
  8439  `})
  8440  
  8441  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  8442  		// the side effect of the resource being applied
  8443  		provisionerOutput = "APPLIED_AGAIN"
  8444  		return testApplyFn(req)
  8445  	}
  8446  
  8447  	ctx = testContext2(t, &ContextOpts{
  8448  		Providers: map[addrs.Provider]providers.Factory{
  8449  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8450  		},
  8451  	})
  8452  
  8453  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  8454  	assertNoErrors(t, diags)
  8455  
  8456  	expectedChanges := map[string]plans.Action{
  8457  		"null_instance.write":        plans.Update,
  8458  		"data.null_data_source.read": plans.Read,
  8459  		"null_instance.depends":      plans.Update,
  8460  	}
  8461  
  8462  	for _, c := range plan.Changes.Resources {
  8463  		if c.Action != expectedChanges[c.Addr.String()] {
  8464  			t.Errorf("unexpected %s for %s", c.Action, c.Addr)
  8465  		}
  8466  	}
  8467  }
  8468  
  8469  func TestContext2Apply_terraformWorkspace(t *testing.T) {
  8470  	m := testModule(t, "apply-terraform-workspace")
  8471  	p := testProvider("aws")
  8472  	p.PlanResourceChangeFn = testDiffFn
  8473  
  8474  	ctx := testContext2(t, &ContextOpts{
  8475  		Meta: &ContextMeta{Env: "foo"},
  8476  		Providers: map[addrs.Provider]providers.Factory{
  8477  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8478  		},
  8479  	})
  8480  
  8481  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8482  	assertNoErrors(t, diags)
  8483  
  8484  	state, diags := ctx.Apply(plan, m)
  8485  	if diags.HasErrors() {
  8486  		t.Fatalf("diags: %s", diags.Err())
  8487  	}
  8488  
  8489  	actual := state.RootModule().OutputValues["output"]
  8490  	expected := cty.StringVal("foo")
  8491  	if actual == nil || actual.Value != expected {
  8492  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  8493  	}
  8494  }
  8495  
  8496  // verify that multiple config references only create a single depends_on entry
  8497  func TestContext2Apply_multiRef(t *testing.T) {
  8498  	m := testModule(t, "apply-multi-ref")
  8499  	p := testProvider("aws")
  8500  	p.PlanResourceChangeFn = testDiffFn
  8501  	ctx := testContext2(t, &ContextOpts{
  8502  		Providers: map[addrs.Provider]providers.Factory{
  8503  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8504  		},
  8505  	})
  8506  
  8507  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8508  	assertNoErrors(t, diags)
  8509  
  8510  	state, diags := ctx.Apply(plan, m)
  8511  	if diags.HasErrors() {
  8512  		t.Fatalf("err: %s", diags.Err())
  8513  	}
  8514  
  8515  	deps := state.Modules[""].Resources["aws_instance.other"].Instances[addrs.NoKey].Current.Dependencies
  8516  	if len(deps) != 1 || deps[0].String() != "aws_instance.create" {
  8517  		t.Fatalf("expected 1 depends_on entry for aws_instance.create, got %q", deps)
  8518  	}
  8519  }
  8520  
  8521  func TestContext2Apply_targetedModuleRecursive(t *testing.T) {
  8522  	m := testModule(t, "apply-targeted-module-recursive")
  8523  	p := testProvider("aws")
  8524  	p.PlanResourceChangeFn = testDiffFn
  8525  	p.ApplyResourceChangeFn = testApplyFn
  8526  	ctx := testContext2(t, &ContextOpts{
  8527  		Providers: map[addrs.Provider]providers.Factory{
  8528  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8529  		},
  8530  	})
  8531  
  8532  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  8533  		Mode: plans.NormalMode,
  8534  		Targets: []addrs.Targetable{
  8535  			addrs.RootModuleInstance.Child("child", addrs.NoKey),
  8536  		},
  8537  	})
  8538  	assertNoErrors(t, diags)
  8539  
  8540  	state, diags := ctx.Apply(plan, m)
  8541  	if diags.HasErrors() {
  8542  		t.Fatalf("err: %s", diags.Err())
  8543  	}
  8544  
  8545  	mod := state.Module(
  8546  		addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("subchild", addrs.NoKey),
  8547  	)
  8548  	if mod == nil {
  8549  		t.Fatalf("no subchild module found in the state!\n\n%#v", state)
  8550  	}
  8551  	if len(mod.Resources) != 1 {
  8552  		t.Fatalf("expected 1 resources, got: %#v", mod.Resources)
  8553  	}
  8554  
  8555  	checkStateString(t, state, `
  8556  <no state>
  8557  module.child.subchild:
  8558    aws_instance.foo:
  8559      ID = foo
  8560      provider = provider["registry.terraform.io/hashicorp/aws"]
  8561      num = 2
  8562      type = aws_instance
  8563  	`)
  8564  }
  8565  
  8566  func TestContext2Apply_localVal(t *testing.T) {
  8567  	m := testModule(t, "apply-local-val")
  8568  	ctx := testContext2(t, &ContextOpts{
  8569  		Providers: map[addrs.Provider]providers.Factory{},
  8570  	})
  8571  
  8572  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8573  	assertNoErrors(t, diags)
  8574  
  8575  	state, diags := ctx.Apply(plan, m)
  8576  	if diags.HasErrors() {
  8577  		t.Fatalf("error during apply: %s", diags.Err())
  8578  	}
  8579  
  8580  	got := strings.TrimSpace(state.String())
  8581  	want := strings.TrimSpace(`
  8582  <no state>
  8583  Outputs:
  8584  
  8585  result_1 = hello
  8586  result_3 = hello world
  8587  `)
  8588  	if got != want {
  8589  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8590  	}
  8591  }
  8592  
  8593  func TestContext2Apply_destroyWithLocals(t *testing.T) {
  8594  	m := testModule(t, "apply-destroy-with-locals")
  8595  	p := testProvider("aws")
  8596  	p.PlanResourceChangeFn = testDiffFn
  8597  
  8598  	state := states.NewState()
  8599  	root := state.EnsureModule(addrs.RootModuleInstance)
  8600  	root.SetResourceInstanceCurrent(
  8601  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  8602  		&states.ResourceInstanceObjectSrc{
  8603  			Status:    states.ObjectReady,
  8604  			AttrsJSON: []byte(`{"id":"foo"}`),
  8605  		},
  8606  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8607  	)
  8608  	root.SetOutputValue("name", cty.StringVal("test-bar"), false)
  8609  
  8610  	ctx := testContext2(t, &ContextOpts{
  8611  		Providers: map[addrs.Provider]providers.Factory{
  8612  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8613  		},
  8614  	})
  8615  
  8616  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8617  		Mode: plans.DestroyMode,
  8618  	})
  8619  	assertNoErrors(t, diags)
  8620  
  8621  	s, diags := ctx.Apply(plan, m)
  8622  	if diags.HasErrors() {
  8623  		t.Fatalf("error during apply: %s", diags.Err())
  8624  	}
  8625  
  8626  	got := strings.TrimSpace(s.String())
  8627  	want := strings.TrimSpace(`<no state>`)
  8628  	if got != want {
  8629  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8630  	}
  8631  }
  8632  
  8633  func TestContext2Apply_providerWithLocals(t *testing.T) {
  8634  	m := testModule(t, "provider-with-locals")
  8635  	p := testProvider("aws")
  8636  
  8637  	providerRegion := ""
  8638  	// this should not be overridden during destroy
  8639  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  8640  		val := req.Config.GetAttr("region")
  8641  		if !val.IsNull() {
  8642  			providerRegion = val.AsString()
  8643  		}
  8644  
  8645  		return
  8646  	}
  8647  
  8648  	p.PlanResourceChangeFn = testDiffFn
  8649  	ctx := testContext2(t, &ContextOpts{
  8650  		Providers: map[addrs.Provider]providers.Factory{
  8651  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8652  		},
  8653  	})
  8654  
  8655  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8656  	assertNoErrors(t, diags)
  8657  
  8658  	state, diags := ctx.Apply(plan, m)
  8659  	if diags.HasErrors() {
  8660  		t.Fatalf("err: %s", diags.Err())
  8661  	}
  8662  
  8663  	ctx = testContext2(t, &ContextOpts{
  8664  		Providers: map[addrs.Provider]providers.Factory{
  8665  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8666  		},
  8667  	})
  8668  
  8669  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  8670  		Mode: plans.DestroyMode,
  8671  	})
  8672  	assertNoErrors(t, diags)
  8673  
  8674  	state, diags = ctx.Apply(plan, m)
  8675  	if diags.HasErrors() {
  8676  		t.Fatalf("err: %s", diags.Err())
  8677  	}
  8678  
  8679  	if state.HasManagedResourceInstanceObjects() {
  8680  		t.Fatal("expected no state, got:", state)
  8681  	}
  8682  
  8683  	if providerRegion != "bar" {
  8684  		t.Fatalf("expected region %q, got: %q", "bar", providerRegion)
  8685  	}
  8686  }
  8687  
  8688  func TestContext2Apply_destroyWithProviders(t *testing.T) {
  8689  	m := testModule(t, "destroy-module-with-provider")
  8690  	p := testProvider("aws")
  8691  	p.PlanResourceChangeFn = testDiffFn
  8692  
  8693  	state := states.NewState()
  8694  	removed := state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.NoKey).Child("removed", addrs.NoKey))
  8695  	removed.SetResourceInstanceCurrent(
  8696  		mustResourceInstanceAddr("aws_instance.child").Resource,
  8697  		&states.ResourceInstanceObjectSrc{
  8698  			Status:    states.ObjectReady,
  8699  			AttrsJSON: []byte(`{"id":"bar"}`),
  8700  		},
  8701  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].baz`),
  8702  	)
  8703  
  8704  	ctx := testContext2(t, &ContextOpts{
  8705  		Providers: map[addrs.Provider]providers.Factory{
  8706  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8707  		},
  8708  	})
  8709  
  8710  	// test that we can't destroy if the provider is missing
  8711  	if _, diags := ctx.Plan(m, state, &PlanOpts{Mode: plans.DestroyMode}); diags == nil {
  8712  		t.Fatal("expected plan error, provider.aws.baz doesn't exist")
  8713  	}
  8714  
  8715  	// correct the state
  8716  	state.Modules["module.mod.module.removed"].Resources["aws_instance.child"].ProviderConfig = mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].bar`)
  8717  
  8718  	ctx = testContext2(t, &ContextOpts{
  8719  		Providers: map[addrs.Provider]providers.Factory{
  8720  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8721  		},
  8722  	})
  8723  
  8724  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8725  		Mode: plans.DestroyMode,
  8726  	})
  8727  	assertNoErrors(t, diags)
  8728  
  8729  	state, diags = ctx.Apply(plan, m)
  8730  	if diags.HasErrors() {
  8731  		t.Fatalf("error during apply: %s", diags.Err())
  8732  	}
  8733  
  8734  	got := strings.TrimSpace(state.String())
  8735  
  8736  	want := strings.TrimSpace("<no state>")
  8737  	if got != want {
  8738  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8739  	}
  8740  }
  8741  
  8742  func TestContext2Apply_providersFromState(t *testing.T) {
  8743  	m := configs.NewEmptyConfig()
  8744  	p := testProvider("aws")
  8745  	p.PlanResourceChangeFn = testDiffFn
  8746  
  8747  	implicitProviderState := states.NewState()
  8748  	impRoot := implicitProviderState.EnsureModule(addrs.RootModuleInstance)
  8749  	impRoot.SetResourceInstanceCurrent(
  8750  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8751  		&states.ResourceInstanceObjectSrc{
  8752  			Status:    states.ObjectReady,
  8753  			AttrsJSON: []byte(`{"id":"bar"}`),
  8754  		},
  8755  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8756  	)
  8757  
  8758  	aliasedProviderState := states.NewState()
  8759  	aliasRoot := aliasedProviderState.EnsureModule(addrs.RootModuleInstance)
  8760  	aliasRoot.SetResourceInstanceCurrent(
  8761  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8762  		&states.ResourceInstanceObjectSrc{
  8763  			Status:    states.ObjectReady,
  8764  			AttrsJSON: []byte(`{"id":"bar"}`),
  8765  		},
  8766  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].bar`),
  8767  	)
  8768  
  8769  	moduleProviderState := states.NewState()
  8770  	moduleProviderRoot := moduleProviderState.EnsureModule(addrs.RootModuleInstance)
  8771  	moduleProviderRoot.SetResourceInstanceCurrent(
  8772  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8773  		&states.ResourceInstanceObjectSrc{
  8774  			Status:    states.ObjectReady,
  8775  			AttrsJSON: []byte(`{"id":"bar"}`),
  8776  		},
  8777  		mustProviderConfig(`module.child.provider["registry.terraform.io/hashicorp/aws"]`),
  8778  	)
  8779  
  8780  	for _, tc := range []struct {
  8781  		name   string
  8782  		state  *states.State
  8783  		output string
  8784  		err    bool
  8785  	}{
  8786  		{
  8787  			name:   "add implicit provider",
  8788  			state:  implicitProviderState,
  8789  			err:    false,
  8790  			output: "<no state>",
  8791  		},
  8792  
  8793  		// an aliased provider must be in the config to remove a resource
  8794  		{
  8795  			name:  "add aliased provider",
  8796  			state: aliasedProviderState,
  8797  			err:   true,
  8798  		},
  8799  
  8800  		// a provider in a module implies some sort of config, so this isn't
  8801  		// allowed even without an alias
  8802  		{
  8803  			name:  "add unaliased module provider",
  8804  			state: moduleProviderState,
  8805  			err:   true,
  8806  		},
  8807  	} {
  8808  		t.Run(tc.name, func(t *testing.T) {
  8809  			ctx := testContext2(t, &ContextOpts{
  8810  				Providers: map[addrs.Provider]providers.Factory{
  8811  					addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8812  				},
  8813  			})
  8814  
  8815  			plan, diags := ctx.Plan(m, tc.state, DefaultPlanOpts)
  8816  			if tc.err {
  8817  				if diags == nil {
  8818  					t.Fatal("expected error")
  8819  				} else {
  8820  					return
  8821  				}
  8822  			}
  8823  			if !tc.err && diags.HasErrors() {
  8824  				t.Fatal(diags.Err())
  8825  			}
  8826  
  8827  			state, diags := ctx.Apply(plan, m)
  8828  			if diags.HasErrors() {
  8829  				t.Fatalf("diags: %s", diags.Err())
  8830  			}
  8831  
  8832  			checkStateString(t, state, "<no state>")
  8833  
  8834  		})
  8835  	}
  8836  }
  8837  
  8838  func TestContext2Apply_plannedInterpolatedCount(t *testing.T) {
  8839  	m, snap := testModuleWithSnapshot(t, "apply-interpolated-count")
  8840  
  8841  	p := testProvider("aws")
  8842  	p.PlanResourceChangeFn = testDiffFn
  8843  
  8844  	Providers := map[addrs.Provider]providers.Factory{
  8845  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8846  	}
  8847  
  8848  	state := states.NewState()
  8849  	root := state.EnsureModule(addrs.RootModuleInstance)
  8850  	root.SetResourceInstanceCurrent(
  8851  		mustResourceInstanceAddr("aws_instance.test").Resource,
  8852  		&states.ResourceInstanceObjectSrc{
  8853  			Status:    states.ObjectReady,
  8854  			AttrsJSON: []byte(`{"id":"foo"}`),
  8855  		},
  8856  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8857  	)
  8858  
  8859  	ctx := testContext2(t, &ContextOpts{
  8860  		Providers: Providers,
  8861  	})
  8862  
  8863  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  8864  	if diags.HasErrors() {
  8865  		t.Fatalf("plan failed: %s", diags.Err())
  8866  	}
  8867  
  8868  	// We'll marshal and unmarshal the plan here, to ensure that we have
  8869  	// a clean new context as would be created if we separately ran
  8870  	// terraform plan -out=tfplan && terraform apply tfplan
  8871  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  8872  	if err != nil {
  8873  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8874  	}
  8875  
  8876  	ctxOpts.Providers = Providers
  8877  	ctx, diags = NewContext(ctxOpts)
  8878  	if diags.HasErrors() {
  8879  		t.Fatalf("err: %s", diags.Err())
  8880  	}
  8881  
  8882  	// Applying the plan should now succeed
  8883  	_, diags = ctx.Apply(plan, m)
  8884  	if diags.HasErrors() {
  8885  		t.Fatalf("apply failed: %s", diags.Err())
  8886  	}
  8887  }
  8888  
  8889  func TestContext2Apply_plannedDestroyInterpolatedCount(t *testing.T) {
  8890  	m, snap := testModuleWithSnapshot(t, "plan-destroy-interpolated-count")
  8891  
  8892  	p := testProvider("aws")
  8893  	p.PlanResourceChangeFn = testDiffFn
  8894  	providers := map[addrs.Provider]providers.Factory{
  8895  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8896  	}
  8897  
  8898  	state := states.NewState()
  8899  	root := state.EnsureModule(addrs.RootModuleInstance)
  8900  	root.SetResourceInstanceCurrent(
  8901  		mustResourceInstanceAddr("aws_instance.a[0]").Resource,
  8902  		&states.ResourceInstanceObjectSrc{
  8903  			Status:    states.ObjectReady,
  8904  			AttrsJSON: []byte(`{"id":"foo"}`),
  8905  		},
  8906  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8907  	)
  8908  	root.SetResourceInstanceCurrent(
  8909  		mustResourceInstanceAddr("aws_instance.a[1]").Resource,
  8910  		&states.ResourceInstanceObjectSrc{
  8911  			Status:    states.ObjectReady,
  8912  			AttrsJSON: []byte(`{"id":"foo"}`),
  8913  		},
  8914  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8915  	)
  8916  	root.SetOutputValue("out", cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("foo")}), false)
  8917  
  8918  	ctx := testContext2(t, &ContextOpts{
  8919  		Providers: providers,
  8920  	})
  8921  
  8922  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.DestroyMode, testInputValuesUnset(m.Module.Variables)))
  8923  	if diags.HasErrors() {
  8924  		t.Fatalf("plan failed: %s", diags.Err())
  8925  	}
  8926  
  8927  	// We'll marshal and unmarshal the plan here, to ensure that we have
  8928  	// a clean new context as would be created if we separately ran
  8929  	// terraform plan -out=tfplan && terraform apply tfplan
  8930  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  8931  	if err != nil {
  8932  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8933  	}
  8934  
  8935  	ctxOpts.Providers = providers
  8936  	ctx, diags = NewContext(ctxOpts)
  8937  	if diags.HasErrors() {
  8938  		t.Fatalf("err: %s", diags.Err())
  8939  	}
  8940  
  8941  	// Applying the plan should now succeed
  8942  	state, diags = ctx.Apply(plan, m)
  8943  	if diags.HasErrors() {
  8944  		t.Fatalf("apply failed: %s", diags.Err())
  8945  	}
  8946  	if !state.Empty() {
  8947  		t.Fatalf("state not empty: %s\n", state)
  8948  	}
  8949  }
  8950  
  8951  func TestContext2Apply_scaleInMultivarRef(t *testing.T) {
  8952  	m := testModule(t, "apply-resource-scale-in")
  8953  
  8954  	p := testProvider("aws")
  8955  	p.PlanResourceChangeFn = testDiffFn
  8956  
  8957  	Providers := map[addrs.Provider]providers.Factory{
  8958  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8959  	}
  8960  
  8961  	state := states.NewState()
  8962  	root := state.EnsureModule(addrs.RootModuleInstance)
  8963  	root.SetResourceInstanceCurrent(
  8964  		mustResourceInstanceAddr("aws_instance.one").Resource,
  8965  		&states.ResourceInstanceObjectSrc{
  8966  			Status:    states.ObjectReady,
  8967  			AttrsJSON: []byte(`{"id":"foo"}`),
  8968  		},
  8969  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8970  	)
  8971  	root.SetResourceInstanceCurrent(
  8972  		mustResourceInstanceAddr("aws_instance.two").Resource,
  8973  		&states.ResourceInstanceObjectSrc{
  8974  			Status:    states.ObjectReady,
  8975  			AttrsJSON: []byte(`{"id":"foo"}`),
  8976  		},
  8977  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8978  	)
  8979  
  8980  	ctx := testContext2(t, &ContextOpts{
  8981  		Providers: Providers,
  8982  	})
  8983  
  8984  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8985  		Mode: plans.NormalMode,
  8986  		SetVariables: InputValues{
  8987  			"instance_count": {
  8988  				Value:      cty.NumberIntVal(0),
  8989  				SourceType: ValueFromCaller,
  8990  			},
  8991  		},
  8992  	})
  8993  	assertNoErrors(t, diags)
  8994  	{
  8995  		addr := mustResourceInstanceAddr("aws_instance.one[0]")
  8996  		change := plan.Changes.ResourceInstance(addr)
  8997  		if change == nil {
  8998  			t.Fatalf("no planned change for %s", addr)
  8999  		}
  9000  		// This test was originally written with Terraform v0.11 and earlier
  9001  		// in mind, so it declares a no-key instance of aws_instance.one,
  9002  		// but its configuration sets count (to zero) and so we end up first
  9003  		// moving the no-key instance to the zero key and then planning to
  9004  		// destroy the zero key.
  9005  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("aws_instance.one"); !want.Equal(got) {
  9006  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
  9007  		}
  9008  		if got, want := change.Action, plans.Delete; got != want {
  9009  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  9010  		}
  9011  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
  9012  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
  9013  		}
  9014  	}
  9015  	{
  9016  		addr := mustResourceInstanceAddr("aws_instance.two")
  9017  		change := plan.Changes.ResourceInstance(addr)
  9018  		if change == nil {
  9019  			t.Fatalf("no planned change for %s", addr)
  9020  		}
  9021  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("aws_instance.two"); !want.Equal(got) {
  9022  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
  9023  		}
  9024  		if got, want := change.Action, plans.Update; got != want {
  9025  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
  9026  		}
  9027  		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
  9028  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
  9029  		}
  9030  	}
  9031  
  9032  	// Applying the plan should now succeed
  9033  	_, diags = ctx.Apply(plan, m)
  9034  	assertNoErrors(t, diags)
  9035  }
  9036  
  9037  func TestContext2Apply_inconsistentWithPlan(t *testing.T) {
  9038  	m := testModule(t, "apply-inconsistent-with-plan")
  9039  	p := testProvider("test")
  9040  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9041  		ResourceTypes: map[string]*configschema.Block{
  9042  			"test": {
  9043  				Attributes: map[string]*configschema.Attribute{
  9044  					"id": {Type: cty.String, Computed: true},
  9045  				},
  9046  			},
  9047  		},
  9048  	})
  9049  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  9050  		return providers.PlanResourceChangeResponse{
  9051  			PlannedState: cty.ObjectVal(map[string]cty.Value{
  9052  				"id": cty.StringVal("before"),
  9053  			}),
  9054  		}
  9055  	}
  9056  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9057  		return providers.ApplyResourceChangeResponse{
  9058  			NewState: cty.ObjectVal(map[string]cty.Value{
  9059  				// This is intentionally incorrect: because id was fixed at "before"
  9060  				// during plan, it must not change during apply.
  9061  				"id": cty.StringVal("after"),
  9062  			}),
  9063  		}
  9064  	}
  9065  	ctx := testContext2(t, &ContextOpts{
  9066  		Providers: map[addrs.Provider]providers.Factory{
  9067  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9068  		},
  9069  	})
  9070  
  9071  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9072  	assertNoErrors(t, diags)
  9073  
  9074  	_, diags = ctx.Apply(plan, m)
  9075  	if !diags.HasErrors() {
  9076  		t.Fatalf("apply succeeded; want error")
  9077  	}
  9078  	if got, want := diags.Err().Error(), "Provider produced inconsistent result after apply"; !strings.Contains(got, want) {
  9079  		t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want)
  9080  	}
  9081  }
  9082  
  9083  // Issue 19908 was about retaining an existing object in the state when an
  9084  // update to it fails and the provider does not return a partially-updated
  9085  // value for it. Previously we were incorrectly removing it from the state
  9086  // in that case, but instead it should be retained so the update can be
  9087  // retried.
  9088  func TestContext2Apply_issue19908(t *testing.T) {
  9089  	m := testModule(t, "apply-issue19908")
  9090  	p := testProvider("test")
  9091  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9092  		ResourceTypes: map[string]*configschema.Block{
  9093  			"test": {
  9094  				Attributes: map[string]*configschema.Attribute{
  9095  					"baz": {Type: cty.String, Required: true},
  9096  				},
  9097  			},
  9098  		},
  9099  	})
  9100  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  9101  		return providers.PlanResourceChangeResponse{
  9102  			PlannedState: req.ProposedNewState,
  9103  		}
  9104  	}
  9105  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9106  		var diags tfdiags.Diagnostics
  9107  		diags = diags.Append(fmt.Errorf("update failed"))
  9108  		return providers.ApplyResourceChangeResponse{
  9109  			Diagnostics: diags,
  9110  		}
  9111  	}
  9112  	ctx := testContext2(t, &ContextOpts{
  9113  		Providers: map[addrs.Provider]providers.Factory{
  9114  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9115  		},
  9116  	})
  9117  
  9118  	state := states.BuildState(func(s *states.SyncState) {
  9119  		s.SetResourceInstanceCurrent(
  9120  			addrs.Resource{
  9121  				Mode: addrs.ManagedResourceMode,
  9122  				Type: "test",
  9123  				Name: "foo",
  9124  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  9125  			&states.ResourceInstanceObjectSrc{
  9126  				AttrsJSON: []byte(`{"baz":"old"}`),
  9127  				Status:    states.ObjectReady,
  9128  			},
  9129  			addrs.AbsProviderConfig{
  9130  				Provider: addrs.NewDefaultProvider("test"),
  9131  				Module:   addrs.RootModule,
  9132  			},
  9133  		)
  9134  	})
  9135  
  9136  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9137  	assertNoErrors(t, diags)
  9138  
  9139  	state, diags = ctx.Apply(plan, m)
  9140  	if !diags.HasErrors() {
  9141  		t.Fatalf("apply succeeded; want error")
  9142  	}
  9143  	if got, want := diags.Err().Error(), "update failed"; !strings.Contains(got, want) {
  9144  		t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want)
  9145  	}
  9146  
  9147  	mod := state.RootModule()
  9148  	rs := mod.Resources["test.foo"]
  9149  	if rs == nil {
  9150  		t.Fatalf("test.foo not in state after apply, but should be")
  9151  	}
  9152  	is := rs.Instances[addrs.NoKey]
  9153  	if is == nil {
  9154  		t.Fatalf("test.foo not in state after apply, but should be")
  9155  	}
  9156  	obj := is.Current
  9157  	if obj == nil {
  9158  		t.Fatalf("test.foo has no current object in state after apply, but should do")
  9159  	}
  9160  
  9161  	if got, want := obj.Status, states.ObjectReady; got != want {
  9162  		t.Errorf("test.foo has wrong status %s after apply; want %s", got, want)
  9163  	}
  9164  	if got, want := obj.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) {
  9165  		t.Errorf("test.foo attributes JSON doesn't contain %s after apply\ngot: %s", want, got)
  9166  	}
  9167  }
  9168  
  9169  func TestContext2Apply_invalidIndexRef(t *testing.T) {
  9170  	p := testProvider("test")
  9171  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9172  		ResourceTypes: map[string]*configschema.Block{
  9173  			"test_instance": {
  9174  				Attributes: map[string]*configschema.Attribute{
  9175  					"value": {Type: cty.String, Optional: true, Computed: true},
  9176  				},
  9177  			},
  9178  		},
  9179  	})
  9180  	p.PlanResourceChangeFn = testDiffFn
  9181  
  9182  	m := testModule(t, "apply-invalid-index")
  9183  	c := testContext2(t, &ContextOpts{
  9184  		Providers: map[addrs.Provider]providers.Factory{
  9185  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9186  		},
  9187  	})
  9188  	diags := c.Validate(m)
  9189  	if diags.HasErrors() {
  9190  		t.Fatalf("unexpected validation failure: %s", diags.Err())
  9191  	}
  9192  
  9193  	wantErr := `The given key does not identify an element in this collection value`
  9194  	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
  9195  
  9196  	if !diags.HasErrors() {
  9197  		t.Fatalf("plan succeeded; want error")
  9198  	}
  9199  	gotErr := diags.Err().Error()
  9200  
  9201  	if !strings.Contains(gotErr, wantErr) {
  9202  		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErr, wantErr)
  9203  	}
  9204  }
  9205  
  9206  func TestContext2Apply_moduleReplaceCycle(t *testing.T) {
  9207  	for _, mode := range []string{"normal", "cbd"} {
  9208  		var m *configs.Config
  9209  
  9210  		switch mode {
  9211  		case "normal":
  9212  			m = testModule(t, "apply-module-replace-cycle")
  9213  		case "cbd":
  9214  			m = testModule(t, "apply-module-replace-cycle-cbd")
  9215  		}
  9216  
  9217  		p := testProvider("aws")
  9218  		p.PlanResourceChangeFn = testDiffFn
  9219  
  9220  		instanceSchema := &configschema.Block{
  9221  			Attributes: map[string]*configschema.Attribute{
  9222  				"id":          {Type: cty.String, Computed: true},
  9223  				"require_new": {Type: cty.String, Optional: true},
  9224  			},
  9225  		}
  9226  
  9227  		p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9228  			ResourceTypes: map[string]*configschema.Block{
  9229  				"aws_instance": instanceSchema,
  9230  			},
  9231  		})
  9232  
  9233  		state := states.NewState()
  9234  		modA := state.EnsureModule(addrs.RootModuleInstance.Child("a", addrs.NoKey))
  9235  		modA.SetResourceInstanceCurrent(
  9236  			addrs.Resource{
  9237  				Mode: addrs.ManagedResourceMode,
  9238  				Type: "aws_instance",
  9239  				Name: "a",
  9240  			}.Instance(addrs.NoKey),
  9241  			&states.ResourceInstanceObjectSrc{
  9242  				Status:              states.ObjectReady,
  9243  				AttrsJSON:           []byte(`{"id":"a","require_new":"old"}`),
  9244  				CreateBeforeDestroy: mode == "cbd",
  9245  			},
  9246  			addrs.AbsProviderConfig{
  9247  				Provider: addrs.NewDefaultProvider("aws"),
  9248  				Module:   addrs.RootModule,
  9249  			},
  9250  		)
  9251  
  9252  		modB := state.EnsureModule(addrs.RootModuleInstance.Child("b", addrs.NoKey))
  9253  		modB.SetResourceInstanceCurrent(
  9254  			addrs.Resource{
  9255  				Mode: addrs.ManagedResourceMode,
  9256  				Type: "aws_instance",
  9257  				Name: "b",
  9258  			}.Instance(addrs.IntKey(0)),
  9259  			&states.ResourceInstanceObjectSrc{
  9260  				Status:    states.ObjectReady,
  9261  				AttrsJSON: []byte(`{"id":"b","require_new":"old"}`),
  9262  			},
  9263  			addrs.AbsProviderConfig{
  9264  				Provider: addrs.NewDefaultProvider("aws"),
  9265  				Module:   addrs.RootModule,
  9266  			},
  9267  		)
  9268  
  9269  		aBefore, _ := plans.NewDynamicValue(
  9270  			cty.ObjectVal(map[string]cty.Value{
  9271  				"id":          cty.StringVal("a"),
  9272  				"require_new": cty.StringVal("old"),
  9273  			}), instanceSchema.ImpliedType())
  9274  		aAfter, _ := plans.NewDynamicValue(
  9275  			cty.ObjectVal(map[string]cty.Value{
  9276  				"id":          cty.UnknownVal(cty.String),
  9277  				"require_new": cty.StringVal("new"),
  9278  			}), instanceSchema.ImpliedType())
  9279  		bBefore, _ := plans.NewDynamicValue(
  9280  			cty.ObjectVal(map[string]cty.Value{
  9281  				"id":          cty.StringVal("b"),
  9282  				"require_new": cty.StringVal("old"),
  9283  			}), instanceSchema.ImpliedType())
  9284  		bAfter, _ := plans.NewDynamicValue(
  9285  			cty.ObjectVal(map[string]cty.Value{
  9286  				"id":          cty.UnknownVal(cty.String),
  9287  				"require_new": cty.UnknownVal(cty.String),
  9288  			}), instanceSchema.ImpliedType())
  9289  
  9290  		var aAction plans.Action
  9291  		switch mode {
  9292  		case "normal":
  9293  			aAction = plans.DeleteThenCreate
  9294  		case "cbd":
  9295  			aAction = plans.CreateThenDelete
  9296  		}
  9297  
  9298  		ctx := testContext2(t, &ContextOpts{
  9299  			Providers: map[addrs.Provider]providers.Factory{
  9300  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  9301  			},
  9302  		})
  9303  
  9304  		changes := &plans.Changes{
  9305  			Resources: []*plans.ResourceInstanceChangeSrc{
  9306  				{
  9307  					Addr: addrs.Resource{
  9308  						Mode: addrs.ManagedResourceMode,
  9309  						Type: "aws_instance",
  9310  						Name: "a",
  9311  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("a", addrs.NoKey)),
  9312  					ProviderAddr: addrs.AbsProviderConfig{
  9313  						Provider: addrs.NewDefaultProvider("aws"),
  9314  						Module:   addrs.RootModule,
  9315  					},
  9316  					ChangeSrc: plans.ChangeSrc{
  9317  						Action: aAction,
  9318  						Before: aBefore,
  9319  						After:  aAfter,
  9320  					},
  9321  				},
  9322  				{
  9323  					Addr: addrs.Resource{
  9324  						Mode: addrs.ManagedResourceMode,
  9325  						Type: "aws_instance",
  9326  						Name: "b",
  9327  					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("b", addrs.NoKey)),
  9328  					ProviderAddr: addrs.AbsProviderConfig{
  9329  						Provider: addrs.NewDefaultProvider("aws"),
  9330  						Module:   addrs.RootModule,
  9331  					},
  9332  					ChangeSrc: plans.ChangeSrc{
  9333  						Action: plans.DeleteThenCreate,
  9334  						Before: bBefore,
  9335  						After:  bAfter,
  9336  					},
  9337  				},
  9338  			},
  9339  		}
  9340  
  9341  		plan := &plans.Plan{
  9342  			UIMode:       plans.NormalMode,
  9343  			Changes:      changes,
  9344  			PriorState:   state.DeepCopy(),
  9345  			PrevRunState: state.DeepCopy(),
  9346  		}
  9347  
  9348  		t.Run(mode, func(t *testing.T) {
  9349  			_, diags := ctx.Apply(plan, m)
  9350  			if diags.HasErrors() {
  9351  				t.Fatal(diags.Err())
  9352  			}
  9353  		})
  9354  	}
  9355  }
  9356  
  9357  func TestContext2Apply_destroyDataCycle(t *testing.T) {
  9358  	m, snap := testModuleWithSnapshot(t, "apply-destroy-data-cycle")
  9359  	p := testProvider("null")
  9360  	p.PlanResourceChangeFn = testDiffFn
  9361  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  9362  		return providers.ReadDataSourceResponse{
  9363  			State: cty.ObjectVal(map[string]cty.Value{
  9364  				"id":  cty.StringVal("new"),
  9365  				"foo": cty.NullVal(cty.String),
  9366  			}),
  9367  		}
  9368  	}
  9369  
  9370  	tp := testProvider("test")
  9371  	tp.PlanResourceChangeFn = testDiffFn
  9372  
  9373  	state := states.NewState()
  9374  	root := state.EnsureModule(addrs.RootModuleInstance)
  9375  	root.SetResourceInstanceCurrent(
  9376  		addrs.Resource{
  9377  			Mode: addrs.ManagedResourceMode,
  9378  			Type: "null_resource",
  9379  			Name: "a",
  9380  		}.Instance(addrs.IntKey(0)),
  9381  		&states.ResourceInstanceObjectSrc{
  9382  			Status:    states.ObjectReady,
  9383  			AttrsJSON: []byte(`{"id":"a"}`),
  9384  		},
  9385  		addrs.AbsProviderConfig{
  9386  			Provider: addrs.NewDefaultProvider("null"),
  9387  			Module:   addrs.RootModule,
  9388  		},
  9389  	)
  9390  	root.SetResourceInstanceCurrent(
  9391  		addrs.Resource{
  9392  			Mode: addrs.ManagedResourceMode,
  9393  			Type: "test_resource",
  9394  			Name: "a",
  9395  		}.Instance(addrs.IntKey(0)),
  9396  		&states.ResourceInstanceObjectSrc{
  9397  			Status:    states.ObjectReady,
  9398  			AttrsJSON: []byte(`{"id":"a"}`),
  9399  			Dependencies: []addrs.ConfigResource{
  9400  				{
  9401  					Resource: addrs.Resource{
  9402  						Mode: addrs.DataResourceMode,
  9403  						Type: "null_data_source",
  9404  						Name: "d",
  9405  					},
  9406  					Module: addrs.RootModule,
  9407  				},
  9408  			},
  9409  		},
  9410  		addrs.AbsProviderConfig{
  9411  			Provider: addrs.NewDefaultProvider("test"),
  9412  			Module:   addrs.RootModule,
  9413  		},
  9414  	)
  9415  	root.SetResourceInstanceCurrent(
  9416  		addrs.Resource{
  9417  			Mode: addrs.DataResourceMode,
  9418  			Type: "null_data_source",
  9419  			Name: "d",
  9420  		}.Instance(addrs.NoKey),
  9421  		&states.ResourceInstanceObjectSrc{
  9422  			Status:    states.ObjectReady,
  9423  			AttrsJSON: []byte(`{"id":"old"}`),
  9424  		},
  9425  		addrs.AbsProviderConfig{
  9426  			Provider: addrs.NewDefaultProvider("null"),
  9427  			Module:   addrs.RootModule,
  9428  		},
  9429  	)
  9430  
  9431  	Providers := map[addrs.Provider]providers.Factory{
  9432  		addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  9433  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(tp),
  9434  	}
  9435  
  9436  	ctx := testContext2(t, &ContextOpts{
  9437  		Providers: Providers,
  9438  	})
  9439  
  9440  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  9441  		Mode: plans.DestroyMode,
  9442  	})
  9443  	diags.HasErrors()
  9444  	if diags.HasErrors() {
  9445  		t.Fatalf("diags: %s", diags.Err())
  9446  	}
  9447  
  9448  	// We'll marshal and unmarshal the plan here, to ensure that we have
  9449  	// a clean new context as would be created if we separately ran
  9450  	// terraform plan -out=tfplan && terraform apply tfplan
  9451  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  9452  	if err != nil {
  9453  		t.Fatal(err)
  9454  	}
  9455  	ctxOpts.Providers = Providers
  9456  	ctx, diags = NewContext(ctxOpts)
  9457  	if diags.HasErrors() {
  9458  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  9459  	}
  9460  
  9461  	tp.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  9462  		foo := req.Config.GetAttr("foo")
  9463  		if !foo.IsKnown() {
  9464  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown config value foo"))
  9465  			return resp
  9466  		}
  9467  
  9468  		if foo.AsString() != "new" {
  9469  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("wrong config value: %q", foo.AsString()))
  9470  		}
  9471  		return resp
  9472  	}
  9473  
  9474  	_, diags = ctx.Apply(plan, m)
  9475  	if diags.HasErrors() {
  9476  		t.Fatalf("diags: %s", diags.Err())
  9477  	}
  9478  }
  9479  
  9480  func TestContext2Apply_taintedDestroyFailure(t *testing.T) {
  9481  	m := testModule(t, "apply-destroy-tainted")
  9482  	p := testProvider("test")
  9483  	p.PlanResourceChangeFn = testDiffFn
  9484  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  9485  		// All destroys fail.
  9486  		if req.PlannedState.IsNull() {
  9487  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure"))
  9488  			return
  9489  		}
  9490  
  9491  		// c will also fail to create, meaning the existing tainted instance
  9492  		// becomes deposed, ans is then promoted back to current.
  9493  		// only C has a foo attribute
  9494  		planned := req.PlannedState.AsValueMap()
  9495  		foo, ok := planned["foo"]
  9496  		if ok && !foo.IsNull() && foo.AsString() == "c" {
  9497  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure"))
  9498  			return
  9499  		}
  9500  
  9501  		return testApplyFn(req)
  9502  	}
  9503  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9504  		ResourceTypes: map[string]*configschema.Block{
  9505  			"test_instance": {
  9506  				Attributes: map[string]*configschema.Attribute{
  9507  					"id": {
  9508  						Type:     cty.String,
  9509  						Computed: true,
  9510  					},
  9511  					"foo": {
  9512  						Type:     cty.String,
  9513  						Optional: true,
  9514  					},
  9515  				},
  9516  			},
  9517  		},
  9518  	})
  9519  
  9520  	state := states.NewState()
  9521  	root := state.EnsureModule(addrs.RootModuleInstance)
  9522  	root.SetResourceInstanceCurrent(
  9523  		addrs.Resource{
  9524  			Mode: addrs.ManagedResourceMode,
  9525  			Type: "test_instance",
  9526  			Name: "a",
  9527  		}.Instance(addrs.NoKey),
  9528  		&states.ResourceInstanceObjectSrc{
  9529  			Status:    states.ObjectTainted,
  9530  			AttrsJSON: []byte(`{"id":"a","foo":"a"}`),
  9531  		},
  9532  		addrs.AbsProviderConfig{
  9533  			Provider: addrs.NewDefaultProvider("test"),
  9534  			Module:   addrs.RootModule,
  9535  		},
  9536  	)
  9537  	root.SetResourceInstanceCurrent(
  9538  		addrs.Resource{
  9539  			Mode: addrs.ManagedResourceMode,
  9540  			Type: "test_instance",
  9541  			Name: "b",
  9542  		}.Instance(addrs.NoKey),
  9543  		&states.ResourceInstanceObjectSrc{
  9544  			Status:    states.ObjectTainted,
  9545  			AttrsJSON: []byte(`{"id":"b","foo":"b"}`),
  9546  		},
  9547  		addrs.AbsProviderConfig{
  9548  			Provider: addrs.NewDefaultProvider("test"),
  9549  			Module:   addrs.RootModule,
  9550  		},
  9551  	)
  9552  	root.SetResourceInstanceCurrent(
  9553  		addrs.Resource{
  9554  			Mode: addrs.ManagedResourceMode,
  9555  			Type: "test_instance",
  9556  			Name: "c",
  9557  		}.Instance(addrs.NoKey),
  9558  		&states.ResourceInstanceObjectSrc{
  9559  			Status:    states.ObjectTainted,
  9560  			AttrsJSON: []byte(`{"id":"c","foo":"old"}`),
  9561  		},
  9562  		addrs.AbsProviderConfig{
  9563  			Provider: addrs.NewDefaultProvider("test"),
  9564  			Module:   addrs.RootModule,
  9565  		},
  9566  	)
  9567  
  9568  	Providers := map[addrs.Provider]providers.Factory{
  9569  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9570  	}
  9571  
  9572  	ctx := testContext2(t, &ContextOpts{
  9573  		Providers: Providers,
  9574  		Hooks:     []Hook{&testHook{}},
  9575  	})
  9576  
  9577  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9578  	diags.HasErrors()
  9579  	if diags.HasErrors() {
  9580  		t.Fatalf("diags: %s", diags.Err())
  9581  	}
  9582  
  9583  	state, diags = ctx.Apply(plan, m)
  9584  	if !diags.HasErrors() {
  9585  		t.Fatal("expected error")
  9586  	}
  9587  
  9588  	root = state.Module(addrs.RootModuleInstance)
  9589  
  9590  	// the instance that failed to destroy should remain tainted
  9591  	a := root.ResourceInstance(addrs.Resource{
  9592  		Mode: addrs.ManagedResourceMode,
  9593  		Type: "test_instance",
  9594  		Name: "a",
  9595  	}.Instance(addrs.NoKey))
  9596  
  9597  	if a.Current.Status != states.ObjectTainted {
  9598  		t.Fatal("test_instance.a should be tainted")
  9599  	}
  9600  
  9601  	// b is create_before_destroy, and the destroy failed, so there should be 1
  9602  	// deposed instance.
  9603  	b := root.ResourceInstance(addrs.Resource{
  9604  		Mode: addrs.ManagedResourceMode,
  9605  		Type: "test_instance",
  9606  		Name: "b",
  9607  	}.Instance(addrs.NoKey))
  9608  
  9609  	if b.Current.Status != states.ObjectReady {
  9610  		t.Fatal("test_instance.b should be Ready")
  9611  	}
  9612  
  9613  	if len(b.Deposed) != 1 {
  9614  		t.Fatal("test_instance.b failed to keep deposed instance")
  9615  	}
  9616  
  9617  	// the desposed c instance should be promoted back to Current, and remain
  9618  	// tainted
  9619  	c := root.ResourceInstance(addrs.Resource{
  9620  		Mode: addrs.ManagedResourceMode,
  9621  		Type: "test_instance",
  9622  		Name: "c",
  9623  	}.Instance(addrs.NoKey))
  9624  
  9625  	if c.Current == nil {
  9626  		t.Fatal("test_instance.c has no current instance, but it should")
  9627  	}
  9628  
  9629  	if c.Current.Status != states.ObjectTainted {
  9630  		t.Fatal("test_instance.c should be tainted")
  9631  	}
  9632  
  9633  	if len(c.Deposed) != 0 {
  9634  		t.Fatal("test_instance.c should have no deposed instances")
  9635  	}
  9636  
  9637  	if string(c.Current.AttrsJSON) != `{"foo":"old","id":"c"}` {
  9638  		t.Fatalf("unexpected attrs for c: %q\n", c.Current.AttrsJSON)
  9639  	}
  9640  }
  9641  
  9642  func TestContext2Apply_plannedConnectionRefs(t *testing.T) {
  9643  	m := testModule(t, "apply-plan-connection-refs")
  9644  	p := testProvider("test")
  9645  	p.PlanResourceChangeFn = testDiffFn
  9646  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  9647  		s := req.PlannedState.AsValueMap()
  9648  		// delay "a" slightly, so if the reference edge is missing the "b"
  9649  		// provisioner will see an unknown value.
  9650  		if s["foo"].AsString() == "a" {
  9651  			time.Sleep(500 * time.Millisecond)
  9652  		}
  9653  
  9654  		s["id"] = cty.StringVal("ID")
  9655  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
  9656  			s["type"] = cty.StringVal(req.TypeName)
  9657  		}
  9658  		resp.NewState = cty.ObjectVal(s)
  9659  		return resp
  9660  	}
  9661  
  9662  	provisionerFactory := func() (provisioners.Interface, error) {
  9663  		pr := testProvisioner()
  9664  		pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  9665  			host := req.Connection.GetAttr("host")
  9666  			if host.IsNull() || !host.IsKnown() {
  9667  				resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("invalid host value: %#v", host))
  9668  			}
  9669  
  9670  			return resp
  9671  		}
  9672  		return pr, nil
  9673  	}
  9674  
  9675  	Providers := map[addrs.Provider]providers.Factory{
  9676  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9677  	}
  9678  
  9679  	provisioners := map[string]provisioners.Factory{
  9680  		"shell": provisionerFactory,
  9681  	}
  9682  
  9683  	hook := &testHook{}
  9684  	ctx := testContext2(t, &ContextOpts{
  9685  		Providers:    Providers,
  9686  		Provisioners: provisioners,
  9687  		Hooks:        []Hook{hook},
  9688  	})
  9689  
  9690  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  9691  	diags.HasErrors()
  9692  	if diags.HasErrors() {
  9693  		t.Fatalf("diags: %s", diags.Err())
  9694  	}
  9695  
  9696  	_, diags = ctx.Apply(plan, m)
  9697  	if diags.HasErrors() {
  9698  		t.Fatalf("diags: %s", diags.Err())
  9699  	}
  9700  }
  9701  
  9702  func TestContext2Apply_cbdCycle(t *testing.T) {
  9703  	m, snap := testModuleWithSnapshot(t, "apply-cbd-cycle")
  9704  	p := testProvider("test")
  9705  	p.PlanResourceChangeFn = testDiffFn
  9706  
  9707  	state := states.NewState()
  9708  	root := state.EnsureModule(addrs.RootModuleInstance)
  9709  	root.SetResourceInstanceCurrent(
  9710  		addrs.Resource{
  9711  			Mode: addrs.ManagedResourceMode,
  9712  			Type: "test_instance",
  9713  			Name: "a",
  9714  		}.Instance(addrs.NoKey),
  9715  		&states.ResourceInstanceObjectSrc{
  9716  			Status:    states.ObjectReady,
  9717  			AttrsJSON: []byte(`{"id":"a","require_new":"old","foo":"b"}`),
  9718  			Dependencies: []addrs.ConfigResource{
  9719  				{
  9720  					Resource: addrs.Resource{
  9721  						Mode: addrs.ManagedResourceMode,
  9722  						Type: "test_instance",
  9723  						Name: "b",
  9724  					},
  9725  					Module: addrs.RootModule,
  9726  				},
  9727  				{
  9728  					Resource: addrs.Resource{
  9729  						Mode: addrs.ManagedResourceMode,
  9730  						Type: "test_instance",
  9731  						Name: "c",
  9732  					},
  9733  					Module: addrs.RootModule,
  9734  				},
  9735  			},
  9736  		},
  9737  		addrs.AbsProviderConfig{
  9738  			Provider: addrs.NewDefaultProvider("test"),
  9739  			Module:   addrs.RootModule,
  9740  		},
  9741  	)
  9742  	root.SetResourceInstanceCurrent(
  9743  		addrs.Resource{
  9744  			Mode: addrs.ManagedResourceMode,
  9745  			Type: "test_instance",
  9746  			Name: "b",
  9747  		}.Instance(addrs.NoKey),
  9748  		&states.ResourceInstanceObjectSrc{
  9749  			Status:    states.ObjectReady,
  9750  			AttrsJSON: []byte(`{"id":"b","require_new":"old","foo":"c"}`),
  9751  			Dependencies: []addrs.ConfigResource{
  9752  				{
  9753  					Resource: addrs.Resource{
  9754  						Mode: addrs.ManagedResourceMode,
  9755  						Type: "test_instance",
  9756  						Name: "c",
  9757  					},
  9758  					Module: addrs.RootModule,
  9759  				},
  9760  			},
  9761  		},
  9762  		addrs.AbsProviderConfig{
  9763  			Provider: addrs.NewDefaultProvider("test"),
  9764  			Module:   addrs.RootModule,
  9765  		},
  9766  	)
  9767  	root.SetResourceInstanceCurrent(
  9768  		addrs.Resource{
  9769  			Mode: addrs.ManagedResourceMode,
  9770  			Type: "test_instance",
  9771  			Name: "c",
  9772  		}.Instance(addrs.NoKey),
  9773  		&states.ResourceInstanceObjectSrc{
  9774  			Status:    states.ObjectReady,
  9775  			AttrsJSON: []byte(`{"id":"c","require_new":"old"}`),
  9776  		},
  9777  		addrs.AbsProviderConfig{
  9778  			Provider: addrs.NewDefaultProvider("test"),
  9779  			Module:   addrs.RootModule,
  9780  		},
  9781  	)
  9782  
  9783  	Providers := map[addrs.Provider]providers.Factory{
  9784  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9785  	}
  9786  
  9787  	hook := &testHook{}
  9788  	ctx := testContext2(t, &ContextOpts{
  9789  		Providers: Providers,
  9790  		Hooks:     []Hook{hook},
  9791  	})
  9792  
  9793  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9794  	diags.HasErrors()
  9795  	if diags.HasErrors() {
  9796  		t.Fatalf("diags: %s", diags.Err())
  9797  	}
  9798  
  9799  	// We'll marshal and unmarshal the plan here, to ensure that we have
  9800  	// a clean new context as would be created if we separately ran
  9801  	// terraform plan -out=tfplan && terraform apply tfplan
  9802  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(t, snap, plan)
  9803  	if err != nil {
  9804  		t.Fatal(err)
  9805  	}
  9806  	ctxOpts.Providers = Providers
  9807  	ctx, diags = NewContext(ctxOpts)
  9808  	if diags.HasErrors() {
  9809  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  9810  	}
  9811  
  9812  	_, diags = ctx.Apply(plan, m)
  9813  	if diags.HasErrors() {
  9814  		t.Fatalf("diags: %s", diags.Err())
  9815  	}
  9816  }
  9817  
  9818  func TestContext2Apply_ProviderMeta_apply_set(t *testing.T) {
  9819  	m := testModule(t, "provider-meta-set")
  9820  	p := testProvider("test")
  9821  	p.PlanResourceChangeFn = testDiffFn
  9822  	schema := p.ProviderSchema()
  9823  	schema.ProviderMeta = &configschema.Block{
  9824  		Attributes: map[string]*configschema.Attribute{
  9825  			"baz": {
  9826  				Type:     cty.String,
  9827  				Required: true,
  9828  			},
  9829  		},
  9830  	}
  9831  
  9832  	var pmMu sync.Mutex
  9833  	arcPMs := map[string]cty.Value{}
  9834  
  9835  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9836  		pmMu.Lock()
  9837  		defer pmMu.Unlock()
  9838  		arcPMs[req.TypeName] = req.ProviderMeta
  9839  
  9840  		s := req.PlannedState.AsValueMap()
  9841  		s["id"] = cty.StringVal("ID")
  9842  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
  9843  			s["type"] = cty.StringVal(req.TypeName)
  9844  		}
  9845  		return providers.ApplyResourceChangeResponse{
  9846  			NewState: cty.ObjectVal(s),
  9847  		}
  9848  	}
  9849  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9850  	ctx := testContext2(t, &ContextOpts{
  9851  		Providers: map[addrs.Provider]providers.Factory{
  9852  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9853  		},
  9854  	})
  9855  
  9856  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9857  	assertNoErrors(t, diags)
  9858  
  9859  	_, diags = ctx.Apply(plan, m)
  9860  	assertNoErrors(t, diags)
  9861  
  9862  	if !p.ApplyResourceChangeCalled {
  9863  		t.Fatalf("ApplyResourceChange not called")
  9864  	}
  9865  
  9866  	expectations := map[string]cty.Value{}
  9867  
  9868  	if pm, ok := arcPMs["test_resource"]; !ok {
  9869  		t.Fatalf("sub-module ApplyResourceChange not called")
  9870  	} else if pm.IsNull() {
  9871  		t.Fatalf("null ProviderMeta in sub-module ApplyResourceChange")
  9872  	} else {
  9873  		expectations["quux-submodule"] = pm
  9874  	}
  9875  
  9876  	if pm, ok := arcPMs["test_instance"]; !ok {
  9877  		t.Fatalf("root module ApplyResourceChange not called")
  9878  	} else if pm.IsNull() {
  9879  		t.Fatalf("null ProviderMeta in root module ApplyResourceChange")
  9880  	} else {
  9881  		expectations["quux"] = pm
  9882  	}
  9883  
  9884  	type metaStruct struct {
  9885  		Baz string `cty:"baz"`
  9886  	}
  9887  
  9888  	for expected, v := range expectations {
  9889  		var meta metaStruct
  9890  		err := gocty.FromCtyValue(v, &meta)
  9891  		if err != nil {
  9892  			t.Fatalf("Error parsing cty value: %s", err)
  9893  		}
  9894  		if meta.Baz != expected {
  9895  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
  9896  		}
  9897  	}
  9898  }
  9899  
  9900  func TestContext2Apply_ProviderMeta_apply_unset(t *testing.T) {
  9901  	m := testModule(t, "provider-meta-unset")
  9902  	p := testProvider("test")
  9903  	p.PlanResourceChangeFn = testDiffFn
  9904  	schema := p.ProviderSchema()
  9905  	schema.ProviderMeta = &configschema.Block{
  9906  		Attributes: map[string]*configschema.Attribute{
  9907  			"baz": {
  9908  				Type:     cty.String,
  9909  				Required: true,
  9910  			},
  9911  		},
  9912  	}
  9913  	var pmMu sync.Mutex
  9914  	arcPMs := map[string]cty.Value{}
  9915  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9916  		pmMu.Lock()
  9917  		defer pmMu.Unlock()
  9918  		arcPMs[req.TypeName] = req.ProviderMeta
  9919  
  9920  		s := req.PlannedState.AsValueMap()
  9921  		s["id"] = cty.StringVal("ID")
  9922  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
  9923  			s["type"] = cty.StringVal(req.TypeName)
  9924  		}
  9925  		return providers.ApplyResourceChangeResponse{
  9926  			NewState: cty.ObjectVal(s),
  9927  		}
  9928  	}
  9929  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9930  	ctx := testContext2(t, &ContextOpts{
  9931  		Providers: map[addrs.Provider]providers.Factory{
  9932  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9933  		},
  9934  	})
  9935  
  9936  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9937  	assertNoErrors(t, diags)
  9938  
  9939  	_, diags = ctx.Apply(plan, m)
  9940  	assertNoErrors(t, diags)
  9941  
  9942  	if !p.ApplyResourceChangeCalled {
  9943  		t.Fatalf("ApplyResourceChange not called")
  9944  	}
  9945  
  9946  	if pm, ok := arcPMs["test_resource"]; !ok {
  9947  		t.Fatalf("sub-module ApplyResourceChange not called")
  9948  	} else if !pm.IsNull() {
  9949  		t.Fatalf("non-null ProviderMeta in sub-module ApplyResourceChange: %+v", pm)
  9950  	}
  9951  
  9952  	if pm, ok := arcPMs["test_instance"]; !ok {
  9953  		t.Fatalf("root module ApplyResourceChange not called")
  9954  	} else if !pm.IsNull() {
  9955  		t.Fatalf("non-null ProviderMeta in root module ApplyResourceChange: %+v", pm)
  9956  	}
  9957  }
  9958  
  9959  func TestContext2Apply_ProviderMeta_plan_set(t *testing.T) {
  9960  	m := testModule(t, "provider-meta-set")
  9961  	p := testProvider("test")
  9962  	schema := p.ProviderSchema()
  9963  	schema.ProviderMeta = &configschema.Block{
  9964  		Attributes: map[string]*configschema.Attribute{
  9965  			"baz": {
  9966  				Type:     cty.String,
  9967  				Required: true,
  9968  			},
  9969  		},
  9970  	}
  9971  	prcPMs := map[string]cty.Value{}
  9972  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  9973  		prcPMs[req.TypeName] = req.ProviderMeta
  9974  		return providers.PlanResourceChangeResponse{
  9975  			PlannedState: req.ProposedNewState,
  9976  		}
  9977  	}
  9978  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9979  	ctx := testContext2(t, &ContextOpts{
  9980  		Providers: map[addrs.Provider]providers.Factory{
  9981  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9982  		},
  9983  	})
  9984  
  9985  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9986  	assertNoErrors(t, diags)
  9987  
  9988  	if !p.PlanResourceChangeCalled {
  9989  		t.Fatalf("PlanResourceChange not called")
  9990  	}
  9991  
  9992  	expectations := map[string]cty.Value{}
  9993  
  9994  	if pm, ok := prcPMs["test_resource"]; !ok {
  9995  		t.Fatalf("sub-module PlanResourceChange not called")
  9996  	} else if pm.IsNull() {
  9997  		t.Fatalf("null ProviderMeta in sub-module PlanResourceChange")
  9998  	} else {
  9999  		expectations["quux-submodule"] = pm
 10000  	}
 10001  
 10002  	if pm, ok := prcPMs["test_instance"]; !ok {
 10003  		t.Fatalf("root module PlanResourceChange not called")
 10004  	} else if pm.IsNull() {
 10005  		t.Fatalf("null ProviderMeta in root module PlanResourceChange")
 10006  	} else {
 10007  		expectations["quux"] = pm
 10008  	}
 10009  
 10010  	type metaStruct struct {
 10011  		Baz string `cty:"baz"`
 10012  	}
 10013  
 10014  	for expected, v := range expectations {
 10015  		var meta metaStruct
 10016  		err := gocty.FromCtyValue(v, &meta)
 10017  		if err != nil {
 10018  			t.Fatalf("Error parsing cty value: %s", err)
 10019  		}
 10020  		if meta.Baz != expected {
 10021  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10022  		}
 10023  	}
 10024  }
 10025  
 10026  func TestContext2Apply_ProviderMeta_plan_unset(t *testing.T) {
 10027  	m := testModule(t, "provider-meta-unset")
 10028  	p := testProvider("test")
 10029  	schema := p.ProviderSchema()
 10030  	schema.ProviderMeta = &configschema.Block{
 10031  		Attributes: map[string]*configschema.Attribute{
 10032  			"baz": {
 10033  				Type:     cty.String,
 10034  				Required: true,
 10035  			},
 10036  		},
 10037  	}
 10038  	prcPMs := map[string]cty.Value{}
 10039  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
 10040  		prcPMs[req.TypeName] = req.ProviderMeta
 10041  		return providers.PlanResourceChangeResponse{
 10042  			PlannedState: req.ProposedNewState,
 10043  		}
 10044  	}
 10045  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10046  	ctx := testContext2(t, &ContextOpts{
 10047  		Providers: map[addrs.Provider]providers.Factory{
 10048  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10049  		},
 10050  	})
 10051  
 10052  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10053  	assertNoErrors(t, diags)
 10054  
 10055  	if !p.PlanResourceChangeCalled {
 10056  		t.Fatalf("PlanResourceChange not called")
 10057  	}
 10058  
 10059  	if pm, ok := prcPMs["test_resource"]; !ok {
 10060  		t.Fatalf("sub-module PlanResourceChange not called")
 10061  	} else if !pm.IsNull() {
 10062  		t.Fatalf("non-null ProviderMeta in sub-module PlanResourceChange: %+v", pm)
 10063  	}
 10064  
 10065  	if pm, ok := prcPMs["test_instance"]; !ok {
 10066  		t.Fatalf("root module PlanResourceChange not called")
 10067  	} else if !pm.IsNull() {
 10068  		t.Fatalf("non-null ProviderMeta in root module PlanResourceChange: %+v", pm)
 10069  	}
 10070  }
 10071  
 10072  func TestContext2Apply_ProviderMeta_plan_setNoSchema(t *testing.T) {
 10073  	m := testModule(t, "provider-meta-set")
 10074  	p := testProvider("test")
 10075  	p.PlanResourceChangeFn = testDiffFn
 10076  	ctx := testContext2(t, &ContextOpts{
 10077  		Providers: map[addrs.Provider]providers.Factory{
 10078  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10079  		},
 10080  	})
 10081  
 10082  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10083  	if !diags.HasErrors() {
 10084  		t.Fatalf("plan supposed to error, has no errors")
 10085  	}
 10086  
 10087  	var rootErr, subErr bool
 10088  	errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks"
 10089  	for _, diag := range diags {
 10090  		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
 10091  			t.Errorf("Unexpected error: %+v", diag.Description())
 10092  		}
 10093  		switch diag.Description().Detail {
 10094  		case fmt.Sprintf(errorSummary, "instance"):
 10095  			rootErr = true
 10096  		case fmt.Sprintf(errorSummary, "resource"):
 10097  			subErr = true
 10098  		default:
 10099  			t.Errorf("Unexpected error: %s", diag.Description())
 10100  		}
 10101  	}
 10102  	if !rootErr {
 10103  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10104  	}
 10105  	if !subErr {
 10106  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10107  	}
 10108  }
 10109  
 10110  func TestContext2Apply_ProviderMeta_plan_setInvalid(t *testing.T) {
 10111  	m := testModule(t, "provider-meta-set")
 10112  	p := testProvider("test")
 10113  	p.PlanResourceChangeFn = testDiffFn
 10114  	schema := p.ProviderSchema()
 10115  	schema.ProviderMeta = &configschema.Block{
 10116  		Attributes: map[string]*configschema.Attribute{
 10117  			"quux": {
 10118  				Type:     cty.String,
 10119  				Required: true,
 10120  			},
 10121  		},
 10122  	}
 10123  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10124  	ctx := testContext2(t, &ContextOpts{
 10125  		Providers: map[addrs.Provider]providers.Factory{
 10126  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10127  		},
 10128  	})
 10129  
 10130  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10131  	if !diags.HasErrors() {
 10132  		t.Fatalf("plan supposed to error, has no errors")
 10133  	}
 10134  
 10135  	var reqErr, invalidErr bool
 10136  	for _, diag := range diags {
 10137  		switch diag.Description().Summary {
 10138  		case "Missing required argument":
 10139  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10140  				reqErr = true
 10141  			} else {
 10142  				t.Errorf("Unexpected error %+v", diag.Description())
 10143  			}
 10144  		case "Unsupported argument":
 10145  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10146  				invalidErr = true
 10147  			} else {
 10148  				t.Errorf("Unexpected error %+v", diag.Description())
 10149  			}
 10150  		default:
 10151  			t.Errorf("Unexpected error %+v", diag.Description())
 10152  		}
 10153  	}
 10154  	if !reqErr {
 10155  		t.Errorf("Expected missing required argument error, none received")
 10156  	}
 10157  	if !invalidErr {
 10158  		t.Errorf("Expected unsupported argument error, none received")
 10159  	}
 10160  }
 10161  
 10162  func TestContext2Apply_ProviderMeta_refresh_set(t *testing.T) {
 10163  	m := testModule(t, "provider-meta-set")
 10164  	p := testProvider("test")
 10165  	p.PlanResourceChangeFn = testDiffFn
 10166  	schema := p.ProviderSchema()
 10167  	schema.ProviderMeta = &configschema.Block{
 10168  		Attributes: map[string]*configschema.Attribute{
 10169  			"baz": {
 10170  				Type:     cty.String,
 10171  				Required: true,
 10172  			},
 10173  		},
 10174  	}
 10175  	rrcPMs := map[string]cty.Value{}
 10176  	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
 10177  		rrcPMs[req.TypeName] = req.ProviderMeta
 10178  		newState, err := p.GetProviderSchemaResponse.ResourceTypes[req.TypeName].Block.CoerceValue(req.PriorState)
 10179  		if err != nil {
 10180  			panic(err)
 10181  		}
 10182  		resp.NewState = newState
 10183  		return resp
 10184  	}
 10185  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10186  	ctx := testContext2(t, &ContextOpts{
 10187  		Providers: map[addrs.Provider]providers.Factory{
 10188  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10189  		},
 10190  	})
 10191  
 10192  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10193  	assertNoErrors(t, diags)
 10194  
 10195  	state, diags := ctx.Apply(plan, m)
 10196  	assertNoErrors(t, diags)
 10197  
 10198  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10199  	assertNoErrors(t, diags)
 10200  
 10201  	if !p.ReadResourceCalled {
 10202  		t.Fatalf("ReadResource not called")
 10203  	}
 10204  
 10205  	expectations := map[string]cty.Value{}
 10206  
 10207  	if pm, ok := rrcPMs["test_resource"]; !ok {
 10208  		t.Fatalf("sub-module ReadResource not called")
 10209  	} else if pm.IsNull() {
 10210  		t.Fatalf("null ProviderMeta in sub-module ReadResource")
 10211  	} else {
 10212  		expectations["quux-submodule"] = pm
 10213  	}
 10214  
 10215  	if pm, ok := rrcPMs["test_instance"]; !ok {
 10216  		t.Fatalf("root module ReadResource not called")
 10217  	} else if pm.IsNull() {
 10218  		t.Fatalf("null ProviderMeta in root module ReadResource")
 10219  	} else {
 10220  		expectations["quux"] = pm
 10221  	}
 10222  
 10223  	type metaStruct struct {
 10224  		Baz string `cty:"baz"`
 10225  	}
 10226  
 10227  	for expected, v := range expectations {
 10228  		var meta metaStruct
 10229  		err := gocty.FromCtyValue(v, &meta)
 10230  		if err != nil {
 10231  			t.Fatalf("Error parsing cty value: %s", err)
 10232  		}
 10233  		if meta.Baz != expected {
 10234  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10235  		}
 10236  	}
 10237  }
 10238  
 10239  func TestContext2Apply_ProviderMeta_refresh_setNoSchema(t *testing.T) {
 10240  	m := testModule(t, "provider-meta-set")
 10241  	p := testProvider("test")
 10242  	p.PlanResourceChangeFn = testDiffFn
 10243  
 10244  	// we need a schema for plan/apply so they don't error
 10245  	schema := p.ProviderSchema()
 10246  	schema.ProviderMeta = &configschema.Block{
 10247  		Attributes: map[string]*configschema.Attribute{
 10248  			"baz": {
 10249  				Type:     cty.String,
 10250  				Required: true,
 10251  			},
 10252  		},
 10253  	}
 10254  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10255  	ctx := testContext2(t, &ContextOpts{
 10256  		Providers: map[addrs.Provider]providers.Factory{
 10257  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10258  		},
 10259  	})
 10260  
 10261  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10262  	assertNoErrors(t, diags)
 10263  
 10264  	state, diags := ctx.Apply(plan, m)
 10265  	assertNoErrors(t, diags)
 10266  
 10267  	// drop the schema before refresh, to test that it errors
 10268  	schema.ProviderMeta = nil
 10269  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10270  	ctx = testContext2(t, &ContextOpts{
 10271  		Providers: map[addrs.Provider]providers.Factory{
 10272  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10273  		},
 10274  	})
 10275  
 10276  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10277  	if !diags.HasErrors() {
 10278  		t.Fatalf("refresh supposed to error, has no errors")
 10279  	}
 10280  
 10281  	var rootErr, subErr bool
 10282  	errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks"
 10283  	for _, diag := range diags {
 10284  		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
 10285  			t.Errorf("Unexpected error: %+v", diag.Description())
 10286  		}
 10287  		switch diag.Description().Detail {
 10288  		case fmt.Sprintf(errorSummary, "instance"):
 10289  			rootErr = true
 10290  		case fmt.Sprintf(errorSummary, "resource"):
 10291  			subErr = true
 10292  		default:
 10293  			t.Errorf("Unexpected error: %s", diag.Description())
 10294  		}
 10295  	}
 10296  	if !rootErr {
 10297  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10298  	}
 10299  	if !subErr {
 10300  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10301  	}
 10302  }
 10303  
 10304  func TestContext2Apply_ProviderMeta_refresh_setInvalid(t *testing.T) {
 10305  	m := testModule(t, "provider-meta-set")
 10306  	p := testProvider("test")
 10307  	p.PlanResourceChangeFn = testDiffFn
 10308  
 10309  	// we need a matching schema for plan/apply so they don't error
 10310  	schema := p.ProviderSchema()
 10311  	schema.ProviderMeta = &configschema.Block{
 10312  		Attributes: map[string]*configschema.Attribute{
 10313  			"baz": {
 10314  				Type:     cty.String,
 10315  				Required: true,
 10316  			},
 10317  		},
 10318  	}
 10319  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10320  	ctx := testContext2(t, &ContextOpts{
 10321  		Providers: map[addrs.Provider]providers.Factory{
 10322  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10323  		},
 10324  	})
 10325  
 10326  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10327  	assertNoErrors(t, diags)
 10328  
 10329  	state, diags := ctx.Apply(plan, m)
 10330  	assertNoErrors(t, diags)
 10331  
 10332  	// change the schema before refresh, to test that it errors
 10333  	schema.ProviderMeta = &configschema.Block{
 10334  		Attributes: map[string]*configschema.Attribute{
 10335  			"quux": {
 10336  				Type:     cty.String,
 10337  				Required: true,
 10338  			},
 10339  		},
 10340  	}
 10341  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10342  	ctx = testContext2(t, &ContextOpts{
 10343  		Providers: map[addrs.Provider]providers.Factory{
 10344  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10345  		},
 10346  	})
 10347  
 10348  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10349  	if !diags.HasErrors() {
 10350  		t.Fatalf("refresh supposed to error, has no errors")
 10351  	}
 10352  
 10353  	var reqErr, invalidErr bool
 10354  	for _, diag := range diags {
 10355  		switch diag.Description().Summary {
 10356  		case "Missing required argument":
 10357  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10358  				reqErr = true
 10359  			} else {
 10360  				t.Errorf("Unexpected error %+v", diag.Description())
 10361  			}
 10362  		case "Unsupported argument":
 10363  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10364  				invalidErr = true
 10365  			} else {
 10366  				t.Errorf("Unexpected error %+v", diag.Description())
 10367  			}
 10368  		default:
 10369  			t.Errorf("Unexpected error %+v", diag.Description())
 10370  		}
 10371  	}
 10372  	if !reqErr {
 10373  		t.Errorf("Expected missing required argument error, none received")
 10374  	}
 10375  	if !invalidErr {
 10376  		t.Errorf("Expected unsupported argument error, none received")
 10377  	}
 10378  }
 10379  
 10380  func TestContext2Apply_ProviderMeta_refreshdata_set(t *testing.T) {
 10381  	m := testModule(t, "provider-meta-data-set")
 10382  	p := testProvider("test")
 10383  	p.PlanResourceChangeFn = testDiffFn
 10384  	schema := p.ProviderSchema()
 10385  	schema.ProviderMeta = &configschema.Block{
 10386  		Attributes: map[string]*configschema.Attribute{
 10387  			"baz": {
 10388  				Type:     cty.String,
 10389  				Required: true,
 10390  			},
 10391  		},
 10392  	}
 10393  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10394  	ctx := testContext2(t, &ContextOpts{
 10395  		Providers: map[addrs.Provider]providers.Factory{
 10396  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10397  		},
 10398  	})
 10399  	rdsPMs := map[string]cty.Value{}
 10400  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10401  		rdsPMs[req.TypeName] = req.ProviderMeta
 10402  		switch req.TypeName {
 10403  		case "test_data_source":
 10404  			log.Printf("[TRACE] test_data_source RDSR returning")
 10405  			return providers.ReadDataSourceResponse{
 10406  				State: cty.ObjectVal(map[string]cty.Value{
 10407  					"id":  cty.StringVal("yo"),
 10408  					"foo": cty.StringVal("bar"),
 10409  				}),
 10410  			}
 10411  		case "test_file":
 10412  			log.Printf("[TRACE] test_file RDSR returning")
 10413  			return providers.ReadDataSourceResponse{
 10414  				State: cty.ObjectVal(map[string]cty.Value{
 10415  					"id":       cty.StringVal("bar"),
 10416  					"rendered": cty.StringVal("baz"),
 10417  					"template": cty.StringVal(""),
 10418  				}),
 10419  			}
 10420  		default:
 10421  			// config drift, oops
 10422  			log.Printf("[TRACE] unknown request TypeName: %q", req.TypeName)
 10423  			return providers.ReadDataSourceResponse{}
 10424  		}
 10425  	}
 10426  
 10427  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10428  	assertNoErrors(t, diags)
 10429  
 10430  	state, diags := ctx.Apply(plan, m)
 10431  	assertNoErrors(t, diags)
 10432  
 10433  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10434  	assertNoErrors(t, diags)
 10435  
 10436  	if !p.ReadDataSourceCalled {
 10437  		t.Fatalf("ReadDataSource not called")
 10438  	}
 10439  
 10440  	expectations := map[string]cty.Value{}
 10441  
 10442  	if pm, ok := rdsPMs["test_file"]; !ok {
 10443  		t.Fatalf("sub-module ReadDataSource not called")
 10444  	} else if pm.IsNull() {
 10445  		t.Fatalf("null ProviderMeta in sub-module ReadDataSource")
 10446  	} else {
 10447  		expectations["quux-submodule"] = pm
 10448  	}
 10449  
 10450  	if pm, ok := rdsPMs["test_data_source"]; !ok {
 10451  		t.Fatalf("root module ReadDataSource not called")
 10452  	} else if pm.IsNull() {
 10453  		t.Fatalf("null ProviderMeta in root module ReadDataSource")
 10454  	} else {
 10455  		expectations["quux"] = pm
 10456  	}
 10457  
 10458  	type metaStruct struct {
 10459  		Baz string `cty:"baz"`
 10460  	}
 10461  
 10462  	for expected, v := range expectations {
 10463  		var meta metaStruct
 10464  		err := gocty.FromCtyValue(v, &meta)
 10465  		if err != nil {
 10466  			t.Fatalf("Error parsing cty value: %s", err)
 10467  		}
 10468  		if meta.Baz != expected {
 10469  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10470  		}
 10471  	}
 10472  }
 10473  
 10474  func TestContext2Apply_ProviderMeta_refreshdata_unset(t *testing.T) {
 10475  	m := testModule(t, "provider-meta-data-unset")
 10476  	p := testProvider("test")
 10477  	p.PlanResourceChangeFn = testDiffFn
 10478  	schema := p.ProviderSchema()
 10479  	schema.ProviderMeta = &configschema.Block{
 10480  		Attributes: map[string]*configschema.Attribute{
 10481  			"baz": {
 10482  				Type:     cty.String,
 10483  				Required: true,
 10484  			},
 10485  		},
 10486  	}
 10487  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10488  	ctx := testContext2(t, &ContextOpts{
 10489  		Providers: map[addrs.Provider]providers.Factory{
 10490  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10491  		},
 10492  	})
 10493  	rdsPMs := map[string]cty.Value{}
 10494  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10495  		rdsPMs[req.TypeName] = req.ProviderMeta
 10496  		switch req.TypeName {
 10497  		case "test_data_source":
 10498  			return providers.ReadDataSourceResponse{
 10499  				State: cty.ObjectVal(map[string]cty.Value{
 10500  					"id":  cty.StringVal("yo"),
 10501  					"foo": cty.StringVal("bar"),
 10502  				}),
 10503  			}
 10504  		case "test_file":
 10505  			return providers.ReadDataSourceResponse{
 10506  				State: cty.ObjectVal(map[string]cty.Value{
 10507  					"id":       cty.StringVal("bar"),
 10508  					"rendered": cty.StringVal("baz"),
 10509  					"template": cty.StringVal(""),
 10510  				}),
 10511  			}
 10512  		default:
 10513  			// config drift, oops
 10514  			return providers.ReadDataSourceResponse{}
 10515  		}
 10516  	}
 10517  
 10518  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10519  	assertNoErrors(t, diags)
 10520  
 10521  	_, diags = ctx.Apply(plan, m)
 10522  	assertNoErrors(t, diags)
 10523  
 10524  	if !p.ReadDataSourceCalled {
 10525  		t.Fatalf("ReadDataSource not called")
 10526  	}
 10527  
 10528  	if pm, ok := rdsPMs["test_file"]; !ok {
 10529  		t.Fatalf("sub-module ReadDataSource not called")
 10530  	} else if !pm.IsNull() {
 10531  		t.Fatalf("non-null ProviderMeta in sub-module ReadDataSource")
 10532  	}
 10533  
 10534  	if pm, ok := rdsPMs["test_data_source"]; !ok {
 10535  		t.Fatalf("root module ReadDataSource not called")
 10536  	} else if !pm.IsNull() {
 10537  		t.Fatalf("non-null ProviderMeta in root module ReadDataSource")
 10538  	}
 10539  }
 10540  
 10541  func TestContext2Apply_ProviderMeta_refreshdata_setNoSchema(t *testing.T) {
 10542  	m := testModule(t, "provider-meta-data-set")
 10543  	p := testProvider("test")
 10544  	p.PlanResourceChangeFn = testDiffFn
 10545  	ctx := testContext2(t, &ContextOpts{
 10546  		Providers: map[addrs.Provider]providers.Factory{
 10547  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10548  		},
 10549  	})
 10550  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 10551  		State: cty.ObjectVal(map[string]cty.Value{
 10552  			"id":  cty.StringVal("yo"),
 10553  			"foo": cty.StringVal("bar"),
 10554  		}),
 10555  	}
 10556  
 10557  	_, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts)
 10558  	if !diags.HasErrors() {
 10559  		t.Fatalf("refresh supposed to error, has no errors")
 10560  	}
 10561  
 10562  	var rootErr, subErr bool
 10563  	errorSummary := "The resource data.test_%s.foo belongs to a provider that doesn't support provider_meta blocks"
 10564  	for _, diag := range diags {
 10565  		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
 10566  			t.Errorf("Unexpected error: %+v", diag.Description())
 10567  		}
 10568  		switch diag.Description().Detail {
 10569  		case fmt.Sprintf(errorSummary, "data_source"):
 10570  			rootErr = true
 10571  		case fmt.Sprintf(errorSummary, "file"):
 10572  			subErr = true
 10573  		default:
 10574  			t.Errorf("Unexpected error: %s", diag.Description())
 10575  		}
 10576  	}
 10577  	if !rootErr {
 10578  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10579  	}
 10580  	if !subErr {
 10581  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10582  	}
 10583  }
 10584  
 10585  func TestContext2Apply_ProviderMeta_refreshdata_setInvalid(t *testing.T) {
 10586  	m := testModule(t, "provider-meta-data-set")
 10587  	p := testProvider("test")
 10588  	p.PlanResourceChangeFn = testDiffFn
 10589  	schema := p.ProviderSchema()
 10590  	schema.ProviderMeta = &configschema.Block{
 10591  		Attributes: map[string]*configschema.Attribute{
 10592  			"quux": {
 10593  				Type:     cty.String,
 10594  				Required: true,
 10595  			},
 10596  		},
 10597  	}
 10598  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10599  	ctx := testContext2(t, &ContextOpts{
 10600  		Providers: map[addrs.Provider]providers.Factory{
 10601  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10602  		},
 10603  	})
 10604  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 10605  		State: cty.ObjectVal(map[string]cty.Value{
 10606  			"id":  cty.StringVal("yo"),
 10607  			"foo": cty.StringVal("bar"),
 10608  		}),
 10609  	}
 10610  
 10611  	_, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts)
 10612  	if !diags.HasErrors() {
 10613  		t.Fatalf("refresh supposed to error, has no errors")
 10614  	}
 10615  
 10616  	var reqErr, invalidErr bool
 10617  	for _, diag := range diags {
 10618  		switch diag.Description().Summary {
 10619  		case "Missing required argument":
 10620  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10621  				reqErr = true
 10622  			} else {
 10623  				t.Errorf("Unexpected error %+v", diag.Description())
 10624  			}
 10625  		case "Unsupported argument":
 10626  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10627  				invalidErr = true
 10628  			} else {
 10629  				t.Errorf("Unexpected error %+v", diag.Description())
 10630  			}
 10631  		default:
 10632  			t.Errorf("Unexpected error %+v", diag.Description())
 10633  		}
 10634  	}
 10635  	if !reqErr {
 10636  		t.Errorf("Expected missing required argument error, none received")
 10637  	}
 10638  	if !invalidErr {
 10639  		t.Errorf("Expected unsupported argument error, none received")
 10640  	}
 10641  }
 10642  
 10643  func TestContext2Apply_expandModuleVariables(t *testing.T) {
 10644  	m := testModuleInline(t, map[string]string{
 10645  		"main.tf": `
 10646  module "mod1" {
 10647    for_each = toset(["a"])
 10648    source = "./mod"
 10649  }
 10650  
 10651  module "mod2" {
 10652    source = "./mod"
 10653    in = module.mod1["a"].out
 10654  }
 10655  `,
 10656  		"mod/main.tf": `
 10657  resource "aws_instance" "foo" {
 10658    foo = var.in
 10659  }
 10660  
 10661  variable "in" {
 10662    type = string
 10663    default = "default"
 10664  }
 10665  
 10666  output "out" {
 10667    value = aws_instance.foo.id
 10668  }
 10669  `,
 10670  	})
 10671  
 10672  	p := testProvider("aws")
 10673  	p.PlanResourceChangeFn = testDiffFn
 10674  	p.ApplyResourceChangeFn = testApplyFn
 10675  	ctx := testContext2(t, &ContextOpts{
 10676  		Providers: map[addrs.Provider]providers.Factory{
 10677  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 10678  		},
 10679  	})
 10680  
 10681  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10682  	if diags.HasErrors() {
 10683  		t.Fatal(diags.ErrWithWarnings())
 10684  	}
 10685  
 10686  	state, diags := ctx.Apply(plan, m)
 10687  	if diags.HasErrors() {
 10688  		t.Fatal(diags.ErrWithWarnings())
 10689  	}
 10690  
 10691  	expected := `<no state>
 10692  module.mod1["a"]:
 10693    aws_instance.foo:
 10694      ID = foo
 10695      provider = provider["registry.terraform.io/hashicorp/aws"]
 10696      foo = default
 10697      type = aws_instance
 10698  
 10699    Outputs:
 10700  
 10701    out = foo
 10702  module.mod2:
 10703    aws_instance.foo:
 10704      ID = foo
 10705      provider = provider["registry.terraform.io/hashicorp/aws"]
 10706      foo = foo
 10707      type = aws_instance
 10708  
 10709      Dependencies:
 10710        module.mod1.aws_instance.foo`
 10711  
 10712  	if state.String() != expected {
 10713  		t.Fatalf("expected:\n%s\ngot:\n%s\n", expected, state)
 10714  	}
 10715  }
 10716  
 10717  func TestContext2Apply_inheritAndStoreCBD(t *testing.T) {
 10718  	m := testModuleInline(t, map[string]string{
 10719  		"main.tf": `
 10720  resource "aws_instance" "foo" {
 10721  }
 10722  
 10723  resource "aws_instance" "cbd" {
 10724    foo = aws_instance.foo.id
 10725    lifecycle {
 10726      create_before_destroy = true
 10727    }
 10728  }
 10729  `,
 10730  	})
 10731  
 10732  	p := testProvider("aws")
 10733  	p.PlanResourceChangeFn = testDiffFn
 10734  	ctx := testContext2(t, &ContextOpts{
 10735  		Providers: map[addrs.Provider]providers.Factory{
 10736  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 10737  		},
 10738  	})
 10739  
 10740  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10741  	if diags.HasErrors() {
 10742  		t.Fatal(diags.ErrWithWarnings())
 10743  	}
 10744  
 10745  	state, diags := ctx.Apply(plan, m)
 10746  	if diags.HasErrors() {
 10747  		t.Fatal(diags.ErrWithWarnings())
 10748  	}
 10749  
 10750  	foo := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo"))
 10751  	if !foo.Current.CreateBeforeDestroy {
 10752  		t.Fatal("aws_instance.foo should also be create_before_destroy")
 10753  	}
 10754  }
 10755  
 10756  func TestContext2Apply_moduleDependsOn(t *testing.T) {
 10757  	m := testModule(t, "apply-module-depends-on")
 10758  
 10759  	p := testProvider("test")
 10760  
 10761  	// each instance being applied should happen in sequential order
 10762  	applied := int64(0)
 10763  
 10764  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10765  		cfg := req.Config.AsValueMap()
 10766  		foo := cfg["foo"].AsString()
 10767  		ord := atomic.LoadInt64(&applied)
 10768  
 10769  		resp := providers.ReadDataSourceResponse{
 10770  			State: cty.ObjectVal(map[string]cty.Value{
 10771  				"id":  cty.StringVal("data"),
 10772  				"foo": cfg["foo"],
 10773  			}),
 10774  		}
 10775  
 10776  		if foo == "a" && ord < 4 {
 10777  			// due to data source "a"'s module depending on instance 4, this
 10778  			// should not be less than 4
 10779  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source a read too early"))
 10780  		}
 10781  		if foo == "b" && ord < 1 {
 10782  			// due to data source "b"'s module depending on instance 1, this
 10783  			// should not be less than 1
 10784  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source b read too early"))
 10785  		}
 10786  		return resp
 10787  	}
 10788  	p.PlanResourceChangeFn = testDiffFn
 10789  
 10790  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 10791  		state := req.PlannedState.AsValueMap()
 10792  		num, _ := state["num"].AsBigFloat().Float64()
 10793  		ord := int64(num)
 10794  		if !atomic.CompareAndSwapInt64(&applied, ord-1, ord) {
 10795  			actual := atomic.LoadInt64(&applied)
 10796  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("instance %d was applied after %d", ord, actual))
 10797  		}
 10798  
 10799  		state["id"] = cty.StringVal(fmt.Sprintf("test_%d", ord))
 10800  		state["type"] = cty.StringVal("test_instance")
 10801  		resp.NewState = cty.ObjectVal(state)
 10802  
 10803  		return resp
 10804  	}
 10805  
 10806  	ctx := testContext2(t, &ContextOpts{
 10807  		Providers: map[addrs.Provider]providers.Factory{
 10808  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10809  		},
 10810  	})
 10811  
 10812  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10813  	if diags.HasErrors() {
 10814  		t.Fatal(diags.ErrWithWarnings())
 10815  	}
 10816  
 10817  	state, diags := ctx.Apply(plan, m)
 10818  	if diags.HasErrors() {
 10819  		t.Fatal(diags.ErrWithWarnings())
 10820  	}
 10821  
 10822  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
 10823  	if diags.HasErrors() {
 10824  		t.Fatal(diags.ErrWithWarnings())
 10825  	}
 10826  
 10827  	for _, res := range plan.Changes.Resources {
 10828  		if res.Action != plans.NoOp {
 10829  			t.Fatalf("expected NoOp, got %s for %s", res.Action, res.Addr)
 10830  		}
 10831  	}
 10832  }
 10833  
 10834  func TestContext2Apply_moduleSelfReference(t *testing.T) {
 10835  	m := testModuleInline(t, map[string]string{
 10836  		"main.tf": `
 10837  module "test" {
 10838    source = "./test"
 10839  
 10840    a = module.test.b
 10841  }
 10842  
 10843  output "c" {
 10844    value = module.test.c
 10845  }
 10846  `,
 10847  		"test/main.tf": `
 10848  variable "a" {}
 10849  
 10850  resource "test_instance" "test" {
 10851  }
 10852  
 10853  output "b" {
 10854    value = test_instance.test.id
 10855  }
 10856  
 10857  output "c" {
 10858    value = var.a
 10859  }`})
 10860  
 10861  	p := testProvider("test")
 10862  	p.PlanResourceChangeFn = testDiffFn
 10863  	ctx := testContext2(t, &ContextOpts{
 10864  		Providers: map[addrs.Provider]providers.Factory{
 10865  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10866  		},
 10867  	})
 10868  
 10869  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10870  	if diags.HasErrors() {
 10871  		t.Fatal(diags.ErrWithWarnings())
 10872  	}
 10873  
 10874  	state, diags := ctx.Apply(plan, m)
 10875  	if diags.HasErrors() {
 10876  		t.Fatal(diags.ErrWithWarnings())
 10877  	}
 10878  
 10879  	ctx = testContext2(t, &ContextOpts{
 10880  		Providers: map[addrs.Provider]providers.Factory{
 10881  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10882  		},
 10883  	})
 10884  
 10885  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 10886  		Mode: plans.DestroyMode,
 10887  	})
 10888  	if diags.HasErrors() {
 10889  		t.Fatal(diags.ErrWithWarnings())
 10890  	}
 10891  
 10892  	state, diags = ctx.Apply(plan, m)
 10893  	if diags.HasErrors() {
 10894  		t.Fatal(diags.ErrWithWarnings())
 10895  	}
 10896  
 10897  	if !state.Empty() {
 10898  		t.Fatal("expected empty state, got:", state)
 10899  	}
 10900  }
 10901  
 10902  func TestContext2Apply_moduleExpandDependsOn(t *testing.T) {
 10903  	m := testModuleInline(t, map[string]string{
 10904  		"main.tf": `
 10905  module "child" {
 10906    count = 1
 10907    source = "./child"
 10908  
 10909    depends_on = [test_instance.a, test_instance.b]
 10910  }
 10911  
 10912  resource "test_instance" "a" {
 10913  }
 10914  
 10915  
 10916  resource "test_instance" "b" {
 10917  }
 10918  `,
 10919  		"child/main.tf": `
 10920  resource "test_instance" "foo" {
 10921  }
 10922  
 10923  output "myoutput" {
 10924    value = "literal string"
 10925  }
 10926  `})
 10927  
 10928  	p := testProvider("test")
 10929  	p.PlanResourceChangeFn = testDiffFn
 10930  	ctx := testContext2(t, &ContextOpts{
 10931  		Providers: map[addrs.Provider]providers.Factory{
 10932  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10933  		},
 10934  	})
 10935  
 10936  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10937  	if diags.HasErrors() {
 10938  		t.Fatal(diags.ErrWithWarnings())
 10939  	}
 10940  
 10941  	state, diags := ctx.Apply(plan, m)
 10942  	if diags.HasErrors() {
 10943  		t.Fatal(diags.ErrWithWarnings())
 10944  	}
 10945  
 10946  	ctx = testContext2(t, &ContextOpts{
 10947  		Providers: map[addrs.Provider]providers.Factory{
 10948  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10949  		},
 10950  	})
 10951  
 10952  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 10953  		Mode: plans.DestroyMode,
 10954  	})
 10955  	if diags.HasErrors() {
 10956  		t.Fatal(diags.ErrWithWarnings())
 10957  	}
 10958  
 10959  	state, diags = ctx.Apply(plan, m)
 10960  	if diags.HasErrors() {
 10961  		t.Fatal(diags.ErrWithWarnings())
 10962  	}
 10963  
 10964  	if !state.Empty() {
 10965  		t.Fatal("expected empty state, got:", state)
 10966  	}
 10967  }
 10968  
 10969  func TestContext2Apply_scaleInCBD(t *testing.T) {
 10970  	m := testModuleInline(t, map[string]string{
 10971  		"main.tf": `
 10972  variable "ct" {
 10973    type = number
 10974  }
 10975  
 10976  resource "test_instance" "a" {
 10977    count = var.ct
 10978  }
 10979  
 10980  resource "test_instance" "b" {
 10981    require_new = local.removable
 10982    lifecycle {
 10983  	create_before_destroy = true
 10984    }
 10985  }
 10986  
 10987  resource "test_instance" "c" {
 10988    require_new = test_instance.b.id
 10989    lifecycle {
 10990  	create_before_destroy = true
 10991    }
 10992  }
 10993  
 10994  output "out" {
 10995    value = join(".", test_instance.a[*].id)
 10996  }
 10997  
 10998  locals {
 10999    removable = join(".", test_instance.a[*].id)
 11000  }
 11001  `})
 11002  
 11003  	state := states.NewState()
 11004  	root := state.EnsureModule(addrs.RootModuleInstance)
 11005  	root.SetResourceInstanceCurrent(
 11006  		mustResourceInstanceAddr("test_instance.a[0]").Resource,
 11007  		&states.ResourceInstanceObjectSrc{
 11008  			Status:              states.ObjectReady,
 11009  			AttrsJSON:           []byte(`{"id":"a0"}`),
 11010  			Dependencies:        []addrs.ConfigResource{},
 11011  			CreateBeforeDestroy: true,
 11012  		},
 11013  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 11014  	)
 11015  	root.SetResourceInstanceCurrent(
 11016  		mustResourceInstanceAddr("test_instance.a[1]").Resource,
 11017  		&states.ResourceInstanceObjectSrc{
 11018  			Status:              states.ObjectReady,
 11019  			AttrsJSON:           []byte(`{"id":"a1"}`),
 11020  			Dependencies:        []addrs.ConfigResource{},
 11021  			CreateBeforeDestroy: true,
 11022  		},
 11023  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 11024  	)
 11025  	root.SetResourceInstanceCurrent(
 11026  		mustResourceInstanceAddr("test_instance.b").Resource,
 11027  		&states.ResourceInstanceObjectSrc{
 11028  			Status:              states.ObjectReady,
 11029  			AttrsJSON:           []byte(`{"id":"b", "require_new":"old.old"}`),
 11030  			Dependencies:        []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")},
 11031  			CreateBeforeDestroy: true,
 11032  		},
 11033  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 11034  	)
 11035  	root.SetResourceInstanceCurrent(
 11036  		mustResourceInstanceAddr("test_instance.c").Resource,
 11037  		&states.ResourceInstanceObjectSrc{
 11038  			Status:    states.ObjectReady,
 11039  			AttrsJSON: []byte(`{"id":"c", "require_new":"b"}`),
 11040  			Dependencies: []addrs.ConfigResource{
 11041  				mustConfigResourceAddr("test_instance.a"),
 11042  				mustConfigResourceAddr("test_instance.b"),
 11043  			},
 11044  			CreateBeforeDestroy: true,
 11045  		},
 11046  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 11047  	)
 11048  
 11049  	p := testProvider("test")
 11050  
 11051  	p.PlanResourceChangeFn = func(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
 11052  		// this is a destroy plan
 11053  		if r.ProposedNewState.IsNull() {
 11054  			resp.PlannedState = r.ProposedNewState
 11055  			resp.PlannedPrivate = r.PriorPrivate
 11056  			return resp
 11057  		}
 11058  
 11059  		n := r.ProposedNewState.AsValueMap()
 11060  
 11061  		if r.PriorState.IsNull() {
 11062  			n["id"] = cty.UnknownVal(cty.String)
 11063  			resp.PlannedState = cty.ObjectVal(n)
 11064  			return resp
 11065  		}
 11066  
 11067  		p := r.PriorState.AsValueMap()
 11068  
 11069  		priorRN := p["require_new"]
 11070  		newRN := n["require_new"]
 11071  
 11072  		if eq := priorRN.Equals(newRN); !eq.IsKnown() || eq.False() {
 11073  			resp.RequiresReplace = []cty.Path{{cty.GetAttrStep{Name: "require_new"}}}
 11074  			n["id"] = cty.UnknownVal(cty.String)
 11075  		}
 11076  
 11077  		resp.PlannedState = cty.ObjectVal(n)
 11078  		return resp
 11079  	}
 11080  
 11081  	// reduce the count to 1
 11082  	ctx := testContext2(t, &ContextOpts{
 11083  		Providers: map[addrs.Provider]providers.Factory{
 11084  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11085  		},
 11086  	})
 11087  
 11088  	plan, diags := ctx.Plan(m, state, &PlanOpts{
 11089  		Mode: plans.NormalMode,
 11090  		SetVariables: InputValues{
 11091  			"ct": &InputValue{
 11092  				Value:      cty.NumberIntVal(1),
 11093  				SourceType: ValueFromCaller,
 11094  			},
 11095  		},
 11096  	})
 11097  	if diags.HasErrors() {
 11098  		t.Fatal(diags.ErrWithWarnings())
 11099  	}
 11100  	{
 11101  		addr := mustResourceInstanceAddr("test_instance.a[0]")
 11102  		change := plan.Changes.ResourceInstance(addr)
 11103  		if change == nil {
 11104  			t.Fatalf("no planned change for %s", addr)
 11105  		}
 11106  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[0]"); !want.Equal(got) {
 11107  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
 11108  		}
 11109  		if got, want := change.Action, plans.NoOp; got != want {
 11110  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
 11111  		}
 11112  		if got, want := change.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
 11113  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
 11114  		}
 11115  	}
 11116  	{
 11117  		addr := mustResourceInstanceAddr("test_instance.a[1]")
 11118  		change := plan.Changes.ResourceInstance(addr)
 11119  		if change == nil {
 11120  			t.Fatalf("no planned change for %s", addr)
 11121  		}
 11122  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[1]"); !want.Equal(got) {
 11123  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
 11124  		}
 11125  		if got, want := change.Action, plans.Delete; got != want {
 11126  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
 11127  		}
 11128  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
 11129  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
 11130  		}
 11131  	}
 11132  
 11133  	state, diags = ctx.Apply(plan, m)
 11134  	if diags.HasErrors() {
 11135  		log.Fatal(diags.ErrWithWarnings())
 11136  	}
 11137  
 11138  	// check the output, as those can't cause an error planning the value
 11139  	out := state.RootModule().OutputValues["out"].Value.AsString()
 11140  	if out != "a0" {
 11141  		t.Fatalf(`expected output "a0", got: %q`, out)
 11142  	}
 11143  
 11144  	// reduce the count to 0
 11145  	ctx = testContext2(t, &ContextOpts{
 11146  		Providers: map[addrs.Provider]providers.Factory{
 11147  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11148  		},
 11149  	})
 11150  
 11151  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11152  		Mode: plans.NormalMode,
 11153  		SetVariables: InputValues{
 11154  			"ct": &InputValue{
 11155  				Value:      cty.NumberIntVal(0),
 11156  				SourceType: ValueFromCaller,
 11157  			},
 11158  		},
 11159  	})
 11160  	if diags.HasErrors() {
 11161  		t.Fatal(diags.ErrWithWarnings())
 11162  	}
 11163  	{
 11164  		addr := mustResourceInstanceAddr("test_instance.a[0]")
 11165  		change := plan.Changes.ResourceInstance(addr)
 11166  		if change == nil {
 11167  			t.Fatalf("no planned change for %s", addr)
 11168  		}
 11169  		if got, want := change.PrevRunAddr, mustResourceInstanceAddr("test_instance.a[0]"); !want.Equal(got) {
 11170  			t.Errorf("wrong previous run address for %s %s; want %s", addr, got, want)
 11171  		}
 11172  		if got, want := change.Action, plans.Delete; got != want {
 11173  			t.Errorf("wrong action for %s %s; want %s", addr, got, want)
 11174  		}
 11175  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseCountIndex; got != want {
 11176  			t.Errorf("wrong action reason for %s %s; want %s", addr, got, want)
 11177  		}
 11178  	}
 11179  	{
 11180  		addr := mustResourceInstanceAddr("test_instance.a[1]")
 11181  		change := plan.Changes.ResourceInstance(addr)
 11182  		if change != nil {
 11183  			// It was already removed in the previous plan/apply
 11184  			t.Errorf("unexpected planned change for %s", addr)
 11185  		}
 11186  	}
 11187  
 11188  	state, diags = ctx.Apply(plan, m)
 11189  	if diags.HasErrors() {
 11190  		t.Fatal(diags.ErrWithWarnings())
 11191  	}
 11192  
 11193  	// check the output, as those can't cause an error planning the value
 11194  	out = state.RootModule().OutputValues["out"].Value.AsString()
 11195  	if out != "" {
 11196  		t.Fatalf(`expected output "", got: %q`, out)
 11197  	}
 11198  }
 11199  
 11200  // Ensure that we can destroy when a provider references a resource that will
 11201  // also be destroyed
 11202  func TestContext2Apply_destroyProviderReference(t *testing.T) {
 11203  	m := testModuleInline(t, map[string]string{
 11204  		"main.tf": `
 11205  provider "null" {
 11206    value = ""
 11207  }
 11208  
 11209  module "mod" {
 11210    source = "./mod"
 11211  }
 11212  
 11213  provider "test" {
 11214    value = module.mod.output
 11215  }
 11216  
 11217  resource "test_instance" "bar" {
 11218  }
 11219  `,
 11220  		"mod/main.tf": `
 11221  data "null_data_source" "foo" {
 11222         count = 1
 11223  }
 11224  
 11225  
 11226  output "output" {
 11227    value = data.null_data_source.foo[0].output
 11228  }
 11229  `})
 11230  
 11231  	schemaFn := func(name string) *ProviderSchema {
 11232  		return &ProviderSchema{
 11233  			Provider: &configschema.Block{
 11234  				Attributes: map[string]*configschema.Attribute{
 11235  					"value": {
 11236  						Type:     cty.String,
 11237  						Required: true,
 11238  					},
 11239  				},
 11240  			},
 11241  			ResourceTypes: map[string]*configschema.Block{
 11242  				name + "_instance": {
 11243  					Attributes: map[string]*configschema.Attribute{
 11244  						"id": {
 11245  							Type:     cty.String,
 11246  							Computed: true,
 11247  						},
 11248  						"foo": {
 11249  							Type:     cty.String,
 11250  							Optional: true,
 11251  						},
 11252  					},
 11253  				},
 11254  			},
 11255  			DataSources: map[string]*configschema.Block{
 11256  				name + "_data_source": {
 11257  					Attributes: map[string]*configschema.Attribute{
 11258  						"id": {
 11259  							Type:     cty.String,
 11260  							Computed: true,
 11261  						},
 11262  						"output": {
 11263  							Type:     cty.String,
 11264  							Computed: true,
 11265  						},
 11266  					},
 11267  				},
 11268  			},
 11269  		}
 11270  	}
 11271  
 11272  	testP := new(MockProvider)
 11273  	testP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11274  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11275  	}
 11276  	testP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("test"))
 11277  
 11278  	providerConfig := ""
 11279  	testP.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
 11280  		value := req.Config.GetAttr("value")
 11281  		if value.IsKnown() && !value.IsNull() {
 11282  			providerConfig = value.AsString()
 11283  		} else {
 11284  			providerConfig = ""
 11285  		}
 11286  		return resp
 11287  	}
 11288  	testP.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 11289  		if providerConfig != "valid" {
 11290  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provider config is %q", providerConfig))
 11291  			return
 11292  		}
 11293  		return testApplyFn(req)
 11294  	}
 11295  	testP.PlanResourceChangeFn = testDiffFn
 11296  
 11297  	nullP := new(MockProvider)
 11298  	nullP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11299  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11300  	}
 11301  	nullP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("null"))
 11302  
 11303  	nullP.ApplyResourceChangeFn = testApplyFn
 11304  	nullP.PlanResourceChangeFn = testDiffFn
 11305  
 11306  	nullP.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 11307  		State: cty.ObjectVal(map[string]cty.Value{
 11308  			"id":     cty.StringVal("ID"),
 11309  			"output": cty.StringVal("valid"),
 11310  		}),
 11311  	}
 11312  
 11313  	ctx := testContext2(t, &ContextOpts{
 11314  		Providers: map[addrs.Provider]providers.Factory{
 11315  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP),
 11316  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP),
 11317  		},
 11318  	})
 11319  
 11320  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11321  	assertNoErrors(t, diags)
 11322  
 11323  	state, diags := ctx.Apply(plan, m)
 11324  	if diags.HasErrors() {
 11325  		t.Fatalf("apply errors: %s", diags.Err())
 11326  	}
 11327  
 11328  	ctx = testContext2(t, &ContextOpts{
 11329  		Providers: map[addrs.Provider]providers.Factory{
 11330  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP),
 11331  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP),
 11332  		},
 11333  	})
 11334  
 11335  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11336  		Mode: plans.DestroyMode,
 11337  	})
 11338  	assertNoErrors(t, diags)
 11339  
 11340  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
 11341  		t.Fatalf("destroy apply errors: %s", diags.Err())
 11342  	}
 11343  }
 11344  
 11345  // Destroying properly requires pruning out all unneeded config nodes to
 11346  // prevent incorrect expansion evaluation.
 11347  func TestContext2Apply_destroyInterModuleExpansion(t *testing.T) {
 11348  	m := testModuleInline(t, map[string]string{
 11349  		"main.tf": `
 11350  data "test_data_source" "a" {
 11351    for_each = {
 11352      one = "thing"
 11353    }
 11354  }
 11355  
 11356  locals {
 11357    module_input = {
 11358      for k, v in data.test_data_source.a : k => v.id
 11359    }
 11360  }
 11361  
 11362  module "mod1" {
 11363    source = "./mod"
 11364    input = local.module_input
 11365  }
 11366  
 11367  module "mod2" {
 11368    source = "./mod"
 11369    input = module.mod1.outputs
 11370  }
 11371  
 11372  resource "test_instance" "bar" {
 11373    for_each = module.mod2.outputs
 11374  }
 11375  
 11376  output "module_output" {
 11377    value = module.mod2.outputs
 11378  }
 11379  output "test_instances" {
 11380    value = test_instance.bar
 11381  }
 11382  `,
 11383  		"mod/main.tf": `
 11384  variable "input" {
 11385  }
 11386  
 11387  data "test_data_source" "foo" {
 11388    for_each = var.input
 11389  }
 11390  
 11391  output "outputs" {
 11392    value = data.test_data_source.foo
 11393  }
 11394  `})
 11395  
 11396  	p := testProvider("test")
 11397  	p.PlanResourceChangeFn = testDiffFn
 11398  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 11399  		return providers.ReadDataSourceResponse{
 11400  			State: cty.ObjectVal(map[string]cty.Value{
 11401  				"id":  cty.StringVal("data_source"),
 11402  				"foo": cty.StringVal("output"),
 11403  			}),
 11404  		}
 11405  	}
 11406  
 11407  	ctx := testContext2(t, &ContextOpts{
 11408  		Providers: map[addrs.Provider]providers.Factory{
 11409  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11410  		},
 11411  	})
 11412  
 11413  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11414  	assertNoErrors(t, diags)
 11415  
 11416  	state, diags := ctx.Apply(plan, m)
 11417  	if diags.HasErrors() {
 11418  		t.Fatalf("apply errors: %s", diags.Err())
 11419  	}
 11420  
 11421  	destroy := func() {
 11422  		ctx = testContext2(t, &ContextOpts{
 11423  			Providers: map[addrs.Provider]providers.Factory{
 11424  				addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11425  			},
 11426  		})
 11427  
 11428  		plan, diags = ctx.Plan(m, state, &PlanOpts{
 11429  			Mode: plans.DestroyMode,
 11430  		})
 11431  		assertNoErrors(t, diags)
 11432  
 11433  		state, diags = ctx.Apply(plan, m)
 11434  		if diags.HasErrors() {
 11435  			t.Fatalf("destroy apply errors: %s", diags.Err())
 11436  		}
 11437  	}
 11438  
 11439  	destroy()
 11440  	// Destroying again from the empty state should not cause any errors either
 11441  	destroy()
 11442  }
 11443  
 11444  func TestContext2Apply_createBeforeDestroyWithModule(t *testing.T) {
 11445  	m := testModuleInline(t, map[string]string{
 11446  		"main.tf": `
 11447  variable "v" {}
 11448  
 11449  module "mod" {
 11450      source = "./mod"
 11451      in = var.v
 11452  }
 11453  
 11454  resource "test_resource" "a" {
 11455    value = var.v
 11456    depends_on = [module.mod]
 11457    lifecycle {
 11458      create_before_destroy = true
 11459    }
 11460  }
 11461  `,
 11462  		"mod/main.tf": `
 11463  variable "in" {}
 11464  
 11465  resource "test_resource" "a" {
 11466    value = var.in
 11467  }
 11468  `})
 11469  
 11470  	p := testProvider("test")
 11471  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
 11472  		// this is a destroy plan
 11473  		if req.ProposedNewState.IsNull() {
 11474  			resp.PlannedState = req.ProposedNewState
 11475  			resp.PlannedPrivate = req.PriorPrivate
 11476  			return resp
 11477  		}
 11478  
 11479  		proposed := req.ProposedNewState.AsValueMap()
 11480  		proposed["id"] = cty.UnknownVal(cty.String)
 11481  
 11482  		resp.PlannedState = cty.ObjectVal(proposed)
 11483  		resp.RequiresReplace = []cty.Path{{cty.GetAttrStep{Name: "value"}}}
 11484  		return resp
 11485  	}
 11486  
 11487  	ctx := testContext2(t, &ContextOpts{
 11488  		Providers: map[addrs.Provider]providers.Factory{
 11489  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11490  		},
 11491  	})
 11492  
 11493  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11494  		Mode: plans.NormalMode,
 11495  		SetVariables: InputValues{
 11496  			"v": &InputValue{
 11497  				Value: cty.StringVal("A"),
 11498  			},
 11499  		},
 11500  	})
 11501  	assertNoErrors(t, diags)
 11502  
 11503  	state, diags := ctx.Apply(plan, m)
 11504  	if diags.HasErrors() {
 11505  		t.Fatalf("apply errors: %s", diags.Err())
 11506  	}
 11507  
 11508  	ctx = testContext2(t, &ContextOpts{
 11509  		Providers: map[addrs.Provider]providers.Factory{
 11510  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11511  		},
 11512  	})
 11513  
 11514  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11515  		Mode: plans.NormalMode,
 11516  		SetVariables: InputValues{
 11517  			"v": &InputValue{
 11518  				Value: cty.StringVal("B"),
 11519  			},
 11520  		},
 11521  	})
 11522  	assertNoErrors(t, diags)
 11523  
 11524  	_, diags = ctx.Apply(plan, m)
 11525  	if diags.HasErrors() {
 11526  		t.Fatalf("apply errors: %s", diags.Err())
 11527  	}
 11528  }
 11529  
 11530  func TestContext2Apply_forcedCBD(t *testing.T) {
 11531  	m := testModuleInline(t, map[string]string{
 11532  		"main.tf": `
 11533  variable "v" {}
 11534  
 11535  resource "test_instance" "a" {
 11536    require_new = var.v
 11537  }
 11538  
 11539  resource "test_instance" "b" {
 11540    depends_on = [test_instance.a]
 11541    lifecycle {
 11542      create_before_destroy = true
 11543    }
 11544  }
 11545  `})
 11546  
 11547  	p := testProvider("test")
 11548  	p.PlanResourceChangeFn = testDiffFn
 11549  
 11550  	ctx := testContext2(t, &ContextOpts{
 11551  		Providers: map[addrs.Provider]providers.Factory{
 11552  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11553  		},
 11554  	})
 11555  
 11556  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11557  		Mode: plans.NormalMode,
 11558  		SetVariables: InputValues{
 11559  			"v": &InputValue{
 11560  				Value: cty.StringVal("A"),
 11561  			},
 11562  		},
 11563  	})
 11564  	assertNoErrors(t, diags)
 11565  
 11566  	state, diags := ctx.Apply(plan, m)
 11567  	if diags.HasErrors() {
 11568  		t.Fatalf("apply errors: %s", diags.Err())
 11569  	}
 11570  
 11571  	ctx = testContext2(t, &ContextOpts{
 11572  		Providers: map[addrs.Provider]providers.Factory{
 11573  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11574  		},
 11575  	})
 11576  
 11577  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11578  		Mode: plans.NormalMode,
 11579  		SetVariables: InputValues{
 11580  			"v": &InputValue{
 11581  				Value: cty.StringVal("B"),
 11582  			},
 11583  		},
 11584  	})
 11585  	assertNoErrors(t, diags)
 11586  
 11587  	_, diags = ctx.Apply(plan, m)
 11588  	if diags.HasErrors() {
 11589  		t.Fatalf("apply errors: %s", diags.Err())
 11590  	}
 11591  }
 11592  
 11593  func TestContext2Apply_removeReferencedResource(t *testing.T) {
 11594  	m := testModuleInline(t, map[string]string{
 11595  		"main.tf": `
 11596  variable "ct" {
 11597  }
 11598  
 11599  resource "test_resource" "to_remove" {
 11600    count = var.ct
 11601  }
 11602  
 11603  resource "test_resource" "c" {
 11604    value = join("", test_resource.to_remove[*].id)
 11605  }
 11606  `})
 11607  
 11608  	p := testProvider("test")
 11609  	p.PlanResourceChangeFn = testDiffFn
 11610  
 11611  	ctx := testContext2(t, &ContextOpts{
 11612  		Providers: map[addrs.Provider]providers.Factory{
 11613  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11614  		},
 11615  	})
 11616  
 11617  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11618  		Mode: plans.NormalMode,
 11619  		SetVariables: InputValues{
 11620  			"ct": &InputValue{
 11621  				Value: cty.NumberIntVal(1),
 11622  			},
 11623  		},
 11624  	})
 11625  	assertNoErrors(t, diags)
 11626  
 11627  	state, diags := ctx.Apply(plan, m)
 11628  	if diags.HasErrors() {
 11629  		t.Fatalf("apply errors: %s", diags.Err())
 11630  	}
 11631  
 11632  	ctx = testContext2(t, &ContextOpts{
 11633  		Providers: map[addrs.Provider]providers.Factory{
 11634  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11635  		},
 11636  	})
 11637  
 11638  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11639  		Mode: plans.NormalMode,
 11640  		SetVariables: InputValues{
 11641  			"ct": &InputValue{
 11642  				Value: cty.NumberIntVal(0),
 11643  			},
 11644  		},
 11645  	})
 11646  	assertNoErrors(t, diags)
 11647  
 11648  	_, diags = ctx.Apply(plan, m)
 11649  	if diags.HasErrors() {
 11650  		t.Fatalf("apply errors: %s", diags.Err())
 11651  	}
 11652  }
 11653  
 11654  func TestContext2Apply_variableSensitivity(t *testing.T) {
 11655  	m := testModuleInline(t, map[string]string{
 11656  		"main.tf": `
 11657  variable "sensitive_var" {
 11658  	default = "foo"
 11659  	sensitive = true
 11660  }
 11661  
 11662  variable "sensitive_id" {
 11663  	default = "secret id"
 11664  	sensitive = true
 11665  }
 11666  
 11667  resource "test_resource" "foo" {
 11668  	value   = var.sensitive_var
 11669  
 11670  	network_interface {
 11671  		network_interface_id = var.sensitive_id
 11672  	}
 11673  }`,
 11674  	})
 11675  
 11676  	p := new(MockProvider)
 11677  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11678  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11679  	}
 11680  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
 11681  		Provider: &configschema.Block{},
 11682  		ResourceTypes: map[string]*configschema.Block{
 11683  			"test_resource": {
 11684  				Attributes: map[string]*configschema.Attribute{
 11685  					"id": {
 11686  						Type:     cty.String,
 11687  						Computed: true,
 11688  					},
 11689  					"value": {
 11690  						Type:     cty.String,
 11691  						Optional: true,
 11692  						Computed: true,
 11693  					},
 11694  				},
 11695  				BlockTypes: map[string]*configschema.NestedBlock{
 11696  					"network_interface": {
 11697  						Block: configschema.Block{
 11698  							Attributes: map[string]*configschema.Attribute{
 11699  								"network_interface_id": {Type: cty.String, Optional: true},
 11700  								"device_index":         {Type: cty.Number, Optional: true},
 11701  							},
 11702  						},
 11703  						Nesting: configschema.NestingSet,
 11704  					},
 11705  				},
 11706  			},
 11707  		},
 11708  	})
 11709  	p.PlanResourceChangeFn = testDiffFn
 11710  
 11711  	ctx := testContext2(t, &ContextOpts{
 11712  		Providers: map[addrs.Provider]providers.Factory{
 11713  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11714  		},
 11715  	})
 11716  
 11717  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 11718  	assertNoErrors(t, diags)
 11719  
 11720  	state, diags := ctx.Apply(plan, m)
 11721  	if diags.HasErrors() {
 11722  		t.Fatalf("apply errors: %s", diags.Err())
 11723  	}
 11724  
 11725  	// Run a second apply with no changes
 11726  	ctx = testContext2(t, &ContextOpts{
 11727  		Providers: map[addrs.Provider]providers.Factory{
 11728  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11729  		},
 11730  	})
 11731  
 11732  	plan, diags = ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 11733  	assertNoErrors(t, diags)
 11734  
 11735  	state, diags = ctx.Apply(plan, m)
 11736  	if diags.HasErrors() {
 11737  		t.Fatalf("apply errors: %s", diags.Err())
 11738  	}
 11739  
 11740  	// Now change the variable value for sensitive_var
 11741  	ctx = testContext2(t, &ContextOpts{
 11742  		Providers: map[addrs.Provider]providers.Factory{
 11743  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11744  		},
 11745  	})
 11746  
 11747  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11748  		Mode: plans.NormalMode,
 11749  		SetVariables: InputValues{
 11750  			"sensitive_id": &InputValue{Value: cty.NilVal},
 11751  			"sensitive_var": &InputValue{
 11752  				Value: cty.StringVal("bar"),
 11753  			},
 11754  		},
 11755  	})
 11756  	assertNoErrors(t, diags)
 11757  
 11758  	_, diags = ctx.Apply(plan, m)
 11759  	if diags.HasErrors() {
 11760  		t.Fatalf("apply errors: %s", diags.Err())
 11761  	}
 11762  }
 11763  
 11764  func TestContext2Apply_variableSensitivityPropagation(t *testing.T) {
 11765  	m := testModuleInline(t, map[string]string{
 11766  		"main.tf": `
 11767  variable "sensitive_map" {
 11768  	type = map(string)
 11769  	default = {
 11770  		"x" = "foo"
 11771  	}
 11772  	sensitive = true
 11773  }
 11774  
 11775  resource "test_resource" "foo" {
 11776  	value = var.sensitive_map.x
 11777  }
 11778  `,
 11779  	})
 11780  
 11781  	p := testProvider("test")
 11782  	p.PlanResourceChangeFn = testDiffFn
 11783  
 11784  	ctx := testContext2(t, &ContextOpts{
 11785  		Providers: map[addrs.Provider]providers.Factory{
 11786  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11787  		},
 11788  	})
 11789  
 11790  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 11791  	if diags.HasErrors() {
 11792  		t.Fatalf("plan errors: %s", diags.Err())
 11793  	}
 11794  
 11795  	verifySensitiveValue := func(pvms []cty.PathValueMarks) {
 11796  		if len(pvms) != 1 {
 11797  			t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 11798  		}
 11799  		pvm := pvms[0]
 11800  		if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) {
 11801  			t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 11802  		}
 11803  		if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 11804  			t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 11805  		}
 11806  	}
 11807  
 11808  	addr := mustResourceInstanceAddr("test_resource.foo")
 11809  	fooChangeSrc := plan.Changes.ResourceInstance(addr)
 11810  	verifySensitiveValue(fooChangeSrc.AfterValMarks)
 11811  
 11812  	state, diags := ctx.Apply(plan, m)
 11813  	if diags.HasErrors() {
 11814  		t.Fatalf("apply errors: %s", diags.Err())
 11815  	}
 11816  
 11817  	fooState := state.ResourceInstance(addr)
 11818  	verifySensitiveValue(fooState.Current.AttrSensitivePaths)
 11819  }
 11820  
 11821  func TestContext2Apply_variableSensitivityProviders(t *testing.T) {
 11822  	m := testModuleInline(t, map[string]string{
 11823  		"main.tf": `
 11824  resource "test_resource" "foo" {
 11825  	sensitive_value = "should get marked"
 11826  }
 11827  
 11828  resource "test_resource" "bar" {
 11829  	value  = test_resource.foo.sensitive_value
 11830  	random = test_resource.foo.id # not sensitive
 11831  
 11832  	nesting_single {
 11833  		value           = "abc"
 11834  		sensitive_value = "xyz"
 11835  	}
 11836  }
 11837  
 11838  resource "test_resource" "baz" {
 11839  	value = test_resource.bar.nesting_single.sensitive_value
 11840  }
 11841  `,
 11842  	})
 11843  
 11844  	p := testProvider("test")
 11845  	p.PlanResourceChangeFn = testDiffFn
 11846  
 11847  	ctx := testContext2(t, &ContextOpts{
 11848  		Providers: map[addrs.Provider]providers.Factory{
 11849  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11850  		},
 11851  	})
 11852  
 11853  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11854  	if diags.HasErrors() {
 11855  		t.Fatalf("plan errors: %s", diags.Err())
 11856  	}
 11857  
 11858  	verifySensitiveValue := func(pvms []cty.PathValueMarks) {
 11859  		if len(pvms) != 1 {
 11860  			t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 11861  		}
 11862  		pvm := pvms[0]
 11863  		if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) {
 11864  			t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 11865  		}
 11866  		if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 11867  			t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 11868  		}
 11869  	}
 11870  
 11871  	// Sensitive attributes (defined by the provider) are marked
 11872  	// as sensitive when referenced from another resource
 11873  	// "bar" references sensitive resources in "foo"
 11874  	barAddr := mustResourceInstanceAddr("test_resource.bar")
 11875  	barChangeSrc := plan.Changes.ResourceInstance(barAddr)
 11876  	verifySensitiveValue(barChangeSrc.AfterValMarks)
 11877  
 11878  	bazAddr := mustResourceInstanceAddr("test_resource.baz")
 11879  	bazChangeSrc := plan.Changes.ResourceInstance(bazAddr)
 11880  	verifySensitiveValue(bazChangeSrc.AfterValMarks)
 11881  
 11882  	state, diags := ctx.Apply(plan, m)
 11883  	if diags.HasErrors() {
 11884  		t.Fatalf("apply errors: %s", diags.Err())
 11885  	}
 11886  
 11887  	barState := state.ResourceInstance(barAddr)
 11888  	verifySensitiveValue(barState.Current.AttrSensitivePaths)
 11889  
 11890  	bazState := state.ResourceInstance(bazAddr)
 11891  	verifySensitiveValue(bazState.Current.AttrSensitivePaths)
 11892  }
 11893  
 11894  func TestContext2Apply_variableSensitivityChange(t *testing.T) {
 11895  	m := testModuleInline(t, map[string]string{
 11896  		"main.tf": `
 11897  variable "sensitive_var" {
 11898  	default = "hello"
 11899  	sensitive = true
 11900  }
 11901  
 11902  resource "test_resource" "foo" {
 11903  	value = var.sensitive_var
 11904  }`,
 11905  	})
 11906  
 11907  	p := testProvider("test")
 11908  	p.PlanResourceChangeFn = testDiffFn
 11909  
 11910  	ctx := testContext2(t, &ContextOpts{
 11911  		Providers: map[addrs.Provider]providers.Factory{
 11912  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11913  		},
 11914  	})
 11915  
 11916  	state := states.BuildState(func(s *states.SyncState) {
 11917  		s.SetResourceInstanceCurrent(
 11918  			addrs.Resource{
 11919  				Mode: addrs.ManagedResourceMode,
 11920  				Type: "test_resource",
 11921  				Name: "foo",
 11922  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
 11923  			&states.ResourceInstanceObjectSrc{
 11924  				Status:    states.ObjectReady,
 11925  				AttrsJSON: []byte(`{"id":"foo", "value":"hello"}`),
 11926  				// No AttrSensitivePaths present
 11927  			},
 11928  			addrs.AbsProviderConfig{
 11929  				Provider: addrs.NewDefaultProvider("test"),
 11930  				Module:   addrs.RootModule,
 11931  			},
 11932  		)
 11933  	})
 11934  
 11935  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 11936  	assertNoErrors(t, diags)
 11937  
 11938  	addr := mustResourceInstanceAddr("test_resource.foo")
 11939  
 11940  	state, diags = ctx.Apply(plan, m)
 11941  	assertNoErrors(t, diags)
 11942  
 11943  	fooState := state.ResourceInstance(addr)
 11944  
 11945  	if len(fooState.Current.AttrSensitivePaths) != 1 {
 11946  		t.Fatalf("wrong number of sensitive paths, expected 1, got, %v", len(fooState.Current.AttrSensitivePaths))
 11947  	}
 11948  	got := fooState.Current.AttrSensitivePaths[0]
 11949  	want := cty.PathValueMarks{
 11950  		Path:  cty.GetAttrPath("value"),
 11951  		Marks: cty.NewValueMarks(marks.Sensitive),
 11952  	}
 11953  
 11954  	if !got.Equal(want) {
 11955  		t.Fatalf("wrong value marks; got:\n%#v\n\nwant:\n%#v\n", got, want)
 11956  	}
 11957  
 11958  	m2 := testModuleInline(t, map[string]string{
 11959  		"main.tf": `
 11960  variable "sensitive_var" {
 11961  	default = "hello"
 11962  	sensitive = false
 11963  }
 11964  
 11965  resource "test_resource" "foo" {
 11966  	value = var.sensitive_var
 11967  }`,
 11968  	})
 11969  
 11970  	ctx2 := testContext2(t, &ContextOpts{
 11971  		Providers: map[addrs.Provider]providers.Factory{
 11972  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11973  		},
 11974  	})
 11975  
 11976  	// NOTE: Prior to our refactoring to make the state an explicit argument
 11977  	// of Plan, as opposed to hidden state inside Context, this test was
 11978  	// calling ctx.Apply instead of ctx2.Apply and thus using the previous
 11979  	// plan instead of this new plan. "Fixing" it to use the new plan seems
 11980  	// to break the test, so we've preserved that oddity here by saving the
 11981  	// old plan as oldPlan and essentially discarding the new plan entirely,
 11982  	// but this seems rather suspicious and we should ideally figure out what
 11983  	// this test was originally intending to do and make it do that.
 11984  	oldPlan := plan
 11985  	_, diags = ctx2.Plan(m2, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 11986  	assertNoErrors(t, diags)
 11987  	stateWithoutSensitive, diags := ctx.Apply(oldPlan, m)
 11988  	assertNoErrors(t, diags)
 11989  
 11990  	fooState2 := stateWithoutSensitive.ResourceInstance(addr)
 11991  	if len(fooState2.Current.AttrSensitivePaths) > 0 {
 11992  		t.Fatalf(
 11993  			"wrong number of sensitive paths, expected 0, got, %v\n%s",
 11994  			len(fooState2.Current.AttrSensitivePaths),
 11995  			spew.Sdump(fooState2.Current.AttrSensitivePaths),
 11996  		)
 11997  	}
 11998  }
 11999  
 12000  func TestContext2Apply_moduleVariableOptionalAttributes(t *testing.T) {
 12001  	m := testModuleInline(t, map[string]string{
 12002  		"main.tf": `
 12003  variable "in" {
 12004    type = object({
 12005      required = string
 12006      optional = optional(string)
 12007      default  = optional(bool, true)
 12008      nested   = optional(
 12009        map(object({
 12010          a = optional(string, "foo")
 12011          b = optional(number, 5)
 12012        })), {
 12013          "boop": {}
 12014        }
 12015      )
 12016    })
 12017  }
 12018  
 12019  output "out" {
 12020    value = var.in
 12021  }
 12022  `})
 12023  
 12024  	ctx := testContext2(t, &ContextOpts{})
 12025  
 12026  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 12027  		Mode: plans.NormalMode,
 12028  		SetVariables: InputValues{
 12029  			"in": &InputValue{
 12030  				Value: cty.MapVal(map[string]cty.Value{
 12031  					"required": cty.StringVal("boop"),
 12032  				}),
 12033  				SourceType: ValueFromCaller,
 12034  			},
 12035  		},
 12036  	})
 12037  	if diags.HasErrors() {
 12038  		t.Fatal(diags.ErrWithWarnings())
 12039  	}
 12040  
 12041  	state, diags := ctx.Apply(plan, m)
 12042  	if diags.HasErrors() {
 12043  		t.Fatal(diags.ErrWithWarnings())
 12044  	}
 12045  
 12046  	got := state.RootModule().OutputValues["out"].Value
 12047  	want := cty.ObjectVal(map[string]cty.Value{
 12048  		"required": cty.StringVal("boop"),
 12049  
 12050  		// Because "optional" was marked as optional, it got silently filled
 12051  		// in as a null value of string type rather than returning an error.
 12052  		"optional": cty.NullVal(cty.String),
 12053  
 12054  		// Similarly, "default" was marked as optional with a default value,
 12055  		// and since it was omitted should be filled in with that default.
 12056  		"default": cty.True,
 12057  
 12058  		// Nested is a complex structure which has fully described defaults,
 12059  		// so again it should be filled with the default structure.
 12060  		"nested": cty.MapVal(map[string]cty.Value{
 12061  			"boop": cty.ObjectVal(map[string]cty.Value{
 12062  				"a": cty.StringVal("foo"),
 12063  				"b": cty.NumberIntVal(5),
 12064  			}),
 12065  		}),
 12066  	})
 12067  	if !want.RawEquals(got) {
 12068  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
 12069  	}
 12070  }
 12071  
 12072  func TestContext2Apply_moduleVariableOptionalAttributesDefault(t *testing.T) {
 12073  	m := testModuleInline(t, map[string]string{
 12074  		"main.tf": `
 12075  variable "in" {
 12076    type    = object({
 12077      required = string
 12078      optional = optional(string)
 12079      default  = optional(bool, true)
 12080    })
 12081    default = {
 12082      required = "boop"
 12083    }
 12084  }
 12085  
 12086  output "out" {
 12087    value = var.in
 12088  }
 12089  `})
 12090  
 12091  	ctx := testContext2(t, &ContextOpts{})
 12092  
 12093  	// We don't specify a value for the variable here, relying on its defined
 12094  	// default.
 12095  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 12096  	if diags.HasErrors() {
 12097  		t.Fatal(diags.ErrWithWarnings())
 12098  	}
 12099  
 12100  	state, diags := ctx.Apply(plan, m)
 12101  	if diags.HasErrors() {
 12102  		t.Fatal(diags.ErrWithWarnings())
 12103  	}
 12104  
 12105  	got := state.RootModule().OutputValues["out"].Value
 12106  	want := cty.ObjectVal(map[string]cty.Value{
 12107  		"required": cty.StringVal("boop"),
 12108  
 12109  		// "optional" is not present in the variable default, so it is filled
 12110  		// with null.
 12111  		"optional": cty.NullVal(cty.String),
 12112  
 12113  		// Similarly, "default" is not present in the variable default, so its
 12114  		// value is replaced with the type's specified default.
 12115  		"default": cty.True,
 12116  	})
 12117  	if !want.RawEquals(got) {
 12118  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
 12119  	}
 12120  }
 12121  
 12122  func TestContext2Apply_moduleVariableOptionalAttributesDefaultNull(t *testing.T) {
 12123  	m := testModuleInline(t, map[string]string{
 12124  		"main.tf": `
 12125  variable "in" {
 12126    type    = object({
 12127      required = string
 12128      optional = optional(string)
 12129      default  = optional(bool, true)
 12130    })
 12131    default = null
 12132  }
 12133  
 12134  # Wrap the input variable in a tuple because a null output value is elided from
 12135  # the plan, which prevents us from testing its type.
 12136  output "out" {
 12137    value = [var.in]
 12138  }
 12139  `})
 12140  
 12141  	ctx := testContext2(t, &ContextOpts{})
 12142  
 12143  	// We don't specify a value for the variable here, relying on its defined
 12144  	// default.
 12145  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 12146  	if diags.HasErrors() {
 12147  		t.Fatal(diags.ErrWithWarnings())
 12148  	}
 12149  
 12150  	state, diags := ctx.Apply(plan, m)
 12151  	if diags.HasErrors() {
 12152  		t.Fatal(diags.ErrWithWarnings())
 12153  	}
 12154  
 12155  	got := state.RootModule().OutputValues["out"].Value
 12156  	// The null default value should be bound, after type converting to the
 12157  	// full object type
 12158  	want := cty.TupleVal([]cty.Value{cty.NullVal(cty.Object(map[string]cty.Type{
 12159  		"required": cty.String,
 12160  		"optional": cty.String,
 12161  		"default":  cty.Bool,
 12162  	}))})
 12163  	if !want.RawEquals(got) {
 12164  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
 12165  	}
 12166  }
 12167  
 12168  func TestContext2Apply_provisionerSensitive(t *testing.T) {
 12169  	m := testModule(t, "apply-provisioner-sensitive")
 12170  	p := testProvider("aws")
 12171  
 12172  	pr := testProvisioner()
 12173  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
 12174  		if req.Config.ContainsMarked() {
 12175  			t.Fatalf("unexpectedly marked config value: %#v", req.Config)
 12176  		}
 12177  		command := req.Config.GetAttr("command")
 12178  		if command.IsMarked() {
 12179  			t.Fatalf("unexpectedly marked command argument: %#v", command.Marks())
 12180  		}
 12181  		req.UIOutput.Output(fmt.Sprintf("Executing: %q", command.AsString()))
 12182  		return
 12183  	}
 12184  	p.PlanResourceChangeFn = testDiffFn
 12185  	p.ApplyResourceChangeFn = testApplyFn
 12186  
 12187  	h := new(MockHook)
 12188  	ctx := testContext2(t, &ContextOpts{
 12189  		Hooks: []Hook{h},
 12190  		Providers: map[addrs.Provider]providers.Factory{
 12191  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 12192  		},
 12193  		Provisioners: map[string]provisioners.Factory{
 12194  			"shell": testProvisionerFuncFixed(pr),
 12195  		},
 12196  	})
 12197  
 12198  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 12199  		Mode: plans.NormalMode,
 12200  		SetVariables: InputValues{
 12201  			"password": &InputValue{
 12202  				Value:      cty.StringVal("secret"),
 12203  				SourceType: ValueFromCaller,
 12204  			},
 12205  		},
 12206  	})
 12207  	assertNoErrors(t, diags)
 12208  
 12209  	// "restart" provisioner
 12210  	pr.CloseCalled = false
 12211  
 12212  	state, diags := ctx.Apply(plan, m)
 12213  	if diags.HasErrors() {
 12214  		logDiagnostics(t, diags)
 12215  		t.Fatal("apply failed")
 12216  	}
 12217  
 12218  	actual := strings.TrimSpace(state.String())
 12219  	expected := strings.TrimSpace(testTerraformApplyProvisionerSensitiveStr)
 12220  	if actual != expected {
 12221  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
 12222  	}
 12223  
 12224  	// Verify apply was invoked
 12225  	if !pr.ProvisionResourceCalled {
 12226  		t.Fatalf("provisioner was not called on apply")
 12227  	}
 12228  
 12229  	// Verify output was suppressed
 12230  	if !h.ProvisionOutputCalled {
 12231  		t.Fatalf("ProvisionOutput hook not called")
 12232  	}
 12233  	if got, doNotWant := h.ProvisionOutputMessage, "secret"; strings.Contains(got, doNotWant) {
 12234  		t.Errorf("sensitive value %q included in output:\n%s", doNotWant, got)
 12235  	}
 12236  	if got, want := h.ProvisionOutputMessage, "output suppressed"; !strings.Contains(got, want) {
 12237  		t.Errorf("expected hook to be called with %q, but was:\n%s", want, got)
 12238  	}
 12239  }
 12240  
 12241  func TestContext2Apply_warnings(t *testing.T) {
 12242  	m := testModuleInline(t, map[string]string{
 12243  		"main.tf": `
 12244  resource "test_resource" "foo" {
 12245  }`,
 12246  	})
 12247  
 12248  	p := testProvider("test")
 12249  	p.PlanResourceChangeFn = testDiffFn
 12250  
 12251  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
 12252  		resp := testApplyFn(req)
 12253  
 12254  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warning"))
 12255  		return resp
 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, states.NewState(), DefaultPlanOpts)
 12265  	assertNoErrors(t, diags)
 12266  
 12267  	state, diags := ctx.Apply(plan, m)
 12268  	if diags.HasErrors() {
 12269  		t.Fatalf("diags: %s", diags.Err())
 12270  	}
 12271  
 12272  	inst := state.ResourceInstance(mustResourceInstanceAddr("test_resource.foo"))
 12273  	if inst == nil {
 12274  		t.Fatal("missing 'test_resource.foo' in state:", state)
 12275  	}
 12276  }
 12277  
 12278  func TestContext2Apply_rpcDiagnostics(t *testing.T) {
 12279  	m := testModuleInline(t, map[string]string{
 12280  		"main.tf": `
 12281  resource "test_instance" "a" {
 12282  }
 12283  `,
 12284  	})
 12285  
 12286  	p := testProvider("test")
 12287  	p.PlanResourceChangeFn = testDiffFn
 12288  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 12289  		resp = testApplyFn(req)
 12290  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("don't frobble"))
 12291  		return resp
 12292  	}
 12293  
 12294  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
 12295  		ResourceTypes: map[string]*configschema.Block{
 12296  			"test_instance": {
 12297  				Attributes: map[string]*configschema.Attribute{
 12298  					"id": {Type: cty.String, Computed: true},
 12299  				},
 12300  			},
 12301  		},
 12302  	})
 12303  
 12304  	ctx := testContext2(t, &ContextOpts{
 12305  		Providers: map[addrs.Provider]providers.Factory{
 12306  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12307  		},
 12308  	})
 12309  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12310  	if diags.HasErrors() {
 12311  		t.Fatal(diags.Err())
 12312  	}
 12313  
 12314  	_, diags = ctx.Apply(plan, m)
 12315  	if diags.HasErrors() {
 12316  		t.Fatal(diags.Err())
 12317  	}
 12318  
 12319  	if len(diags) == 0 {
 12320  		t.Fatal("expected warnings")
 12321  	}
 12322  
 12323  	for _, d := range diags {
 12324  		des := d.Description().Summary
 12325  		if !strings.Contains(des, "frobble") {
 12326  			t.Fatalf(`expected frobble, got %q`, des)
 12327  		}
 12328  	}
 12329  }
 12330  
 12331  func TestContext2Apply_dataSensitive(t *testing.T) {
 12332  	m := testModule(t, "apply-data-sensitive")
 12333  	p := testProvider("null")
 12334  	p.PlanResourceChangeFn = testDiffFn
 12335  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 12336  		// add the required id
 12337  		m := req.Config.AsValueMap()
 12338  		m["id"] = cty.StringVal("foo")
 12339  
 12340  		return providers.ReadDataSourceResponse{
 12341  			State: cty.ObjectVal(m),
 12342  		}
 12343  	}
 12344  
 12345  	ctx := testContext2(t, &ContextOpts{
 12346  		Providers: map[addrs.Provider]providers.Factory{
 12347  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
 12348  		},
 12349  	})
 12350  
 12351  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
 12352  	if diags.HasErrors() {
 12353  		t.Fatalf("diags: %s", diags.Err())
 12354  	} else {
 12355  		t.Logf(legacyDiffComparisonString(plan.Changes))
 12356  	}
 12357  
 12358  	state, diags := ctx.Apply(plan, m)
 12359  	assertNoErrors(t, diags)
 12360  
 12361  	addr := mustResourceInstanceAddr("data.null_data_source.testing")
 12362  
 12363  	dataSourceState := state.ResourceInstance(addr)
 12364  	pvms := dataSourceState.Current.AttrSensitivePaths
 12365  	if len(pvms) != 1 {
 12366  		t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 12367  	}
 12368  	pvm := pvms[0]
 12369  	if gotPath, wantPath := pvm.Path, cty.GetAttrPath("foo"); !gotPath.Equals(wantPath) {
 12370  		t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 12371  	}
 12372  	if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 12373  		t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 12374  	}
 12375  }
 12376  
 12377  func TestContext2Apply_errorRestorePrivateData(t *testing.T) {
 12378  	// empty config to remove our resource
 12379  	m := testModuleInline(t, map[string]string{
 12380  		"main.tf": "",
 12381  	})
 12382  
 12383  	p := simpleMockProvider()
 12384  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
 12385  		// we error during apply, which will trigger core to preserve the last
 12386  		// known state, including private data
 12387  		Diagnostics: tfdiags.Diagnostics(nil).Append(errors.New("oops")),
 12388  	}
 12389  
 12390  	addr := mustResourceInstanceAddr("test_object.a")
 12391  
 12392  	state := states.BuildState(func(s *states.SyncState) {
 12393  		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
 12394  			Status:    states.ObjectReady,
 12395  			AttrsJSON: []byte(`{"id":"foo"}`),
 12396  			Private:   []byte("private"),
 12397  		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
 12398  	})
 12399  
 12400  	ctx := testContext2(t, &ContextOpts{
 12401  		Providers: map[addrs.Provider]providers.Factory{
 12402  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12403  		},
 12404  	})
 12405  
 12406  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
 12407  	if diags.HasErrors() {
 12408  		t.Fatal(diags.Err())
 12409  	}
 12410  
 12411  	state, _ = ctx.Apply(plan, m)
 12412  	if string(state.ResourceInstance(addr).Current.Private) != "private" {
 12413  		t.Fatal("missing private data in state")
 12414  	}
 12415  }
 12416  
 12417  func TestContext2Apply_errorRestoreStatus(t *testing.T) {
 12418  	// empty config to remove our resource
 12419  	m := testModuleInline(t, map[string]string{
 12420  		"main.tf": "",
 12421  	})
 12422  
 12423  	p := simpleMockProvider()
 12424  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 12425  		// We error during apply, but return the current object state.
 12426  		resp.Diagnostics = resp.Diagnostics.Append(errors.New("oops"))
 12427  		// return a warning too to make sure it isn't dropped
 12428  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warned"))
 12429  		resp.NewState = req.PriorState
 12430  		resp.Private = req.PlannedPrivate
 12431  		return resp
 12432  	}
 12433  
 12434  	addr := mustResourceInstanceAddr("test_object.a")
 12435  
 12436  	state := states.BuildState(func(s *states.SyncState) {
 12437  		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
 12438  			Status:       states.ObjectTainted,
 12439  			AttrsJSON:    []byte(`{"test_string":"foo"}`),
 12440  			Private:      []byte("private"),
 12441  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.b")},
 12442  		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
 12443  	})
 12444  
 12445  	ctx := testContext2(t, &ContextOpts{
 12446  		Providers: map[addrs.Provider]providers.Factory{
 12447  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12448  		},
 12449  	})
 12450  
 12451  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
 12452  	if diags.HasErrors() {
 12453  		t.Fatal(diags.Err())
 12454  	}
 12455  
 12456  	state, diags = ctx.Apply(plan, m)
 12457  
 12458  	errString := diags.ErrWithWarnings().Error()
 12459  	if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") {
 12460  		t.Fatalf("error missing expected info: %q", errString)
 12461  	}
 12462  
 12463  	if len(diags) != 2 {
 12464  		t.Fatalf("expected 1 error and 1 warning, got: %q", errString)
 12465  	}
 12466  
 12467  	res := state.ResourceInstance(addr)
 12468  	if res == nil {
 12469  		t.Fatal("resource was removed from state")
 12470  	}
 12471  
 12472  	if res.Current.Status != states.ObjectTainted {
 12473  		t.Fatal("resource should still be tainted in the state")
 12474  	}
 12475  
 12476  	if len(res.Current.Dependencies) != 1 || !res.Current.Dependencies[0].Equal(mustConfigResourceAddr("test_object.b")) {
 12477  		t.Fatalf("incorrect dependencies, got %q", res.Current.Dependencies)
 12478  	}
 12479  
 12480  	if string(res.Current.Private) != "private" {
 12481  		t.Fatalf("incorrect private data, got %q", res.Current.Private)
 12482  	}
 12483  }
 12484  
 12485  func TestContext2Apply_nonConformingResponse(t *testing.T) {
 12486  	// empty config to remove our resource
 12487  	m := testModuleInline(t, map[string]string{
 12488  		"main.tf": `
 12489  resource "test_object" "a" {
 12490    test_string = "x"
 12491  }
 12492  `,
 12493  	})
 12494  
 12495  	p := simpleMockProvider()
 12496  	respDiags := tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("warned"))
 12497  	respDiags = respDiags.Append(errors.New("oops"))
 12498  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
 12499  		// Don't lose these diagnostics
 12500  		Diagnostics: respDiags,
 12501  		// This state is missing required attributes, and should produce an error
 12502  		NewState: cty.ObjectVal(map[string]cty.Value{
 12503  			"test_string": cty.StringVal("x"),
 12504  		}),
 12505  	}
 12506  
 12507  	ctx := testContext2(t, &ContextOpts{
 12508  		Providers: map[addrs.Provider]providers.Factory{
 12509  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12510  		},
 12511  	})
 12512  
 12513  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12514  	if diags.HasErrors() {
 12515  		t.Fatal(diags.Err())
 12516  	}
 12517  
 12518  	_, diags = ctx.Apply(plan, m)
 12519  	errString := diags.ErrWithWarnings().Error()
 12520  	if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") {
 12521  		t.Fatalf("error missing expected info: %q", errString)
 12522  	}
 12523  
 12524  	// we should have more than the ones returned from the provider, and they
 12525  	// should not be coalesced into a single value
 12526  	if len(diags) < 3 {
 12527  		t.Fatalf("incorrect diagnostics, got %d values with %s", len(diags), diags.ErrWithWarnings())
 12528  	}
 12529  }
 12530  
 12531  func TestContext2Apply_nilResponse(t *testing.T) {
 12532  	// empty config to remove our resource
 12533  	m := testModuleInline(t, map[string]string{
 12534  		"main.tf": `
 12535  resource "test_object" "a" {
 12536  }
 12537  `,
 12538  	})
 12539  
 12540  	p := simpleMockProvider()
 12541  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{}
 12542  
 12543  	ctx := testContext2(t, &ContextOpts{
 12544  		Providers: map[addrs.Provider]providers.Factory{
 12545  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12546  		},
 12547  	})
 12548  
 12549  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12550  	if diags.HasErrors() {
 12551  		t.Fatal(diags.Err())
 12552  	}
 12553  
 12554  	_, diags = ctx.Apply(plan, m)
 12555  	if !diags.HasErrors() {
 12556  		t.Fatal("expected and error")
 12557  	}
 12558  
 12559  	errString := diags.ErrWithWarnings().Error()
 12560  	if !strings.Contains(errString, "invalid nil value") {
 12561  		t.Fatalf("error missing expected info: %q", errString)
 12562  	}
 12563  }
 12564  
 12565  ////////////////////////////////////////////////////////////////////////////////
 12566  // NOTE: Due to the size of this file, new tests should be added to
 12567  // context_apply2_test.go.
 12568  ////////////////////////////////////////////////////////////////////////////////