github.com/jaredpalmer/terraform@v1.1.0-alpha20210908.0.20210911170307-88705c943a03/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/hashicorp/terraform/internal/addrs"
    22  	"github.com/hashicorp/terraform/internal/configs"
    23  	"github.com/hashicorp/terraform/internal/configs/configschema"
    24  	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
    25  	"github.com/hashicorp/terraform/internal/lang/marks"
    26  	"github.com/hashicorp/terraform/internal/plans"
    27  	"github.com/hashicorp/terraform/internal/providers"
    28  	"github.com/hashicorp/terraform/internal/provisioners"
    29  	"github.com/hashicorp/terraform/internal/states"
    30  	"github.com/hashicorp/terraform/internal/tfdiags"
    31  	"github.com/zclconf/go-cty/cty"
    32  	"github.com/zclconf/go-cty/cty/gocty"
    33  )
    34  
    35  func TestContext2Apply_basic(t *testing.T) {
    36  	m := testModule(t, "apply-good")
    37  	p := testProvider("aws")
    38  	p.PlanResourceChangeFn = testDiffFn
    39  	p.ApplyResourceChangeFn = testApplyFn
    40  	ctx := testContext2(t, &ContextOpts{
    41  		Providers: map[addrs.Provider]providers.Factory{
    42  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
    43  		},
    44  	})
    45  
    46  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
    47  	assertNoErrors(t, diags)
    48  
    49  	state, diags := ctx.Apply(plan, m)
    50  	if diags.HasErrors() {
    51  		t.Fatalf("diags: %s", diags.Err())
    52  	}
    53  
    54  	mod := state.RootModule()
    55  	if len(mod.Resources) < 2 {
    56  		t.Fatalf("bad: %#v", mod.Resources)
    57  	}
    58  
    59  	actual := strings.TrimSpace(state.String())
    60  	expected := strings.TrimSpace(testTerraformApplyStr)
    61  	if actual != expected {
    62  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
    63  	}
    64  }
    65  
    66  func TestContext2Apply_unstable(t *testing.T) {
    67  	// This tests behavior when the configuration contains an unstable value,
    68  	// such as the result of uuid() or timestamp(), where each call produces
    69  	// a different result.
    70  	//
    71  	// This is an important case to test because we need to ensure that
    72  	// we don't re-call the function during the apply phase: the value should
    73  	// be fixed during plan
    74  
    75  	m := testModule(t, "apply-unstable")
    76  	p := testProvider("test")
    77  	p.PlanResourceChangeFn = testDiffFn
    78  	ctx := testContext2(t, &ContextOpts{
    79  		Providers: map[addrs.Provider]providers.Factory{
    80  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
    81  		},
    82  	})
    83  
    84  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
    85  	if diags.HasErrors() {
    86  		t.Fatalf("unexpected error during Plan: %s", diags.Err())
    87  	}
    88  
    89  	addr := addrs.Resource{
    90  		Mode: addrs.ManagedResourceMode,
    91  		Type: "test_resource",
    92  		Name: "foo",
    93  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)
    94  	schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
    95  	rds := plan.Changes.ResourceInstance(addr)
    96  	rd, err := rds.Decode(schema.ImpliedType())
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  	if rd.After.GetAttr("random").IsKnown() {
   101  		t.Fatalf("Attribute 'random' has known value %#v; should be unknown in plan", rd.After.GetAttr("random"))
   102  	}
   103  
   104  	state, diags := ctx.Apply(plan, m)
   105  	if diags.HasErrors() {
   106  		t.Fatalf("unexpected error during Apply: %s", diags.Err())
   107  	}
   108  
   109  	mod := state.Module(addr.Module)
   110  	rss := state.ResourceInstance(addr)
   111  
   112  	if len(mod.Resources) != 1 {
   113  		t.Fatalf("wrong number of resources %d; want 1", len(mod.Resources))
   114  	}
   115  
   116  	rs, err := rss.Current.Decode(schema.ImpliedType())
   117  	if err != nil {
   118  		t.Fatalf("decode error: %v", err)
   119  	}
   120  	got := rs.Value.GetAttr("random")
   121  	if !got.IsKnown() {
   122  		t.Fatalf("random is still unknown after apply")
   123  	}
   124  	if got, want := len(got.AsString()), 36; got != want {
   125  		t.Fatalf("random string has wrong length %d; want %d", got, want)
   126  	}
   127  }
   128  
   129  func TestContext2Apply_escape(t *testing.T) {
   130  	m := testModule(t, "apply-escape")
   131  	p := testProvider("aws")
   132  	p.PlanResourceChangeFn = testDiffFn
   133  	p.ApplyResourceChangeFn = testApplyFn
   134  	ctx := testContext2(t, &ContextOpts{
   135  		Providers: map[addrs.Provider]providers.Factory{
   136  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   137  		},
   138  	})
   139  
   140  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   141  	assertNoErrors(t, diags)
   142  
   143  	state, diags := ctx.Apply(plan, m)
   144  	if diags.HasErrors() {
   145  		t.Fatalf("diags: %s", diags.Err())
   146  	}
   147  
   148  	checkStateString(t, state, `
   149  aws_instance.bar:
   150    ID = foo
   151    provider = provider["registry.terraform.io/hashicorp/aws"]
   152    foo = "bar"
   153    type = aws_instance
   154  `)
   155  }
   156  
   157  func TestContext2Apply_resourceCountOneList(t *testing.T) {
   158  	m := testModule(t, "apply-resource-count-one-list")
   159  	p := testProvider("null")
   160  	p.PlanResourceChangeFn = testDiffFn
   161  	p.ApplyResourceChangeFn = testApplyFn
   162  	ctx := testContext2(t, &ContextOpts{
   163  		Providers: map[addrs.Provider]providers.Factory{
   164  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   165  		},
   166  	})
   167  
   168  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   169  	assertNoErrors(t, diags)
   170  
   171  	state, diags := ctx.Apply(plan, m)
   172  	assertNoDiagnostics(t, diags)
   173  
   174  	got := strings.TrimSpace(state.String())
   175  	want := strings.TrimSpace(`null_resource.foo.0:
   176    ID = foo
   177    provider = provider["registry.terraform.io/hashicorp/null"]
   178  
   179  Outputs:
   180  
   181  test = [foo]`)
   182  	if got != want {
   183  		t.Fatalf("got:\n%s\n\nwant:\n%s\n", got, want)
   184  	}
   185  }
   186  func TestContext2Apply_resourceCountZeroList(t *testing.T) {
   187  	m := testModule(t, "apply-resource-count-zero-list")
   188  	p := testProvider("null")
   189  	p.PlanResourceChangeFn = testDiffFn
   190  	ctx := testContext2(t, &ContextOpts{
   191  		Providers: map[addrs.Provider]providers.Factory{
   192  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   193  		},
   194  	})
   195  
   196  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   197  	assertNoErrors(t, diags)
   198  
   199  	state, diags := ctx.Apply(plan, m)
   200  	if diags.HasErrors() {
   201  		t.Fatalf("diags: %s", diags.Err())
   202  	}
   203  
   204  	got := strings.TrimSpace(state.String())
   205  	want := strings.TrimSpace(`<no state>
   206  Outputs:
   207  
   208  test = []`)
   209  	if got != want {
   210  		t.Fatalf("wrong state\n\ngot:\n%s\n\nwant:\n%s\n", got, want)
   211  	}
   212  }
   213  
   214  func TestContext2Apply_resourceDependsOnModule(t *testing.T) {
   215  	m := testModule(t, "apply-resource-depends-on-module")
   216  	p := testProvider("aws")
   217  	p.PlanResourceChangeFn = testDiffFn
   218  
   219  	// verify the apply happens in the correct order
   220  	var mu sync.Mutex
   221  	var order []string
   222  
   223  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   224  		ami := req.PlannedState.GetAttr("ami").AsString()
   225  		switch ami {
   226  		case "child":
   227  
   228  			// make the child slower than the parent
   229  			time.Sleep(50 * time.Millisecond)
   230  
   231  			mu.Lock()
   232  			order = append(order, "child")
   233  			mu.Unlock()
   234  		case "parent":
   235  			mu.Lock()
   236  			order = append(order, "parent")
   237  			mu.Unlock()
   238  		}
   239  
   240  		return testApplyFn(req)
   241  	}
   242  
   243  	ctx := testContext2(t, &ContextOpts{
   244  		Providers: map[addrs.Provider]providers.Factory{
   245  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   246  		},
   247  	})
   248  
   249  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   250  	assertNoErrors(t, diags)
   251  
   252  	state, diags := ctx.Apply(plan, m)
   253  	if diags.HasErrors() {
   254  		t.Fatalf("diags: %s", diags.Err())
   255  	}
   256  
   257  	if !reflect.DeepEqual(order, []string{"child", "parent"}) {
   258  		t.Fatal("resources applied out of order")
   259  	}
   260  
   261  	checkStateString(t, state, testTerraformApplyResourceDependsOnModuleStr)
   262  }
   263  
   264  // Test that without a config, the Dependencies in the state are enough
   265  // to maintain proper ordering.
   266  func TestContext2Apply_resourceDependsOnModuleStateOnly(t *testing.T) {
   267  	m := testModule(t, "apply-resource-depends-on-module-empty")
   268  	p := testProvider("aws")
   269  	p.PlanResourceChangeFn = testDiffFn
   270  
   271  	state := states.NewState()
   272  	root := state.EnsureModule(addrs.RootModuleInstance)
   273  	root.SetResourceInstanceCurrent(
   274  		mustResourceInstanceAddr("aws_instance.a").Resource,
   275  		&states.ResourceInstanceObjectSrc{
   276  			Status:       states.ObjectReady,
   277  			AttrsJSON:    []byte(`{"id":"parent"}`),
   278  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.child")},
   279  		},
   280  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   281  	)
   282  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
   283  	child.SetResourceInstanceCurrent(
   284  		mustResourceInstanceAddr("aws_instance.child").Resource,
   285  		&states.ResourceInstanceObjectSrc{
   286  			Status:    states.ObjectReady,
   287  			AttrsJSON: []byte(`{"id":"child"}`),
   288  		},
   289  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   290  	)
   291  
   292  	{
   293  		// verify the apply happens in the correct order
   294  		var mu sync.Mutex
   295  		var order []string
   296  
   297  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   298  			id := req.PriorState.GetAttr("id")
   299  			if id.IsKnown() && id.AsString() == "parent" {
   300  				// make the dep slower than the parent
   301  				time.Sleep(50 * time.Millisecond)
   302  
   303  				mu.Lock()
   304  				order = append(order, "child")
   305  				mu.Unlock()
   306  			} else {
   307  				mu.Lock()
   308  				order = append(order, "parent")
   309  				mu.Unlock()
   310  			}
   311  
   312  			return testApplyFn(req)
   313  		}
   314  
   315  		ctx := testContext2(t, &ContextOpts{
   316  			Providers: map[addrs.Provider]providers.Factory{
   317  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   318  			},
   319  		})
   320  
   321  		plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   322  		assertNoErrors(t, diags)
   323  
   324  		state, diags := ctx.Apply(plan, m)
   325  		assertNoErrors(t, diags)
   326  
   327  		if !reflect.DeepEqual(order, []string{"child", "parent"}) {
   328  			t.Fatal("resources applied out of order")
   329  		}
   330  
   331  		checkStateString(t, state, "<no state>")
   332  	}
   333  }
   334  
   335  func TestContext2Apply_resourceDependsOnModuleDestroy(t *testing.T) {
   336  	m := testModule(t, "apply-resource-depends-on-module")
   337  	p := testProvider("aws")
   338  	p.PlanResourceChangeFn = testDiffFn
   339  
   340  	var globalState *states.State
   341  	{
   342  		ctx := testContext2(t, &ContextOpts{
   343  			Providers: map[addrs.Provider]providers.Factory{
   344  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   345  			},
   346  		})
   347  
   348  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   349  		assertNoErrors(t, diags)
   350  
   351  		state, diags := ctx.Apply(plan, m)
   352  		if diags.HasErrors() {
   353  			t.Fatalf("diags: %s", diags.Err())
   354  		}
   355  
   356  		globalState = state
   357  	}
   358  
   359  	{
   360  		// Wait for the dependency, sleep, and verify the graph never
   361  		// called a child.
   362  		var called int32
   363  		var checked bool
   364  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   365  			ami := req.PriorState.GetAttr("ami").AsString()
   366  			if ami == "parent" {
   367  				checked = true
   368  
   369  				// Sleep to allow parallel execution
   370  				time.Sleep(50 * time.Millisecond)
   371  
   372  				// Verify that called is 0 (dep not called)
   373  				if atomic.LoadInt32(&called) != 0 {
   374  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("module child should not be called"))
   375  					return resp
   376  				}
   377  			}
   378  
   379  			atomic.AddInt32(&called, 1)
   380  			return testApplyFn(req)
   381  		}
   382  
   383  		ctx := testContext2(t, &ContextOpts{
   384  			Providers: map[addrs.Provider]providers.Factory{
   385  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   386  			},
   387  		})
   388  
   389  		plan, diags := ctx.Plan(m, globalState, &PlanOpts{
   390  			Mode: plans.DestroyMode,
   391  		})
   392  		assertNoErrors(t, diags)
   393  
   394  		state, diags := ctx.Apply(plan, m)
   395  		if diags.HasErrors() {
   396  			t.Fatalf("diags: %s", diags.Err())
   397  		}
   398  
   399  		if !checked {
   400  			t.Fatal("should check")
   401  		}
   402  
   403  		checkStateString(t, state, `<no state>`)
   404  	}
   405  }
   406  
   407  func TestContext2Apply_resourceDependsOnModuleGrandchild(t *testing.T) {
   408  	m := testModule(t, "apply-resource-depends-on-module-deep")
   409  	p := testProvider("aws")
   410  	p.PlanResourceChangeFn = testDiffFn
   411  
   412  	{
   413  		// Wait for the dependency, sleep, and verify the graph never
   414  		// called a child.
   415  		var called int32
   416  		var checked bool
   417  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   418  			planned := req.PlannedState.AsValueMap()
   419  			if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" {
   420  				checked = true
   421  
   422  				// Sleep to allow parallel execution
   423  				time.Sleep(50 * time.Millisecond)
   424  
   425  				// Verify that called is 0 (dep not called)
   426  				if atomic.LoadInt32(&called) != 0 {
   427  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("aws_instance.a should not be called"))
   428  					return resp
   429  				}
   430  			}
   431  
   432  			atomic.AddInt32(&called, 1)
   433  			return testApplyFn(req)
   434  		}
   435  
   436  		ctx := testContext2(t, &ContextOpts{
   437  			Providers: map[addrs.Provider]providers.Factory{
   438  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   439  			},
   440  		})
   441  
   442  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   443  		assertNoErrors(t, diags)
   444  
   445  		state, diags := ctx.Apply(plan, m)
   446  		if diags.HasErrors() {
   447  			t.Fatalf("diags: %s", diags.Err())
   448  		}
   449  
   450  		if !checked {
   451  			t.Fatal("should check")
   452  		}
   453  
   454  		checkStateString(t, state, testTerraformApplyResourceDependsOnModuleDeepStr)
   455  	}
   456  }
   457  
   458  func TestContext2Apply_resourceDependsOnModuleInModule(t *testing.T) {
   459  	m := testModule(t, "apply-resource-depends-on-module-in-module")
   460  	p := testProvider("aws")
   461  	p.PlanResourceChangeFn = testDiffFn
   462  
   463  	{
   464  		// Wait for the dependency, sleep, and verify the graph never
   465  		// called a child.
   466  		var called int32
   467  		var checked bool
   468  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   469  			planned := req.PlannedState.AsValueMap()
   470  			if ami, ok := planned["ami"]; ok && ami.AsString() == "grandchild" {
   471  				checked = true
   472  
   473  				// Sleep to allow parallel execution
   474  				time.Sleep(50 * time.Millisecond)
   475  
   476  				// Verify that called is 0 (dep not called)
   477  				if atomic.LoadInt32(&called) != 0 {
   478  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("something else was applied before grandchild; grandchild should be first"))
   479  					return resp
   480  				}
   481  			}
   482  
   483  			atomic.AddInt32(&called, 1)
   484  			return testApplyFn(req)
   485  		}
   486  
   487  		ctx := testContext2(t, &ContextOpts{
   488  			Providers: map[addrs.Provider]providers.Factory{
   489  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   490  			},
   491  		})
   492  
   493  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   494  		assertNoErrors(t, diags)
   495  
   496  		state, diags := ctx.Apply(plan, m)
   497  		if diags.HasErrors() {
   498  			t.Fatalf("diags: %s", diags.Err())
   499  		}
   500  
   501  		if !checked {
   502  			t.Fatal("should check")
   503  		}
   504  
   505  		checkStateString(t, state, testTerraformApplyResourceDependsOnModuleInModuleStr)
   506  	}
   507  }
   508  
   509  func TestContext2Apply_mapVarBetweenModules(t *testing.T) {
   510  	m := testModule(t, "apply-map-var-through-module")
   511  	p := testProvider("null")
   512  	p.PlanResourceChangeFn = testDiffFn
   513  	p.ApplyResourceChangeFn = testApplyFn
   514  	ctx := testContext2(t, &ContextOpts{
   515  		Providers: map[addrs.Provider]providers.Factory{
   516  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
   517  		},
   518  	})
   519  
   520  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   521  	assertNoErrors(t, diags)
   522  
   523  	state, diags := ctx.Apply(plan, m)
   524  	if diags.HasErrors() {
   525  		t.Fatalf("diags: %s", diags.Err())
   526  	}
   527  
   528  	actual := strings.TrimSpace(state.String())
   529  	expected := strings.TrimSpace(`<no state>
   530  Outputs:
   531  
   532  amis_from_module = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }
   533  
   534  module.test:
   535    null_resource.noop:
   536      ID = foo
   537      provider = provider["registry.terraform.io/hashicorp/null"]
   538  
   539    Outputs:
   540  
   541    amis_out = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }`)
   542  	if actual != expected {
   543  		t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual)
   544  	}
   545  }
   546  
   547  func TestContext2Apply_refCount(t *testing.T) {
   548  	m := testModule(t, "apply-ref-count")
   549  	p := testProvider("aws")
   550  	p.PlanResourceChangeFn = testDiffFn
   551  	p.ApplyResourceChangeFn = testApplyFn
   552  	ctx := testContext2(t, &ContextOpts{
   553  		Providers: map[addrs.Provider]providers.Factory{
   554  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   555  		},
   556  	})
   557  
   558  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   559  	assertNoErrors(t, diags)
   560  
   561  	state, diags := ctx.Apply(plan, m)
   562  	if diags.HasErrors() {
   563  		t.Fatalf("diags: %s", diags.Err())
   564  	}
   565  
   566  	mod := state.RootModule()
   567  	if len(mod.Resources) < 2 {
   568  		t.Fatalf("bad: %#v", mod.Resources)
   569  	}
   570  
   571  	actual := strings.TrimSpace(state.String())
   572  	expected := strings.TrimSpace(testTerraformApplyRefCountStr)
   573  	if actual != expected {
   574  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   575  	}
   576  }
   577  
   578  func TestContext2Apply_providerAlias(t *testing.T) {
   579  	m := testModule(t, "apply-provider-alias")
   580  	p := testProvider("aws")
   581  	p.PlanResourceChangeFn = testDiffFn
   582  	p.ApplyResourceChangeFn = testApplyFn
   583  	ctx := testContext2(t, &ContextOpts{
   584  		Providers: map[addrs.Provider]providers.Factory{
   585  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   586  		},
   587  	})
   588  
   589  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   590  	assertNoErrors(t, diags)
   591  
   592  	state, diags := ctx.Apply(plan, m)
   593  	if diags.HasErrors() {
   594  		t.Fatalf("diags: %s", diags.Err())
   595  	}
   596  
   597  	mod := state.RootModule()
   598  	if len(mod.Resources) < 2 {
   599  		t.Fatalf("bad: %#v", mod.Resources)
   600  	}
   601  
   602  	actual := strings.TrimSpace(state.String())
   603  	expected := strings.TrimSpace(testTerraformApplyProviderAliasStr)
   604  	if actual != expected {
   605  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   606  	}
   607  }
   608  
   609  // Two providers that are configured should both be configured prior to apply
   610  func TestContext2Apply_providerAliasConfigure(t *testing.T) {
   611  	m := testModule(t, "apply-provider-alias-configure")
   612  
   613  	p2 := testProvider("another")
   614  	p2.ApplyResourceChangeFn = testApplyFn
   615  	p2.PlanResourceChangeFn = testDiffFn
   616  
   617  	ctx := testContext2(t, &ContextOpts{
   618  		Providers: map[addrs.Provider]providers.Factory{
   619  			addrs.NewDefaultProvider("another"): testProviderFuncFixed(p2),
   620  		},
   621  	})
   622  
   623  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   624  	if diags.HasErrors() {
   625  		t.Fatalf("diags: %s", diags.Err())
   626  	} else {
   627  		t.Logf(legacyDiffComparisonString(plan.Changes))
   628  	}
   629  
   630  	// Configure to record calls AFTER Plan above
   631  	var configCount int32
   632  	p2.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
   633  		atomic.AddInt32(&configCount, 1)
   634  
   635  		foo := req.Config.GetAttr("foo").AsString()
   636  		if foo != "bar" {
   637  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("foo: %#v", foo))
   638  		}
   639  
   640  		return
   641  	}
   642  
   643  	state, diags := ctx.Apply(plan, m)
   644  	if diags.HasErrors() {
   645  		t.Fatalf("diags: %s", diags.Err())
   646  	}
   647  
   648  	if configCount != 2 {
   649  		t.Fatalf("provider config expected 2 calls, got: %d", configCount)
   650  	}
   651  
   652  	actual := strings.TrimSpace(state.String())
   653  	expected := strings.TrimSpace(testTerraformApplyProviderAliasConfigStr)
   654  	if actual != expected {
   655  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   656  	}
   657  }
   658  
   659  // GH-2870
   660  func TestContext2Apply_providerWarning(t *testing.T) {
   661  	m := testModule(t, "apply-provider-warning")
   662  	p := testProvider("aws")
   663  	p.PlanResourceChangeFn = testDiffFn
   664  	p.ApplyResourceChangeFn = testApplyFn
   665  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
   666  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("just a warning"))
   667  		return
   668  	}
   669  	ctx := testContext2(t, &ContextOpts{
   670  		Providers: map[addrs.Provider]providers.Factory{
   671  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   672  		},
   673  	})
   674  
   675  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   676  	assertNoErrors(t, diags)
   677  
   678  	state, diags := ctx.Apply(plan, m)
   679  	if diags.HasErrors() {
   680  		t.Fatalf("diags: %s", diags.Err())
   681  	}
   682  
   683  	actual := strings.TrimSpace(state.String())
   684  	expected := strings.TrimSpace(`
   685  aws_instance.foo:
   686    ID = foo
   687    provider = provider["registry.terraform.io/hashicorp/aws"]
   688    type = aws_instance
   689  	`)
   690  	if actual != expected {
   691  		t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected)
   692  	}
   693  
   694  	if !p.ConfigureProviderCalled {
   695  		t.Fatalf("provider Configure() was never called!")
   696  	}
   697  }
   698  
   699  func TestContext2Apply_emptyModule(t *testing.T) {
   700  	// A module with only outputs (no resources)
   701  	m := testModule(t, "apply-empty-module")
   702  	p := testProvider("aws")
   703  	p.PlanResourceChangeFn = testDiffFn
   704  	ctx := testContext2(t, &ContextOpts{
   705  		Providers: map[addrs.Provider]providers.Factory{
   706  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   707  		},
   708  	})
   709  
   710  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   711  	assertNoErrors(t, diags)
   712  
   713  	state, diags := ctx.Apply(plan, m)
   714  	if diags.HasErrors() {
   715  		t.Fatalf("diags: %s", diags.Err())
   716  	}
   717  
   718  	actual := strings.TrimSpace(state.String())
   719  	actual = strings.Replace(actual, "  ", "", -1)
   720  	expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr)
   721  	if actual != expected {
   722  		t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected)
   723  	}
   724  }
   725  
   726  func TestContext2Apply_createBeforeDestroy(t *testing.T) {
   727  	m := testModule(t, "apply-good-create-before")
   728  	p := testProvider("aws")
   729  	p.PlanResourceChangeFn = testDiffFn
   730  	p.ApplyResourceChangeFn = testApplyFn
   731  	state := states.NewState()
   732  	root := state.EnsureModule(addrs.RootModuleInstance)
   733  	root.SetResourceInstanceCurrent(
   734  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   735  		&states.ResourceInstanceObjectSrc{
   736  			Status:    states.ObjectReady,
   737  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
   738  		},
   739  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   740  	)
   741  	ctx := testContext2(t, &ContextOpts{
   742  		Providers: map[addrs.Provider]providers.Factory{
   743  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   744  		},
   745  	})
   746  
   747  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   748  	if diags.HasErrors() {
   749  		t.Fatalf("diags: %s", diags.Err())
   750  	} else {
   751  		t.Logf(legacyDiffComparisonString(plan.Changes))
   752  	}
   753  
   754  	state, diags = ctx.Apply(plan, m)
   755  	if diags.HasErrors() {
   756  		t.Fatalf("diags: %s", diags.Err())
   757  	}
   758  
   759  	mod := state.RootModule()
   760  	if got, want := len(mod.Resources), 1; got != want {
   761  		t.Logf("state:\n%s", state)
   762  		t.Fatalf("wrong number of resources %d; want %d", got, want)
   763  	}
   764  
   765  	actual := strings.TrimSpace(state.String())
   766  	expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr)
   767  	if actual != expected {
   768  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
   769  	}
   770  }
   771  
   772  func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) {
   773  	m := testModule(t, "apply-good-create-before-update")
   774  	p := testProvider("aws")
   775  	p.PlanResourceChangeFn = testDiffFn
   776  
   777  	// signal that resource foo has started applying
   778  	fooChan := make(chan struct{})
   779  
   780  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
   781  		id := req.PriorState.GetAttr("id").AsString()
   782  		switch id {
   783  		case "bar":
   784  			select {
   785  			case <-fooChan:
   786  				resp.Diagnostics = resp.Diagnostics.Append(errors.New("bar must be updated before foo is destroyed"))
   787  				return resp
   788  			case <-time.After(100 * time.Millisecond):
   789  				// wait a moment to ensure that foo is not going to be destroyed first
   790  			}
   791  		case "foo":
   792  			close(fooChan)
   793  		}
   794  
   795  		return testApplyFn(req)
   796  	}
   797  
   798  	state := states.NewState()
   799  	root := state.EnsureModule(addrs.RootModuleInstance)
   800  	fooAddr := mustResourceInstanceAddr("aws_instance.foo")
   801  	root.SetResourceInstanceCurrent(
   802  		fooAddr.Resource,
   803  		&states.ResourceInstanceObjectSrc{
   804  			Status:              states.ObjectReady,
   805  			AttrsJSON:           []byte(`{"id":"foo","foo":"bar"}`),
   806  			CreateBeforeDestroy: true,
   807  		},
   808  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   809  	)
   810  	root.SetResourceInstanceCurrent(
   811  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   812  		&states.ResourceInstanceObjectSrc{
   813  			Status:              states.ObjectReady,
   814  			AttrsJSON:           []byte(`{"id":"bar","foo":"bar"}`),
   815  			CreateBeforeDestroy: true,
   816  			Dependencies:        []addrs.ConfigResource{fooAddr.ContainingResource().Config()},
   817  		},
   818  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   819  	)
   820  
   821  	ctx := testContext2(t, &ContextOpts{
   822  		Providers: map[addrs.Provider]providers.Factory{
   823  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   824  		},
   825  	})
   826  
   827  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   828  	if diags.HasErrors() {
   829  		t.Fatalf("diags: %s", diags.Err())
   830  	} else {
   831  		t.Logf(legacyDiffComparisonString(plan.Changes))
   832  	}
   833  
   834  	state, diags = ctx.Apply(plan, m)
   835  	if diags.HasErrors() {
   836  		t.Fatalf("diags: %s", diags.Err())
   837  	}
   838  
   839  	mod := state.RootModule()
   840  	if len(mod.Resources) != 1 {
   841  		t.Fatalf("bad: %s", state)
   842  	}
   843  
   844  	actual := strings.TrimSpace(state.String())
   845  	expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr)
   846  	if actual != expected {
   847  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
   848  	}
   849  }
   850  
   851  // This tests that when a CBD resource depends on a non-CBD resource,
   852  // we can still properly apply changes that require new for both.
   853  func TestContext2Apply_createBeforeDestroy_dependsNonCBD(t *testing.T) {
   854  	m := testModule(t, "apply-cbd-depends-non-cbd")
   855  	p := testProvider("aws")
   856  	p.PlanResourceChangeFn = testDiffFn
   857  	p.ApplyResourceChangeFn = testApplyFn
   858  
   859  	state := states.NewState()
   860  	root := state.EnsureModule(addrs.RootModuleInstance)
   861  	root.SetResourceInstanceCurrent(
   862  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   863  		&states.ResourceInstanceObjectSrc{
   864  			Status:    states.ObjectReady,
   865  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
   866  		},
   867  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   868  	)
   869  	root.SetResourceInstanceCurrent(
   870  		mustResourceInstanceAddr("aws_instance.foo").Resource,
   871  		&states.ResourceInstanceObjectSrc{
   872  			Status:    states.ObjectReady,
   873  			AttrsJSON: []byte(`{"id":"foo", "require_new": "abc"}`),
   874  		},
   875  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   876  	)
   877  
   878  	ctx := testContext2(t, &ContextOpts{
   879  		Providers: map[addrs.Provider]providers.Factory{
   880  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   881  		},
   882  	})
   883  
   884  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   885  	if diags.HasErrors() {
   886  		t.Fatalf("diags: %s", diags.Err())
   887  	} else {
   888  		t.Logf(legacyDiffComparisonString(plan.Changes))
   889  	}
   890  
   891  	state, diags = ctx.Apply(plan, m)
   892  	if diags.HasErrors() {
   893  		t.Fatalf("diags: %s", diags.Err())
   894  	}
   895  
   896  	checkStateString(t, state, `
   897  aws_instance.bar:
   898    ID = foo
   899    provider = provider["registry.terraform.io/hashicorp/aws"]
   900    require_new = yes
   901    type = aws_instance
   902    value = foo
   903  
   904    Dependencies:
   905      aws_instance.foo
   906  aws_instance.foo:
   907    ID = foo
   908    provider = provider["registry.terraform.io/hashicorp/aws"]
   909    require_new = yes
   910    type = aws_instance
   911  	`)
   912  }
   913  
   914  func TestContext2Apply_createBeforeDestroy_hook(t *testing.T) {
   915  	h := new(MockHook)
   916  	m := testModule(t, "apply-good-create-before")
   917  	p := testProvider("aws")
   918  	p.PlanResourceChangeFn = testDiffFn
   919  	p.ApplyResourceChangeFn = testApplyFn
   920  	state := states.NewState()
   921  	root := state.EnsureModule(addrs.RootModuleInstance)
   922  	root.SetResourceInstanceCurrent(
   923  		mustResourceInstanceAddr("aws_instance.bar").Resource,
   924  		&states.ResourceInstanceObjectSrc{
   925  			Status:    states.ObjectReady,
   926  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
   927  		},
   928  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   929  	)
   930  
   931  	var actual []cty.Value
   932  	var actualLock sync.Mutex
   933  	h.PostApplyFn = func(addr addrs.AbsResourceInstance, gen states.Generation, sv cty.Value, e error) (HookAction, error) {
   934  		actualLock.Lock()
   935  
   936  		defer actualLock.Unlock()
   937  		actual = append(actual, sv)
   938  		return HookActionContinue, nil
   939  	}
   940  
   941  	ctx := testContext2(t, &ContextOpts{
   942  		Hooks: []Hook{h},
   943  		Providers: map[addrs.Provider]providers.Factory{
   944  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   945  		},
   946  	})
   947  
   948  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   949  	if diags.HasErrors() {
   950  		t.Fatalf("diags: %s", diags.Err())
   951  	} else {
   952  		t.Logf(legacyDiffComparisonString(plan.Changes))
   953  	}
   954  
   955  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
   956  		t.Fatalf("apply errors: %s", diags.Err())
   957  	}
   958  
   959  	expected := []cty.Value{
   960  		cty.ObjectVal(map[string]cty.Value{
   961  			"id":          cty.StringVal("foo"),
   962  			"require_new": cty.StringVal("xyz"),
   963  			"type":        cty.StringVal("aws_instance"),
   964  		}),
   965  		cty.NullVal(cty.DynamicPseudoType),
   966  	}
   967  
   968  	cmpOpt := cmp.Transformer("ctyshim", hcl2shim.ConfigValueFromHCL2)
   969  	if !cmp.Equal(actual, expected, cmpOpt) {
   970  		t.Fatalf("wrong state snapshot sequence\n%s", cmp.Diff(expected, actual, cmpOpt))
   971  	}
   972  }
   973  
   974  // Test that we can perform an apply with CBD in a count with deposed instances.
   975  func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) {
   976  	m := testModule(t, "apply-cbd-count")
   977  	p := testProvider("aws")
   978  	p.PlanResourceChangeFn = testDiffFn
   979  	p.ApplyResourceChangeFn = testApplyFn
   980  
   981  	state := states.NewState()
   982  	root := state.EnsureModule(addrs.RootModuleInstance)
   983  	root.SetResourceInstanceCurrent(
   984  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
   985  		&states.ResourceInstanceObjectSrc{
   986  			Status:    states.ObjectTainted,
   987  			AttrsJSON: []byte(`{"id":"bar"}`),
   988  		},
   989  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   990  	)
   991  	root.SetResourceInstanceDeposed(
   992  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
   993  		states.NewDeposedKey(),
   994  		&states.ResourceInstanceObjectSrc{
   995  			Status:    states.ObjectTainted,
   996  			AttrsJSON: []byte(`{"id":"foo"}`),
   997  		},
   998  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   999  	)
  1000  	root.SetResourceInstanceCurrent(
  1001  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  1002  		&states.ResourceInstanceObjectSrc{
  1003  			Status:    states.ObjectTainted,
  1004  			AttrsJSON: []byte(`{"id":"bar"}`),
  1005  		},
  1006  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1007  	)
  1008  	root.SetResourceInstanceDeposed(
  1009  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  1010  		states.NewDeposedKey(),
  1011  		&states.ResourceInstanceObjectSrc{
  1012  			Status:    states.ObjectTainted,
  1013  			AttrsJSON: []byte(`{"id":"bar"}`),
  1014  		},
  1015  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1016  	)
  1017  
  1018  	ctx := testContext2(t, &ContextOpts{
  1019  		Providers: map[addrs.Provider]providers.Factory{
  1020  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1021  		},
  1022  	})
  1023  
  1024  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1025  	if diags.HasErrors() {
  1026  		t.Fatalf("diags: %s", diags.Err())
  1027  	} else {
  1028  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1029  	}
  1030  
  1031  	state, diags = ctx.Apply(plan, m)
  1032  	if diags.HasErrors() {
  1033  		t.Fatalf("diags: %s", diags.Err())
  1034  	}
  1035  
  1036  	checkStateString(t, state, `
  1037  aws_instance.bar.0:
  1038    ID = foo
  1039    provider = provider["registry.terraform.io/hashicorp/aws"]
  1040    foo = bar
  1041    type = aws_instance
  1042  aws_instance.bar.1:
  1043    ID = foo
  1044    provider = provider["registry.terraform.io/hashicorp/aws"]
  1045    foo = bar
  1046    type = aws_instance
  1047  	`)
  1048  }
  1049  
  1050  // Test that when we have a deposed instance but a good primary, we still
  1051  // destroy the deposed instance.
  1052  func TestContext2Apply_createBeforeDestroy_deposedOnly(t *testing.T) {
  1053  	m := testModule(t, "apply-cbd-deposed-only")
  1054  	p := testProvider("aws")
  1055  	p.PlanResourceChangeFn = testDiffFn
  1056  	p.ApplyResourceChangeFn = testApplyFn
  1057  
  1058  	state := states.NewState()
  1059  	root := state.EnsureModule(addrs.RootModuleInstance)
  1060  	root.SetResourceInstanceCurrent(
  1061  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1062  		&states.ResourceInstanceObjectSrc{
  1063  			Status:    states.ObjectReady,
  1064  			AttrsJSON: []byte(`{"id":"bar"}`),
  1065  		},
  1066  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1067  	)
  1068  	root.SetResourceInstanceDeposed(
  1069  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1070  		states.NewDeposedKey(),
  1071  		&states.ResourceInstanceObjectSrc{
  1072  			Status:    states.ObjectTainted,
  1073  			AttrsJSON: []byte(`{"id":"foo"}`),
  1074  		},
  1075  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1076  	)
  1077  
  1078  	ctx := testContext2(t, &ContextOpts{
  1079  		Providers: map[addrs.Provider]providers.Factory{
  1080  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1081  		},
  1082  	})
  1083  
  1084  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1085  	if diags.HasErrors() {
  1086  		t.Fatalf("diags: %s", diags.Err())
  1087  	} else {
  1088  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1089  	}
  1090  
  1091  	state, diags = ctx.Apply(plan, m)
  1092  	if diags.HasErrors() {
  1093  		t.Fatalf("diags: %s", diags.Err())
  1094  	}
  1095  
  1096  	checkStateString(t, state, `
  1097  aws_instance.bar:
  1098    ID = bar
  1099    provider = provider["registry.terraform.io/hashicorp/aws"]
  1100    type = aws_instance
  1101  	`)
  1102  }
  1103  
  1104  func TestContext2Apply_destroyComputed(t *testing.T) {
  1105  	m := testModule(t, "apply-destroy-computed")
  1106  	p := testProvider("aws")
  1107  	p.PlanResourceChangeFn = testDiffFn
  1108  	state := states.NewState()
  1109  	root := state.EnsureModule(addrs.RootModuleInstance)
  1110  	root.SetResourceInstanceCurrent(
  1111  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1112  		&states.ResourceInstanceObjectSrc{
  1113  			Status:    states.ObjectReady,
  1114  			AttrsJSON: []byte(`{"id":"foo", "output": "value"}`),
  1115  		},
  1116  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1117  	)
  1118  	ctx := testContext2(t, &ContextOpts{
  1119  		Providers: map[addrs.Provider]providers.Factory{
  1120  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1121  		},
  1122  	})
  1123  
  1124  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1125  		Mode: plans.DestroyMode,
  1126  	})
  1127  	if diags.HasErrors() {
  1128  		logDiagnostics(t, diags)
  1129  		t.Fatal("plan failed")
  1130  	} else {
  1131  		t.Logf("plan:\n\n%s", legacyDiffComparisonString(plan.Changes))
  1132  	}
  1133  
  1134  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1135  		logDiagnostics(t, diags)
  1136  		t.Fatal("apply failed")
  1137  	}
  1138  }
  1139  
  1140  // Test that the destroy operation uses depends_on as a source of ordering.
  1141  func TestContext2Apply_destroyDependsOn(t *testing.T) {
  1142  	// It is possible for this to be racy, so we loop a number of times
  1143  	// just to check.
  1144  	for i := 0; i < 10; i++ {
  1145  		testContext2Apply_destroyDependsOn(t)
  1146  	}
  1147  }
  1148  
  1149  func testContext2Apply_destroyDependsOn(t *testing.T) {
  1150  	m := testModule(t, "apply-destroy-depends-on")
  1151  	p := testProvider("aws")
  1152  	p.PlanResourceChangeFn = testDiffFn
  1153  
  1154  	state := states.NewState()
  1155  	root := state.EnsureModule(addrs.RootModuleInstance)
  1156  	root.SetResourceInstanceCurrent(
  1157  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1158  		&states.ResourceInstanceObjectSrc{
  1159  			Status:    states.ObjectReady,
  1160  			AttrsJSON: []byte(`{"id":"bar"}`),
  1161  		},
  1162  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1163  	)
  1164  	root.SetResourceInstanceCurrent(
  1165  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1166  		&states.ResourceInstanceObjectSrc{
  1167  			Status:       states.ObjectReady,
  1168  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1169  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
  1170  		},
  1171  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1172  	)
  1173  
  1174  	// Record the order we see Apply
  1175  	var actual []string
  1176  	var actualLock sync.Mutex
  1177  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1178  		actualLock.Lock()
  1179  		defer actualLock.Unlock()
  1180  		id := req.PriorState.GetAttr("id").AsString()
  1181  		actual = append(actual, id)
  1182  
  1183  		return testApplyFn(req)
  1184  	}
  1185  
  1186  	ctx := testContext2(t, &ContextOpts{
  1187  		Providers: map[addrs.Provider]providers.Factory{
  1188  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1189  		},
  1190  		Parallelism: 1, // To check ordering
  1191  	})
  1192  
  1193  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1194  		Mode: plans.DestroyMode,
  1195  	})
  1196  	assertNoErrors(t, diags)
  1197  
  1198  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1199  		t.Fatalf("apply errors: %s", diags.Err())
  1200  	}
  1201  
  1202  	expected := []string{"foo", "bar"}
  1203  	if !reflect.DeepEqual(actual, expected) {
  1204  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1205  	}
  1206  }
  1207  
  1208  // Test that destroy ordering is correct with dependencies only
  1209  // in the state.
  1210  func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) {
  1211  	newState := states.NewState()
  1212  	root := newState.EnsureModule(addrs.RootModuleInstance)
  1213  	root.SetResourceInstanceCurrent(
  1214  		addrs.Resource{
  1215  			Mode: addrs.ManagedResourceMode,
  1216  			Type: "aws_instance",
  1217  			Name: "foo",
  1218  		}.Instance(addrs.NoKey),
  1219  		&states.ResourceInstanceObjectSrc{
  1220  			Status:       states.ObjectReady,
  1221  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1222  			Dependencies: []addrs.ConfigResource{},
  1223  		},
  1224  		addrs.AbsProviderConfig{
  1225  			Provider: addrs.NewDefaultProvider("aws"),
  1226  			Module:   addrs.RootModule,
  1227  		},
  1228  	)
  1229  	root.SetResourceInstanceCurrent(
  1230  		addrs.Resource{
  1231  			Mode: addrs.ManagedResourceMode,
  1232  			Type: "aws_instance",
  1233  			Name: "bar",
  1234  		}.Instance(addrs.NoKey),
  1235  		&states.ResourceInstanceObjectSrc{
  1236  			Status:    states.ObjectReady,
  1237  			AttrsJSON: []byte(`{"id":"bar"}`),
  1238  			Dependencies: []addrs.ConfigResource{
  1239  				{
  1240  					Resource: addrs.Resource{
  1241  						Mode: addrs.ManagedResourceMode,
  1242  						Type: "aws_instance",
  1243  						Name: "foo",
  1244  					},
  1245  					Module: root.Addr.Module(),
  1246  				},
  1247  			},
  1248  		},
  1249  		addrs.AbsProviderConfig{
  1250  			Provider: addrs.NewDefaultProvider("aws"),
  1251  			Module:   addrs.RootModule,
  1252  		},
  1253  	)
  1254  
  1255  	// It is possible for this to be racy, so we loop a number of times
  1256  	// just to check.
  1257  	for i := 0; i < 10; i++ {
  1258  		t.Run("new", func(t *testing.T) {
  1259  			testContext2Apply_destroyDependsOnStateOnly(t, newState)
  1260  		})
  1261  	}
  1262  }
  1263  
  1264  func testContext2Apply_destroyDependsOnStateOnly(t *testing.T, state *states.State) {
  1265  	state = state.DeepCopy()
  1266  	m := testModule(t, "empty")
  1267  	p := testProvider("aws")
  1268  	p.PlanResourceChangeFn = testDiffFn
  1269  	// Record the order we see Apply
  1270  	var actual []string
  1271  	var actualLock sync.Mutex
  1272  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1273  		actualLock.Lock()
  1274  		defer actualLock.Unlock()
  1275  		id := req.PriorState.GetAttr("id").AsString()
  1276  		actual = append(actual, id)
  1277  		return testApplyFn(req)
  1278  	}
  1279  
  1280  	ctx := testContext2(t, &ContextOpts{
  1281  		Providers: map[addrs.Provider]providers.Factory{
  1282  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1283  		},
  1284  		Parallelism: 1, // To check ordering
  1285  	})
  1286  
  1287  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1288  		Mode: plans.DestroyMode,
  1289  	})
  1290  	assertNoErrors(t, diags)
  1291  
  1292  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1293  		t.Fatalf("apply errors: %s", diags.Err())
  1294  	}
  1295  
  1296  	expected := []string{"bar", "foo"}
  1297  	if !reflect.DeepEqual(actual, expected) {
  1298  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1299  	}
  1300  }
  1301  
  1302  // Test that destroy ordering is correct with dependencies only
  1303  // in the state within a module (GH-11749)
  1304  func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) {
  1305  	newState := states.NewState()
  1306  	child := newState.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1307  	child.SetResourceInstanceCurrent(
  1308  		addrs.Resource{
  1309  			Mode: addrs.ManagedResourceMode,
  1310  			Type: "aws_instance",
  1311  			Name: "foo",
  1312  		}.Instance(addrs.NoKey),
  1313  		&states.ResourceInstanceObjectSrc{
  1314  			Status:       states.ObjectReady,
  1315  			AttrsJSON:    []byte(`{"id":"foo"}`),
  1316  			Dependencies: []addrs.ConfigResource{},
  1317  		},
  1318  		addrs.AbsProviderConfig{
  1319  			Provider: addrs.NewDefaultProvider("aws"),
  1320  			Module:   addrs.RootModule,
  1321  		},
  1322  	)
  1323  	child.SetResourceInstanceCurrent(
  1324  		addrs.Resource{
  1325  			Mode: addrs.ManagedResourceMode,
  1326  			Type: "aws_instance",
  1327  			Name: "bar",
  1328  		}.Instance(addrs.NoKey),
  1329  		&states.ResourceInstanceObjectSrc{
  1330  			Status:    states.ObjectReady,
  1331  			AttrsJSON: []byte(`{"id":"bar"}`),
  1332  			Dependencies: []addrs.ConfigResource{
  1333  				{
  1334  					Resource: addrs.Resource{
  1335  						Mode: addrs.ManagedResourceMode,
  1336  						Type: "aws_instance",
  1337  						Name: "foo",
  1338  					},
  1339  					Module: child.Addr.Module(),
  1340  				},
  1341  			},
  1342  		},
  1343  		addrs.AbsProviderConfig{
  1344  			Provider: addrs.NewDefaultProvider("aws"),
  1345  			Module:   addrs.RootModule,
  1346  		},
  1347  	)
  1348  
  1349  	// It is possible for this to be racy, so we loop a number of times
  1350  	// just to check.
  1351  	for i := 0; i < 10; i++ {
  1352  		t.Run("new", func(t *testing.T) {
  1353  			testContext2Apply_destroyDependsOnStateOnlyModule(t, newState)
  1354  		})
  1355  	}
  1356  }
  1357  
  1358  func testContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T, state *states.State) {
  1359  	state = state.DeepCopy()
  1360  	m := testModule(t, "empty")
  1361  	p := testProvider("aws")
  1362  	p.PlanResourceChangeFn = testDiffFn
  1363  
  1364  	// Record the order we see Apply
  1365  	var actual []string
  1366  	var actualLock sync.Mutex
  1367  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1368  		actualLock.Lock()
  1369  		defer actualLock.Unlock()
  1370  		id := req.PriorState.GetAttr("id").AsString()
  1371  		actual = append(actual, id)
  1372  		return testApplyFn(req)
  1373  	}
  1374  
  1375  	ctx := testContext2(t, &ContextOpts{
  1376  		Providers: map[addrs.Provider]providers.Factory{
  1377  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1378  		},
  1379  		Parallelism: 1, // To check ordering
  1380  	})
  1381  
  1382  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1383  		Mode: plans.DestroyMode,
  1384  	})
  1385  	assertNoErrors(t, diags)
  1386  
  1387  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1388  		t.Fatalf("apply errors: %s", diags.Err())
  1389  	}
  1390  
  1391  	expected := []string{"bar", "foo"}
  1392  	if !reflect.DeepEqual(actual, expected) {
  1393  		t.Fatalf("wrong order\ngot:  %#v\nwant: %#v", actual, expected)
  1394  	}
  1395  }
  1396  
  1397  func TestContext2Apply_dataBasic(t *testing.T) {
  1398  	m := testModule(t, "apply-data-basic")
  1399  	p := testProvider("null")
  1400  	p.PlanResourceChangeFn = testDiffFn
  1401  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  1402  		State: cty.ObjectVal(map[string]cty.Value{
  1403  			"id":  cty.StringVal("yo"),
  1404  			"foo": cty.NullVal(cty.String),
  1405  		}),
  1406  	}
  1407  
  1408  	ctx := testContext2(t, &ContextOpts{
  1409  		Providers: map[addrs.Provider]providers.Factory{
  1410  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  1411  		},
  1412  	})
  1413  
  1414  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1415  	if diags.HasErrors() {
  1416  		t.Fatalf("diags: %s", diags.Err())
  1417  	} else {
  1418  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1419  	}
  1420  
  1421  	state, diags := ctx.Apply(plan, m)
  1422  	assertNoErrors(t, diags)
  1423  
  1424  	actual := strings.TrimSpace(state.String())
  1425  	expected := strings.TrimSpace(testTerraformApplyDataBasicStr)
  1426  	if actual != expected {
  1427  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1428  	}
  1429  }
  1430  
  1431  func TestContext2Apply_destroyData(t *testing.T) {
  1432  	m := testModule(t, "apply-destroy-data-resource")
  1433  	p := testProvider("null")
  1434  	p.PlanResourceChangeFn = testDiffFn
  1435  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  1436  		return providers.ReadDataSourceResponse{
  1437  			State: req.Config,
  1438  		}
  1439  	}
  1440  
  1441  	state := states.NewState()
  1442  	root := state.EnsureModule(addrs.RootModuleInstance)
  1443  	root.SetResourceInstanceCurrent(
  1444  		mustResourceInstanceAddr("data.null_data_source.testing").Resource,
  1445  		&states.ResourceInstanceObjectSrc{
  1446  			Status:    states.ObjectReady,
  1447  			AttrsJSON: []byte(`{"id":"-"}`),
  1448  		},
  1449  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/null"]`),
  1450  	)
  1451  
  1452  	hook := &testHook{}
  1453  	ctx := testContext2(t, &ContextOpts{
  1454  		Providers: map[addrs.Provider]providers.Factory{
  1455  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  1456  		},
  1457  		Hooks: []Hook{hook},
  1458  	})
  1459  
  1460  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1461  		Mode: plans.DestroyMode,
  1462  	})
  1463  	if diags.HasErrors() {
  1464  		t.Fatalf("diags: %s", diags.Err())
  1465  	} else {
  1466  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1467  	}
  1468  
  1469  	newState, diags := ctx.Apply(plan, m)
  1470  	if diags.HasErrors() {
  1471  		t.Fatalf("diags: %s", diags.Err())
  1472  	}
  1473  
  1474  	if got := len(newState.Modules); got != 1 {
  1475  		t.Fatalf("state has %d modules after destroy; want 1", got)
  1476  	}
  1477  
  1478  	if got := len(newState.RootModule().Resources); got != 0 {
  1479  		t.Fatalf("state has %d resources after destroy; want 0", got)
  1480  	}
  1481  
  1482  	wantHookCalls := []*testHookCall{
  1483  		{"PreDiff", "data.null_data_source.testing"},
  1484  		{"PostDiff", "data.null_data_source.testing"},
  1485  		{"PreDiff", "data.null_data_source.testing"},
  1486  		{"PostDiff", "data.null_data_source.testing"},
  1487  		{"PostStateUpdate", ""},
  1488  	}
  1489  	if !reflect.DeepEqual(hook.Calls, wantHookCalls) {
  1490  		t.Errorf("wrong hook calls\ngot: %swant: %s", spew.Sdump(hook.Calls), spew.Sdump(wantHookCalls))
  1491  	}
  1492  }
  1493  
  1494  // https://github.com/hashicorp/terraform/pull/5096
  1495  func TestContext2Apply_destroySkipsCBD(t *testing.T) {
  1496  	// Config contains CBD resource depending on non-CBD resource, which triggers
  1497  	// a cycle if they are both replaced, but should _not_ trigger a cycle when
  1498  	// just doing a `terraform destroy`.
  1499  	m := testModule(t, "apply-destroy-cbd")
  1500  	p := testProvider("aws")
  1501  	p.PlanResourceChangeFn = testDiffFn
  1502  	state := states.NewState()
  1503  	root := state.EnsureModule(addrs.RootModuleInstance)
  1504  	root.SetResourceInstanceCurrent(
  1505  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1506  		&states.ResourceInstanceObjectSrc{
  1507  			Status:    states.ObjectReady,
  1508  			AttrsJSON: []byte(`{"id":"foo"}`),
  1509  		},
  1510  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1511  	)
  1512  	root.SetResourceInstanceCurrent(
  1513  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  1514  		&states.ResourceInstanceObjectSrc{
  1515  			Status:    states.ObjectReady,
  1516  			AttrsJSON: []byte(`{"id":"foo"}`),
  1517  		},
  1518  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1519  	)
  1520  
  1521  	ctx := testContext2(t, &ContextOpts{
  1522  		Providers: map[addrs.Provider]providers.Factory{
  1523  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1524  		},
  1525  	})
  1526  
  1527  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1528  		Mode: plans.DestroyMode,
  1529  	})
  1530  	if diags.HasErrors() {
  1531  		t.Fatalf("diags: %s", diags.Err())
  1532  	} else {
  1533  		t.Logf(legacyDiffComparisonString(plan.Changes))
  1534  	}
  1535  
  1536  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1537  		t.Fatalf("apply errors: %s", diags.Err())
  1538  	}
  1539  }
  1540  
  1541  func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) {
  1542  	m := testModule(t, "apply-destroy-mod-var-provider-config")
  1543  	p := testProvider("aws")
  1544  	p.PlanResourceChangeFn = testDiffFn
  1545  	state := states.NewState()
  1546  	root := state.EnsureModule(addrs.RootModuleInstance)
  1547  	root.SetResourceInstanceCurrent(
  1548  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1549  		&states.ResourceInstanceObjectSrc{
  1550  			Status:    states.ObjectReady,
  1551  			AttrsJSON: []byte(`{"id":"foo"}`),
  1552  		},
  1553  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1554  	)
  1555  	ctx := testContext2(t, &ContextOpts{
  1556  		Providers: map[addrs.Provider]providers.Factory{
  1557  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1558  		},
  1559  	})
  1560  
  1561  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1562  		Mode: plans.DestroyMode,
  1563  	})
  1564  	assertNoErrors(t, diags)
  1565  
  1566  	_, diags = ctx.Apply(plan, m)
  1567  	if diags.HasErrors() {
  1568  		t.Fatalf("diags: %s", diags.Err())
  1569  	}
  1570  }
  1571  
  1572  func TestContext2Apply_destroyCrossProviders(t *testing.T) {
  1573  	m := testModule(t, "apply-destroy-cross-providers")
  1574  
  1575  	p_aws := testProvider("aws")
  1576  	p_aws.ApplyResourceChangeFn = testApplyFn
  1577  	p_aws.PlanResourceChangeFn = testDiffFn
  1578  	p_aws.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1579  		ResourceTypes: map[string]*configschema.Block{
  1580  			"aws_instance": {
  1581  				Attributes: map[string]*configschema.Attribute{
  1582  					"id": {
  1583  						Type:     cty.String,
  1584  						Computed: true,
  1585  					},
  1586  				},
  1587  			},
  1588  			"aws_vpc": {
  1589  				Attributes: map[string]*configschema.Attribute{
  1590  					"id": {
  1591  						Type:     cty.String,
  1592  						Computed: true,
  1593  					},
  1594  					"value": {
  1595  						Type:     cty.String,
  1596  						Optional: true,
  1597  					},
  1598  				},
  1599  			},
  1600  		},
  1601  	})
  1602  
  1603  	providers := map[addrs.Provider]providers.Factory{
  1604  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p_aws),
  1605  	}
  1606  
  1607  	ctx, m, state := getContextForApply_destroyCrossProviders(t, m, providers)
  1608  
  1609  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1610  		Mode: plans.DestroyMode,
  1611  	})
  1612  	assertNoErrors(t, diags)
  1613  
  1614  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  1615  		logDiagnostics(t, diags)
  1616  		t.Fatal("apply failed")
  1617  	}
  1618  }
  1619  
  1620  func getContextForApply_destroyCrossProviders(t *testing.T, m *configs.Config, providerFactories map[addrs.Provider]providers.Factory) (*Context, *configs.Config, *states.State) {
  1621  	state := states.NewState()
  1622  	root := state.EnsureModule(addrs.RootModuleInstance)
  1623  	root.SetResourceInstanceCurrent(
  1624  		mustResourceInstanceAddr("aws_instance.shared").Resource,
  1625  		&states.ResourceInstanceObjectSrc{
  1626  			Status:    states.ObjectReady,
  1627  			AttrsJSON: []byte(`{"id":"test"}`),
  1628  		},
  1629  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1630  	)
  1631  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  1632  	child.SetResourceInstanceCurrent(
  1633  		mustResourceInstanceAddr("aws_vpc.bar").Resource,
  1634  		&states.ResourceInstanceObjectSrc{
  1635  			Status:    states.ObjectReady,
  1636  			AttrsJSON: []byte(`{"id": "vpc-aaabbb12", "value":"test"}`),
  1637  		},
  1638  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1639  	)
  1640  
  1641  	ctx := testContext2(t, &ContextOpts{
  1642  		Providers: providerFactories,
  1643  	})
  1644  
  1645  	return ctx, m, state
  1646  }
  1647  
  1648  func TestContext2Apply_minimal(t *testing.T) {
  1649  	m := testModule(t, "apply-minimal")
  1650  	p := testProvider("aws")
  1651  	p.PlanResourceChangeFn = testDiffFn
  1652  	p.ApplyResourceChangeFn = testApplyFn
  1653  	ctx := testContext2(t, &ContextOpts{
  1654  		Providers: map[addrs.Provider]providers.Factory{
  1655  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1656  		},
  1657  	})
  1658  
  1659  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1660  	assertNoErrors(t, diags)
  1661  
  1662  	state, diags := ctx.Apply(plan, m)
  1663  	if diags.HasErrors() {
  1664  		t.Fatalf("diags: %s", diags.Err())
  1665  	}
  1666  
  1667  	actual := strings.TrimSpace(state.String())
  1668  	expected := strings.TrimSpace(testTerraformApplyMinimalStr)
  1669  	if actual != expected {
  1670  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1671  	}
  1672  }
  1673  
  1674  func TestContext2Apply_cancel(t *testing.T) {
  1675  	stopped := false
  1676  
  1677  	m := testModule(t, "apply-cancel")
  1678  	p := testProvider("aws")
  1679  	ctx := testContext2(t, &ContextOpts{
  1680  		Providers: map[addrs.Provider]providers.Factory{
  1681  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1682  		},
  1683  	})
  1684  
  1685  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1686  		if !stopped {
  1687  			stopped = true
  1688  			go ctx.Stop()
  1689  
  1690  			for {
  1691  				if ctx.sh.Stopped() {
  1692  					break
  1693  				}
  1694  				time.Sleep(10 * time.Millisecond)
  1695  			}
  1696  		}
  1697  		return testApplyFn(req)
  1698  	}
  1699  	p.PlanResourceChangeFn = testDiffFn
  1700  
  1701  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1702  	assertNoErrors(t, diags)
  1703  
  1704  	// Start the Apply in a goroutine
  1705  	var applyDiags tfdiags.Diagnostics
  1706  	stateCh := make(chan *states.State)
  1707  	go func() {
  1708  		state, diags := ctx.Apply(plan, m)
  1709  		applyDiags = diags
  1710  
  1711  		stateCh <- state
  1712  	}()
  1713  
  1714  	state := <-stateCh
  1715  	// only expecting an early exit error
  1716  	if !applyDiags.HasErrors() {
  1717  		t.Fatal("expected early exit error")
  1718  	}
  1719  
  1720  	for _, d := range applyDiags {
  1721  		desc := d.Description()
  1722  		if desc.Summary != "execution halted" {
  1723  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  1724  		}
  1725  	}
  1726  
  1727  	actual := strings.TrimSpace(state.String())
  1728  	expected := strings.TrimSpace(testTerraformApplyCancelStr)
  1729  	if actual != expected {
  1730  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1731  	}
  1732  
  1733  	if !p.StopCalled {
  1734  		t.Fatal("stop should be called")
  1735  	}
  1736  }
  1737  
  1738  func TestContext2Apply_cancelBlock(t *testing.T) {
  1739  	m := testModule(t, "apply-cancel-block")
  1740  	p := testProvider("aws")
  1741  	ctx := testContext2(t, &ContextOpts{
  1742  		Providers: map[addrs.Provider]providers.Factory{
  1743  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1744  		},
  1745  	})
  1746  
  1747  	applyCh := make(chan struct{})
  1748  	p.PlanResourceChangeFn = testDiffFn
  1749  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  1750  		close(applyCh)
  1751  
  1752  		for !ctx.sh.Stopped() {
  1753  			// Wait for stop to be called. We call Gosched here so that
  1754  			// the other goroutines can always be scheduled to set Stopped.
  1755  			runtime.Gosched()
  1756  		}
  1757  
  1758  		// Sleep
  1759  		time.Sleep(100 * time.Millisecond)
  1760  		return testApplyFn(req)
  1761  	}
  1762  
  1763  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1764  	assertNoErrors(t, diags)
  1765  
  1766  	// Start the Apply in a goroutine
  1767  	var applyDiags tfdiags.Diagnostics
  1768  	stateCh := make(chan *states.State)
  1769  	go func() {
  1770  		state, diags := ctx.Apply(plan, m)
  1771  		applyDiags = diags
  1772  
  1773  		stateCh <- state
  1774  	}()
  1775  
  1776  	stopDone := make(chan struct{})
  1777  	go func() {
  1778  		defer close(stopDone)
  1779  		<-applyCh
  1780  		ctx.Stop()
  1781  	}()
  1782  
  1783  	// Make sure that stop blocks
  1784  	select {
  1785  	case <-stopDone:
  1786  		t.Fatal("stop should block")
  1787  	case <-time.After(10 * time.Millisecond):
  1788  	}
  1789  
  1790  	// Wait for stop
  1791  	select {
  1792  	case <-stopDone:
  1793  	case <-time.After(500 * time.Millisecond):
  1794  		t.Fatal("stop should be done")
  1795  	}
  1796  
  1797  	// Wait for apply to complete
  1798  	state := <-stateCh
  1799  	// only expecting an early exit error
  1800  	if !applyDiags.HasErrors() {
  1801  		t.Fatal("expected early exit error")
  1802  	}
  1803  
  1804  	for _, d := range applyDiags {
  1805  		desc := d.Description()
  1806  		if desc.Summary != "execution halted" {
  1807  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  1808  		}
  1809  	}
  1810  
  1811  	checkStateString(t, state, `
  1812  aws_instance.foo:
  1813    ID = foo
  1814    provider = provider["registry.terraform.io/hashicorp/aws"]
  1815    num = 2
  1816    type = aws_instance
  1817  	`)
  1818  }
  1819  
  1820  func TestContext2Apply_cancelProvisioner(t *testing.T) {
  1821  	m := testModule(t, "apply-cancel-provisioner")
  1822  	p := testProvider("aws")
  1823  	p.PlanResourceChangeFn = testDiffFn
  1824  	p.ApplyResourceChangeFn = testApplyFn
  1825  
  1826  	pr := testProvisioner()
  1827  	pr.GetSchemaResponse = provisioners.GetSchemaResponse{
  1828  		Provisioner: &configschema.Block{
  1829  			Attributes: map[string]*configschema.Attribute{
  1830  				"foo": {
  1831  					Type:     cty.String,
  1832  					Optional: true,
  1833  				},
  1834  			},
  1835  		},
  1836  	}
  1837  
  1838  	ctx := testContext2(t, &ContextOpts{
  1839  		Providers: map[addrs.Provider]providers.Factory{
  1840  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1841  		},
  1842  		Provisioners: map[string]provisioners.Factory{
  1843  			"shell": testProvisionerFuncFixed(pr),
  1844  		},
  1845  	})
  1846  
  1847  	prStopped := make(chan struct{})
  1848  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  1849  		// Start the stop process
  1850  		go ctx.Stop()
  1851  
  1852  		<-prStopped
  1853  		return
  1854  	}
  1855  	pr.StopFn = func() error {
  1856  		close(prStopped)
  1857  		return nil
  1858  	}
  1859  
  1860  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1861  	assertNoErrors(t, diags)
  1862  
  1863  	// Start the Apply in a goroutine
  1864  	var applyDiags tfdiags.Diagnostics
  1865  	stateCh := make(chan *states.State)
  1866  	go func() {
  1867  		state, diags := ctx.Apply(plan, m)
  1868  		applyDiags = diags
  1869  
  1870  		stateCh <- state
  1871  	}()
  1872  
  1873  	// Wait for completion
  1874  	state := <-stateCh
  1875  
  1876  	// we are expecting only an early exit error
  1877  	if !applyDiags.HasErrors() {
  1878  		t.Fatal("expected early exit error")
  1879  	}
  1880  
  1881  	for _, d := range applyDiags {
  1882  		desc := d.Description()
  1883  		if desc.Summary != "execution halted" {
  1884  			t.Fatalf("unexpected error: %v", applyDiags.Err())
  1885  		}
  1886  	}
  1887  
  1888  	checkStateString(t, state, `
  1889  aws_instance.foo: (tainted)
  1890    ID = foo
  1891    provider = provider["registry.terraform.io/hashicorp/aws"]
  1892    num = 2
  1893    type = aws_instance
  1894  	`)
  1895  
  1896  	if !pr.StopCalled {
  1897  		t.Fatal("stop should be called")
  1898  	}
  1899  }
  1900  
  1901  func TestContext2Apply_compute(t *testing.T) {
  1902  	m := testModule(t, "apply-compute")
  1903  	p := testProvider("aws")
  1904  	p.PlanResourceChangeFn = testDiffFn
  1905  	p.ApplyResourceChangeFn = testApplyFn
  1906  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1907  		ResourceTypes: map[string]*configschema.Block{
  1908  			"aws_instance": {
  1909  				Attributes: map[string]*configschema.Attribute{
  1910  					"num": {
  1911  						Type:     cty.Number,
  1912  						Optional: true,
  1913  					},
  1914  					"compute": {
  1915  						Type:     cty.String,
  1916  						Optional: true,
  1917  					},
  1918  					"compute_value": {
  1919  						Type:     cty.String,
  1920  						Optional: true,
  1921  					},
  1922  					"foo": {
  1923  						Type:     cty.String,
  1924  						Optional: true,
  1925  					},
  1926  					"id": {
  1927  						Type:     cty.String,
  1928  						Computed: true,
  1929  					},
  1930  					"type": {
  1931  						Type:     cty.String,
  1932  						Computed: true,
  1933  					},
  1934  					"value": { // Populated from compute_value because compute = "value" in the config fixture
  1935  						Type:     cty.String,
  1936  						Computed: true,
  1937  					},
  1938  				},
  1939  			},
  1940  		},
  1941  	})
  1942  
  1943  	ctx := testContext2(t, &ContextOpts{
  1944  		Providers: map[addrs.Provider]providers.Factory{
  1945  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1946  		},
  1947  	})
  1948  
  1949  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  1950  		SetVariables: InputValues{
  1951  			"value": &InputValue{
  1952  				Value:      cty.NumberIntVal(1),
  1953  				SourceType: ValueFromCaller,
  1954  			},
  1955  		},
  1956  	})
  1957  	assertNoErrors(t, diags)
  1958  
  1959  	state, diags := ctx.Apply(plan, m)
  1960  	if diags.HasErrors() {
  1961  		t.Fatalf("unexpected errors: %s", diags.Err())
  1962  	}
  1963  
  1964  	actual := strings.TrimSpace(state.String())
  1965  	expected := strings.TrimSpace(testTerraformApplyComputeStr)
  1966  	if actual != expected {
  1967  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  1968  	}
  1969  }
  1970  
  1971  func TestContext2Apply_countDecrease(t *testing.T) {
  1972  	m := testModule(t, "apply-count-dec")
  1973  	p := testProvider("aws")
  1974  	p.PlanResourceChangeFn = testDiffFn
  1975  	p.ApplyResourceChangeFn = testApplyFn
  1976  	state := states.NewState()
  1977  	root := state.EnsureModule(addrs.RootModuleInstance)
  1978  	root.SetResourceInstanceCurrent(
  1979  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  1980  		&states.ResourceInstanceObjectSrc{
  1981  			Status:    states.ObjectReady,
  1982  			AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`),
  1983  		},
  1984  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1985  	)
  1986  	root.SetResourceInstanceCurrent(
  1987  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  1988  		&states.ResourceInstanceObjectSrc{
  1989  			Status:    states.ObjectReady,
  1990  			AttrsJSON: []byte(`{"id":"bar","foo": "foo","type": "aws_instance"}`),
  1991  		},
  1992  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1993  	)
  1994  	root.SetResourceInstanceCurrent(
  1995  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  1996  		&states.ResourceInstanceObjectSrc{
  1997  			Status:    states.ObjectReady,
  1998  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  1999  		},
  2000  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2001  	)
  2002  
  2003  	ctx := testContext2(t, &ContextOpts{
  2004  		Providers: map[addrs.Provider]providers.Factory{
  2005  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2006  		},
  2007  	})
  2008  
  2009  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2010  	assertNoErrors(t, diags)
  2011  
  2012  	s, diags := ctx.Apply(plan, m)
  2013  	assertNoErrors(t, diags)
  2014  
  2015  	actual := strings.TrimSpace(s.String())
  2016  	expected := strings.TrimSpace(testTerraformApplyCountDecStr)
  2017  	if actual != expected {
  2018  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2019  	}
  2020  }
  2021  
  2022  func TestContext2Apply_countDecreaseToOneX(t *testing.T) {
  2023  	m := testModule(t, "apply-count-dec-one")
  2024  	p := testProvider("aws")
  2025  	p.PlanResourceChangeFn = testDiffFn
  2026  	state := states.NewState()
  2027  	root := state.EnsureModule(addrs.RootModuleInstance)
  2028  	root.SetResourceInstanceCurrent(
  2029  		mustResourceInstanceAddr("aws_instance.foo[0]").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  	root.SetResourceInstanceCurrent(
  2037  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  2038  		&states.ResourceInstanceObjectSrc{
  2039  			Status:    states.ObjectReady,
  2040  			AttrsJSON: []byte(`{"id":"bar"}`),
  2041  		},
  2042  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2043  	)
  2044  	root.SetResourceInstanceCurrent(
  2045  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  2046  		&states.ResourceInstanceObjectSrc{
  2047  			Status:    states.ObjectReady,
  2048  			AttrsJSON: []byte(`{"id":"bar"}`),
  2049  		},
  2050  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2051  	)
  2052  
  2053  	ctx := testContext2(t, &ContextOpts{
  2054  		Providers: map[addrs.Provider]providers.Factory{
  2055  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2056  		},
  2057  	})
  2058  
  2059  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2060  	assertNoErrors(t, diags)
  2061  
  2062  	s, diags := ctx.Apply(plan, m)
  2063  	if diags.HasErrors() {
  2064  		t.Fatalf("diags: %s", diags.Err())
  2065  	}
  2066  
  2067  	actual := strings.TrimSpace(s.String())
  2068  	expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr)
  2069  	if actual != expected {
  2070  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2071  	}
  2072  }
  2073  
  2074  // https://github.com/PeoplePerHour/terraform/pull/11
  2075  //
  2076  // This tests a case where both a "resource" and "resource.0" are in
  2077  // the state file, which apparently is a reasonable backwards compatibility
  2078  // concern found in the above 3rd party repo.
  2079  func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) {
  2080  	m := testModule(t, "apply-count-dec-one")
  2081  	p := testProvider("aws")
  2082  	p.PlanResourceChangeFn = testDiffFn
  2083  	state := states.NewState()
  2084  	root := state.EnsureModule(addrs.RootModuleInstance)
  2085  	root.SetResourceInstanceCurrent(
  2086  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2087  		&states.ResourceInstanceObjectSrc{
  2088  			Status:    states.ObjectReady,
  2089  			AttrsJSON: []byte(`{"id":"bar", "foo": "foo", "type": "aws_instance"}`),
  2090  		},
  2091  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2092  	)
  2093  	root.SetResourceInstanceCurrent(
  2094  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2095  		&states.ResourceInstanceObjectSrc{
  2096  			Status:    states.ObjectReady,
  2097  			AttrsJSON: []byte(`{"id":"baz", "type": "aws_instance"}`),
  2098  		},
  2099  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2100  	)
  2101  
  2102  	ctx := testContext2(t, &ContextOpts{
  2103  		Providers: map[addrs.Provider]providers.Factory{
  2104  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2105  		},
  2106  	})
  2107  
  2108  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2109  	assertNoErrors(t, diags)
  2110  	{
  2111  		got := strings.TrimSpace(legacyPlanComparisonString(state, plan.Changes))
  2112  		want := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedPlanStr)
  2113  		if got != want {
  2114  			t.Fatalf("wrong plan result\ngot:\n%s\nwant:\n%s", got, want)
  2115  		}
  2116  	}
  2117  
  2118  	s, diags := ctx.Apply(plan, m)
  2119  	if diags.HasErrors() {
  2120  		t.Fatalf("diags: %s", diags.Err())
  2121  	}
  2122  
  2123  	actual := strings.TrimSpace(s.String())
  2124  	expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr)
  2125  	if actual != expected {
  2126  		t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2127  	}
  2128  }
  2129  
  2130  func TestContext2Apply_countTainted(t *testing.T) {
  2131  	m := testModule(t, "apply-count-tainted")
  2132  	p := testProvider("aws")
  2133  	p.PlanResourceChangeFn = testDiffFn
  2134  	p.ApplyResourceChangeFn = testApplyFn
  2135  	state := states.NewState()
  2136  	root := state.EnsureModule(addrs.RootModuleInstance)
  2137  	root.SetResourceInstanceCurrent(
  2138  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2139  		&states.ResourceInstanceObjectSrc{
  2140  			Status:    states.ObjectTainted,
  2141  			AttrsJSON: []byte(`{"id":"bar", "type": "aws_instance", "foo": "foo"}`),
  2142  		},
  2143  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2144  	)
  2145  	ctx := testContext2(t, &ContextOpts{
  2146  		Providers: map[addrs.Provider]providers.Factory{
  2147  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2148  		},
  2149  	})
  2150  
  2151  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2152  	assertNoErrors(t, diags)
  2153  	{
  2154  		got := strings.TrimSpace(legacyDiffComparisonString(plan.Changes))
  2155  		want := strings.TrimSpace(`
  2156  DESTROY/CREATE: aws_instance.foo[0]
  2157    foo:  "foo" => "foo"
  2158    id:   "bar" => "<computed>"
  2159    type: "aws_instance" => "<computed>"
  2160  CREATE: aws_instance.foo[1]
  2161    foo:  "" => "foo"
  2162    id:   "" => "<computed>"
  2163    type: "" => "<computed>"
  2164  `)
  2165  		if got != want {
  2166  			t.Fatalf("wrong plan\n\ngot:\n%s\n\nwant:\n%s", got, want)
  2167  		}
  2168  	}
  2169  
  2170  	s, diags := ctx.Apply(plan, m)
  2171  	assertNoErrors(t, diags)
  2172  
  2173  	got := strings.TrimSpace(s.String())
  2174  	want := strings.TrimSpace(`
  2175  aws_instance.foo.0:
  2176    ID = foo
  2177    provider = provider["registry.terraform.io/hashicorp/aws"]
  2178    foo = foo
  2179    type = aws_instance
  2180  aws_instance.foo.1:
  2181    ID = foo
  2182    provider = provider["registry.terraform.io/hashicorp/aws"]
  2183    foo = foo
  2184    type = aws_instance
  2185  `)
  2186  	if got != want {
  2187  		t.Fatalf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", got, want)
  2188  	}
  2189  }
  2190  
  2191  func TestContext2Apply_countVariable(t *testing.T) {
  2192  	m := testModule(t, "apply-count-variable")
  2193  	p := testProvider("aws")
  2194  	p.PlanResourceChangeFn = testDiffFn
  2195  	p.ApplyResourceChangeFn = testApplyFn
  2196  	ctx := testContext2(t, &ContextOpts{
  2197  		Providers: map[addrs.Provider]providers.Factory{
  2198  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2199  		},
  2200  	})
  2201  
  2202  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2203  	assertNoErrors(t, diags)
  2204  
  2205  	state, diags := ctx.Apply(plan, m)
  2206  	if diags.HasErrors() {
  2207  		t.Fatalf("diags: %s", diags.Err())
  2208  	}
  2209  
  2210  	actual := strings.TrimSpace(state.String())
  2211  	expected := strings.TrimSpace(testTerraformApplyCountVariableStr)
  2212  	if actual != expected {
  2213  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2214  	}
  2215  }
  2216  
  2217  func TestContext2Apply_countVariableRef(t *testing.T) {
  2218  	m := testModule(t, "apply-count-variable-ref")
  2219  	p := testProvider("aws")
  2220  	p.PlanResourceChangeFn = testDiffFn
  2221  	p.ApplyResourceChangeFn = testApplyFn
  2222  	ctx := testContext2(t, &ContextOpts{
  2223  		Providers: map[addrs.Provider]providers.Factory{
  2224  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2225  		},
  2226  	})
  2227  
  2228  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2229  	assertNoErrors(t, diags)
  2230  
  2231  	state, diags := ctx.Apply(plan, m)
  2232  	if diags.HasErrors() {
  2233  		t.Fatalf("diags: %s", diags.Err())
  2234  	}
  2235  
  2236  	actual := strings.TrimSpace(state.String())
  2237  	expected := strings.TrimSpace(testTerraformApplyCountVariableRefStr)
  2238  	if actual != expected {
  2239  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2240  	}
  2241  }
  2242  
  2243  func TestContext2Apply_provisionerInterpCount(t *testing.T) {
  2244  	// This test ensures that a provisioner can interpolate a resource count
  2245  	// even though the provisioner expression is evaluated during the plan
  2246  	// walk. https://github.com/hashicorp/terraform/issues/16840
  2247  
  2248  	m, snap := testModuleWithSnapshot(t, "apply-provisioner-interp-count")
  2249  
  2250  	p := testProvider("aws")
  2251  	p.PlanResourceChangeFn = testDiffFn
  2252  
  2253  	pr := testProvisioner()
  2254  
  2255  	Providers := map[addrs.Provider]providers.Factory{
  2256  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2257  	}
  2258  
  2259  	provisioners := map[string]provisioners.Factory{
  2260  		"local-exec": testProvisionerFuncFixed(pr),
  2261  	}
  2262  	ctx := testContext2(t, &ContextOpts{
  2263  		Providers:    Providers,
  2264  		Provisioners: provisioners,
  2265  	})
  2266  
  2267  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2268  	assertNoErrors(t, diags)
  2269  
  2270  	// We'll marshal and unmarshal the plan here, to ensure that we have
  2271  	// a clean new context as would be created if we separately ran
  2272  	// terraform plan -out=tfplan && terraform apply tfplan
  2273  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  2274  	if err != nil {
  2275  		t.Fatal(err)
  2276  	}
  2277  	ctxOpts.Providers = Providers
  2278  	ctxOpts.Provisioners = provisioners
  2279  	ctx, diags = NewContext(ctxOpts)
  2280  	if diags.HasErrors() {
  2281  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  2282  	}
  2283  
  2284  	// Applying the plan should now succeed
  2285  	_, diags = ctx.Apply(plan, m)
  2286  	if diags.HasErrors() {
  2287  		t.Fatalf("apply failed unexpectedly: %s", diags.Err())
  2288  	}
  2289  
  2290  	// Verify apply was invoked
  2291  	if !pr.ProvisionResourceCalled {
  2292  		t.Fatalf("provisioner was not called")
  2293  	}
  2294  }
  2295  
  2296  func TestContext2Apply_foreachVariable(t *testing.T) {
  2297  	m := testModule(t, "plan-for-each-unknown-value")
  2298  	p := testProvider("aws")
  2299  	p.PlanResourceChangeFn = testDiffFn
  2300  	p.ApplyResourceChangeFn = testApplyFn
  2301  	ctx := testContext2(t, &ContextOpts{
  2302  		Providers: map[addrs.Provider]providers.Factory{
  2303  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2304  		},
  2305  	})
  2306  
  2307  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2308  		Mode: plans.NormalMode,
  2309  		SetVariables: InputValues{
  2310  			"foo": &InputValue{
  2311  				Value: cty.StringVal("hello"),
  2312  			},
  2313  		},
  2314  	})
  2315  	assertNoErrors(t, diags)
  2316  
  2317  	state, diags := ctx.Apply(plan, m)
  2318  	if diags.HasErrors() {
  2319  		t.Fatalf("diags: %s", diags.Err())
  2320  	}
  2321  
  2322  	actual := strings.TrimSpace(state.String())
  2323  	expected := strings.TrimSpace(testTerraformApplyForEachVariableStr)
  2324  	if actual != expected {
  2325  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2326  	}
  2327  }
  2328  
  2329  func TestContext2Apply_moduleBasic(t *testing.T) {
  2330  	m := testModule(t, "apply-module")
  2331  	p := testProvider("aws")
  2332  	p.PlanResourceChangeFn = testDiffFn
  2333  	p.ApplyResourceChangeFn = testApplyFn
  2334  	ctx := testContext2(t, &ContextOpts{
  2335  		Providers: map[addrs.Provider]providers.Factory{
  2336  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2337  		},
  2338  	})
  2339  
  2340  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2341  	assertNoErrors(t, diags)
  2342  
  2343  	state, diags := ctx.Apply(plan, m)
  2344  	if diags.HasErrors() {
  2345  		t.Fatalf("diags: %s", diags.Err())
  2346  	}
  2347  
  2348  	actual := strings.TrimSpace(state.String())
  2349  	expected := strings.TrimSpace(testTerraformApplyModuleStr)
  2350  	if actual != expected {
  2351  		t.Fatalf("bad, expected:\n%s\n\nactual:\n%s", expected, actual)
  2352  	}
  2353  }
  2354  
  2355  func TestContext2Apply_moduleDestroyOrder(t *testing.T) {
  2356  	m := testModule(t, "apply-module-destroy-order")
  2357  	p := testProvider("aws")
  2358  	p.PlanResourceChangeFn = testDiffFn
  2359  
  2360  	// Create a custom apply function to track the order they were destroyed
  2361  	var order []string
  2362  	var orderLock sync.Mutex
  2363  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  2364  		id := req.PriorState.GetAttr("id").AsString()
  2365  
  2366  		if id == "b" {
  2367  			// Pause briefly to make any race conditions more visible, since
  2368  			// missing edges here can cause undeterministic ordering.
  2369  			time.Sleep(100 * time.Millisecond)
  2370  		}
  2371  
  2372  		orderLock.Lock()
  2373  		defer orderLock.Unlock()
  2374  
  2375  		order = append(order, id)
  2376  		resp.NewState = req.PlannedState
  2377  		return resp
  2378  	}
  2379  
  2380  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2381  		ResourceTypes: map[string]*configschema.Block{
  2382  			"aws_instance": {
  2383  				Attributes: map[string]*configschema.Attribute{
  2384  					"id":    {Type: cty.String, Required: true},
  2385  					"blah":  {Type: cty.String, Optional: true},
  2386  					"value": {Type: cty.String, Optional: true},
  2387  				},
  2388  			},
  2389  		},
  2390  	})
  2391  
  2392  	state := states.NewState()
  2393  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2394  	child.SetResourceInstanceCurrent(
  2395  		mustResourceInstanceAddr("aws_instance.a").Resource,
  2396  		&states.ResourceInstanceObjectSrc{
  2397  			Status:    states.ObjectReady,
  2398  			AttrsJSON: []byte(`{"id":"a"}`),
  2399  		},
  2400  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2401  	)
  2402  	root := state.EnsureModule(addrs.RootModuleInstance)
  2403  	root.SetResourceInstanceCurrent(
  2404  		mustResourceInstanceAddr("aws_instance.b").Resource,
  2405  		&states.ResourceInstanceObjectSrc{
  2406  			Status:       states.ObjectReady,
  2407  			AttrsJSON:    []byte(`{"id":"b"}`),
  2408  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("module.child.aws_instance.a")},
  2409  		},
  2410  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2411  	)
  2412  
  2413  	ctx := testContext2(t, &ContextOpts{
  2414  		Providers: map[addrs.Provider]providers.Factory{
  2415  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2416  		},
  2417  	})
  2418  
  2419  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  2420  		Mode: plans.DestroyMode,
  2421  	})
  2422  	assertNoErrors(t, diags)
  2423  
  2424  	state, diags = ctx.Apply(plan, m)
  2425  	if diags.HasErrors() {
  2426  		t.Fatalf("diags: %s", diags.Err())
  2427  	}
  2428  
  2429  	expected := []string{"b", "a"}
  2430  	if !reflect.DeepEqual(order, expected) {
  2431  		t.Errorf("wrong order\ngot: %#v\nwant: %#v", order, expected)
  2432  	}
  2433  
  2434  	{
  2435  		actual := strings.TrimSpace(state.String())
  2436  		expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr)
  2437  		if actual != expected {
  2438  			t.Errorf("wrong final state\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2439  		}
  2440  	}
  2441  }
  2442  
  2443  func TestContext2Apply_moduleInheritAlias(t *testing.T) {
  2444  	m := testModule(t, "apply-module-provider-inherit-alias")
  2445  	p := testProvider("aws")
  2446  	p.PlanResourceChangeFn = testDiffFn
  2447  	p.ApplyResourceChangeFn = testApplyFn
  2448  
  2449  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2450  		val := req.Config.GetAttr("value")
  2451  		if val.IsNull() {
  2452  			return
  2453  		}
  2454  
  2455  		root := req.Config.GetAttr("root")
  2456  		if !root.IsNull() {
  2457  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root"))
  2458  		}
  2459  
  2460  		return
  2461  	}
  2462  
  2463  	ctx := testContext2(t, &ContextOpts{
  2464  		Providers: map[addrs.Provider]providers.Factory{
  2465  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2466  		},
  2467  	})
  2468  
  2469  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2470  	assertNoErrors(t, diags)
  2471  
  2472  	state, diags := ctx.Apply(plan, m)
  2473  	if diags.HasErrors() {
  2474  		t.Fatalf("diags: %s", diags.Err())
  2475  	}
  2476  
  2477  	checkStateString(t, state, `
  2478  <no state>
  2479  module.child:
  2480    aws_instance.foo:
  2481      ID = foo
  2482      provider = provider["registry.terraform.io/hashicorp/aws"].eu
  2483      type = aws_instance
  2484  	`)
  2485  }
  2486  
  2487  func TestContext2Apply_orphanResource(t *testing.T) {
  2488  	// This is a two-step test:
  2489  	// 1. Apply a configuration with resources that have count set.
  2490  	//    This should place the empty resource object in the state to record
  2491  	//    that each exists, and record any instances.
  2492  	// 2. Apply an empty configuration against the same state, which should
  2493  	//    then clean up both the instances and the containing resource objects.
  2494  	p := testProvider("test")
  2495  	p.PlanResourceChangeFn = testDiffFn
  2496  	p.ApplyResourceChangeFn = testApplyFn
  2497  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2498  		ResourceTypes: map[string]*configschema.Block{
  2499  			"test_thing": {
  2500  				Attributes: map[string]*configschema.Attribute{
  2501  					"id":  {Type: cty.String, Computed: true},
  2502  					"foo": {Type: cty.String, Optional: true},
  2503  				},
  2504  			},
  2505  		},
  2506  	})
  2507  
  2508  	// Step 1: create the resources and instances
  2509  	m := testModule(t, "apply-orphan-resource")
  2510  	ctx := testContext2(t, &ContextOpts{
  2511  		Providers: map[addrs.Provider]providers.Factory{
  2512  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  2513  		},
  2514  	})
  2515  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2516  	assertNoErrors(t, diags)
  2517  	state, diags := ctx.Apply(plan, m)
  2518  	assertNoErrors(t, diags)
  2519  
  2520  	// At this point both resources should be recorded in the state, along
  2521  	// with the single instance associated with test_thing.one.
  2522  	want := states.BuildState(func(s *states.SyncState) {
  2523  		providerAddr := addrs.AbsProviderConfig{
  2524  			Provider: addrs.NewDefaultProvider("test"),
  2525  			Module:   addrs.RootModule,
  2526  		}
  2527  		oneAddr := addrs.Resource{
  2528  			Mode: addrs.ManagedResourceMode,
  2529  			Type: "test_thing",
  2530  			Name: "one",
  2531  		}.Absolute(addrs.RootModuleInstance)
  2532  		s.SetResourceProvider(oneAddr, providerAddr)
  2533  		s.SetResourceInstanceCurrent(oneAddr.Instance(addrs.IntKey(0)), &states.ResourceInstanceObjectSrc{
  2534  			Status:    states.ObjectReady,
  2535  			AttrsJSON: []byte(`{"id":"foo"}`),
  2536  		}, providerAddr)
  2537  	})
  2538  
  2539  	if state.String() != want.String() {
  2540  		t.Fatalf("wrong state after step 1\n%s", cmp.Diff(want, state))
  2541  	}
  2542  
  2543  	// Step 2: update with an empty config, to destroy everything
  2544  	m = testModule(t, "empty")
  2545  	ctx = testContext2(t, &ContextOpts{
  2546  		Providers: map[addrs.Provider]providers.Factory{
  2547  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  2548  		},
  2549  	})
  2550  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  2551  	assertNoErrors(t, diags)
  2552  	state, diags = ctx.Apply(plan, m)
  2553  	assertNoErrors(t, diags)
  2554  
  2555  	// The state should now be _totally_ empty, with just an empty root module
  2556  	// (since that always exists) and no resources at all.
  2557  	want = states.NewState()
  2558  	if !cmp.Equal(state, want) {
  2559  		t.Fatalf("wrong state after step 2\ngot: %swant: %s", spew.Sdump(state), spew.Sdump(want))
  2560  	}
  2561  
  2562  }
  2563  
  2564  func TestContext2Apply_moduleOrphanInheritAlias(t *testing.T) {
  2565  	m := testModule(t, "apply-module-provider-inherit-alias-orphan")
  2566  	p := testProvider("aws")
  2567  	p.PlanResourceChangeFn = testDiffFn
  2568  
  2569  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2570  		val := req.Config.GetAttr("value")
  2571  		if val.IsNull() {
  2572  			return
  2573  		}
  2574  
  2575  		root := req.Config.GetAttr("root")
  2576  		if !root.IsNull() {
  2577  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("child should not get root"))
  2578  		}
  2579  
  2580  		return
  2581  	}
  2582  
  2583  	// Create a state with an orphan module
  2584  	state := states.NewState()
  2585  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2586  	child.SetResourceInstanceCurrent(
  2587  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2588  		&states.ResourceInstanceObjectSrc{
  2589  			Status:    states.ObjectReady,
  2590  			AttrsJSON: []byte(`{"id":"bar"}`),
  2591  		},
  2592  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2593  	)
  2594  
  2595  	ctx := testContext2(t, &ContextOpts{
  2596  		Providers: map[addrs.Provider]providers.Factory{
  2597  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2598  		},
  2599  	})
  2600  
  2601  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2602  	assertNoErrors(t, diags)
  2603  
  2604  	state, diags = ctx.Apply(plan, m)
  2605  	if diags.HasErrors() {
  2606  		t.Fatalf("diags: %s", diags.Err())
  2607  	}
  2608  
  2609  	if !p.ConfigureProviderCalled {
  2610  		t.Fatal("must call configure")
  2611  	}
  2612  
  2613  	checkStateString(t, state, "<no state>")
  2614  }
  2615  
  2616  func TestContext2Apply_moduleOrphanProvider(t *testing.T) {
  2617  	m := testModule(t, "apply-module-orphan-provider-inherit")
  2618  	p := testProvider("aws")
  2619  	p.PlanResourceChangeFn = testDiffFn
  2620  
  2621  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2622  		val := req.Config.GetAttr("value")
  2623  		if val.IsNull() {
  2624  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2625  		}
  2626  
  2627  		return
  2628  	}
  2629  
  2630  	// Create a state with an orphan module
  2631  	state := states.NewState()
  2632  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  2633  	child.SetResourceInstanceCurrent(
  2634  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2635  		&states.ResourceInstanceObjectSrc{
  2636  			Status:    states.ObjectReady,
  2637  			AttrsJSON: []byte(`{"id":"bar"}`),
  2638  		},
  2639  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2640  	)
  2641  
  2642  	ctx := testContext2(t, &ContextOpts{
  2643  		Providers: map[addrs.Provider]providers.Factory{
  2644  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2645  		},
  2646  	})
  2647  
  2648  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2649  	assertNoErrors(t, diags)
  2650  
  2651  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2652  		t.Fatalf("apply errors: %s", diags.Err())
  2653  	}
  2654  }
  2655  
  2656  func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) {
  2657  	m := testModule(t, "apply-module-orphan-provider-inherit")
  2658  	p := testProvider("aws")
  2659  	p.PlanResourceChangeFn = testDiffFn
  2660  
  2661  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2662  		val := req.Config.GetAttr("value")
  2663  		if val.IsNull() {
  2664  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2665  		}
  2666  
  2667  		return
  2668  	}
  2669  
  2670  	// Create a state with an orphan module that is nested (grandchild)
  2671  	state := states.NewState()
  2672  	child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child", addrs.NoKey))
  2673  	child.SetResourceInstanceCurrent(
  2674  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  2675  		&states.ResourceInstanceObjectSrc{
  2676  			Status:    states.ObjectReady,
  2677  			AttrsJSON: []byte(`{"id":"bar"}`),
  2678  		},
  2679  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2680  	)
  2681  
  2682  	ctx := testContext2(t, &ContextOpts{
  2683  		Providers: map[addrs.Provider]providers.Factory{
  2684  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2685  		},
  2686  	})
  2687  
  2688  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2689  	assertNoErrors(t, diags)
  2690  
  2691  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2692  		t.Fatalf("apply errors: %s", diags.Err())
  2693  	}
  2694  }
  2695  
  2696  func TestContext2Apply_moduleGrandchildProvider(t *testing.T) {
  2697  	m := testModule(t, "apply-module-grandchild-provider-inherit")
  2698  	p := testProvider("aws")
  2699  	p.PlanResourceChangeFn = testDiffFn
  2700  
  2701  	var callLock sync.Mutex
  2702  	called := false
  2703  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  2704  		val := req.Config.GetAttr("value")
  2705  		if val.IsNull() {
  2706  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  2707  		}
  2708  
  2709  		callLock.Lock()
  2710  		called = true
  2711  		callLock.Unlock()
  2712  
  2713  		return
  2714  	}
  2715  
  2716  	ctx := testContext2(t, &ContextOpts{
  2717  		Providers: map[addrs.Provider]providers.Factory{
  2718  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2719  		},
  2720  	})
  2721  
  2722  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2723  	assertNoErrors(t, diags)
  2724  
  2725  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2726  		t.Fatalf("apply errors: %s", diags.Err())
  2727  	}
  2728  
  2729  	callLock.Lock()
  2730  	defer callLock.Unlock()
  2731  	if called != true {
  2732  		t.Fatalf("err: configure never called")
  2733  	}
  2734  }
  2735  
  2736  // This tests an issue where all the providers in a module but not
  2737  // in the root weren't being added to the root properly. In this test
  2738  // case: aws is explicitly added to root, but "test" should be added to.
  2739  // With the bug, it wasn't.
  2740  func TestContext2Apply_moduleOnlyProvider(t *testing.T) {
  2741  	m := testModule(t, "apply-module-only-provider")
  2742  	p := testProvider("aws")
  2743  	p.PlanResourceChangeFn = testDiffFn
  2744  	p.ApplyResourceChangeFn = testApplyFn
  2745  	pTest := testProvider("test")
  2746  	pTest.ApplyResourceChangeFn = testApplyFn
  2747  	pTest.PlanResourceChangeFn = testDiffFn
  2748  
  2749  	ctx := testContext2(t, &ContextOpts{
  2750  		Providers: map[addrs.Provider]providers.Factory{
  2751  			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
  2752  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
  2753  		},
  2754  	})
  2755  
  2756  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2757  	assertNoErrors(t, diags)
  2758  
  2759  	state, diags := ctx.Apply(plan, m)
  2760  	if diags.HasErrors() {
  2761  		t.Fatalf("diags: %s", diags.Err())
  2762  	}
  2763  
  2764  	actual := strings.TrimSpace(state.String())
  2765  	expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr)
  2766  	if actual != expected {
  2767  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2768  	}
  2769  }
  2770  
  2771  func TestContext2Apply_moduleProviderAlias(t *testing.T) {
  2772  	m := testModule(t, "apply-module-provider-alias")
  2773  	p := testProvider("aws")
  2774  	p.PlanResourceChangeFn = testDiffFn
  2775  	p.ApplyResourceChangeFn = testApplyFn
  2776  	ctx := testContext2(t, &ContextOpts{
  2777  		Providers: map[addrs.Provider]providers.Factory{
  2778  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2779  		},
  2780  	})
  2781  
  2782  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2783  	assertNoErrors(t, diags)
  2784  
  2785  	state, diags := ctx.Apply(plan, m)
  2786  	if diags.HasErrors() {
  2787  		t.Fatalf("diags: %s", diags.Err())
  2788  	}
  2789  
  2790  	actual := strings.TrimSpace(state.String())
  2791  	expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr)
  2792  	if actual != expected {
  2793  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2794  	}
  2795  }
  2796  
  2797  func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) {
  2798  	m := testModule(t, "apply-module-provider-alias")
  2799  	p := testProvider("aws")
  2800  	p.PlanResourceChangeFn = testDiffFn
  2801  	ctx := testContext2(t, &ContextOpts{
  2802  		Providers: map[addrs.Provider]providers.Factory{
  2803  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2804  		},
  2805  	})
  2806  
  2807  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2808  		Mode: plans.NormalMode,
  2809  		Targets: []addrs.Targetable{
  2810  			addrs.ConfigResource{
  2811  				Module: addrs.RootModule,
  2812  				Resource: addrs.Resource{
  2813  					Mode: addrs.ManagedResourceMode,
  2814  					Type: "nonexistent",
  2815  					Name: "thing",
  2816  				},
  2817  			},
  2818  		},
  2819  	})
  2820  	assertNoErrors(t, diags)
  2821  
  2822  	state, diags := ctx.Apply(plan, m)
  2823  	if diags.HasErrors() {
  2824  		t.Fatalf("diags: %s", diags.Err())
  2825  	}
  2826  
  2827  	actual := strings.TrimSpace(state.String())
  2828  	expected := strings.TrimSpace(`
  2829  <no state>
  2830  	`)
  2831  	if actual != expected {
  2832  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2833  	}
  2834  }
  2835  
  2836  func TestContext2Apply_moduleProviderCloseNested(t *testing.T) {
  2837  	m := testModule(t, "apply-module-provider-close-nested")
  2838  	p := testProvider("aws")
  2839  	p.PlanResourceChangeFn = testDiffFn
  2840  	state := states.NewState()
  2841  	root := state.EnsureModule(addrs.RootModuleInstance)
  2842  	root.SetResourceInstanceCurrent(
  2843  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2844  		&states.ResourceInstanceObjectSrc{
  2845  			Status:    states.ObjectReady,
  2846  			AttrsJSON: []byte(`{"id":"bar"}`),
  2847  		},
  2848  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2849  	)
  2850  
  2851  	ctx := testContext2(t, &ContextOpts{
  2852  		Providers: map[addrs.Provider]providers.Factory{
  2853  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2854  		},
  2855  	})
  2856  
  2857  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  2858  		Mode: plans.DestroyMode,
  2859  	})
  2860  	assertNoErrors(t, diags)
  2861  
  2862  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2863  		t.Fatalf("apply errors: %s", diags.Err())
  2864  	}
  2865  }
  2866  
  2867  // Tests that variables used as module vars that reference data that
  2868  // already exists in the state and requires no diff works properly. This
  2869  // fixes an issue faced where module variables were pruned because they were
  2870  // accessing "non-existent" resources (they existed, just not in the graph
  2871  // cause they weren't in the diff).
  2872  func TestContext2Apply_moduleVarRefExisting(t *testing.T) {
  2873  	m := testModule(t, "apply-ref-existing")
  2874  	p := testProvider("aws")
  2875  	p.PlanResourceChangeFn = testDiffFn
  2876  	p.ApplyResourceChangeFn = testApplyFn
  2877  	state := states.NewState()
  2878  	root := state.EnsureModule(addrs.RootModuleInstance)
  2879  	root.SetResourceInstanceCurrent(
  2880  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2881  		&states.ResourceInstanceObjectSrc{
  2882  			Status:    states.ObjectReady,
  2883  			AttrsJSON: []byte(`{"id":"foo","foo":"bar"}`),
  2884  		},
  2885  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2886  	)
  2887  
  2888  	ctx := testContext2(t, &ContextOpts{
  2889  		Providers: map[addrs.Provider]providers.Factory{
  2890  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2891  		},
  2892  	})
  2893  
  2894  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2895  	assertNoErrors(t, diags)
  2896  
  2897  	state, diags = ctx.Apply(plan, m)
  2898  	if diags.HasErrors() {
  2899  		t.Fatalf("diags: %s", diags.Err())
  2900  	}
  2901  
  2902  	actual := strings.TrimSpace(state.String())
  2903  	expected := strings.TrimSpace(testTerraformApplyModuleVarRefExistingStr)
  2904  	if actual != expected {
  2905  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2906  	}
  2907  }
  2908  
  2909  func TestContext2Apply_moduleVarResourceCount(t *testing.T) {
  2910  	m := testModule(t, "apply-module-var-resource-count")
  2911  	p := testProvider("aws")
  2912  	p.PlanResourceChangeFn = testDiffFn
  2913  	ctx := testContext2(t, &ContextOpts{
  2914  		Providers: map[addrs.Provider]providers.Factory{
  2915  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2916  		},
  2917  	})
  2918  
  2919  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2920  		Mode: plans.DestroyMode,
  2921  		SetVariables: InputValues{
  2922  			"num": &InputValue{
  2923  				Value:      cty.NumberIntVal(2),
  2924  				SourceType: ValueFromCaller,
  2925  			},
  2926  		},
  2927  	})
  2928  	assertNoErrors(t, diags)
  2929  
  2930  	state, diags := ctx.Apply(plan, m)
  2931  	assertNoErrors(t, diags)
  2932  
  2933  	ctx = testContext2(t, &ContextOpts{
  2934  		Providers: map[addrs.Provider]providers.Factory{
  2935  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2936  		},
  2937  	})
  2938  
  2939  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  2940  		Mode: plans.NormalMode,
  2941  		SetVariables: InputValues{
  2942  			"num": &InputValue{
  2943  				Value:      cty.NumberIntVal(5),
  2944  				SourceType: ValueFromCaller,
  2945  			},
  2946  		},
  2947  	})
  2948  	assertNoErrors(t, diags)
  2949  
  2950  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  2951  		t.Fatalf("apply errors: %s", diags.Err())
  2952  	}
  2953  }
  2954  
  2955  // GH-819
  2956  func TestContext2Apply_moduleBool(t *testing.T) {
  2957  	m := testModule(t, "apply-module-bool")
  2958  	p := testProvider("aws")
  2959  	p.PlanResourceChangeFn = testDiffFn
  2960  	p.ApplyResourceChangeFn = testApplyFn
  2961  	ctx := testContext2(t, &ContextOpts{
  2962  		Providers: map[addrs.Provider]providers.Factory{
  2963  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2964  		},
  2965  	})
  2966  
  2967  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2968  	assertNoErrors(t, diags)
  2969  
  2970  	state, diags := ctx.Apply(plan, m)
  2971  	if diags.HasErrors() {
  2972  		t.Fatalf("diags: %s", diags.Err())
  2973  	}
  2974  
  2975  	actual := strings.TrimSpace(state.String())
  2976  	expected := strings.TrimSpace(testTerraformApplyModuleBoolStr)
  2977  	if actual != expected {
  2978  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  2979  	}
  2980  }
  2981  
  2982  // Tests that a module can be targeted and everything is properly created.
  2983  // This adds to the plan test to also just verify that apply works.
  2984  func TestContext2Apply_moduleTarget(t *testing.T) {
  2985  	m := testModule(t, "plan-targeted-cross-module")
  2986  	p := testProvider("aws")
  2987  	p.PlanResourceChangeFn = testDiffFn
  2988  	p.ApplyResourceChangeFn = testApplyFn
  2989  	ctx := testContext2(t, &ContextOpts{
  2990  		Providers: map[addrs.Provider]providers.Factory{
  2991  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2992  		},
  2993  	})
  2994  
  2995  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2996  		Mode: plans.NormalMode,
  2997  		Targets: []addrs.Targetable{
  2998  			addrs.RootModuleInstance.Child("B", addrs.NoKey),
  2999  		},
  3000  	})
  3001  	assertNoErrors(t, diags)
  3002  
  3003  	state, diags := ctx.Apply(plan, m)
  3004  	if diags.HasErrors() {
  3005  		t.Fatalf("diags: %s", diags.Err())
  3006  	}
  3007  
  3008  	checkStateString(t, state, `
  3009  <no state>
  3010  module.A:
  3011    aws_instance.foo:
  3012      ID = foo
  3013      provider = provider["registry.terraform.io/hashicorp/aws"]
  3014      foo = bar
  3015      type = aws_instance
  3016  
  3017    Outputs:
  3018  
  3019    value = foo
  3020  module.B:
  3021    aws_instance.bar:
  3022      ID = foo
  3023      provider = provider["registry.terraform.io/hashicorp/aws"]
  3024      foo = foo
  3025      type = aws_instance
  3026  
  3027      Dependencies:
  3028        module.A.aws_instance.foo
  3029  	`)
  3030  }
  3031  
  3032  func TestContext2Apply_multiProvider(t *testing.T) {
  3033  	m := testModule(t, "apply-multi-provider")
  3034  	p := testProvider("aws")
  3035  	p.PlanResourceChangeFn = testDiffFn
  3036  	p.ApplyResourceChangeFn = testApplyFn
  3037  
  3038  	pDO := testProvider("do")
  3039  	pDO.ApplyResourceChangeFn = testApplyFn
  3040  	pDO.PlanResourceChangeFn = testDiffFn
  3041  
  3042  	ctx := testContext2(t, &ContextOpts{
  3043  		Providers: map[addrs.Provider]providers.Factory{
  3044  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3045  			addrs.NewDefaultProvider("do"):  testProviderFuncFixed(pDO),
  3046  		},
  3047  	})
  3048  
  3049  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3050  	assertNoErrors(t, diags)
  3051  
  3052  	state, diags := ctx.Apply(plan, m)
  3053  	if diags.HasErrors() {
  3054  		t.Fatalf("diags: %s", diags.Err())
  3055  	}
  3056  
  3057  	mod := state.RootModule()
  3058  	if len(mod.Resources) < 2 {
  3059  		t.Fatalf("bad: %#v", mod.Resources)
  3060  	}
  3061  
  3062  	actual := strings.TrimSpace(state.String())
  3063  	expected := strings.TrimSpace(testTerraformApplyMultiProviderStr)
  3064  	if actual != expected {
  3065  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3066  	}
  3067  }
  3068  
  3069  func TestContext2Apply_multiProviderDestroy(t *testing.T) {
  3070  	m := testModule(t, "apply-multi-provider-destroy")
  3071  	p := testProvider("aws")
  3072  	p.PlanResourceChangeFn = testDiffFn
  3073  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3074  		Provider: &configschema.Block{
  3075  			Attributes: map[string]*configschema.Attribute{
  3076  				"addr": {Type: cty.String, Optional: true},
  3077  			},
  3078  		},
  3079  		ResourceTypes: map[string]*configschema.Block{
  3080  			"aws_instance": {
  3081  				Attributes: map[string]*configschema.Attribute{
  3082  					"id":  {Type: cty.String, Computed: true},
  3083  					"foo": {Type: cty.String, Optional: true},
  3084  				},
  3085  			},
  3086  		},
  3087  	})
  3088  
  3089  	p2 := testProvider("vault")
  3090  	p2.ApplyResourceChangeFn = testApplyFn
  3091  	p2.PlanResourceChangeFn = testDiffFn
  3092  	p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3093  		ResourceTypes: map[string]*configschema.Block{
  3094  			"vault_instance": {
  3095  				Attributes: map[string]*configschema.Attribute{
  3096  					"id": {Type: cty.String, Computed: true},
  3097  				},
  3098  			},
  3099  		},
  3100  	})
  3101  
  3102  	var state *states.State
  3103  
  3104  	// First, create the instances
  3105  	{
  3106  		ctx := testContext2(t, &ContextOpts{
  3107  			Providers: map[addrs.Provider]providers.Factory{
  3108  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3109  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3110  			},
  3111  		})
  3112  
  3113  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3114  		assertNoErrors(t, diags)
  3115  
  3116  		s, diags := ctx.Apply(plan, m)
  3117  		assertNoErrors(t, diags)
  3118  
  3119  		state = s
  3120  	}
  3121  
  3122  	// Destroy them
  3123  	{
  3124  		// Verify that aws_instance.bar is destroyed first
  3125  		var checked bool
  3126  		var called int32
  3127  		var lock sync.Mutex
  3128  		applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3129  			lock.Lock()
  3130  			defer lock.Unlock()
  3131  
  3132  			if req.TypeName == "aws_instance" {
  3133  				checked = true
  3134  
  3135  				// Sleep to allow parallel execution
  3136  				time.Sleep(50 * time.Millisecond)
  3137  
  3138  				// Verify that called is 0 (dep not called)
  3139  				if atomic.LoadInt32(&called) != 0 {
  3140  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3141  					return resp
  3142  				}
  3143  			}
  3144  
  3145  			atomic.AddInt32(&called, 1)
  3146  			return testApplyFn(req)
  3147  		}
  3148  
  3149  		// Set the apply functions
  3150  		p.ApplyResourceChangeFn = applyFn
  3151  		p2.ApplyResourceChangeFn = applyFn
  3152  
  3153  		ctx := testContext2(t, &ContextOpts{
  3154  			Providers: map[addrs.Provider]providers.Factory{
  3155  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3156  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3157  			},
  3158  		})
  3159  
  3160  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3161  			Mode: plans.DestroyMode,
  3162  		})
  3163  		assertNoErrors(t, diags)
  3164  
  3165  		s, diags := ctx.Apply(plan, m)
  3166  		assertNoErrors(t, diags)
  3167  
  3168  		if !checked {
  3169  			t.Fatal("should be checked")
  3170  		}
  3171  
  3172  		state = s
  3173  	}
  3174  
  3175  	checkStateString(t, state, `<no state>`)
  3176  }
  3177  
  3178  // This is like the multiProviderDestroy test except it tests that
  3179  // dependent resources within a child module that inherit provider
  3180  // configuration are still destroyed first.
  3181  func TestContext2Apply_multiProviderDestroyChild(t *testing.T) {
  3182  	m := testModule(t, "apply-multi-provider-destroy-child")
  3183  	p := testProvider("aws")
  3184  	p.PlanResourceChangeFn = testDiffFn
  3185  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3186  		Provider: &configschema.Block{
  3187  			Attributes: map[string]*configschema.Attribute{
  3188  				"value": {Type: cty.String, Optional: true},
  3189  			},
  3190  		},
  3191  		ResourceTypes: map[string]*configschema.Block{
  3192  			"aws_instance": {
  3193  				Attributes: map[string]*configschema.Attribute{
  3194  					"id":  {Type: cty.String, Computed: true},
  3195  					"foo": {Type: cty.String, Optional: true},
  3196  				},
  3197  			},
  3198  		},
  3199  	})
  3200  
  3201  	p2 := testProvider("vault")
  3202  	p2.ApplyResourceChangeFn = testApplyFn
  3203  	p2.PlanResourceChangeFn = testDiffFn
  3204  	p2.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3205  		Provider: &configschema.Block{},
  3206  		ResourceTypes: map[string]*configschema.Block{
  3207  			"vault_instance": {
  3208  				Attributes: map[string]*configschema.Attribute{
  3209  					"id": {Type: cty.String, Computed: true},
  3210  				},
  3211  			},
  3212  		},
  3213  	})
  3214  
  3215  	var state *states.State
  3216  
  3217  	// First, create the instances
  3218  	{
  3219  		ctx := testContext2(t, &ContextOpts{
  3220  			Providers: map[addrs.Provider]providers.Factory{
  3221  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3222  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3223  			},
  3224  		})
  3225  
  3226  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3227  		assertNoErrors(t, diags)
  3228  
  3229  		s, diags := ctx.Apply(plan, m)
  3230  		if diags.HasErrors() {
  3231  			t.Fatalf("diags: %s", diags.Err())
  3232  		}
  3233  
  3234  		state = s
  3235  	}
  3236  
  3237  	// Destroy them
  3238  	{
  3239  		// Verify that aws_instance.bar is destroyed first
  3240  		var checked bool
  3241  		var called int32
  3242  		var lock sync.Mutex
  3243  		applyFn := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3244  			lock.Lock()
  3245  			defer lock.Unlock()
  3246  
  3247  			if req.TypeName == "aws_instance" {
  3248  				checked = true
  3249  
  3250  				// Sleep to allow parallel execution
  3251  				time.Sleep(50 * time.Millisecond)
  3252  
  3253  				// Verify that called is 0 (dep not called)
  3254  				if atomic.LoadInt32(&called) != 0 {
  3255  					resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3256  					return resp
  3257  				}
  3258  			}
  3259  
  3260  			atomic.AddInt32(&called, 1)
  3261  			return testApplyFn(req)
  3262  		}
  3263  
  3264  		// Set the apply functions
  3265  		p.ApplyResourceChangeFn = applyFn
  3266  		p2.ApplyResourceChangeFn = applyFn
  3267  
  3268  		ctx := testContext2(t, &ContextOpts{
  3269  			Providers: map[addrs.Provider]providers.Factory{
  3270  				addrs.NewDefaultProvider("aws"):   testProviderFuncFixed(p),
  3271  				addrs.NewDefaultProvider("vault"): testProviderFuncFixed(p2),
  3272  			},
  3273  		})
  3274  
  3275  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3276  			Mode: plans.DestroyMode,
  3277  		})
  3278  		assertNoErrors(t, diags)
  3279  
  3280  		s, diags := ctx.Apply(plan, m)
  3281  		if diags.HasErrors() {
  3282  			t.Fatalf("diags: %s", diags.Err())
  3283  		}
  3284  
  3285  		if !checked {
  3286  			t.Fatal("should be checked")
  3287  		}
  3288  
  3289  		state = s
  3290  	}
  3291  
  3292  	checkStateString(t, state, `
  3293  <no state>
  3294  `)
  3295  }
  3296  
  3297  func TestContext2Apply_multiVar(t *testing.T) {
  3298  	m := testModule(t, "apply-multi-var")
  3299  	p := testProvider("aws")
  3300  	p.PlanResourceChangeFn = testDiffFn
  3301  
  3302  	// First, apply with a count of 3
  3303  	ctx := testContext2(t, &ContextOpts{
  3304  		Providers: map[addrs.Provider]providers.Factory{
  3305  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3306  		},
  3307  	})
  3308  
  3309  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3310  		Mode: plans.NormalMode,
  3311  		SetVariables: InputValues{
  3312  			"num": &InputValue{
  3313  				Value:      cty.NumberIntVal(3),
  3314  				SourceType: ValueFromCaller,
  3315  			},
  3316  		},
  3317  	})
  3318  	assertNoErrors(t, diags)
  3319  
  3320  	state, diags := ctx.Apply(plan, m)
  3321  	if diags.HasErrors() {
  3322  		t.Fatalf("diags: %s", diags.Err())
  3323  	}
  3324  
  3325  	actual := state.RootModule().OutputValues["output"]
  3326  	expected := cty.StringVal("bar0,bar1,bar2")
  3327  	if actual == nil || actual.Value != expected {
  3328  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3329  	}
  3330  
  3331  	t.Logf("Initial state: %s", state.String())
  3332  
  3333  	// Apply again, reduce the count to 1
  3334  	{
  3335  		ctx := testContext2(t, &ContextOpts{
  3336  			Providers: map[addrs.Provider]providers.Factory{
  3337  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3338  			},
  3339  		})
  3340  
  3341  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  3342  			Mode: plans.NormalMode,
  3343  			SetVariables: InputValues{
  3344  				"num": &InputValue{
  3345  					Value:      cty.NumberIntVal(1),
  3346  					SourceType: ValueFromCaller,
  3347  				},
  3348  			},
  3349  		})
  3350  		assertNoErrors(t, diags)
  3351  
  3352  		state, diags := ctx.Apply(plan, m)
  3353  		if diags.HasErrors() {
  3354  			t.Fatalf("diags: %s", diags.Err())
  3355  		}
  3356  
  3357  		t.Logf("End state: %s", state.String())
  3358  
  3359  		actual := state.RootModule().OutputValues["output"]
  3360  		if actual == nil {
  3361  			t.Fatal("missing output")
  3362  		}
  3363  
  3364  		expected := cty.StringVal("bar0")
  3365  		if actual.Value != expected {
  3366  			t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3367  		}
  3368  	}
  3369  }
  3370  
  3371  // This is a holistic test of multi-var (aka "splat variable") handling
  3372  // across several different Terraform subsystems. This is here because
  3373  // historically there were quirky differences in handling across different
  3374  // parts of Terraform and so here we want to assert the expected behavior and
  3375  // ensure that it remains consistent in future.
  3376  func TestContext2Apply_multiVarComprehensive(t *testing.T) {
  3377  	m := testModule(t, "apply-multi-var-comprehensive")
  3378  	p := testProvider("test")
  3379  
  3380  	configs := map[string]cty.Value{}
  3381  	var configsLock sync.Mutex
  3382  
  3383  	p.ApplyResourceChangeFn = testApplyFn
  3384  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  3385  		proposed := req.ProposedNewState
  3386  		configsLock.Lock()
  3387  		defer configsLock.Unlock()
  3388  		key := proposed.GetAttr("key").AsString()
  3389  		// This test was originally written using the legacy p.PlanResourceChangeFn interface,
  3390  		// and so the assertions below expect an old-style ResourceConfig, which
  3391  		// we'll construct via our shim for now to avoid rewriting all of the
  3392  		// assertions.
  3393  		configs[key] = req.ProposedNewState
  3394  
  3395  		retVals := make(map[string]cty.Value)
  3396  		for it := proposed.ElementIterator(); it.Next(); {
  3397  			idxVal, val := it.Element()
  3398  			idx := idxVal.AsString()
  3399  
  3400  			switch idx {
  3401  			case "id":
  3402  				retVals[idx] = cty.UnknownVal(cty.String)
  3403  			case "name":
  3404  				retVals[idx] = cty.StringVal(key)
  3405  			default:
  3406  				retVals[idx] = val
  3407  			}
  3408  		}
  3409  
  3410  		return providers.PlanResourceChangeResponse{
  3411  			PlannedState: cty.ObjectVal(retVals),
  3412  		}
  3413  	}
  3414  
  3415  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3416  		ResourceTypes: map[string]*configschema.Block{
  3417  			"test_thing": {
  3418  				Attributes: map[string]*configschema.Attribute{
  3419  					"key": {Type: cty.String, Required: true},
  3420  
  3421  					"source_id":              {Type: cty.String, Optional: true},
  3422  					"source_name":            {Type: cty.String, Optional: true},
  3423  					"first_source_id":        {Type: cty.String, Optional: true},
  3424  					"first_source_name":      {Type: cty.String, Optional: true},
  3425  					"source_ids":             {Type: cty.List(cty.String), Optional: true},
  3426  					"source_names":           {Type: cty.List(cty.String), Optional: true},
  3427  					"source_ids_from_func":   {Type: cty.List(cty.String), Optional: true},
  3428  					"source_names_from_func": {Type: cty.List(cty.String), Optional: true},
  3429  					"source_ids_wrapped":     {Type: cty.List(cty.List(cty.String)), Optional: true},
  3430  					"source_names_wrapped":   {Type: cty.List(cty.List(cty.String)), Optional: true},
  3431  
  3432  					"id":   {Type: cty.String, Computed: true},
  3433  					"name": {Type: cty.String, Computed: true},
  3434  				},
  3435  			},
  3436  		},
  3437  	})
  3438  
  3439  	// First, apply with a count of 3
  3440  	ctx := testContext2(t, &ContextOpts{
  3441  		Providers: map[addrs.Provider]providers.Factory{
  3442  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  3443  		},
  3444  	})
  3445  
  3446  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3447  		Mode: plans.NormalMode,
  3448  		SetVariables: InputValues{
  3449  			"num": &InputValue{
  3450  				Value:      cty.NumberIntVal(3),
  3451  				SourceType: ValueFromCaller,
  3452  			},
  3453  		},
  3454  	})
  3455  	assertNoErrors(t, diags)
  3456  
  3457  	checkConfig := func(key string, want cty.Value) {
  3458  		configsLock.Lock()
  3459  		defer configsLock.Unlock()
  3460  
  3461  		got, ok := configs[key]
  3462  		if !ok {
  3463  			t.Errorf("no config recorded for %s; expected a configuration", key)
  3464  			return
  3465  		}
  3466  
  3467  		t.Run("config for "+key, func(t *testing.T) {
  3468  			for _, problem := range deep.Equal(got, want) {
  3469  				t.Errorf(problem)
  3470  			}
  3471  		})
  3472  	}
  3473  
  3474  	checkConfig("multi_count_var.0", cty.ObjectVal(map[string]cty.Value{
  3475  		"source_id":   cty.UnknownVal(cty.String),
  3476  		"source_name": cty.StringVal("source.0"),
  3477  	}))
  3478  	checkConfig("multi_count_var.2", cty.ObjectVal(map[string]cty.Value{
  3479  		"source_id":   cty.UnknownVal(cty.String),
  3480  		"source_name": cty.StringVal("source.2"),
  3481  	}))
  3482  	checkConfig("multi_count_derived.0", cty.ObjectVal(map[string]cty.Value{
  3483  		"source_id":   cty.UnknownVal(cty.String),
  3484  		"source_name": cty.StringVal("source.0"),
  3485  	}))
  3486  	checkConfig("multi_count_derived.2", cty.ObjectVal(map[string]cty.Value{
  3487  		"source_id":   cty.UnknownVal(cty.String),
  3488  		"source_name": cty.StringVal("source.2"),
  3489  	}))
  3490  	checkConfig("whole_splat", cty.ObjectVal(map[string]cty.Value{
  3491  		"source_ids": cty.ListVal([]cty.Value{
  3492  			cty.UnknownVal(cty.String),
  3493  			cty.UnknownVal(cty.String),
  3494  			cty.UnknownVal(cty.String),
  3495  		}),
  3496  		"source_names": cty.ListVal([]cty.Value{
  3497  			cty.StringVal("source.0"),
  3498  			cty.StringVal("source.1"),
  3499  			cty.StringVal("source.2"),
  3500  		}),
  3501  		"source_ids_from_func": cty.UnknownVal(cty.String),
  3502  		"source_names_from_func": cty.ListVal([]cty.Value{
  3503  			cty.StringVal("source.0"),
  3504  			cty.StringVal("source.1"),
  3505  			cty.StringVal("source.2"),
  3506  		}),
  3507  		"source_ids_wrapped": cty.ListVal([]cty.Value{
  3508  			cty.ListVal([]cty.Value{
  3509  				cty.UnknownVal(cty.String),
  3510  				cty.UnknownVal(cty.String),
  3511  				cty.UnknownVal(cty.String),
  3512  			}),
  3513  		}),
  3514  		"source_names_wrapped": cty.ListVal([]cty.Value{
  3515  			cty.ListVal([]cty.Value{
  3516  				cty.StringVal("source.0"),
  3517  				cty.StringVal("source.1"),
  3518  				cty.StringVal("source.2"),
  3519  			}),
  3520  		}),
  3521  		"first_source_id":   cty.UnknownVal(cty.String),
  3522  		"first_source_name": cty.StringVal("source.0"),
  3523  	}))
  3524  	checkConfig("child.whole_splat", cty.ObjectVal(map[string]cty.Value{
  3525  		"source_ids": cty.ListVal([]cty.Value{
  3526  			cty.UnknownVal(cty.String),
  3527  			cty.UnknownVal(cty.String),
  3528  			cty.UnknownVal(cty.String),
  3529  		}),
  3530  		"source_names": cty.ListVal([]cty.Value{
  3531  			cty.StringVal("source.0"),
  3532  			cty.StringVal("source.1"),
  3533  			cty.StringVal("source.2"),
  3534  		}),
  3535  		"source_ids_wrapped": cty.ListVal([]cty.Value{
  3536  			cty.ListVal([]cty.Value{
  3537  				cty.UnknownVal(cty.String),
  3538  				cty.UnknownVal(cty.String),
  3539  				cty.UnknownVal(cty.String),
  3540  			}),
  3541  		}),
  3542  		"source_names_wrapped": cty.ListVal([]cty.Value{
  3543  			cty.ListVal([]cty.Value{
  3544  				cty.StringVal("source.0"),
  3545  				cty.StringVal("source.1"),
  3546  				cty.StringVal("source.2"),
  3547  			}),
  3548  		}),
  3549  	}))
  3550  
  3551  	t.Run("apply", func(t *testing.T) {
  3552  		state, diags := ctx.Apply(plan, m)
  3553  		if diags.HasErrors() {
  3554  			t.Fatalf("error during apply: %s", diags.Err())
  3555  		}
  3556  
  3557  		want := map[string]interface{}{
  3558  			"source_ids": []interface{}{"foo", "foo", "foo"},
  3559  			"source_names": []interface{}{
  3560  				"source.0",
  3561  				"source.1",
  3562  				"source.2",
  3563  			},
  3564  		}
  3565  		got := map[string]interface{}{}
  3566  		for k, s := range state.RootModule().OutputValues {
  3567  			got[k] = hcl2shim.ConfigValueFromHCL2(s.Value)
  3568  		}
  3569  		if !reflect.DeepEqual(got, want) {
  3570  			t.Errorf(
  3571  				"wrong outputs\ngot:  %s\nwant: %s",
  3572  				spew.Sdump(got), spew.Sdump(want),
  3573  			)
  3574  		}
  3575  	})
  3576  }
  3577  
  3578  // Test that multi-var (splat) access is ordered by count, not by
  3579  // value.
  3580  func TestContext2Apply_multiVarOrder(t *testing.T) {
  3581  	m := testModule(t, "apply-multi-var-order")
  3582  	p := testProvider("aws")
  3583  	p.PlanResourceChangeFn = testDiffFn
  3584  
  3585  	// First, apply with a count of 3
  3586  	ctx := testContext2(t, &ContextOpts{
  3587  		Providers: map[addrs.Provider]providers.Factory{
  3588  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3589  		},
  3590  	})
  3591  
  3592  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3593  	assertNoErrors(t, diags)
  3594  
  3595  	state, diags := ctx.Apply(plan, m)
  3596  	if diags.HasErrors() {
  3597  		t.Fatalf("diags: %s", diags.Err())
  3598  	}
  3599  
  3600  	t.Logf("State: %s", state.String())
  3601  
  3602  	actual := state.RootModule().OutputValues["should-be-11"]
  3603  	expected := cty.StringVal("index-11")
  3604  	if actual == nil || actual.Value != expected {
  3605  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3606  	}
  3607  }
  3608  
  3609  // Test that multi-var (splat) access is ordered by count, not by
  3610  // value, through interpolations.
  3611  func TestContext2Apply_multiVarOrderInterp(t *testing.T) {
  3612  	m := testModule(t, "apply-multi-var-order-interp")
  3613  	p := testProvider("aws")
  3614  	p.PlanResourceChangeFn = testDiffFn
  3615  
  3616  	// First, apply with a count of 3
  3617  	ctx := testContext2(t, &ContextOpts{
  3618  		Providers: map[addrs.Provider]providers.Factory{
  3619  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3620  		},
  3621  	})
  3622  
  3623  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3624  	assertNoErrors(t, diags)
  3625  
  3626  	state, diags := ctx.Apply(plan, m)
  3627  	if diags.HasErrors() {
  3628  		t.Fatalf("diags: %s", diags.Err())
  3629  	}
  3630  
  3631  	t.Logf("State: %s", state.String())
  3632  
  3633  	actual := state.RootModule().OutputValues["should-be-11"]
  3634  	expected := cty.StringVal("baz-index-11")
  3635  	if actual == nil || actual.Value != expected {
  3636  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  3637  	}
  3638  }
  3639  
  3640  // Based on GH-10440 where a graph edge wasn't properly being created
  3641  // between a modified resource and a count instance being destroyed.
  3642  func TestContext2Apply_multiVarCountDec(t *testing.T) {
  3643  	var s *states.State
  3644  
  3645  	// First create resources. Nothing sneaky here.
  3646  	{
  3647  		m := testModule(t, "apply-multi-var-count-dec")
  3648  		p := testProvider("aws")
  3649  		p.PlanResourceChangeFn = testDiffFn
  3650  		p.ApplyResourceChangeFn = testApplyFn
  3651  		ctx := testContext2(t, &ContextOpts{
  3652  			Providers: map[addrs.Provider]providers.Factory{
  3653  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3654  			},
  3655  		})
  3656  
  3657  		log.Print("\n========\nStep 1 Plan\n========")
  3658  		plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3659  			Mode: plans.NormalMode,
  3660  			SetVariables: InputValues{
  3661  				"num": &InputValue{
  3662  					Value:      cty.NumberIntVal(2),
  3663  					SourceType: ValueFromCaller,
  3664  				},
  3665  			},
  3666  		})
  3667  		assertNoErrors(t, diags)
  3668  
  3669  		log.Print("\n========\nStep 1 Apply\n========")
  3670  		state, diags := ctx.Apply(plan, m)
  3671  		if diags.HasErrors() {
  3672  			t.Fatalf("diags: %s", diags.Err())
  3673  		}
  3674  
  3675  		t.Logf("Step 1 state:\n%s", state)
  3676  
  3677  		s = state
  3678  	}
  3679  
  3680  	// Decrease the count by 1 and verify that everything happens in the
  3681  	// right order.
  3682  	m := testModule(t, "apply-multi-var-count-dec")
  3683  	p := testProvider("aws")
  3684  	p.PlanResourceChangeFn = testDiffFn
  3685  
  3686  	// Verify that aws_instance.bar is modified first and nothing
  3687  	// else happens at the same time.
  3688  	{
  3689  		var checked bool
  3690  		var called int32
  3691  		var lock sync.Mutex
  3692  		p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  3693  			lock.Lock()
  3694  			defer lock.Unlock()
  3695  
  3696  			if !req.PlannedState.IsNull() {
  3697  				s := req.PlannedState.AsValueMap()
  3698  				if ami, ok := s["ami"]; ok && !ami.IsNull() && ami.AsString() == "special" {
  3699  					checked = true
  3700  
  3701  					// Sleep to allow parallel execution
  3702  					time.Sleep(50 * time.Millisecond)
  3703  
  3704  					// Verify that called is 0 (dep not called)
  3705  					if atomic.LoadInt32(&called) != 1 {
  3706  						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("nothing else should be called"))
  3707  						return
  3708  					}
  3709  				}
  3710  			}
  3711  			atomic.AddInt32(&called, 1)
  3712  			return testApplyFn(req)
  3713  		}
  3714  
  3715  		ctx := testContext2(t, &ContextOpts{
  3716  			Providers: map[addrs.Provider]providers.Factory{
  3717  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3718  			},
  3719  		})
  3720  
  3721  		log.Print("\n========\nStep 2 Plan\n========")
  3722  		plan, diags := ctx.Plan(m, s, &PlanOpts{
  3723  			Mode: plans.NormalMode,
  3724  			SetVariables: InputValues{
  3725  				"num": &InputValue{
  3726  					Value:      cty.NumberIntVal(1),
  3727  					SourceType: ValueFromCaller,
  3728  				},
  3729  			},
  3730  		})
  3731  		assertNoErrors(t, diags)
  3732  
  3733  		t.Logf("Step 2 plan:\n%s", legacyDiffComparisonString(plan.Changes))
  3734  
  3735  		log.Print("\n========\nStep 2 Apply\n========")
  3736  		_, diags = ctx.Apply(plan, m)
  3737  		if diags.HasErrors() {
  3738  			t.Fatalf("apply errors: %s", diags.Err())
  3739  		}
  3740  
  3741  		if !checked {
  3742  			t.Error("apply never called")
  3743  		}
  3744  	}
  3745  }
  3746  
  3747  // Test that we can resolve a multi-var (splat) for the first resource
  3748  // created in a non-root module, which happens when the module state doesn't
  3749  // exist yet.
  3750  // https://github.com/hashicorp/terraform/issues/14438
  3751  func TestContext2Apply_multiVarMissingState(t *testing.T) {
  3752  	m := testModule(t, "apply-multi-var-missing-state")
  3753  	p := testProvider("test")
  3754  	p.PlanResourceChangeFn = testDiffFn
  3755  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3756  		ResourceTypes: map[string]*configschema.Block{
  3757  			"test_thing": {
  3758  				Attributes: map[string]*configschema.Attribute{
  3759  					"a_ids": {Type: cty.String, Optional: true},
  3760  					"id":    {Type: cty.String, Computed: true},
  3761  				},
  3762  			},
  3763  		},
  3764  	})
  3765  
  3766  	// First, apply with a count of 3
  3767  	ctx := testContext2(t, &ContextOpts{
  3768  		Providers: map[addrs.Provider]providers.Factory{
  3769  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  3770  		},
  3771  	})
  3772  
  3773  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3774  	assertNoErrors(t, diags)
  3775  
  3776  	// Before the relevant bug was fixed, Terraform would panic during apply.
  3777  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3778  		t.Fatalf("apply failed: %s", diags.Err())
  3779  	}
  3780  
  3781  	// If we get here with no errors or panics then our test was successful.
  3782  }
  3783  
  3784  func TestContext2Apply_outputOrphan(t *testing.T) {
  3785  	m := testModule(t, "apply-output-orphan")
  3786  	p := testProvider("aws")
  3787  	p.PlanResourceChangeFn = testDiffFn
  3788  
  3789  	state := states.NewState()
  3790  	root := state.EnsureModule(addrs.RootModuleInstance)
  3791  	root.SetOutputValue("foo", cty.StringVal("bar"), false)
  3792  	root.SetOutputValue("bar", cty.StringVal("baz"), false)
  3793  
  3794  	ctx := testContext2(t, &ContextOpts{
  3795  		Providers: map[addrs.Provider]providers.Factory{
  3796  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3797  		},
  3798  	})
  3799  
  3800  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3801  	assertNoErrors(t, diags)
  3802  
  3803  	state, diags = ctx.Apply(plan, m)
  3804  	if diags.HasErrors() {
  3805  		t.Fatalf("diags: %s", diags.Err())
  3806  	}
  3807  
  3808  	actual := strings.TrimSpace(state.String())
  3809  	expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr)
  3810  	if actual != expected {
  3811  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3812  	}
  3813  }
  3814  
  3815  func TestContext2Apply_outputOrphanModule(t *testing.T) {
  3816  	m := testModule(t, "apply-output-orphan-module")
  3817  	p := testProvider("aws")
  3818  	p.PlanResourceChangeFn = testDiffFn
  3819  
  3820  	state := states.NewState()
  3821  
  3822  	ctx := testContext2(t, &ContextOpts{
  3823  		Providers: map[addrs.Provider]providers.Factory{
  3824  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3825  		},
  3826  	})
  3827  
  3828  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3829  	assertNoErrors(t, diags)
  3830  
  3831  	s, diags := ctx.Apply(plan, m)
  3832  	if diags.HasErrors() {
  3833  		t.Fatalf("diags: %s", diags.Err())
  3834  	}
  3835  
  3836  	actual := strings.TrimSpace(s.String())
  3837  	expected := strings.TrimSpace(testTerraformApplyOutputOrphanModuleStr)
  3838  	if actual != expected {
  3839  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  3840  	}
  3841  
  3842  	// now apply with no module in the config, which should remove the
  3843  	// remaining output
  3844  	ctx = testContext2(t, &ContextOpts{
  3845  		Providers: map[addrs.Provider]providers.Factory{
  3846  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3847  		},
  3848  	})
  3849  
  3850  	emptyConfig := configs.NewEmptyConfig()
  3851  
  3852  	// NOTE: While updating this test to pass the state in as a Plan argument,
  3853  	// rather than into the testContext2 call above, it previously said
  3854  	// State: state.DeepCopy(), which is a little weird since we just
  3855  	// created "s" above as the result of the previous apply, but I've preserved
  3856  	// it to avoid changing the flow of this test in case that's important
  3857  	// for some reason.
  3858  	plan, diags = ctx.Plan(emptyConfig, state.DeepCopy(), DefaultPlanOpts)
  3859  	assertNoErrors(t, diags)
  3860  
  3861  	state, diags = ctx.Apply(plan, emptyConfig)
  3862  	if diags.HasErrors() {
  3863  		t.Fatalf("diags: %s", diags.Err())
  3864  	}
  3865  
  3866  	if !state.Empty() {
  3867  		t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(state))
  3868  	}
  3869  }
  3870  
  3871  func TestContext2Apply_providerComputedVar(t *testing.T) {
  3872  	m := testModule(t, "apply-provider-computed")
  3873  	p := testProvider("aws")
  3874  	p.PlanResourceChangeFn = testDiffFn
  3875  
  3876  	pTest := testProvider("test")
  3877  	pTest.ApplyResourceChangeFn = testApplyFn
  3878  	pTest.PlanResourceChangeFn = testDiffFn
  3879  
  3880  	ctx := testContext2(t, &ContextOpts{
  3881  		Providers: map[addrs.Provider]providers.Factory{
  3882  			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
  3883  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
  3884  		},
  3885  	})
  3886  
  3887  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  3888  		val := req.Config.GetAttr("value")
  3889  		if val.IsNull() {
  3890  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  3891  			return
  3892  		}
  3893  		return
  3894  	}
  3895  
  3896  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3897  	assertNoErrors(t, diags)
  3898  
  3899  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3900  		t.Fatalf("apply errors: %s", diags.Err())
  3901  	}
  3902  }
  3903  
  3904  func TestContext2Apply_providerConfigureDisabled(t *testing.T) {
  3905  	m := testModule(t, "apply-provider-configure-disabled")
  3906  	p := testProvider("aws")
  3907  	p.PlanResourceChangeFn = testDiffFn
  3908  
  3909  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  3910  		val := req.Config.GetAttr("value")
  3911  		if val.IsNull() {
  3912  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value is not found"))
  3913  		}
  3914  
  3915  		return
  3916  	}
  3917  
  3918  	ctx := testContext2(t, &ContextOpts{
  3919  		Providers: map[addrs.Provider]providers.Factory{
  3920  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3921  		},
  3922  	})
  3923  
  3924  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3925  	assertNoErrors(t, diags)
  3926  
  3927  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  3928  		t.Fatalf("apply errors: %s", diags.Err())
  3929  	}
  3930  
  3931  	if !p.ConfigureProviderCalled {
  3932  		t.Fatal("configure never called")
  3933  	}
  3934  }
  3935  
  3936  func TestContext2Apply_provisionerModule(t *testing.T) {
  3937  	m := testModule(t, "apply-provisioner-module")
  3938  
  3939  	p := testProvider("aws")
  3940  	p.PlanResourceChangeFn = testDiffFn
  3941  	p.ApplyResourceChangeFn = testApplyFn
  3942  
  3943  	pr := testProvisioner()
  3944  	pr.GetSchemaResponse = provisioners.GetSchemaResponse{
  3945  		Provisioner: &configschema.Block{
  3946  			Attributes: map[string]*configschema.Attribute{
  3947  				"foo": {Type: cty.String, Optional: true},
  3948  			},
  3949  		},
  3950  	}
  3951  
  3952  	ctx := testContext2(t, &ContextOpts{
  3953  		Providers: map[addrs.Provider]providers.Factory{
  3954  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3955  		},
  3956  		Provisioners: map[string]provisioners.Factory{
  3957  			"shell": testProvisionerFuncFixed(pr),
  3958  		},
  3959  	})
  3960  
  3961  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3962  	assertNoErrors(t, diags)
  3963  
  3964  	state, diags := ctx.Apply(plan, m)
  3965  	if diags.HasErrors() {
  3966  		t.Fatalf("diags: %s", diags.Err())
  3967  	}
  3968  
  3969  	actual := strings.TrimSpace(state.String())
  3970  	expected := strings.TrimSpace(testTerraformApplyProvisionerModuleStr)
  3971  	if actual != expected {
  3972  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  3973  	}
  3974  
  3975  	// Verify apply was invoked
  3976  	if !pr.ProvisionResourceCalled {
  3977  		t.Fatalf("provisioner not invoked")
  3978  	}
  3979  }
  3980  
  3981  func TestContext2Apply_Provisioner_compute(t *testing.T) {
  3982  	m := testModule(t, "apply-provisioner-compute")
  3983  	p := testProvider("aws")
  3984  	pr := testProvisioner()
  3985  	p.PlanResourceChangeFn = testDiffFn
  3986  	p.ApplyResourceChangeFn = testApplyFn
  3987  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  3988  
  3989  		val := req.Config.GetAttr("command").AsString()
  3990  		if val != "computed_value" {
  3991  			t.Fatalf("bad value for foo: %q", val)
  3992  		}
  3993  		req.UIOutput.Output(fmt.Sprintf("Executing: %q", val))
  3994  
  3995  		return
  3996  	}
  3997  	h := new(MockHook)
  3998  	ctx := testContext2(t, &ContextOpts{
  3999  		Hooks: []Hook{h},
  4000  		Providers: map[addrs.Provider]providers.Factory{
  4001  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4002  		},
  4003  		Provisioners: map[string]provisioners.Factory{
  4004  			"shell": testProvisionerFuncFixed(pr),
  4005  		},
  4006  	})
  4007  
  4008  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  4009  		Mode: plans.NormalMode,
  4010  		SetVariables: InputValues{
  4011  			"value": &InputValue{
  4012  				Value:      cty.NumberIntVal(1),
  4013  				SourceType: ValueFromCaller,
  4014  			},
  4015  		},
  4016  	})
  4017  	assertNoErrors(t, diags)
  4018  
  4019  	state, diags := ctx.Apply(plan, m)
  4020  	if diags.HasErrors() {
  4021  		t.Fatalf("diags: %s", diags.Err())
  4022  	}
  4023  
  4024  	actual := strings.TrimSpace(state.String())
  4025  	expected := strings.TrimSpace(testTerraformApplyProvisionerStr)
  4026  	if actual != expected {
  4027  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4028  	}
  4029  
  4030  	// Verify apply was invoked
  4031  	if !pr.ProvisionResourceCalled {
  4032  		t.Fatalf("provisioner not invoked")
  4033  	}
  4034  
  4035  	// Verify output was rendered
  4036  	if !h.ProvisionOutputCalled {
  4037  		t.Fatalf("ProvisionOutput hook not called")
  4038  	}
  4039  	if got, want := h.ProvisionOutputMessage, `Executing: "computed_value"`; got != want {
  4040  		t.Errorf("expected output to be %q, but was %q", want, got)
  4041  	}
  4042  }
  4043  
  4044  func TestContext2Apply_provisionerCreateFail(t *testing.T) {
  4045  	m := testModule(t, "apply-provisioner-fail-create")
  4046  	p := testProvider("aws")
  4047  	pr := testProvisioner()
  4048  	p.PlanResourceChangeFn = testDiffFn
  4049  
  4050  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  4051  		resp := testApplyFn(req)
  4052  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4053  
  4054  		return resp
  4055  	}
  4056  
  4057  	ctx := testContext2(t, &ContextOpts{
  4058  		Providers: map[addrs.Provider]providers.Factory{
  4059  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4060  		},
  4061  		Provisioners: map[string]provisioners.Factory{
  4062  			"shell": testProvisionerFuncFixed(pr),
  4063  		},
  4064  	})
  4065  
  4066  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4067  	assertNoErrors(t, diags)
  4068  
  4069  	state, diags := ctx.Apply(plan, m)
  4070  	if diags == nil {
  4071  		t.Fatal("should error")
  4072  	}
  4073  
  4074  	got := strings.TrimSpace(state.String())
  4075  	want := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr)
  4076  	if got != want {
  4077  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want)
  4078  	}
  4079  }
  4080  
  4081  func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) {
  4082  	m := testModule(t, "apply-provisioner-fail-create")
  4083  	p := testProvider("aws")
  4084  	pr := testProvisioner()
  4085  	p.PlanResourceChangeFn = testDiffFn
  4086  
  4087  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4088  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4089  		return
  4090  	}
  4091  
  4092  	ctx := testContext2(t, &ContextOpts{
  4093  		Providers: map[addrs.Provider]providers.Factory{
  4094  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4095  		},
  4096  		Provisioners: map[string]provisioners.Factory{
  4097  			"shell": testProvisionerFuncFixed(pr),
  4098  		},
  4099  	})
  4100  
  4101  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4102  	assertNoErrors(t, diags)
  4103  
  4104  	state, diags := ctx.Apply(plan, m)
  4105  	if diags == nil {
  4106  		t.Fatal("should error")
  4107  	}
  4108  
  4109  	actual := strings.TrimSpace(state.String())
  4110  	expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr)
  4111  	if actual != expected {
  4112  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4113  	}
  4114  }
  4115  
  4116  func TestContext2Apply_provisionerFail(t *testing.T) {
  4117  	m := testModule(t, "apply-provisioner-fail")
  4118  	p := testProvider("aws")
  4119  	p.PlanResourceChangeFn = testDiffFn
  4120  	p.ApplyResourceChangeFn = testApplyFn
  4121  	pr := testProvisioner()
  4122  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4123  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION"))
  4124  		return
  4125  	}
  4126  
  4127  	ctx := testContext2(t, &ContextOpts{
  4128  		Providers: map[addrs.Provider]providers.Factory{
  4129  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4130  		},
  4131  		Provisioners: map[string]provisioners.Factory{
  4132  			"shell": testProvisionerFuncFixed(pr),
  4133  		},
  4134  	})
  4135  
  4136  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4137  	assertNoErrors(t, diags)
  4138  
  4139  	state, diags := ctx.Apply(plan, m)
  4140  	if diags == nil {
  4141  		t.Fatal("should error")
  4142  	}
  4143  
  4144  	actual := strings.TrimSpace(state.String())
  4145  	expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr)
  4146  	if actual != expected {
  4147  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4148  	}
  4149  }
  4150  
  4151  func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) {
  4152  	m := testModule(t, "apply-provisioner-fail-create-before")
  4153  	p := testProvider("aws")
  4154  	pr := testProvisioner()
  4155  	p.PlanResourceChangeFn = testDiffFn
  4156  	p.ApplyResourceChangeFn = testApplyFn
  4157  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4158  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("EXPLOSION"))
  4159  		return
  4160  	}
  4161  
  4162  	state := states.NewState()
  4163  	root := state.EnsureModule(addrs.RootModuleInstance)
  4164  	root.SetResourceInstanceCurrent(
  4165  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4166  		&states.ResourceInstanceObjectSrc{
  4167  			Status:    states.ObjectReady,
  4168  			AttrsJSON: []byte(`{"id":"bar","require_new":"abc"}`),
  4169  		},
  4170  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4171  	)
  4172  
  4173  	ctx := testContext2(t, &ContextOpts{
  4174  		Providers: map[addrs.Provider]providers.Factory{
  4175  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4176  		},
  4177  		Provisioners: map[string]provisioners.Factory{
  4178  			"shell": testProvisionerFuncFixed(pr),
  4179  		},
  4180  	})
  4181  
  4182  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4183  	assertNoErrors(t, diags)
  4184  
  4185  	state, diags = ctx.Apply(plan, m)
  4186  	if !diags.HasErrors() {
  4187  		t.Fatal("should error")
  4188  	}
  4189  
  4190  	actual := strings.TrimSpace(state.String())
  4191  	expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr)
  4192  	if actual != expected {
  4193  		t.Fatalf("expected:\n%s\n:got\n%s", expected, actual)
  4194  	}
  4195  }
  4196  
  4197  func TestContext2Apply_error_createBeforeDestroy(t *testing.T) {
  4198  	m := testModule(t, "apply-error-create-before")
  4199  	p := testProvider("aws")
  4200  
  4201  	state := states.NewState()
  4202  	root := state.EnsureModule(addrs.RootModuleInstance)
  4203  	root.SetResourceInstanceCurrent(
  4204  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4205  		&states.ResourceInstanceObjectSrc{
  4206  			Status:    states.ObjectReady,
  4207  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc","type":"aws_instance"}`),
  4208  		},
  4209  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4210  	)
  4211  
  4212  	ctx := testContext2(t, &ContextOpts{
  4213  		Providers: map[addrs.Provider]providers.Factory{
  4214  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4215  		},
  4216  	})
  4217  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4218  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("placeholder error from ApplyFn"))
  4219  		return
  4220  	}
  4221  	p.PlanResourceChangeFn = testDiffFn
  4222  
  4223  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4224  	assertNoErrors(t, diags)
  4225  
  4226  	state, diags = ctx.Apply(plan, m)
  4227  	if !diags.HasErrors() {
  4228  		t.Fatal("should have error")
  4229  	}
  4230  	if got, want := diags.Err().Error(), "placeholder error from ApplyFn"; got != want {
  4231  		// We're looking for our artificial error from ApplyFn above, whose
  4232  		// message is literally "placeholder error from ApplyFn".
  4233  		t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
  4234  	}
  4235  
  4236  	actual := strings.TrimSpace(state.String())
  4237  	expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr)
  4238  	if actual != expected {
  4239  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4240  	}
  4241  }
  4242  
  4243  func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) {
  4244  	m := testModule(t, "apply-error-create-before")
  4245  	p := testProvider("aws")
  4246  
  4247  	state := states.NewState()
  4248  	root := state.EnsureModule(addrs.RootModuleInstance)
  4249  	root.SetResourceInstanceCurrent(
  4250  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  4251  		&states.ResourceInstanceObjectSrc{
  4252  			Status:    states.ObjectReady,
  4253  			AttrsJSON: []byte(`{"id":"bar", "require_new": "abc"}`),
  4254  		},
  4255  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4256  	)
  4257  
  4258  	ctx := testContext2(t, &ContextOpts{
  4259  		Providers: map[addrs.Provider]providers.Factory{
  4260  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4261  		},
  4262  	})
  4263  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4264  		// Fail the destroy!
  4265  		if req.PlannedState.IsNull() {
  4266  			resp.NewState = req.PriorState
  4267  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  4268  			return
  4269  		}
  4270  
  4271  		return testApplyFn(req)
  4272  	}
  4273  	p.PlanResourceChangeFn = testDiffFn
  4274  
  4275  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  4276  	assertNoErrors(t, diags)
  4277  
  4278  	state, diags = ctx.Apply(plan, m)
  4279  	if !diags.HasErrors() {
  4280  		t.Fatal("should have error")
  4281  	}
  4282  
  4283  	actual := strings.TrimSpace(state.String())
  4284  	expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr)
  4285  	if actual != expected {
  4286  		t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected)
  4287  	}
  4288  }
  4289  
  4290  func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) {
  4291  	m := testModule(t, "apply-multi-depose-create-before-destroy")
  4292  	p := testProvider("aws")
  4293  	ps := map[addrs.Provider]providers.Factory{addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p)}
  4294  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4295  		ResourceTypes: map[string]*configschema.Block{
  4296  			"aws_instance": {
  4297  				Attributes: map[string]*configschema.Attribute{
  4298  					"require_new": {Type: cty.String, Optional: true},
  4299  					"id":          {Type: cty.String, Computed: true},
  4300  				},
  4301  			},
  4302  		},
  4303  	})
  4304  
  4305  	state := states.NewState()
  4306  	root := state.EnsureModule(addrs.RootModuleInstance)
  4307  	root.SetResourceInstanceCurrent(
  4308  		mustResourceInstanceAddr("aws_instance.web").Resource,
  4309  		&states.ResourceInstanceObjectSrc{
  4310  			Status:    states.ObjectReady,
  4311  			AttrsJSON: []byte(`{"id":"foo"}`),
  4312  		},
  4313  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4314  	)
  4315  
  4316  	p.PlanResourceChangeFn = testDiffFn
  4317  
  4318  	ctx := testContext2(t, &ContextOpts{
  4319  		Providers: ps,
  4320  	})
  4321  	createdInstanceId := "bar"
  4322  	// Create works
  4323  	createFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4324  		s := req.PlannedState.AsValueMap()
  4325  		s["id"] = cty.StringVal(createdInstanceId)
  4326  		resp.NewState = cty.ObjectVal(s)
  4327  		return
  4328  	}
  4329  
  4330  	// Destroy starts broken
  4331  	destroyFunc := func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4332  		resp.NewState = req.PriorState
  4333  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy failed"))
  4334  		return
  4335  	}
  4336  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4337  		if req.PlannedState.IsNull() {
  4338  			return destroyFunc(req)
  4339  		} else {
  4340  			return createFunc(req)
  4341  		}
  4342  	}
  4343  
  4344  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4345  		Mode: plans.NormalMode,
  4346  		SetVariables: InputValues{
  4347  			"require_new": &InputValue{
  4348  				Value: cty.StringVal("yes"),
  4349  			},
  4350  		},
  4351  	})
  4352  	assertNoErrors(t, diags)
  4353  
  4354  	// Destroy is broken, so even though CBD successfully replaces the instance,
  4355  	// we'll have to save the Deposed instance to destroy later
  4356  	state, diags = ctx.Apply(plan, m)
  4357  	if !diags.HasErrors() {
  4358  		t.Fatal("should have error")
  4359  	}
  4360  
  4361  	checkStateString(t, state, `
  4362  aws_instance.web: (1 deposed)
  4363    ID = bar
  4364    provider = provider["registry.terraform.io/hashicorp/aws"]
  4365    require_new = yes
  4366    Deposed ID 1 = foo
  4367  	`)
  4368  
  4369  	createdInstanceId = "baz"
  4370  	ctx = testContext2(t, &ContextOpts{
  4371  		Providers: ps,
  4372  	})
  4373  
  4374  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4375  		Mode: plans.NormalMode,
  4376  		SetVariables: InputValues{
  4377  			"require_new": &InputValue{
  4378  				Value: cty.StringVal("baz"),
  4379  			},
  4380  		},
  4381  	})
  4382  	assertNoErrors(t, diags)
  4383  
  4384  	// We're replacing the primary instance once again. Destroy is _still_
  4385  	// broken, so the Deposed list gets longer
  4386  	state, diags = ctx.Apply(plan, m)
  4387  	if !diags.HasErrors() {
  4388  		t.Fatal("should have error")
  4389  	}
  4390  
  4391  	// For this one we can't rely on checkStateString because its result is
  4392  	// not deterministic when multiple deposed objects are present. Instead,
  4393  	// we will probe the state object directly.
  4394  	{
  4395  		is := state.RootModule().Resources["aws_instance.web"].Instances[addrs.NoKey]
  4396  		if is.Current == nil {
  4397  			t.Fatalf("no current object for aws_instance web; should have one")
  4398  		}
  4399  		if !bytes.Contains(is.Current.AttrsJSON, []byte("baz")) {
  4400  			t.Fatalf("incorrect current object attrs %s; want id=baz", is.Current.AttrsJSON)
  4401  		}
  4402  		if got, want := len(is.Deposed), 2; got != want {
  4403  			t.Fatalf("wrong number of deposed instances %d; want %d", got, want)
  4404  		}
  4405  		var foos, bars int
  4406  		for _, obj := range is.Deposed {
  4407  			if bytes.Contains(obj.AttrsJSON, []byte("foo")) {
  4408  				foos++
  4409  			}
  4410  			if bytes.Contains(obj.AttrsJSON, []byte("bar")) {
  4411  				bars++
  4412  			}
  4413  		}
  4414  		if got, want := foos, 1; got != want {
  4415  			t.Fatalf("wrong number of deposed instances with id=foo %d; want %d", got, want)
  4416  		}
  4417  		if got, want := bars, 1; got != want {
  4418  			t.Fatalf("wrong number of deposed instances with id=bar %d; want %d", got, want)
  4419  		}
  4420  	}
  4421  
  4422  	// Destroy partially fixed!
  4423  	destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4424  		s := req.PriorState.AsValueMap()
  4425  		id := s["id"].AsString()
  4426  		if id == "foo" || id == "baz" {
  4427  			resp.NewState = cty.NullVal(req.PriorState.Type())
  4428  		} else {
  4429  			resp.NewState = req.PriorState
  4430  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("destroy partially failed"))
  4431  		}
  4432  		return
  4433  	}
  4434  
  4435  	createdInstanceId = "qux"
  4436  	ctx = testContext2(t, &ContextOpts{
  4437  		Providers: ps,
  4438  	})
  4439  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4440  		Mode: plans.NormalMode,
  4441  		SetVariables: InputValues{
  4442  			"require_new": &InputValue{
  4443  				Value: cty.StringVal("qux"),
  4444  			},
  4445  		},
  4446  	})
  4447  	assertNoErrors(t, diags)
  4448  
  4449  	state, diags = ctx.Apply(plan, m)
  4450  	// Expect error because 1/2 of Deposed destroys failed
  4451  	if !diags.HasErrors() {
  4452  		t.Fatal("should have error")
  4453  	}
  4454  
  4455  	// foo and baz are now gone, bar sticks around
  4456  	checkStateString(t, state, `
  4457  aws_instance.web: (1 deposed)
  4458    ID = qux
  4459    provider = provider["registry.terraform.io/hashicorp/aws"]
  4460    require_new = qux
  4461    Deposed ID 1 = bar
  4462  	`)
  4463  
  4464  	// Destroy working fully!
  4465  	destroyFunc = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  4466  		resp.NewState = cty.NullVal(req.PriorState.Type())
  4467  		return
  4468  	}
  4469  
  4470  	createdInstanceId = "quux"
  4471  	ctx = testContext2(t, &ContextOpts{
  4472  		Providers: ps,
  4473  	})
  4474  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  4475  		Mode: plans.NormalMode,
  4476  		SetVariables: InputValues{
  4477  			"require_new": &InputValue{
  4478  				Value: cty.StringVal("quux"),
  4479  			},
  4480  		},
  4481  	})
  4482  	assertNoErrors(t, diags)
  4483  	state, diags = ctx.Apply(plan, m)
  4484  	if diags.HasErrors() {
  4485  		t.Fatal("should not have error:", diags.Err())
  4486  	}
  4487  
  4488  	// And finally the state is clean
  4489  	checkStateString(t, state, `
  4490  aws_instance.web:
  4491    ID = quux
  4492    provider = provider["registry.terraform.io/hashicorp/aws"]
  4493    require_new = quux
  4494  	`)
  4495  }
  4496  
  4497  // Verify that a normal provisioner with on_failure "continue" set won't
  4498  // taint the resource and continues executing.
  4499  func TestContext2Apply_provisionerFailContinue(t *testing.T) {
  4500  	m := testModule(t, "apply-provisioner-fail-continue")
  4501  	p := testProvider("aws")
  4502  	pr := testProvisioner()
  4503  	p.PlanResourceChangeFn = testDiffFn
  4504  	p.ApplyResourceChangeFn = testApplyFn
  4505  
  4506  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4507  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4508  		return
  4509  	}
  4510  
  4511  	ctx := testContext2(t, &ContextOpts{
  4512  		Providers: map[addrs.Provider]providers.Factory{
  4513  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4514  		},
  4515  		Provisioners: map[string]provisioners.Factory{
  4516  			"shell": testProvisionerFuncFixed(pr),
  4517  		},
  4518  	})
  4519  
  4520  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4521  	assertNoErrors(t, diags)
  4522  
  4523  	state, diags := ctx.Apply(plan, m)
  4524  	if diags.HasErrors() {
  4525  		t.Fatalf("diags: %s", diags.Err())
  4526  	}
  4527  
  4528  	checkStateString(t, state, `
  4529  aws_instance.foo:
  4530    ID = foo
  4531    provider = provider["registry.terraform.io/hashicorp/aws"]
  4532    foo = bar
  4533    type = aws_instance
  4534    `)
  4535  
  4536  	// Verify apply was invoked
  4537  	if !pr.ProvisionResourceCalled {
  4538  		t.Fatalf("provisioner not invoked")
  4539  	}
  4540  }
  4541  
  4542  // Verify that a normal provisioner with on_failure "continue" records
  4543  // the error with the hook.
  4544  func TestContext2Apply_provisionerFailContinueHook(t *testing.T) {
  4545  	h := new(MockHook)
  4546  	m := testModule(t, "apply-provisioner-fail-continue")
  4547  	p := testProvider("aws")
  4548  	pr := testProvisioner()
  4549  	p.PlanResourceChangeFn = testDiffFn
  4550  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4551  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4552  		return
  4553  	}
  4554  
  4555  	ctx := testContext2(t, &ContextOpts{
  4556  		Hooks: []Hook{h},
  4557  		Providers: map[addrs.Provider]providers.Factory{
  4558  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4559  		},
  4560  		Provisioners: map[string]provisioners.Factory{
  4561  			"shell": testProvisionerFuncFixed(pr),
  4562  		},
  4563  	})
  4564  
  4565  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4566  	assertNoErrors(t, diags)
  4567  
  4568  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  4569  		t.Fatalf("apply errors: %s", diags.Err())
  4570  	}
  4571  
  4572  	if !h.PostProvisionInstanceStepCalled {
  4573  		t.Fatal("PostProvisionInstanceStep not called")
  4574  	}
  4575  	if h.PostProvisionInstanceStepErrorArg == nil {
  4576  		t.Fatal("should have error")
  4577  	}
  4578  }
  4579  
  4580  func TestContext2Apply_provisionerDestroy(t *testing.T) {
  4581  	m := testModule(t, "apply-provisioner-destroy")
  4582  	p := testProvider("aws")
  4583  	pr := testProvisioner()
  4584  	p.PlanResourceChangeFn = testDiffFn
  4585  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4586  		val := req.Config.GetAttr("command").AsString()
  4587  		if val != "destroy a bar" {
  4588  			t.Fatalf("bad value for foo: %q", val)
  4589  		}
  4590  
  4591  		return
  4592  	}
  4593  
  4594  	state := states.NewState()
  4595  	root := state.RootModule()
  4596  	root.SetResourceInstanceCurrent(
  4597  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4598  		&states.ResourceInstanceObjectSrc{
  4599  			Status:    states.ObjectReady,
  4600  			AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
  4601  		},
  4602  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4603  	)
  4604  
  4605  	ctx := testContext2(t, &ContextOpts{
  4606  		Providers: map[addrs.Provider]providers.Factory{
  4607  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4608  		},
  4609  		Provisioners: map[string]provisioners.Factory{
  4610  			"shell": testProvisionerFuncFixed(pr),
  4611  		},
  4612  	})
  4613  
  4614  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4615  		Mode: plans.DestroyMode,
  4616  	})
  4617  	assertNoErrors(t, diags)
  4618  
  4619  	state, diags = ctx.Apply(plan, m)
  4620  	if diags.HasErrors() {
  4621  		t.Fatalf("diags: %s", diags.Err())
  4622  	}
  4623  
  4624  	checkStateString(t, state, `<no state>`)
  4625  
  4626  	// Verify apply was invoked
  4627  	if !pr.ProvisionResourceCalled {
  4628  		t.Fatalf("provisioner not invoked")
  4629  	}
  4630  }
  4631  
  4632  // Verify that on destroy provisioner failure, nothing happens to the instance
  4633  func TestContext2Apply_provisionerDestroyFail(t *testing.T) {
  4634  	m := testModule(t, "apply-provisioner-destroy")
  4635  	p := testProvider("aws")
  4636  	pr := testProvisioner()
  4637  	p.PlanResourceChangeFn = testDiffFn
  4638  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4639  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4640  		return
  4641  	}
  4642  
  4643  	state := states.NewState()
  4644  	root := state.RootModule()
  4645  	root.SetResourceInstanceCurrent(
  4646  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4647  		&states.ResourceInstanceObjectSrc{
  4648  			Status:    states.ObjectReady,
  4649  			AttrsJSON: []byte(`{"id":"bar","foo":"bar"}`),
  4650  		},
  4651  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4652  	)
  4653  
  4654  	ctx := testContext2(t, &ContextOpts{
  4655  		Providers: map[addrs.Provider]providers.Factory{
  4656  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4657  		},
  4658  		Provisioners: map[string]provisioners.Factory{
  4659  			"shell": testProvisionerFuncFixed(pr),
  4660  		},
  4661  	})
  4662  
  4663  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4664  		Mode: plans.DestroyMode,
  4665  	})
  4666  	assertNoErrors(t, diags)
  4667  
  4668  	state, diags = ctx.Apply(plan, m)
  4669  	if diags == nil {
  4670  		t.Fatal("should error")
  4671  	}
  4672  
  4673  	checkStateString(t, state, `
  4674  aws_instance.foo["a"]:
  4675    ID = bar
  4676    provider = provider["registry.terraform.io/hashicorp/aws"]
  4677    foo = bar
  4678  	`)
  4679  
  4680  	// Verify apply was invoked
  4681  	if !pr.ProvisionResourceCalled {
  4682  		t.Fatalf("provisioner not invoked")
  4683  	}
  4684  }
  4685  
  4686  // Verify that on destroy provisioner failure with "continue" that
  4687  // we continue to the next provisioner.
  4688  func TestContext2Apply_provisionerDestroyFailContinue(t *testing.T) {
  4689  	m := testModule(t, "apply-provisioner-destroy-continue")
  4690  	p := testProvider("aws")
  4691  	pr := testProvisioner()
  4692  	p.PlanResourceChangeFn = testDiffFn
  4693  
  4694  	var l sync.Mutex
  4695  	var calls []string
  4696  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4697  		val := req.Config.GetAttr("command")
  4698  		if val.IsNull() {
  4699  			t.Fatalf("bad value for foo: %#v", val)
  4700  		}
  4701  
  4702  		l.Lock()
  4703  		defer l.Unlock()
  4704  		calls = append(calls, val.AsString())
  4705  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4706  		return
  4707  	}
  4708  
  4709  	state := states.NewState()
  4710  	root := state.RootModule()
  4711  	root.SetResourceInstanceCurrent(
  4712  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4713  		&states.ResourceInstanceObjectSrc{
  4714  			Status:    states.ObjectReady,
  4715  			AttrsJSON: []byte(`{"id":"bar"}`),
  4716  		},
  4717  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4718  	)
  4719  
  4720  	ctx := testContext2(t, &ContextOpts{
  4721  		Providers: map[addrs.Provider]providers.Factory{
  4722  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4723  		},
  4724  		Provisioners: map[string]provisioners.Factory{
  4725  			"shell": testProvisionerFuncFixed(pr),
  4726  		},
  4727  	})
  4728  
  4729  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4730  		Mode: plans.DestroyMode,
  4731  	})
  4732  	assertNoErrors(t, diags)
  4733  
  4734  	state, diags = ctx.Apply(plan, m)
  4735  	if diags.HasErrors() {
  4736  		t.Fatalf("diags: %s", diags.Err())
  4737  	}
  4738  
  4739  	checkStateString(t, state, `<no state>`)
  4740  
  4741  	// Verify apply was invoked
  4742  	if !pr.ProvisionResourceCalled {
  4743  		t.Fatalf("provisioner not invoked")
  4744  	}
  4745  
  4746  	expected := []string{"one", "two"}
  4747  	if !reflect.DeepEqual(calls, expected) {
  4748  		t.Fatalf("wrong commands\ngot:  %#v\nwant: %#v", calls, expected)
  4749  	}
  4750  }
  4751  
  4752  // Verify that on destroy provisioner failure with "continue" that
  4753  // we continue to the next provisioner. But if the next provisioner defines
  4754  // to fail, then we fail after running it.
  4755  func TestContext2Apply_provisionerDestroyFailContinueFail(t *testing.T) {
  4756  	m := testModule(t, "apply-provisioner-destroy-fail")
  4757  	p := testProvider("aws")
  4758  	pr := testProvisioner()
  4759  	p.PlanResourceChangeFn = testDiffFn
  4760  
  4761  	var l sync.Mutex
  4762  	var calls []string
  4763  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4764  		val := req.Config.GetAttr("command")
  4765  		if val.IsNull() {
  4766  			t.Fatalf("bad value for foo: %#v", val)
  4767  		}
  4768  
  4769  		l.Lock()
  4770  		defer l.Unlock()
  4771  		calls = append(calls, val.AsString())
  4772  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provisioner error"))
  4773  		return
  4774  	}
  4775  
  4776  	state := states.NewState()
  4777  	root := state.EnsureModule(addrs.RootModuleInstance)
  4778  	root.SetResourceInstanceCurrent(
  4779  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  4780  		&states.ResourceInstanceObjectSrc{
  4781  			Status:    states.ObjectReady,
  4782  			AttrsJSON: []byte(`{"id":"bar"}`),
  4783  		},
  4784  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4785  	)
  4786  
  4787  	ctx := testContext2(t, &ContextOpts{
  4788  		Providers: map[addrs.Provider]providers.Factory{
  4789  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4790  		},
  4791  		Provisioners: map[string]provisioners.Factory{
  4792  			"shell": testProvisionerFuncFixed(pr),
  4793  		},
  4794  	})
  4795  
  4796  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4797  		Mode: plans.DestroyMode,
  4798  	})
  4799  	assertNoErrors(t, diags)
  4800  
  4801  	state, diags = ctx.Apply(plan, m)
  4802  	if diags == nil {
  4803  		t.Fatal("apply succeeded; wanted error from second provisioner")
  4804  	}
  4805  
  4806  	checkStateString(t, state, `
  4807  aws_instance.foo:
  4808    ID = bar
  4809    provider = provider["registry.terraform.io/hashicorp/aws"]
  4810    `)
  4811  
  4812  	// Verify apply was invoked
  4813  	if !pr.ProvisionResourceCalled {
  4814  		t.Fatalf("provisioner not invoked")
  4815  	}
  4816  
  4817  	expected := []string{"one", "two"}
  4818  	if !reflect.DeepEqual(calls, expected) {
  4819  		t.Fatalf("bad: %#v", calls)
  4820  	}
  4821  }
  4822  
  4823  // Verify destroy provisioners are not run for tainted instances.
  4824  func TestContext2Apply_provisionerDestroyTainted(t *testing.T) {
  4825  	m := testModule(t, "apply-provisioner-destroy")
  4826  	p := testProvider("aws")
  4827  	pr := testProvisioner()
  4828  	p.PlanResourceChangeFn = testDiffFn
  4829  	p.ApplyResourceChangeFn = testApplyFn
  4830  
  4831  	destroyCalled := false
  4832  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4833  		expected := "create a b"
  4834  		val := req.Config.GetAttr("command")
  4835  		if val.AsString() != expected {
  4836  			t.Fatalf("bad value for command: %#v", val)
  4837  		}
  4838  
  4839  		return
  4840  	}
  4841  
  4842  	state := states.NewState()
  4843  	root := state.RootModule()
  4844  	root.SetResourceInstanceCurrent(
  4845  		mustResourceInstanceAddr(`aws_instance.foo["a"]`).Resource,
  4846  		&states.ResourceInstanceObjectSrc{
  4847  			Status:    states.ObjectTainted,
  4848  			AttrsJSON: []byte(`{"id":"bar"}`),
  4849  		},
  4850  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4851  	)
  4852  
  4853  	ctx := testContext2(t, &ContextOpts{
  4854  		Providers: map[addrs.Provider]providers.Factory{
  4855  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4856  		},
  4857  		Provisioners: map[string]provisioners.Factory{
  4858  			"shell": testProvisionerFuncFixed(pr),
  4859  		},
  4860  	})
  4861  
  4862  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4863  		Mode: plans.NormalMode,
  4864  		SetVariables: InputValues{
  4865  			"input": &InputValue{
  4866  				Value: cty.MapVal(map[string]cty.Value{
  4867  					"a": cty.StringVal("b"),
  4868  				}),
  4869  				SourceType: ValueFromInput,
  4870  			},
  4871  		},
  4872  	})
  4873  	assertNoErrors(t, diags)
  4874  
  4875  	state, diags = ctx.Apply(plan, m)
  4876  	if diags.HasErrors() {
  4877  		t.Fatalf("diags: %s", diags.Err())
  4878  	}
  4879  
  4880  	checkStateString(t, state, `
  4881  aws_instance.foo["a"]:
  4882    ID = foo
  4883    provider = provider["registry.terraform.io/hashicorp/aws"]
  4884    foo = bar
  4885    type = aws_instance
  4886  	`)
  4887  
  4888  	// Verify apply was invoked
  4889  	if !pr.ProvisionResourceCalled {
  4890  		t.Fatalf("provisioner not invoked")
  4891  	}
  4892  
  4893  	if destroyCalled {
  4894  		t.Fatal("destroy should not be called")
  4895  	}
  4896  }
  4897  
  4898  func TestContext2Apply_provisionerResourceRef(t *testing.T) {
  4899  	m := testModule(t, "apply-provisioner-resource-ref")
  4900  	p := testProvider("aws")
  4901  	p.PlanResourceChangeFn = testDiffFn
  4902  	p.ApplyResourceChangeFn = testApplyFn
  4903  
  4904  	pr := testProvisioner()
  4905  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4906  		val := req.Config.GetAttr("command")
  4907  		if val.AsString() != "2" {
  4908  			t.Fatalf("bad value for command: %#v", val)
  4909  		}
  4910  
  4911  		return
  4912  	}
  4913  
  4914  	ctx := testContext2(t, &ContextOpts{
  4915  		Providers: map[addrs.Provider]providers.Factory{
  4916  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4917  		},
  4918  		Provisioners: map[string]provisioners.Factory{
  4919  			"shell": testProvisionerFuncFixed(pr),
  4920  		},
  4921  	})
  4922  
  4923  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4924  	assertNoErrors(t, diags)
  4925  
  4926  	state, diags := ctx.Apply(plan, m)
  4927  	if diags.HasErrors() {
  4928  		t.Fatalf("diags: %s", diags.Err())
  4929  	}
  4930  
  4931  	actual := strings.TrimSpace(state.String())
  4932  	expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr)
  4933  	if actual != expected {
  4934  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4935  	}
  4936  
  4937  	// Verify apply was invoked
  4938  	if !pr.ProvisionResourceCalled {
  4939  		t.Fatalf("provisioner not invoked")
  4940  	}
  4941  }
  4942  
  4943  func TestContext2Apply_provisionerSelfRef(t *testing.T) {
  4944  	m := testModule(t, "apply-provisioner-self-ref")
  4945  	p := testProvider("aws")
  4946  	pr := testProvisioner()
  4947  	p.PlanResourceChangeFn = testDiffFn
  4948  	p.ApplyResourceChangeFn = testApplyFn
  4949  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4950  		val := req.Config.GetAttr("command")
  4951  		if val.AsString() != "bar" {
  4952  			t.Fatalf("bad value for command: %#v", val)
  4953  		}
  4954  
  4955  		return
  4956  	}
  4957  
  4958  	ctx := testContext2(t, &ContextOpts{
  4959  		Providers: map[addrs.Provider]providers.Factory{
  4960  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4961  		},
  4962  		Provisioners: map[string]provisioners.Factory{
  4963  			"shell": testProvisionerFuncFixed(pr),
  4964  		},
  4965  	})
  4966  
  4967  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4968  	assertNoErrors(t, diags)
  4969  
  4970  	state, diags := ctx.Apply(plan, m)
  4971  	if diags.HasErrors() {
  4972  		t.Fatalf("diags: %s", diags.Err())
  4973  	}
  4974  
  4975  	actual := strings.TrimSpace(state.String())
  4976  	expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr)
  4977  	if actual != expected {
  4978  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  4979  	}
  4980  
  4981  	// Verify apply was invoked
  4982  	if !pr.ProvisionResourceCalled {
  4983  		t.Fatalf("provisioner not invoked")
  4984  	}
  4985  }
  4986  
  4987  func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) {
  4988  	var lock sync.Mutex
  4989  	commands := make([]string, 0, 5)
  4990  
  4991  	m := testModule(t, "apply-provisioner-multi-self-ref")
  4992  	p := testProvider("aws")
  4993  	pr := testProvisioner()
  4994  	p.PlanResourceChangeFn = testDiffFn
  4995  	p.ApplyResourceChangeFn = testApplyFn
  4996  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  4997  		lock.Lock()
  4998  		defer lock.Unlock()
  4999  
  5000  		val := req.Config.GetAttr("command")
  5001  		if val.IsNull() {
  5002  			t.Fatalf("bad value for command: %#v", val)
  5003  		}
  5004  
  5005  		commands = append(commands, val.AsString())
  5006  		return
  5007  	}
  5008  
  5009  	ctx := testContext2(t, &ContextOpts{
  5010  		Providers: map[addrs.Provider]providers.Factory{
  5011  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5012  		},
  5013  		Provisioners: map[string]provisioners.Factory{
  5014  			"shell": testProvisionerFuncFixed(pr),
  5015  		},
  5016  	})
  5017  
  5018  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5019  	assertNoErrors(t, diags)
  5020  
  5021  	state, diags := ctx.Apply(plan, m)
  5022  	if diags.HasErrors() {
  5023  		t.Fatalf("diags: %s", diags.Err())
  5024  	}
  5025  
  5026  	actual := strings.TrimSpace(state.String())
  5027  	expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr)
  5028  	if actual != expected {
  5029  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5030  	}
  5031  
  5032  	// Verify apply was invoked
  5033  	if !pr.ProvisionResourceCalled {
  5034  		t.Fatalf("provisioner not invoked")
  5035  	}
  5036  
  5037  	// Verify our result
  5038  	sort.Strings(commands)
  5039  	expectedCommands := []string{"number 0", "number 1", "number 2"}
  5040  	if !reflect.DeepEqual(commands, expectedCommands) {
  5041  		t.Fatalf("bad: %#v", commands)
  5042  	}
  5043  }
  5044  
  5045  func TestContext2Apply_provisionerMultiSelfRefSingle(t *testing.T) {
  5046  	var lock sync.Mutex
  5047  	order := make([]string, 0, 5)
  5048  
  5049  	m := testModule(t, "apply-provisioner-multi-self-ref-single")
  5050  	p := testProvider("aws")
  5051  	pr := testProvisioner()
  5052  	p.PlanResourceChangeFn = testDiffFn
  5053  	p.ApplyResourceChangeFn = testApplyFn
  5054  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5055  		lock.Lock()
  5056  		defer lock.Unlock()
  5057  
  5058  		val := req.Config.GetAttr("order")
  5059  		if val.IsNull() {
  5060  			t.Fatalf("no val for order")
  5061  		}
  5062  
  5063  		order = append(order, val.AsString())
  5064  		return
  5065  	}
  5066  
  5067  	ctx := testContext2(t, &ContextOpts{
  5068  		Providers: map[addrs.Provider]providers.Factory{
  5069  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5070  		},
  5071  		Provisioners: map[string]provisioners.Factory{
  5072  			"shell": testProvisionerFuncFixed(pr),
  5073  		},
  5074  	})
  5075  
  5076  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5077  	assertNoErrors(t, diags)
  5078  
  5079  	state, diags := ctx.Apply(plan, m)
  5080  	if diags.HasErrors() {
  5081  		t.Fatalf("diags: %s", diags.Err())
  5082  	}
  5083  
  5084  	actual := strings.TrimSpace(state.String())
  5085  	expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefSingleStr)
  5086  	if actual != expected {
  5087  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5088  	}
  5089  
  5090  	// Verify apply was invoked
  5091  	if !pr.ProvisionResourceCalled {
  5092  		t.Fatalf("provisioner not invoked")
  5093  	}
  5094  
  5095  	// Verify our result
  5096  	sort.Strings(order)
  5097  	expectedOrder := []string{"0", "1", "2"}
  5098  	if !reflect.DeepEqual(order, expectedOrder) {
  5099  		t.Fatalf("bad: %#v", order)
  5100  	}
  5101  }
  5102  
  5103  func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) {
  5104  	m := testModule(t, "apply-provisioner-explicit-self-ref")
  5105  	p := testProvider("aws")
  5106  	pr := testProvisioner()
  5107  	p.PlanResourceChangeFn = testDiffFn
  5108  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5109  		val := req.Config.GetAttr("command")
  5110  		if val.IsNull() || val.AsString() != "bar" {
  5111  			t.Fatalf("bad value for command: %#v", val)
  5112  		}
  5113  
  5114  		return
  5115  	}
  5116  
  5117  	var state *states.State
  5118  	{
  5119  		ctx := testContext2(t, &ContextOpts{
  5120  			Providers: map[addrs.Provider]providers.Factory{
  5121  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5122  			},
  5123  			Provisioners: map[string]provisioners.Factory{
  5124  				"shell": testProvisionerFuncFixed(pr),
  5125  			},
  5126  		})
  5127  
  5128  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5129  		if diags.HasErrors() {
  5130  			t.Fatalf("diags: %s", diags.Err())
  5131  		}
  5132  
  5133  		state, diags = ctx.Apply(plan, m)
  5134  		if diags.HasErrors() {
  5135  			t.Fatalf("diags: %s", diags.Err())
  5136  		}
  5137  
  5138  		// Verify apply was invoked
  5139  		if !pr.ProvisionResourceCalled {
  5140  			t.Fatalf("provisioner not invoked")
  5141  		}
  5142  	}
  5143  
  5144  	{
  5145  		ctx := testContext2(t, &ContextOpts{
  5146  			Providers: map[addrs.Provider]providers.Factory{
  5147  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5148  			},
  5149  			Provisioners: map[string]provisioners.Factory{
  5150  				"shell": testProvisionerFuncFixed(pr),
  5151  			},
  5152  		})
  5153  
  5154  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5155  			Mode: plans.DestroyMode,
  5156  		})
  5157  		if diags.HasErrors() {
  5158  			t.Fatalf("diags: %s", diags.Err())
  5159  		}
  5160  
  5161  		state, diags = ctx.Apply(plan, m)
  5162  		if diags.HasErrors() {
  5163  			t.Fatalf("diags: %s", diags.Err())
  5164  		}
  5165  
  5166  		checkStateString(t, state, `<no state>`)
  5167  	}
  5168  }
  5169  
  5170  func TestContext2Apply_provisionerForEachSelfRef(t *testing.T) {
  5171  	m := testModule(t, "apply-provisioner-for-each-self")
  5172  	p := testProvider("aws")
  5173  	pr := testProvisioner()
  5174  	p.PlanResourceChangeFn = testDiffFn
  5175  
  5176  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  5177  		val := req.Config.GetAttr("command")
  5178  		if val.IsNull() {
  5179  			t.Fatalf("bad value for command: %#v", val)
  5180  		}
  5181  
  5182  		return resp
  5183  	}
  5184  
  5185  	ctx := testContext2(t, &ContextOpts{
  5186  		Providers: map[addrs.Provider]providers.Factory{
  5187  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5188  		},
  5189  		Provisioners: map[string]provisioners.Factory{
  5190  			"shell": testProvisionerFuncFixed(pr),
  5191  		},
  5192  	})
  5193  
  5194  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5195  	assertNoErrors(t, diags)
  5196  
  5197  	_, diags = ctx.Apply(plan, m)
  5198  	if diags.HasErrors() {
  5199  		t.Fatalf("diags: %s", diags.Err())
  5200  	}
  5201  }
  5202  
  5203  // Provisioner should NOT run on a diff, only create
  5204  func TestContext2Apply_Provisioner_Diff(t *testing.T) {
  5205  	m := testModule(t, "apply-provisioner-diff")
  5206  	p := testProvider("aws")
  5207  	pr := testProvisioner()
  5208  	p.PlanResourceChangeFn = testDiffFn
  5209  	p.ApplyResourceChangeFn = testApplyFn
  5210  	ctx := testContext2(t, &ContextOpts{
  5211  		Providers: map[addrs.Provider]providers.Factory{
  5212  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5213  		},
  5214  		Provisioners: map[string]provisioners.Factory{
  5215  			"shell": testProvisionerFuncFixed(pr),
  5216  		},
  5217  	})
  5218  
  5219  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5220  	assertNoErrors(t, diags)
  5221  
  5222  	state, diags := ctx.Apply(plan, m)
  5223  	if diags.HasErrors() {
  5224  		logDiagnostics(t, diags)
  5225  		t.Fatal("apply failed")
  5226  	}
  5227  
  5228  	actual := strings.TrimSpace(state.String())
  5229  	expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr)
  5230  	if actual != expected {
  5231  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5232  	}
  5233  
  5234  	// Verify apply was invoked
  5235  	if !pr.ProvisionResourceCalled {
  5236  		t.Fatalf("provisioner was not called on first apply")
  5237  	}
  5238  	pr.ProvisionResourceCalled = false
  5239  
  5240  	// Change the state to force a diff
  5241  	mod := state.RootModule()
  5242  	obj := mod.Resources["aws_instance.bar"].Instances[addrs.NoKey].Current
  5243  	var attrs map[string]interface{}
  5244  	err := json.Unmarshal(obj.AttrsJSON, &attrs)
  5245  	if err != nil {
  5246  		t.Fatal(err)
  5247  	}
  5248  	attrs["foo"] = "baz"
  5249  	obj.AttrsJSON, err = json.Marshal(attrs)
  5250  	if err != nil {
  5251  		t.Fatal(err)
  5252  	}
  5253  
  5254  	// Re-create context with state
  5255  	ctx = testContext2(t, &ContextOpts{
  5256  		Providers: map[addrs.Provider]providers.Factory{
  5257  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5258  		},
  5259  		Provisioners: map[string]provisioners.Factory{
  5260  			"shell": testProvisionerFuncFixed(pr),
  5261  		},
  5262  	})
  5263  
  5264  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  5265  	assertNoErrors(t, diags)
  5266  
  5267  	state2, diags := ctx.Apply(plan, m)
  5268  	if diags.HasErrors() {
  5269  		logDiagnostics(t, diags)
  5270  		t.Fatal("apply failed")
  5271  	}
  5272  
  5273  	actual = strings.TrimSpace(state2.String())
  5274  	if actual != expected {
  5275  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5276  	}
  5277  
  5278  	// Verify apply was NOT invoked
  5279  	if pr.ProvisionResourceCalled {
  5280  		t.Fatalf("provisioner was called on second apply; should not have been")
  5281  	}
  5282  }
  5283  
  5284  func TestContext2Apply_outputDiffVars(t *testing.T) {
  5285  	m := testModule(t, "apply-good")
  5286  	p := testProvider("aws")
  5287  
  5288  	state := states.NewState()
  5289  	root := state.EnsureModule(addrs.RootModuleInstance)
  5290  	root.SetResourceInstanceCurrent(
  5291  		mustResourceInstanceAddr("aws_instance.baz").Resource,
  5292  		&states.ResourceInstanceObjectSrc{
  5293  			Status:    states.ObjectReady,
  5294  			AttrsJSON: []byte(`{"id":"bar"}`),
  5295  		},
  5296  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5297  	)
  5298  
  5299  	ctx := testContext2(t, &ContextOpts{
  5300  		Providers: map[addrs.Provider]providers.Factory{
  5301  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5302  		},
  5303  	})
  5304  
  5305  	p.PlanResourceChangeFn = testDiffFn
  5306  	//func(info *InstanceInfo, s *InstanceState, rc *ResourceConfig) (*InstanceDiff, error) {
  5307  	//    d := &InstanceDiff{
  5308  	//        Attributes: map[string]*ResourceAttrDiff{},
  5309  	//    }
  5310  	//    if new, ok := rc.Get("value"); ok {
  5311  	//        d.Attributes["value"] = &ResourceAttrDiff{
  5312  	//            New: new.(string),
  5313  	//        }
  5314  	//    }
  5315  	//    if new, ok := rc.Get("foo"); ok {
  5316  	//        d.Attributes["foo"] = &ResourceAttrDiff{
  5317  	//            New: new.(string),
  5318  	//        }
  5319  	//    } else if rc.IsComputed("foo") {
  5320  	//        d.Attributes["foo"] = &ResourceAttrDiff{
  5321  	//            NewComputed: true,
  5322  	//            Type:        DiffAttrOutput, // This doesn't actually really do anything anymore, but this test originally set it.
  5323  	//        }
  5324  	//    }
  5325  	//    if new, ok := rc.Get("num"); ok {
  5326  	//        d.Attributes["num"] = &ResourceAttrDiff{
  5327  	//            New: fmt.Sprintf("%#v", new),
  5328  	//        }
  5329  	//    }
  5330  	//    return d, nil
  5331  	//}
  5332  
  5333  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5334  	assertNoErrors(t, diags)
  5335  
  5336  	_, diags = ctx.Apply(plan, m)
  5337  	assertNoErrors(t, diags)
  5338  }
  5339  
  5340  func TestContext2Apply_destroyX(t *testing.T) {
  5341  	m := testModule(t, "apply-destroy")
  5342  	h := new(HookRecordApplyOrder)
  5343  	p := testProvider("aws")
  5344  	p.PlanResourceChangeFn = testDiffFn
  5345  	ctx := testContext2(t, &ContextOpts{
  5346  		Hooks: []Hook{h},
  5347  		Providers: map[addrs.Provider]providers.Factory{
  5348  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5349  		},
  5350  	})
  5351  
  5352  	// First plan and apply a create operation
  5353  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5354  	assertNoErrors(t, diags)
  5355  
  5356  	state, diags := ctx.Apply(plan, m)
  5357  	if diags.HasErrors() {
  5358  		t.Fatalf("diags: %s", diags.Err())
  5359  	}
  5360  
  5361  	// Next, plan and apply a destroy operation
  5362  	h.Active = true
  5363  	ctx = testContext2(t, &ContextOpts{
  5364  		Hooks: []Hook{h},
  5365  		Providers: map[addrs.Provider]providers.Factory{
  5366  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5367  		},
  5368  	})
  5369  
  5370  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5371  		Mode: plans.DestroyMode,
  5372  	})
  5373  	assertNoErrors(t, diags)
  5374  
  5375  	state, diags = ctx.Apply(plan, m)
  5376  	if diags.HasErrors() {
  5377  		t.Fatalf("diags: %s", diags.Err())
  5378  	}
  5379  
  5380  	// Test that things were destroyed
  5381  	actual := strings.TrimSpace(state.String())
  5382  	expected := strings.TrimSpace(testTerraformApplyDestroyStr)
  5383  	if actual != expected {
  5384  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5385  	}
  5386  
  5387  	// Test that things were destroyed _in the right order_
  5388  	expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
  5389  	actual2 := h.IDs
  5390  	if !reflect.DeepEqual(actual2, expected2) {
  5391  		t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
  5392  	}
  5393  }
  5394  
  5395  func TestContext2Apply_destroyOrder(t *testing.T) {
  5396  	m := testModule(t, "apply-destroy")
  5397  	h := new(HookRecordApplyOrder)
  5398  	p := testProvider("aws")
  5399  	p.PlanResourceChangeFn = testDiffFn
  5400  	ctx := testContext2(t, &ContextOpts{
  5401  		Hooks: []Hook{h},
  5402  		Providers: map[addrs.Provider]providers.Factory{
  5403  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5404  		},
  5405  	})
  5406  
  5407  	// First plan and apply a create operation
  5408  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5409  	assertNoErrors(t, diags)
  5410  
  5411  	state, diags := ctx.Apply(plan, m)
  5412  	if diags.HasErrors() {
  5413  		t.Fatalf("diags: %s", diags.Err())
  5414  	}
  5415  
  5416  	t.Logf("State 1: %s", state)
  5417  
  5418  	// Next, plan and apply a destroy
  5419  	h.Active = true
  5420  	ctx = testContext2(t, &ContextOpts{
  5421  		Hooks: []Hook{h},
  5422  		Providers: map[addrs.Provider]providers.Factory{
  5423  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5424  		},
  5425  	})
  5426  
  5427  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5428  		Mode: plans.DestroyMode,
  5429  	})
  5430  	assertNoErrors(t, diags)
  5431  
  5432  	state, diags = ctx.Apply(plan, m)
  5433  	if diags.HasErrors() {
  5434  		t.Fatalf("diags: %s", diags.Err())
  5435  	}
  5436  
  5437  	// Test that things were destroyed
  5438  	actual := strings.TrimSpace(state.String())
  5439  	expected := strings.TrimSpace(testTerraformApplyDestroyStr)
  5440  	if actual != expected {
  5441  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  5442  	}
  5443  
  5444  	// Test that things were destroyed _in the right order_
  5445  	expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
  5446  	actual2 := h.IDs
  5447  	if !reflect.DeepEqual(actual2, expected2) {
  5448  		t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
  5449  	}
  5450  }
  5451  
  5452  // https://github.com/hashicorp/terraform/issues/2767
  5453  func TestContext2Apply_destroyModulePrefix(t *testing.T) {
  5454  	m := testModule(t, "apply-destroy-module-resource-prefix")
  5455  	h := new(MockHook)
  5456  	p := testProvider("aws")
  5457  	p.PlanResourceChangeFn = testDiffFn
  5458  	ctx := testContext2(t, &ContextOpts{
  5459  		Hooks: []Hook{h},
  5460  		Providers: map[addrs.Provider]providers.Factory{
  5461  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5462  		},
  5463  	})
  5464  
  5465  	// First plan and apply a create operation
  5466  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5467  	assertNoErrors(t, diags)
  5468  
  5469  	state, diags := ctx.Apply(plan, m)
  5470  	if diags.HasErrors() {
  5471  		t.Fatalf("diags: %s", diags.Err())
  5472  	}
  5473  
  5474  	// Verify that we got the apply info correct
  5475  	if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" {
  5476  		t.Fatalf("bad: %s", v)
  5477  	}
  5478  
  5479  	// Next, plan and apply a destroy operation and reset the hook
  5480  	h = new(MockHook)
  5481  	ctx = testContext2(t, &ContextOpts{
  5482  		Hooks: []Hook{h},
  5483  		Providers: map[addrs.Provider]providers.Factory{
  5484  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5485  		},
  5486  	})
  5487  
  5488  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5489  		Mode: plans.DestroyMode,
  5490  	})
  5491  	assertNoErrors(t, diags)
  5492  
  5493  	_, diags = ctx.Apply(plan, m)
  5494  	if diags.HasErrors() {
  5495  		t.Fatalf("diags: %s", diags.Err())
  5496  	}
  5497  
  5498  	// Test that things were destroyed
  5499  	if v := h.PreApplyAddr.String(); v != "module.child.aws_instance.foo" {
  5500  		t.Fatalf("bad: %s", v)
  5501  	}
  5502  }
  5503  
  5504  func TestContext2Apply_destroyNestedModule(t *testing.T) {
  5505  	m := testModule(t, "apply-destroy-nested-module")
  5506  	p := testProvider("aws")
  5507  	p.PlanResourceChangeFn = testDiffFn
  5508  
  5509  	state := states.NewState()
  5510  	root := state.EnsureModule(addrs.RootModuleInstance)
  5511  	root.SetResourceInstanceCurrent(
  5512  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  5513  		&states.ResourceInstanceObjectSrc{
  5514  			Status:    states.ObjectReady,
  5515  			AttrsJSON: []byte(`{"id":"bar"}`),
  5516  		},
  5517  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5518  	)
  5519  
  5520  	ctx := testContext2(t, &ContextOpts{
  5521  		Providers: map[addrs.Provider]providers.Factory{
  5522  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5523  		},
  5524  	})
  5525  
  5526  	// First plan and apply a create operation
  5527  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5528  	assertNoErrors(t, diags)
  5529  
  5530  	s, 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(s.String())
  5537  	if actual != "<no state>" {
  5538  		t.Fatalf("expected no state, got: %s", actual)
  5539  	}
  5540  }
  5541  
  5542  func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) {
  5543  	m := testModule(t, "apply-destroy-deeply-nested-module")
  5544  	p := testProvider("aws")
  5545  	p.PlanResourceChangeFn = testDiffFn
  5546  
  5547  	state := states.NewState()
  5548  	root := state.EnsureModule(addrs.RootModuleInstance)
  5549  	root.SetResourceInstanceCurrent(
  5550  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  5551  		&states.ResourceInstanceObjectSrc{
  5552  			Status:    states.ObjectReady,
  5553  			AttrsJSON: []byte(`{"id":"bar"}`),
  5554  		},
  5555  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5556  	)
  5557  
  5558  	ctx := testContext2(t, &ContextOpts{
  5559  		Providers: map[addrs.Provider]providers.Factory{
  5560  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5561  		},
  5562  	})
  5563  
  5564  	// First plan and apply a create operation
  5565  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5566  	assertNoErrors(t, diags)
  5567  
  5568  	s, diags := ctx.Apply(plan, m)
  5569  	if diags.HasErrors() {
  5570  		t.Fatalf("diags: %s", diags.Err())
  5571  	}
  5572  
  5573  	// Test that things were destroyed
  5574  	if !s.Empty() {
  5575  		t.Fatalf("wrong final state %s\nwant empty state", spew.Sdump(s))
  5576  	}
  5577  }
  5578  
  5579  // https://github.com/hashicorp/terraform/issues/5440
  5580  func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) {
  5581  	m, snap := testModuleWithSnapshot(t, "apply-destroy-module-with-attrs")
  5582  	p := testProvider("aws")
  5583  	p.PlanResourceChangeFn = testDiffFn
  5584  
  5585  	var state *states.State
  5586  	{
  5587  		ctx := testContext2(t, &ContextOpts{
  5588  			Providers: map[addrs.Provider]providers.Factory{
  5589  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5590  			},
  5591  		})
  5592  
  5593  		// First plan and apply a create operation
  5594  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5595  		if diags.HasErrors() {
  5596  			t.Fatalf("plan diags: %s", diags.Err())
  5597  		} else {
  5598  			t.Logf("Step 1 plan: %s", legacyDiffComparisonString(plan.Changes))
  5599  		}
  5600  
  5601  		state, diags = ctx.Apply(plan, m)
  5602  		if diags.HasErrors() {
  5603  			t.Fatalf("apply errs: %s", diags.Err())
  5604  		}
  5605  
  5606  		t.Logf("Step 1 state: %s", state)
  5607  	}
  5608  
  5609  	h := new(HookRecordApplyOrder)
  5610  	h.Active = true
  5611  
  5612  	{
  5613  		ctx := testContext2(t, &ContextOpts{
  5614  			Hooks: []Hook{h},
  5615  			Providers: map[addrs.Provider]providers.Factory{
  5616  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5617  			},
  5618  		})
  5619  
  5620  		// First plan and apply a create operation
  5621  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5622  			Mode: plans.DestroyMode,
  5623  		})
  5624  		if diags.HasErrors() {
  5625  			t.Fatalf("destroy plan err: %s", diags.Err())
  5626  		}
  5627  
  5628  		t.Logf("Step 2 plan: %s", legacyDiffComparisonString(plan.Changes))
  5629  
  5630  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  5631  		if err != nil {
  5632  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5633  		}
  5634  
  5635  		ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  5636  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5637  		}
  5638  
  5639  		ctx, diags = NewContext(ctxOpts)
  5640  		if diags.HasErrors() {
  5641  			t.Fatalf("err: %s", diags.Err())
  5642  		}
  5643  
  5644  		state, diags = ctx.Apply(plan, m)
  5645  		if diags.HasErrors() {
  5646  			t.Fatalf("destroy apply err: %s", diags.Err())
  5647  		}
  5648  
  5649  		t.Logf("Step 2 state: %s", state)
  5650  	}
  5651  
  5652  	//Test that things were destroyed
  5653  	if state.HasResources() {
  5654  		t.Fatal("expected empty state, got:", state)
  5655  	}
  5656  }
  5657  
  5658  func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) {
  5659  	m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count")
  5660  	p := testProvider("aws")
  5661  	p.PlanResourceChangeFn = testDiffFn
  5662  
  5663  	var state *states.State
  5664  	{
  5665  		ctx := testContext2(t, &ContextOpts{
  5666  			Providers: map[addrs.Provider]providers.Factory{
  5667  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5668  			},
  5669  		})
  5670  
  5671  		// First plan and apply a create operation
  5672  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5673  		assertNoErrors(t, diags)
  5674  
  5675  		state, diags = ctx.Apply(plan, m)
  5676  		if diags.HasErrors() {
  5677  			t.Fatalf("apply err: %s", diags.Err())
  5678  		}
  5679  	}
  5680  
  5681  	h := new(HookRecordApplyOrder)
  5682  	h.Active = true
  5683  
  5684  	{
  5685  		ctx := testContext2(t, &ContextOpts{
  5686  			Hooks: []Hook{h},
  5687  			Providers: map[addrs.Provider]providers.Factory{
  5688  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5689  			},
  5690  		})
  5691  
  5692  		// First plan and apply a create operation
  5693  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5694  			Mode: plans.DestroyMode,
  5695  		})
  5696  		if diags.HasErrors() {
  5697  			t.Fatalf("destroy plan err: %s", diags.Err())
  5698  		}
  5699  
  5700  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  5701  		if err != nil {
  5702  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5703  		}
  5704  
  5705  		ctxOpts.Providers =
  5706  			map[addrs.Provider]providers.Factory{
  5707  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5708  			}
  5709  
  5710  		ctx, diags = NewContext(ctxOpts)
  5711  		if diags.HasErrors() {
  5712  			t.Fatalf("err: %s", diags.Err())
  5713  		}
  5714  
  5715  		state, diags = ctx.Apply(plan, m)
  5716  		if diags.HasErrors() {
  5717  			t.Fatalf("destroy apply err: %s", diags.Err())
  5718  		}
  5719  	}
  5720  
  5721  	//Test that things were destroyed
  5722  	actual := strings.TrimSpace(state.String())
  5723  	expected := strings.TrimSpace(`
  5724  <no state>`)
  5725  	if actual != expected {
  5726  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  5727  	}
  5728  }
  5729  
  5730  func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) {
  5731  	m := testModule(t, "apply-destroy-mod-var-and-count")
  5732  	p := testProvider("aws")
  5733  	p.PlanResourceChangeFn = testDiffFn
  5734  
  5735  	var state *states.State
  5736  	{
  5737  		ctx := testContext2(t, &ContextOpts{
  5738  			Providers: map[addrs.Provider]providers.Factory{
  5739  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5740  			},
  5741  		})
  5742  
  5743  		// First plan and apply a create operation
  5744  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5745  		assertNoErrors(t, diags)
  5746  
  5747  		state, diags = ctx.Apply(plan, m)
  5748  		if diags.HasErrors() {
  5749  			t.Fatalf("apply err: %s", diags.Err())
  5750  		}
  5751  	}
  5752  
  5753  	{
  5754  		ctx := testContext2(t, &ContextOpts{
  5755  			Providers: map[addrs.Provider]providers.Factory{
  5756  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5757  			},
  5758  		})
  5759  
  5760  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5761  			Mode: plans.DestroyMode,
  5762  			Targets: []addrs.Targetable{
  5763  				addrs.RootModuleInstance.Child("child", addrs.NoKey),
  5764  			},
  5765  		})
  5766  		if diags.HasErrors() {
  5767  			t.Fatalf("plan err: %s", diags)
  5768  		}
  5769  		if len(diags) != 1 {
  5770  			// Should have one warning that -target is in effect.
  5771  			t.Fatalf("got %d diagnostics in plan; want 1", len(diags))
  5772  		}
  5773  		if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
  5774  			t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
  5775  		}
  5776  		if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want {
  5777  			t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
  5778  		}
  5779  
  5780  		// Destroy, targeting the module explicitly
  5781  		state, diags = ctx.Apply(plan, m)
  5782  		if diags.HasErrors() {
  5783  			t.Fatalf("destroy apply err: %s", diags)
  5784  		}
  5785  		if len(diags) != 1 {
  5786  			t.Fatalf("got %d diagnostics; want 1", len(diags))
  5787  		}
  5788  		if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
  5789  			t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
  5790  		}
  5791  		if got, want := diags[0].Description().Summary, "Applied changes may be incomplete"; got != want {
  5792  			t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
  5793  		}
  5794  	}
  5795  
  5796  	//Test that things were destroyed
  5797  	actual := strings.TrimSpace(state.String())
  5798  	expected := strings.TrimSpace(`<no state>`)
  5799  	if actual != expected {
  5800  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  5801  	}
  5802  }
  5803  
  5804  func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) {
  5805  	m, snap := testModuleWithSnapshot(t, "apply-destroy-mod-var-and-count-nested")
  5806  	p := testProvider("aws")
  5807  	p.PlanResourceChangeFn = testDiffFn
  5808  
  5809  	var state *states.State
  5810  	{
  5811  		ctx := testContext2(t, &ContextOpts{
  5812  			Providers: map[addrs.Provider]providers.Factory{
  5813  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5814  			},
  5815  		})
  5816  
  5817  		// First plan and apply a create operation
  5818  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5819  		assertNoErrors(t, diags)
  5820  
  5821  		state, diags = ctx.Apply(plan, m)
  5822  		if diags.HasErrors() {
  5823  			t.Fatalf("apply err: %s", diags.Err())
  5824  		}
  5825  	}
  5826  
  5827  	h := new(HookRecordApplyOrder)
  5828  	h.Active = true
  5829  
  5830  	{
  5831  		ctx := testContext2(t, &ContextOpts{
  5832  			Hooks: []Hook{h},
  5833  			Providers: map[addrs.Provider]providers.Factory{
  5834  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5835  			},
  5836  		})
  5837  
  5838  		// First plan and apply a create operation
  5839  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  5840  			Mode: plans.DestroyMode,
  5841  		})
  5842  		if diags.HasErrors() {
  5843  			t.Fatalf("destroy plan err: %s", diags.Err())
  5844  		}
  5845  
  5846  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  5847  		if err != nil {
  5848  			t.Fatalf("failed to round-trip through planfile: %s", err)
  5849  		}
  5850  
  5851  		ctxOpts.Providers =
  5852  			map[addrs.Provider]providers.Factory{
  5853  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5854  			}
  5855  
  5856  		ctx, diags = NewContext(ctxOpts)
  5857  		if diags.HasErrors() {
  5858  			t.Fatalf("err: %s", diags.Err())
  5859  		}
  5860  
  5861  		state, diags = ctx.Apply(plan, m)
  5862  		if diags.HasErrors() {
  5863  			t.Fatalf("destroy apply err: %s", diags.Err())
  5864  		}
  5865  	}
  5866  
  5867  	//Test that things were destroyed
  5868  	actual := strings.TrimSpace(state.String())
  5869  	expected := strings.TrimSpace(`
  5870  <no state>`)
  5871  	if actual != expected {
  5872  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  5873  	}
  5874  }
  5875  
  5876  func TestContext2Apply_destroyOutputs(t *testing.T) {
  5877  	m := testModule(t, "apply-destroy-outputs")
  5878  	p := testProvider("test")
  5879  	p.PlanResourceChangeFn = testDiffFn
  5880  
  5881  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  5882  		// add the required id
  5883  		m := req.Config.AsValueMap()
  5884  		m["id"] = cty.StringVal("foo")
  5885  
  5886  		return providers.ReadDataSourceResponse{
  5887  			State: cty.ObjectVal(m),
  5888  		}
  5889  	}
  5890  
  5891  	ctx := testContext2(t, &ContextOpts{
  5892  		Providers: map[addrs.Provider]providers.Factory{
  5893  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  5894  		},
  5895  	})
  5896  
  5897  	// First plan and apply a create operation
  5898  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5899  	assertNoErrors(t, diags)
  5900  
  5901  	state, diags := ctx.Apply(plan, m)
  5902  
  5903  	if diags.HasErrors() {
  5904  		t.Fatalf("diags: %s", diags.Err())
  5905  	}
  5906  
  5907  	// Next, plan and apply a destroy operation
  5908  	ctx = testContext2(t, &ContextOpts{
  5909  		Providers: map[addrs.Provider]providers.Factory{
  5910  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  5911  		},
  5912  	})
  5913  
  5914  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5915  		Mode: plans.DestroyMode,
  5916  	})
  5917  	assertNoErrors(t, diags)
  5918  
  5919  	state, diags = ctx.Apply(plan, m)
  5920  	if diags.HasErrors() {
  5921  		t.Fatalf("diags: %s", diags.Err())
  5922  	}
  5923  
  5924  	mod := state.RootModule()
  5925  	if len(mod.Resources) > 0 {
  5926  		t.Fatalf("expected no resources, got: %#v", mod)
  5927  	}
  5928  
  5929  	// destroying again should produce no errors
  5930  	ctx = testContext2(t, &ContextOpts{
  5931  		Providers: map[addrs.Provider]providers.Factory{
  5932  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  5933  		},
  5934  	})
  5935  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  5936  		Mode: plans.DestroyMode,
  5937  	})
  5938  	assertNoErrors(t, diags)
  5939  
  5940  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  5941  		t.Fatal(diags.Err())
  5942  	}
  5943  }
  5944  
  5945  func TestContext2Apply_destroyOrphan(t *testing.T) {
  5946  	m := testModule(t, "apply-error")
  5947  	p := testProvider("aws")
  5948  	state := states.NewState()
  5949  	root := state.EnsureModule(addrs.RootModuleInstance)
  5950  	root.SetResourceInstanceCurrent(
  5951  		mustResourceInstanceAddr("aws_instance.baz").Resource,
  5952  		&states.ResourceInstanceObjectSrc{
  5953  			Status:    states.ObjectReady,
  5954  			AttrsJSON: []byte(`{"id":"bar"}`),
  5955  		},
  5956  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5957  	)
  5958  	ctx := testContext2(t, &ContextOpts{
  5959  		Providers: map[addrs.Provider]providers.Factory{
  5960  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5961  		},
  5962  	})
  5963  
  5964  	p.PlanResourceChangeFn = testDiffFn
  5965  
  5966  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5967  	assertNoErrors(t, diags)
  5968  
  5969  	s, diags := ctx.Apply(plan, m)
  5970  	if diags.HasErrors() {
  5971  		t.Fatalf("diags: %s", diags.Err())
  5972  	}
  5973  
  5974  	mod := s.RootModule()
  5975  	if _, ok := mod.Resources["aws_instance.baz"]; ok {
  5976  		t.Fatalf("bad: %#v", mod.Resources)
  5977  	}
  5978  }
  5979  
  5980  func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) {
  5981  	m := testModule(t, "apply-destroy-provisioner")
  5982  	p := testProvider("aws")
  5983  	pr := testProvisioner()
  5984  	p.PlanResourceChangeFn = testDiffFn
  5985  
  5986  	state := states.NewState()
  5987  	root := state.EnsureModule(addrs.RootModuleInstance)
  5988  	root.SetResourceInstanceCurrent(
  5989  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  5990  		&states.ResourceInstanceObjectSrc{
  5991  			Status:    states.ObjectReady,
  5992  			AttrsJSON: []byte(`{"id":"bar"}`),
  5993  		},
  5994  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5995  	)
  5996  
  5997  	ctx := testContext2(t, &ContextOpts{
  5998  		Providers: map[addrs.Provider]providers.Factory{
  5999  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6000  		},
  6001  		Provisioners: map[string]provisioners.Factory{
  6002  			"shell": testProvisionerFuncFixed(pr),
  6003  		},
  6004  	})
  6005  
  6006  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  6007  		Mode: plans.DestroyMode,
  6008  	})
  6009  	assertNoErrors(t, diags)
  6010  
  6011  	s, diags := ctx.Apply(plan, m)
  6012  	if diags.HasErrors() {
  6013  		t.Fatalf("diags: %s", diags.Err())
  6014  	}
  6015  
  6016  	if pr.ProvisionResourceCalled {
  6017  		t.Fatal("provisioner should not be called")
  6018  	}
  6019  
  6020  	actual := strings.TrimSpace(s.String())
  6021  	expected := strings.TrimSpace("<no state>")
  6022  	if actual != expected {
  6023  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6024  	}
  6025  }
  6026  
  6027  func TestContext2Apply_error(t *testing.T) {
  6028  	errored := false
  6029  
  6030  	m := testModule(t, "apply-error")
  6031  	p := testProvider("aws")
  6032  	ctx := testContext2(t, &ContextOpts{
  6033  		Providers: map[addrs.Provider]providers.Factory{
  6034  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6035  		},
  6036  	})
  6037  
  6038  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  6039  		if errored {
  6040  			resp.NewState = req.PlannedState
  6041  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  6042  			return
  6043  		}
  6044  		errored = true
  6045  
  6046  		return testApplyFn(req)
  6047  	}
  6048  	p.PlanResourceChangeFn = testDiffFn
  6049  
  6050  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6051  	assertNoErrors(t, diags)
  6052  
  6053  	state, diags := ctx.Apply(plan, m)
  6054  	if diags == nil {
  6055  		t.Fatal("should have error")
  6056  	}
  6057  
  6058  	actual := strings.TrimSpace(state.String())
  6059  	expected := strings.TrimSpace(testTerraformApplyErrorStr)
  6060  	if actual != expected {
  6061  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6062  	}
  6063  }
  6064  
  6065  func TestContext2Apply_errorDestroy(t *testing.T) {
  6066  	m := testModule(t, "empty")
  6067  	p := testProvider("test")
  6068  
  6069  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6070  		ResourceTypes: map[string]*configschema.Block{
  6071  			"test_thing": {
  6072  				Attributes: map[string]*configschema.Attribute{
  6073  					"id": {Type: cty.String, Optional: true},
  6074  				},
  6075  			},
  6076  		},
  6077  	})
  6078  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6079  		// Should actually be called for this test, because Terraform Core
  6080  		// constructs the plan for a destroy operation itself.
  6081  		return providers.PlanResourceChangeResponse{
  6082  			PlannedState: req.ProposedNewState,
  6083  		}
  6084  	}
  6085  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6086  		// The apply (in this case, a destroy) always fails, so we can verify
  6087  		// that the object stays in the state after a destroy fails even though
  6088  		// we aren't returning a new state object here.
  6089  		return providers.ApplyResourceChangeResponse{
  6090  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("failed")),
  6091  		}
  6092  	}
  6093  
  6094  	ctx := testContext2(t, &ContextOpts{
  6095  		Providers: map[addrs.Provider]providers.Factory{
  6096  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6097  		},
  6098  	})
  6099  
  6100  	state := states.BuildState(func(ss *states.SyncState) {
  6101  		ss.SetResourceInstanceCurrent(
  6102  			addrs.Resource{
  6103  				Mode: addrs.ManagedResourceMode,
  6104  				Type: "test_thing",
  6105  				Name: "foo",
  6106  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  6107  			&states.ResourceInstanceObjectSrc{
  6108  				Status:    states.ObjectReady,
  6109  				AttrsJSON: []byte(`{"id":"baz"}`),
  6110  			},
  6111  			addrs.AbsProviderConfig{
  6112  				Provider: addrs.NewDefaultProvider("test"),
  6113  				Module:   addrs.RootModule,
  6114  			},
  6115  		)
  6116  	})
  6117  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6118  	assertNoErrors(t, diags)
  6119  
  6120  	state, diags = ctx.Apply(plan, m)
  6121  	if !diags.HasErrors() {
  6122  		t.Fatal("should have error")
  6123  	}
  6124  
  6125  	actual := strings.TrimSpace(state.String())
  6126  	expected := strings.TrimSpace(`
  6127  test_thing.foo:
  6128    ID = baz
  6129    provider = provider["registry.terraform.io/hashicorp/test"]
  6130  `) // test_thing.foo is still here, even though provider returned no new state along with its error
  6131  	if actual != expected {
  6132  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6133  	}
  6134  }
  6135  
  6136  func TestContext2Apply_errorCreateInvalidNew(t *testing.T) {
  6137  	m := testModule(t, "apply-error")
  6138  
  6139  	p := testProvider("aws")
  6140  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6141  		ResourceTypes: map[string]*configschema.Block{
  6142  			"aws_instance": {
  6143  				Attributes: map[string]*configschema.Attribute{
  6144  					"value": {Type: cty.String, Optional: true},
  6145  					"foo":   {Type: cty.String, Optional: true},
  6146  				},
  6147  			},
  6148  		},
  6149  	})
  6150  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6151  		return providers.PlanResourceChangeResponse{
  6152  			PlannedState: req.ProposedNewState,
  6153  		}
  6154  	}
  6155  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6156  		// We're intentionally returning an inconsistent new state here
  6157  		// because we want to test that Terraform ignores the inconsistency
  6158  		// when accompanied by another error.
  6159  		return providers.ApplyResourceChangeResponse{
  6160  			NewState: cty.ObjectVal(map[string]cty.Value{
  6161  				"value": cty.StringVal("wrong wrong wrong wrong"),
  6162  				"foo":   cty.StringVal("absolutely brimming over with wrongability"),
  6163  			}),
  6164  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")),
  6165  		}
  6166  	}
  6167  
  6168  	ctx := testContext2(t, &ContextOpts{
  6169  		Providers: map[addrs.Provider]providers.Factory{
  6170  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6171  		},
  6172  	})
  6173  
  6174  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6175  	assertNoErrors(t, diags)
  6176  
  6177  	state, diags := ctx.Apply(plan, m)
  6178  	if diags == nil {
  6179  		t.Fatal("should have error")
  6180  	}
  6181  	if got, want := len(diags), 1; got != want {
  6182  		// There should be no additional diagnostics generated by Terraform's own eval logic,
  6183  		// because the provider's own error supersedes them.
  6184  		t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err())
  6185  	}
  6186  	if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) {
  6187  		t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err())
  6188  	}
  6189  	if got, want := len(state.RootModule().Resources), 2; got != want {
  6190  		t.Errorf("%d resources in state before prune; should have %d\n%s", got, want, spew.Sdump(state))
  6191  	}
  6192  	state.PruneResourceHusks() // aws_instance.bar with no instances gets left behind when we bail out, but that's okay
  6193  	if got, want := len(state.RootModule().Resources), 1; got != want {
  6194  		t.Errorf("%d resources in state after prune; should have only one (aws_instance.foo, tainted)\n%s", got, spew.Sdump(state))
  6195  	}
  6196  }
  6197  
  6198  func TestContext2Apply_errorUpdateNullNew(t *testing.T) {
  6199  	m := testModule(t, "apply-error")
  6200  
  6201  	p := testProvider("aws")
  6202  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6203  		ResourceTypes: map[string]*configschema.Block{
  6204  			"aws_instance": {
  6205  				Attributes: map[string]*configschema.Attribute{
  6206  					"value": {Type: cty.String, Optional: true},
  6207  					"foo":   {Type: cty.String, Optional: true},
  6208  				},
  6209  			},
  6210  		},
  6211  	})
  6212  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6213  		return providers.PlanResourceChangeResponse{
  6214  			PlannedState: req.ProposedNewState,
  6215  		}
  6216  	}
  6217  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6218  		// We're intentionally returning no NewState here because we want to
  6219  		// test that Terraform retains the prior state, rather than treating
  6220  		// the returned null as "no state" (object deleted).
  6221  		return providers.ApplyResourceChangeResponse{
  6222  			Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("forced error")),
  6223  		}
  6224  	}
  6225  
  6226  	ctx := testContext2(t, &ContextOpts{
  6227  		Providers: map[addrs.Provider]providers.Factory{
  6228  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6229  		},
  6230  	})
  6231  
  6232  	state := states.BuildState(func(ss *states.SyncState) {
  6233  		ss.SetResourceInstanceCurrent(
  6234  			addrs.Resource{
  6235  				Mode: addrs.ManagedResourceMode,
  6236  				Type: "aws_instance",
  6237  				Name: "foo",
  6238  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  6239  			&states.ResourceInstanceObjectSrc{
  6240  				Status:    states.ObjectReady,
  6241  				AttrsJSON: []byte(`{"value":"old"}`),
  6242  			},
  6243  			addrs.AbsProviderConfig{
  6244  				Provider: addrs.NewDefaultProvider("aws"),
  6245  				Module:   addrs.RootModule,
  6246  			},
  6247  		)
  6248  	})
  6249  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6250  	assertNoErrors(t, diags)
  6251  
  6252  	state, diags = ctx.Apply(plan, m)
  6253  	if !diags.HasErrors() {
  6254  		t.Fatal("should have error")
  6255  	}
  6256  	if got, want := len(diags), 1; got != want {
  6257  		// There should be no additional diagnostics generated by Terraform's own eval logic,
  6258  		// because the provider's own error supersedes them.
  6259  		t.Errorf("wrong number of diagnostics %d; want %d\n%s", got, want, diags.Err())
  6260  	}
  6261  	if got, want := diags.Err().Error(), "forced error"; !strings.Contains(got, want) {
  6262  		t.Errorf("returned error does not contain %q, but it should\n%s", want, diags.Err())
  6263  	}
  6264  	state.PruneResourceHusks()
  6265  	if got, want := len(state.RootModule().Resources), 1; got != want {
  6266  		t.Fatalf("%d resources in state; should have only one (aws_instance.foo, unmodified)\n%s", got, spew.Sdump(state))
  6267  	}
  6268  
  6269  	is := state.ResourceInstance(addrs.Resource{
  6270  		Mode: addrs.ManagedResourceMode,
  6271  		Type: "aws_instance",
  6272  		Name: "foo",
  6273  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
  6274  	if is == nil {
  6275  		t.Fatalf("aws_instance.foo is not in the state after apply")
  6276  	}
  6277  	if got, want := is.Current.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) {
  6278  		t.Fatalf("incorrect attributes for aws_instance.foo\ngot: %s\nwant: JSON containing %s\n\n%s", got, want, spew.Sdump(is))
  6279  	}
  6280  }
  6281  
  6282  func TestContext2Apply_errorPartial(t *testing.T) {
  6283  	errored := false
  6284  
  6285  	m := testModule(t, "apply-error")
  6286  	p := testProvider("aws")
  6287  
  6288  	state := states.NewState()
  6289  	root := state.EnsureModule(addrs.RootModuleInstance)
  6290  	root.SetResourceInstanceCurrent(
  6291  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6292  		&states.ResourceInstanceObjectSrc{
  6293  			Status:    states.ObjectReady,
  6294  			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
  6295  		},
  6296  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6297  	)
  6298  
  6299  	ctx := testContext2(t, &ContextOpts{
  6300  		Providers: map[addrs.Provider]providers.Factory{
  6301  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6302  		},
  6303  	})
  6304  
  6305  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  6306  		if errored {
  6307  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("error"))
  6308  			return
  6309  		}
  6310  		errored = true
  6311  
  6312  		return testApplyFn(req)
  6313  	}
  6314  	p.PlanResourceChangeFn = testDiffFn
  6315  
  6316  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6317  	assertNoErrors(t, diags)
  6318  
  6319  	s, diags := ctx.Apply(plan, m)
  6320  	if diags == nil {
  6321  		t.Fatal("should have error")
  6322  	}
  6323  
  6324  	mod := s.RootModule()
  6325  	if len(mod.Resources) != 2 {
  6326  		t.Fatalf("bad: %#v", mod.Resources)
  6327  	}
  6328  
  6329  	actual := strings.TrimSpace(s.String())
  6330  	expected := strings.TrimSpace(testTerraformApplyErrorPartialStr)
  6331  	if actual != expected {
  6332  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  6333  	}
  6334  }
  6335  
  6336  func TestContext2Apply_hook(t *testing.T) {
  6337  	m := testModule(t, "apply-good")
  6338  	h := new(MockHook)
  6339  	p := testProvider("aws")
  6340  	p.PlanResourceChangeFn = testDiffFn
  6341  	ctx := testContext2(t, &ContextOpts{
  6342  		Hooks: []Hook{h},
  6343  		Providers: map[addrs.Provider]providers.Factory{
  6344  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6345  		},
  6346  	})
  6347  
  6348  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6349  	assertNoErrors(t, diags)
  6350  
  6351  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6352  		t.Fatalf("apply errors: %s", diags.Err())
  6353  	}
  6354  
  6355  	if !h.PreApplyCalled {
  6356  		t.Fatal("should be called")
  6357  	}
  6358  	if !h.PostApplyCalled {
  6359  		t.Fatal("should be called")
  6360  	}
  6361  	if !h.PostStateUpdateCalled {
  6362  		t.Fatalf("should call post state update")
  6363  	}
  6364  }
  6365  
  6366  func TestContext2Apply_hookOrphan(t *testing.T) {
  6367  	m := testModule(t, "apply-blank")
  6368  	h := new(MockHook)
  6369  	p := testProvider("aws")
  6370  	p.PlanResourceChangeFn = testDiffFn
  6371  
  6372  	state := states.NewState()
  6373  	root := state.EnsureModule(addrs.RootModuleInstance)
  6374  	root.SetResourceInstanceCurrent(
  6375  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6376  		&states.ResourceInstanceObjectSrc{
  6377  			Status:    states.ObjectReady,
  6378  			AttrsJSON: []byte(`{"id":"bar"}`),
  6379  		},
  6380  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6381  	)
  6382  
  6383  	ctx := testContext2(t, &ContextOpts{
  6384  		Hooks: []Hook{h},
  6385  		Providers: map[addrs.Provider]providers.Factory{
  6386  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6387  		},
  6388  	})
  6389  
  6390  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6391  	assertNoErrors(t, diags)
  6392  
  6393  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  6394  		t.Fatalf("apply errors: %s", diags.Err())
  6395  	}
  6396  
  6397  	if !h.PreApplyCalled {
  6398  		t.Fatal("should be called")
  6399  	}
  6400  	if !h.PostApplyCalled {
  6401  		t.Fatal("should be called")
  6402  	}
  6403  	if !h.PostStateUpdateCalled {
  6404  		t.Fatalf("should call post state update")
  6405  	}
  6406  }
  6407  
  6408  func TestContext2Apply_idAttr(t *testing.T) {
  6409  	m := testModule(t, "apply-idattr")
  6410  	p := testProvider("aws")
  6411  	ctx := testContext2(t, &ContextOpts{
  6412  		Providers: map[addrs.Provider]providers.Factory{
  6413  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6414  		},
  6415  	})
  6416  
  6417  	p.PlanResourceChangeFn = testDiffFn
  6418  	p.ApplyResourceChangeFn = testApplyFn
  6419  
  6420  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6421  	assertNoErrors(t, diags)
  6422  
  6423  	state, diags := ctx.Apply(plan, m)
  6424  	if diags.HasErrors() {
  6425  		t.Fatalf("apply errors: %s", diags.Err())
  6426  	}
  6427  
  6428  	mod := state.RootModule()
  6429  	rs, ok := mod.Resources["aws_instance.foo"]
  6430  	if !ok {
  6431  		t.Fatal("not in state")
  6432  	}
  6433  	var attrs map[string]interface{}
  6434  	err := json.Unmarshal(rs.Instances[addrs.NoKey].Current.AttrsJSON, &attrs)
  6435  	if err != nil {
  6436  		t.Fatal(err)
  6437  	}
  6438  	if got, want := attrs["id"], "foo"; got != want {
  6439  		t.Fatalf("wrong id\ngot:  %#v\nwant: %#v", got, want)
  6440  	}
  6441  }
  6442  
  6443  func TestContext2Apply_outputBasic(t *testing.T) {
  6444  	m := testModule(t, "apply-output")
  6445  	p := testProvider("aws")
  6446  	p.PlanResourceChangeFn = testDiffFn
  6447  	p.ApplyResourceChangeFn = testApplyFn
  6448  	ctx := testContext2(t, &ContextOpts{
  6449  		Providers: map[addrs.Provider]providers.Factory{
  6450  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6451  		},
  6452  	})
  6453  
  6454  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6455  	assertNoErrors(t, diags)
  6456  
  6457  	state, diags := ctx.Apply(plan, m)
  6458  	if diags.HasErrors() {
  6459  		t.Fatalf("diags: %s", diags.Err())
  6460  	}
  6461  
  6462  	actual := strings.TrimSpace(state.String())
  6463  	expected := strings.TrimSpace(testTerraformApplyOutputStr)
  6464  	if actual != expected {
  6465  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6466  	}
  6467  }
  6468  
  6469  func TestContext2Apply_outputAdd(t *testing.T) {
  6470  	m1 := testModule(t, "apply-output-add-before")
  6471  	p1 := testProvider("aws")
  6472  	p1.ApplyResourceChangeFn = testApplyFn
  6473  	p1.PlanResourceChangeFn = testDiffFn
  6474  	ctx1 := testContext2(t, &ContextOpts{
  6475  		Providers: map[addrs.Provider]providers.Factory{
  6476  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p1),
  6477  		},
  6478  	})
  6479  
  6480  	plan1, diags := ctx1.Plan(m1, states.NewState(), DefaultPlanOpts)
  6481  	assertNoErrors(t, diags)
  6482  
  6483  	state1, diags := ctx1.Apply(plan1, m1)
  6484  	if diags.HasErrors() {
  6485  		t.Fatalf("diags: %s", diags.Err())
  6486  	}
  6487  
  6488  	m2 := testModule(t, "apply-output-add-after")
  6489  	p2 := testProvider("aws")
  6490  	p2.ApplyResourceChangeFn = testApplyFn
  6491  	p2.PlanResourceChangeFn = testDiffFn
  6492  	ctx2 := testContext2(t, &ContextOpts{
  6493  		Providers: map[addrs.Provider]providers.Factory{
  6494  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p2),
  6495  		},
  6496  	})
  6497  
  6498  	plan2, diags := ctx1.Plan(m2, state1, DefaultPlanOpts)
  6499  	assertNoErrors(t, diags)
  6500  
  6501  	state2, diags := ctx2.Apply(plan2, m2)
  6502  	if diags.HasErrors() {
  6503  		t.Fatalf("diags: %s", diags.Err())
  6504  	}
  6505  
  6506  	actual := strings.TrimSpace(state2.String())
  6507  	expected := strings.TrimSpace(testTerraformApplyOutputAddStr)
  6508  	if actual != expected {
  6509  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6510  	}
  6511  }
  6512  
  6513  func TestContext2Apply_outputList(t *testing.T) {
  6514  	m := testModule(t, "apply-output-list")
  6515  	p := testProvider("aws")
  6516  	p.PlanResourceChangeFn = testDiffFn
  6517  	p.ApplyResourceChangeFn = testApplyFn
  6518  	ctx := testContext2(t, &ContextOpts{
  6519  		Providers: map[addrs.Provider]providers.Factory{
  6520  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6521  		},
  6522  	})
  6523  
  6524  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6525  	assertNoErrors(t, diags)
  6526  
  6527  	state, diags := ctx.Apply(plan, m)
  6528  	if diags.HasErrors() {
  6529  		t.Fatalf("diags: %s", diags.Err())
  6530  	}
  6531  
  6532  	actual := strings.TrimSpace(state.String())
  6533  	expected := strings.TrimSpace(testTerraformApplyOutputListStr)
  6534  	if actual != expected {
  6535  		t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)
  6536  	}
  6537  }
  6538  
  6539  func TestContext2Apply_outputMulti(t *testing.T) {
  6540  	m := testModule(t, "apply-output-multi")
  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(testTerraformApplyOutputMultiStr)
  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_outputMultiIndex(t *testing.T) {
  6566  	m := testModule(t, "apply-output-multi-index")
  6567  	p := testProvider("aws")
  6568  	p.PlanResourceChangeFn = testDiffFn
  6569  	p.ApplyResourceChangeFn = testApplyFn
  6570  	ctx := testContext2(t, &ContextOpts{
  6571  		Providers: map[addrs.Provider]providers.Factory{
  6572  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6573  		},
  6574  	})
  6575  
  6576  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6577  	assertNoErrors(t, diags)
  6578  
  6579  	state, diags := ctx.Apply(plan, m)
  6580  	if diags.HasErrors() {
  6581  		t.Fatalf("diags: %s", diags.Err())
  6582  	}
  6583  
  6584  	actual := strings.TrimSpace(state.String())
  6585  	expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr)
  6586  	if actual != expected {
  6587  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  6588  	}
  6589  }
  6590  
  6591  func TestContext2Apply_taintX(t *testing.T) {
  6592  	m := testModule(t, "apply-taint")
  6593  	p := testProvider("aws")
  6594  	// destroyCount tests against regression of
  6595  	// https://github.com/hashicorp/terraform/issues/1056
  6596  	var destroyCount = int32(0)
  6597  	var once sync.Once
  6598  	simulateProviderDelay := func() {
  6599  		time.Sleep(10 * time.Millisecond)
  6600  	}
  6601  
  6602  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  6603  		once.Do(simulateProviderDelay)
  6604  		if req.PlannedState.IsNull() {
  6605  			atomic.AddInt32(&destroyCount, 1)
  6606  		}
  6607  		return testApplyFn(req)
  6608  	}
  6609  	p.PlanResourceChangeFn = testDiffFn
  6610  
  6611  	state := states.NewState()
  6612  	root := state.EnsureModule(addrs.RootModuleInstance)
  6613  	root.SetResourceInstanceCurrent(
  6614  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6615  		&states.ResourceInstanceObjectSrc{
  6616  			Status:    states.ObjectTainted,
  6617  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6618  		},
  6619  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6620  	)
  6621  
  6622  	ctx := testContext2(t, &ContextOpts{
  6623  		Providers: map[addrs.Provider]providers.Factory{
  6624  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6625  		},
  6626  	})
  6627  
  6628  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6629  	if diags.HasErrors() {
  6630  		t.Fatalf("diags: %s", diags.Err())
  6631  	} else {
  6632  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6633  	}
  6634  
  6635  	s, diags := ctx.Apply(plan, m)
  6636  	if diags.HasErrors() {
  6637  		t.Fatalf("diags: %s", diags.Err())
  6638  	}
  6639  
  6640  	actual := strings.TrimSpace(s.String())
  6641  	expected := strings.TrimSpace(testTerraformApplyTaintStr)
  6642  	if actual != expected {
  6643  		t.Fatalf("bad:\n%s", actual)
  6644  	}
  6645  
  6646  	if destroyCount != 1 {
  6647  		t.Fatalf("Expected 1 destroy, got %d", destroyCount)
  6648  	}
  6649  }
  6650  
  6651  func TestContext2Apply_taintDep(t *testing.T) {
  6652  	m := testModule(t, "apply-taint-dep")
  6653  	p := testProvider("aws")
  6654  	p.PlanResourceChangeFn = testDiffFn
  6655  	p.ApplyResourceChangeFn = testApplyFn
  6656  
  6657  	state := states.NewState()
  6658  	root := state.EnsureModule(addrs.RootModuleInstance)
  6659  	root.SetResourceInstanceCurrent(
  6660  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6661  		&states.ResourceInstanceObjectSrc{
  6662  			Status:    states.ObjectTainted,
  6663  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6664  		},
  6665  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6666  	)
  6667  	root.SetResourceInstanceCurrent(
  6668  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6669  		&states.ResourceInstanceObjectSrc{
  6670  			Status:       states.ObjectReady,
  6671  			AttrsJSON:    []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`),
  6672  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  6673  		},
  6674  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6675  	)
  6676  
  6677  	ctx := testContext2(t, &ContextOpts{
  6678  		Providers: map[addrs.Provider]providers.Factory{
  6679  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6680  		},
  6681  	})
  6682  
  6683  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6684  	if diags.HasErrors() {
  6685  		t.Fatalf("diags: %s", diags.Err())
  6686  	} else {
  6687  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6688  	}
  6689  
  6690  	s, diags := ctx.Apply(plan, m)
  6691  	if diags.HasErrors() {
  6692  		t.Fatalf("diags: %s", diags.Err())
  6693  	}
  6694  
  6695  	actual := strings.TrimSpace(s.String())
  6696  	expected := strings.TrimSpace(testTerraformApplyTaintDepStr)
  6697  	if actual != expected {
  6698  		t.Fatalf("bad:\n%s", actual)
  6699  	}
  6700  }
  6701  
  6702  func TestContext2Apply_taintDepRequiresNew(t *testing.T) {
  6703  	m := testModule(t, "apply-taint-dep-requires-new")
  6704  	p := testProvider("aws")
  6705  	p.PlanResourceChangeFn = testDiffFn
  6706  	p.ApplyResourceChangeFn = testApplyFn
  6707  
  6708  	state := states.NewState()
  6709  	root := state.EnsureModule(addrs.RootModuleInstance)
  6710  	root.SetResourceInstanceCurrent(
  6711  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6712  		&states.ResourceInstanceObjectSrc{
  6713  			Status:    states.ObjectTainted,
  6714  			AttrsJSON: []byte(`{"id":"baz","num": "2", "type": "aws_instance"}`),
  6715  		},
  6716  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6717  	)
  6718  	root.SetResourceInstanceCurrent(
  6719  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6720  		&states.ResourceInstanceObjectSrc{
  6721  			Status:       states.ObjectReady,
  6722  			AttrsJSON:    []byte(`{"id":"bar","num": "2", "type": "aws_instance", "foo": "baz"}`),
  6723  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  6724  		},
  6725  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6726  	)
  6727  
  6728  	ctx := testContext2(t, &ContextOpts{
  6729  		Providers: map[addrs.Provider]providers.Factory{
  6730  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6731  		},
  6732  	})
  6733  
  6734  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6735  	if diags.HasErrors() {
  6736  		t.Fatalf("diags: %s", diags.Err())
  6737  	} else {
  6738  		t.Logf("plan: %s", legacyDiffComparisonString(plan.Changes))
  6739  	}
  6740  
  6741  	s, diags := ctx.Apply(plan, m)
  6742  	if diags.HasErrors() {
  6743  		t.Fatalf("diags: %s", diags.Err())
  6744  	}
  6745  
  6746  	actual := strings.TrimSpace(s.String())
  6747  	expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr)
  6748  	if actual != expected {
  6749  		t.Fatalf("bad:\n%s", actual)
  6750  	}
  6751  }
  6752  
  6753  func TestContext2Apply_targeted(t *testing.T) {
  6754  	m := testModule(t, "apply-targeted")
  6755  	p := testProvider("aws")
  6756  	p.PlanResourceChangeFn = testDiffFn
  6757  	p.ApplyResourceChangeFn = testApplyFn
  6758  	ctx := testContext2(t, &ContextOpts{
  6759  		Providers: map[addrs.Provider]providers.Factory{
  6760  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6761  		},
  6762  	})
  6763  
  6764  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  6765  		Mode: plans.NormalMode,
  6766  		Targets: []addrs.Targetable{
  6767  			addrs.RootModuleInstance.Resource(
  6768  				addrs.ManagedResourceMode, "aws_instance", "foo",
  6769  			),
  6770  		},
  6771  	})
  6772  	assertNoErrors(t, diags)
  6773  
  6774  	state, diags := ctx.Apply(plan, m)
  6775  	if diags.HasErrors() {
  6776  		t.Fatalf("diags: %s", diags.Err())
  6777  	}
  6778  
  6779  	mod := state.RootModule()
  6780  	if len(mod.Resources) != 1 {
  6781  		t.Fatalf("expected 1 resource, got: %#v", mod.Resources)
  6782  	}
  6783  
  6784  	checkStateString(t, state, `
  6785  aws_instance.foo:
  6786    ID = foo
  6787    provider = provider["registry.terraform.io/hashicorp/aws"]
  6788    num = 2
  6789    type = aws_instance
  6790  	`)
  6791  }
  6792  
  6793  func TestContext2Apply_targetedCount(t *testing.T) {
  6794  	m := testModule(t, "apply-targeted-count")
  6795  	p := testProvider("aws")
  6796  	p.PlanResourceChangeFn = testDiffFn
  6797  	p.ApplyResourceChangeFn = testApplyFn
  6798  	ctx := testContext2(t, &ContextOpts{
  6799  		Providers: map[addrs.Provider]providers.Factory{
  6800  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6801  		},
  6802  	})
  6803  
  6804  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  6805  		Mode: plans.NormalMode,
  6806  		Targets: []addrs.Targetable{
  6807  			addrs.RootModuleInstance.Resource(
  6808  				addrs.ManagedResourceMode, "aws_instance", "foo",
  6809  			),
  6810  		},
  6811  	})
  6812  	assertNoErrors(t, diags)
  6813  
  6814  	state, diags := ctx.Apply(plan, m)
  6815  	if diags.HasErrors() {
  6816  		t.Fatalf("diags: %s", diags.Err())
  6817  	}
  6818  
  6819  	checkStateString(t, state, `
  6820  aws_instance.foo.0:
  6821    ID = foo
  6822    provider = provider["registry.terraform.io/hashicorp/aws"]
  6823    type = aws_instance
  6824  aws_instance.foo.1:
  6825    ID = foo
  6826    provider = provider["registry.terraform.io/hashicorp/aws"]
  6827    type = aws_instance
  6828  aws_instance.foo.2:
  6829    ID = foo
  6830    provider = provider["registry.terraform.io/hashicorp/aws"]
  6831    type = aws_instance
  6832  	`)
  6833  }
  6834  
  6835  func TestContext2Apply_targetedCountIndex(t *testing.T) {
  6836  	m := testModule(t, "apply-targeted-count")
  6837  	p := testProvider("aws")
  6838  	p.PlanResourceChangeFn = testDiffFn
  6839  	p.ApplyResourceChangeFn = testApplyFn
  6840  	ctx := testContext2(t, &ContextOpts{
  6841  		Providers: map[addrs.Provider]providers.Factory{
  6842  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6843  		},
  6844  	})
  6845  
  6846  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  6847  		Mode: plans.NormalMode,
  6848  		Targets: []addrs.Targetable{
  6849  			addrs.RootModuleInstance.ResourceInstance(
  6850  				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(1),
  6851  			),
  6852  		},
  6853  	})
  6854  	assertNoErrors(t, diags)
  6855  
  6856  	state, diags := ctx.Apply(plan, m)
  6857  	if diags.HasErrors() {
  6858  		t.Fatalf("diags: %s", diags.Err())
  6859  	}
  6860  
  6861  	checkStateString(t, state, `
  6862  aws_instance.foo.1:
  6863    ID = foo
  6864    provider = provider["registry.terraform.io/hashicorp/aws"]
  6865    type = aws_instance
  6866  	`)
  6867  }
  6868  
  6869  func TestContext2Apply_targetedDestroy(t *testing.T) {
  6870  	m := testModule(t, "destroy-targeted")
  6871  	p := testProvider("aws")
  6872  	p.PlanResourceChangeFn = testDiffFn
  6873  
  6874  	state := states.NewState()
  6875  	root := state.EnsureModule(addrs.RootModuleInstance)
  6876  	root.SetResourceInstanceCurrent(
  6877  		mustResourceInstanceAddr("aws_instance.a").Resource,
  6878  		&states.ResourceInstanceObjectSrc{
  6879  			Status:    states.ObjectReady,
  6880  			AttrsJSON: []byte(`{"id":"bar"}`),
  6881  		},
  6882  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6883  	)
  6884  	root.SetOutputValue("out", cty.StringVal("bar"), false)
  6885  
  6886  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  6887  	child.SetResourceInstanceCurrent(
  6888  		mustResourceInstanceAddr("aws_instance.b").Resource,
  6889  		&states.ResourceInstanceObjectSrc{
  6890  			Status:    states.ObjectReady,
  6891  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  6892  		},
  6893  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6894  	)
  6895  
  6896  	ctx := testContext2(t, &ContextOpts{
  6897  		Providers: map[addrs.Provider]providers.Factory{
  6898  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6899  		},
  6900  	})
  6901  
  6902  	if diags := ctx.Validate(m); diags.HasErrors() {
  6903  		t.Fatalf("validate errors: %s", diags.Err())
  6904  	}
  6905  
  6906  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  6907  		Mode: plans.DestroyMode,
  6908  		Targets: []addrs.Targetable{
  6909  			addrs.RootModuleInstance.Resource(
  6910  				addrs.ManagedResourceMode, "aws_instance", "a",
  6911  			),
  6912  		},
  6913  	})
  6914  	assertNoErrors(t, diags)
  6915  
  6916  	state, diags = ctx.Apply(plan, m)
  6917  	if diags.HasErrors() {
  6918  		t.Fatalf("diags: %s", diags.Err())
  6919  	}
  6920  
  6921  	mod := state.RootModule()
  6922  	if len(mod.Resources) != 0 {
  6923  		t.Fatalf("expected 0 resources, got: %#v", mod.Resources)
  6924  	}
  6925  
  6926  	// the root output should not get removed; only the targeted resource.
  6927  	//
  6928  	// Note: earlier versions of this test expected 0 outputs, but it turns out
  6929  	// that was because Validate - not apply or destroy - removed the output
  6930  	// (which depends on the targeted resource) from state. That version of this
  6931  	// test did not match actual terraform behavior: the output remains in
  6932  	// state.
  6933  	//
  6934  	// TODO: Future refactoring may enable us to remove the output from state in
  6935  	// this case, and that would be Just Fine - this test can be modified to
  6936  	// expect 0 outputs.
  6937  	if len(mod.OutputValues) != 1 {
  6938  		t.Fatalf("expected 1 outputs, got: %#v", mod.OutputValues)
  6939  	}
  6940  
  6941  	// the module instance should remain
  6942  	mod = state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  6943  	if len(mod.Resources) != 1 {
  6944  		t.Fatalf("expected 1 resources, got: %#v", mod.Resources)
  6945  	}
  6946  }
  6947  
  6948  func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) {
  6949  	m := testModule(t, "apply-destroy-targeted-count")
  6950  	p := testProvider("aws")
  6951  	p.PlanResourceChangeFn = testDiffFn
  6952  
  6953  	state := states.NewState()
  6954  	root := state.EnsureModule(addrs.RootModuleInstance)
  6955  	root.SetResourceInstanceCurrent(
  6956  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  6957  		&states.ResourceInstanceObjectSrc{
  6958  			Status:    states.ObjectReady,
  6959  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  6960  		},
  6961  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6962  	)
  6963  	root.SetResourceInstanceCurrent(
  6964  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  6965  		&states.ResourceInstanceObjectSrc{
  6966  			Status:       states.ObjectReady,
  6967  			AttrsJSON:    []byte(`{"id":"i-abc123"}`),
  6968  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  6969  		},
  6970  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  6971  	)
  6972  
  6973  	ctx := testContext2(t, &ContextOpts{
  6974  		Providers: map[addrs.Provider]providers.Factory{
  6975  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6976  		},
  6977  	})
  6978  
  6979  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  6980  		Mode: plans.DestroyMode,
  6981  		Targets: []addrs.Targetable{
  6982  			addrs.RootModuleInstance.Resource(
  6983  				addrs.ManagedResourceMode, "aws_instance", "foo",
  6984  			),
  6985  		},
  6986  	})
  6987  	assertNoErrors(t, diags)
  6988  
  6989  	state, diags = ctx.Apply(plan, m)
  6990  	if diags.HasErrors() {
  6991  		t.Fatalf("diags: %s", diags.Err())
  6992  	}
  6993  
  6994  	checkStateString(t, state, `<no state>`)
  6995  }
  6996  
  6997  // https://github.com/hashicorp/terraform/issues/4462
  6998  func TestContext2Apply_targetedDestroyModule(t *testing.T) {
  6999  	m := testModule(t, "apply-targeted-module")
  7000  	p := testProvider("aws")
  7001  	p.PlanResourceChangeFn = testDiffFn
  7002  
  7003  	state := states.NewState()
  7004  	root := state.EnsureModule(addrs.RootModuleInstance)
  7005  	root.SetResourceInstanceCurrent(
  7006  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7007  		&states.ResourceInstanceObjectSrc{
  7008  			Status:    states.ObjectReady,
  7009  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7010  		},
  7011  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7012  	)
  7013  	root.SetResourceInstanceCurrent(
  7014  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7015  		&states.ResourceInstanceObjectSrc{
  7016  			Status:    states.ObjectReady,
  7017  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7018  		},
  7019  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7020  	)
  7021  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7022  	child.SetResourceInstanceCurrent(
  7023  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  7024  		&states.ResourceInstanceObjectSrc{
  7025  			Status:    states.ObjectReady,
  7026  			AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7027  		},
  7028  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7029  	)
  7030  	child.SetResourceInstanceCurrent(
  7031  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7032  		&states.ResourceInstanceObjectSrc{
  7033  			Status:    states.ObjectReady,
  7034  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7035  		},
  7036  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7037  	)
  7038  
  7039  	ctx := testContext2(t, &ContextOpts{
  7040  		Providers: map[addrs.Provider]providers.Factory{
  7041  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7042  		},
  7043  	})
  7044  
  7045  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7046  		Mode: plans.DestroyMode,
  7047  		Targets: []addrs.Targetable{
  7048  			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
  7049  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7050  			),
  7051  		},
  7052  	})
  7053  	assertNoErrors(t, diags)
  7054  
  7055  	state, diags = ctx.Apply(plan, m)
  7056  	if diags.HasErrors() {
  7057  		t.Fatalf("diags: %s", diags.Err())
  7058  	}
  7059  
  7060  	checkStateString(t, state, `
  7061  aws_instance.bar:
  7062    ID = i-abc123
  7063    provider = provider["registry.terraform.io/hashicorp/aws"]
  7064  aws_instance.foo:
  7065    ID = i-bcd345
  7066    provider = provider["registry.terraform.io/hashicorp/aws"]
  7067  
  7068  module.child:
  7069    aws_instance.bar:
  7070      ID = i-abc123
  7071      provider = provider["registry.terraform.io/hashicorp/aws"]
  7072  	`)
  7073  }
  7074  
  7075  func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) {
  7076  	m := testModule(t, "apply-targeted-count")
  7077  	p := testProvider("aws")
  7078  	p.PlanResourceChangeFn = testDiffFn
  7079  
  7080  	foo := &states.ResourceInstanceObjectSrc{
  7081  		Status:    states.ObjectReady,
  7082  		AttrsJSON: []byte(`{"id":"i-bcd345"}`),
  7083  	}
  7084  	bar := &states.ResourceInstanceObjectSrc{
  7085  		Status:    states.ObjectReady,
  7086  		AttrsJSON: []byte(`{"id":"i-abc123"}`),
  7087  	}
  7088  
  7089  	state := states.NewState()
  7090  	root := state.EnsureModule(addrs.RootModuleInstance)
  7091  	root.SetResourceInstanceCurrent(
  7092  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  7093  		foo,
  7094  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7095  	)
  7096  	root.SetResourceInstanceCurrent(
  7097  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  7098  		foo,
  7099  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7100  	)
  7101  	root.SetResourceInstanceCurrent(
  7102  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  7103  		foo,
  7104  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7105  	)
  7106  	root.SetResourceInstanceCurrent(
  7107  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  7108  		bar,
  7109  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7110  	)
  7111  	root.SetResourceInstanceCurrent(
  7112  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  7113  		bar,
  7114  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7115  	)
  7116  	root.SetResourceInstanceCurrent(
  7117  		mustResourceInstanceAddr("aws_instance.bar[2]").Resource,
  7118  		bar,
  7119  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7120  	)
  7121  
  7122  	ctx := testContext2(t, &ContextOpts{
  7123  		Providers: map[addrs.Provider]providers.Factory{
  7124  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7125  		},
  7126  	})
  7127  
  7128  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7129  		Mode: plans.DestroyMode,
  7130  		Targets: []addrs.Targetable{
  7131  			addrs.RootModuleInstance.ResourceInstance(
  7132  				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(2),
  7133  			),
  7134  			addrs.RootModuleInstance.ResourceInstance(
  7135  				addrs.ManagedResourceMode, "aws_instance", "bar", addrs.IntKey(1),
  7136  			),
  7137  		},
  7138  	})
  7139  	assertNoErrors(t, diags)
  7140  
  7141  	state, diags = ctx.Apply(plan, m)
  7142  	if diags.HasErrors() {
  7143  		t.Fatalf("diags: %s", diags.Err())
  7144  	}
  7145  
  7146  	checkStateString(t, state, `
  7147  aws_instance.bar.0:
  7148    ID = i-abc123
  7149    provider = provider["registry.terraform.io/hashicorp/aws"]
  7150  aws_instance.bar.2:
  7151    ID = i-abc123
  7152    provider = provider["registry.terraform.io/hashicorp/aws"]
  7153  aws_instance.foo.0:
  7154    ID = i-bcd345
  7155    provider = provider["registry.terraform.io/hashicorp/aws"]
  7156  aws_instance.foo.1:
  7157    ID = i-bcd345
  7158    provider = provider["registry.terraform.io/hashicorp/aws"]
  7159  	`)
  7160  }
  7161  
  7162  func TestContext2Apply_targetedModule(t *testing.T) {
  7163  	m := testModule(t, "apply-targeted-module")
  7164  	p := testProvider("aws")
  7165  	p.PlanResourceChangeFn = testDiffFn
  7166  	p.ApplyResourceChangeFn = testApplyFn
  7167  	ctx := testContext2(t, &ContextOpts{
  7168  		Providers: map[addrs.Provider]providers.Factory{
  7169  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7170  		},
  7171  	})
  7172  
  7173  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7174  		Mode: plans.NormalMode,
  7175  		Targets: []addrs.Targetable{
  7176  			addrs.RootModuleInstance.Child("child", addrs.NoKey),
  7177  		},
  7178  	})
  7179  	assertNoErrors(t, diags)
  7180  
  7181  	state, diags := ctx.Apply(plan, m)
  7182  	if diags.HasErrors() {
  7183  		t.Fatalf("diags: %s", diags.Err())
  7184  	}
  7185  
  7186  	mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7187  	if mod == nil {
  7188  		t.Fatalf("no child module found in the state!\n\n%#v", state)
  7189  	}
  7190  	if len(mod.Resources) != 2 {
  7191  		t.Fatalf("expected 2 resources, got: %#v", mod.Resources)
  7192  	}
  7193  
  7194  	checkStateString(t, state, `
  7195  <no state>
  7196  module.child:
  7197    aws_instance.bar:
  7198      ID = foo
  7199      provider = provider["registry.terraform.io/hashicorp/aws"]
  7200      num = 2
  7201      type = aws_instance
  7202    aws_instance.foo:
  7203      ID = foo
  7204      provider = provider["registry.terraform.io/hashicorp/aws"]
  7205      num = 2
  7206      type = aws_instance
  7207  	`)
  7208  }
  7209  
  7210  // GH-1858
  7211  func TestContext2Apply_targetedModuleDep(t *testing.T) {
  7212  	m := testModule(t, "apply-targeted-module-dep")
  7213  	p := testProvider("aws")
  7214  	p.PlanResourceChangeFn = testDiffFn
  7215  	p.ApplyResourceChangeFn = testApplyFn
  7216  	ctx := testContext2(t, &ContextOpts{
  7217  		Providers: map[addrs.Provider]providers.Factory{
  7218  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7219  		},
  7220  	})
  7221  
  7222  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7223  		Mode: plans.NormalMode,
  7224  		Targets: []addrs.Targetable{
  7225  			addrs.RootModuleInstance.Resource(
  7226  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7227  			),
  7228  		},
  7229  	})
  7230  	if diags.HasErrors() {
  7231  		t.Fatalf("diags: %s", diags.Err())
  7232  	} else {
  7233  		t.Logf("Diff: %s", legacyDiffComparisonString(plan.Changes))
  7234  	}
  7235  
  7236  	state, diags := ctx.Apply(plan, m)
  7237  	if diags.HasErrors() {
  7238  		t.Fatalf("diags: %s", diags.Err())
  7239  	}
  7240  
  7241  	checkStateString(t, state, `
  7242  aws_instance.foo:
  7243    ID = foo
  7244    provider = provider["registry.terraform.io/hashicorp/aws"]
  7245    foo = foo
  7246    type = aws_instance
  7247  
  7248    Dependencies:
  7249      module.child.aws_instance.mod
  7250  
  7251  module.child:
  7252    aws_instance.mod:
  7253      ID = foo
  7254      provider = provider["registry.terraform.io/hashicorp/aws"]
  7255      type = aws_instance
  7256  
  7257    Outputs:
  7258  
  7259    output = foo
  7260  	`)
  7261  }
  7262  
  7263  // GH-10911 untargeted outputs should not be in the graph, and therefore
  7264  // not execute.
  7265  func TestContext2Apply_targetedModuleUnrelatedOutputs(t *testing.T) {
  7266  	m := testModule(t, "apply-targeted-module-unrelated-outputs")
  7267  	p := testProvider("aws")
  7268  	p.PlanResourceChangeFn = testDiffFn
  7269  	p.ApplyResourceChangeFn = testApplyFn
  7270  
  7271  	state := states.NewState()
  7272  	_ = state.EnsureModule(addrs.RootModuleInstance.Child("child2", addrs.NoKey))
  7273  
  7274  	ctx := testContext2(t, &ContextOpts{
  7275  		Providers: map[addrs.Provider]providers.Factory{
  7276  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7277  		},
  7278  	})
  7279  
  7280  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7281  		Mode: plans.NormalMode,
  7282  		Targets: []addrs.Targetable{
  7283  			addrs.RootModuleInstance.Child("child2", addrs.NoKey),
  7284  		},
  7285  	})
  7286  	assertNoErrors(t, diags)
  7287  
  7288  	s, diags := ctx.Apply(plan, m)
  7289  	if diags.HasErrors() {
  7290  		t.Fatalf("diags: %s", diags.Err())
  7291  	}
  7292  
  7293  	// - module.child1's instance_id output is dropped because we don't preserve
  7294  	//   non-root module outputs between runs (they can be recalculated from config)
  7295  	// - module.child2's instance_id is updated because its dependency is updated
  7296  	// - child2_id is updated because if its transitive dependency via module.child2
  7297  	checkStateString(t, s, `
  7298  <no state>
  7299  Outputs:
  7300  
  7301  child2_id = foo
  7302  
  7303  module.child2:
  7304    aws_instance.foo:
  7305      ID = foo
  7306      provider = provider["registry.terraform.io/hashicorp/aws"]
  7307      type = aws_instance
  7308  
  7309    Outputs:
  7310  
  7311    instance_id = foo
  7312  `)
  7313  }
  7314  
  7315  func TestContext2Apply_targetedModuleResource(t *testing.T) {
  7316  	m := testModule(t, "apply-targeted-module-resource")
  7317  	p := testProvider("aws")
  7318  	p.PlanResourceChangeFn = testDiffFn
  7319  	p.ApplyResourceChangeFn = testApplyFn
  7320  	ctx := testContext2(t, &ContextOpts{
  7321  		Providers: map[addrs.Provider]providers.Factory{
  7322  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7323  		},
  7324  	})
  7325  
  7326  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7327  		Mode: plans.NormalMode,
  7328  		Targets: []addrs.Targetable{
  7329  			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
  7330  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7331  			),
  7332  		},
  7333  	})
  7334  	assertNoErrors(t, diags)
  7335  
  7336  	state, diags := ctx.Apply(plan, m)
  7337  	if diags.HasErrors() {
  7338  		t.Fatalf("diags: %s", diags.Err())
  7339  	}
  7340  
  7341  	mod := state.Module(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  7342  	if mod == nil || len(mod.Resources) != 1 {
  7343  		t.Fatalf("expected 1 resource, got: %#v", mod)
  7344  	}
  7345  
  7346  	checkStateString(t, state, `
  7347  <no state>
  7348  module.child:
  7349    aws_instance.foo:
  7350      ID = foo
  7351      provider = provider["registry.terraform.io/hashicorp/aws"]
  7352      num = 2
  7353      type = aws_instance
  7354  	`)
  7355  }
  7356  
  7357  func TestContext2Apply_targetedResourceOrphanModule(t *testing.T) {
  7358  	m := testModule(t, "apply-targeted-resource-orphan-module")
  7359  	p := testProvider("aws")
  7360  	p.PlanResourceChangeFn = testDiffFn
  7361  
  7362  	state := states.NewState()
  7363  	child := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey))
  7364  	child.SetResourceInstanceCurrent(
  7365  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  7366  		&states.ResourceInstanceObjectSrc{
  7367  			Status:    states.ObjectReady,
  7368  			AttrsJSON: []byte(`{"type":"aws_instance"}`),
  7369  		},
  7370  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7371  	)
  7372  
  7373  	ctx := testContext2(t, &ContextOpts{
  7374  		Providers: map[addrs.Provider]providers.Factory{
  7375  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7376  		},
  7377  	})
  7378  
  7379  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7380  		Mode: plans.NormalMode,
  7381  		Targets: []addrs.Targetable{
  7382  			addrs.RootModuleInstance.Resource(
  7383  				addrs.ManagedResourceMode, "aws_instance", "foo",
  7384  			),
  7385  		},
  7386  	})
  7387  	assertNoErrors(t, diags)
  7388  
  7389  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
  7390  		t.Fatalf("apply errors: %s", diags.Err())
  7391  	}
  7392  }
  7393  
  7394  func TestContext2Apply_unknownAttribute(t *testing.T) {
  7395  	m := testModule(t, "apply-unknown")
  7396  	p := testProvider("aws")
  7397  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  7398  		resp = testDiffFn(req)
  7399  		planned := resp.PlannedState.AsValueMap()
  7400  		planned["unknown"] = cty.UnknownVal(cty.String)
  7401  		resp.PlannedState = cty.ObjectVal(planned)
  7402  		return resp
  7403  	}
  7404  	p.ApplyResourceChangeFn = testApplyFn
  7405  
  7406  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  7407  		ResourceTypes: map[string]*configschema.Block{
  7408  			"aws_instance": {
  7409  				Attributes: map[string]*configschema.Attribute{
  7410  					"id":      {Type: cty.String, Computed: true},
  7411  					"num":     {Type: cty.Number, Optional: true},
  7412  					"unknown": {Type: cty.String, Computed: true},
  7413  					"type":    {Type: cty.String, Computed: true},
  7414  				},
  7415  			},
  7416  		},
  7417  	})
  7418  
  7419  	ctx := testContext2(t, &ContextOpts{
  7420  		Providers: map[addrs.Provider]providers.Factory{
  7421  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7422  		},
  7423  	})
  7424  
  7425  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  7426  	assertNoErrors(t, diags)
  7427  
  7428  	state, diags := ctx.Apply(plan, m)
  7429  	if !diags.HasErrors() {
  7430  		t.Error("should error, because attribute 'unknown' is still unknown after apply")
  7431  	}
  7432  
  7433  	actual := strings.TrimSpace(state.String())
  7434  	expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr)
  7435  	if actual != expected {
  7436  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  7437  	}
  7438  }
  7439  
  7440  func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) {
  7441  	m := testModule(t, "apply-unknown-interpolate")
  7442  	p := testProvider("aws")
  7443  	p.PlanResourceChangeFn = testDiffFn
  7444  	ctx := testContext2(t, &ContextOpts{
  7445  		Providers: map[addrs.Provider]providers.Factory{
  7446  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7447  		},
  7448  	})
  7449  
  7450  	if _, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts); diags == nil {
  7451  		t.Fatal("should error")
  7452  	}
  7453  }
  7454  
  7455  func TestContext2Apply_vars(t *testing.T) {
  7456  	fixture := contextFixtureApplyVars(t)
  7457  	opts := fixture.ContextOpts()
  7458  	ctx := testContext2(t, opts)
  7459  	m := fixture.Config
  7460  
  7461  	diags := ctx.Validate(m)
  7462  	if len(diags) != 0 {
  7463  		t.Fatalf("bad: %s", diags.ErrWithWarnings())
  7464  	}
  7465  
  7466  	variables := InputValues{
  7467  		"foo": &InputValue{
  7468  			Value:      cty.StringVal("us-east-1"),
  7469  			SourceType: ValueFromCaller,
  7470  		},
  7471  		"test_list": &InputValue{
  7472  			Value: cty.ListVal([]cty.Value{
  7473  				cty.StringVal("Hello"),
  7474  				cty.StringVal("World"),
  7475  			}),
  7476  			SourceType: ValueFromCaller,
  7477  		},
  7478  		"test_map": &InputValue{
  7479  			Value: cty.MapVal(map[string]cty.Value{
  7480  				"Hello": cty.StringVal("World"),
  7481  				"Foo":   cty.StringVal("Bar"),
  7482  				"Baz":   cty.StringVal("Foo"),
  7483  			}),
  7484  			SourceType: ValueFromCaller,
  7485  		},
  7486  		"amis": &InputValue{
  7487  			Value: cty.MapVal(map[string]cty.Value{
  7488  				"us-east-1": cty.StringVal("override"),
  7489  			}),
  7490  			SourceType: ValueFromCaller,
  7491  		},
  7492  	}
  7493  
  7494  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7495  		Mode:         plans.NormalMode,
  7496  		SetVariables: variables,
  7497  	})
  7498  	assertNoErrors(t, diags)
  7499  
  7500  	state, diags := ctx.Apply(plan, m)
  7501  	if diags.HasErrors() {
  7502  		t.Fatalf("err: %s", diags.Err())
  7503  	}
  7504  
  7505  	got := strings.TrimSpace(state.String())
  7506  	want := strings.TrimSpace(testTerraformApplyVarsStr)
  7507  	if got != want {
  7508  		t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", got, want)
  7509  	}
  7510  }
  7511  
  7512  func TestContext2Apply_varsEnv(t *testing.T) {
  7513  	fixture := contextFixtureApplyVarsEnv(t)
  7514  	opts := fixture.ContextOpts()
  7515  	ctx := testContext2(t, opts)
  7516  	m := fixture.Config
  7517  
  7518  	diags := ctx.Validate(m)
  7519  	if len(diags) != 0 {
  7520  		t.Fatalf("bad: %s", diags.ErrWithWarnings())
  7521  	}
  7522  
  7523  	variables := InputValues{
  7524  		"string": &InputValue{
  7525  			Value:      cty.StringVal("baz"),
  7526  			SourceType: ValueFromEnvVar,
  7527  		},
  7528  		"list": &InputValue{
  7529  			Value: cty.ListVal([]cty.Value{
  7530  				cty.StringVal("Hello"),
  7531  				cty.StringVal("World"),
  7532  			}),
  7533  			SourceType: ValueFromEnvVar,
  7534  		},
  7535  		"map": &InputValue{
  7536  			Value: cty.MapVal(map[string]cty.Value{
  7537  				"Hello": cty.StringVal("World"),
  7538  				"Foo":   cty.StringVal("Bar"),
  7539  				"Baz":   cty.StringVal("Foo"),
  7540  			}),
  7541  			SourceType: ValueFromEnvVar,
  7542  		},
  7543  	}
  7544  
  7545  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  7546  		Mode:         plans.NormalMode,
  7547  		SetVariables: variables,
  7548  	})
  7549  	assertNoErrors(t, diags)
  7550  
  7551  	state, diags := ctx.Apply(plan, m)
  7552  	if diags.HasErrors() {
  7553  		t.Fatalf("err: %s", diags.Err())
  7554  	}
  7555  
  7556  	actual := strings.TrimSpace(state.String())
  7557  	expected := strings.TrimSpace(testTerraformApplyVarsEnvStr)
  7558  	if actual != expected {
  7559  		t.Errorf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
  7560  	}
  7561  }
  7562  
  7563  func TestContext2Apply_createBefore_depends(t *testing.T) {
  7564  	m := testModule(t, "apply-depends-create-before")
  7565  	h := new(HookRecordApplyOrder)
  7566  	p := testProvider("aws")
  7567  	p.PlanResourceChangeFn = testDiffFn
  7568  	p.ApplyResourceChangeFn = testApplyFn
  7569  	state := states.NewState()
  7570  	root := state.EnsureModule(addrs.RootModuleInstance)
  7571  	root.SetResourceInstanceCurrent(
  7572  		addrs.Resource{
  7573  			Mode: addrs.ManagedResourceMode,
  7574  			Type: "aws_instance",
  7575  			Name: "web",
  7576  		}.Instance(addrs.NoKey),
  7577  		&states.ResourceInstanceObjectSrc{
  7578  			Status:    states.ObjectReady,
  7579  			AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`),
  7580  		},
  7581  		addrs.AbsProviderConfig{
  7582  			Provider: addrs.NewDefaultProvider("aws"),
  7583  			Module:   addrs.RootModule,
  7584  		},
  7585  	)
  7586  
  7587  	root.SetResourceInstanceCurrent(
  7588  		addrs.Resource{
  7589  			Mode: addrs.ManagedResourceMode,
  7590  			Type: "aws_instance",
  7591  			Name: "lb",
  7592  		}.Instance(addrs.NoKey),
  7593  		&states.ResourceInstanceObjectSrc{
  7594  			Status:    states.ObjectReady,
  7595  			AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`),
  7596  			Dependencies: []addrs.ConfigResource{
  7597  				{
  7598  					Resource: addrs.Resource{
  7599  						Mode: addrs.ManagedResourceMode,
  7600  						Type: "aws_instance",
  7601  						Name: "web",
  7602  					},
  7603  					Module: addrs.RootModule,
  7604  				},
  7605  			},
  7606  		},
  7607  		addrs.AbsProviderConfig{
  7608  			Provider: addrs.NewDefaultProvider("aws"),
  7609  			Module:   addrs.RootModule,
  7610  		},
  7611  	)
  7612  
  7613  	ctx := testContext2(t, &ContextOpts{
  7614  		Hooks: []Hook{h},
  7615  		Providers: map[addrs.Provider]providers.Factory{
  7616  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7617  		},
  7618  	})
  7619  
  7620  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  7621  	if diags.HasErrors() {
  7622  		logDiagnostics(t, diags)
  7623  		t.Fatal("plan failed")
  7624  	} else {
  7625  		t.Logf("plan:\n%s", legacyDiffComparisonString(plan.Changes))
  7626  	}
  7627  
  7628  	h.Active = true
  7629  	state, diags = ctx.Apply(plan, m)
  7630  	if diags.HasErrors() {
  7631  		logDiagnostics(t, diags)
  7632  		t.Fatal("apply failed")
  7633  	}
  7634  
  7635  	mod := state.RootModule()
  7636  	if len(mod.Resources) < 2 {
  7637  		t.Logf("state after apply:\n%s", state.String())
  7638  		t.Fatalf("only %d resources in root module; want at least 2", len(mod.Resources))
  7639  	}
  7640  
  7641  	got := strings.TrimSpace(state.String())
  7642  	want := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr)
  7643  	if got != want {
  7644  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", got, want)
  7645  	}
  7646  
  7647  	// Test that things were managed _in the right order_
  7648  	order := h.States
  7649  
  7650  	diffs := h.Diffs
  7651  	if !order[0].IsNull() || diffs[0].Action == plans.Delete {
  7652  		t.Fatalf("should create new instance first: %#v", order)
  7653  	}
  7654  
  7655  	if order[1].GetAttr("id").AsString() != "baz" {
  7656  		t.Fatalf("update must happen after create: %#v", order[1])
  7657  	}
  7658  
  7659  	if order[2].GetAttr("id").AsString() != "bar" || diffs[2].Action != plans.Delete {
  7660  		t.Fatalf("destroy must happen after update: %#v", order[2])
  7661  	}
  7662  }
  7663  
  7664  func TestContext2Apply_singleDestroy(t *testing.T) {
  7665  	m := testModule(t, "apply-depends-create-before")
  7666  	h := new(HookRecordApplyOrder)
  7667  	p := testProvider("aws")
  7668  	invokeCount := 0
  7669  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  7670  		invokeCount++
  7671  		switch invokeCount {
  7672  		case 1:
  7673  			if req.PlannedState.IsNull() {
  7674  				t.Fatalf("should not destroy")
  7675  			}
  7676  			if id := req.PlannedState.GetAttr("id"); id.IsKnown() {
  7677  				t.Fatalf("should not have ID")
  7678  			}
  7679  		case 2:
  7680  			if req.PlannedState.IsNull() {
  7681  				t.Fatalf("should not destroy")
  7682  			}
  7683  			if id := req.PlannedState.GetAttr("id"); id.AsString() != "baz" {
  7684  				t.Fatalf("should have id")
  7685  			}
  7686  		case 3:
  7687  			if !req.PlannedState.IsNull() {
  7688  				t.Fatalf("should destroy")
  7689  			}
  7690  		default:
  7691  			t.Fatalf("bad invoke count %d", invokeCount)
  7692  		}
  7693  		return testApplyFn(req)
  7694  	}
  7695  
  7696  	p.PlanResourceChangeFn = testDiffFn
  7697  	state := states.NewState()
  7698  	root := state.EnsureModule(addrs.RootModuleInstance)
  7699  	root.SetResourceInstanceCurrent(
  7700  		addrs.Resource{
  7701  			Mode: addrs.ManagedResourceMode,
  7702  			Type: "aws_instance",
  7703  			Name: "web",
  7704  		}.Instance(addrs.NoKey),
  7705  		&states.ResourceInstanceObjectSrc{
  7706  			Status:    states.ObjectReady,
  7707  			AttrsJSON: []byte(`{"id":"bar","require_new":"ami-old"}`),
  7708  		},
  7709  		addrs.AbsProviderConfig{
  7710  			Provider: addrs.NewDefaultProvider("aws"),
  7711  			Module:   addrs.RootModule,
  7712  		},
  7713  	)
  7714  
  7715  	root.SetResourceInstanceCurrent(
  7716  		addrs.Resource{
  7717  			Mode: addrs.ManagedResourceMode,
  7718  			Type: "aws_instance",
  7719  			Name: "lb",
  7720  		}.Instance(addrs.NoKey),
  7721  		&states.ResourceInstanceObjectSrc{
  7722  			Status:    states.ObjectReady,
  7723  			AttrsJSON: []byte(`{"id":"baz","instance":"bar"}`),
  7724  			Dependencies: []addrs.ConfigResource{
  7725  				{
  7726  					Resource: addrs.Resource{
  7727  						Mode: addrs.ManagedResourceMode,
  7728  						Type: "aws_instance",
  7729  						Name: "web",
  7730  					},
  7731  					Module: addrs.RootModule,
  7732  				},
  7733  			},
  7734  		},
  7735  		addrs.AbsProviderConfig{
  7736  			Provider: addrs.NewDefaultProvider("aws"),
  7737  			Module:   addrs.RootModule,
  7738  		},
  7739  	)
  7740  
  7741  	ctx := testContext2(t, &ContextOpts{
  7742  		Hooks: []Hook{h},
  7743  		Providers: map[addrs.Provider]providers.Factory{
  7744  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7745  		},
  7746  	})
  7747  
  7748  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  7749  	assertNoErrors(t, diags)
  7750  
  7751  	h.Active = true
  7752  	_, diags = ctx.Apply(plan, m)
  7753  	if diags.HasErrors() {
  7754  		t.Fatalf("diags: %s", diags.Err())
  7755  	}
  7756  
  7757  	if invokeCount != 3 {
  7758  		t.Fatalf("bad: %d", invokeCount)
  7759  	}
  7760  }
  7761  
  7762  // GH-7824
  7763  func TestContext2Apply_issue7824(t *testing.T) {
  7764  	p := testProvider("template")
  7765  	p.PlanResourceChangeFn = testDiffFn
  7766  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  7767  		ResourceTypes: map[string]*configschema.Block{
  7768  			"template_file": {
  7769  				Attributes: map[string]*configschema.Attribute{
  7770  					"template":                {Type: cty.String, Optional: true},
  7771  					"__template_requires_new": {Type: cty.Bool, Optional: true},
  7772  				},
  7773  			},
  7774  		},
  7775  	})
  7776  
  7777  	m, snap := testModuleWithSnapshot(t, "issue-7824")
  7778  
  7779  	// Apply cleanly step 0
  7780  	ctx := testContext2(t, &ContextOpts{
  7781  		Providers: map[addrs.Provider]providers.Factory{
  7782  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7783  		},
  7784  	})
  7785  
  7786  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  7787  	if diags.HasErrors() {
  7788  		t.Fatalf("err: %s", diags.Err())
  7789  	}
  7790  
  7791  	// Write / Read plan to simulate running it through a Plan file
  7792  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  7793  	if err != nil {
  7794  		t.Fatalf("failed to round-trip through planfile: %s", err)
  7795  	}
  7796  
  7797  	ctxOpts.Providers =
  7798  		map[addrs.Provider]providers.Factory{
  7799  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7800  		}
  7801  
  7802  	ctx, diags = NewContext(ctxOpts)
  7803  	if diags.HasErrors() {
  7804  		t.Fatalf("err: %s", diags.Err())
  7805  	}
  7806  
  7807  	_, diags = ctx.Apply(plan, m)
  7808  	if diags.HasErrors() {
  7809  		t.Fatalf("err: %s", diags.Err())
  7810  	}
  7811  }
  7812  
  7813  // This deals with the situation where a splat expression is used referring
  7814  // to another resource whose count is non-constant.
  7815  func TestContext2Apply_issue5254(t *testing.T) {
  7816  	// Create a provider. We use "template" here just to match the repro
  7817  	// we got from the issue itself.
  7818  	p := testProvider("template")
  7819  	p.PlanResourceChangeFn = testDiffFn
  7820  	p.ApplyResourceChangeFn = testApplyFn
  7821  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  7822  		ResourceTypes: map[string]*configschema.Block{
  7823  			"template_file": {
  7824  				Attributes: map[string]*configschema.Attribute{
  7825  					"template":                {Type: cty.String, Optional: true},
  7826  					"__template_requires_new": {Type: cty.Bool, Optional: true},
  7827  					"id":                      {Type: cty.String, Computed: true},
  7828  					"type":                    {Type: cty.String, Computed: true},
  7829  				},
  7830  			},
  7831  		},
  7832  	})
  7833  
  7834  	// Apply cleanly step 0
  7835  	m := testModule(t, "issue-5254/step-0")
  7836  	ctx := testContext2(t, &ContextOpts{
  7837  		Providers: map[addrs.Provider]providers.Factory{
  7838  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7839  		},
  7840  	})
  7841  
  7842  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  7843  	if diags.HasErrors() {
  7844  		t.Fatalf("err: %s", diags.Err())
  7845  	}
  7846  
  7847  	state, diags := ctx.Apply(plan, m)
  7848  	if diags.HasErrors() {
  7849  		t.Fatalf("err: %s", diags.Err())
  7850  	}
  7851  
  7852  	m, snap := testModuleWithSnapshot(t, "issue-5254/step-1")
  7853  
  7854  	// Application success. Now make the modification and store a plan
  7855  	ctx = testContext2(t, &ContextOpts{
  7856  		Providers: map[addrs.Provider]providers.Factory{
  7857  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7858  		},
  7859  	})
  7860  
  7861  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  7862  	if diags.HasErrors() {
  7863  		t.Fatalf("err: %s", diags.Err())
  7864  	}
  7865  
  7866  	// Write / Read plan to simulate running it through a Plan file
  7867  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  7868  	if err != nil {
  7869  		t.Fatalf("failed to round-trip through planfile: %s", err)
  7870  	}
  7871  
  7872  	ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  7873  		addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  7874  	}
  7875  
  7876  	ctx, diags = NewContext(ctxOpts)
  7877  	if diags.HasErrors() {
  7878  		t.Fatalf("err: %s", diags.Err())
  7879  	}
  7880  
  7881  	state, diags = ctx.Apply(plan, m)
  7882  	if diags.HasErrors() {
  7883  		t.Fatalf("err: %s", diags.Err())
  7884  	}
  7885  
  7886  	actual := strings.TrimSpace(state.String())
  7887  	expected := strings.TrimSpace(`
  7888  template_file.child:
  7889    ID = foo
  7890    provider = provider["registry.terraform.io/hashicorp/template"]
  7891    __template_requires_new = true
  7892    template = Hi
  7893    type = template_file
  7894  
  7895    Dependencies:
  7896      template_file.parent
  7897  template_file.parent.0:
  7898    ID = foo
  7899    provider = provider["registry.terraform.io/hashicorp/template"]
  7900    template = Hi
  7901    type = template_file
  7902  `)
  7903  	if actual != expected {
  7904  		t.Fatalf("wrong final state\ngot:\n%s\n\nwant:\n%s", actual, expected)
  7905  	}
  7906  }
  7907  
  7908  func TestContext2Apply_targetedWithTaintedInState(t *testing.T) {
  7909  	p := testProvider("aws")
  7910  	p.PlanResourceChangeFn = testDiffFn
  7911  	p.ApplyResourceChangeFn = testApplyFn
  7912  	m, snap := testModuleWithSnapshot(t, "apply-tainted-targets")
  7913  
  7914  	state := states.NewState()
  7915  	root := state.EnsureModule(addrs.RootModuleInstance)
  7916  	root.SetResourceInstanceCurrent(
  7917  		mustResourceInstanceAddr("aws_instance.ifailedprovisioners").Resource,
  7918  		&states.ResourceInstanceObjectSrc{
  7919  			Status:    states.ObjectTainted,
  7920  			AttrsJSON: []byte(`{"id":"ifailedprovisioners"}`),
  7921  		},
  7922  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  7923  	)
  7924  
  7925  	ctx := testContext2(t, &ContextOpts{
  7926  		Providers: map[addrs.Provider]providers.Factory{
  7927  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7928  		},
  7929  	})
  7930  
  7931  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  7932  		Mode: plans.NormalMode,
  7933  		Targets: []addrs.Targetable{
  7934  			addrs.RootModuleInstance.Resource(
  7935  				addrs.ManagedResourceMode, "aws_instance", "iambeingadded",
  7936  			),
  7937  		},
  7938  	})
  7939  	if diags.HasErrors() {
  7940  		t.Fatalf("err: %s", diags.Err())
  7941  	}
  7942  
  7943  	// Write / Read plan to simulate running it through a Plan file
  7944  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  7945  	if err != nil {
  7946  		t.Fatalf("failed to round-trip through planfile: %s", err)
  7947  	}
  7948  
  7949  	ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  7950  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7951  	}
  7952  
  7953  	ctx, diags = NewContext(ctxOpts)
  7954  	if diags.HasErrors() {
  7955  		t.Fatalf("err: %s", diags.Err())
  7956  	}
  7957  
  7958  	s, diags := ctx.Apply(plan, m)
  7959  	if diags.HasErrors() {
  7960  		t.Fatalf("err: %s", diags.Err())
  7961  	}
  7962  
  7963  	actual := strings.TrimSpace(s.String())
  7964  	expected := strings.TrimSpace(`
  7965  aws_instance.iambeingadded:
  7966    ID = foo
  7967    provider = provider["registry.terraform.io/hashicorp/aws"]
  7968    type = aws_instance
  7969  aws_instance.ifailedprovisioners: (tainted)
  7970    ID = ifailedprovisioners
  7971    provider = provider["registry.terraform.io/hashicorp/aws"]
  7972  		`)
  7973  	if actual != expected {
  7974  		t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual)
  7975  	}
  7976  }
  7977  
  7978  // Higher level test exposing the bug this covers in
  7979  // TestResource_ignoreChangesRequired
  7980  func TestContext2Apply_ignoreChangesCreate(t *testing.T) {
  7981  	m := testModule(t, "apply-ignore-changes-create")
  7982  	p := testProvider("aws")
  7983  	p.PlanResourceChangeFn = testDiffFn
  7984  	p.ApplyResourceChangeFn = testApplyFn
  7985  
  7986  	instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  7987  	instanceSchema.Attributes["required_field"] = &configschema.Attribute{
  7988  		Type:     cty.String,
  7989  		Required: true,
  7990  	}
  7991  
  7992  	ctx := testContext2(t, &ContextOpts{
  7993  		Providers: map[addrs.Provider]providers.Factory{
  7994  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  7995  		},
  7996  	})
  7997  
  7998  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  7999  	if diags.HasErrors() {
  8000  		t.Fatalf("diags: %s", diags.Err())
  8001  	} else {
  8002  		t.Logf(legacyDiffComparisonString(plan.Changes))
  8003  	}
  8004  
  8005  	state, diags := ctx.Apply(plan, m)
  8006  	if diags.HasErrors() {
  8007  		t.Fatalf("diags: %s", diags.Err())
  8008  	}
  8009  
  8010  	mod := state.RootModule()
  8011  	if len(mod.Resources) != 1 {
  8012  		t.Fatalf("bad: %s", state)
  8013  	}
  8014  
  8015  	actual := strings.TrimSpace(state.String())
  8016  	// Expect no changes from original state
  8017  	expected := strings.TrimSpace(`
  8018  aws_instance.foo:
  8019    ID = foo
  8020    provider = provider["registry.terraform.io/hashicorp/aws"]
  8021    required_field = set
  8022    type = aws_instance
  8023  `)
  8024  	if actual != expected {
  8025  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
  8026  	}
  8027  }
  8028  
  8029  func TestContext2Apply_ignoreChangesWithDep(t *testing.T) {
  8030  	m := testModule(t, "apply-ignore-changes-dep")
  8031  	p := testProvider("aws")
  8032  
  8033  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  8034  		resp.PlannedState = req.ProposedNewState
  8035  
  8036  		switch req.TypeName {
  8037  		case "aws_instance":
  8038  			resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: "ami"}})
  8039  		case "aws_eip":
  8040  			return testDiffFn(req)
  8041  		default:
  8042  			t.Fatalf("Unexpected type: %s", req.TypeName)
  8043  		}
  8044  		return
  8045  	}
  8046  
  8047  	state := states.NewState()
  8048  	root := state.EnsureModule(addrs.RootModuleInstance)
  8049  	root.SetResourceInstanceCurrent(
  8050  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  8051  		&states.ResourceInstanceObjectSrc{
  8052  			Status:    states.ObjectReady,
  8053  			AttrsJSON: []byte(`{"id":"i-abc123","ami":"ami-abcd1234"}`),
  8054  		},
  8055  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8056  	)
  8057  	root.SetResourceInstanceCurrent(
  8058  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  8059  		&states.ResourceInstanceObjectSrc{
  8060  			Status:    states.ObjectReady,
  8061  			AttrsJSON: []byte(`{"id":"i-bcd234","ami":"i-bcd234"}`),
  8062  		},
  8063  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8064  	)
  8065  	root.SetResourceInstanceCurrent(
  8066  		mustResourceInstanceAddr("aws_eip.foo[0]").Resource,
  8067  		&states.ResourceInstanceObjectSrc{
  8068  			Status:    states.ObjectReady,
  8069  			AttrsJSON: []byte(`{"id":"eip-abc123","instance":"i-abc123"}`),
  8070  			Dependencies: []addrs.ConfigResource{
  8071  				{
  8072  					Resource: addrs.Resource{
  8073  						Mode: addrs.ManagedResourceMode,
  8074  						Type: "aws_instance",
  8075  						Name: "foo",
  8076  					},
  8077  					Module: addrs.RootModule,
  8078  				},
  8079  			},
  8080  		},
  8081  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8082  	)
  8083  	root.SetResourceInstanceCurrent(
  8084  		mustResourceInstanceAddr("aws_eip.foo[1]").Resource,
  8085  		&states.ResourceInstanceObjectSrc{
  8086  			Status:    states.ObjectReady,
  8087  			AttrsJSON: []byte(`{"id":"eip-bcd234","instance":"i-bcd234"}`),
  8088  			Dependencies: []addrs.ConfigResource{
  8089  				{
  8090  					Resource: addrs.Resource{
  8091  						Mode: addrs.ManagedResourceMode,
  8092  						Type: "aws_instance",
  8093  						Name: "foo",
  8094  					},
  8095  					Module: addrs.RootModule,
  8096  				},
  8097  			},
  8098  		},
  8099  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8100  	)
  8101  
  8102  	ctx := testContext2(t, &ContextOpts{
  8103  		Providers: map[addrs.Provider]providers.Factory{
  8104  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8105  		},
  8106  	})
  8107  
  8108  	plan, diags := ctx.Plan(m, state.DeepCopy(), DefaultPlanOpts)
  8109  	assertNoErrors(t, diags)
  8110  
  8111  	s, diags := ctx.Apply(plan, m)
  8112  	assertNoErrors(t, diags)
  8113  
  8114  	actual := strings.TrimSpace(s.String())
  8115  	expected := strings.TrimSpace(state.String())
  8116  	if actual != expected {
  8117  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
  8118  	}
  8119  }
  8120  
  8121  func TestContext2Apply_ignoreChangesAll(t *testing.T) {
  8122  	m := testModule(t, "apply-ignore-changes-all")
  8123  	p := testProvider("aws")
  8124  	p.PlanResourceChangeFn = testDiffFn
  8125  	p.ApplyResourceChangeFn = testApplyFn
  8126  
  8127  	instanceSchema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  8128  	instanceSchema.Attributes["required_field"] = &configschema.Attribute{
  8129  		Type:     cty.String,
  8130  		Required: true,
  8131  	}
  8132  
  8133  	ctx := testContext2(t, &ContextOpts{
  8134  		Providers: map[addrs.Provider]providers.Factory{
  8135  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8136  		},
  8137  	})
  8138  
  8139  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8140  	if diags.HasErrors() {
  8141  		logDiagnostics(t, diags)
  8142  		t.Fatal("plan failed")
  8143  	} else {
  8144  		t.Logf(legacyDiffComparisonString(plan.Changes))
  8145  	}
  8146  
  8147  	state, diags := ctx.Apply(plan, m)
  8148  	assertNoErrors(t, diags)
  8149  
  8150  	mod := state.RootModule()
  8151  	if len(mod.Resources) != 1 {
  8152  		t.Fatalf("bad: %s", state)
  8153  	}
  8154  
  8155  	actual := strings.TrimSpace(state.String())
  8156  	// Expect no changes from original state
  8157  	expected := strings.TrimSpace(`
  8158  aws_instance.foo:
  8159    ID = foo
  8160    provider = provider["registry.terraform.io/hashicorp/aws"]
  8161    required_field = set
  8162    type = aws_instance
  8163  `)
  8164  	if actual != expected {
  8165  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
  8166  	}
  8167  }
  8168  
  8169  // https://github.com/hashicorp/terraform/issues/7378
  8170  func TestContext2Apply_destroyNestedModuleWithAttrsReferencingResource(t *testing.T) {
  8171  	m, snap := testModuleWithSnapshot(t, "apply-destroy-nested-module-with-attrs")
  8172  	p := testProvider("null")
  8173  	p.PlanResourceChangeFn = testDiffFn
  8174  
  8175  	var state *states.State
  8176  	{
  8177  		ctx := testContext2(t, &ContextOpts{
  8178  			Providers: map[addrs.Provider]providers.Factory{
  8179  				addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8180  			},
  8181  		})
  8182  
  8183  		// First plan and apply a create operation
  8184  		plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8185  		assertNoErrors(t, diags)
  8186  
  8187  		state, diags = ctx.Apply(plan, m)
  8188  		if diags.HasErrors() {
  8189  			t.Fatalf("apply err: %s", diags.Err())
  8190  		}
  8191  	}
  8192  
  8193  	{
  8194  		ctx := testContext2(t, &ContextOpts{
  8195  			Providers: map[addrs.Provider]providers.Factory{
  8196  				addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8197  			},
  8198  		})
  8199  
  8200  		plan, diags := ctx.Plan(m, state, &PlanOpts{
  8201  			Mode: plans.DestroyMode,
  8202  		})
  8203  		if diags.HasErrors() {
  8204  			t.Fatalf("destroy plan err: %s", diags.Err())
  8205  		}
  8206  
  8207  		ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  8208  		if err != nil {
  8209  			t.Fatalf("failed to round-trip through planfile: %s", err)
  8210  		}
  8211  
  8212  		ctxOpts.Providers = map[addrs.Provider]providers.Factory{
  8213  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8214  		}
  8215  
  8216  		ctx, diags = NewContext(ctxOpts)
  8217  		if diags.HasErrors() {
  8218  			t.Fatalf("err: %s", diags.Err())
  8219  		}
  8220  
  8221  		state, diags = ctx.Apply(plan, m)
  8222  		if diags.HasErrors() {
  8223  			t.Fatalf("destroy apply err: %s", diags.Err())
  8224  		}
  8225  	}
  8226  
  8227  	if !state.Empty() {
  8228  		t.Fatalf("state after apply: %s\nwant empty state", spew.Sdump(state))
  8229  	}
  8230  }
  8231  
  8232  // If a data source explicitly depends on another resource, it's because we need
  8233  // that resource to be applied first.
  8234  func TestContext2Apply_dataDependsOn(t *testing.T) {
  8235  	p := testProvider("null")
  8236  	m := testModuleInline(t, map[string]string{
  8237  		"main.tf": `
  8238  resource "null_instance" "write" {
  8239    foo = "attribute"
  8240  }
  8241  
  8242  data "null_data_source" "read" {
  8243    count = 1
  8244    depends_on = ["null_instance.write"]
  8245  }
  8246  
  8247  resource "null_instance" "depends" {
  8248    foo = data.null_data_source.read[0].foo
  8249  }
  8250  `})
  8251  
  8252  	ctx := testContext2(t, &ContextOpts{
  8253  		Providers: map[addrs.Provider]providers.Factory{
  8254  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8255  		},
  8256  	})
  8257  
  8258  	// the "provisioner" here writes to this variable, because the intent is to
  8259  	// create a dependency which can't be viewed through the graph, and depends
  8260  	// solely on the configuration providing "depends_on"
  8261  	provisionerOutput := ""
  8262  
  8263  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  8264  		// the side effect of the resource being applied
  8265  		provisionerOutput = "APPLIED"
  8266  		return testApplyFn(req)
  8267  	}
  8268  
  8269  	p.PlanResourceChangeFn = testDiffFn
  8270  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  8271  		return providers.ReadDataSourceResponse{
  8272  			State: cty.ObjectVal(map[string]cty.Value{
  8273  				"id":  cty.StringVal("boop"),
  8274  				"foo": cty.StringVal(provisionerOutput),
  8275  			}),
  8276  		}
  8277  	}
  8278  
  8279  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8280  	assertNoErrors(t, diags)
  8281  
  8282  	state, diags := ctx.Apply(plan, m)
  8283  	assertNoErrors(t, diags)
  8284  
  8285  	root := state.Module(addrs.RootModuleInstance)
  8286  	is := root.ResourceInstance(addrs.Resource{
  8287  		Mode: addrs.DataResourceMode,
  8288  		Type: "null_data_source",
  8289  		Name: "read",
  8290  	}.Instance(addrs.IntKey(0)))
  8291  	if is == nil {
  8292  		t.Fatal("data resource instance is not present in state; should be")
  8293  	}
  8294  	var attrs map[string]interface{}
  8295  	err := json.Unmarshal(is.Current.AttrsJSON, &attrs)
  8296  	if err != nil {
  8297  		t.Fatal(err)
  8298  	}
  8299  	actual := attrs["foo"]
  8300  	expected := "APPLIED"
  8301  	if actual != expected {
  8302  		t.Fatalf("bad:\n%s", strings.TrimSpace(state.String()))
  8303  	}
  8304  
  8305  	// run another plan to make sure the data source doesn't show as a change
  8306  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  8307  	assertNoErrors(t, diags)
  8308  
  8309  	for _, c := range plan.Changes.Resources {
  8310  		if c.Action != plans.NoOp {
  8311  			t.Fatalf("unexpected change for %s", c.Addr)
  8312  		}
  8313  	}
  8314  
  8315  	// now we cause a change in the first resource, which should trigger a plan
  8316  	// in the data source, and the resource that depends on the data source
  8317  	// must plan a change as well.
  8318  	m = testModuleInline(t, map[string]string{
  8319  		"main.tf": `
  8320  resource "null_instance" "write" {
  8321    foo = "new"
  8322  }
  8323  
  8324  data "null_data_source" "read" {
  8325    depends_on = ["null_instance.write"]
  8326  }
  8327  
  8328  resource "null_instance" "depends" {
  8329    foo = data.null_data_source.read.foo
  8330  }
  8331  `})
  8332  
  8333  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  8334  		// the side effect of the resource being applied
  8335  		provisionerOutput = "APPLIED_AGAIN"
  8336  		return testApplyFn(req)
  8337  	}
  8338  
  8339  	ctx = testContext2(t, &ContextOpts{
  8340  		Providers: map[addrs.Provider]providers.Factory{
  8341  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  8342  		},
  8343  	})
  8344  
  8345  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
  8346  	assertNoErrors(t, diags)
  8347  
  8348  	expectedChanges := map[string]plans.Action{
  8349  		"null_instance.write":        plans.Update,
  8350  		"data.null_data_source.read": plans.Read,
  8351  		"null_instance.depends":      plans.Update,
  8352  	}
  8353  
  8354  	for _, c := range plan.Changes.Resources {
  8355  		if c.Action != expectedChanges[c.Addr.String()] {
  8356  			t.Errorf("unexpected %s for %s", c.Action, c.Addr)
  8357  		}
  8358  	}
  8359  }
  8360  
  8361  func TestContext2Apply_terraformWorkspace(t *testing.T) {
  8362  	m := testModule(t, "apply-terraform-workspace")
  8363  	p := testProvider("aws")
  8364  	p.PlanResourceChangeFn = testDiffFn
  8365  
  8366  	ctx := testContext2(t, &ContextOpts{
  8367  		Meta: &ContextMeta{Env: "foo"},
  8368  		Providers: map[addrs.Provider]providers.Factory{
  8369  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8370  		},
  8371  	})
  8372  
  8373  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8374  	assertNoErrors(t, diags)
  8375  
  8376  	state, diags := ctx.Apply(plan, m)
  8377  	if diags.HasErrors() {
  8378  		t.Fatalf("diags: %s", diags.Err())
  8379  	}
  8380  
  8381  	actual := state.RootModule().OutputValues["output"]
  8382  	expected := cty.StringVal("foo")
  8383  	if actual == nil || actual.Value != expected {
  8384  		t.Fatalf("wrong value\ngot:  %#v\nwant: %#v", actual.Value, expected)
  8385  	}
  8386  }
  8387  
  8388  // verify that multiple config references only create a single depends_on entry
  8389  func TestContext2Apply_multiRef(t *testing.T) {
  8390  	m := testModule(t, "apply-multi-ref")
  8391  	p := testProvider("aws")
  8392  	p.PlanResourceChangeFn = testDiffFn
  8393  	ctx := testContext2(t, &ContextOpts{
  8394  		Providers: map[addrs.Provider]providers.Factory{
  8395  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8396  		},
  8397  	})
  8398  
  8399  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8400  	assertNoErrors(t, diags)
  8401  
  8402  	state, diags := ctx.Apply(plan, m)
  8403  	if diags.HasErrors() {
  8404  		t.Fatalf("err: %s", diags.Err())
  8405  	}
  8406  
  8407  	deps := state.Modules[""].Resources["aws_instance.other"].Instances[addrs.NoKey].Current.Dependencies
  8408  	if len(deps) != 1 || deps[0].String() != "aws_instance.create" {
  8409  		t.Fatalf("expected 1 depends_on entry for aws_instance.create, got %q", deps)
  8410  	}
  8411  }
  8412  
  8413  func TestContext2Apply_targetedModuleRecursive(t *testing.T) {
  8414  	m := testModule(t, "apply-targeted-module-recursive")
  8415  	p := testProvider("aws")
  8416  	p.PlanResourceChangeFn = testDiffFn
  8417  	p.ApplyResourceChangeFn = testApplyFn
  8418  	ctx := testContext2(t, &ContextOpts{
  8419  		Providers: map[addrs.Provider]providers.Factory{
  8420  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8421  		},
  8422  	})
  8423  
  8424  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  8425  		Mode: plans.NormalMode,
  8426  		Targets: []addrs.Targetable{
  8427  			addrs.RootModuleInstance.Child("child", addrs.NoKey),
  8428  		},
  8429  	})
  8430  	assertNoErrors(t, diags)
  8431  
  8432  	state, diags := ctx.Apply(plan, m)
  8433  	if diags.HasErrors() {
  8434  		t.Fatalf("err: %s", diags.Err())
  8435  	}
  8436  
  8437  	mod := state.Module(
  8438  		addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("subchild", addrs.NoKey),
  8439  	)
  8440  	if mod == nil {
  8441  		t.Fatalf("no subchild module found in the state!\n\n%#v", state)
  8442  	}
  8443  	if len(mod.Resources) != 1 {
  8444  		t.Fatalf("expected 1 resources, got: %#v", mod.Resources)
  8445  	}
  8446  
  8447  	checkStateString(t, state, `
  8448  <no state>
  8449  module.child.subchild:
  8450    aws_instance.foo:
  8451      ID = foo
  8452      provider = provider["registry.terraform.io/hashicorp/aws"]
  8453      num = 2
  8454      type = aws_instance
  8455  	`)
  8456  }
  8457  
  8458  func TestContext2Apply_localVal(t *testing.T) {
  8459  	m := testModule(t, "apply-local-val")
  8460  	ctx := testContext2(t, &ContextOpts{
  8461  		Providers: map[addrs.Provider]providers.Factory{},
  8462  	})
  8463  
  8464  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8465  	assertNoErrors(t, diags)
  8466  
  8467  	state, diags := ctx.Apply(plan, m)
  8468  	if diags.HasErrors() {
  8469  		t.Fatalf("error during apply: %s", diags.Err())
  8470  	}
  8471  
  8472  	got := strings.TrimSpace(state.String())
  8473  	want := strings.TrimSpace(`
  8474  <no state>
  8475  Outputs:
  8476  
  8477  result_1 = hello
  8478  result_3 = hello world
  8479  `)
  8480  	if got != want {
  8481  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8482  	}
  8483  }
  8484  
  8485  func TestContext2Apply_destroyWithLocals(t *testing.T) {
  8486  	m := testModule(t, "apply-destroy-with-locals")
  8487  	p := testProvider("aws")
  8488  	p.PlanResourceChangeFn = testDiffFn
  8489  
  8490  	state := states.NewState()
  8491  	root := state.EnsureModule(addrs.RootModuleInstance)
  8492  	root.SetResourceInstanceCurrent(
  8493  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  8494  		&states.ResourceInstanceObjectSrc{
  8495  			Status:    states.ObjectReady,
  8496  			AttrsJSON: []byte(`{"id":"foo"}`),
  8497  		},
  8498  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8499  	)
  8500  	root.SetOutputValue("name", cty.StringVal("test-bar"), false)
  8501  
  8502  	ctx := testContext2(t, &ContextOpts{
  8503  		Providers: map[addrs.Provider]providers.Factory{
  8504  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8505  		},
  8506  	})
  8507  
  8508  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8509  		Mode: plans.DestroyMode,
  8510  	})
  8511  	assertNoErrors(t, diags)
  8512  
  8513  	s, diags := ctx.Apply(plan, m)
  8514  	if diags.HasErrors() {
  8515  		t.Fatalf("error during apply: %s", diags.Err())
  8516  	}
  8517  
  8518  	got := strings.TrimSpace(s.String())
  8519  	want := strings.TrimSpace(`<no state>`)
  8520  	if got != want {
  8521  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8522  	}
  8523  }
  8524  
  8525  func TestContext2Apply_providerWithLocals(t *testing.T) {
  8526  	m := testModule(t, "provider-with-locals")
  8527  	p := testProvider("aws")
  8528  
  8529  	providerRegion := ""
  8530  	// this should not be overridden during destroy
  8531  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  8532  		val := req.Config.GetAttr("region")
  8533  		if !val.IsNull() {
  8534  			providerRegion = val.AsString()
  8535  		}
  8536  
  8537  		return
  8538  	}
  8539  
  8540  	p.PlanResourceChangeFn = testDiffFn
  8541  	ctx := testContext2(t, &ContextOpts{
  8542  		Providers: map[addrs.Provider]providers.Factory{
  8543  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8544  		},
  8545  	})
  8546  
  8547  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8548  	assertNoErrors(t, diags)
  8549  
  8550  	state, diags := ctx.Apply(plan, m)
  8551  	if diags.HasErrors() {
  8552  		t.Fatalf("err: %s", diags.Err())
  8553  	}
  8554  
  8555  	ctx = testContext2(t, &ContextOpts{
  8556  		Providers: map[addrs.Provider]providers.Factory{
  8557  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8558  		},
  8559  	})
  8560  
  8561  	plan, diags = ctx.Plan(m, state, &PlanOpts{
  8562  		Mode: plans.DestroyMode,
  8563  	})
  8564  	assertNoErrors(t, diags)
  8565  
  8566  	state, diags = ctx.Apply(plan, m)
  8567  	if diags.HasErrors() {
  8568  		t.Fatalf("err: %s", diags.Err())
  8569  	}
  8570  
  8571  	if state.HasResources() {
  8572  		t.Fatal("expected no state, got:", state)
  8573  	}
  8574  
  8575  	if providerRegion != "bar" {
  8576  		t.Fatalf("expected region %q, got: %q", "bar", providerRegion)
  8577  	}
  8578  }
  8579  
  8580  func TestContext2Apply_destroyWithProviders(t *testing.T) {
  8581  	m := testModule(t, "destroy-module-with-provider")
  8582  	p := testProvider("aws")
  8583  	p.PlanResourceChangeFn = testDiffFn
  8584  
  8585  	state := states.NewState()
  8586  	removed := state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.NoKey).Child("removed", addrs.NoKey))
  8587  	removed.SetResourceInstanceCurrent(
  8588  		mustResourceInstanceAddr("aws_instance.child").Resource,
  8589  		&states.ResourceInstanceObjectSrc{
  8590  			Status:    states.ObjectReady,
  8591  			AttrsJSON: []byte(`{"id":"bar"}`),
  8592  		},
  8593  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].baz`),
  8594  	)
  8595  
  8596  	ctx := testContext2(t, &ContextOpts{
  8597  		Providers: map[addrs.Provider]providers.Factory{
  8598  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8599  		},
  8600  	})
  8601  
  8602  	// test that we can't destroy if the provider is missing
  8603  	if _, diags := ctx.Plan(m, state, &PlanOpts{Mode: plans.DestroyMode}); diags == nil {
  8604  		t.Fatal("expected plan error, provider.aws.baz doesn't exist")
  8605  	}
  8606  
  8607  	// correct the state
  8608  	state.Modules["module.mod.module.removed"].Resources["aws_instance.child"].ProviderConfig = mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].bar`)
  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  	state, diags = ctx.Apply(plan, m)
  8622  	if diags.HasErrors() {
  8623  		t.Fatalf("error during apply: %s", diags.Err())
  8624  	}
  8625  
  8626  	got := strings.TrimSpace(state.String())
  8627  
  8628  	want := strings.TrimSpace("<no state>")
  8629  	if got != want {
  8630  		t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
  8631  	}
  8632  }
  8633  
  8634  func TestContext2Apply_providersFromState(t *testing.T) {
  8635  	m := configs.NewEmptyConfig()
  8636  	p := testProvider("aws")
  8637  	p.PlanResourceChangeFn = testDiffFn
  8638  
  8639  	implicitProviderState := states.NewState()
  8640  	impRoot := implicitProviderState.EnsureModule(addrs.RootModuleInstance)
  8641  	impRoot.SetResourceInstanceCurrent(
  8642  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8643  		&states.ResourceInstanceObjectSrc{
  8644  			Status:    states.ObjectReady,
  8645  			AttrsJSON: []byte(`{"id":"bar"}`),
  8646  		},
  8647  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8648  	)
  8649  
  8650  	aliasedProviderState := states.NewState()
  8651  	aliasRoot := aliasedProviderState.EnsureModule(addrs.RootModuleInstance)
  8652  	aliasRoot.SetResourceInstanceCurrent(
  8653  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8654  		&states.ResourceInstanceObjectSrc{
  8655  			Status:    states.ObjectReady,
  8656  			AttrsJSON: []byte(`{"id":"bar"}`),
  8657  		},
  8658  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"].bar`),
  8659  	)
  8660  
  8661  	moduleProviderState := states.NewState()
  8662  	moduleProviderRoot := moduleProviderState.EnsureModule(addrs.RootModuleInstance)
  8663  	moduleProviderRoot.SetResourceInstanceCurrent(
  8664  		mustResourceInstanceAddr("aws_instance.a").Resource,
  8665  		&states.ResourceInstanceObjectSrc{
  8666  			Status:    states.ObjectReady,
  8667  			AttrsJSON: []byte(`{"id":"bar"}`),
  8668  		},
  8669  		mustProviderConfig(`module.child.provider["registry.terraform.io/hashicorp/aws"]`),
  8670  	)
  8671  
  8672  	for _, tc := range []struct {
  8673  		name   string
  8674  		state  *states.State
  8675  		output string
  8676  		err    bool
  8677  	}{
  8678  		{
  8679  			name:   "add implicit provider",
  8680  			state:  implicitProviderState,
  8681  			err:    false,
  8682  			output: "<no state>",
  8683  		},
  8684  
  8685  		// an aliased provider must be in the config to remove a resource
  8686  		{
  8687  			name:  "add aliased provider",
  8688  			state: aliasedProviderState,
  8689  			err:   true,
  8690  		},
  8691  
  8692  		// a provider in a module implies some sort of config, so this isn't
  8693  		// allowed even without an alias
  8694  		{
  8695  			name:  "add unaliased module provider",
  8696  			state: moduleProviderState,
  8697  			err:   true,
  8698  		},
  8699  	} {
  8700  		t.Run(tc.name, func(t *testing.T) {
  8701  			ctx := testContext2(t, &ContextOpts{
  8702  				Providers: map[addrs.Provider]providers.Factory{
  8703  					addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8704  				},
  8705  			})
  8706  
  8707  			plan, diags := ctx.Plan(m, tc.state, DefaultPlanOpts)
  8708  			if tc.err {
  8709  				if diags == nil {
  8710  					t.Fatal("expected error")
  8711  				} else {
  8712  					return
  8713  				}
  8714  			}
  8715  			if !tc.err && diags.HasErrors() {
  8716  				t.Fatal(diags.Err())
  8717  			}
  8718  
  8719  			state, diags := ctx.Apply(plan, m)
  8720  			if diags.HasErrors() {
  8721  				t.Fatalf("diags: %s", diags.Err())
  8722  			}
  8723  
  8724  			checkStateString(t, state, "<no state>")
  8725  
  8726  		})
  8727  	}
  8728  }
  8729  
  8730  func TestContext2Apply_plannedInterpolatedCount(t *testing.T) {
  8731  	m, snap := testModuleWithSnapshot(t, "apply-interpolated-count")
  8732  
  8733  	p := testProvider("aws")
  8734  	p.PlanResourceChangeFn = testDiffFn
  8735  
  8736  	Providers := map[addrs.Provider]providers.Factory{
  8737  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8738  	}
  8739  
  8740  	state := states.NewState()
  8741  	root := state.EnsureModule(addrs.RootModuleInstance)
  8742  	root.SetResourceInstanceCurrent(
  8743  		mustResourceInstanceAddr("aws_instance.test").Resource,
  8744  		&states.ResourceInstanceObjectSrc{
  8745  			Status:    states.ObjectReady,
  8746  			AttrsJSON: []byte(`{"id":"foo"}`),
  8747  		},
  8748  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8749  	)
  8750  
  8751  	ctx := testContext2(t, &ContextOpts{
  8752  		Providers: Providers,
  8753  	})
  8754  
  8755  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  8756  	if diags.HasErrors() {
  8757  		t.Fatalf("plan failed: %s", diags.Err())
  8758  	}
  8759  
  8760  	// We'll marshal and unmarshal the plan here, to ensure that we have
  8761  	// a clean new context as would be created if we separately ran
  8762  	// terraform plan -out=tfplan && terraform apply tfplan
  8763  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  8764  	if err != nil {
  8765  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8766  	}
  8767  
  8768  	ctxOpts.Providers = Providers
  8769  	ctx, diags = NewContext(ctxOpts)
  8770  	if diags.HasErrors() {
  8771  		t.Fatalf("err: %s", diags.Err())
  8772  	}
  8773  
  8774  	// Applying the plan should now succeed
  8775  	_, diags = ctx.Apply(plan, m)
  8776  	if diags.HasErrors() {
  8777  		t.Fatalf("apply failed: %s", diags.Err())
  8778  	}
  8779  }
  8780  
  8781  func TestContext2Apply_plannedDestroyInterpolatedCount(t *testing.T) {
  8782  	m, snap := testModuleWithSnapshot(t, "plan-destroy-interpolated-count")
  8783  
  8784  	p := testProvider("aws")
  8785  	p.PlanResourceChangeFn = testDiffFn
  8786  	providers := map[addrs.Provider]providers.Factory{
  8787  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8788  	}
  8789  
  8790  	state := states.NewState()
  8791  	root := state.EnsureModule(addrs.RootModuleInstance)
  8792  	root.SetResourceInstanceCurrent(
  8793  		mustResourceInstanceAddr("aws_instance.a[0]").Resource,
  8794  		&states.ResourceInstanceObjectSrc{
  8795  			Status:    states.ObjectReady,
  8796  			AttrsJSON: []byte(`{"id":"foo"}`),
  8797  		},
  8798  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8799  	)
  8800  	root.SetResourceInstanceCurrent(
  8801  		mustResourceInstanceAddr("aws_instance.a[1]").Resource,
  8802  		&states.ResourceInstanceObjectSrc{
  8803  			Status:    states.ObjectReady,
  8804  			AttrsJSON: []byte(`{"id":"foo"}`),
  8805  		},
  8806  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8807  	)
  8808  	root.SetOutputValue("out", cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("foo")}), false)
  8809  
  8810  	ctx := testContext2(t, &ContextOpts{
  8811  		Providers: providers,
  8812  	})
  8813  
  8814  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8815  		Mode: plans.DestroyMode,
  8816  	})
  8817  	if diags.HasErrors() {
  8818  		t.Fatalf("plan failed: %s", diags.Err())
  8819  	}
  8820  
  8821  	// We'll marshal and unmarshal the plan here, to ensure that we have
  8822  	// a clean new context as would be created if we separately ran
  8823  	// terraform plan -out=tfplan && terraform apply tfplan
  8824  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  8825  	if err != nil {
  8826  		t.Fatalf("failed to round-trip through planfile: %s", err)
  8827  	}
  8828  
  8829  	ctxOpts.Providers = providers
  8830  	ctx, diags = NewContext(ctxOpts)
  8831  	if diags.HasErrors() {
  8832  		t.Fatalf("err: %s", diags.Err())
  8833  	}
  8834  
  8835  	// Applying the plan should now succeed
  8836  	state, diags = ctx.Apply(plan, m)
  8837  	if diags.HasErrors() {
  8838  		t.Fatalf("apply failed: %s", diags.Err())
  8839  	}
  8840  	if !state.Empty() {
  8841  		t.Fatalf("state not empty: %s\n", state)
  8842  	}
  8843  }
  8844  
  8845  func TestContext2Apply_scaleInMultivarRef(t *testing.T) {
  8846  	m := testModule(t, "apply-resource-scale-in")
  8847  
  8848  	p := testProvider("aws")
  8849  	p.PlanResourceChangeFn = testDiffFn
  8850  
  8851  	Providers := map[addrs.Provider]providers.Factory{
  8852  		addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  8853  	}
  8854  
  8855  	state := states.NewState()
  8856  	root := state.EnsureModule(addrs.RootModuleInstance)
  8857  	root.SetResourceInstanceCurrent(
  8858  		mustResourceInstanceAddr("aws_instance.one").Resource,
  8859  		&states.ResourceInstanceObjectSrc{
  8860  			Status:    states.ObjectReady,
  8861  			AttrsJSON: []byte(`{"id":"foo"}`),
  8862  		},
  8863  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8864  	)
  8865  	root.SetResourceInstanceCurrent(
  8866  		mustResourceInstanceAddr("aws_instance.two").Resource,
  8867  		&states.ResourceInstanceObjectSrc{
  8868  			Status:    states.ObjectReady,
  8869  			AttrsJSON: []byte(`{"id":"foo"}`),
  8870  		},
  8871  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  8872  	)
  8873  
  8874  	ctx := testContext2(t, &ContextOpts{
  8875  		Providers: Providers,
  8876  	})
  8877  
  8878  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  8879  		Mode: plans.NormalMode,
  8880  		SetVariables: InputValues{
  8881  			"instance_count": {
  8882  				Value:      cty.NumberIntVal(0),
  8883  				SourceType: ValueFromCaller,
  8884  			},
  8885  		},
  8886  	})
  8887  	assertNoErrors(t, diags)
  8888  
  8889  	// Applying the plan should now succeed
  8890  	_, diags = ctx.Apply(plan, m)
  8891  	assertNoErrors(t, diags)
  8892  }
  8893  
  8894  func TestContext2Apply_inconsistentWithPlan(t *testing.T) {
  8895  	m := testModule(t, "apply-inconsistent-with-plan")
  8896  	p := testProvider("test")
  8897  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  8898  		ResourceTypes: map[string]*configschema.Block{
  8899  			"test": {
  8900  				Attributes: map[string]*configschema.Attribute{
  8901  					"id": {Type: cty.String, Computed: true},
  8902  				},
  8903  			},
  8904  		},
  8905  	})
  8906  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  8907  		return providers.PlanResourceChangeResponse{
  8908  			PlannedState: cty.ObjectVal(map[string]cty.Value{
  8909  				"id": cty.StringVal("before"),
  8910  			}),
  8911  		}
  8912  	}
  8913  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  8914  		return providers.ApplyResourceChangeResponse{
  8915  			NewState: cty.ObjectVal(map[string]cty.Value{
  8916  				// This is intentionally incorrect: because id was fixed at "before"
  8917  				// during plan, it must not change during apply.
  8918  				"id": cty.StringVal("after"),
  8919  			}),
  8920  		}
  8921  	}
  8922  	ctx := testContext2(t, &ContextOpts{
  8923  		Providers: map[addrs.Provider]providers.Factory{
  8924  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  8925  		},
  8926  	})
  8927  
  8928  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  8929  	assertNoErrors(t, diags)
  8930  
  8931  	_, diags = ctx.Apply(plan, m)
  8932  	if !diags.HasErrors() {
  8933  		t.Fatalf("apply succeeded; want error")
  8934  	}
  8935  	if got, want := diags.Err().Error(), "Provider produced inconsistent result after apply"; !strings.Contains(got, want) {
  8936  		t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want)
  8937  	}
  8938  }
  8939  
  8940  // Issue 19908 was about retaining an existing object in the state when an
  8941  // update to it fails and the provider does not return a partially-updated
  8942  // value for it. Previously we were incorrectly removing it from the state
  8943  // in that case, but instead it should be retained so the update can be
  8944  // retried.
  8945  func TestContext2Apply_issue19908(t *testing.T) {
  8946  	m := testModule(t, "apply-issue19908")
  8947  	p := testProvider("test")
  8948  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  8949  		ResourceTypes: map[string]*configschema.Block{
  8950  			"test": {
  8951  				Attributes: map[string]*configschema.Attribute{
  8952  					"baz": {Type: cty.String, Required: true},
  8953  				},
  8954  			},
  8955  		},
  8956  	})
  8957  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  8958  		return providers.PlanResourceChangeResponse{
  8959  			PlannedState: req.ProposedNewState,
  8960  		}
  8961  	}
  8962  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  8963  		var diags tfdiags.Diagnostics
  8964  		diags = diags.Append(fmt.Errorf("update failed"))
  8965  		return providers.ApplyResourceChangeResponse{
  8966  			Diagnostics: diags,
  8967  		}
  8968  	}
  8969  	ctx := testContext2(t, &ContextOpts{
  8970  		Providers: map[addrs.Provider]providers.Factory{
  8971  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  8972  		},
  8973  	})
  8974  
  8975  	state := states.BuildState(func(s *states.SyncState) {
  8976  		s.SetResourceInstanceCurrent(
  8977  			addrs.Resource{
  8978  				Mode: addrs.ManagedResourceMode,
  8979  				Type: "test",
  8980  				Name: "foo",
  8981  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  8982  			&states.ResourceInstanceObjectSrc{
  8983  				AttrsJSON: []byte(`{"baz":"old"}`),
  8984  				Status:    states.ObjectReady,
  8985  			},
  8986  			addrs.AbsProviderConfig{
  8987  				Provider: addrs.NewDefaultProvider("test"),
  8988  				Module:   addrs.RootModule,
  8989  			},
  8990  		)
  8991  	})
  8992  
  8993  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  8994  	assertNoErrors(t, diags)
  8995  
  8996  	state, diags = ctx.Apply(plan, m)
  8997  	if !diags.HasErrors() {
  8998  		t.Fatalf("apply succeeded; want error")
  8999  	}
  9000  	if got, want := diags.Err().Error(), "update failed"; !strings.Contains(got, want) {
  9001  		t.Fatalf("wrong error\ngot: %s\nshould contain: %s", got, want)
  9002  	}
  9003  
  9004  	mod := state.RootModule()
  9005  	rs := mod.Resources["test.foo"]
  9006  	if rs == nil {
  9007  		t.Fatalf("test.foo not in state after apply, but should be")
  9008  	}
  9009  	is := rs.Instances[addrs.NoKey]
  9010  	if is == nil {
  9011  		t.Fatalf("test.foo not in state after apply, but should be")
  9012  	}
  9013  	obj := is.Current
  9014  	if obj == nil {
  9015  		t.Fatalf("test.foo has no current object in state after apply, but should do")
  9016  	}
  9017  
  9018  	if got, want := obj.Status, states.ObjectReady; got != want {
  9019  		t.Errorf("test.foo has wrong status %s after apply; want %s", got, want)
  9020  	}
  9021  	if got, want := obj.AttrsJSON, []byte(`"old"`); !bytes.Contains(got, want) {
  9022  		t.Errorf("test.foo attributes JSON doesn't contain %s after apply\ngot: %s", want, got)
  9023  	}
  9024  }
  9025  
  9026  func TestContext2Apply_invalidIndexRef(t *testing.T) {
  9027  	p := testProvider("test")
  9028  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9029  		ResourceTypes: map[string]*configschema.Block{
  9030  			"test_instance": {
  9031  				Attributes: map[string]*configschema.Attribute{
  9032  					"value": {Type: cty.String, Optional: true, Computed: true},
  9033  				},
  9034  			},
  9035  		},
  9036  	})
  9037  	p.PlanResourceChangeFn = testDiffFn
  9038  
  9039  	m := testModule(t, "apply-invalid-index")
  9040  	c := testContext2(t, &ContextOpts{
  9041  		Providers: map[addrs.Provider]providers.Factory{
  9042  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9043  		},
  9044  	})
  9045  	diags := c.Validate(m)
  9046  	if diags.HasErrors() {
  9047  		t.Fatalf("unexpected validation failure: %s", diags.Err())
  9048  	}
  9049  
  9050  	wantErr := `The given key does not identify an element in this collection value`
  9051  	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
  9052  
  9053  	if !diags.HasErrors() {
  9054  		t.Fatalf("plan succeeded; want error")
  9055  	}
  9056  	gotErr := diags.Err().Error()
  9057  
  9058  	if !strings.Contains(gotErr, wantErr) {
  9059  		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErr, wantErr)
  9060  	}
  9061  }
  9062  
  9063  func TestContext2Apply_moduleReplaceCycle(t *testing.T) {
  9064  	for _, mode := range []string{"normal", "cbd"} {
  9065  		var m *configs.Config
  9066  
  9067  		switch mode {
  9068  		case "normal":
  9069  			m = testModule(t, "apply-module-replace-cycle")
  9070  		case "cbd":
  9071  			m = testModule(t, "apply-module-replace-cycle-cbd")
  9072  		}
  9073  
  9074  		p := testProvider("aws")
  9075  		p.PlanResourceChangeFn = testDiffFn
  9076  
  9077  		instanceSchema := &configschema.Block{
  9078  			Attributes: map[string]*configschema.Attribute{
  9079  				"id":          {Type: cty.String, Computed: true},
  9080  				"require_new": {Type: cty.String, Optional: true},
  9081  			},
  9082  		}
  9083  
  9084  		p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9085  			ResourceTypes: map[string]*configschema.Block{
  9086  				"aws_instance": instanceSchema,
  9087  			},
  9088  		})
  9089  
  9090  		state := states.NewState()
  9091  		modA := state.EnsureModule(addrs.RootModuleInstance.Child("a", addrs.NoKey))
  9092  		modA.SetResourceInstanceCurrent(
  9093  			addrs.Resource{
  9094  				Mode: addrs.ManagedResourceMode,
  9095  				Type: "aws_instance",
  9096  				Name: "a",
  9097  			}.Instance(addrs.NoKey),
  9098  			&states.ResourceInstanceObjectSrc{
  9099  				Status:              states.ObjectReady,
  9100  				AttrsJSON:           []byte(`{"id":"a","require_new":"old"}`),
  9101  				CreateBeforeDestroy: mode == "cbd",
  9102  			},
  9103  			addrs.AbsProviderConfig{
  9104  				Provider: addrs.NewDefaultProvider("aws"),
  9105  				Module:   addrs.RootModule,
  9106  			},
  9107  		)
  9108  
  9109  		modB := state.EnsureModule(addrs.RootModuleInstance.Child("b", addrs.NoKey))
  9110  		modB.SetResourceInstanceCurrent(
  9111  			addrs.Resource{
  9112  				Mode: addrs.ManagedResourceMode,
  9113  				Type: "aws_instance",
  9114  				Name: "b",
  9115  			}.Instance(addrs.IntKey(0)),
  9116  			&states.ResourceInstanceObjectSrc{
  9117  				Status:    states.ObjectReady,
  9118  				AttrsJSON: []byte(`{"id":"b","require_new":"old"}`),
  9119  			},
  9120  			addrs.AbsProviderConfig{
  9121  				Provider: addrs.NewDefaultProvider("aws"),
  9122  				Module:   addrs.RootModule,
  9123  			},
  9124  		)
  9125  
  9126  		aBefore, _ := plans.NewDynamicValue(
  9127  			cty.ObjectVal(map[string]cty.Value{
  9128  				"id":          cty.StringVal("a"),
  9129  				"require_new": cty.StringVal("old"),
  9130  			}), instanceSchema.ImpliedType())
  9131  		aAfter, _ := plans.NewDynamicValue(
  9132  			cty.ObjectVal(map[string]cty.Value{
  9133  				"id":          cty.UnknownVal(cty.String),
  9134  				"require_new": cty.StringVal("new"),
  9135  			}), instanceSchema.ImpliedType())
  9136  		bBefore, _ := plans.NewDynamicValue(
  9137  			cty.ObjectVal(map[string]cty.Value{
  9138  				"id":          cty.StringVal("b"),
  9139  				"require_new": cty.StringVal("old"),
  9140  			}), instanceSchema.ImpliedType())
  9141  		bAfter, _ := plans.NewDynamicValue(
  9142  			cty.ObjectVal(map[string]cty.Value{
  9143  				"id":          cty.UnknownVal(cty.String),
  9144  				"require_new": cty.UnknownVal(cty.String),
  9145  			}), instanceSchema.ImpliedType())
  9146  
  9147  		var aAction plans.Action
  9148  		switch mode {
  9149  		case "normal":
  9150  			aAction = plans.DeleteThenCreate
  9151  		case "cbd":
  9152  			aAction = plans.CreateThenDelete
  9153  		}
  9154  
  9155  		ctx := testContext2(t, &ContextOpts{
  9156  			Providers: map[addrs.Provider]providers.Factory{
  9157  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  9158  			},
  9159  		})
  9160  
  9161  		changes := &plans.Changes{
  9162  			Resources: []*plans.ResourceInstanceChangeSrc{
  9163  				{
  9164  					Addr: addrs.Resource{
  9165  						Mode: addrs.ManagedResourceMode,
  9166  						Type: "aws_instance",
  9167  						Name: "a",
  9168  					}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("a", addrs.NoKey)),
  9169  					ProviderAddr: addrs.AbsProviderConfig{
  9170  						Provider: addrs.NewDefaultProvider("aws"),
  9171  						Module:   addrs.RootModule,
  9172  					},
  9173  					ChangeSrc: plans.ChangeSrc{
  9174  						Action: aAction,
  9175  						Before: aBefore,
  9176  						After:  aAfter,
  9177  					},
  9178  				},
  9179  				{
  9180  					Addr: addrs.Resource{
  9181  						Mode: addrs.ManagedResourceMode,
  9182  						Type: "aws_instance",
  9183  						Name: "b",
  9184  					}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("b", addrs.NoKey)),
  9185  					ProviderAddr: addrs.AbsProviderConfig{
  9186  						Provider: addrs.NewDefaultProvider("aws"),
  9187  						Module:   addrs.RootModule,
  9188  					},
  9189  					ChangeSrc: plans.ChangeSrc{
  9190  						Action: plans.DeleteThenCreate,
  9191  						Before: bBefore,
  9192  						After:  bAfter,
  9193  					},
  9194  				},
  9195  			},
  9196  		}
  9197  
  9198  		plan := &plans.Plan{
  9199  			UIMode:       plans.NormalMode,
  9200  			Changes:      changes,
  9201  			PriorState:   state.DeepCopy(),
  9202  			PrevRunState: state.DeepCopy(),
  9203  		}
  9204  
  9205  		t.Run(mode, func(t *testing.T) {
  9206  			_, diags := ctx.Apply(plan, m)
  9207  			if diags.HasErrors() {
  9208  				t.Fatal(diags.Err())
  9209  			}
  9210  		})
  9211  	}
  9212  }
  9213  
  9214  func TestContext2Apply_destroyDataCycle(t *testing.T) {
  9215  	m, snap := testModuleWithSnapshot(t, "apply-destroy-data-cycle")
  9216  	p := testProvider("null")
  9217  	p.PlanResourceChangeFn = testDiffFn
  9218  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  9219  		return providers.ReadDataSourceResponse{
  9220  			State: cty.ObjectVal(map[string]cty.Value{
  9221  				"id":  cty.StringVal("new"),
  9222  				"foo": cty.NullVal(cty.String),
  9223  			}),
  9224  		}
  9225  	}
  9226  
  9227  	tp := testProvider("test")
  9228  	tp.PlanResourceChangeFn = testDiffFn
  9229  
  9230  	state := states.NewState()
  9231  	root := state.EnsureModule(addrs.RootModuleInstance)
  9232  	root.SetResourceInstanceCurrent(
  9233  		addrs.Resource{
  9234  			Mode: addrs.ManagedResourceMode,
  9235  			Type: "null_resource",
  9236  			Name: "a",
  9237  		}.Instance(addrs.IntKey(0)),
  9238  		&states.ResourceInstanceObjectSrc{
  9239  			Status:    states.ObjectReady,
  9240  			AttrsJSON: []byte(`{"id":"a"}`),
  9241  		},
  9242  		addrs.AbsProviderConfig{
  9243  			Provider: addrs.NewDefaultProvider("null"),
  9244  			Module:   addrs.RootModule,
  9245  		},
  9246  	)
  9247  	root.SetResourceInstanceCurrent(
  9248  		addrs.Resource{
  9249  			Mode: addrs.ManagedResourceMode,
  9250  			Type: "test_resource",
  9251  			Name: "a",
  9252  		}.Instance(addrs.IntKey(0)),
  9253  		&states.ResourceInstanceObjectSrc{
  9254  			Status:    states.ObjectReady,
  9255  			AttrsJSON: []byte(`{"id":"a"}`),
  9256  			Dependencies: []addrs.ConfigResource{
  9257  				{
  9258  					Resource: addrs.Resource{
  9259  						Mode: addrs.DataResourceMode,
  9260  						Type: "null_data_source",
  9261  						Name: "d",
  9262  					},
  9263  					Module: addrs.RootModule,
  9264  				},
  9265  			},
  9266  		},
  9267  		addrs.AbsProviderConfig{
  9268  			Provider: addrs.NewDefaultProvider("test"),
  9269  			Module:   addrs.RootModule,
  9270  		},
  9271  	)
  9272  	root.SetResourceInstanceCurrent(
  9273  		addrs.Resource{
  9274  			Mode: addrs.DataResourceMode,
  9275  			Type: "null_data_source",
  9276  			Name: "d",
  9277  		}.Instance(addrs.NoKey),
  9278  		&states.ResourceInstanceObjectSrc{
  9279  			Status:    states.ObjectReady,
  9280  			AttrsJSON: []byte(`{"id":"old"}`),
  9281  		},
  9282  		addrs.AbsProviderConfig{
  9283  			Provider: addrs.NewDefaultProvider("null"),
  9284  			Module:   addrs.RootModule,
  9285  		},
  9286  	)
  9287  
  9288  	Providers := map[addrs.Provider]providers.Factory{
  9289  		addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  9290  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(tp),
  9291  	}
  9292  
  9293  	ctx := testContext2(t, &ContextOpts{
  9294  		Providers: Providers,
  9295  	})
  9296  
  9297  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  9298  		Mode: plans.DestroyMode,
  9299  	})
  9300  	diags.HasErrors()
  9301  	if diags.HasErrors() {
  9302  		t.Fatalf("diags: %s", diags.Err())
  9303  	}
  9304  
  9305  	// We'll marshal and unmarshal the plan here, to ensure that we have
  9306  	// a clean new context as would be created if we separately ran
  9307  	// terraform plan -out=tfplan && terraform apply tfplan
  9308  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  9309  	if err != nil {
  9310  		t.Fatal(err)
  9311  	}
  9312  	ctxOpts.Providers = Providers
  9313  	ctx, diags = NewContext(ctxOpts)
  9314  	if diags.HasErrors() {
  9315  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  9316  	}
  9317  
  9318  	tp.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  9319  		foo := req.Config.GetAttr("foo")
  9320  		if !foo.IsKnown() {
  9321  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("unknown config value foo"))
  9322  			return resp
  9323  		}
  9324  
  9325  		if foo.AsString() != "new" {
  9326  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("wrong config value: %q", foo.AsString()))
  9327  		}
  9328  		return resp
  9329  	}
  9330  
  9331  	_, diags = ctx.Apply(plan, m)
  9332  	if diags.HasErrors() {
  9333  		t.Fatalf("diags: %s", diags.Err())
  9334  	}
  9335  }
  9336  
  9337  func TestContext2Apply_taintedDestroyFailure(t *testing.T) {
  9338  	m := testModule(t, "apply-destroy-tainted")
  9339  	p := testProvider("test")
  9340  	p.PlanResourceChangeFn = testDiffFn
  9341  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  9342  		// All destroys fail.
  9343  		if req.PlannedState.IsNull() {
  9344  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure"))
  9345  			return
  9346  		}
  9347  
  9348  		// c will also fail to create, meaning the existing tainted instance
  9349  		// becomes deposed, ans is then promoted back to current.
  9350  		// only C has a foo attribute
  9351  		planned := req.PlannedState.AsValueMap()
  9352  		foo, ok := planned["foo"]
  9353  		if ok && !foo.IsNull() && foo.AsString() == "c" {
  9354  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("failure"))
  9355  			return
  9356  		}
  9357  
  9358  		return testApplyFn(req)
  9359  	}
  9360  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  9361  		ResourceTypes: map[string]*configschema.Block{
  9362  			"test_instance": {
  9363  				Attributes: map[string]*configschema.Attribute{
  9364  					"id": {
  9365  						Type:     cty.String,
  9366  						Computed: true,
  9367  					},
  9368  					"foo": {
  9369  						Type:     cty.String,
  9370  						Optional: true,
  9371  					},
  9372  				},
  9373  			},
  9374  		},
  9375  	})
  9376  
  9377  	state := states.NewState()
  9378  	root := state.EnsureModule(addrs.RootModuleInstance)
  9379  	root.SetResourceInstanceCurrent(
  9380  		addrs.Resource{
  9381  			Mode: addrs.ManagedResourceMode,
  9382  			Type: "test_instance",
  9383  			Name: "a",
  9384  		}.Instance(addrs.NoKey),
  9385  		&states.ResourceInstanceObjectSrc{
  9386  			Status:    states.ObjectTainted,
  9387  			AttrsJSON: []byte(`{"id":"a","foo":"a"}`),
  9388  		},
  9389  		addrs.AbsProviderConfig{
  9390  			Provider: addrs.NewDefaultProvider("test"),
  9391  			Module:   addrs.RootModule,
  9392  		},
  9393  	)
  9394  	root.SetResourceInstanceCurrent(
  9395  		addrs.Resource{
  9396  			Mode: addrs.ManagedResourceMode,
  9397  			Type: "test_instance",
  9398  			Name: "b",
  9399  		}.Instance(addrs.NoKey),
  9400  		&states.ResourceInstanceObjectSrc{
  9401  			Status:    states.ObjectTainted,
  9402  			AttrsJSON: []byte(`{"id":"b","foo":"b"}`),
  9403  		},
  9404  		addrs.AbsProviderConfig{
  9405  			Provider: addrs.NewDefaultProvider("test"),
  9406  			Module:   addrs.RootModule,
  9407  		},
  9408  	)
  9409  	root.SetResourceInstanceCurrent(
  9410  		addrs.Resource{
  9411  			Mode: addrs.ManagedResourceMode,
  9412  			Type: "test_instance",
  9413  			Name: "c",
  9414  		}.Instance(addrs.NoKey),
  9415  		&states.ResourceInstanceObjectSrc{
  9416  			Status:    states.ObjectTainted,
  9417  			AttrsJSON: []byte(`{"id":"c","foo":"old"}`),
  9418  		},
  9419  		addrs.AbsProviderConfig{
  9420  			Provider: addrs.NewDefaultProvider("test"),
  9421  			Module:   addrs.RootModule,
  9422  		},
  9423  	)
  9424  
  9425  	Providers := map[addrs.Provider]providers.Factory{
  9426  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9427  	}
  9428  
  9429  	ctx := testContext2(t, &ContextOpts{
  9430  		Providers: Providers,
  9431  		Hooks:     []Hook{&testHook{}},
  9432  	})
  9433  
  9434  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9435  	diags.HasErrors()
  9436  	if diags.HasErrors() {
  9437  		t.Fatalf("diags: %s", diags.Err())
  9438  	}
  9439  
  9440  	state, diags = ctx.Apply(plan, m)
  9441  	if !diags.HasErrors() {
  9442  		t.Fatal("expected error")
  9443  	}
  9444  
  9445  	root = state.Module(addrs.RootModuleInstance)
  9446  
  9447  	// the instance that failed to destroy should remain tainted
  9448  	a := root.ResourceInstance(addrs.Resource{
  9449  		Mode: addrs.ManagedResourceMode,
  9450  		Type: "test_instance",
  9451  		Name: "a",
  9452  	}.Instance(addrs.NoKey))
  9453  
  9454  	if a.Current.Status != states.ObjectTainted {
  9455  		t.Fatal("test_instance.a should be tainted")
  9456  	}
  9457  
  9458  	// b is create_before_destroy, and the destroy failed, so there should be 1
  9459  	// deposed instance.
  9460  	b := root.ResourceInstance(addrs.Resource{
  9461  		Mode: addrs.ManagedResourceMode,
  9462  		Type: "test_instance",
  9463  		Name: "b",
  9464  	}.Instance(addrs.NoKey))
  9465  
  9466  	if b.Current.Status != states.ObjectReady {
  9467  		t.Fatal("test_instance.b should be Ready")
  9468  	}
  9469  
  9470  	if len(b.Deposed) != 1 {
  9471  		t.Fatal("test_instance.b failed to keep deposed instance")
  9472  	}
  9473  
  9474  	// the desposed c instance should be promoted back to Current, and remain
  9475  	// tainted
  9476  	c := root.ResourceInstance(addrs.Resource{
  9477  		Mode: addrs.ManagedResourceMode,
  9478  		Type: "test_instance",
  9479  		Name: "c",
  9480  	}.Instance(addrs.NoKey))
  9481  
  9482  	if c.Current == nil {
  9483  		t.Fatal("test_instance.c has no current instance, but it should")
  9484  	}
  9485  
  9486  	if c.Current.Status != states.ObjectTainted {
  9487  		t.Fatal("test_instance.c should be tainted")
  9488  	}
  9489  
  9490  	if len(c.Deposed) != 0 {
  9491  		t.Fatal("test_instance.c should have no deposed instances")
  9492  	}
  9493  
  9494  	if string(c.Current.AttrsJSON) != `{"foo":"old","id":"c"}` {
  9495  		t.Fatalf("unexpected attrs for c: %q\n", c.Current.AttrsJSON)
  9496  	}
  9497  }
  9498  
  9499  func TestContext2Apply_plannedConnectionRefs(t *testing.T) {
  9500  	m := testModule(t, "apply-plan-connection-refs")
  9501  	p := testProvider("test")
  9502  	p.PlanResourceChangeFn = testDiffFn
  9503  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  9504  		s := req.PlannedState.AsValueMap()
  9505  		// delay "a" slightly, so if the reference edge is missing the "b"
  9506  		// provisioner will see an unknown value.
  9507  		if s["foo"].AsString() == "a" {
  9508  			time.Sleep(500 * time.Millisecond)
  9509  		}
  9510  
  9511  		s["id"] = cty.StringVal("ID")
  9512  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
  9513  			s["type"] = cty.StringVal(req.TypeName)
  9514  		}
  9515  		resp.NewState = cty.ObjectVal(s)
  9516  		return resp
  9517  	}
  9518  
  9519  	provisionerFactory := func() (provisioners.Interface, error) {
  9520  		pr := testProvisioner()
  9521  		pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
  9522  			host := req.Connection.GetAttr("host")
  9523  			if host.IsNull() || !host.IsKnown() {
  9524  				resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("invalid host value: %#v", host))
  9525  			}
  9526  
  9527  			return resp
  9528  		}
  9529  		return pr, nil
  9530  	}
  9531  
  9532  	Providers := map[addrs.Provider]providers.Factory{
  9533  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9534  	}
  9535  
  9536  	provisioners := map[string]provisioners.Factory{
  9537  		"shell": provisionerFactory,
  9538  	}
  9539  
  9540  	hook := &testHook{}
  9541  	ctx := testContext2(t, &ContextOpts{
  9542  		Providers:    Providers,
  9543  		Provisioners: provisioners,
  9544  		Hooks:        []Hook{hook},
  9545  	})
  9546  
  9547  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9548  	diags.HasErrors()
  9549  	if diags.HasErrors() {
  9550  		t.Fatalf("diags: %s", diags.Err())
  9551  	}
  9552  
  9553  	_, diags = ctx.Apply(plan, m)
  9554  	if diags.HasErrors() {
  9555  		t.Fatalf("diags: %s", diags.Err())
  9556  	}
  9557  }
  9558  
  9559  func TestContext2Apply_cbdCycle(t *testing.T) {
  9560  	m, snap := testModuleWithSnapshot(t, "apply-cbd-cycle")
  9561  	p := testProvider("test")
  9562  	p.PlanResourceChangeFn = testDiffFn
  9563  
  9564  	state := states.NewState()
  9565  	root := state.EnsureModule(addrs.RootModuleInstance)
  9566  	root.SetResourceInstanceCurrent(
  9567  		addrs.Resource{
  9568  			Mode: addrs.ManagedResourceMode,
  9569  			Type: "test_instance",
  9570  			Name: "a",
  9571  		}.Instance(addrs.NoKey),
  9572  		&states.ResourceInstanceObjectSrc{
  9573  			Status:    states.ObjectReady,
  9574  			AttrsJSON: []byte(`{"id":"a","require_new":"old","foo":"b"}`),
  9575  			Dependencies: []addrs.ConfigResource{
  9576  				{
  9577  					Resource: addrs.Resource{
  9578  						Mode: addrs.ManagedResourceMode,
  9579  						Type: "test_instance",
  9580  						Name: "b",
  9581  					},
  9582  					Module: addrs.RootModule,
  9583  				},
  9584  				{
  9585  					Resource: addrs.Resource{
  9586  						Mode: addrs.ManagedResourceMode,
  9587  						Type: "test_instance",
  9588  						Name: "c",
  9589  					},
  9590  					Module: addrs.RootModule,
  9591  				},
  9592  			},
  9593  		},
  9594  		addrs.AbsProviderConfig{
  9595  			Provider: addrs.NewDefaultProvider("test"),
  9596  			Module:   addrs.RootModule,
  9597  		},
  9598  	)
  9599  	root.SetResourceInstanceCurrent(
  9600  		addrs.Resource{
  9601  			Mode: addrs.ManagedResourceMode,
  9602  			Type: "test_instance",
  9603  			Name: "b",
  9604  		}.Instance(addrs.NoKey),
  9605  		&states.ResourceInstanceObjectSrc{
  9606  			Status:    states.ObjectReady,
  9607  			AttrsJSON: []byte(`{"id":"b","require_new":"old","foo":"c"}`),
  9608  			Dependencies: []addrs.ConfigResource{
  9609  				{
  9610  					Resource: addrs.Resource{
  9611  						Mode: addrs.ManagedResourceMode,
  9612  						Type: "test_instance",
  9613  						Name: "c",
  9614  					},
  9615  					Module: addrs.RootModule,
  9616  				},
  9617  			},
  9618  		},
  9619  		addrs.AbsProviderConfig{
  9620  			Provider: addrs.NewDefaultProvider("test"),
  9621  			Module:   addrs.RootModule,
  9622  		},
  9623  	)
  9624  	root.SetResourceInstanceCurrent(
  9625  		addrs.Resource{
  9626  			Mode: addrs.ManagedResourceMode,
  9627  			Type: "test_instance",
  9628  			Name: "c",
  9629  		}.Instance(addrs.NoKey),
  9630  		&states.ResourceInstanceObjectSrc{
  9631  			Status:    states.ObjectReady,
  9632  			AttrsJSON: []byte(`{"id":"c","require_new":"old"}`),
  9633  		},
  9634  		addrs.AbsProviderConfig{
  9635  			Provider: addrs.NewDefaultProvider("test"),
  9636  			Module:   addrs.RootModule,
  9637  		},
  9638  	)
  9639  
  9640  	Providers := map[addrs.Provider]providers.Factory{
  9641  		addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9642  	}
  9643  
  9644  	hook := &testHook{}
  9645  	ctx := testContext2(t, &ContextOpts{
  9646  		Providers: Providers,
  9647  		Hooks:     []Hook{hook},
  9648  	})
  9649  
  9650  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  9651  	diags.HasErrors()
  9652  	if diags.HasErrors() {
  9653  		t.Fatalf("diags: %s", diags.Err())
  9654  	}
  9655  
  9656  	// We'll marshal and unmarshal the plan here, to ensure that we have
  9657  	// a clean new context as would be created if we separately ran
  9658  	// terraform plan -out=tfplan && terraform apply tfplan
  9659  	ctxOpts, m, plan, err := contextOptsForPlanViaFile(snap, plan)
  9660  	if err != nil {
  9661  		t.Fatal(err)
  9662  	}
  9663  	ctxOpts.Providers = Providers
  9664  	ctx, diags = NewContext(ctxOpts)
  9665  	if diags.HasErrors() {
  9666  		t.Fatalf("failed to create context for plan: %s", diags.Err())
  9667  	}
  9668  
  9669  	_, diags = ctx.Apply(plan, m)
  9670  	if diags.HasErrors() {
  9671  		t.Fatalf("diags: %s", diags.Err())
  9672  	}
  9673  }
  9674  
  9675  func TestContext2Apply_ProviderMeta_apply_set(t *testing.T) {
  9676  	m := testModule(t, "provider-meta-set")
  9677  	p := testProvider("test")
  9678  	p.PlanResourceChangeFn = testDiffFn
  9679  	schema := p.ProviderSchema()
  9680  	schema.ProviderMeta = &configschema.Block{
  9681  		Attributes: map[string]*configschema.Attribute{
  9682  			"baz": {
  9683  				Type:     cty.String,
  9684  				Required: true,
  9685  			},
  9686  		},
  9687  	}
  9688  
  9689  	var pmMu sync.Mutex
  9690  	arcPMs := map[string]cty.Value{}
  9691  
  9692  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9693  		pmMu.Lock()
  9694  		defer pmMu.Unlock()
  9695  		arcPMs[req.TypeName] = req.ProviderMeta
  9696  
  9697  		s := req.PlannedState.AsValueMap()
  9698  		s["id"] = cty.StringVal("ID")
  9699  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
  9700  			s["type"] = cty.StringVal(req.TypeName)
  9701  		}
  9702  		return providers.ApplyResourceChangeResponse{
  9703  			NewState: cty.ObjectVal(s),
  9704  		}
  9705  	}
  9706  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9707  	ctx := testContext2(t, &ContextOpts{
  9708  		Providers: map[addrs.Provider]providers.Factory{
  9709  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9710  		},
  9711  	})
  9712  
  9713  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9714  	assertNoErrors(t, diags)
  9715  
  9716  	_, diags = ctx.Apply(plan, m)
  9717  	assertNoErrors(t, diags)
  9718  
  9719  	if !p.ApplyResourceChangeCalled {
  9720  		t.Fatalf("ApplyResourceChange not called")
  9721  	}
  9722  
  9723  	expectations := map[string]cty.Value{}
  9724  
  9725  	if pm, ok := arcPMs["test_resource"]; !ok {
  9726  		t.Fatalf("sub-module ApplyResourceChange not called")
  9727  	} else if pm.IsNull() {
  9728  		t.Fatalf("null ProviderMeta in sub-module ApplyResourceChange")
  9729  	} else {
  9730  		expectations["quux-submodule"] = pm
  9731  	}
  9732  
  9733  	if pm, ok := arcPMs["test_instance"]; !ok {
  9734  		t.Fatalf("root module ApplyResourceChange not called")
  9735  	} else if pm.IsNull() {
  9736  		t.Fatalf("null ProviderMeta in root module ApplyResourceChange")
  9737  	} else {
  9738  		expectations["quux"] = pm
  9739  	}
  9740  
  9741  	type metaStruct struct {
  9742  		Baz string `cty:"baz"`
  9743  	}
  9744  
  9745  	for expected, v := range expectations {
  9746  		var meta metaStruct
  9747  		err := gocty.FromCtyValue(v, &meta)
  9748  		if err != nil {
  9749  			t.Fatalf("Error parsing cty value: %s", err)
  9750  		}
  9751  		if meta.Baz != expected {
  9752  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
  9753  		}
  9754  	}
  9755  }
  9756  
  9757  func TestContext2Apply_ProviderMeta_apply_unset(t *testing.T) {
  9758  	m := testModule(t, "provider-meta-unset")
  9759  	p := testProvider("test")
  9760  	p.PlanResourceChangeFn = testDiffFn
  9761  	schema := p.ProviderSchema()
  9762  	schema.ProviderMeta = &configschema.Block{
  9763  		Attributes: map[string]*configschema.Attribute{
  9764  			"baz": {
  9765  				Type:     cty.String,
  9766  				Required: true,
  9767  			},
  9768  		},
  9769  	}
  9770  	var pmMu sync.Mutex
  9771  	arcPMs := map[string]cty.Value{}
  9772  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
  9773  		pmMu.Lock()
  9774  		defer pmMu.Unlock()
  9775  		arcPMs[req.TypeName] = req.ProviderMeta
  9776  
  9777  		s := req.PlannedState.AsValueMap()
  9778  		s["id"] = cty.StringVal("ID")
  9779  		if ty, ok := s["type"]; ok && !ty.IsKnown() {
  9780  			s["type"] = cty.StringVal(req.TypeName)
  9781  		}
  9782  		return providers.ApplyResourceChangeResponse{
  9783  			NewState: cty.ObjectVal(s),
  9784  		}
  9785  	}
  9786  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9787  	ctx := testContext2(t, &ContextOpts{
  9788  		Providers: map[addrs.Provider]providers.Factory{
  9789  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9790  		},
  9791  	})
  9792  
  9793  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9794  	assertNoErrors(t, diags)
  9795  
  9796  	_, diags = ctx.Apply(plan, m)
  9797  	assertNoErrors(t, diags)
  9798  
  9799  	if !p.ApplyResourceChangeCalled {
  9800  		t.Fatalf("ApplyResourceChange not called")
  9801  	}
  9802  
  9803  	if pm, ok := arcPMs["test_resource"]; !ok {
  9804  		t.Fatalf("sub-module ApplyResourceChange not called")
  9805  	} else if !pm.IsNull() {
  9806  		t.Fatalf("non-null ProviderMeta in sub-module ApplyResourceChange: %+v", pm)
  9807  	}
  9808  
  9809  	if pm, ok := arcPMs["test_instance"]; !ok {
  9810  		t.Fatalf("root module ApplyResourceChange not called")
  9811  	} else if !pm.IsNull() {
  9812  		t.Fatalf("non-null ProviderMeta in root module ApplyResourceChange: %+v", pm)
  9813  	}
  9814  }
  9815  
  9816  func TestContext2Apply_ProviderMeta_plan_set(t *testing.T) {
  9817  	m := testModule(t, "provider-meta-set")
  9818  	p := testProvider("test")
  9819  	schema := p.ProviderSchema()
  9820  	schema.ProviderMeta = &configschema.Block{
  9821  		Attributes: map[string]*configschema.Attribute{
  9822  			"baz": {
  9823  				Type:     cty.String,
  9824  				Required: true,
  9825  			},
  9826  		},
  9827  	}
  9828  	prcPMs := map[string]cty.Value{}
  9829  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  9830  		prcPMs[req.TypeName] = req.ProviderMeta
  9831  		return providers.PlanResourceChangeResponse{
  9832  			PlannedState: req.ProposedNewState,
  9833  		}
  9834  	}
  9835  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9836  	ctx := testContext2(t, &ContextOpts{
  9837  		Providers: map[addrs.Provider]providers.Factory{
  9838  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9839  		},
  9840  	})
  9841  
  9842  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9843  	assertNoErrors(t, diags)
  9844  
  9845  	if !p.PlanResourceChangeCalled {
  9846  		t.Fatalf("PlanResourceChange not called")
  9847  	}
  9848  
  9849  	expectations := map[string]cty.Value{}
  9850  
  9851  	if pm, ok := prcPMs["test_resource"]; !ok {
  9852  		t.Fatalf("sub-module PlanResourceChange not called")
  9853  	} else if pm.IsNull() {
  9854  		t.Fatalf("null ProviderMeta in sub-module PlanResourceChange")
  9855  	} else {
  9856  		expectations["quux-submodule"] = pm
  9857  	}
  9858  
  9859  	if pm, ok := prcPMs["test_instance"]; !ok {
  9860  		t.Fatalf("root module PlanResourceChange not called")
  9861  	} else if pm.IsNull() {
  9862  		t.Fatalf("null ProviderMeta in root module PlanResourceChange")
  9863  	} else {
  9864  		expectations["quux"] = pm
  9865  	}
  9866  
  9867  	type metaStruct struct {
  9868  		Baz string `cty:"baz"`
  9869  	}
  9870  
  9871  	for expected, v := range expectations {
  9872  		var meta metaStruct
  9873  		err := gocty.FromCtyValue(v, &meta)
  9874  		if err != nil {
  9875  			t.Fatalf("Error parsing cty value: %s", err)
  9876  		}
  9877  		if meta.Baz != expected {
  9878  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
  9879  		}
  9880  	}
  9881  }
  9882  
  9883  func TestContext2Apply_ProviderMeta_plan_unset(t *testing.T) {
  9884  	m := testModule(t, "provider-meta-unset")
  9885  	p := testProvider("test")
  9886  	schema := p.ProviderSchema()
  9887  	schema.ProviderMeta = &configschema.Block{
  9888  		Attributes: map[string]*configschema.Attribute{
  9889  			"baz": {
  9890  				Type:     cty.String,
  9891  				Required: true,
  9892  			},
  9893  		},
  9894  	}
  9895  	prcPMs := map[string]cty.Value{}
  9896  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  9897  		prcPMs[req.TypeName] = req.ProviderMeta
  9898  		return providers.PlanResourceChangeResponse{
  9899  			PlannedState: req.ProposedNewState,
  9900  		}
  9901  	}
  9902  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9903  	ctx := testContext2(t, &ContextOpts{
  9904  		Providers: map[addrs.Provider]providers.Factory{
  9905  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9906  		},
  9907  	})
  9908  
  9909  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9910  	assertNoErrors(t, diags)
  9911  
  9912  	if !p.PlanResourceChangeCalled {
  9913  		t.Fatalf("PlanResourceChange not called")
  9914  	}
  9915  
  9916  	if pm, ok := prcPMs["test_resource"]; !ok {
  9917  		t.Fatalf("sub-module PlanResourceChange not called")
  9918  	} else if !pm.IsNull() {
  9919  		t.Fatalf("non-null ProviderMeta in sub-module PlanResourceChange: %+v", pm)
  9920  	}
  9921  
  9922  	if pm, ok := prcPMs["test_instance"]; !ok {
  9923  		t.Fatalf("root module PlanResourceChange not called")
  9924  	} else if !pm.IsNull() {
  9925  		t.Fatalf("non-null ProviderMeta in root module PlanResourceChange: %+v", pm)
  9926  	}
  9927  }
  9928  
  9929  func TestContext2Apply_ProviderMeta_plan_setNoSchema(t *testing.T) {
  9930  	m := testModule(t, "provider-meta-set")
  9931  	p := testProvider("test")
  9932  	p.PlanResourceChangeFn = testDiffFn
  9933  	ctx := testContext2(t, &ContextOpts{
  9934  		Providers: map[addrs.Provider]providers.Factory{
  9935  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9936  		},
  9937  	})
  9938  
  9939  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9940  	if !diags.HasErrors() {
  9941  		t.Fatalf("plan supposed to error, has no errors")
  9942  	}
  9943  
  9944  	var rootErr, subErr bool
  9945  	errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks"
  9946  	for _, diag := range diags {
  9947  		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
  9948  			t.Errorf("Unexpected error: %+v", diag.Description())
  9949  		}
  9950  		switch diag.Description().Detail {
  9951  		case fmt.Sprintf(errorSummary, "instance"):
  9952  			rootErr = true
  9953  		case fmt.Sprintf(errorSummary, "resource"):
  9954  			subErr = true
  9955  		default:
  9956  			t.Errorf("Unexpected error: %s", diag.Description())
  9957  		}
  9958  	}
  9959  	if !rootErr {
  9960  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
  9961  	}
  9962  	if !subErr {
  9963  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
  9964  	}
  9965  }
  9966  
  9967  func TestContext2Apply_ProviderMeta_plan_setInvalid(t *testing.T) {
  9968  	m := testModule(t, "provider-meta-set")
  9969  	p := testProvider("test")
  9970  	p.PlanResourceChangeFn = testDiffFn
  9971  	schema := p.ProviderSchema()
  9972  	schema.ProviderMeta = &configschema.Block{
  9973  		Attributes: map[string]*configschema.Attribute{
  9974  			"quux": {
  9975  				Type:     cty.String,
  9976  				Required: true,
  9977  			},
  9978  		},
  9979  	}
  9980  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
  9981  	ctx := testContext2(t, &ContextOpts{
  9982  		Providers: map[addrs.Provider]providers.Factory{
  9983  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  9984  		},
  9985  	})
  9986  
  9987  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  9988  	if !diags.HasErrors() {
  9989  		t.Fatalf("plan supposed to error, has no errors")
  9990  	}
  9991  
  9992  	var reqErr, invalidErr bool
  9993  	for _, diag := range diags {
  9994  		switch diag.Description().Summary {
  9995  		case "Missing required argument":
  9996  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
  9997  				reqErr = true
  9998  			} else {
  9999  				t.Errorf("Unexpected error %+v", diag.Description())
 10000  			}
 10001  		case "Unsupported argument":
 10002  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10003  				invalidErr = true
 10004  			} else {
 10005  				t.Errorf("Unexpected error %+v", diag.Description())
 10006  			}
 10007  		default:
 10008  			t.Errorf("Unexpected error %+v", diag.Description())
 10009  		}
 10010  	}
 10011  	if !reqErr {
 10012  		t.Errorf("Expected missing required argument error, none received")
 10013  	}
 10014  	if !invalidErr {
 10015  		t.Errorf("Expected unsupported argument error, none received")
 10016  	}
 10017  }
 10018  
 10019  func TestContext2Apply_ProviderMeta_refresh_set(t *testing.T) {
 10020  	m := testModule(t, "provider-meta-set")
 10021  	p := testProvider("test")
 10022  	p.PlanResourceChangeFn = testDiffFn
 10023  	schema := p.ProviderSchema()
 10024  	schema.ProviderMeta = &configschema.Block{
 10025  		Attributes: map[string]*configschema.Attribute{
 10026  			"baz": {
 10027  				Type:     cty.String,
 10028  				Required: true,
 10029  			},
 10030  		},
 10031  	}
 10032  	rrcPMs := map[string]cty.Value{}
 10033  	p.ReadResourceFn = func(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
 10034  		rrcPMs[req.TypeName] = req.ProviderMeta
 10035  		newState, err := p.GetProviderSchemaResponse.ResourceTypes[req.TypeName].Block.CoerceValue(req.PriorState)
 10036  		if err != nil {
 10037  			panic(err)
 10038  		}
 10039  		resp.NewState = newState
 10040  		return resp
 10041  	}
 10042  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10043  	ctx := testContext2(t, &ContextOpts{
 10044  		Providers: map[addrs.Provider]providers.Factory{
 10045  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10046  		},
 10047  	})
 10048  
 10049  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10050  	assertNoErrors(t, diags)
 10051  
 10052  	state, diags := ctx.Apply(plan, m)
 10053  	assertNoErrors(t, diags)
 10054  
 10055  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10056  	assertNoErrors(t, diags)
 10057  
 10058  	if !p.ReadResourceCalled {
 10059  		t.Fatalf("ReadResource not called")
 10060  	}
 10061  
 10062  	expectations := map[string]cty.Value{}
 10063  
 10064  	if pm, ok := rrcPMs["test_resource"]; !ok {
 10065  		t.Fatalf("sub-module ReadResource not called")
 10066  	} else if pm.IsNull() {
 10067  		t.Fatalf("null ProviderMeta in sub-module ReadResource")
 10068  	} else {
 10069  		expectations["quux-submodule"] = pm
 10070  	}
 10071  
 10072  	if pm, ok := rrcPMs["test_instance"]; !ok {
 10073  		t.Fatalf("root module ReadResource not called")
 10074  	} else if pm.IsNull() {
 10075  		t.Fatalf("null ProviderMeta in root module ReadResource")
 10076  	} else {
 10077  		expectations["quux"] = pm
 10078  	}
 10079  
 10080  	type metaStruct struct {
 10081  		Baz string `cty:"baz"`
 10082  	}
 10083  
 10084  	for expected, v := range expectations {
 10085  		var meta metaStruct
 10086  		err := gocty.FromCtyValue(v, &meta)
 10087  		if err != nil {
 10088  			t.Fatalf("Error parsing cty value: %s", err)
 10089  		}
 10090  		if meta.Baz != expected {
 10091  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10092  		}
 10093  	}
 10094  }
 10095  
 10096  func TestContext2Apply_ProviderMeta_refresh_setNoSchema(t *testing.T) {
 10097  	m := testModule(t, "provider-meta-set")
 10098  	p := testProvider("test")
 10099  	p.PlanResourceChangeFn = testDiffFn
 10100  
 10101  	// we need a schema for plan/apply so they don't error
 10102  	schema := p.ProviderSchema()
 10103  	schema.ProviderMeta = &configschema.Block{
 10104  		Attributes: map[string]*configschema.Attribute{
 10105  			"baz": {
 10106  				Type:     cty.String,
 10107  				Required: true,
 10108  			},
 10109  		},
 10110  	}
 10111  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10112  	ctx := testContext2(t, &ContextOpts{
 10113  		Providers: map[addrs.Provider]providers.Factory{
 10114  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10115  		},
 10116  	})
 10117  
 10118  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10119  	assertNoErrors(t, diags)
 10120  
 10121  	state, diags := ctx.Apply(plan, m)
 10122  	assertNoErrors(t, diags)
 10123  
 10124  	// drop the schema before refresh, to test that it errors
 10125  	schema.ProviderMeta = nil
 10126  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10127  	ctx = testContext2(t, &ContextOpts{
 10128  		Providers: map[addrs.Provider]providers.Factory{
 10129  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10130  		},
 10131  	})
 10132  
 10133  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10134  	if !diags.HasErrors() {
 10135  		t.Fatalf("refresh supposed to error, has no errors")
 10136  	}
 10137  
 10138  	var rootErr, subErr bool
 10139  	errorSummary := "The resource test_%s.bar belongs to a provider that doesn't support provider_meta blocks"
 10140  	for _, diag := range diags {
 10141  		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
 10142  			t.Errorf("Unexpected error: %+v", diag.Description())
 10143  		}
 10144  		switch diag.Description().Detail {
 10145  		case fmt.Sprintf(errorSummary, "instance"):
 10146  			rootErr = true
 10147  		case fmt.Sprintf(errorSummary, "resource"):
 10148  			subErr = true
 10149  		default:
 10150  			t.Errorf("Unexpected error: %s", diag.Description())
 10151  		}
 10152  	}
 10153  	if !rootErr {
 10154  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10155  	}
 10156  	if !subErr {
 10157  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10158  	}
 10159  }
 10160  
 10161  func TestContext2Apply_ProviderMeta_refresh_setInvalid(t *testing.T) {
 10162  	m := testModule(t, "provider-meta-set")
 10163  	p := testProvider("test")
 10164  	p.PlanResourceChangeFn = testDiffFn
 10165  
 10166  	// we need a matching schema for plan/apply so they don't error
 10167  	schema := p.ProviderSchema()
 10168  	schema.ProviderMeta = &configschema.Block{
 10169  		Attributes: map[string]*configschema.Attribute{
 10170  			"baz": {
 10171  				Type:     cty.String,
 10172  				Required: true,
 10173  			},
 10174  		},
 10175  	}
 10176  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10177  	ctx := testContext2(t, &ContextOpts{
 10178  		Providers: map[addrs.Provider]providers.Factory{
 10179  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10180  		},
 10181  	})
 10182  
 10183  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10184  	assertNoErrors(t, diags)
 10185  
 10186  	state, diags := ctx.Apply(plan, m)
 10187  	assertNoErrors(t, diags)
 10188  
 10189  	// change the schema before refresh, to test that it errors
 10190  	schema.ProviderMeta = &configschema.Block{
 10191  		Attributes: map[string]*configschema.Attribute{
 10192  			"quux": {
 10193  				Type:     cty.String,
 10194  				Required: true,
 10195  			},
 10196  		},
 10197  	}
 10198  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10199  	ctx = testContext2(t, &ContextOpts{
 10200  		Providers: map[addrs.Provider]providers.Factory{
 10201  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10202  		},
 10203  	})
 10204  
 10205  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10206  	if !diags.HasErrors() {
 10207  		t.Fatalf("refresh supposed to error, has no errors")
 10208  	}
 10209  
 10210  	var reqErr, invalidErr bool
 10211  	for _, diag := range diags {
 10212  		switch diag.Description().Summary {
 10213  		case "Missing required argument":
 10214  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10215  				reqErr = true
 10216  			} else {
 10217  				t.Errorf("Unexpected error %+v", diag.Description())
 10218  			}
 10219  		case "Unsupported argument":
 10220  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10221  				invalidErr = true
 10222  			} else {
 10223  				t.Errorf("Unexpected error %+v", diag.Description())
 10224  			}
 10225  		default:
 10226  			t.Errorf("Unexpected error %+v", diag.Description())
 10227  		}
 10228  	}
 10229  	if !reqErr {
 10230  		t.Errorf("Expected missing required argument error, none received")
 10231  	}
 10232  	if !invalidErr {
 10233  		t.Errorf("Expected unsupported argument error, none received")
 10234  	}
 10235  }
 10236  
 10237  func TestContext2Apply_ProviderMeta_refreshdata_set(t *testing.T) {
 10238  	m := testModule(t, "provider-meta-data-set")
 10239  	p := testProvider("test")
 10240  	p.PlanResourceChangeFn = testDiffFn
 10241  	schema := p.ProviderSchema()
 10242  	schema.ProviderMeta = &configschema.Block{
 10243  		Attributes: map[string]*configschema.Attribute{
 10244  			"baz": {
 10245  				Type:     cty.String,
 10246  				Required: true,
 10247  			},
 10248  		},
 10249  	}
 10250  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10251  	ctx := testContext2(t, &ContextOpts{
 10252  		Providers: map[addrs.Provider]providers.Factory{
 10253  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10254  		},
 10255  	})
 10256  	rdsPMs := map[string]cty.Value{}
 10257  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10258  		rdsPMs[req.TypeName] = req.ProviderMeta
 10259  		switch req.TypeName {
 10260  		case "test_data_source":
 10261  			log.Printf("[TRACE] test_data_source RDSR returning")
 10262  			return providers.ReadDataSourceResponse{
 10263  				State: cty.ObjectVal(map[string]cty.Value{
 10264  					"id":  cty.StringVal("yo"),
 10265  					"foo": cty.StringVal("bar"),
 10266  				}),
 10267  			}
 10268  		case "test_file":
 10269  			log.Printf("[TRACE] test_file RDSR returning")
 10270  			return providers.ReadDataSourceResponse{
 10271  				State: cty.ObjectVal(map[string]cty.Value{
 10272  					"id":       cty.StringVal("bar"),
 10273  					"rendered": cty.StringVal("baz"),
 10274  					"template": cty.StringVal(""),
 10275  				}),
 10276  			}
 10277  		default:
 10278  			// config drift, oops
 10279  			log.Printf("[TRACE] unknown request TypeName: %q", req.TypeName)
 10280  			return providers.ReadDataSourceResponse{}
 10281  		}
 10282  	}
 10283  
 10284  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10285  	assertNoErrors(t, diags)
 10286  
 10287  	state, diags := ctx.Apply(plan, m)
 10288  	assertNoErrors(t, diags)
 10289  
 10290  	_, diags = ctx.Refresh(m, state, DefaultPlanOpts)
 10291  	assertNoErrors(t, diags)
 10292  
 10293  	if !p.ReadDataSourceCalled {
 10294  		t.Fatalf("ReadDataSource not called")
 10295  	}
 10296  
 10297  	expectations := map[string]cty.Value{}
 10298  
 10299  	if pm, ok := rdsPMs["test_file"]; !ok {
 10300  		t.Fatalf("sub-module ReadDataSource not called")
 10301  	} else if pm.IsNull() {
 10302  		t.Fatalf("null ProviderMeta in sub-module ReadDataSource")
 10303  	} else {
 10304  		expectations["quux-submodule"] = pm
 10305  	}
 10306  
 10307  	if pm, ok := rdsPMs["test_data_source"]; !ok {
 10308  		t.Fatalf("root module ReadDataSource not called")
 10309  	} else if pm.IsNull() {
 10310  		t.Fatalf("null ProviderMeta in root module ReadDataSource")
 10311  	} else {
 10312  		expectations["quux"] = pm
 10313  	}
 10314  
 10315  	type metaStruct struct {
 10316  		Baz string `cty:"baz"`
 10317  	}
 10318  
 10319  	for expected, v := range expectations {
 10320  		var meta metaStruct
 10321  		err := gocty.FromCtyValue(v, &meta)
 10322  		if err != nil {
 10323  			t.Fatalf("Error parsing cty value: %s", err)
 10324  		}
 10325  		if meta.Baz != expected {
 10326  			t.Fatalf("Expected meta.Baz to be %q, got %q", expected, meta.Baz)
 10327  		}
 10328  	}
 10329  }
 10330  
 10331  func TestContext2Apply_ProviderMeta_refreshdata_unset(t *testing.T) {
 10332  	m := testModule(t, "provider-meta-data-unset")
 10333  	p := testProvider("test")
 10334  	p.PlanResourceChangeFn = testDiffFn
 10335  	schema := p.ProviderSchema()
 10336  	schema.ProviderMeta = &configschema.Block{
 10337  		Attributes: map[string]*configschema.Attribute{
 10338  			"baz": {
 10339  				Type:     cty.String,
 10340  				Required: true,
 10341  			},
 10342  		},
 10343  	}
 10344  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10345  	ctx := testContext2(t, &ContextOpts{
 10346  		Providers: map[addrs.Provider]providers.Factory{
 10347  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10348  		},
 10349  	})
 10350  	rdsPMs := map[string]cty.Value{}
 10351  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10352  		rdsPMs[req.TypeName] = req.ProviderMeta
 10353  		switch req.TypeName {
 10354  		case "test_data_source":
 10355  			return providers.ReadDataSourceResponse{
 10356  				State: cty.ObjectVal(map[string]cty.Value{
 10357  					"id":  cty.StringVal("yo"),
 10358  					"foo": cty.StringVal("bar"),
 10359  				}),
 10360  			}
 10361  		case "test_file":
 10362  			return providers.ReadDataSourceResponse{
 10363  				State: cty.ObjectVal(map[string]cty.Value{
 10364  					"id":       cty.StringVal("bar"),
 10365  					"rendered": cty.StringVal("baz"),
 10366  					"template": cty.StringVal(""),
 10367  				}),
 10368  			}
 10369  		default:
 10370  			// config drift, oops
 10371  			return providers.ReadDataSourceResponse{}
 10372  		}
 10373  	}
 10374  
 10375  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10376  	assertNoErrors(t, diags)
 10377  
 10378  	_, diags = ctx.Apply(plan, m)
 10379  	assertNoErrors(t, diags)
 10380  
 10381  	if !p.ReadDataSourceCalled {
 10382  		t.Fatalf("ReadDataSource not called")
 10383  	}
 10384  
 10385  	if pm, ok := rdsPMs["test_file"]; !ok {
 10386  		t.Fatalf("sub-module ReadDataSource not called")
 10387  	} else if !pm.IsNull() {
 10388  		t.Fatalf("non-null ProviderMeta in sub-module ReadDataSource")
 10389  	}
 10390  
 10391  	if pm, ok := rdsPMs["test_data_source"]; !ok {
 10392  		t.Fatalf("root module ReadDataSource not called")
 10393  	} else if !pm.IsNull() {
 10394  		t.Fatalf("non-null ProviderMeta in root module ReadDataSource")
 10395  	}
 10396  }
 10397  
 10398  func TestContext2Apply_ProviderMeta_refreshdata_setNoSchema(t *testing.T) {
 10399  	m := testModule(t, "provider-meta-data-set")
 10400  	p := testProvider("test")
 10401  	p.PlanResourceChangeFn = testDiffFn
 10402  	ctx := testContext2(t, &ContextOpts{
 10403  		Providers: map[addrs.Provider]providers.Factory{
 10404  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10405  		},
 10406  	})
 10407  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 10408  		State: cty.ObjectVal(map[string]cty.Value{
 10409  			"id":  cty.StringVal("yo"),
 10410  			"foo": cty.StringVal("bar"),
 10411  		}),
 10412  	}
 10413  
 10414  	_, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts)
 10415  	if !diags.HasErrors() {
 10416  		t.Fatalf("refresh supposed to error, has no errors")
 10417  	}
 10418  
 10419  	var rootErr, subErr bool
 10420  	errorSummary := "The resource data.test_%s.foo belongs to a provider that doesn't support provider_meta blocks"
 10421  	for _, diag := range diags {
 10422  		if diag.Description().Summary != "Provider registry.terraform.io/hashicorp/test doesn't support provider_meta" {
 10423  			t.Errorf("Unexpected error: %+v", diag.Description())
 10424  		}
 10425  		switch diag.Description().Detail {
 10426  		case fmt.Sprintf(errorSummary, "data_source"):
 10427  			rootErr = true
 10428  		case fmt.Sprintf(errorSummary, "file"):
 10429  			subErr = true
 10430  		default:
 10431  			t.Errorf("Unexpected error: %s", diag.Description())
 10432  		}
 10433  	}
 10434  	if !rootErr {
 10435  		t.Errorf("Expected unsupported provider_meta block error for root module, none received")
 10436  	}
 10437  	if !subErr {
 10438  		t.Errorf("Expected unsupported provider_meta block error for sub-module, none received")
 10439  	}
 10440  }
 10441  
 10442  func TestContext2Apply_ProviderMeta_refreshdata_setInvalid(t *testing.T) {
 10443  	m := testModule(t, "provider-meta-data-set")
 10444  	p := testProvider("test")
 10445  	p.PlanResourceChangeFn = testDiffFn
 10446  	schema := p.ProviderSchema()
 10447  	schema.ProviderMeta = &configschema.Block{
 10448  		Attributes: map[string]*configschema.Attribute{
 10449  			"quux": {
 10450  				Type:     cty.String,
 10451  				Required: true,
 10452  			},
 10453  		},
 10454  	}
 10455  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schema)
 10456  	ctx := testContext2(t, &ContextOpts{
 10457  		Providers: map[addrs.Provider]providers.Factory{
 10458  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10459  		},
 10460  	})
 10461  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 10462  		State: cty.ObjectVal(map[string]cty.Value{
 10463  			"id":  cty.StringVal("yo"),
 10464  			"foo": cty.StringVal("bar"),
 10465  		}),
 10466  	}
 10467  
 10468  	_, diags := ctx.Refresh(m, states.NewState(), DefaultPlanOpts)
 10469  	if !diags.HasErrors() {
 10470  		t.Fatalf("refresh supposed to error, has no errors")
 10471  	}
 10472  
 10473  	var reqErr, invalidErr bool
 10474  	for _, diag := range diags {
 10475  		switch diag.Description().Summary {
 10476  		case "Missing required argument":
 10477  			if diag.Description().Detail == `The argument "quux" is required, but no definition was found.` {
 10478  				reqErr = true
 10479  			} else {
 10480  				t.Errorf("Unexpected error %+v", diag.Description())
 10481  			}
 10482  		case "Unsupported argument":
 10483  			if diag.Description().Detail == `An argument named "baz" is not expected here.` {
 10484  				invalidErr = true
 10485  			} else {
 10486  				t.Errorf("Unexpected error %+v", diag.Description())
 10487  			}
 10488  		default:
 10489  			t.Errorf("Unexpected error %+v", diag.Description())
 10490  		}
 10491  	}
 10492  	if !reqErr {
 10493  		t.Errorf("Expected missing required argument error, none received")
 10494  	}
 10495  	if !invalidErr {
 10496  		t.Errorf("Expected unsupported argument error, none received")
 10497  	}
 10498  }
 10499  
 10500  func TestContext2Apply_expandModuleVariables(t *testing.T) {
 10501  	m := testModuleInline(t, map[string]string{
 10502  		"main.tf": `
 10503  module "mod1" {
 10504    for_each = toset(["a"])
 10505    source = "./mod"
 10506  }
 10507  
 10508  module "mod2" {
 10509    source = "./mod"
 10510    in = module.mod1["a"].out
 10511  }
 10512  `,
 10513  		"mod/main.tf": `
 10514  resource "aws_instance" "foo" {
 10515    foo = var.in
 10516  }
 10517  
 10518  variable "in" {
 10519    type = string
 10520    default = "default"
 10521  }
 10522  
 10523  output "out" {
 10524    value = aws_instance.foo.id
 10525  }
 10526  `,
 10527  	})
 10528  
 10529  	p := testProvider("aws")
 10530  	p.PlanResourceChangeFn = testDiffFn
 10531  	p.ApplyResourceChangeFn = testApplyFn
 10532  	ctx := testContext2(t, &ContextOpts{
 10533  		Providers: map[addrs.Provider]providers.Factory{
 10534  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 10535  		},
 10536  	})
 10537  
 10538  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10539  	if diags.HasErrors() {
 10540  		t.Fatal(diags.ErrWithWarnings())
 10541  	}
 10542  
 10543  	state, diags := ctx.Apply(plan, m)
 10544  	if diags.HasErrors() {
 10545  		t.Fatal(diags.ErrWithWarnings())
 10546  	}
 10547  
 10548  	expected := `<no state>
 10549  module.mod1["a"]:
 10550    aws_instance.foo:
 10551      ID = foo
 10552      provider = provider["registry.terraform.io/hashicorp/aws"]
 10553      foo = default
 10554      type = aws_instance
 10555  
 10556    Outputs:
 10557  
 10558    out = foo
 10559  module.mod2:
 10560    aws_instance.foo:
 10561      ID = foo
 10562      provider = provider["registry.terraform.io/hashicorp/aws"]
 10563      foo = foo
 10564      type = aws_instance
 10565  
 10566      Dependencies:
 10567        module.mod1.aws_instance.foo`
 10568  
 10569  	if state.String() != expected {
 10570  		t.Fatalf("expected:\n%s\ngot:\n%s\n", expected, state)
 10571  	}
 10572  }
 10573  
 10574  func TestContext2Apply_inheritAndStoreCBD(t *testing.T) {
 10575  	m := testModuleInline(t, map[string]string{
 10576  		"main.tf": `
 10577  resource "aws_instance" "foo" {
 10578  }
 10579  
 10580  resource "aws_instance" "cbd" {
 10581    foo = aws_instance.foo.id
 10582    lifecycle {
 10583      create_before_destroy = true
 10584    }
 10585  }
 10586  `,
 10587  	})
 10588  
 10589  	p := testProvider("aws")
 10590  	p.PlanResourceChangeFn = testDiffFn
 10591  	ctx := testContext2(t, &ContextOpts{
 10592  		Providers: map[addrs.Provider]providers.Factory{
 10593  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 10594  		},
 10595  	})
 10596  
 10597  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10598  	if diags.HasErrors() {
 10599  		t.Fatal(diags.ErrWithWarnings())
 10600  	}
 10601  
 10602  	state, diags := ctx.Apply(plan, m)
 10603  	if diags.HasErrors() {
 10604  		t.Fatal(diags.ErrWithWarnings())
 10605  	}
 10606  
 10607  	foo := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo"))
 10608  	if !foo.Current.CreateBeforeDestroy {
 10609  		t.Fatal("aws_instance.foo should also be create_before_destroy")
 10610  	}
 10611  }
 10612  
 10613  func TestContext2Apply_moduleDependsOn(t *testing.T) {
 10614  	m := testModule(t, "apply-module-depends-on")
 10615  
 10616  	p := testProvider("test")
 10617  
 10618  	// each instance being applied should happen in sequential order
 10619  	applied := int64(0)
 10620  
 10621  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 10622  		cfg := req.Config.AsValueMap()
 10623  		foo := cfg["foo"].AsString()
 10624  		ord := atomic.LoadInt64(&applied)
 10625  
 10626  		resp := providers.ReadDataSourceResponse{
 10627  			State: cty.ObjectVal(map[string]cty.Value{
 10628  				"id":  cty.StringVal("data"),
 10629  				"foo": cfg["foo"],
 10630  			}),
 10631  		}
 10632  
 10633  		if foo == "a" && ord < 4 {
 10634  			// due to data source "a"'s module depending on instance 4, this
 10635  			// should not be less than 4
 10636  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source a read too early"))
 10637  		}
 10638  		if foo == "b" && ord < 1 {
 10639  			// due to data source "b"'s module depending on instance 1, this
 10640  			// should not be less than 1
 10641  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source b read too early"))
 10642  		}
 10643  		return resp
 10644  	}
 10645  	p.PlanResourceChangeFn = testDiffFn
 10646  
 10647  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 10648  		state := req.PlannedState.AsValueMap()
 10649  		num, _ := state["num"].AsBigFloat().Float64()
 10650  		ord := int64(num)
 10651  		if !atomic.CompareAndSwapInt64(&applied, ord-1, ord) {
 10652  			actual := atomic.LoadInt64(&applied)
 10653  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("instance %d was applied after %d", ord, actual))
 10654  		}
 10655  
 10656  		state["id"] = cty.StringVal(fmt.Sprintf("test_%d", ord))
 10657  		state["type"] = cty.StringVal("test_instance")
 10658  		resp.NewState = cty.ObjectVal(state)
 10659  
 10660  		return resp
 10661  	}
 10662  
 10663  	ctx := testContext2(t, &ContextOpts{
 10664  		Providers: map[addrs.Provider]providers.Factory{
 10665  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10666  		},
 10667  	})
 10668  
 10669  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10670  	if diags.HasErrors() {
 10671  		t.Fatal(diags.ErrWithWarnings())
 10672  	}
 10673  
 10674  	state, diags := ctx.Apply(plan, m)
 10675  	if diags.HasErrors() {
 10676  		t.Fatal(diags.ErrWithWarnings())
 10677  	}
 10678  
 10679  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
 10680  	if diags.HasErrors() {
 10681  		t.Fatal(diags.ErrWithWarnings())
 10682  	}
 10683  
 10684  	for _, res := range plan.Changes.Resources {
 10685  		if res.Action != plans.NoOp {
 10686  			t.Fatalf("expected NoOp, got %s for %s", res.Action, res.Addr)
 10687  		}
 10688  	}
 10689  }
 10690  
 10691  func TestContext2Apply_moduleSelfReference(t *testing.T) {
 10692  	m := testModuleInline(t, map[string]string{
 10693  		"main.tf": `
 10694  module "test" {
 10695    source = "./test"
 10696  
 10697    a = module.test.b
 10698  }
 10699  
 10700  output "c" {
 10701    value = module.test.c
 10702  }
 10703  `,
 10704  		"test/main.tf": `
 10705  variable "a" {}
 10706  
 10707  resource "test_instance" "test" {
 10708  }
 10709  
 10710  output "b" {
 10711    value = test_instance.test.id
 10712  }
 10713  
 10714  output "c" {
 10715    value = var.a
 10716  }`})
 10717  
 10718  	p := testProvider("test")
 10719  	p.PlanResourceChangeFn = testDiffFn
 10720  	ctx := testContext2(t, &ContextOpts{
 10721  		Providers: map[addrs.Provider]providers.Factory{
 10722  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10723  		},
 10724  	})
 10725  
 10726  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10727  	if diags.HasErrors() {
 10728  		t.Fatal(diags.ErrWithWarnings())
 10729  	}
 10730  
 10731  	state, diags := ctx.Apply(plan, m)
 10732  	if diags.HasErrors() {
 10733  		t.Fatal(diags.ErrWithWarnings())
 10734  	}
 10735  
 10736  	ctx = testContext2(t, &ContextOpts{
 10737  		Providers: map[addrs.Provider]providers.Factory{
 10738  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10739  		},
 10740  	})
 10741  
 10742  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 10743  		Mode: plans.DestroyMode,
 10744  	})
 10745  	if diags.HasErrors() {
 10746  		t.Fatal(diags.ErrWithWarnings())
 10747  	}
 10748  
 10749  	state, diags = ctx.Apply(plan, m)
 10750  	if diags.HasErrors() {
 10751  		t.Fatal(diags.ErrWithWarnings())
 10752  	}
 10753  
 10754  	if !state.Empty() {
 10755  		t.Fatal("expected empty state, got:", state)
 10756  	}
 10757  }
 10758  
 10759  func TestContext2Apply_moduleExpandDependsOn(t *testing.T) {
 10760  	m := testModuleInline(t, map[string]string{
 10761  		"main.tf": `
 10762  module "child" {
 10763    count = 1
 10764    source = "./child"
 10765  
 10766    depends_on = [test_instance.a, test_instance.b]
 10767  }
 10768  
 10769  resource "test_instance" "a" {
 10770  }
 10771  
 10772  
 10773  resource "test_instance" "b" {
 10774  }
 10775  `,
 10776  		"child/main.tf": `
 10777  resource "test_instance" "foo" {
 10778  }
 10779  
 10780  output "myoutput" {
 10781    value = "literal string"
 10782  }
 10783  `})
 10784  
 10785  	p := testProvider("test")
 10786  	p.PlanResourceChangeFn = testDiffFn
 10787  	ctx := testContext2(t, &ContextOpts{
 10788  		Providers: map[addrs.Provider]providers.Factory{
 10789  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10790  		},
 10791  	})
 10792  
 10793  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 10794  	if diags.HasErrors() {
 10795  		t.Fatal(diags.ErrWithWarnings())
 10796  	}
 10797  
 10798  	state, diags := ctx.Apply(plan, m)
 10799  	if diags.HasErrors() {
 10800  		t.Fatal(diags.ErrWithWarnings())
 10801  	}
 10802  
 10803  	ctx = testContext2(t, &ContextOpts{
 10804  		Providers: map[addrs.Provider]providers.Factory{
 10805  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10806  		},
 10807  	})
 10808  
 10809  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 10810  		Mode: plans.DestroyMode,
 10811  	})
 10812  	if diags.HasErrors() {
 10813  		t.Fatal(diags.ErrWithWarnings())
 10814  	}
 10815  
 10816  	state, diags = ctx.Apply(plan, m)
 10817  	if diags.HasErrors() {
 10818  		t.Fatal(diags.ErrWithWarnings())
 10819  	}
 10820  
 10821  	if !state.Empty() {
 10822  		t.Fatal("expected empty state, got:", state)
 10823  	}
 10824  }
 10825  
 10826  func TestContext2Apply_scaleInCBD(t *testing.T) {
 10827  	m := testModuleInline(t, map[string]string{
 10828  		"main.tf": `
 10829  variable "ct" {
 10830    type = number
 10831  }
 10832  
 10833  resource "test_instance" "a" {
 10834    count = var.ct
 10835  }
 10836  
 10837  resource "test_instance" "b" {
 10838    require_new = local.removable
 10839    lifecycle {
 10840  	create_before_destroy = true
 10841    }
 10842  }
 10843  
 10844  resource "test_instance" "c" {
 10845    require_new = test_instance.b.id
 10846    lifecycle {
 10847  	create_before_destroy = true
 10848    }
 10849  }
 10850  
 10851  output "out" {
 10852    value = join(".", test_instance.a[*].id)
 10853  }
 10854  
 10855  locals {
 10856    removable = join(".", test_instance.a[*].id)
 10857  }
 10858  `})
 10859  
 10860  	state := states.NewState()
 10861  	root := state.EnsureModule(addrs.RootModuleInstance)
 10862  	root.SetResourceInstanceCurrent(
 10863  		mustResourceInstanceAddr("test_instance.a[0]").Resource,
 10864  		&states.ResourceInstanceObjectSrc{
 10865  			Status:              states.ObjectReady,
 10866  			AttrsJSON:           []byte(`{"id":"a0"}`),
 10867  			Dependencies:        []addrs.ConfigResource{},
 10868  			CreateBeforeDestroy: true,
 10869  		},
 10870  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 10871  	)
 10872  	root.SetResourceInstanceCurrent(
 10873  		mustResourceInstanceAddr("test_instance.a[1]").Resource,
 10874  		&states.ResourceInstanceObjectSrc{
 10875  			Status:              states.ObjectReady,
 10876  			AttrsJSON:           []byte(`{"id":"a1"}`),
 10877  			Dependencies:        []addrs.ConfigResource{},
 10878  			CreateBeforeDestroy: true,
 10879  		},
 10880  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 10881  	)
 10882  	root.SetResourceInstanceCurrent(
 10883  		mustResourceInstanceAddr("test_instance.b").Resource,
 10884  		&states.ResourceInstanceObjectSrc{
 10885  			Status:              states.ObjectReady,
 10886  			AttrsJSON:           []byte(`{"id":"b", "require_new":"old.old"}`),
 10887  			Dependencies:        []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")},
 10888  			CreateBeforeDestroy: true,
 10889  		},
 10890  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 10891  	)
 10892  	root.SetResourceInstanceCurrent(
 10893  		mustResourceInstanceAddr("test_instance.c").Resource,
 10894  		&states.ResourceInstanceObjectSrc{
 10895  			Status:    states.ObjectReady,
 10896  			AttrsJSON: []byte(`{"id":"c", "require_new":"b"}`),
 10897  			Dependencies: []addrs.ConfigResource{
 10898  				mustConfigResourceAddr("test_instance.a"),
 10899  				mustConfigResourceAddr("test_instance.b"),
 10900  			},
 10901  			CreateBeforeDestroy: true,
 10902  		},
 10903  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
 10904  	)
 10905  
 10906  	p := testProvider("test")
 10907  
 10908  	p.PlanResourceChangeFn = func(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
 10909  		n := r.ProposedNewState.AsValueMap()
 10910  
 10911  		if r.PriorState.IsNull() {
 10912  			n["id"] = cty.UnknownVal(cty.String)
 10913  			resp.PlannedState = cty.ObjectVal(n)
 10914  			return resp
 10915  		}
 10916  
 10917  		p := r.PriorState.AsValueMap()
 10918  
 10919  		priorRN := p["require_new"]
 10920  		newRN := n["require_new"]
 10921  
 10922  		if eq := priorRN.Equals(newRN); !eq.IsKnown() || eq.False() {
 10923  			resp.RequiresReplace = []cty.Path{{cty.GetAttrStep{Name: "require_new"}}}
 10924  			n["id"] = cty.UnknownVal(cty.String)
 10925  		}
 10926  
 10927  		resp.PlannedState = cty.ObjectVal(n)
 10928  		return resp
 10929  	}
 10930  
 10931  	// reduce the count to 1
 10932  	ctx := testContext2(t, &ContextOpts{
 10933  		Providers: map[addrs.Provider]providers.Factory{
 10934  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10935  		},
 10936  	})
 10937  
 10938  	plan, diags := ctx.Plan(m, state, &PlanOpts{
 10939  		Mode: plans.NormalMode,
 10940  		SetVariables: InputValues{
 10941  			"ct": &InputValue{
 10942  				Value:      cty.NumberIntVal(1),
 10943  				SourceType: ValueFromCaller,
 10944  			},
 10945  		},
 10946  	})
 10947  	if diags.HasErrors() {
 10948  		t.Fatal(diags.ErrWithWarnings())
 10949  	}
 10950  
 10951  	state, diags = ctx.Apply(plan, m)
 10952  	if diags.HasErrors() {
 10953  		log.Fatal(diags.ErrWithWarnings())
 10954  	}
 10955  
 10956  	// check the output, as those can't cause an error planning the value
 10957  	out := state.RootModule().OutputValues["out"].Value.AsString()
 10958  	if out != "a0" {
 10959  		t.Fatalf(`expected output "a0", got: %q`, out)
 10960  	}
 10961  
 10962  	// reduce the count to 0
 10963  	ctx = testContext2(t, &ContextOpts{
 10964  		Providers: map[addrs.Provider]providers.Factory{
 10965  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 10966  		},
 10967  	})
 10968  
 10969  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 10970  		Mode: plans.NormalMode,
 10971  		SetVariables: InputValues{
 10972  			"ct": &InputValue{
 10973  				Value:      cty.NumberIntVal(0),
 10974  				SourceType: ValueFromCaller,
 10975  			},
 10976  		},
 10977  	})
 10978  	if diags.HasErrors() {
 10979  		t.Fatal(diags.ErrWithWarnings())
 10980  	}
 10981  
 10982  	state, diags = ctx.Apply(plan, m)
 10983  	if diags.HasErrors() {
 10984  		t.Fatal(diags.ErrWithWarnings())
 10985  	}
 10986  
 10987  	// check the output, as those can't cause an error planning the value
 10988  	out = state.RootModule().OutputValues["out"].Value.AsString()
 10989  	if out != "" {
 10990  		t.Fatalf(`expected output "", got: %q`, out)
 10991  	}
 10992  }
 10993  
 10994  // Ensure that we can destroy when a provider references a resource that will
 10995  // also be destroyed
 10996  func TestContext2Apply_destroyProviderReference(t *testing.T) {
 10997  	m := testModuleInline(t, map[string]string{
 10998  		"main.tf": `
 10999  provider "null" {
 11000    value = ""
 11001  }
 11002  
 11003  module "mod" {
 11004    source = "./mod"
 11005  }
 11006  
 11007  provider "test" {
 11008    value = module.mod.output
 11009  }
 11010  
 11011  resource "test_instance" "bar" {
 11012  }
 11013  `,
 11014  		"mod/main.tf": `
 11015  data "null_data_source" "foo" {
 11016         count = 1
 11017  }
 11018  
 11019  
 11020  output "output" {
 11021    value = data.null_data_source.foo[0].output
 11022  }
 11023  `})
 11024  
 11025  	schemaFn := func(name string) *ProviderSchema {
 11026  		return &ProviderSchema{
 11027  			Provider: &configschema.Block{
 11028  				Attributes: map[string]*configschema.Attribute{
 11029  					"value": {
 11030  						Type:     cty.String,
 11031  						Required: true,
 11032  					},
 11033  				},
 11034  			},
 11035  			ResourceTypes: map[string]*configschema.Block{
 11036  				name + "_instance": {
 11037  					Attributes: map[string]*configschema.Attribute{
 11038  						"id": {
 11039  							Type:     cty.String,
 11040  							Computed: true,
 11041  						},
 11042  						"foo": {
 11043  							Type:     cty.String,
 11044  							Optional: true,
 11045  						},
 11046  					},
 11047  				},
 11048  			},
 11049  			DataSources: map[string]*configschema.Block{
 11050  				name + "_data_source": {
 11051  					Attributes: map[string]*configschema.Attribute{
 11052  						"id": {
 11053  							Type:     cty.String,
 11054  							Computed: true,
 11055  						},
 11056  						"output": {
 11057  							Type:     cty.String,
 11058  							Computed: true,
 11059  						},
 11060  					},
 11061  				},
 11062  			},
 11063  		}
 11064  	}
 11065  
 11066  	testP := new(MockProvider)
 11067  	testP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11068  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11069  	}
 11070  	testP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("test"))
 11071  
 11072  	providerConfig := ""
 11073  	testP.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
 11074  		value := req.Config.GetAttr("value")
 11075  		if value.IsKnown() && !value.IsNull() {
 11076  			providerConfig = value.AsString()
 11077  		} else {
 11078  			providerConfig = ""
 11079  		}
 11080  		return resp
 11081  	}
 11082  	testP.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 11083  		if providerConfig != "valid" {
 11084  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("provider config is %q", providerConfig))
 11085  			return
 11086  		}
 11087  		return testApplyFn(req)
 11088  	}
 11089  	testP.PlanResourceChangeFn = testDiffFn
 11090  
 11091  	nullP := new(MockProvider)
 11092  	nullP.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11093  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11094  	}
 11095  	nullP.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(schemaFn("null"))
 11096  
 11097  	nullP.ApplyResourceChangeFn = testApplyFn
 11098  	nullP.PlanResourceChangeFn = testDiffFn
 11099  
 11100  	nullP.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
 11101  		State: cty.ObjectVal(map[string]cty.Value{
 11102  			"id":     cty.StringVal("ID"),
 11103  			"output": cty.StringVal("valid"),
 11104  		}),
 11105  	}
 11106  
 11107  	ctx := testContext2(t, &ContextOpts{
 11108  		Providers: map[addrs.Provider]providers.Factory{
 11109  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP),
 11110  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP),
 11111  		},
 11112  	})
 11113  
 11114  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11115  	assertNoErrors(t, diags)
 11116  
 11117  	state, diags := ctx.Apply(plan, m)
 11118  	if diags.HasErrors() {
 11119  		t.Fatalf("apply errors: %s", diags.Err())
 11120  	}
 11121  
 11122  	ctx = testContext2(t, &ContextOpts{
 11123  		Providers: map[addrs.Provider]providers.Factory{
 11124  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(testP),
 11125  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(nullP),
 11126  		},
 11127  	})
 11128  
 11129  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11130  		Mode: plans.DestroyMode,
 11131  	})
 11132  	assertNoErrors(t, diags)
 11133  
 11134  	if _, diags := ctx.Apply(plan, m); diags.HasErrors() {
 11135  		t.Fatalf("destroy apply errors: %s", diags.Err())
 11136  	}
 11137  }
 11138  
 11139  // Destroying properly requires pruning out all unneeded config nodes to
 11140  // prevent incorrect expansion evaluation.
 11141  func TestContext2Apply_destroyInterModuleExpansion(t *testing.T) {
 11142  	m := testModuleInline(t, map[string]string{
 11143  		"main.tf": `
 11144  data "test_data_source" "a" {
 11145    for_each = {
 11146      one = "thing"
 11147    }
 11148  }
 11149  
 11150  locals {
 11151    module_input = {
 11152      for k, v in data.test_data_source.a : k => v.id
 11153    }
 11154  }
 11155  
 11156  module "mod1" {
 11157    source = "./mod"
 11158    input = local.module_input
 11159  }
 11160  
 11161  module "mod2" {
 11162    source = "./mod"
 11163    input = module.mod1.outputs
 11164  }
 11165  
 11166  resource "test_instance" "bar" {
 11167    for_each = module.mod2.outputs
 11168  }
 11169  
 11170  output "module_output" {
 11171    value = module.mod2.outputs
 11172  }
 11173  output "test_instances" {
 11174    value = test_instance.bar
 11175  }
 11176  `,
 11177  		"mod/main.tf": `
 11178  variable "input" {
 11179  }
 11180  
 11181  data "test_data_source" "foo" {
 11182    for_each = var.input
 11183  }
 11184  
 11185  output "outputs" {
 11186    value = data.test_data_source.foo
 11187  }
 11188  `})
 11189  
 11190  	p := testProvider("test")
 11191  	p.PlanResourceChangeFn = testDiffFn
 11192  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 11193  		return providers.ReadDataSourceResponse{
 11194  			State: cty.ObjectVal(map[string]cty.Value{
 11195  				"id":  cty.StringVal("data_source"),
 11196  				"foo": cty.StringVal("output"),
 11197  			}),
 11198  		}
 11199  	}
 11200  
 11201  	ctx := testContext2(t, &ContextOpts{
 11202  		Providers: map[addrs.Provider]providers.Factory{
 11203  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11204  		},
 11205  	})
 11206  
 11207  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11208  	assertNoErrors(t, diags)
 11209  
 11210  	state, diags := ctx.Apply(plan, m)
 11211  	if diags.HasErrors() {
 11212  		t.Fatalf("apply errors: %s", diags.Err())
 11213  	}
 11214  
 11215  	destroy := func() {
 11216  		ctx = testContext2(t, &ContextOpts{
 11217  			Providers: map[addrs.Provider]providers.Factory{
 11218  				addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11219  			},
 11220  		})
 11221  
 11222  		plan, diags = ctx.Plan(m, state, &PlanOpts{
 11223  			Mode: plans.DestroyMode,
 11224  		})
 11225  		assertNoErrors(t, diags)
 11226  
 11227  		state, diags = ctx.Apply(plan, m)
 11228  		if diags.HasErrors() {
 11229  			t.Fatalf("destroy apply errors: %s", diags.Err())
 11230  		}
 11231  	}
 11232  
 11233  	destroy()
 11234  	// Destroying again from the empty state should not cause any errors either
 11235  	destroy()
 11236  }
 11237  
 11238  func TestContext2Apply_createBeforeDestroyWithModule(t *testing.T) {
 11239  	m := testModuleInline(t, map[string]string{
 11240  		"main.tf": `
 11241  variable "v" {}
 11242  
 11243  module "mod" {
 11244      source = "./mod"
 11245      in = var.v
 11246  }
 11247  
 11248  resource "test_resource" "a" {
 11249    value = var.v
 11250    depends_on = [module.mod]
 11251    lifecycle {
 11252      create_before_destroy = true
 11253    }
 11254  }
 11255  `,
 11256  		"mod/main.tf": `
 11257  variable "in" {}
 11258  
 11259  resource "test_resource" "a" {
 11260    value = var.in
 11261  }
 11262  `})
 11263  
 11264  	p := testProvider("test")
 11265  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
 11266  		proposed := req.ProposedNewState.AsValueMap()
 11267  		proposed["id"] = cty.UnknownVal(cty.String)
 11268  		return providers.PlanResourceChangeResponse{
 11269  			PlannedState:    cty.ObjectVal(proposed),
 11270  			RequiresReplace: []cty.Path{{cty.GetAttrStep{Name: "value"}}},
 11271  		}
 11272  	}
 11273  
 11274  	ctx := testContext2(t, &ContextOpts{
 11275  		Providers: map[addrs.Provider]providers.Factory{
 11276  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11277  		},
 11278  	})
 11279  
 11280  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11281  		Mode: plans.NormalMode,
 11282  		SetVariables: InputValues{
 11283  			"v": &InputValue{
 11284  				Value: cty.StringVal("A"),
 11285  			},
 11286  		},
 11287  	})
 11288  	assertNoErrors(t, diags)
 11289  
 11290  	state, diags := ctx.Apply(plan, m)
 11291  	if diags.HasErrors() {
 11292  		t.Fatalf("apply errors: %s", diags.Err())
 11293  	}
 11294  
 11295  	ctx = testContext2(t, &ContextOpts{
 11296  		Providers: map[addrs.Provider]providers.Factory{
 11297  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11298  		},
 11299  	})
 11300  
 11301  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11302  		Mode: plans.NormalMode,
 11303  		SetVariables: InputValues{
 11304  			"v": &InputValue{
 11305  				Value: cty.StringVal("B"),
 11306  			},
 11307  		},
 11308  	})
 11309  	assertNoErrors(t, diags)
 11310  
 11311  	_, diags = ctx.Apply(plan, m)
 11312  	if diags.HasErrors() {
 11313  		t.Fatalf("apply errors: %s", diags.Err())
 11314  	}
 11315  }
 11316  
 11317  func TestContext2Apply_forcedCBD(t *testing.T) {
 11318  	m := testModuleInline(t, map[string]string{
 11319  		"main.tf": `
 11320  variable "v" {}
 11321  
 11322  resource "test_instance" "a" {
 11323    require_new = var.v
 11324  }
 11325  
 11326  resource "test_instance" "b" {
 11327    depends_on = [test_instance.a]
 11328    lifecycle {
 11329      create_before_destroy = true
 11330    }
 11331  }
 11332  `})
 11333  
 11334  	p := testProvider("test")
 11335  	p.PlanResourceChangeFn = testDiffFn
 11336  
 11337  	ctx := testContext2(t, &ContextOpts{
 11338  		Providers: map[addrs.Provider]providers.Factory{
 11339  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11340  		},
 11341  	})
 11342  
 11343  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11344  		Mode: plans.NormalMode,
 11345  		SetVariables: InputValues{
 11346  			"v": &InputValue{
 11347  				Value: cty.StringVal("A"),
 11348  			},
 11349  		},
 11350  	})
 11351  	assertNoErrors(t, diags)
 11352  
 11353  	state, diags := ctx.Apply(plan, m)
 11354  	if diags.HasErrors() {
 11355  		t.Fatalf("apply errors: %s", diags.Err())
 11356  	}
 11357  
 11358  	ctx = testContext2(t, &ContextOpts{
 11359  		Providers: map[addrs.Provider]providers.Factory{
 11360  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11361  		},
 11362  	})
 11363  
 11364  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11365  		Mode: plans.NormalMode,
 11366  		SetVariables: InputValues{
 11367  			"v": &InputValue{
 11368  				Value: cty.StringVal("B"),
 11369  			},
 11370  		},
 11371  	})
 11372  	assertNoErrors(t, diags)
 11373  
 11374  	_, diags = ctx.Apply(plan, m)
 11375  	if diags.HasErrors() {
 11376  		t.Fatalf("apply errors: %s", diags.Err())
 11377  	}
 11378  }
 11379  
 11380  func TestContext2Apply_removeReferencedResource(t *testing.T) {
 11381  	m := testModuleInline(t, map[string]string{
 11382  		"main.tf": `
 11383  variable "ct" {
 11384  }
 11385  
 11386  resource "test_resource" "to_remove" {
 11387    count = var.ct
 11388  }
 11389  
 11390  resource "test_resource" "c" {
 11391    value = join("", test_resource.to_remove[*].id)
 11392  }
 11393  `})
 11394  
 11395  	p := testProvider("test")
 11396  	p.PlanResourceChangeFn = testDiffFn
 11397  
 11398  	ctx := testContext2(t, &ContextOpts{
 11399  		Providers: map[addrs.Provider]providers.Factory{
 11400  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11401  		},
 11402  	})
 11403  
 11404  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11405  		Mode: plans.NormalMode,
 11406  		SetVariables: InputValues{
 11407  			"ct": &InputValue{
 11408  				Value: cty.NumberIntVal(1),
 11409  			},
 11410  		},
 11411  	})
 11412  	assertNoErrors(t, diags)
 11413  
 11414  	state, diags := ctx.Apply(plan, m)
 11415  	if diags.HasErrors() {
 11416  		t.Fatalf("apply errors: %s", diags.Err())
 11417  	}
 11418  
 11419  	ctx = testContext2(t, &ContextOpts{
 11420  		Providers: map[addrs.Provider]providers.Factory{
 11421  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11422  		},
 11423  	})
 11424  
 11425  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11426  		Mode: plans.NormalMode,
 11427  		SetVariables: InputValues{
 11428  			"ct": &InputValue{
 11429  				Value: cty.NumberIntVal(0),
 11430  			},
 11431  		},
 11432  	})
 11433  	assertNoErrors(t, diags)
 11434  
 11435  	_, diags = ctx.Apply(plan, m)
 11436  	if diags.HasErrors() {
 11437  		t.Fatalf("apply errors: %s", diags.Err())
 11438  	}
 11439  }
 11440  
 11441  func TestContext2Apply_variableSensitivity(t *testing.T) {
 11442  	m := testModuleInline(t, map[string]string{
 11443  		"main.tf": `
 11444  variable "sensitive_var" {
 11445  	default = "foo"
 11446  	sensitive = true
 11447  }
 11448  
 11449  variable "sensitive_id" {
 11450  	default = "secret id"
 11451  	sensitive = true
 11452  }
 11453  
 11454  resource "test_resource" "foo" {
 11455  	value   = var.sensitive_var
 11456  
 11457  	network_interface {
 11458  		network_interface_id = var.sensitive_id
 11459  	}
 11460  }`,
 11461  	})
 11462  
 11463  	p := new(MockProvider)
 11464  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
 11465  		return providers.ReadResourceResponse{NewState: req.PriorState}
 11466  	}
 11467  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
 11468  		Provider: &configschema.Block{},
 11469  		ResourceTypes: map[string]*configschema.Block{
 11470  			"test_resource": {
 11471  				Attributes: map[string]*configschema.Attribute{
 11472  					"id": {
 11473  						Type:     cty.String,
 11474  						Computed: true,
 11475  					},
 11476  					"value": {
 11477  						Type:     cty.String,
 11478  						Optional: true,
 11479  						Computed: true,
 11480  					},
 11481  				},
 11482  				BlockTypes: map[string]*configschema.NestedBlock{
 11483  					"network_interface": {
 11484  						Block: configschema.Block{
 11485  							Attributes: map[string]*configschema.Attribute{
 11486  								"network_interface_id": {Type: cty.String, Optional: true},
 11487  								"device_index":         {Type: cty.Number, Optional: true},
 11488  							},
 11489  						},
 11490  						Nesting: configschema.NestingSet,
 11491  					},
 11492  				},
 11493  			},
 11494  		},
 11495  	})
 11496  	p.PlanResourceChangeFn = testDiffFn
 11497  
 11498  	ctx := testContext2(t, &ContextOpts{
 11499  		Providers: map[addrs.Provider]providers.Factory{
 11500  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11501  		},
 11502  	})
 11503  
 11504  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11505  	assertNoErrors(t, diags)
 11506  
 11507  	state, diags := ctx.Apply(plan, m)
 11508  	if diags.HasErrors() {
 11509  		t.Fatalf("apply errors: %s", diags.Err())
 11510  	}
 11511  
 11512  	// Run a second apply with no changes
 11513  	ctx = testContext2(t, &ContextOpts{
 11514  		Providers: map[addrs.Provider]providers.Factory{
 11515  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11516  		},
 11517  	})
 11518  
 11519  	plan, diags = ctx.Plan(m, state, DefaultPlanOpts)
 11520  	assertNoErrors(t, diags)
 11521  
 11522  	state, diags = ctx.Apply(plan, m)
 11523  	if diags.HasErrors() {
 11524  		t.Fatalf("apply errors: %s", diags.Err())
 11525  	}
 11526  
 11527  	// Now change the variable value for sensitive_var
 11528  	ctx = testContext2(t, &ContextOpts{
 11529  		Providers: map[addrs.Provider]providers.Factory{
 11530  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11531  		},
 11532  	})
 11533  
 11534  	plan, diags = ctx.Plan(m, state, &PlanOpts{
 11535  		Mode: plans.NormalMode,
 11536  		SetVariables: InputValues{
 11537  			"sensitive_var": &InputValue{
 11538  				Value: cty.StringVal("bar"),
 11539  			},
 11540  		},
 11541  	})
 11542  	assertNoErrors(t, diags)
 11543  
 11544  	_, diags = ctx.Apply(plan, m)
 11545  	if diags.HasErrors() {
 11546  		t.Fatalf("apply errors: %s", diags.Err())
 11547  	}
 11548  }
 11549  
 11550  func TestContext2Apply_variableSensitivityPropagation(t *testing.T) {
 11551  	m := testModuleInline(t, map[string]string{
 11552  		"main.tf": `
 11553  variable "sensitive_map" {
 11554  	type = map(string)
 11555  	default = {
 11556  		"x" = "foo"
 11557  	}
 11558  	sensitive = true
 11559  }
 11560  
 11561  resource "test_resource" "foo" {
 11562  	value = var.sensitive_map.x
 11563  }
 11564  `,
 11565  	})
 11566  
 11567  	p := testProvider("test")
 11568  	p.PlanResourceChangeFn = testDiffFn
 11569  
 11570  	ctx := testContext2(t, &ContextOpts{
 11571  		Providers: map[addrs.Provider]providers.Factory{
 11572  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11573  		},
 11574  	})
 11575  
 11576  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11577  	if diags.HasErrors() {
 11578  		t.Fatalf("plan errors: %s", diags.Err())
 11579  	}
 11580  
 11581  	verifySensitiveValue := func(pvms []cty.PathValueMarks) {
 11582  		if len(pvms) != 1 {
 11583  			t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 11584  		}
 11585  		pvm := pvms[0]
 11586  		if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) {
 11587  			t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 11588  		}
 11589  		if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 11590  			t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 11591  		}
 11592  	}
 11593  
 11594  	addr := mustResourceInstanceAddr("test_resource.foo")
 11595  	fooChangeSrc := plan.Changes.ResourceInstance(addr)
 11596  	verifySensitiveValue(fooChangeSrc.AfterValMarks)
 11597  
 11598  	state, diags := ctx.Apply(plan, m)
 11599  	if diags.HasErrors() {
 11600  		t.Fatalf("apply errors: %s", diags.Err())
 11601  	}
 11602  
 11603  	fooState := state.ResourceInstance(addr)
 11604  	verifySensitiveValue(fooState.Current.AttrSensitivePaths)
 11605  }
 11606  
 11607  func TestContext2Apply_variableSensitivityProviders(t *testing.T) {
 11608  	m := testModuleInline(t, map[string]string{
 11609  		"main.tf": `
 11610  resource "test_resource" "foo" {
 11611  	sensitive_value = "should get marked"
 11612  }
 11613  
 11614  resource "test_resource" "bar" {
 11615  	value  = test_resource.foo.sensitive_value
 11616  	random = test_resource.foo.id # not sensitive
 11617  
 11618  	nesting_single {
 11619  		value           = "abc"
 11620  		sensitive_value = "xyz"
 11621  	}
 11622  }
 11623  
 11624  resource "test_resource" "baz" {
 11625  	value = test_resource.bar.nesting_single.sensitive_value
 11626  }
 11627  `,
 11628  	})
 11629  
 11630  	p := testProvider("test")
 11631  	p.PlanResourceChangeFn = testDiffFn
 11632  
 11633  	ctx := testContext2(t, &ContextOpts{
 11634  		Providers: map[addrs.Provider]providers.Factory{
 11635  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11636  		},
 11637  	})
 11638  
 11639  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11640  	if diags.HasErrors() {
 11641  		t.Fatalf("plan errors: %s", diags.Err())
 11642  	}
 11643  
 11644  	verifySensitiveValue := func(pvms []cty.PathValueMarks) {
 11645  		if len(pvms) != 1 {
 11646  			t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 11647  		}
 11648  		pvm := pvms[0]
 11649  		if gotPath, wantPath := pvm.Path, cty.GetAttrPath("value"); !gotPath.Equals(wantPath) {
 11650  			t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 11651  		}
 11652  		if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 11653  			t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 11654  		}
 11655  	}
 11656  
 11657  	// Sensitive attributes (defined by the provider) are marked
 11658  	// as sensitive when referenced from another resource
 11659  	// "bar" references sensitive resources in "foo"
 11660  	barAddr := mustResourceInstanceAddr("test_resource.bar")
 11661  	barChangeSrc := plan.Changes.ResourceInstance(barAddr)
 11662  	verifySensitiveValue(barChangeSrc.AfterValMarks)
 11663  
 11664  	bazAddr := mustResourceInstanceAddr("test_resource.baz")
 11665  	bazChangeSrc := plan.Changes.ResourceInstance(bazAddr)
 11666  	verifySensitiveValue(bazChangeSrc.AfterValMarks)
 11667  
 11668  	state, diags := ctx.Apply(plan, m)
 11669  	if diags.HasErrors() {
 11670  		t.Fatalf("apply errors: %s", diags.Err())
 11671  	}
 11672  
 11673  	barState := state.ResourceInstance(barAddr)
 11674  	verifySensitiveValue(barState.Current.AttrSensitivePaths)
 11675  
 11676  	bazState := state.ResourceInstance(bazAddr)
 11677  	verifySensitiveValue(bazState.Current.AttrSensitivePaths)
 11678  }
 11679  
 11680  func TestContext2Apply_variableSensitivityChange(t *testing.T) {
 11681  	m := testModuleInline(t, map[string]string{
 11682  		"main.tf": `
 11683  variable "sensitive_var" {
 11684  	default = "hello"
 11685  	sensitive = true
 11686  }
 11687  
 11688  resource "test_resource" "foo" {
 11689  	value = var.sensitive_var
 11690  }`,
 11691  	})
 11692  
 11693  	p := testProvider("test")
 11694  	p.PlanResourceChangeFn = testDiffFn
 11695  
 11696  	ctx := testContext2(t, &ContextOpts{
 11697  		Providers: map[addrs.Provider]providers.Factory{
 11698  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11699  		},
 11700  	})
 11701  
 11702  	state := states.BuildState(func(s *states.SyncState) {
 11703  		s.SetResourceInstanceCurrent(
 11704  			addrs.Resource{
 11705  				Mode: addrs.ManagedResourceMode,
 11706  				Type: "test_resource",
 11707  				Name: "foo",
 11708  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
 11709  			&states.ResourceInstanceObjectSrc{
 11710  				Status:    states.ObjectReady,
 11711  				AttrsJSON: []byte(`{"id":"foo", "value":"hello"}`),
 11712  				// No AttrSensitivePaths present
 11713  			},
 11714  			addrs.AbsProviderConfig{
 11715  				Provider: addrs.NewDefaultProvider("test"),
 11716  				Module:   addrs.RootModule,
 11717  			},
 11718  		)
 11719  	})
 11720  
 11721  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
 11722  	assertNoErrors(t, diags)
 11723  
 11724  	addr := mustResourceInstanceAddr("test_resource.foo")
 11725  
 11726  	state, diags = ctx.Apply(plan, m)
 11727  	assertNoErrors(t, diags)
 11728  
 11729  	fooState := state.ResourceInstance(addr)
 11730  
 11731  	if len(fooState.Current.AttrSensitivePaths) != 1 {
 11732  		t.Fatalf("wrong number of sensitive paths, expected 1, got, %v", len(fooState.Current.AttrSensitivePaths))
 11733  	}
 11734  	got := fooState.Current.AttrSensitivePaths[0]
 11735  	want := cty.PathValueMarks{
 11736  		Path:  cty.GetAttrPath("value"),
 11737  		Marks: cty.NewValueMarks(marks.Sensitive),
 11738  	}
 11739  
 11740  	if !got.Equal(want) {
 11741  		t.Fatalf("wrong value marks; got:\n%#v\n\nwant:\n%#v\n", got, want)
 11742  	}
 11743  
 11744  	m2 := testModuleInline(t, map[string]string{
 11745  		"main.tf": `
 11746  variable "sensitive_var" {
 11747  	default = "hello"
 11748  	sensitive = false
 11749  }
 11750  
 11751  resource "test_resource" "foo" {
 11752  	value = var.sensitive_var
 11753  }`,
 11754  	})
 11755  
 11756  	ctx2 := testContext2(t, &ContextOpts{
 11757  		Providers: map[addrs.Provider]providers.Factory{
 11758  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11759  		},
 11760  	})
 11761  
 11762  	// NOTE: Prior to our refactoring to make the state an explicit argument
 11763  	// of Plan, as opposed to hidden state inside Context, this test was
 11764  	// calling ctx.Apply instead of ctx2.Apply and thus using the previous
 11765  	// plan instead of this new plan. "Fixing" it to use the new plan seems
 11766  	// to break the test, so we've preserved that oddity here by saving the
 11767  	// old plan as oldPlan and essentially discarding the new plan entirely,
 11768  	// but this seems rather suspicious and we should ideally figure out what
 11769  	// this test was originally intending to do and make it do that.
 11770  	oldPlan := plan
 11771  	_, diags = ctx2.Plan(m2, state, DefaultPlanOpts)
 11772  	assertNoErrors(t, diags)
 11773  	stateWithoutSensitive, diags := ctx.Apply(oldPlan, m)
 11774  	assertNoErrors(t, diags)
 11775  
 11776  	fooState2 := stateWithoutSensitive.ResourceInstance(addr)
 11777  	if len(fooState2.Current.AttrSensitivePaths) > 0 {
 11778  		t.Fatalf(
 11779  			"wrong number of sensitive paths, expected 0, got, %v\n%s",
 11780  			len(fooState2.Current.AttrSensitivePaths),
 11781  			spew.Sdump(fooState2.Current.AttrSensitivePaths),
 11782  		)
 11783  	}
 11784  }
 11785  
 11786  func TestContext2Apply_moduleVariableOptionalAttributes(t *testing.T) {
 11787  	m := testModuleInline(t, map[string]string{
 11788  		"main.tf": `
 11789  terraform {
 11790    experiments = [module_variable_optional_attrs]
 11791  }
 11792  
 11793  variable "in" {
 11794    type = object({
 11795  	required = string
 11796  	optional = optional(string)
 11797    })
 11798  }
 11799  
 11800  output "out" {
 11801    value = var.in
 11802  }
 11803  `})
 11804  
 11805  	ctx := testContext2(t, &ContextOpts{})
 11806  
 11807  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11808  		Mode: plans.NormalMode,
 11809  		SetVariables: InputValues{
 11810  			"in": &InputValue{
 11811  				Value: cty.MapVal(map[string]cty.Value{
 11812  					"required": cty.StringVal("boop"),
 11813  				}),
 11814  				SourceType: ValueFromCaller,
 11815  			},
 11816  		},
 11817  	})
 11818  	if diags.HasErrors() {
 11819  		t.Fatal(diags.ErrWithWarnings())
 11820  	}
 11821  
 11822  	state, diags := ctx.Apply(plan, m)
 11823  	if diags.HasErrors() {
 11824  		t.Fatal(diags.ErrWithWarnings())
 11825  	}
 11826  
 11827  	got := state.RootModule().OutputValues["out"].Value
 11828  	want := cty.ObjectVal(map[string]cty.Value{
 11829  		"required": cty.StringVal("boop"),
 11830  
 11831  		// Because "optional" was marked as optional, it got silently filled
 11832  		// in as a null value of string type rather than returning an error.
 11833  		"optional": cty.NullVal(cty.String),
 11834  	})
 11835  	if !want.RawEquals(got) {
 11836  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", got, want)
 11837  	}
 11838  }
 11839  
 11840  func TestContext2Apply_provisionerSensitive(t *testing.T) {
 11841  	m := testModule(t, "apply-provisioner-sensitive")
 11842  	p := testProvider("aws")
 11843  
 11844  	pr := testProvisioner()
 11845  	pr.ProvisionResourceFn = func(req provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
 11846  		if req.Config.ContainsMarked() {
 11847  			t.Fatalf("unexpectedly marked config value: %#v", req.Config)
 11848  		}
 11849  		command := req.Config.GetAttr("command")
 11850  		if command.IsMarked() {
 11851  			t.Fatalf("unexpectedly marked command argument: %#v", command.Marks())
 11852  		}
 11853  		req.UIOutput.Output(fmt.Sprintf("Executing: %q", command.AsString()))
 11854  		return
 11855  	}
 11856  	p.PlanResourceChangeFn = testDiffFn
 11857  	p.ApplyResourceChangeFn = testApplyFn
 11858  
 11859  	h := new(MockHook)
 11860  	ctx := testContext2(t, &ContextOpts{
 11861  		Hooks: []Hook{h},
 11862  		Providers: map[addrs.Provider]providers.Factory{
 11863  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
 11864  		},
 11865  		Provisioners: map[string]provisioners.Factory{
 11866  			"shell": testProvisionerFuncFixed(pr),
 11867  		},
 11868  	})
 11869  
 11870  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
 11871  		Mode: plans.NormalMode,
 11872  		SetVariables: InputValues{
 11873  			"password": &InputValue{
 11874  				Value:      cty.StringVal("secret"),
 11875  				SourceType: ValueFromCaller,
 11876  			},
 11877  		},
 11878  	})
 11879  	assertNoErrors(t, diags)
 11880  
 11881  	// "restart" provisioner
 11882  	pr.CloseCalled = false
 11883  
 11884  	state, diags := ctx.Apply(plan, m)
 11885  	if diags.HasErrors() {
 11886  		logDiagnostics(t, diags)
 11887  		t.Fatal("apply failed")
 11888  	}
 11889  
 11890  	actual := strings.TrimSpace(state.String())
 11891  	expected := strings.TrimSpace(testTerraformApplyProvisionerSensitiveStr)
 11892  	if actual != expected {
 11893  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
 11894  	}
 11895  
 11896  	// Verify apply was invoked
 11897  	if !pr.ProvisionResourceCalled {
 11898  		t.Fatalf("provisioner was not called on apply")
 11899  	}
 11900  
 11901  	// Verify output was suppressed
 11902  	if !h.ProvisionOutputCalled {
 11903  		t.Fatalf("ProvisionOutput hook not called")
 11904  	}
 11905  	if got, doNotWant := h.ProvisionOutputMessage, "secret"; strings.Contains(got, doNotWant) {
 11906  		t.Errorf("sensitive value %q included in output:\n%s", doNotWant, got)
 11907  	}
 11908  	if got, want := h.ProvisionOutputMessage, "output suppressed"; !strings.Contains(got, want) {
 11909  		t.Errorf("expected hook to be called with %q, but was:\n%s", want, got)
 11910  	}
 11911  }
 11912  
 11913  func TestContext2Apply_warnings(t *testing.T) {
 11914  	m := testModuleInline(t, map[string]string{
 11915  		"main.tf": `
 11916  resource "test_resource" "foo" {
 11917  }`,
 11918  	})
 11919  
 11920  	p := testProvider("test")
 11921  	p.PlanResourceChangeFn = testDiffFn
 11922  
 11923  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
 11924  		resp := testApplyFn(req)
 11925  
 11926  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warning"))
 11927  		return resp
 11928  	}
 11929  
 11930  	ctx := testContext2(t, &ContextOpts{
 11931  		Providers: map[addrs.Provider]providers.Factory{
 11932  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11933  		},
 11934  	})
 11935  
 11936  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11937  	assertNoErrors(t, diags)
 11938  
 11939  	state, diags := ctx.Apply(plan, m)
 11940  	if diags.HasErrors() {
 11941  		t.Fatalf("diags: %s", diags.Err())
 11942  	}
 11943  
 11944  	inst := state.ResourceInstance(mustResourceInstanceAddr("test_resource.foo"))
 11945  	if inst == nil {
 11946  		t.Fatal("missing 'test_resource.foo' in state:", state)
 11947  	}
 11948  }
 11949  
 11950  func TestContext2Apply_rpcDiagnostics(t *testing.T) {
 11951  	m := testModuleInline(t, map[string]string{
 11952  		"main.tf": `
 11953  resource "test_instance" "a" {
 11954  }
 11955  `,
 11956  	})
 11957  
 11958  	p := testProvider("test")
 11959  	p.PlanResourceChangeFn = testDiffFn
 11960  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 11961  		resp = testApplyFn(req)
 11962  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("don't frobble"))
 11963  		return resp
 11964  	}
 11965  
 11966  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
 11967  		ResourceTypes: map[string]*configschema.Block{
 11968  			"test_instance": {
 11969  				Attributes: map[string]*configschema.Attribute{
 11970  					"id": {Type: cty.String, Computed: true},
 11971  				},
 11972  			},
 11973  		},
 11974  	})
 11975  
 11976  	ctx := testContext2(t, &ContextOpts{
 11977  		Providers: map[addrs.Provider]providers.Factory{
 11978  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 11979  		},
 11980  	})
 11981  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 11982  	if diags.HasErrors() {
 11983  		t.Fatal(diags.Err())
 11984  	}
 11985  
 11986  	_, diags = ctx.Apply(plan, m)
 11987  	if diags.HasErrors() {
 11988  		t.Fatal(diags.Err())
 11989  	}
 11990  
 11991  	if len(diags) == 0 {
 11992  		t.Fatal("expected warnings")
 11993  	}
 11994  
 11995  	for _, d := range diags {
 11996  		des := d.Description().Summary
 11997  		if !strings.Contains(des, "frobble") {
 11998  			t.Fatalf(`expected frobble, got %q`, des)
 11999  		}
 12000  	}
 12001  }
 12002  
 12003  func TestContext2Apply_dataSensitive(t *testing.T) {
 12004  	m := testModule(t, "apply-data-sensitive")
 12005  	p := testProvider("null")
 12006  	p.PlanResourceChangeFn = testDiffFn
 12007  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
 12008  		// add the required id
 12009  		m := req.Config.AsValueMap()
 12010  		m["id"] = cty.StringVal("foo")
 12011  
 12012  		return providers.ReadDataSourceResponse{
 12013  			State: cty.ObjectVal(m),
 12014  		}
 12015  	}
 12016  
 12017  	ctx := testContext2(t, &ContextOpts{
 12018  		Providers: map[addrs.Provider]providers.Factory{
 12019  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
 12020  		},
 12021  	})
 12022  
 12023  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12024  	if diags.HasErrors() {
 12025  		t.Fatalf("diags: %s", diags.Err())
 12026  	} else {
 12027  		t.Logf(legacyDiffComparisonString(plan.Changes))
 12028  	}
 12029  
 12030  	state, diags := ctx.Apply(plan, m)
 12031  	assertNoErrors(t, diags)
 12032  
 12033  	addr := mustResourceInstanceAddr("data.null_data_source.testing")
 12034  
 12035  	dataSourceState := state.ResourceInstance(addr)
 12036  	pvms := dataSourceState.Current.AttrSensitivePaths
 12037  	if len(pvms) != 1 {
 12038  		t.Fatalf("expected 1 sensitive path, got %d", len(pvms))
 12039  	}
 12040  	pvm := pvms[0]
 12041  	if gotPath, wantPath := pvm.Path, cty.GetAttrPath("foo"); !gotPath.Equals(wantPath) {
 12042  		t.Errorf("wrong path\n got: %#v\nwant: %#v", gotPath, wantPath)
 12043  	}
 12044  	if gotMarks, wantMarks := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !gotMarks.Equal(wantMarks) {
 12045  		t.Errorf("wrong marks\n got: %#v\nwant: %#v", gotMarks, wantMarks)
 12046  	}
 12047  }
 12048  
 12049  func TestContext2Apply_errorRestorePrivateData(t *testing.T) {
 12050  	// empty config to remove our resource
 12051  	m := testModuleInline(t, map[string]string{
 12052  		"main.tf": "",
 12053  	})
 12054  
 12055  	p := simpleMockProvider()
 12056  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
 12057  		// we error during apply, which will trigger core to preserve the last
 12058  		// known state, including private data
 12059  		Diagnostics: tfdiags.Diagnostics(nil).Append(errors.New("oops")),
 12060  	}
 12061  
 12062  	addr := mustResourceInstanceAddr("test_object.a")
 12063  
 12064  	state := states.BuildState(func(s *states.SyncState) {
 12065  		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
 12066  			Status:    states.ObjectReady,
 12067  			AttrsJSON: []byte(`{"id":"foo"}`),
 12068  			Private:   []byte("private"),
 12069  		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
 12070  	})
 12071  
 12072  	ctx := testContext2(t, &ContextOpts{
 12073  		Providers: map[addrs.Provider]providers.Factory{
 12074  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12075  		},
 12076  	})
 12077  
 12078  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
 12079  	if diags.HasErrors() {
 12080  		t.Fatal(diags.Err())
 12081  	}
 12082  
 12083  	state, _ = ctx.Apply(plan, m)
 12084  	if string(state.ResourceInstance(addr).Current.Private) != "private" {
 12085  		t.Fatal("missing private data in state")
 12086  	}
 12087  }
 12088  
 12089  func TestContext2Apply_errorRestoreStatus(t *testing.T) {
 12090  	// empty config to remove our resource
 12091  	m := testModuleInline(t, map[string]string{
 12092  		"main.tf": "",
 12093  	})
 12094  
 12095  	p := simpleMockProvider()
 12096  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
 12097  		// We error during apply, but return the current object state.
 12098  		resp.Diagnostics = resp.Diagnostics.Append(errors.New("oops"))
 12099  		// return a warning too to make sure it isn't dropped
 12100  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("warned"))
 12101  		resp.NewState = req.PriorState
 12102  		resp.Private = req.PlannedPrivate
 12103  		return resp
 12104  	}
 12105  
 12106  	addr := mustResourceInstanceAddr("test_object.a")
 12107  
 12108  	state := states.BuildState(func(s *states.SyncState) {
 12109  		s.SetResourceInstanceCurrent(addr, &states.ResourceInstanceObjectSrc{
 12110  			Status:       states.ObjectTainted,
 12111  			AttrsJSON:    []byte(`{"test_string":"foo"}`),
 12112  			Private:      []byte("private"),
 12113  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_object.b")},
 12114  		}, mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`))
 12115  	})
 12116  
 12117  	ctx := testContext2(t, &ContextOpts{
 12118  		Providers: map[addrs.Provider]providers.Factory{
 12119  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12120  		},
 12121  	})
 12122  
 12123  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
 12124  	if diags.HasErrors() {
 12125  		t.Fatal(diags.Err())
 12126  	}
 12127  
 12128  	state, diags = ctx.Apply(plan, m)
 12129  
 12130  	errString := diags.ErrWithWarnings().Error()
 12131  	if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") {
 12132  		t.Fatalf("error missing expected info: %q", errString)
 12133  	}
 12134  
 12135  	if len(diags) != 2 {
 12136  		t.Fatalf("expected 1 error and 1 warning, got: %q", errString)
 12137  	}
 12138  
 12139  	res := state.ResourceInstance(addr)
 12140  	if res == nil {
 12141  		t.Fatal("resource was removed from state")
 12142  	}
 12143  
 12144  	if res.Current.Status != states.ObjectTainted {
 12145  		t.Fatal("resource should still be tainted in the state")
 12146  	}
 12147  
 12148  	if len(res.Current.Dependencies) != 1 || !res.Current.Dependencies[0].Equal(mustConfigResourceAddr("test_object.b")) {
 12149  		t.Fatalf("incorrect dependencies, got %q", res.Current.Dependencies)
 12150  	}
 12151  
 12152  	if string(res.Current.Private) != "private" {
 12153  		t.Fatalf("incorrect private data, got %q", res.Current.Private)
 12154  	}
 12155  }
 12156  
 12157  func TestContext2Apply_nonConformingResponse(t *testing.T) {
 12158  	// empty config to remove our resource
 12159  	m := testModuleInline(t, map[string]string{
 12160  		"main.tf": `
 12161  resource "test_object" "a" {
 12162    test_string = "x"
 12163  }
 12164  `,
 12165  	})
 12166  
 12167  	p := simpleMockProvider()
 12168  	respDiags := tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("warned"))
 12169  	respDiags = respDiags.Append(errors.New("oops"))
 12170  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{
 12171  		// Don't lose these diagnostics
 12172  		Diagnostics: respDiags,
 12173  		// This state is missing required attributes, and should produce an error
 12174  		NewState: cty.ObjectVal(map[string]cty.Value{
 12175  			"test_string": cty.StringVal("x"),
 12176  		}),
 12177  	}
 12178  
 12179  	ctx := testContext2(t, &ContextOpts{
 12180  		Providers: map[addrs.Provider]providers.Factory{
 12181  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12182  		},
 12183  	})
 12184  
 12185  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12186  	if diags.HasErrors() {
 12187  		t.Fatal(diags.Err())
 12188  	}
 12189  
 12190  	_, diags = ctx.Apply(plan, m)
 12191  	errString := diags.ErrWithWarnings().Error()
 12192  	if !strings.Contains(errString, "oops") || !strings.Contains(errString, "warned") {
 12193  		t.Fatalf("error missing expected info: %q", errString)
 12194  	}
 12195  
 12196  	// we should have more than the ones returned from the provider, and they
 12197  	// should not be coalesced into a single value
 12198  	if len(diags) < 3 {
 12199  		t.Fatalf("incorrect diagnostics, got %d values with %s", len(diags), diags.ErrWithWarnings())
 12200  	}
 12201  }
 12202  
 12203  func TestContext2Apply_nilResponse(t *testing.T) {
 12204  	// empty config to remove our resource
 12205  	m := testModuleInline(t, map[string]string{
 12206  		"main.tf": `
 12207  resource "test_object" "a" {
 12208  }
 12209  `,
 12210  	})
 12211  
 12212  	p := simpleMockProvider()
 12213  	p.ApplyResourceChangeResponse = &providers.ApplyResourceChangeResponse{}
 12214  
 12215  	ctx := testContext2(t, &ContextOpts{
 12216  		Providers: map[addrs.Provider]providers.Factory{
 12217  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
 12218  		},
 12219  	})
 12220  
 12221  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
 12222  	if diags.HasErrors() {
 12223  		t.Fatal(diags.Err())
 12224  	}
 12225  
 12226  	_, diags = ctx.Apply(plan, m)
 12227  	if !diags.HasErrors() {
 12228  		t.Fatal("expected and error")
 12229  	}
 12230  
 12231  	errString := diags.ErrWithWarnings().Error()
 12232  	if !strings.Contains(errString, "invalid nil value") {
 12233  		t.Fatalf("error missing expected info: %q", errString)
 12234  	}
 12235  }
 12236  
 12237  ////////////////////////////////////////////////////////////////////////////////
 12238  // NOTE: Due to the size of this file, new tests should be added to
 12239  // context_apply2_test.go.
 12240  ////////////////////////////////////////////////////////////////////////////////