github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/terraform/context_plan_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"reflect"
     9  	"sort"
    10  	"strings"
    11  	"sync"
    12  	"sync/atomic"
    13  	"testing"
    14  
    15  	"github.com/davecgh/go-spew/spew"
    16  	"github.com/google/go-cmp/cmp"
    17  	"github.com/zclconf/go-cty/cty"
    18  
    19  	"github.com/hashicorp/terraform/internal/addrs"
    20  	"github.com/hashicorp/terraform/internal/configs/configschema"
    21  	"github.com/hashicorp/terraform/internal/configs/hcl2shim"
    22  	"github.com/hashicorp/terraform/internal/lang/marks"
    23  	"github.com/hashicorp/terraform/internal/plans"
    24  	"github.com/hashicorp/terraform/internal/providers"
    25  	"github.com/hashicorp/terraform/internal/provisioners"
    26  	"github.com/hashicorp/terraform/internal/states"
    27  	"github.com/hashicorp/terraform/internal/tfdiags"
    28  )
    29  
    30  func TestContext2Plan_basic(t *testing.T) {
    31  	m := testModule(t, "plan-good")
    32  	p := testProvider("aws")
    33  	ctx := testContext2(t, &ContextOpts{
    34  		Providers: map[addrs.Provider]providers.Factory{
    35  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
    36  		},
    37  	})
    38  
    39  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
    40  	if diags.HasErrors() {
    41  		t.Fatalf("unexpected errors: %s", diags.Err())
    42  	}
    43  
    44  	if l := len(plan.Changes.Resources); l < 2 {
    45  		t.Fatalf("wrong number of resources %d; want fewer than two\n%s", l, spew.Sdump(plan.Changes.Resources))
    46  	}
    47  
    48  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
    49  	ty := schema.ImpliedType()
    50  	for _, r := range plan.Changes.Resources {
    51  		ric, err := r.Decode(ty)
    52  		if err != nil {
    53  			t.Fatal(err)
    54  		}
    55  
    56  		switch i := ric.Addr.String(); i {
    57  		case "aws_instance.bar":
    58  			foo := ric.After.GetAttr("foo").AsString()
    59  			if foo != "2" {
    60  				t.Fatalf("incorrect plan for 'bar': %#v", ric.After)
    61  			}
    62  		case "aws_instance.foo":
    63  			num, _ := ric.After.GetAttr("num").AsBigFloat().Int64()
    64  			if num != 2 {
    65  				t.Fatalf("incorrect plan for 'foo': %#v", ric.After)
    66  			}
    67  		default:
    68  			t.Fatal("unknown instance:", i)
    69  		}
    70  	}
    71  
    72  	if !p.ValidateProviderConfigCalled {
    73  		t.Fatal("provider config was not checked before Configure")
    74  	}
    75  
    76  }
    77  
    78  func TestContext2Plan_createBefore_deposed(t *testing.T) {
    79  	m := testModule(t, "plan-cbd")
    80  	p := testProvider("aws")
    81  	p.PlanResourceChangeFn = testDiffFn
    82  
    83  	state := states.NewState()
    84  	root := state.EnsureModule(addrs.RootModuleInstance)
    85  	root.SetResourceInstanceCurrent(
    86  		mustResourceInstanceAddr("aws_instance.foo").Resource,
    87  		&states.ResourceInstanceObjectSrc{
    88  			Status:    states.ObjectReady,
    89  			AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
    90  		},
    91  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
    92  	)
    93  	root.SetResourceInstanceDeposed(
    94  		mustResourceInstanceAddr("aws_instance.foo").Resource,
    95  		states.DeposedKey("00000001"),
    96  		&states.ResourceInstanceObjectSrc{
    97  			Status:    states.ObjectReady,
    98  			AttrsJSON: []byte(`{"id":"foo"}`),
    99  		},
   100  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   101  	)
   102  
   103  	ctx := testContext2(t, &ContextOpts{
   104  		Providers: map[addrs.Provider]providers.Factory{
   105  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   106  		},
   107  	})
   108  
   109  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   110  	if diags.HasErrors() {
   111  		t.Fatalf("unexpected errors: %s", diags.Err())
   112  	}
   113  
   114  	// the state should still show one deposed
   115  	expectedState := strings.TrimSpace(`
   116   aws_instance.foo: (1 deposed)
   117    ID = baz
   118    provider = provider["registry.terraform.io/hashicorp/aws"]
   119    type = aws_instance
   120    Deposed ID 1 = foo`)
   121  
   122  	if plan.PriorState.String() != expectedState {
   123  		t.Fatalf("\nexpected: %q\ngot:      %q\n", expectedState, plan.PriorState.String())
   124  	}
   125  
   126  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   127  	ty := schema.ImpliedType()
   128  
   129  	type InstanceGen struct {
   130  		Addr       string
   131  		DeposedKey states.DeposedKey
   132  	}
   133  	want := map[InstanceGen]bool{
   134  		{
   135  			Addr: "aws_instance.foo",
   136  		}: true,
   137  		{
   138  			Addr:       "aws_instance.foo",
   139  			DeposedKey: states.DeposedKey("00000001"),
   140  		}: true,
   141  	}
   142  	got := make(map[InstanceGen]bool)
   143  	changes := make(map[InstanceGen]*plans.ResourceInstanceChangeSrc)
   144  
   145  	for _, change := range plan.Changes.Resources {
   146  		k := InstanceGen{
   147  			Addr:       change.Addr.String(),
   148  			DeposedKey: change.DeposedKey,
   149  		}
   150  		got[k] = true
   151  		changes[k] = change
   152  	}
   153  	if !reflect.DeepEqual(got, want) {
   154  		t.Fatalf("wrong resource instance object changes in plan\ngot: %s\nwant: %s", spew.Sdump(got), spew.Sdump(want))
   155  	}
   156  
   157  	{
   158  		ric, err := changes[InstanceGen{Addr: "aws_instance.foo"}].Decode(ty)
   159  		if err != nil {
   160  			t.Fatal(err)
   161  		}
   162  
   163  		if got, want := ric.Action, plans.NoOp; got != want {
   164  			t.Errorf("current object change action is %s; want %s", got, want)
   165  		}
   166  
   167  		// the existing instance should only have an unchanged id
   168  		expected, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
   169  			"id":   cty.StringVal("baz"),
   170  			"type": cty.StringVal("aws_instance"),
   171  		}))
   172  		if err != nil {
   173  			t.Fatal(err)
   174  		}
   175  
   176  		checkVals(t, expected, ric.After)
   177  	}
   178  
   179  	{
   180  		ric, err := changes[InstanceGen{Addr: "aws_instance.foo", DeposedKey: states.DeposedKey("00000001")}].Decode(ty)
   181  		if err != nil {
   182  			t.Fatal(err)
   183  		}
   184  
   185  		if got, want := ric.Action, plans.Delete; got != want {
   186  			t.Errorf("deposed object change action is %s; want %s", got, want)
   187  		}
   188  	}
   189  }
   190  
   191  func TestContext2Plan_createBefore_maintainRoot(t *testing.T) {
   192  	m := testModule(t, "plan-cbd-maintain-root")
   193  	p := testProvider("aws")
   194  	ctx := testContext2(t, &ContextOpts{
   195  		Providers: map[addrs.Provider]providers.Factory{
   196  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   197  		},
   198  	})
   199  
   200  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   201  	if diags.HasErrors() {
   202  		t.Fatalf("unexpected errors: %s", diags.Err())
   203  	}
   204  
   205  	if !plan.PriorState.Empty() {
   206  		t.Fatal("expected empty prior state, got:", plan.PriorState)
   207  	}
   208  
   209  	if len(plan.Changes.Resources) != 4 {
   210  		t.Error("expected 4 resource in plan, got", len(plan.Changes.Resources))
   211  	}
   212  
   213  	for _, res := range plan.Changes.Resources {
   214  		// these should all be creates
   215  		if res.Action != plans.Create {
   216  			t.Fatalf("unexpected action %s for %s", res.Action, res.Addr.String())
   217  		}
   218  	}
   219  }
   220  
   221  func TestContext2Plan_emptyDiff(t *testing.T) {
   222  	m := testModule(t, "plan-empty")
   223  	p := testProvider("aws")
   224  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
   225  		resp.PlannedState = req.ProposedNewState
   226  		return resp
   227  	}
   228  
   229  	ctx := testContext2(t, &ContextOpts{
   230  		Providers: map[addrs.Provider]providers.Factory{
   231  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   232  		},
   233  	})
   234  
   235  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   236  	if diags.HasErrors() {
   237  		t.Fatalf("unexpected errors: %s", diags.Err())
   238  	}
   239  
   240  	if !plan.PriorState.Empty() {
   241  		t.Fatal("expected empty state, got:", plan.PriorState)
   242  	}
   243  
   244  	if len(plan.Changes.Resources) != 2 {
   245  		t.Error("expected 2 resource in plan, got", len(plan.Changes.Resources))
   246  	}
   247  
   248  	actions := map[string]plans.Action{}
   249  
   250  	for _, res := range plan.Changes.Resources {
   251  		actions[res.Addr.String()] = res.Action
   252  	}
   253  
   254  	expected := map[string]plans.Action{
   255  		"aws_instance.foo": plans.Create,
   256  		"aws_instance.bar": plans.Create,
   257  	}
   258  	if !cmp.Equal(expected, actions) {
   259  		t.Fatal(cmp.Diff(expected, actions))
   260  	}
   261  }
   262  
   263  func TestContext2Plan_escapedVar(t *testing.T) {
   264  	m := testModule(t, "plan-escaped-var")
   265  	p := testProvider("aws")
   266  	p.PlanResourceChangeFn = testDiffFn
   267  	ctx := testContext2(t, &ContextOpts{
   268  		Providers: map[addrs.Provider]providers.Factory{
   269  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   270  		},
   271  	})
   272  
   273  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   274  	if diags.HasErrors() {
   275  		t.Fatalf("unexpected errors: %s", diags.Err())
   276  	}
   277  
   278  	if len(plan.Changes.Resources) != 1 {
   279  		t.Error("expected 1 resource in plan, got", len(plan.Changes.Resources))
   280  	}
   281  
   282  	res := plan.Changes.Resources[0]
   283  	if res.Action != plans.Create {
   284  		t.Fatalf("expected resource creation, got %s", res.Action)
   285  	}
   286  
   287  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   288  	ty := schema.ImpliedType()
   289  
   290  	ric, err := res.Decode(ty)
   291  	if err != nil {
   292  		t.Fatal(err)
   293  	}
   294  
   295  	expected := objectVal(t, schema, map[string]cty.Value{
   296  		"id":   cty.UnknownVal(cty.String),
   297  		"foo":  cty.StringVal("bar-${baz}"),
   298  		"type": cty.UnknownVal(cty.String),
   299  	})
   300  
   301  	checkVals(t, expected, ric.After)
   302  }
   303  
   304  func TestContext2Plan_minimal(t *testing.T) {
   305  	m := testModule(t, "plan-empty")
   306  	p := testProvider("aws")
   307  	ctx := testContext2(t, &ContextOpts{
   308  		Providers: map[addrs.Provider]providers.Factory{
   309  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   310  		},
   311  	})
   312  
   313  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   314  	if diags.HasErrors() {
   315  		t.Fatalf("unexpected errors: %s", diags.Err())
   316  	}
   317  
   318  	if !plan.PriorState.Empty() {
   319  		t.Fatal("expected empty state, got:", plan.PriorState)
   320  	}
   321  
   322  	if len(plan.Changes.Resources) != 2 {
   323  		t.Error("expected 2 resource in plan, got", len(plan.Changes.Resources))
   324  	}
   325  
   326  	actions := map[string]plans.Action{}
   327  
   328  	for _, res := range plan.Changes.Resources {
   329  		actions[res.Addr.String()] = res.Action
   330  	}
   331  
   332  	expected := map[string]plans.Action{
   333  		"aws_instance.foo": plans.Create,
   334  		"aws_instance.bar": plans.Create,
   335  	}
   336  	if !cmp.Equal(expected, actions) {
   337  		t.Fatal(cmp.Diff(expected, actions))
   338  	}
   339  }
   340  
   341  func TestContext2Plan_modules(t *testing.T) {
   342  	m := testModule(t, "plan-modules")
   343  	p := testProvider("aws")
   344  	p.PlanResourceChangeFn = testDiffFn
   345  	ctx := testContext2(t, &ContextOpts{
   346  		Providers: map[addrs.Provider]providers.Factory{
   347  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   348  		},
   349  	})
   350  
   351  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   352  	if diags.HasErrors() {
   353  		t.Fatalf("unexpected errors: %s", diags.Err())
   354  	}
   355  
   356  	if len(plan.Changes.Resources) != 3 {
   357  		t.Error("expected 3 resource in plan, got", len(plan.Changes.Resources))
   358  	}
   359  
   360  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   361  	ty := schema.ImpliedType()
   362  
   363  	expectFoo := objectVal(t, schema, map[string]cty.Value{
   364  		"id":   cty.UnknownVal(cty.String),
   365  		"foo":  cty.StringVal("2"),
   366  		"type": cty.UnknownVal(cty.String),
   367  	})
   368  
   369  	expectNum := objectVal(t, schema, map[string]cty.Value{
   370  		"id":   cty.UnknownVal(cty.String),
   371  		"num":  cty.NumberIntVal(2),
   372  		"type": cty.UnknownVal(cty.String),
   373  	})
   374  
   375  	for _, res := range plan.Changes.Resources {
   376  		if res.Action != plans.Create {
   377  			t.Fatalf("expected resource creation, got %s", res.Action)
   378  		}
   379  		ric, err := res.Decode(ty)
   380  		if err != nil {
   381  			t.Fatal(err)
   382  		}
   383  
   384  		var expected cty.Value
   385  		switch i := ric.Addr.String(); i {
   386  		case "aws_instance.bar":
   387  			expected = expectFoo
   388  		case "aws_instance.foo":
   389  			expected = expectNum
   390  		case "module.child.aws_instance.foo":
   391  			expected = expectNum
   392  		default:
   393  			t.Fatal("unknown instance:", i)
   394  		}
   395  
   396  		checkVals(t, expected, ric.After)
   397  	}
   398  }
   399  func TestContext2Plan_moduleExpand(t *testing.T) {
   400  	// Test a smattering of plan expansion behavior
   401  	m := testModule(t, "plan-modules-expand")
   402  	p := testProvider("aws")
   403  	ctx := testContext2(t, &ContextOpts{
   404  		Providers: map[addrs.Provider]providers.Factory{
   405  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   406  		},
   407  	})
   408  
   409  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
   410  	if diags.HasErrors() {
   411  		t.Fatalf("unexpected errors: %s", diags.Err())
   412  	}
   413  
   414  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   415  	ty := schema.ImpliedType()
   416  
   417  	expected := map[string]struct{}{
   418  		`aws_instance.foo["a"]`:                          {},
   419  		`module.count_child[1].aws_instance.foo[0]`:      {},
   420  		`module.count_child[1].aws_instance.foo[1]`:      {},
   421  		`module.count_child[0].aws_instance.foo[0]`:      {},
   422  		`module.count_child[0].aws_instance.foo[1]`:      {},
   423  		`module.for_each_child["a"].aws_instance.foo[1]`: {},
   424  		`module.for_each_child["a"].aws_instance.foo[0]`: {},
   425  	}
   426  
   427  	for _, res := range plan.Changes.Resources {
   428  		if res.Action != plans.Create {
   429  			t.Fatalf("expected resource creation, got %s", res.Action)
   430  		}
   431  		ric, err := res.Decode(ty)
   432  		if err != nil {
   433  			t.Fatal(err)
   434  		}
   435  
   436  		_, ok := expected[ric.Addr.String()]
   437  		if !ok {
   438  			t.Fatal("unexpected resource:", ric.Addr.String())
   439  		}
   440  		delete(expected, ric.Addr.String())
   441  	}
   442  	for addr := range expected {
   443  		t.Error("missing resource", addr)
   444  	}
   445  }
   446  
   447  // GH-1475
   448  func TestContext2Plan_moduleCycle(t *testing.T) {
   449  	m := testModule(t, "plan-module-cycle")
   450  	p := testProvider("aws")
   451  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   452  		ResourceTypes: map[string]*configschema.Block{
   453  			"aws_instance": {
   454  				Attributes: map[string]*configschema.Attribute{
   455  					"id":         {Type: cty.String, Computed: true},
   456  					"some_input": {Type: cty.String, Optional: true},
   457  					"type":       {Type: cty.String, Computed: true},
   458  				},
   459  			},
   460  		},
   461  	})
   462  
   463  	ctx := testContext2(t, &ContextOpts{
   464  		Providers: map[addrs.Provider]providers.Factory{
   465  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   466  		},
   467  	})
   468  
   469  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   470  	if diags.HasErrors() {
   471  		t.Fatalf("unexpected errors: %s", diags.Err())
   472  	}
   473  
   474  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   475  	ty := schema.ImpliedType()
   476  
   477  	if len(plan.Changes.Resources) != 2 {
   478  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
   479  	}
   480  
   481  	for _, res := range plan.Changes.Resources {
   482  		if res.Action != plans.Create {
   483  			t.Fatalf("expected resource creation, got %s", res.Action)
   484  		}
   485  		ric, err := res.Decode(ty)
   486  		if err != nil {
   487  			t.Fatal(err)
   488  		}
   489  
   490  		var expected cty.Value
   491  		switch i := ric.Addr.String(); i {
   492  		case "aws_instance.b":
   493  			expected = objectVal(t, schema, map[string]cty.Value{
   494  				"id":   cty.UnknownVal(cty.String),
   495  				"type": cty.UnknownVal(cty.String),
   496  			})
   497  		case "aws_instance.c":
   498  			expected = objectVal(t, schema, map[string]cty.Value{
   499  				"id":         cty.UnknownVal(cty.String),
   500  				"some_input": cty.UnknownVal(cty.String),
   501  				"type":       cty.UnknownVal(cty.String),
   502  			})
   503  		default:
   504  			t.Fatal("unknown instance:", i)
   505  		}
   506  
   507  		checkVals(t, expected, ric.After)
   508  	}
   509  }
   510  
   511  func TestContext2Plan_moduleDeadlock(t *testing.T) {
   512  	testCheckDeadlock(t, func() {
   513  		m := testModule(t, "plan-module-deadlock")
   514  		p := testProvider("aws")
   515  		p.PlanResourceChangeFn = testDiffFn
   516  
   517  		ctx := testContext2(t, &ContextOpts{
   518  			Providers: map[addrs.Provider]providers.Factory{
   519  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   520  			},
   521  		})
   522  
   523  		plan, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   524  		if err != nil {
   525  			t.Fatalf("err: %s", err)
   526  		}
   527  
   528  		schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   529  		ty := schema.ImpliedType()
   530  
   531  		for _, res := range plan.Changes.Resources {
   532  			if res.Action != plans.Create {
   533  				t.Fatalf("expected resource creation, got %s", res.Action)
   534  			}
   535  			ric, err := res.Decode(ty)
   536  			if err != nil {
   537  				t.Fatal(err)
   538  			}
   539  
   540  			expected := objectVal(t, schema, map[string]cty.Value{
   541  				"id":   cty.UnknownVal(cty.String),
   542  				"type": cty.UnknownVal(cty.String),
   543  			})
   544  			switch i := ric.Addr.String(); i {
   545  			case "module.child.aws_instance.foo[0]":
   546  			case "module.child.aws_instance.foo[1]":
   547  			case "module.child.aws_instance.foo[2]":
   548  			default:
   549  				t.Fatal("unknown instance:", i)
   550  			}
   551  
   552  			checkVals(t, expected, ric.After)
   553  		}
   554  	})
   555  }
   556  
   557  func TestContext2Plan_moduleInput(t *testing.T) {
   558  	m := testModule(t, "plan-module-input")
   559  	p := testProvider("aws")
   560  	p.PlanResourceChangeFn = testDiffFn
   561  	ctx := testContext2(t, &ContextOpts{
   562  		Providers: map[addrs.Provider]providers.Factory{
   563  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   564  		},
   565  	})
   566  
   567  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   568  	if diags.HasErrors() {
   569  		t.Fatalf("unexpected errors: %s", diags.Err())
   570  	}
   571  
   572  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   573  	ty := schema.ImpliedType()
   574  
   575  	if len(plan.Changes.Resources) != 2 {
   576  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
   577  	}
   578  
   579  	for _, res := range plan.Changes.Resources {
   580  		if res.Action != plans.Create {
   581  			t.Fatalf("expected resource creation, got %s", res.Action)
   582  		}
   583  		ric, err := res.Decode(ty)
   584  		if err != nil {
   585  			t.Fatal(err)
   586  		}
   587  
   588  		var expected cty.Value
   589  
   590  		switch i := ric.Addr.String(); i {
   591  		case "aws_instance.bar":
   592  			expected = objectVal(t, schema, map[string]cty.Value{
   593  				"id":   cty.UnknownVal(cty.String),
   594  				"foo":  cty.StringVal("2"),
   595  				"type": cty.UnknownVal(cty.String),
   596  			})
   597  		case "module.child.aws_instance.foo":
   598  			expected = objectVal(t, schema, map[string]cty.Value{
   599  				"id":   cty.UnknownVal(cty.String),
   600  				"foo":  cty.StringVal("42"),
   601  				"type": cty.UnknownVal(cty.String),
   602  			})
   603  		default:
   604  			t.Fatal("unknown instance:", i)
   605  		}
   606  
   607  		checkVals(t, expected, ric.After)
   608  	}
   609  }
   610  
   611  func TestContext2Plan_moduleInputComputed(t *testing.T) {
   612  	m := testModule(t, "plan-module-input-computed")
   613  	p := testProvider("aws")
   614  	p.PlanResourceChangeFn = testDiffFn
   615  	ctx := testContext2(t, &ContextOpts{
   616  		Providers: map[addrs.Provider]providers.Factory{
   617  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   618  		},
   619  	})
   620  
   621  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   622  	if diags.HasErrors() {
   623  		t.Fatalf("unexpected errors: %s", diags.Err())
   624  	}
   625  
   626  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   627  	ty := schema.ImpliedType()
   628  
   629  	if len(plan.Changes.Resources) != 2 {
   630  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
   631  	}
   632  
   633  	for _, res := range plan.Changes.Resources {
   634  		if res.Action != plans.Create {
   635  			t.Fatalf("expected resource creation, got %s", res.Action)
   636  		}
   637  		ric, err := res.Decode(ty)
   638  		if err != nil {
   639  			t.Fatal(err)
   640  		}
   641  
   642  		switch i := ric.Addr.String(); i {
   643  		case "aws_instance.bar":
   644  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
   645  				"id":      cty.UnknownVal(cty.String),
   646  				"foo":     cty.UnknownVal(cty.String),
   647  				"type":    cty.UnknownVal(cty.String),
   648  				"compute": cty.StringVal("foo"),
   649  			}), ric.After)
   650  		case "module.child.aws_instance.foo":
   651  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
   652  				"id":   cty.UnknownVal(cty.String),
   653  				"foo":  cty.UnknownVal(cty.String),
   654  				"type": cty.UnknownVal(cty.String),
   655  			}), ric.After)
   656  		default:
   657  			t.Fatal("unknown instance:", i)
   658  		}
   659  	}
   660  }
   661  
   662  func TestContext2Plan_moduleInputFromVar(t *testing.T) {
   663  	m := testModule(t, "plan-module-input-var")
   664  	p := testProvider("aws")
   665  	p.PlanResourceChangeFn = testDiffFn
   666  	ctx := testContext2(t, &ContextOpts{
   667  		Providers: map[addrs.Provider]providers.Factory{
   668  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   669  		},
   670  	})
   671  
   672  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
   673  		Mode: plans.NormalMode,
   674  		SetVariables: InputValues{
   675  			"foo": &InputValue{
   676  				Value:      cty.StringVal("52"),
   677  				SourceType: ValueFromCaller,
   678  			},
   679  		},
   680  	})
   681  	if diags.HasErrors() {
   682  		t.Fatalf("unexpected errors: %s", diags.Err())
   683  	}
   684  
   685  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   686  	ty := schema.ImpliedType()
   687  
   688  	if len(plan.Changes.Resources) != 2 {
   689  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
   690  	}
   691  
   692  	for _, res := range plan.Changes.Resources {
   693  		if res.Action != plans.Create {
   694  			t.Fatalf("expected resource creation, got %s", res.Action)
   695  		}
   696  		ric, err := res.Decode(ty)
   697  		if err != nil {
   698  			t.Fatal(err)
   699  		}
   700  
   701  		switch i := ric.Addr.String(); i {
   702  		case "aws_instance.bar":
   703  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
   704  				"id":   cty.UnknownVal(cty.String),
   705  				"foo":  cty.StringVal("2"),
   706  				"type": cty.UnknownVal(cty.String),
   707  			}), ric.After)
   708  		case "module.child.aws_instance.foo":
   709  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
   710  				"id":   cty.UnknownVal(cty.String),
   711  				"foo":  cty.StringVal("52"),
   712  				"type": cty.UnknownVal(cty.String),
   713  			}), ric.After)
   714  		default:
   715  			t.Fatal("unknown instance:", i)
   716  		}
   717  	}
   718  }
   719  
   720  func TestContext2Plan_moduleMultiVar(t *testing.T) {
   721  	m := testModule(t, "plan-module-multi-var")
   722  	p := testProvider("aws")
   723  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   724  		ResourceTypes: map[string]*configschema.Block{
   725  			"aws_instance": {
   726  				Attributes: map[string]*configschema.Attribute{
   727  					"id":  {Type: cty.String, Computed: true},
   728  					"foo": {Type: cty.String, Optional: true},
   729  					"baz": {Type: cty.String, Optional: true},
   730  				},
   731  			},
   732  		},
   733  	})
   734  
   735  	ctx := testContext2(t, &ContextOpts{
   736  		Providers: map[addrs.Provider]providers.Factory{
   737  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   738  		},
   739  	})
   740  
   741  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
   742  	if diags.HasErrors() {
   743  		t.Fatalf("unexpected errors: %s", diags.Err())
   744  	}
   745  
   746  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   747  	ty := schema.ImpliedType()
   748  
   749  	if len(plan.Changes.Resources) != 5 {
   750  		t.Fatal("expected 5 changes, got", len(plan.Changes.Resources))
   751  	}
   752  
   753  	for _, res := range plan.Changes.Resources {
   754  		if res.Action != plans.Create {
   755  			t.Fatalf("expected resource creation, got %s", res.Action)
   756  		}
   757  
   758  		ric, err := res.Decode(ty)
   759  		if err != nil {
   760  			t.Fatal(err)
   761  		}
   762  
   763  		switch i := ric.Addr.String(); i {
   764  		case "aws_instance.parent[0]":
   765  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
   766  				"id": cty.UnknownVal(cty.String),
   767  			}), ric.After)
   768  		case "aws_instance.parent[1]":
   769  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
   770  				"id": cty.UnknownVal(cty.String),
   771  			}), ric.After)
   772  		case "module.child.aws_instance.bar[0]":
   773  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
   774  				"id":  cty.UnknownVal(cty.String),
   775  				"baz": cty.StringVal("baz"),
   776  			}), ric.After)
   777  		case "module.child.aws_instance.bar[1]":
   778  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
   779  				"id":  cty.UnknownVal(cty.String),
   780  				"baz": cty.StringVal("baz"),
   781  			}), ric.After)
   782  		case "module.child.aws_instance.foo":
   783  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
   784  				"id":  cty.UnknownVal(cty.String),
   785  				"foo": cty.StringVal("baz,baz"),
   786  			}), ric.After)
   787  		default:
   788  			t.Fatal("unknown instance:", i)
   789  		}
   790  	}
   791  }
   792  
   793  func TestContext2Plan_moduleOrphans(t *testing.T) {
   794  	m := testModule(t, "plan-modules-remove")
   795  	p := testProvider("aws")
   796  	p.PlanResourceChangeFn = testDiffFn
   797  
   798  	state := states.NewState()
   799  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
   800  	child.SetResourceInstanceCurrent(
   801  		mustResourceInstanceAddr("aws_instance.foo").Resource,
   802  		&states.ResourceInstanceObjectSrc{
   803  			Status:    states.ObjectReady,
   804  			AttrsJSON: []byte(`{"id":"baz"}`),
   805  		},
   806  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   807  	)
   808  
   809  	ctx := testContext2(t, &ContextOpts{
   810  		Providers: map[addrs.Provider]providers.Factory{
   811  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   812  		},
   813  	})
   814  
   815  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   816  	if diags.HasErrors() {
   817  		t.Fatalf("unexpected errors: %s", diags.Err())
   818  	}
   819  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   820  	ty := schema.ImpliedType()
   821  
   822  	if len(plan.Changes.Resources) != 2 {
   823  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
   824  	}
   825  
   826  	for _, res := range plan.Changes.Resources {
   827  
   828  		ric, err := res.Decode(ty)
   829  		if err != nil {
   830  			t.Fatal(err)
   831  		}
   832  
   833  		switch i := ric.Addr.String(); i {
   834  		case "aws_instance.foo":
   835  			if res.Action != plans.Create {
   836  				t.Fatalf("expected resource creation, got %s", res.Action)
   837  			}
   838  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
   839  				"id":   cty.UnknownVal(cty.String),
   840  				"num":  cty.NumberIntVal(2),
   841  				"type": cty.UnknownVal(cty.String),
   842  			}), ric.After)
   843  		case "module.child.aws_instance.foo":
   844  			if res.Action != plans.Delete {
   845  				t.Fatalf("expected resource delete, got %s", res.Action)
   846  			}
   847  		default:
   848  			t.Fatal("unknown instance:", i)
   849  		}
   850  	}
   851  
   852  	expectedState := `<no state>
   853  module.child:
   854    aws_instance.foo:
   855      ID = baz
   856      provider = provider["registry.terraform.io/hashicorp/aws"]`
   857  
   858  	if plan.PriorState.String() != expectedState {
   859  		t.Fatalf("\nexpected state: %q\n\ngot: %q", expectedState, plan.PriorState.String())
   860  	}
   861  }
   862  
   863  // https://github.com/hashicorp/terraform/issues/3114
   864  func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
   865  	m := testModule(t, "plan-modules-remove-provisioners")
   866  	p := testProvider("aws")
   867  	p.PlanResourceChangeFn = testDiffFn
   868  	pr := testProvisioner()
   869  
   870  	state := states.NewState()
   871  	root := state.EnsureModule(addrs.RootModuleInstance)
   872  	root.SetResourceInstanceCurrent(
   873  		mustResourceInstanceAddr("aws_instance.top").Resource,
   874  		&states.ResourceInstanceObjectSrc{
   875  			Status:    states.ObjectReady,
   876  			AttrsJSON: []byte(`{"id":"top","type":"aws_instance"}`),
   877  		},
   878  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   879  	)
   880  	child1 := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child1", addrs.NoKey))
   881  	child1.SetResourceInstanceCurrent(
   882  		mustResourceInstanceAddr("aws_instance.foo").Resource,
   883  		&states.ResourceInstanceObjectSrc{
   884  			Status:    states.ObjectReady,
   885  			AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
   886  		},
   887  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   888  	)
   889  	child2 := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child2", addrs.NoKey))
   890  	child2.SetResourceInstanceCurrent(
   891  		mustResourceInstanceAddr("aws_instance.foo").Resource,
   892  		&states.ResourceInstanceObjectSrc{
   893  			Status:    states.ObjectReady,
   894  			AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
   895  		},
   896  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
   897  	)
   898  
   899  	ctx := testContext2(t, &ContextOpts{
   900  		Providers: map[addrs.Provider]providers.Factory{
   901  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   902  		},
   903  		Provisioners: map[string]provisioners.Factory{
   904  			"shell": testProvisionerFuncFixed(pr),
   905  		},
   906  	})
   907  
   908  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
   909  	if diags.HasErrors() {
   910  		t.Fatalf("unexpected errors: %s", diags.Err())
   911  	}
   912  
   913  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
   914  	ty := schema.ImpliedType()
   915  
   916  	if len(plan.Changes.Resources) != 3 {
   917  		t.Error("expected 3 planned resources, got", len(plan.Changes.Resources))
   918  	}
   919  
   920  	for _, res := range plan.Changes.Resources {
   921  
   922  		ric, err := res.Decode(ty)
   923  		if err != nil {
   924  			t.Fatal(err)
   925  		}
   926  
   927  		switch i := ric.Addr.String(); i {
   928  		case "module.parent.module.child1.aws_instance.foo":
   929  			if res.Action != plans.Delete {
   930  				t.Fatalf("expected resource Delete, got %s", res.Action)
   931  			}
   932  		case "module.parent.module.child2.aws_instance.foo":
   933  			if res.Action != plans.Delete {
   934  				t.Fatalf("expected resource Delete, got %s", res.Action)
   935  			}
   936  		case "aws_instance.top":
   937  			if res.Action != plans.NoOp {
   938  				t.Fatalf("expected no changes, got %s", res.Action)
   939  			}
   940  		default:
   941  			t.Fatalf("unknown instance: %s\nafter: %#v", i, hcl2shim.ConfigValueFromHCL2(ric.After))
   942  		}
   943  	}
   944  
   945  	expectedState := `aws_instance.top:
   946    ID = top
   947    provider = provider["registry.terraform.io/hashicorp/aws"]
   948    type = aws_instance
   949  
   950  module.parent.child1:
   951    aws_instance.foo:
   952      ID = baz
   953      provider = provider["registry.terraform.io/hashicorp/aws"]
   954      type = aws_instance
   955  module.parent.child2:
   956    aws_instance.foo:
   957      ID = baz
   958      provider = provider["registry.terraform.io/hashicorp/aws"]
   959      type = aws_instance`
   960  
   961  	if expectedState != plan.PriorState.String() {
   962  		t.Fatalf("\nexpect state:\n%s\n\ngot state:\n%s\n", expectedState, plan.PriorState.String())
   963  	}
   964  }
   965  
   966  func TestContext2Plan_moduleProviderInherit(t *testing.T) {
   967  	var l sync.Mutex
   968  	var calls []string
   969  
   970  	m := testModule(t, "plan-module-provider-inherit")
   971  	ctx := testContext2(t, &ContextOpts{
   972  		Providers: map[addrs.Provider]providers.Factory{
   973  			addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
   974  				l.Lock()
   975  				defer l.Unlock()
   976  
   977  				p := testProvider("aws")
   978  				p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
   979  					Provider: &configschema.Block{
   980  						Attributes: map[string]*configschema.Attribute{
   981  							"from": {Type: cty.String, Optional: true},
   982  						},
   983  					},
   984  					ResourceTypes: map[string]*configschema.Block{
   985  						"aws_instance": {
   986  							Attributes: map[string]*configschema.Attribute{
   987  								"from": {Type: cty.String, Optional: true},
   988  							},
   989  						},
   990  					},
   991  				})
   992  				p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
   993  					from := req.Config.GetAttr("from")
   994  					if from.IsNull() || from.AsString() != "root" {
   995  						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("not root"))
   996  					}
   997  
   998  					return
   999  				}
  1000  				p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  1001  					from := req.Config.GetAttr("from").AsString()
  1002  
  1003  					l.Lock()
  1004  					defer l.Unlock()
  1005  					calls = append(calls, from)
  1006  					return testDiffFn(req)
  1007  				}
  1008  				return p, nil
  1009  			},
  1010  		},
  1011  	})
  1012  
  1013  	_, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1014  	if err != nil {
  1015  		t.Fatalf("err: %s", err)
  1016  	}
  1017  
  1018  	actual := calls
  1019  	sort.Strings(actual)
  1020  	expected := []string{"child", "root"}
  1021  	if !reflect.DeepEqual(actual, expected) {
  1022  		t.Fatalf("bad: %#v", actual)
  1023  	}
  1024  }
  1025  
  1026  // This tests (for GH-11282) that deeply nested modules properly inherit
  1027  // configuration.
  1028  func TestContext2Plan_moduleProviderInheritDeep(t *testing.T) {
  1029  	var l sync.Mutex
  1030  
  1031  	m := testModule(t, "plan-module-provider-inherit-deep")
  1032  	ctx := testContext2(t, &ContextOpts{
  1033  		Providers: map[addrs.Provider]providers.Factory{
  1034  			addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
  1035  				l.Lock()
  1036  				defer l.Unlock()
  1037  
  1038  				var from string
  1039  				p := testProvider("aws")
  1040  
  1041  				p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1042  					Provider: &configschema.Block{
  1043  						Attributes: map[string]*configschema.Attribute{
  1044  							"from": {Type: cty.String, Optional: true},
  1045  						},
  1046  					},
  1047  					ResourceTypes: map[string]*configschema.Block{
  1048  						"aws_instance": {
  1049  							Attributes: map[string]*configschema.Attribute{},
  1050  						},
  1051  					},
  1052  				})
  1053  
  1054  				p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  1055  					v := req.Config.GetAttr("from")
  1056  					if v.IsNull() || v.AsString() != "root" {
  1057  						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("not root"))
  1058  					}
  1059  					from = v.AsString()
  1060  
  1061  					return
  1062  				}
  1063  
  1064  				p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  1065  					if from != "root" {
  1066  						resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("bad resource"))
  1067  						return
  1068  					}
  1069  
  1070  					return testDiffFn(req)
  1071  				}
  1072  				return p, nil
  1073  			},
  1074  		},
  1075  	})
  1076  
  1077  	_, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1078  	if err != nil {
  1079  		t.Fatalf("err: %s", err)
  1080  	}
  1081  }
  1082  
  1083  func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) {
  1084  	var l sync.Mutex
  1085  	var calls []string
  1086  
  1087  	m := testModule(t, "plan-module-provider-defaults-var")
  1088  	ctx := testContext2(t, &ContextOpts{
  1089  		Providers: map[addrs.Provider]providers.Factory{
  1090  			addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
  1091  				l.Lock()
  1092  				defer l.Unlock()
  1093  
  1094  				p := testProvider("aws")
  1095  				p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1096  					Provider: &configschema.Block{
  1097  						Attributes: map[string]*configschema.Attribute{
  1098  							"to":   {Type: cty.String, Optional: true},
  1099  							"from": {Type: cty.String, Optional: true},
  1100  						},
  1101  					},
  1102  					ResourceTypes: map[string]*configschema.Block{
  1103  						"aws_instance": {
  1104  							Attributes: map[string]*configschema.Attribute{
  1105  								"from": {Type: cty.String, Optional: true},
  1106  							},
  1107  						},
  1108  					},
  1109  				})
  1110  				p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  1111  					var buf bytes.Buffer
  1112  					from := req.Config.GetAttr("from")
  1113  					if !from.IsNull() {
  1114  						buf.WriteString(from.AsString() + "\n")
  1115  					}
  1116  					to := req.Config.GetAttr("to")
  1117  					if !to.IsNull() {
  1118  						buf.WriteString(to.AsString() + "\n")
  1119  					}
  1120  
  1121  					l.Lock()
  1122  					defer l.Unlock()
  1123  					calls = append(calls, buf.String())
  1124  					return
  1125  				}
  1126  
  1127  				return p, nil
  1128  			},
  1129  		},
  1130  	})
  1131  
  1132  	_, err := ctx.Plan(m, states.NewState(), &PlanOpts{
  1133  		Mode: plans.NormalMode,
  1134  		SetVariables: InputValues{
  1135  			"foo": &InputValue{
  1136  				Value:      cty.StringVal("root"),
  1137  				SourceType: ValueFromCaller,
  1138  			},
  1139  		},
  1140  	})
  1141  	if err != nil {
  1142  		t.Fatalf("err: %s", err)
  1143  	}
  1144  
  1145  	expected := []string{
  1146  		"child\nchild\n",
  1147  		"root\n",
  1148  	}
  1149  	sort.Strings(calls)
  1150  	if !reflect.DeepEqual(calls, expected) {
  1151  		t.Fatalf("expected:\n%#v\ngot:\n%#v\n", expected, calls)
  1152  	}
  1153  }
  1154  
  1155  func TestContext2Plan_moduleProviderVar(t *testing.T) {
  1156  	m := testModule(t, "plan-module-provider-var")
  1157  	p := testProvider("aws")
  1158  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1159  		Provider: &configschema.Block{
  1160  			Attributes: map[string]*configschema.Attribute{
  1161  				"value": {Type: cty.String, Optional: true},
  1162  			},
  1163  		},
  1164  		ResourceTypes: map[string]*configschema.Block{
  1165  			"aws_instance": {
  1166  				Attributes: map[string]*configschema.Attribute{
  1167  					"value": {Type: cty.String, Optional: true},
  1168  				},
  1169  			},
  1170  		},
  1171  	})
  1172  
  1173  	ctx := testContext2(t, &ContextOpts{
  1174  		Providers: map[addrs.Provider]providers.Factory{
  1175  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1176  		},
  1177  	})
  1178  
  1179  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  1180  	if diags.HasErrors() {
  1181  		t.Fatalf("unexpected errors: %s", diags.Err())
  1182  	}
  1183  
  1184  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  1185  	ty := schema.ImpliedType()
  1186  
  1187  	if len(plan.Changes.Resources) != 1 {
  1188  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  1189  	}
  1190  
  1191  	for _, res := range plan.Changes.Resources {
  1192  		if res.Action != plans.Create {
  1193  			t.Fatalf("expected resource creation, got %s", res.Action)
  1194  		}
  1195  		ric, err := res.Decode(ty)
  1196  		if err != nil {
  1197  			t.Fatal(err)
  1198  		}
  1199  
  1200  		switch i := ric.Addr.String(); i {
  1201  		case "module.child.aws_instance.test":
  1202  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  1203  				"value": cty.StringVal("hello"),
  1204  			}), ric.After)
  1205  		default:
  1206  			t.Fatal("unknown instance:", i)
  1207  		}
  1208  	}
  1209  }
  1210  
  1211  func TestContext2Plan_moduleVar(t *testing.T) {
  1212  	m := testModule(t, "plan-module-var")
  1213  	p := testProvider("aws")
  1214  	p.PlanResourceChangeFn = testDiffFn
  1215  	ctx := testContext2(t, &ContextOpts{
  1216  		Providers: map[addrs.Provider]providers.Factory{
  1217  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1218  		},
  1219  	})
  1220  
  1221  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1222  	if diags.HasErrors() {
  1223  		t.Fatalf("unexpected errors: %s", diags.Err())
  1224  	}
  1225  
  1226  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  1227  	ty := schema.ImpliedType()
  1228  
  1229  	if len(plan.Changes.Resources) != 2 {
  1230  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  1231  	}
  1232  
  1233  	for _, res := range plan.Changes.Resources {
  1234  		if res.Action != plans.Create {
  1235  			t.Fatalf("expected resource creation, got %s", res.Action)
  1236  		}
  1237  		ric, err := res.Decode(ty)
  1238  		if err != nil {
  1239  			t.Fatal(err)
  1240  		}
  1241  
  1242  		var expected cty.Value
  1243  
  1244  		switch i := ric.Addr.String(); i {
  1245  		case "aws_instance.bar":
  1246  			expected = objectVal(t, schema, map[string]cty.Value{
  1247  				"id":   cty.UnknownVal(cty.String),
  1248  				"foo":  cty.StringVal("2"),
  1249  				"type": cty.UnknownVal(cty.String),
  1250  			})
  1251  		case "module.child.aws_instance.foo":
  1252  			expected = objectVal(t, schema, map[string]cty.Value{
  1253  				"id":   cty.UnknownVal(cty.String),
  1254  				"num":  cty.NumberIntVal(2),
  1255  				"type": cty.UnknownVal(cty.String),
  1256  			})
  1257  		default:
  1258  			t.Fatal("unknown instance:", i)
  1259  		}
  1260  
  1261  		checkVals(t, expected, ric.After)
  1262  	}
  1263  }
  1264  
  1265  func TestContext2Plan_moduleVarWrongTypeBasic(t *testing.T) {
  1266  	m := testModule(t, "plan-module-wrong-var-type")
  1267  	p := testProvider("aws")
  1268  	ctx := testContext2(t, &ContextOpts{
  1269  		Providers: map[addrs.Provider]providers.Factory{
  1270  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1271  		},
  1272  	})
  1273  
  1274  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1275  	if !diags.HasErrors() {
  1276  		t.Fatalf("succeeded; want errors")
  1277  	}
  1278  }
  1279  
  1280  func TestContext2Plan_moduleVarWrongTypeNested(t *testing.T) {
  1281  	m := testModule(t, "plan-module-wrong-var-type-nested")
  1282  	p := testProvider("null")
  1283  	ctx := testContext2(t, &ContextOpts{
  1284  		Providers: map[addrs.Provider]providers.Factory{
  1285  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  1286  		},
  1287  	})
  1288  
  1289  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1290  	if !diags.HasErrors() {
  1291  		t.Fatalf("succeeded; want errors")
  1292  	}
  1293  }
  1294  
  1295  func TestContext2Plan_moduleVarWithDefaultValue(t *testing.T) {
  1296  	m := testModule(t, "plan-module-var-with-default-value")
  1297  	p := testProvider("null")
  1298  	ctx := testContext2(t, &ContextOpts{
  1299  		Providers: map[addrs.Provider]providers.Factory{
  1300  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  1301  		},
  1302  	})
  1303  
  1304  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1305  	if diags.HasErrors() {
  1306  		t.Fatalf("unexpected errors: %s", diags.Err())
  1307  	}
  1308  }
  1309  
  1310  func TestContext2Plan_moduleVarComputed(t *testing.T) {
  1311  	m := testModule(t, "plan-module-var-computed")
  1312  	p := testProvider("aws")
  1313  	p.PlanResourceChangeFn = testDiffFn
  1314  	ctx := testContext2(t, &ContextOpts{
  1315  		Providers: map[addrs.Provider]providers.Factory{
  1316  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1317  		},
  1318  	})
  1319  
  1320  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1321  	if diags.HasErrors() {
  1322  		t.Fatalf("unexpected errors: %s", diags.Err())
  1323  	}
  1324  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  1325  	ty := schema.ImpliedType()
  1326  
  1327  	if len(plan.Changes.Resources) != 2 {
  1328  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  1329  	}
  1330  
  1331  	for _, res := range plan.Changes.Resources {
  1332  		if res.Action != plans.Create {
  1333  			t.Fatalf("expected resource creation, got %s", res.Action)
  1334  		}
  1335  		ric, err := res.Decode(ty)
  1336  		if err != nil {
  1337  			t.Fatal(err)
  1338  		}
  1339  
  1340  		switch i := ric.Addr.String(); i {
  1341  		case "aws_instance.bar":
  1342  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  1343  				"id":   cty.UnknownVal(cty.String),
  1344  				"foo":  cty.UnknownVal(cty.String),
  1345  				"type": cty.UnknownVal(cty.String),
  1346  			}), ric.After)
  1347  		case "module.child.aws_instance.foo":
  1348  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  1349  				"id":      cty.UnknownVal(cty.String),
  1350  				"foo":     cty.UnknownVal(cty.String),
  1351  				"type":    cty.UnknownVal(cty.String),
  1352  				"compute": cty.StringVal("foo"),
  1353  			}), ric.After)
  1354  		default:
  1355  			t.Fatal("unknown instance:", i)
  1356  		}
  1357  	}
  1358  }
  1359  
  1360  func TestContext2Plan_preventDestroy_bad(t *testing.T) {
  1361  	m := testModule(t, "plan-prevent-destroy-bad")
  1362  	p := testProvider("aws")
  1363  	p.PlanResourceChangeFn = testDiffFn
  1364  	state := states.NewState()
  1365  	root := state.EnsureModule(addrs.RootModuleInstance)
  1366  	root.SetResourceInstanceCurrent(
  1367  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1368  		&states.ResourceInstanceObjectSrc{
  1369  			Status:    states.ObjectReady,
  1370  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  1371  		},
  1372  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1373  	)
  1374  
  1375  	ctx := testContext2(t, &ContextOpts{
  1376  		Providers: map[addrs.Provider]providers.Factory{
  1377  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1378  		},
  1379  	})
  1380  
  1381  	plan, err := ctx.Plan(m, state, DefaultPlanOpts)
  1382  
  1383  	expectedErr := "aws_instance.foo has lifecycle.prevent_destroy"
  1384  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
  1385  		if plan != nil {
  1386  			t.Logf(legacyDiffComparisonString(plan.Changes))
  1387  		}
  1388  		t.Fatalf("expected err would contain %q\nerr: %s", expectedErr, err)
  1389  	}
  1390  }
  1391  
  1392  func TestContext2Plan_preventDestroy_good(t *testing.T) {
  1393  	m := testModule(t, "plan-prevent-destroy-good")
  1394  	p := testProvider("aws")
  1395  	p.PlanResourceChangeFn = testDiffFn
  1396  
  1397  	state := states.NewState()
  1398  	root := state.EnsureModule(addrs.RootModuleInstance)
  1399  	root.SetResourceInstanceCurrent(
  1400  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1401  		&states.ResourceInstanceObjectSrc{
  1402  			Status:    states.ObjectReady,
  1403  			AttrsJSON: []byte(`{"id":"i-abc123","type":"aws_instance"}`),
  1404  		},
  1405  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1406  	)
  1407  
  1408  	ctx := testContext2(t, &ContextOpts{
  1409  		Providers: map[addrs.Provider]providers.Factory{
  1410  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1411  		},
  1412  	})
  1413  
  1414  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1415  	if diags.HasErrors() {
  1416  		t.Fatalf("unexpected errors: %s", diags.Err())
  1417  	}
  1418  
  1419  	if !plan.Changes.Empty() {
  1420  		t.Fatalf("expected no changes, got %#v\n", plan.Changes)
  1421  	}
  1422  }
  1423  
  1424  func TestContext2Plan_preventDestroy_countBad(t *testing.T) {
  1425  	m := testModule(t, "plan-prevent-destroy-count-bad")
  1426  	p := testProvider("aws")
  1427  
  1428  	state := states.NewState()
  1429  	root := state.EnsureModule(addrs.RootModuleInstance)
  1430  	root.SetResourceInstanceCurrent(
  1431  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  1432  		&states.ResourceInstanceObjectSrc{
  1433  			Status:    states.ObjectReady,
  1434  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  1435  		},
  1436  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1437  	)
  1438  	root.SetResourceInstanceCurrent(
  1439  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  1440  		&states.ResourceInstanceObjectSrc{
  1441  			Status:    states.ObjectReady,
  1442  			AttrsJSON: []byte(`{"id":"i-abc345"}`),
  1443  		},
  1444  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1445  	)
  1446  
  1447  	ctx := testContext2(t, &ContextOpts{
  1448  		Providers: map[addrs.Provider]providers.Factory{
  1449  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1450  		},
  1451  	})
  1452  
  1453  	plan, err := ctx.Plan(m, state, DefaultPlanOpts)
  1454  
  1455  	expectedErr := "aws_instance.foo[1] has lifecycle.prevent_destroy"
  1456  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
  1457  		if plan != nil {
  1458  			t.Logf(legacyDiffComparisonString(plan.Changes))
  1459  		}
  1460  		t.Fatalf("expected err would contain %q\nerr: %s", expectedErr, err)
  1461  	}
  1462  }
  1463  
  1464  func TestContext2Plan_preventDestroy_countGood(t *testing.T) {
  1465  	m := testModule(t, "plan-prevent-destroy-count-good")
  1466  	p := testProvider("aws")
  1467  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1468  		ResourceTypes: map[string]*configschema.Block{
  1469  			"aws_instance": {
  1470  				Attributes: map[string]*configschema.Attribute{
  1471  					"current": {Type: cty.String, Optional: true},
  1472  					"id":      {Type: cty.String, Computed: true},
  1473  				},
  1474  			},
  1475  		},
  1476  	})
  1477  
  1478  	state := states.NewState()
  1479  	root := state.EnsureModule(addrs.RootModuleInstance)
  1480  	root.SetResourceInstanceCurrent(
  1481  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  1482  		&states.ResourceInstanceObjectSrc{
  1483  			Status:    states.ObjectReady,
  1484  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  1485  		},
  1486  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1487  	)
  1488  	root.SetResourceInstanceCurrent(
  1489  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  1490  		&states.ResourceInstanceObjectSrc{
  1491  			Status:    states.ObjectReady,
  1492  			AttrsJSON: []byte(`{"id":"i-abc345"}`),
  1493  		},
  1494  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1495  	)
  1496  
  1497  	ctx := testContext2(t, &ContextOpts{
  1498  		Providers: map[addrs.Provider]providers.Factory{
  1499  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1500  		},
  1501  	})
  1502  
  1503  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1504  	if diags.HasErrors() {
  1505  		t.Fatalf("unexpected errors: %s", diags.Err())
  1506  	}
  1507  
  1508  	if plan.Changes.Empty() {
  1509  		t.Fatalf("Expected non-empty plan, got %s", legacyDiffComparisonString(plan.Changes))
  1510  	}
  1511  }
  1512  
  1513  func TestContext2Plan_preventDestroy_countGoodNoChange(t *testing.T) {
  1514  	m := testModule(t, "plan-prevent-destroy-count-good")
  1515  	p := testProvider("aws")
  1516  	p.PlanResourceChangeFn = testDiffFn
  1517  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1518  		ResourceTypes: map[string]*configschema.Block{
  1519  			"aws_instance": {
  1520  				Attributes: map[string]*configschema.Attribute{
  1521  					"current": {Type: cty.String, Optional: true},
  1522  					"type":    {Type: cty.String, Optional: true, Computed: true},
  1523  					"id":      {Type: cty.String, Computed: true},
  1524  				},
  1525  			},
  1526  		},
  1527  	})
  1528  
  1529  	state := states.NewState()
  1530  	root := state.EnsureModule(addrs.RootModuleInstance)
  1531  	root.SetResourceInstanceCurrent(
  1532  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  1533  		&states.ResourceInstanceObjectSrc{
  1534  			Status:    states.ObjectReady,
  1535  			AttrsJSON: []byte(`{"id":"i-abc123","current":"0","type":"aws_instance"}`),
  1536  		},
  1537  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1538  	)
  1539  
  1540  	ctx := testContext2(t, &ContextOpts{
  1541  		Providers: map[addrs.Provider]providers.Factory{
  1542  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1543  		},
  1544  	})
  1545  
  1546  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1547  	if diags.HasErrors() {
  1548  		t.Fatalf("unexpected errors: %s", diags.Err())
  1549  	}
  1550  
  1551  	if !plan.Changes.Empty() {
  1552  		t.Fatalf("Expected empty plan, got %s", legacyDiffComparisonString(plan.Changes))
  1553  	}
  1554  }
  1555  
  1556  func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) {
  1557  	m := testModule(t, "plan-prevent-destroy-good")
  1558  	p := testProvider("aws")
  1559  
  1560  	state := states.NewState()
  1561  	root := state.EnsureModule(addrs.RootModuleInstance)
  1562  	root.SetResourceInstanceCurrent(
  1563  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  1564  		&states.ResourceInstanceObjectSrc{
  1565  			Status:    states.ObjectReady,
  1566  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  1567  		},
  1568  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1569  	)
  1570  
  1571  	ctx := testContext2(t, &ContextOpts{
  1572  		Providers: map[addrs.Provider]providers.Factory{
  1573  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1574  		},
  1575  	})
  1576  
  1577  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  1578  		Mode: plans.DestroyMode,
  1579  	})
  1580  
  1581  	expectedErr := "aws_instance.foo has lifecycle.prevent_destroy"
  1582  	if !strings.Contains(fmt.Sprintf("%s", diags.Err()), expectedErr) {
  1583  		if plan != nil {
  1584  			t.Logf(legacyDiffComparisonString(plan.Changes))
  1585  		}
  1586  		t.Fatalf("expected diagnostics would contain %q\nactual diags: %s", expectedErr, diags.Err())
  1587  	}
  1588  }
  1589  
  1590  func TestContext2Plan_provisionerCycle(t *testing.T) {
  1591  	m := testModule(t, "plan-provisioner-cycle")
  1592  	p := testProvider("aws")
  1593  	pr := testProvisioner()
  1594  	ctx := testContext2(t, &ContextOpts{
  1595  		Providers: map[addrs.Provider]providers.Factory{
  1596  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1597  		},
  1598  		Provisioners: map[string]provisioners.Factory{
  1599  			"local-exec": testProvisionerFuncFixed(pr),
  1600  		},
  1601  	})
  1602  
  1603  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1604  	if !diags.HasErrors() {
  1605  		t.Fatalf("succeeded; want errors")
  1606  	}
  1607  }
  1608  
  1609  func TestContext2Plan_computed(t *testing.T) {
  1610  	m := testModule(t, "plan-computed")
  1611  	p := testProvider("aws")
  1612  	p.PlanResourceChangeFn = testDiffFn
  1613  	ctx := testContext2(t, &ContextOpts{
  1614  		Providers: map[addrs.Provider]providers.Factory{
  1615  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1616  		},
  1617  	})
  1618  
  1619  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1620  	if diags.HasErrors() {
  1621  		t.Fatalf("unexpected errors: %s", diags.Err())
  1622  	}
  1623  
  1624  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  1625  	ty := schema.ImpliedType()
  1626  
  1627  	if len(plan.Changes.Resources) != 2 {
  1628  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  1629  	}
  1630  
  1631  	for _, res := range plan.Changes.Resources {
  1632  		if res.Action != plans.Create {
  1633  			t.Fatalf("expected resource creation, got %s", res.Action)
  1634  		}
  1635  		ric, err := res.Decode(ty)
  1636  		if err != nil {
  1637  			t.Fatal(err)
  1638  		}
  1639  
  1640  		switch i := ric.Addr.String(); i {
  1641  		case "aws_instance.bar":
  1642  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  1643  				"id":   cty.UnknownVal(cty.String),
  1644  				"foo":  cty.UnknownVal(cty.String),
  1645  				"type": cty.UnknownVal(cty.String),
  1646  			}), ric.After)
  1647  		case "aws_instance.foo":
  1648  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  1649  				"id":      cty.UnknownVal(cty.String),
  1650  				"foo":     cty.UnknownVal(cty.String),
  1651  				"num":     cty.NumberIntVal(2),
  1652  				"type":    cty.UnknownVal(cty.String),
  1653  				"compute": cty.StringVal("foo"),
  1654  			}), ric.After)
  1655  		default:
  1656  			t.Fatal("unknown instance:", i)
  1657  		}
  1658  	}
  1659  }
  1660  
  1661  func TestContext2Plan_blockNestingGroup(t *testing.T) {
  1662  	m := testModule(t, "plan-block-nesting-group")
  1663  	p := testProvider("test")
  1664  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1665  		ResourceTypes: map[string]*configschema.Block{
  1666  			"test": {
  1667  				BlockTypes: map[string]*configschema.NestedBlock{
  1668  					"blah": {
  1669  						Nesting: configschema.NestingGroup,
  1670  						Block: configschema.Block{
  1671  							Attributes: map[string]*configschema.Attribute{
  1672  								"baz": {Type: cty.String, Required: true},
  1673  							},
  1674  						},
  1675  					},
  1676  				},
  1677  			},
  1678  		},
  1679  	})
  1680  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  1681  		return providers.PlanResourceChangeResponse{
  1682  			PlannedState: req.ProposedNewState,
  1683  		}
  1684  	}
  1685  	ctx := testContext2(t, &ContextOpts{
  1686  		Providers: map[addrs.Provider]providers.Factory{
  1687  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1688  		},
  1689  	})
  1690  
  1691  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1692  	if diags.HasErrors() {
  1693  		t.Fatalf("unexpected errors: %s", diags.Err())
  1694  	}
  1695  
  1696  	if got, want := 1, len(plan.Changes.Resources); got != want {
  1697  		t.Fatalf("wrong number of planned resource changes %d; want %d\n%s", got, want, spew.Sdump(plan.Changes.Resources))
  1698  	}
  1699  
  1700  	if !p.PlanResourceChangeCalled {
  1701  		t.Fatalf("PlanResourceChange was not called at all")
  1702  	}
  1703  
  1704  	got := p.PlanResourceChangeRequest
  1705  	want := providers.PlanResourceChangeRequest{
  1706  		TypeName: "test",
  1707  
  1708  		// Because block type "blah" is defined as NestingGroup, we get a non-null
  1709  		// value for it with null nested attributes, rather than the "blah" object
  1710  		// itself being null, when there's no "blah" block in the config at all.
  1711  		//
  1712  		// This represents the situation where the remote service _always_ creates
  1713  		// a single "blah", regardless of whether the block is present, but when
  1714  		// the block _is_ present the user can override some aspects of it. The
  1715  		// absense of the block means "use the defaults", in that case.
  1716  		Config: cty.ObjectVal(map[string]cty.Value{
  1717  			"blah": cty.ObjectVal(map[string]cty.Value{
  1718  				"baz": cty.NullVal(cty.String),
  1719  			}),
  1720  		}),
  1721  		ProposedNewState: cty.ObjectVal(map[string]cty.Value{
  1722  			"blah": cty.ObjectVal(map[string]cty.Value{
  1723  				"baz": cty.NullVal(cty.String),
  1724  			}),
  1725  		}),
  1726  	}
  1727  	if !cmp.Equal(got, want, valueTrans) {
  1728  		t.Errorf("wrong PlanResourceChange request\n%s", cmp.Diff(got, want, valueTrans))
  1729  	}
  1730  }
  1731  
  1732  func TestContext2Plan_computedDataResource(t *testing.T) {
  1733  	m := testModule(t, "plan-computed-data-resource")
  1734  	p := testProvider("aws")
  1735  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1736  		ResourceTypes: map[string]*configschema.Block{
  1737  			"aws_instance": {
  1738  				Attributes: map[string]*configschema.Attribute{
  1739  					"num":     {Type: cty.String, Optional: true},
  1740  					"compute": {Type: cty.String, Optional: true},
  1741  					"foo":     {Type: cty.String, Computed: true},
  1742  				},
  1743  			},
  1744  		},
  1745  		DataSources: map[string]*configschema.Block{
  1746  			"aws_vpc": {
  1747  				Attributes: map[string]*configschema.Attribute{
  1748  					"foo": {Type: cty.String, Optional: true},
  1749  				},
  1750  			},
  1751  		},
  1752  	})
  1753  
  1754  	ctx := testContext2(t, &ContextOpts{
  1755  		Providers: map[addrs.Provider]providers.Factory{
  1756  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1757  		},
  1758  	})
  1759  
  1760  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1761  	if diags.HasErrors() {
  1762  		t.Fatalf("unexpected errors: %s", diags.Err())
  1763  	}
  1764  	schema := p.GetProviderSchemaResponse.DataSources["aws_vpc"].Block
  1765  	ty := schema.ImpliedType()
  1766  
  1767  	if rc := plan.Changes.ResourceInstance(addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "aws_instance", Name: "foo"}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)); rc == nil {
  1768  		t.Fatalf("missing diff for aws_instance.foo")
  1769  	}
  1770  	rcs := plan.Changes.ResourceInstance(addrs.Resource{
  1771  		Mode: addrs.DataResourceMode,
  1772  		Type: "aws_vpc",
  1773  		Name: "bar",
  1774  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
  1775  	if rcs == nil {
  1776  		t.Fatalf("missing diff for data.aws_vpc.bar")
  1777  	}
  1778  
  1779  	rc, err := rcs.Decode(ty)
  1780  	if err != nil {
  1781  		t.Fatal(err)
  1782  	}
  1783  
  1784  	checkVals(t,
  1785  		cty.ObjectVal(map[string]cty.Value{
  1786  			"foo": cty.UnknownVal(cty.String),
  1787  		}),
  1788  		rc.After,
  1789  	)
  1790  	if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseConfigUnknown; got != want {
  1791  		t.Errorf("wrong ActionReason\ngot:  %s\nwant: %s", got, want)
  1792  	}
  1793  }
  1794  
  1795  func TestContext2Plan_computedInFunction(t *testing.T) {
  1796  	m := testModule(t, "plan-computed-in-function")
  1797  	p := testProvider("aws")
  1798  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1799  		ResourceTypes: map[string]*configschema.Block{
  1800  			"aws_instance": {
  1801  				Attributes: map[string]*configschema.Attribute{
  1802  					"attr": {Type: cty.Number, Optional: true},
  1803  				},
  1804  			},
  1805  		},
  1806  		DataSources: map[string]*configschema.Block{
  1807  			"aws_data_source": {
  1808  				Attributes: map[string]*configschema.Attribute{
  1809  					"computed": {Type: cty.List(cty.String), Computed: true},
  1810  				},
  1811  			},
  1812  		},
  1813  	})
  1814  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  1815  		State: cty.ObjectVal(map[string]cty.Value{
  1816  			"computed": cty.ListVal([]cty.Value{
  1817  				cty.StringVal("foo"),
  1818  			}),
  1819  		}),
  1820  	}
  1821  
  1822  	ctx := testContext2(t, &ContextOpts{
  1823  		Providers: map[addrs.Provider]providers.Factory{
  1824  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1825  		},
  1826  	})
  1827  
  1828  	diags := ctx.Validate(m)
  1829  	assertNoErrors(t, diags)
  1830  
  1831  	_, diags = ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1832  	assertNoErrors(t, diags)
  1833  
  1834  	if !p.ReadDataSourceCalled {
  1835  		t.Fatalf("ReadDataSource was not called on provider during plan; should've been called")
  1836  	}
  1837  }
  1838  
  1839  func TestContext2Plan_computedDataCountResource(t *testing.T) {
  1840  	m := testModule(t, "plan-computed-data-count")
  1841  	p := testProvider("aws")
  1842  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1843  		ResourceTypes: map[string]*configschema.Block{
  1844  			"aws_instance": {
  1845  				Attributes: map[string]*configschema.Attribute{
  1846  					"num":     {Type: cty.String, Optional: true},
  1847  					"compute": {Type: cty.String, Optional: true},
  1848  					"foo":     {Type: cty.String, Computed: true},
  1849  				},
  1850  			},
  1851  		},
  1852  		DataSources: map[string]*configschema.Block{
  1853  			"aws_vpc": {
  1854  				Attributes: map[string]*configschema.Attribute{
  1855  					"foo": {Type: cty.String, Optional: true},
  1856  				},
  1857  			},
  1858  		},
  1859  	})
  1860  
  1861  	ctx := testContext2(t, &ContextOpts{
  1862  		Providers: map[addrs.Provider]providers.Factory{
  1863  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1864  		},
  1865  	})
  1866  
  1867  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1868  	if diags.HasErrors() {
  1869  		t.Fatalf("unexpected errors: %s", diags.Err())
  1870  	}
  1871  
  1872  	// make sure we created 3 "bar"s
  1873  	for i := 0; i < 3; i++ {
  1874  		addr := addrs.Resource{
  1875  			Mode: addrs.DataResourceMode,
  1876  			Type: "aws_vpc",
  1877  			Name: "bar",
  1878  		}.Instance(addrs.IntKey(i)).Absolute(addrs.RootModuleInstance)
  1879  
  1880  		if rcs := plan.Changes.ResourceInstance(addr); rcs == nil {
  1881  			t.Fatalf("missing changes for %s", addr)
  1882  		}
  1883  	}
  1884  }
  1885  
  1886  func TestContext2Plan_localValueCount(t *testing.T) {
  1887  	m := testModule(t, "plan-local-value-count")
  1888  	p := testProvider("test")
  1889  	ctx := testContext2(t, &ContextOpts{
  1890  		Providers: map[addrs.Provider]providers.Factory{
  1891  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1892  		},
  1893  	})
  1894  
  1895  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  1896  	if diags.HasErrors() {
  1897  		t.Fatalf("unexpected errors: %s", diags.Err())
  1898  	}
  1899  
  1900  	// make sure we created 3 "foo"s
  1901  	for i := 0; i < 3; i++ {
  1902  		addr := addrs.Resource{
  1903  			Mode: addrs.ManagedResourceMode,
  1904  			Type: "test_resource",
  1905  			Name: "foo",
  1906  		}.Instance(addrs.IntKey(i)).Absolute(addrs.RootModuleInstance)
  1907  
  1908  		if rcs := plan.Changes.ResourceInstance(addr); rcs == nil {
  1909  			t.Fatalf("missing changes for %s", addr)
  1910  		}
  1911  	}
  1912  }
  1913  
  1914  func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) {
  1915  	m := testModule(t, "plan-data-resource-becomes-computed")
  1916  	p := testProvider("aws")
  1917  
  1918  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1919  		ResourceTypes: map[string]*configschema.Block{
  1920  			"aws_instance": {
  1921  				Attributes: map[string]*configschema.Attribute{
  1922  					"foo":      {Type: cty.String, Optional: true},
  1923  					"computed": {Type: cty.String, Computed: true},
  1924  				},
  1925  			},
  1926  		},
  1927  		DataSources: map[string]*configschema.Block{
  1928  			"aws_data_source": {
  1929  				Attributes: map[string]*configschema.Attribute{
  1930  					"id":  {Type: cty.String, Computed: true},
  1931  					"foo": {Type: cty.String, Optional: true},
  1932  				},
  1933  			},
  1934  		},
  1935  	})
  1936  
  1937  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  1938  		fooVal := req.ProposedNewState.GetAttr("foo")
  1939  		return providers.PlanResourceChangeResponse{
  1940  			PlannedState: cty.ObjectVal(map[string]cty.Value{
  1941  				"foo":      fooVal,
  1942  				"computed": cty.UnknownVal(cty.String),
  1943  			}),
  1944  			PlannedPrivate: req.PriorPrivate,
  1945  		}
  1946  	}
  1947  
  1948  	schema := p.GetProviderSchemaResponse.DataSources["aws_data_source"].Block
  1949  	ty := schema.ImpliedType()
  1950  
  1951  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  1952  		// This should not be called, because the configuration for the
  1953  		// data resource contains an unknown value for "foo".
  1954  		Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("ReadDataSource called, but should not have been")),
  1955  	}
  1956  
  1957  	state := states.NewState()
  1958  	root := state.EnsureModule(addrs.RootModuleInstance)
  1959  	root.SetResourceInstanceCurrent(
  1960  		mustResourceInstanceAddr("data.aws_data_source.foo").Resource,
  1961  		&states.ResourceInstanceObjectSrc{
  1962  			Status:    states.ObjectReady,
  1963  			AttrsJSON: []byte(`{"id":"i-abc123","foo":"baz"}`),
  1964  		},
  1965  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  1966  	)
  1967  
  1968  	ctx := testContext2(t, &ContextOpts{
  1969  		Providers: map[addrs.Provider]providers.Factory{
  1970  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1971  		},
  1972  	})
  1973  
  1974  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  1975  	if diags.HasErrors() {
  1976  		t.Fatalf("unexpected errors during plan: %s", diags.Err())
  1977  	}
  1978  
  1979  	rcs := plan.Changes.ResourceInstance(addrs.Resource{
  1980  		Mode: addrs.DataResourceMode,
  1981  		Type: "aws_data_source",
  1982  		Name: "foo",
  1983  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
  1984  	if rcs == nil {
  1985  		t.Logf("full changeset: %s", spew.Sdump(plan.Changes))
  1986  		t.Fatalf("missing diff for data.aws_data_resource.foo")
  1987  	}
  1988  
  1989  	rc, err := rcs.Decode(ty)
  1990  	if err != nil {
  1991  		t.Fatal(err)
  1992  	}
  1993  
  1994  	if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseConfigUnknown; got != want {
  1995  		t.Errorf("wrong ActionReason\ngot:  %s\nwant: %s", got, want)
  1996  	}
  1997  
  1998  	// foo should now be unknown
  1999  	foo := rc.After.GetAttr("foo")
  2000  	if foo.IsKnown() {
  2001  		t.Fatalf("foo should be unknown, got %#v", foo)
  2002  	}
  2003  }
  2004  
  2005  func TestContext2Plan_computedList(t *testing.T) {
  2006  	m := testModule(t, "plan-computed-list")
  2007  	p := testProvider("aws")
  2008  	p.PlanResourceChangeFn = testDiffFn
  2009  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2010  		ResourceTypes: map[string]*configschema.Block{
  2011  			"aws_instance": {
  2012  				Attributes: map[string]*configschema.Attribute{
  2013  					"compute": {Type: cty.String, Optional: true},
  2014  					"foo":     {Type: cty.String, Optional: true},
  2015  					"num":     {Type: cty.String, Optional: true},
  2016  					"list":    {Type: cty.List(cty.String), Computed: true},
  2017  				},
  2018  			},
  2019  		},
  2020  	})
  2021  
  2022  	ctx := testContext2(t, &ContextOpts{
  2023  		Providers: map[addrs.Provider]providers.Factory{
  2024  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2025  		},
  2026  	})
  2027  
  2028  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2029  	if diags.HasErrors() {
  2030  		t.Fatalf("unexpected errors: %s", diags.Err())
  2031  	}
  2032  
  2033  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2034  	ty := schema.ImpliedType()
  2035  
  2036  	if len(plan.Changes.Resources) != 2 {
  2037  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  2038  	}
  2039  
  2040  	for _, res := range plan.Changes.Resources {
  2041  		if res.Action != plans.Create {
  2042  			t.Fatalf("expected resource creation, got %s", res.Action)
  2043  		}
  2044  		ric, err := res.Decode(ty)
  2045  		if err != nil {
  2046  			t.Fatal(err)
  2047  		}
  2048  
  2049  		switch i := ric.Addr.String(); i {
  2050  		case "aws_instance.bar":
  2051  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2052  				"foo": cty.UnknownVal(cty.String),
  2053  			}), ric.After)
  2054  		case "aws_instance.foo":
  2055  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2056  				"list":    cty.UnknownVal(cty.List(cty.String)),
  2057  				"num":     cty.NumberIntVal(2),
  2058  				"compute": cty.StringVal("list.#"),
  2059  			}), ric.After)
  2060  		default:
  2061  			t.Fatal("unknown instance:", i)
  2062  		}
  2063  	}
  2064  }
  2065  
  2066  // GH-8695. This tests that you can index into a computed list on a
  2067  // splatted resource.
  2068  func TestContext2Plan_computedMultiIndex(t *testing.T) {
  2069  	m := testModule(t, "plan-computed-multi-index")
  2070  	p := testProvider("aws")
  2071  	p.PlanResourceChangeFn = testDiffFn
  2072  
  2073  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2074  		ResourceTypes: map[string]*configschema.Block{
  2075  			"aws_instance": {
  2076  				Attributes: map[string]*configschema.Attribute{
  2077  					"compute": {Type: cty.String, Optional: true},
  2078  					"foo":     {Type: cty.List(cty.String), Optional: true},
  2079  					"ip":      {Type: cty.List(cty.String), Computed: true},
  2080  				},
  2081  			},
  2082  		},
  2083  	})
  2084  
  2085  	ctx := testContext2(t, &ContextOpts{
  2086  		Providers: map[addrs.Provider]providers.Factory{
  2087  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2088  		},
  2089  	})
  2090  
  2091  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2092  	if diags.HasErrors() {
  2093  		t.Fatalf("unexpected errors: %s", diags.Err())
  2094  	}
  2095  
  2096  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2097  	ty := schema.ImpliedType()
  2098  
  2099  	if len(plan.Changes.Resources) != 3 {
  2100  		t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
  2101  	}
  2102  
  2103  	for _, res := range plan.Changes.Resources {
  2104  		if res.Action != plans.Create {
  2105  			t.Fatalf("expected resource creation, got %s", res.Action)
  2106  		}
  2107  		ric, err := res.Decode(ty)
  2108  		if err != nil {
  2109  			t.Fatal(err)
  2110  		}
  2111  
  2112  		switch i := ric.Addr.String(); i {
  2113  		case "aws_instance.foo[0]":
  2114  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2115  				"ip":      cty.UnknownVal(cty.List(cty.String)),
  2116  				"foo":     cty.NullVal(cty.List(cty.String)),
  2117  				"compute": cty.StringVal("ip.#"),
  2118  			}), ric.After)
  2119  		case "aws_instance.foo[1]":
  2120  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2121  				"ip":      cty.UnknownVal(cty.List(cty.String)),
  2122  				"foo":     cty.NullVal(cty.List(cty.String)),
  2123  				"compute": cty.StringVal("ip.#"),
  2124  			}), ric.After)
  2125  		case "aws_instance.bar[0]":
  2126  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2127  				"foo": cty.UnknownVal(cty.List(cty.String)),
  2128  			}), ric.After)
  2129  		default:
  2130  			t.Fatal("unknown instance:", i)
  2131  		}
  2132  	}
  2133  }
  2134  
  2135  func TestContext2Plan_count(t *testing.T) {
  2136  	m := testModule(t, "plan-count")
  2137  	p := testProvider("aws")
  2138  	p.PlanResourceChangeFn = testDiffFn
  2139  	ctx := testContext2(t, &ContextOpts{
  2140  		Providers: map[addrs.Provider]providers.Factory{
  2141  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2142  		},
  2143  	})
  2144  
  2145  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2146  	if diags.HasErrors() {
  2147  		t.Fatalf("unexpected errors: %s", diags.Err())
  2148  	}
  2149  
  2150  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2151  	ty := schema.ImpliedType()
  2152  
  2153  	if len(plan.Changes.Resources) != 6 {
  2154  		t.Fatal("expected 6 changes, got", len(plan.Changes.Resources))
  2155  	}
  2156  
  2157  	for _, res := range plan.Changes.Resources {
  2158  		if res.Action != plans.Create {
  2159  			t.Fatalf("expected resource creation, got %s", res.Action)
  2160  		}
  2161  		ric, err := res.Decode(ty)
  2162  		if err != nil {
  2163  			t.Fatal(err)
  2164  		}
  2165  
  2166  		switch i := ric.Addr.String(); i {
  2167  		case "aws_instance.bar":
  2168  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2169  				"id":   cty.UnknownVal(cty.String),
  2170  				"foo":  cty.StringVal("foo,foo,foo,foo,foo"),
  2171  				"type": cty.UnknownVal(cty.String),
  2172  			}), ric.After)
  2173  		case "aws_instance.foo[0]":
  2174  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2175  				"id":   cty.UnknownVal(cty.String),
  2176  				"foo":  cty.StringVal("foo"),
  2177  				"type": cty.UnknownVal(cty.String),
  2178  			}), ric.After)
  2179  		case "aws_instance.foo[1]":
  2180  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2181  				"id":   cty.UnknownVal(cty.String),
  2182  				"foo":  cty.StringVal("foo"),
  2183  				"type": cty.UnknownVal(cty.String),
  2184  			}), ric.After)
  2185  		case "aws_instance.foo[2]":
  2186  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2187  				"id":   cty.UnknownVal(cty.String),
  2188  				"foo":  cty.StringVal("foo"),
  2189  				"type": cty.UnknownVal(cty.String),
  2190  			}), ric.After)
  2191  		case "aws_instance.foo[3]":
  2192  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2193  				"id":   cty.UnknownVal(cty.String),
  2194  				"foo":  cty.StringVal("foo"),
  2195  				"type": cty.UnknownVal(cty.String),
  2196  			}), ric.After)
  2197  		case "aws_instance.foo[4]":
  2198  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2199  				"id":   cty.UnknownVal(cty.String),
  2200  				"foo":  cty.StringVal("foo"),
  2201  				"type": cty.UnknownVal(cty.String),
  2202  			}), ric.After)
  2203  		default:
  2204  			t.Fatal("unknown instance:", i)
  2205  		}
  2206  	}
  2207  }
  2208  
  2209  func TestContext2Plan_countComputed(t *testing.T) {
  2210  	m := testModule(t, "plan-count-computed")
  2211  	p := testProvider("aws")
  2212  	ctx := testContext2(t, &ContextOpts{
  2213  		Providers: map[addrs.Provider]providers.Factory{
  2214  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2215  		},
  2216  	})
  2217  
  2218  	_, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2219  	if err == nil {
  2220  		t.Fatal("should error")
  2221  	}
  2222  }
  2223  
  2224  func TestContext2Plan_countComputedModule(t *testing.T) {
  2225  	m := testModule(t, "plan-count-computed-module")
  2226  	p := testProvider("aws")
  2227  	p.PlanResourceChangeFn = testDiffFn
  2228  	ctx := testContext2(t, &ContextOpts{
  2229  		Providers: map[addrs.Provider]providers.Factory{
  2230  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2231  		},
  2232  	})
  2233  
  2234  	_, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2235  
  2236  	expectedErr := `The "count" value depends on resource attributes`
  2237  	if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
  2238  		t.Fatalf("expected err would contain %q\nerr: %s\n",
  2239  			expectedErr, err)
  2240  	}
  2241  }
  2242  
  2243  func TestContext2Plan_countModuleStatic(t *testing.T) {
  2244  	m := testModule(t, "plan-count-module-static")
  2245  	p := testProvider("aws")
  2246  	p.PlanResourceChangeFn = testDiffFn
  2247  	ctx := testContext2(t, &ContextOpts{
  2248  		Providers: map[addrs.Provider]providers.Factory{
  2249  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2250  		},
  2251  	})
  2252  
  2253  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  2254  	if diags.HasErrors() {
  2255  		t.Fatalf("unexpected errors: %s", diags.Err())
  2256  	}
  2257  
  2258  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2259  	ty := schema.ImpliedType()
  2260  
  2261  	if len(plan.Changes.Resources) != 3 {
  2262  		t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
  2263  	}
  2264  
  2265  	for _, res := range plan.Changes.Resources {
  2266  		if res.Action != plans.Create {
  2267  			t.Fatalf("expected resource creation, got %s", res.Action)
  2268  		}
  2269  		ric, err := res.Decode(ty)
  2270  		if err != nil {
  2271  			t.Fatal(err)
  2272  		}
  2273  
  2274  		switch i := ric.Addr.String(); i {
  2275  		case "module.child.aws_instance.foo[0]":
  2276  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2277  				"id":   cty.UnknownVal(cty.String),
  2278  				"type": cty.UnknownVal(cty.String),
  2279  			}), ric.After)
  2280  		case "module.child.aws_instance.foo[1]":
  2281  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2282  				"id":   cty.UnknownVal(cty.String),
  2283  				"type": cty.UnknownVal(cty.String),
  2284  			}), ric.After)
  2285  		case "module.child.aws_instance.foo[2]":
  2286  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2287  				"id":   cty.UnknownVal(cty.String),
  2288  				"type": cty.UnknownVal(cty.String),
  2289  			}), ric.After)
  2290  		default:
  2291  			t.Fatal("unknown instance:", i)
  2292  		}
  2293  	}
  2294  }
  2295  
  2296  func TestContext2Plan_countModuleStaticGrandchild(t *testing.T) {
  2297  	m := testModule(t, "plan-count-module-static-grandchild")
  2298  	p := testProvider("aws")
  2299  	p.PlanResourceChangeFn = testDiffFn
  2300  	ctx := testContext2(t, &ContextOpts{
  2301  		Providers: map[addrs.Provider]providers.Factory{
  2302  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2303  		},
  2304  	})
  2305  
  2306  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  2307  	if diags.HasErrors() {
  2308  		t.Fatalf("unexpected errors: %s", diags.Err())
  2309  	}
  2310  
  2311  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2312  	ty := schema.ImpliedType()
  2313  
  2314  	if len(plan.Changes.Resources) != 3 {
  2315  		t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
  2316  	}
  2317  
  2318  	for _, res := range plan.Changes.Resources {
  2319  		if res.Action != plans.Create {
  2320  			t.Fatalf("expected resource creation, got %s", res.Action)
  2321  		}
  2322  		ric, err := res.Decode(ty)
  2323  		if err != nil {
  2324  			t.Fatal(err)
  2325  		}
  2326  
  2327  		switch i := ric.Addr.String(); i {
  2328  		case "module.child.module.child.aws_instance.foo[0]":
  2329  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2330  				"id":   cty.UnknownVal(cty.String),
  2331  				"type": cty.UnknownVal(cty.String),
  2332  			}), ric.After)
  2333  		case "module.child.module.child.aws_instance.foo[1]":
  2334  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2335  				"id":   cty.UnknownVal(cty.String),
  2336  				"type": cty.UnknownVal(cty.String),
  2337  			}), ric.After)
  2338  		case "module.child.module.child.aws_instance.foo[2]":
  2339  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2340  				"id":   cty.UnknownVal(cty.String),
  2341  				"type": cty.UnknownVal(cty.String),
  2342  			}), ric.After)
  2343  		default:
  2344  			t.Fatal("unknown instance:", i)
  2345  		}
  2346  	}
  2347  }
  2348  
  2349  func TestContext2Plan_countIndex(t *testing.T) {
  2350  	m := testModule(t, "plan-count-index")
  2351  	p := testProvider("aws")
  2352  	p.PlanResourceChangeFn = testDiffFn
  2353  	ctx := testContext2(t, &ContextOpts{
  2354  		Providers: map[addrs.Provider]providers.Factory{
  2355  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2356  		},
  2357  	})
  2358  
  2359  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2360  	if diags.HasErrors() {
  2361  		t.Fatalf("unexpected errors: %s", diags.Err())
  2362  	}
  2363  
  2364  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2365  	ty := schema.ImpliedType()
  2366  
  2367  	if len(plan.Changes.Resources) != 2 {
  2368  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  2369  	}
  2370  
  2371  	for _, res := range plan.Changes.Resources {
  2372  		if res.Action != plans.Create {
  2373  			t.Fatalf("expected resource creation, got %s", res.Action)
  2374  		}
  2375  		ric, err := res.Decode(ty)
  2376  		if err != nil {
  2377  			t.Fatal(err)
  2378  		}
  2379  
  2380  		switch i := ric.Addr.String(); i {
  2381  		case "aws_instance.foo[0]":
  2382  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2383  				"id":   cty.UnknownVal(cty.String),
  2384  				"foo":  cty.StringVal("0"),
  2385  				"type": cty.UnknownVal(cty.String),
  2386  			}), ric.After)
  2387  		case "aws_instance.foo[1]":
  2388  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2389  				"id":   cty.UnknownVal(cty.String),
  2390  				"foo":  cty.StringVal("1"),
  2391  				"type": cty.UnknownVal(cty.String),
  2392  			}), ric.After)
  2393  		default:
  2394  			t.Fatal("unknown instance:", i)
  2395  		}
  2396  	}
  2397  }
  2398  
  2399  func TestContext2Plan_countVar(t *testing.T) {
  2400  	m := testModule(t, "plan-count-var")
  2401  	p := testProvider("aws")
  2402  	p.PlanResourceChangeFn = testDiffFn
  2403  	ctx := testContext2(t, &ContextOpts{
  2404  		Providers: map[addrs.Provider]providers.Factory{
  2405  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2406  		},
  2407  	})
  2408  
  2409  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  2410  		Mode: plans.NormalMode,
  2411  		SetVariables: InputValues{
  2412  			"instance_count": &InputValue{
  2413  				Value:      cty.StringVal("3"),
  2414  				SourceType: ValueFromCaller,
  2415  			},
  2416  		},
  2417  	})
  2418  	if diags.HasErrors() {
  2419  		t.Fatalf("unexpected errors: %s", diags.Err())
  2420  	}
  2421  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2422  	ty := schema.ImpliedType()
  2423  
  2424  	if len(plan.Changes.Resources) != 4 {
  2425  		t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
  2426  	}
  2427  
  2428  	for _, res := range plan.Changes.Resources {
  2429  		if res.Action != plans.Create {
  2430  			t.Fatalf("expected resource creation, got %s", res.Action)
  2431  		}
  2432  		ric, err := res.Decode(ty)
  2433  		if err != nil {
  2434  			t.Fatal(err)
  2435  		}
  2436  
  2437  		switch i := ric.Addr.String(); i {
  2438  		case "aws_instance.bar":
  2439  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2440  				"id":   cty.UnknownVal(cty.String),
  2441  				"foo":  cty.StringVal("foo,foo,foo"),
  2442  				"type": cty.UnknownVal(cty.String),
  2443  			}), ric.After)
  2444  		case "aws_instance.foo[0]":
  2445  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2446  				"id":   cty.UnknownVal(cty.String),
  2447  				"foo":  cty.StringVal("foo"),
  2448  				"type": cty.UnknownVal(cty.String),
  2449  			}), ric.After)
  2450  		case "aws_instance.foo[1]":
  2451  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2452  				"id":   cty.UnknownVal(cty.String),
  2453  				"foo":  cty.StringVal("foo"),
  2454  				"type": cty.UnknownVal(cty.String),
  2455  			}), ric.After)
  2456  		case "aws_instance.foo[2]":
  2457  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2458  				"id":   cty.UnknownVal(cty.String),
  2459  				"foo":  cty.StringVal("foo"),
  2460  				"type": cty.UnknownVal(cty.String),
  2461  			}), ric.After)
  2462  		default:
  2463  			t.Fatal("unknown instance:", i)
  2464  		}
  2465  	}
  2466  }
  2467  
  2468  func TestContext2Plan_countZero(t *testing.T) {
  2469  	m := testModule(t, "plan-count-zero")
  2470  	p := testProvider("aws")
  2471  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2472  		ResourceTypes: map[string]*configschema.Block{
  2473  			"aws_instance": {
  2474  				Attributes: map[string]*configschema.Attribute{
  2475  					"foo": {Type: cty.DynamicPseudoType, Optional: true},
  2476  				},
  2477  			},
  2478  		},
  2479  	})
  2480  
  2481  	// This schema contains a DynamicPseudoType, and therefore can't go through any shim functions
  2482  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  2483  		resp.PlannedState = req.ProposedNewState
  2484  		resp.PlannedPrivate = req.PriorPrivate
  2485  		return resp
  2486  	}
  2487  
  2488  	ctx := testContext2(t, &ContextOpts{
  2489  		Providers: map[addrs.Provider]providers.Factory{
  2490  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2491  		},
  2492  	})
  2493  
  2494  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2495  	if diags.HasErrors() {
  2496  		t.Fatalf("unexpected errors: %s", diags.Err())
  2497  	}
  2498  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2499  	ty := schema.ImpliedType()
  2500  
  2501  	if len(plan.Changes.Resources) != 1 {
  2502  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  2503  	}
  2504  
  2505  	res := plan.Changes.Resources[0]
  2506  
  2507  	if res.Action != plans.Create {
  2508  		t.Fatalf("expected resource creation, got %s", res.Action)
  2509  	}
  2510  	ric, err := res.Decode(ty)
  2511  	if err != nil {
  2512  		t.Fatal(err)
  2513  	}
  2514  
  2515  	expected := cty.TupleVal(nil)
  2516  
  2517  	foo := ric.After.GetAttr("foo")
  2518  
  2519  	if !cmp.Equal(expected, foo, valueComparer) {
  2520  		t.Fatal(cmp.Diff(expected, foo, valueComparer))
  2521  	}
  2522  }
  2523  
  2524  func TestContext2Plan_countOneIndex(t *testing.T) {
  2525  	m := testModule(t, "plan-count-one-index")
  2526  	p := testProvider("aws")
  2527  	p.PlanResourceChangeFn = testDiffFn
  2528  	ctx := testContext2(t, &ContextOpts{
  2529  		Providers: map[addrs.Provider]providers.Factory{
  2530  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2531  		},
  2532  	})
  2533  
  2534  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  2535  	if diags.HasErrors() {
  2536  		t.Fatalf("unexpected errors: %s", diags.Err())
  2537  	}
  2538  
  2539  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2540  	ty := schema.ImpliedType()
  2541  
  2542  	if len(plan.Changes.Resources) != 2 {
  2543  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  2544  	}
  2545  
  2546  	for _, res := range plan.Changes.Resources {
  2547  		if res.Action != plans.Create {
  2548  			t.Fatalf("expected resource creation, got %s", res.Action)
  2549  		}
  2550  		ric, err := res.Decode(ty)
  2551  		if err != nil {
  2552  			t.Fatal(err)
  2553  		}
  2554  
  2555  		switch i := ric.Addr.String(); i {
  2556  		case "aws_instance.bar":
  2557  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2558  				"id":   cty.UnknownVal(cty.String),
  2559  				"foo":  cty.StringVal("foo"),
  2560  				"type": cty.UnknownVal(cty.String),
  2561  			}), ric.After)
  2562  		case "aws_instance.foo[0]":
  2563  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2564  				"id":   cty.UnknownVal(cty.String),
  2565  				"foo":  cty.StringVal("foo"),
  2566  				"type": cty.UnknownVal(cty.String),
  2567  			}), ric.After)
  2568  		default:
  2569  			t.Fatal("unknown instance:", i)
  2570  		}
  2571  	}
  2572  }
  2573  
  2574  func TestContext2Plan_countDecreaseToOne(t *testing.T) {
  2575  	m := testModule(t, "plan-count-dec")
  2576  	p := testProvider("aws")
  2577  	p.PlanResourceChangeFn = testDiffFn
  2578  
  2579  	state := states.NewState()
  2580  	root := state.EnsureModule(addrs.RootModuleInstance)
  2581  	root.SetResourceInstanceCurrent(
  2582  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2583  		&states.ResourceInstanceObjectSrc{
  2584  			Status:    states.ObjectReady,
  2585  			AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
  2586  		},
  2587  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2588  	)
  2589  	root.SetResourceInstanceCurrent(
  2590  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  2591  		&states.ResourceInstanceObjectSrc{
  2592  			Status:    states.ObjectReady,
  2593  			AttrsJSON: []byte(`{"id":"bar"}`),
  2594  		},
  2595  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2596  	)
  2597  	root.SetResourceInstanceCurrent(
  2598  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  2599  		&states.ResourceInstanceObjectSrc{
  2600  			Status:    states.ObjectReady,
  2601  			AttrsJSON: []byte(`{"id":"bar"}`),
  2602  		},
  2603  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2604  	)
  2605  
  2606  	ctx := testContext2(t, &ContextOpts{
  2607  		Providers: map[addrs.Provider]providers.Factory{
  2608  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2609  		},
  2610  	})
  2611  
  2612  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2613  	if diags.HasErrors() {
  2614  		t.Fatalf("unexpected errors: %s", diags.Err())
  2615  	}
  2616  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2617  	ty := schema.ImpliedType()
  2618  
  2619  	if len(plan.Changes.Resources) != 4 {
  2620  		t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
  2621  	}
  2622  
  2623  	for _, res := range plan.Changes.Resources {
  2624  
  2625  		ric, err := res.Decode(ty)
  2626  		if err != nil {
  2627  			t.Fatal(err)
  2628  		}
  2629  
  2630  		switch i := ric.Addr.String(); i {
  2631  		case "aws_instance.bar":
  2632  			if res.Action != plans.Create {
  2633  				t.Fatalf("expected resource create, got %s", res.Action)
  2634  			}
  2635  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2636  				"id":   cty.UnknownVal(cty.String),
  2637  				"foo":  cty.StringVal("bar"),
  2638  				"type": cty.UnknownVal(cty.String),
  2639  			}), ric.After)
  2640  		case "aws_instance.foo":
  2641  			if res.Action != plans.NoOp {
  2642  				t.Fatalf("resource %s should be unchanged", i)
  2643  			}
  2644  		case "aws_instance.foo[1]":
  2645  			if res.Action != plans.Delete {
  2646  				t.Fatalf("expected resource delete, got %s", res.Action)
  2647  			}
  2648  		case "aws_instance.foo[2]":
  2649  			if res.Action != plans.Delete {
  2650  				t.Fatalf("expected resource delete, got %s", res.Action)
  2651  			}
  2652  		default:
  2653  			t.Fatal("unknown instance:", i)
  2654  		}
  2655  	}
  2656  
  2657  	expectedState := `aws_instance.foo:
  2658    ID = bar
  2659    provider = provider["registry.terraform.io/hashicorp/aws"]
  2660    foo = foo
  2661    type = aws_instance
  2662  aws_instance.foo.1:
  2663    ID = bar
  2664    provider = provider["registry.terraform.io/hashicorp/aws"]
  2665  aws_instance.foo.2:
  2666    ID = bar
  2667    provider = provider["registry.terraform.io/hashicorp/aws"]`
  2668  
  2669  	if plan.PriorState.String() != expectedState {
  2670  		t.Fatalf("epected state:\n%q\n\ngot state:\n%q\n", expectedState, plan.PriorState.String())
  2671  	}
  2672  }
  2673  
  2674  func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) {
  2675  	m := testModule(t, "plan-count-inc")
  2676  	p := testProvider("aws")
  2677  	p.PlanResourceChangeFn = testDiffFn
  2678  
  2679  	state := states.NewState()
  2680  	root := state.EnsureModule(addrs.RootModuleInstance)
  2681  	root.SetResourceInstanceCurrent(
  2682  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2683  		&states.ResourceInstanceObjectSrc{
  2684  			Status:    states.ObjectReady,
  2685  			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance","foo":"foo"}`),
  2686  		},
  2687  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2688  	)
  2689  
  2690  	ctx := testContext2(t, &ContextOpts{
  2691  		Providers: map[addrs.Provider]providers.Factory{
  2692  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2693  		},
  2694  	})
  2695  
  2696  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2697  	if diags.HasErrors() {
  2698  		t.Fatalf("unexpected errors: %s", diags.Err())
  2699  	}
  2700  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2701  	ty := schema.ImpliedType()
  2702  
  2703  	if len(plan.Changes.Resources) != 4 {
  2704  		t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
  2705  	}
  2706  
  2707  	for _, res := range plan.Changes.Resources {
  2708  
  2709  		ric, err := res.Decode(ty)
  2710  		if err != nil {
  2711  			t.Fatal(err)
  2712  		}
  2713  
  2714  		switch i := ric.Addr.String(); i {
  2715  		case "aws_instance.bar":
  2716  			if res.Action != plans.Create {
  2717  				t.Fatalf("expected resource create, got %s", res.Action)
  2718  			}
  2719  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2720  				"id":   cty.UnknownVal(cty.String),
  2721  				"foo":  cty.StringVal("bar"),
  2722  				"type": cty.UnknownVal(cty.String),
  2723  			}), ric.After)
  2724  		case "aws_instance.foo[0]":
  2725  			if res.Action != plans.NoOp {
  2726  				t.Fatalf("resource %s should be unchanged", i)
  2727  			}
  2728  		case "aws_instance.foo[1]":
  2729  			if res.Action != plans.Create {
  2730  				t.Fatalf("expected resource create, got %s", res.Action)
  2731  			}
  2732  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2733  				"id":   cty.UnknownVal(cty.String),
  2734  				"foo":  cty.StringVal("foo"),
  2735  				"type": cty.UnknownVal(cty.String),
  2736  			}), ric.After)
  2737  		case "aws_instance.foo[2]":
  2738  			if res.Action != plans.Create {
  2739  				t.Fatalf("expected resource create, got %s", res.Action)
  2740  			}
  2741  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2742  				"id":   cty.UnknownVal(cty.String),
  2743  				"foo":  cty.StringVal("foo"),
  2744  				"type": cty.UnknownVal(cty.String),
  2745  			}), ric.After)
  2746  		default:
  2747  			t.Fatal("unknown instance:", i)
  2748  		}
  2749  	}
  2750  }
  2751  
  2752  func TestContext2Plan_countIncreaseFromOne(t *testing.T) {
  2753  	m := testModule(t, "plan-count-inc")
  2754  	p := testProvider("aws")
  2755  	p.PlanResourceChangeFn = testDiffFn
  2756  	state := states.NewState()
  2757  	root := state.EnsureModule(addrs.RootModuleInstance)
  2758  	root.SetResourceInstanceCurrent(
  2759  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2760  		&states.ResourceInstanceObjectSrc{
  2761  			Status:    states.ObjectReady,
  2762  			AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
  2763  		},
  2764  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2765  	)
  2766  
  2767  	ctx := testContext2(t, &ContextOpts{
  2768  		Providers: map[addrs.Provider]providers.Factory{
  2769  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2770  		},
  2771  	})
  2772  
  2773  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2774  	if diags.HasErrors() {
  2775  		t.Fatalf("unexpected errors: %s", diags.Err())
  2776  	}
  2777  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2778  	ty := schema.ImpliedType()
  2779  
  2780  	if len(plan.Changes.Resources) != 4 {
  2781  		t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
  2782  	}
  2783  
  2784  	for _, res := range plan.Changes.Resources {
  2785  
  2786  		ric, err := res.Decode(ty)
  2787  		if err != nil {
  2788  			t.Fatal(err)
  2789  		}
  2790  
  2791  		switch i := ric.Addr.String(); i {
  2792  		case "aws_instance.bar":
  2793  			if res.Action != plans.Create {
  2794  				t.Fatalf("expected resource create, got %s", res.Action)
  2795  			}
  2796  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2797  				"id":   cty.UnknownVal(cty.String),
  2798  				"foo":  cty.StringVal("bar"),
  2799  				"type": cty.UnknownVal(cty.String),
  2800  			}), ric.After)
  2801  		case "aws_instance.foo[0]":
  2802  			if res.Action != plans.NoOp {
  2803  				t.Fatalf("resource %s should be unchanged", i)
  2804  			}
  2805  		case "aws_instance.foo[1]":
  2806  			if res.Action != plans.Create {
  2807  				t.Fatalf("expected resource create, got %s", res.Action)
  2808  			}
  2809  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2810  				"id":   cty.UnknownVal(cty.String),
  2811  				"foo":  cty.StringVal("foo"),
  2812  				"type": cty.UnknownVal(cty.String),
  2813  			}), ric.After)
  2814  		case "aws_instance.foo[2]":
  2815  			if res.Action != plans.Create {
  2816  				t.Fatalf("expected resource create, got %s", res.Action)
  2817  			}
  2818  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2819  				"id":   cty.UnknownVal(cty.String),
  2820  				"foo":  cty.StringVal("foo"),
  2821  				"type": cty.UnknownVal(cty.String),
  2822  			}), ric.After)
  2823  		default:
  2824  			t.Fatal("unknown instance:", i)
  2825  		}
  2826  	}
  2827  }
  2828  
  2829  // https://github.com/PeoplePerHour/terraform/pull/11
  2830  //
  2831  // This tests a case where both a "resource" and "resource.0" are in
  2832  // the state file, which apparently is a reasonable backwards compatibility
  2833  // concern found in the above 3rd party repo.
  2834  func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) {
  2835  	m := testModule(t, "plan-count-inc")
  2836  	p := testProvider("aws")
  2837  	p.PlanResourceChangeFn = testDiffFn
  2838  
  2839  	state := states.NewState()
  2840  	root := state.EnsureModule(addrs.RootModuleInstance)
  2841  	root.SetResourceInstanceCurrent(
  2842  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  2843  		&states.ResourceInstanceObjectSrc{
  2844  			Status:    states.ObjectReady,
  2845  			AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
  2846  		},
  2847  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2848  	)
  2849  	root.SetResourceInstanceCurrent(
  2850  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2851  		&states.ResourceInstanceObjectSrc{
  2852  			Status:    states.ObjectReady,
  2853  			AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
  2854  		},
  2855  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2856  	)
  2857  
  2858  	ctx := testContext2(t, &ContextOpts{
  2859  		Providers: map[addrs.Provider]providers.Factory{
  2860  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2861  		},
  2862  	})
  2863  
  2864  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2865  	if diags.HasErrors() {
  2866  		t.Fatalf("unexpected errors: %s", diags.Err())
  2867  	}
  2868  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2869  	ty := schema.ImpliedType()
  2870  
  2871  	if len(plan.Changes.Resources) != 5 {
  2872  		t.Fatal("expected 5 changes, got", len(plan.Changes.Resources))
  2873  	}
  2874  
  2875  	for _, res := range plan.Changes.Resources {
  2876  
  2877  		ric, err := res.Decode(ty)
  2878  		if err != nil {
  2879  			t.Fatal(err)
  2880  		}
  2881  
  2882  		switch i := ric.Addr.String(); i {
  2883  		case "aws_instance.bar":
  2884  			if res.Action != plans.Create {
  2885  				t.Fatalf("expected resource create, got %s", res.Action)
  2886  			}
  2887  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2888  				"id":   cty.UnknownVal(cty.String),
  2889  				"foo":  cty.StringVal("bar"),
  2890  				"type": cty.UnknownVal(cty.String),
  2891  			}), ric.After)
  2892  		case "aws_instance.foo":
  2893  			if res.Action != plans.Delete {
  2894  				t.Fatalf("resource %s should be removed", i)
  2895  			}
  2896  		case "aws_instance.foo[0]":
  2897  			if res.Action != plans.NoOp {
  2898  				t.Fatalf("resource %s should be unchanged", i)
  2899  			}
  2900  		case "aws_instance.foo[1]":
  2901  			if res.Action != plans.Create {
  2902  				t.Fatalf("expected resource create, got %s", res.Action)
  2903  			}
  2904  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2905  				"id":   cty.UnknownVal(cty.String),
  2906  				"foo":  cty.StringVal("foo"),
  2907  				"type": cty.UnknownVal(cty.String),
  2908  			}), ric.After)
  2909  		case "aws_instance.foo[2]":
  2910  			if res.Action != plans.Create {
  2911  				t.Fatalf("expected resource create, got %s", res.Action)
  2912  			}
  2913  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  2914  				"id":   cty.UnknownVal(cty.String),
  2915  				"foo":  cty.StringVal("foo"),
  2916  				"type": cty.UnknownVal(cty.String),
  2917  			}), ric.After)
  2918  		default:
  2919  			t.Fatal("unknown instance:", i)
  2920  		}
  2921  	}
  2922  }
  2923  
  2924  // A common pattern in TF configs is to have a set of resources with the same
  2925  // count and to use count.index to create correspondences between them:
  2926  //
  2927  //	foo_id = "${foo.bar.*.id[count.index]}"
  2928  //
  2929  // This test is for the situation where some instances already exist and the
  2930  // count is increased. In that case, we should see only the create diffs
  2931  // for the new instances and not any update diffs for the existing ones.
  2932  func TestContext2Plan_countIncreaseWithSplatReference(t *testing.T) {
  2933  	m := testModule(t, "plan-count-splat-reference")
  2934  	p := testProvider("aws")
  2935  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2936  		ResourceTypes: map[string]*configschema.Block{
  2937  			"aws_instance": {
  2938  				Attributes: map[string]*configschema.Attribute{
  2939  					"name":     {Type: cty.String, Optional: true},
  2940  					"foo_name": {Type: cty.String, Optional: true},
  2941  					"id":       {Type: cty.String, Computed: true},
  2942  				},
  2943  			},
  2944  		},
  2945  	})
  2946  
  2947  	state := states.NewState()
  2948  	root := state.EnsureModule(addrs.RootModuleInstance)
  2949  	root.SetResourceInstanceCurrent(
  2950  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  2951  		&states.ResourceInstanceObjectSrc{
  2952  			Status:    states.ObjectReady,
  2953  			AttrsJSON: []byte(`{"id":"bar","name":"foo 0"}`),
  2954  		},
  2955  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2956  	)
  2957  	root.SetResourceInstanceCurrent(
  2958  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  2959  		&states.ResourceInstanceObjectSrc{
  2960  			Status:    states.ObjectReady,
  2961  			AttrsJSON: []byte(`{"id":"bar","name":"foo 1"}`),
  2962  		},
  2963  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2964  	)
  2965  	root.SetResourceInstanceCurrent(
  2966  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  2967  		&states.ResourceInstanceObjectSrc{
  2968  			Status:    states.ObjectReady,
  2969  			AttrsJSON: []byte(`{"id":"bar","foo_name":"foo 0"}`),
  2970  		},
  2971  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2972  	)
  2973  	root.SetResourceInstanceCurrent(
  2974  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  2975  		&states.ResourceInstanceObjectSrc{
  2976  			Status:    states.ObjectReady,
  2977  			AttrsJSON: []byte(`{"id":"bar","foo_name":"foo 1"}`),
  2978  		},
  2979  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  2980  	)
  2981  
  2982  	ctx := testContext2(t, &ContextOpts{
  2983  		Providers: map[addrs.Provider]providers.Factory{
  2984  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  2985  		},
  2986  	})
  2987  
  2988  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  2989  	if diags.HasErrors() {
  2990  		t.Fatalf("unexpected errors: %s", diags.Err())
  2991  	}
  2992  
  2993  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  2994  	ty := schema.ImpliedType()
  2995  
  2996  	if len(plan.Changes.Resources) != 6 {
  2997  		t.Fatal("expected 6 changes, got", len(plan.Changes.Resources))
  2998  	}
  2999  
  3000  	for _, res := range plan.Changes.Resources {
  3001  		ric, err := res.Decode(ty)
  3002  		if err != nil {
  3003  			t.Fatal(err)
  3004  		}
  3005  
  3006  		switch i := ric.Addr.String(); i {
  3007  		case "aws_instance.bar[0]", "aws_instance.bar[1]", "aws_instance.foo[0]", "aws_instance.foo[1]":
  3008  			if res.Action != plans.NoOp {
  3009  				t.Fatalf("resource %s should be unchanged", i)
  3010  			}
  3011  		case "aws_instance.bar[2]":
  3012  			if res.Action != plans.Create {
  3013  				t.Fatalf("expected resource create, got %s", res.Action)
  3014  			}
  3015  			// The instance ID changed, so just check that the name updated
  3016  			if ric.After.GetAttr("foo_name") != cty.StringVal("foo 2") {
  3017  				t.Fatalf("resource %s attr \"foo_name\" should be changed", i)
  3018  			}
  3019  		case "aws_instance.foo[2]":
  3020  			if res.Action != plans.Create {
  3021  				t.Fatalf("expected resource create, got %s", res.Action)
  3022  			}
  3023  			// The instance ID changed, so just check that the name updated
  3024  			if ric.After.GetAttr("name") != cty.StringVal("foo 2") {
  3025  				t.Fatalf("resource %s attr \"name\" should be changed", i)
  3026  			}
  3027  		default:
  3028  			t.Fatal("unknown instance:", i)
  3029  		}
  3030  	}
  3031  }
  3032  
  3033  func TestContext2Plan_forEach(t *testing.T) {
  3034  	m := testModule(t, "plan-for-each")
  3035  	p := testProvider("aws")
  3036  	ctx := testContext2(t, &ContextOpts{
  3037  		Providers: map[addrs.Provider]providers.Factory{
  3038  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3039  		},
  3040  	})
  3041  
  3042  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3043  	if diags.HasErrors() {
  3044  		t.Fatalf("unexpected errors: %s", diags.Err())
  3045  	}
  3046  
  3047  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3048  	ty := schema.ImpliedType()
  3049  
  3050  	if len(plan.Changes.Resources) != 8 {
  3051  		t.Fatal("expected 8 changes, got", len(plan.Changes.Resources))
  3052  	}
  3053  
  3054  	for _, res := range plan.Changes.Resources {
  3055  		if res.Action != plans.Create {
  3056  			t.Fatalf("expected resource creation, got %s", res.Action)
  3057  		}
  3058  		_, err := res.Decode(ty)
  3059  		if err != nil {
  3060  			t.Fatal(err)
  3061  		}
  3062  	}
  3063  }
  3064  
  3065  func TestContext2Plan_forEachUnknownValue(t *testing.T) {
  3066  	// This module has a variable defined, but it's value is unknown. We
  3067  	// expect this to produce an error, but not to panic.
  3068  	m := testModule(t, "plan-for-each-unknown-value")
  3069  	p := testProvider("aws")
  3070  	ctx := testContext2(t, &ContextOpts{
  3071  		Providers: map[addrs.Provider]providers.Factory{
  3072  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3073  		},
  3074  	})
  3075  
  3076  	_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  3077  		Mode: plans.NormalMode,
  3078  		SetVariables: InputValues{
  3079  			"foo": {
  3080  				Value:      cty.UnknownVal(cty.String),
  3081  				SourceType: ValueFromCLIArg,
  3082  			},
  3083  		},
  3084  	})
  3085  	if !diags.HasErrors() {
  3086  		// Should get this error:
  3087  		// Invalid for_each argument: The "for_each" value depends on resource attributes that cannot be determined until apply...
  3088  		t.Fatal("succeeded; want errors")
  3089  	}
  3090  
  3091  	gotErrStr := diags.Err().Error()
  3092  	wantErrStr := "Invalid for_each argument"
  3093  	if !strings.Contains(gotErrStr, wantErrStr) {
  3094  		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
  3095  	}
  3096  
  3097  	// We should have a diagnostic that is marked as being caused by unknown
  3098  	// values.
  3099  	for _, diag := range diags {
  3100  		if tfdiags.DiagnosticCausedByUnknown(diag) {
  3101  			return // don't fall through to the error below
  3102  		}
  3103  	}
  3104  	t.Fatalf("no diagnostic is marked as being caused by unknown\n%s", diags.Err().Error())
  3105  }
  3106  
  3107  func TestContext2Plan_destroy(t *testing.T) {
  3108  	m := testModule(t, "plan-destroy")
  3109  	p := testProvider("aws")
  3110  
  3111  	state := states.NewState()
  3112  	root := state.EnsureModule(addrs.RootModuleInstance)
  3113  	root.SetResourceInstanceCurrent(
  3114  		mustResourceInstanceAddr("aws_instance.one").Resource,
  3115  		&states.ResourceInstanceObjectSrc{
  3116  			Status:    states.ObjectReady,
  3117  			AttrsJSON: []byte(`{"id":"bar"}`),
  3118  		},
  3119  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3120  	)
  3121  	root.SetResourceInstanceCurrent(
  3122  		mustResourceInstanceAddr("aws_instance.two").Resource,
  3123  		&states.ResourceInstanceObjectSrc{
  3124  			Status:    states.ObjectReady,
  3125  			AttrsJSON: []byte(`{"id":"baz"}`),
  3126  		},
  3127  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3128  	)
  3129  
  3130  	ctx := testContext2(t, &ContextOpts{
  3131  		Providers: map[addrs.Provider]providers.Factory{
  3132  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3133  		},
  3134  	})
  3135  
  3136  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  3137  		Mode: plans.DestroyMode,
  3138  	})
  3139  	if diags.HasErrors() {
  3140  		t.Fatalf("unexpected errors: %s", diags.Err())
  3141  	}
  3142  
  3143  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3144  	ty := schema.ImpliedType()
  3145  
  3146  	if len(plan.Changes.Resources) != 2 {
  3147  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  3148  	}
  3149  
  3150  	for _, res := range plan.Changes.Resources {
  3151  		ric, err := res.Decode(ty)
  3152  		if err != nil {
  3153  			t.Fatal(err)
  3154  		}
  3155  
  3156  		switch i := ric.Addr.String(); i {
  3157  		case "aws_instance.one", "aws_instance.two":
  3158  			if res.Action != plans.Delete {
  3159  				t.Fatalf("resource %s should be removed", i)
  3160  			}
  3161  
  3162  		default:
  3163  			t.Fatal("unknown instance:", i)
  3164  		}
  3165  	}
  3166  }
  3167  
  3168  func TestContext2Plan_moduleDestroy(t *testing.T) {
  3169  	m := testModule(t, "plan-module-destroy")
  3170  	p := testProvider("aws")
  3171  
  3172  	state := states.NewState()
  3173  	root := state.EnsureModule(addrs.RootModuleInstance)
  3174  	root.SetResourceInstanceCurrent(
  3175  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  3176  		&states.ResourceInstanceObjectSrc{
  3177  			Status:    states.ObjectReady,
  3178  			AttrsJSON: []byte(`{"id":"bar"}`),
  3179  		},
  3180  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3181  	)
  3182  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  3183  	child.SetResourceInstanceCurrent(
  3184  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  3185  		&states.ResourceInstanceObjectSrc{
  3186  			Status:    states.ObjectReady,
  3187  			AttrsJSON: []byte(`{"id":"bar"}`),
  3188  		},
  3189  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3190  	)
  3191  
  3192  	ctx := testContext2(t, &ContextOpts{
  3193  		Providers: map[addrs.Provider]providers.Factory{
  3194  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3195  		},
  3196  	})
  3197  
  3198  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  3199  		Mode: plans.DestroyMode,
  3200  	})
  3201  	if diags.HasErrors() {
  3202  		t.Fatalf("unexpected errors: %s", diags.Err())
  3203  	}
  3204  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3205  	ty := schema.ImpliedType()
  3206  
  3207  	if len(plan.Changes.Resources) != 2 {
  3208  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  3209  	}
  3210  
  3211  	for _, res := range plan.Changes.Resources {
  3212  		ric, err := res.Decode(ty)
  3213  		if err != nil {
  3214  			t.Fatal(err)
  3215  		}
  3216  
  3217  		switch i := ric.Addr.String(); i {
  3218  		case "aws_instance.foo", "module.child.aws_instance.foo":
  3219  			if res.Action != plans.Delete {
  3220  				t.Fatalf("resource %s should be removed", i)
  3221  			}
  3222  
  3223  		default:
  3224  			t.Fatal("unknown instance:", i)
  3225  		}
  3226  	}
  3227  }
  3228  
  3229  // GH-1835
  3230  func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
  3231  	m := testModule(t, "plan-module-destroy-gh-1835")
  3232  	p := testProvider("aws")
  3233  
  3234  	state := states.NewState()
  3235  	aModule := state.EnsureModule(addrs.RootModuleInstance.Child("a_module", addrs.NoKey))
  3236  	aModule.SetResourceInstanceCurrent(
  3237  		mustResourceInstanceAddr("aws_instance.a").Resource,
  3238  		&states.ResourceInstanceObjectSrc{
  3239  			Status:    states.ObjectReady,
  3240  			AttrsJSON: []byte(`{"id":"a"}`),
  3241  		},
  3242  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3243  	)
  3244  	bModule := state.EnsureModule(addrs.RootModuleInstance.Child("b_module", addrs.NoKey))
  3245  	bModule.SetResourceInstanceCurrent(
  3246  		mustResourceInstanceAddr("aws_instance.b").Resource,
  3247  		&states.ResourceInstanceObjectSrc{
  3248  			Status:    states.ObjectReady,
  3249  			AttrsJSON: []byte(`{"id":"b"}`),
  3250  		},
  3251  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3252  	)
  3253  
  3254  	ctx := testContext2(t, &ContextOpts{
  3255  		Providers: map[addrs.Provider]providers.Factory{
  3256  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3257  		},
  3258  	})
  3259  
  3260  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  3261  		Mode: plans.DestroyMode,
  3262  	})
  3263  	if diags.HasErrors() {
  3264  		t.Fatalf("unexpected errors: %s", diags.Err())
  3265  	}
  3266  
  3267  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3268  	ty := schema.ImpliedType()
  3269  
  3270  	if len(plan.Changes.Resources) != 2 {
  3271  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  3272  	}
  3273  
  3274  	for _, res := range plan.Changes.Resources {
  3275  		ric, err := res.Decode(ty)
  3276  		if err != nil {
  3277  			t.Fatal(err)
  3278  		}
  3279  
  3280  		switch i := ric.Addr.String(); i {
  3281  		case "module.a_module.aws_instance.a", "module.b_module.aws_instance.b":
  3282  			if res.Action != plans.Delete {
  3283  				t.Fatalf("resource %s should be removed", i)
  3284  			}
  3285  
  3286  		default:
  3287  			t.Fatal("unknown instance:", i)
  3288  		}
  3289  	}
  3290  }
  3291  
  3292  func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
  3293  	m := testModule(t, "plan-module-destroy-multivar")
  3294  	p := testProvider("aws")
  3295  
  3296  	state := states.NewState()
  3297  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  3298  	child.SetResourceInstanceCurrent(
  3299  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  3300  		&states.ResourceInstanceObjectSrc{
  3301  			Status:    states.ObjectReady,
  3302  			AttrsJSON: []byte(`{"id":"bar0"}`),
  3303  		},
  3304  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3305  	)
  3306  	child.SetResourceInstanceCurrent(
  3307  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  3308  		&states.ResourceInstanceObjectSrc{
  3309  			Status:    states.ObjectReady,
  3310  			AttrsJSON: []byte(`{"id":"bar1"}`),
  3311  		},
  3312  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3313  	)
  3314  
  3315  	ctx := testContext2(t, &ContextOpts{
  3316  		Providers: map[addrs.Provider]providers.Factory{
  3317  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3318  		},
  3319  	})
  3320  
  3321  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  3322  		Mode: plans.DestroyMode,
  3323  	})
  3324  	if diags.HasErrors() {
  3325  		t.Fatalf("unexpected errors: %s", diags.Err())
  3326  	}
  3327  
  3328  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3329  	ty := schema.ImpliedType()
  3330  
  3331  	if len(plan.Changes.Resources) != 2 {
  3332  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  3333  	}
  3334  
  3335  	for _, res := range plan.Changes.Resources {
  3336  		ric, err := res.Decode(ty)
  3337  		if err != nil {
  3338  			t.Fatal(err)
  3339  		}
  3340  
  3341  		switch i := ric.Addr.String(); i {
  3342  		case "module.child.aws_instance.foo[0]", "module.child.aws_instance.foo[1]":
  3343  			if res.Action != plans.Delete {
  3344  				t.Fatalf("resource %s should be removed", i)
  3345  			}
  3346  
  3347  		default:
  3348  			t.Fatal("unknown instance:", i)
  3349  		}
  3350  	}
  3351  }
  3352  
  3353  func TestContext2Plan_pathVar(t *testing.T) {
  3354  	cwd, err := os.Getwd()
  3355  	if err != nil {
  3356  		t.Fatalf("err: %s", err)
  3357  	}
  3358  
  3359  	m := testModule(t, "plan-path-var")
  3360  	p := testProvider("aws")
  3361  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3362  		ResourceTypes: map[string]*configschema.Block{
  3363  			"aws_instance": {
  3364  				Attributes: map[string]*configschema.Attribute{
  3365  					"cwd":    {Type: cty.String, Optional: true},
  3366  					"module": {Type: cty.String, Optional: true},
  3367  					"root":   {Type: cty.String, Optional: true},
  3368  				},
  3369  			},
  3370  		},
  3371  	})
  3372  
  3373  	ctx := testContext2(t, &ContextOpts{
  3374  		Providers: map[addrs.Provider]providers.Factory{
  3375  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3376  		},
  3377  	})
  3378  
  3379  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3380  	if diags.HasErrors() {
  3381  		t.Fatalf("err: %s", diags.Err())
  3382  	}
  3383  
  3384  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3385  	ty := schema.ImpliedType()
  3386  
  3387  	if len(plan.Changes.Resources) != 1 {
  3388  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  3389  	}
  3390  
  3391  	for _, res := range plan.Changes.Resources {
  3392  		ric, err := res.Decode(ty)
  3393  		if err != nil {
  3394  			t.Fatal(err)
  3395  		}
  3396  
  3397  		switch i := ric.Addr.String(); i {
  3398  		case "aws_instance.foo":
  3399  			if res.Action != plans.Create {
  3400  				t.Fatalf("resource %s should be created", i)
  3401  			}
  3402  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3403  				"cwd":    cty.StringVal(cwd + "/barpath"),
  3404  				"module": cty.StringVal(m.Module.SourceDir + "/foopath"),
  3405  				"root":   cty.StringVal(m.Module.SourceDir + "/barpath"),
  3406  			}), ric.After)
  3407  		default:
  3408  			t.Fatal("unknown instance:", i)
  3409  		}
  3410  	}
  3411  }
  3412  
  3413  func TestContext2Plan_diffVar(t *testing.T) {
  3414  	m := testModule(t, "plan-diffvar")
  3415  	p := testProvider("aws")
  3416  	p.PlanResourceChangeFn = testDiffFn
  3417  	state := states.NewState()
  3418  	root := state.EnsureModule(addrs.RootModuleInstance)
  3419  	root.SetResourceInstanceCurrent(
  3420  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  3421  		&states.ResourceInstanceObjectSrc{
  3422  			Status:    states.ObjectReady,
  3423  			AttrsJSON: []byte(`{"id":"bar","num":"2","type":"aws_instance"}`),
  3424  		},
  3425  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3426  	)
  3427  
  3428  	ctx := testContext2(t, &ContextOpts{
  3429  		Providers: map[addrs.Provider]providers.Factory{
  3430  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3431  		},
  3432  	})
  3433  
  3434  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3435  	if diags.HasErrors() {
  3436  		t.Fatalf("unexpected errors: %s", diags.Err())
  3437  	}
  3438  
  3439  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3440  	ty := schema.ImpliedType()
  3441  
  3442  	if len(plan.Changes.Resources) != 2 {
  3443  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  3444  	}
  3445  
  3446  	for _, res := range plan.Changes.Resources {
  3447  		ric, err := res.Decode(ty)
  3448  		if err != nil {
  3449  			t.Fatal(err)
  3450  		}
  3451  
  3452  		switch i := ric.Addr.String(); i {
  3453  		case "aws_instance.bar":
  3454  			if res.Action != plans.Create {
  3455  				t.Fatalf("resource %s should be created", i)
  3456  			}
  3457  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3458  				"id":   cty.UnknownVal(cty.String),
  3459  				"num":  cty.NumberIntVal(3),
  3460  				"type": cty.UnknownVal(cty.String),
  3461  			}), ric.After)
  3462  		case "aws_instance.foo":
  3463  			if res.Action != plans.Update {
  3464  				t.Fatalf("resource %s should be updated", i)
  3465  			}
  3466  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3467  				"id":   cty.StringVal("bar"),
  3468  				"num":  cty.NumberIntVal(2),
  3469  				"type": cty.StringVal("aws_instance"),
  3470  			}), ric.Before)
  3471  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3472  				"id":   cty.StringVal("bar"),
  3473  				"num":  cty.NumberIntVal(3),
  3474  				"type": cty.StringVal("aws_instance"),
  3475  			}), ric.After)
  3476  		default:
  3477  			t.Fatal("unknown instance:", i)
  3478  		}
  3479  	}
  3480  }
  3481  
  3482  func TestContext2Plan_hook(t *testing.T) {
  3483  	m := testModule(t, "plan-good")
  3484  	h := new(MockHook)
  3485  	p := testProvider("aws")
  3486  	ctx := testContext2(t, &ContextOpts{
  3487  		Hooks: []Hook{h},
  3488  		Providers: map[addrs.Provider]providers.Factory{
  3489  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3490  		},
  3491  	})
  3492  
  3493  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3494  	if diags.HasErrors() {
  3495  		t.Fatalf("unexpected errors: %s", diags.Err())
  3496  	}
  3497  
  3498  	if !h.PreDiffCalled {
  3499  		t.Fatal("should be called")
  3500  	}
  3501  	if !h.PostDiffCalled {
  3502  		t.Fatal("should be called")
  3503  	}
  3504  }
  3505  
  3506  func TestContext2Plan_closeProvider(t *testing.T) {
  3507  	// this fixture only has an aliased provider located in the module, to make
  3508  	// sure that the provier name contains a path more complex than
  3509  	// "provider.aws".
  3510  	m := testModule(t, "plan-close-module-provider")
  3511  	p := testProvider("aws")
  3512  	ctx := testContext2(t, &ContextOpts{
  3513  		Providers: map[addrs.Provider]providers.Factory{
  3514  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3515  		},
  3516  	})
  3517  
  3518  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3519  	if diags.HasErrors() {
  3520  		t.Fatalf("unexpected errors: %s", diags.Err())
  3521  	}
  3522  
  3523  	if !p.CloseCalled {
  3524  		t.Fatal("provider not closed")
  3525  	}
  3526  }
  3527  
  3528  func TestContext2Plan_orphan(t *testing.T) {
  3529  	m := testModule(t, "plan-orphan")
  3530  	p := testProvider("aws")
  3531  	p.PlanResourceChangeFn = testDiffFn
  3532  	state := states.NewState()
  3533  	root := state.EnsureModule(addrs.RootModuleInstance)
  3534  	root.SetResourceInstanceCurrent(
  3535  		mustResourceInstanceAddr("aws_instance.baz").Resource,
  3536  		&states.ResourceInstanceObjectSrc{
  3537  			Status:    states.ObjectReady,
  3538  			AttrsJSON: []byte(`{"id":"bar"}`),
  3539  		},
  3540  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3541  	)
  3542  
  3543  	ctx := testContext2(t, &ContextOpts{
  3544  		Providers: map[addrs.Provider]providers.Factory{
  3545  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3546  		},
  3547  	})
  3548  
  3549  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3550  	if diags.HasErrors() {
  3551  		t.Fatalf("unexpected errors: %s", diags.Err())
  3552  	}
  3553  
  3554  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3555  	ty := schema.ImpliedType()
  3556  
  3557  	if len(plan.Changes.Resources) != 2 {
  3558  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  3559  	}
  3560  
  3561  	for _, res := range plan.Changes.Resources {
  3562  		ric, err := res.Decode(ty)
  3563  		if err != nil {
  3564  			t.Fatal(err)
  3565  		}
  3566  
  3567  		switch i := ric.Addr.String(); i {
  3568  		case "aws_instance.baz":
  3569  			if res.Action != plans.Delete {
  3570  				t.Fatalf("resource %s should be removed", i)
  3571  			}
  3572  			if got, want := ric.ActionReason, plans.ResourceInstanceDeleteBecauseNoResourceConfig; got != want {
  3573  				t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
  3574  			}
  3575  		case "aws_instance.foo":
  3576  			if res.Action != plans.Create {
  3577  				t.Fatalf("resource %s should be created", i)
  3578  			}
  3579  			if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
  3580  				t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
  3581  			}
  3582  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3583  				"id":   cty.UnknownVal(cty.String),
  3584  				"num":  cty.NumberIntVal(2),
  3585  				"type": cty.UnknownVal(cty.String),
  3586  			}), ric.After)
  3587  		default:
  3588  			t.Fatal("unknown instance:", i)
  3589  		}
  3590  	}
  3591  }
  3592  
  3593  // This tests that configurations with UUIDs don't produce errors.
  3594  // For shadows, this would produce errors since a UUID changes every time.
  3595  func TestContext2Plan_shadowUuid(t *testing.T) {
  3596  	m := testModule(t, "plan-shadow-uuid")
  3597  	p := testProvider("aws")
  3598  	ctx := testContext2(t, &ContextOpts{
  3599  		Providers: map[addrs.Provider]providers.Factory{
  3600  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3601  		},
  3602  	})
  3603  
  3604  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  3605  	if diags.HasErrors() {
  3606  		t.Fatalf("unexpected errors: %s", diags.Err())
  3607  	}
  3608  }
  3609  
  3610  func TestContext2Plan_state(t *testing.T) {
  3611  	m := testModule(t, "plan-good")
  3612  	p := testProvider("aws")
  3613  	p.PlanResourceChangeFn = testDiffFn
  3614  	state := states.NewState()
  3615  	root := state.EnsureModule(addrs.RootModuleInstance)
  3616  	root.SetResourceInstanceCurrent(
  3617  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  3618  		&states.ResourceInstanceObjectSrc{
  3619  			Status:    states.ObjectReady,
  3620  			AttrsJSON: []byte(`{"id":"bar"}`),
  3621  		},
  3622  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3623  	)
  3624  	ctx := testContext2(t, &ContextOpts{
  3625  		Providers: map[addrs.Provider]providers.Factory{
  3626  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3627  		},
  3628  	})
  3629  
  3630  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3631  	if diags.HasErrors() {
  3632  		t.Fatalf("unexpected errors: %s", diags.Err())
  3633  	}
  3634  
  3635  	if len(plan.Changes.Resources) < 2 {
  3636  		t.Fatalf("bad: %#v", plan.Changes.Resources)
  3637  	}
  3638  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3639  	ty := schema.ImpliedType()
  3640  
  3641  	if len(plan.Changes.Resources) != 2 {
  3642  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  3643  	}
  3644  
  3645  	for _, res := range plan.Changes.Resources {
  3646  		ric, err := res.Decode(ty)
  3647  		if err != nil {
  3648  			t.Fatal(err)
  3649  		}
  3650  
  3651  		switch i := ric.Addr.String(); i {
  3652  		case "aws_instance.bar":
  3653  			if res.Action != plans.Create {
  3654  				t.Fatalf("resource %s should be created", i)
  3655  			}
  3656  			if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
  3657  				t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
  3658  			}
  3659  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3660  				"id":   cty.UnknownVal(cty.String),
  3661  				"foo":  cty.StringVal("2"),
  3662  				"type": cty.UnknownVal(cty.String),
  3663  			}), ric.After)
  3664  		case "aws_instance.foo":
  3665  			if res.Action != plans.Update {
  3666  				t.Fatalf("resource %s should be updated", i)
  3667  			}
  3668  			if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
  3669  				t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
  3670  			}
  3671  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3672  				"id":   cty.StringVal("bar"),
  3673  				"num":  cty.NullVal(cty.Number),
  3674  				"type": cty.NullVal(cty.String),
  3675  			}), ric.Before)
  3676  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3677  				"id":   cty.StringVal("bar"),
  3678  				"num":  cty.NumberIntVal(2),
  3679  				"type": cty.UnknownVal(cty.String),
  3680  			}), ric.After)
  3681  		default:
  3682  			t.Fatal("unknown instance:", i)
  3683  		}
  3684  	}
  3685  }
  3686  
  3687  func TestContext2Plan_requiresReplace(t *testing.T) {
  3688  	m := testModule(t, "plan-requires-replace")
  3689  	p := testProvider("test")
  3690  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  3691  		Provider: providers.Schema{
  3692  			Block: &configschema.Block{},
  3693  		},
  3694  		ResourceTypes: map[string]providers.Schema{
  3695  			"test_thing": {
  3696  				Block: &configschema.Block{
  3697  					Attributes: map[string]*configschema.Attribute{
  3698  						"v": {
  3699  							Type:     cty.String,
  3700  							Required: true,
  3701  						},
  3702  					},
  3703  				},
  3704  			},
  3705  		},
  3706  	}
  3707  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  3708  		return providers.PlanResourceChangeResponse{
  3709  			PlannedState: req.ProposedNewState,
  3710  			RequiresReplace: []cty.Path{
  3711  				cty.GetAttrPath("v"),
  3712  			},
  3713  		}
  3714  	}
  3715  
  3716  	state := states.NewState()
  3717  	root := state.EnsureModule(addrs.RootModuleInstance)
  3718  	root.SetResourceInstanceCurrent(
  3719  		mustResourceInstanceAddr("test_thing.foo").Resource,
  3720  		&states.ResourceInstanceObjectSrc{
  3721  			Status:    states.ObjectReady,
  3722  			AttrsJSON: []byte(`{"v":"hello"}`),
  3723  		},
  3724  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
  3725  	)
  3726  
  3727  	ctx := testContext2(t, &ContextOpts{
  3728  		Providers: map[addrs.Provider]providers.Factory{
  3729  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  3730  		},
  3731  	})
  3732  
  3733  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3734  	if diags.HasErrors() {
  3735  		t.Fatalf("unexpected errors: %s", diags.Err())
  3736  	}
  3737  
  3738  	schema := p.GetProviderSchemaResponse.ResourceTypes["test_thing"].Block
  3739  	ty := schema.ImpliedType()
  3740  
  3741  	if got, want := len(plan.Changes.Resources), 1; got != want {
  3742  		t.Fatalf("got %d changes; want %d", got, want)
  3743  	}
  3744  
  3745  	for _, res := range plan.Changes.Resources {
  3746  		t.Run(res.Addr.String(), func(t *testing.T) {
  3747  			ric, err := res.Decode(ty)
  3748  			if err != nil {
  3749  				t.Fatal(err)
  3750  			}
  3751  
  3752  			switch i := ric.Addr.String(); i {
  3753  			case "test_thing.foo":
  3754  				if got, want := ric.Action, plans.DeleteThenCreate; got != want {
  3755  					t.Errorf("wrong action\ngot:  %s\nwant: %s", got, want)
  3756  				}
  3757  				if got, want := ric.ActionReason, plans.ResourceInstanceReplaceBecauseCannotUpdate; got != want {
  3758  					t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
  3759  				}
  3760  				checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3761  					"v": cty.StringVal("goodbye"),
  3762  				}), ric.After)
  3763  			default:
  3764  				t.Fatalf("unexpected resource instance %s", i)
  3765  			}
  3766  		})
  3767  	}
  3768  }
  3769  
  3770  func TestContext2Plan_taint(t *testing.T) {
  3771  	m := testModule(t, "plan-taint")
  3772  	p := testProvider("aws")
  3773  	p.PlanResourceChangeFn = testDiffFn
  3774  	state := states.NewState()
  3775  	root := state.EnsureModule(addrs.RootModuleInstance)
  3776  	root.SetResourceInstanceCurrent(
  3777  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  3778  		&states.ResourceInstanceObjectSrc{
  3779  			Status:    states.ObjectReady,
  3780  			AttrsJSON: []byte(`{"id":"bar","num":"2","type":"aws_instance"}`),
  3781  		},
  3782  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3783  	)
  3784  	root.SetResourceInstanceCurrent(
  3785  		mustResourceInstanceAddr("aws_instance.bar").Resource,
  3786  		&states.ResourceInstanceObjectSrc{
  3787  			Status:    states.ObjectTainted,
  3788  			AttrsJSON: []byte(`{"id":"baz"}`),
  3789  		},
  3790  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3791  	)
  3792  
  3793  	ctx := testContext2(t, &ContextOpts{
  3794  		Providers: map[addrs.Provider]providers.Factory{
  3795  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3796  		},
  3797  	})
  3798  
  3799  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3800  	if diags.HasErrors() {
  3801  		t.Fatalf("unexpected errors: %s", diags.Err())
  3802  	}
  3803  
  3804  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3805  	ty := schema.ImpliedType()
  3806  
  3807  	if len(plan.Changes.Resources) != 2 {
  3808  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  3809  	}
  3810  
  3811  	for _, res := range plan.Changes.Resources {
  3812  		t.Run(res.Addr.String(), func(t *testing.T) {
  3813  			ric, err := res.Decode(ty)
  3814  			if err != nil {
  3815  				t.Fatal(err)
  3816  			}
  3817  
  3818  			switch i := ric.Addr.String(); i {
  3819  			case "aws_instance.bar":
  3820  				if got, want := res.Action, plans.DeleteThenCreate; got != want {
  3821  					t.Errorf("wrong action\ngot:  %s\nwant: %s", got, want)
  3822  				}
  3823  				if got, want := res.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want {
  3824  					t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
  3825  				}
  3826  				checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3827  					"id":   cty.UnknownVal(cty.String),
  3828  					"foo":  cty.StringVal("2"),
  3829  					"type": cty.UnknownVal(cty.String),
  3830  				}), ric.After)
  3831  			case "aws_instance.foo":
  3832  				if got, want := res.Action, plans.NoOp; got != want {
  3833  					t.Errorf("wrong action\ngot:  %s\nwant: %s", got, want)
  3834  				}
  3835  				if got, want := res.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
  3836  					t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
  3837  				}
  3838  			default:
  3839  				t.Fatal("unknown instance:", i)
  3840  			}
  3841  		})
  3842  	}
  3843  }
  3844  
  3845  func TestContext2Plan_taintIgnoreChanges(t *testing.T) {
  3846  	m := testModule(t, "plan-taint-ignore-changes")
  3847  	p := testProvider("aws")
  3848  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  3849  		ResourceTypes: map[string]*configschema.Block{
  3850  			"aws_instance": {
  3851  				Attributes: map[string]*configschema.Attribute{
  3852  					"id":   {Type: cty.String, Computed: true},
  3853  					"vars": {Type: cty.String, Optional: true},
  3854  					"type": {Type: cty.String, Computed: true},
  3855  				},
  3856  			},
  3857  		},
  3858  	})
  3859  
  3860  	state := states.NewState()
  3861  	root := state.EnsureModule(addrs.RootModuleInstance)
  3862  	root.SetResourceInstanceCurrent(
  3863  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  3864  		&states.ResourceInstanceObjectSrc{
  3865  			Status:    states.ObjectTainted,
  3866  			AttrsJSON: []byte(`{"id":"foo","vars":"foo","type":"aws_instance"}`),
  3867  		},
  3868  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3869  	)
  3870  
  3871  	ctx := testContext2(t, &ContextOpts{
  3872  		Providers: map[addrs.Provider]providers.Factory{
  3873  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3874  		},
  3875  	})
  3876  
  3877  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  3878  	if diags.HasErrors() {
  3879  		t.Fatalf("unexpected errors: %s", diags.Err())
  3880  	}
  3881  
  3882  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3883  	ty := schema.ImpliedType()
  3884  
  3885  	if len(plan.Changes.Resources) != 1 {
  3886  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  3887  	}
  3888  
  3889  	for _, res := range plan.Changes.Resources {
  3890  		ric, err := res.Decode(ty)
  3891  		if err != nil {
  3892  			t.Fatal(err)
  3893  		}
  3894  
  3895  		switch i := ric.Addr.String(); i {
  3896  		case "aws_instance.foo":
  3897  			if got, want := res.Action, plans.DeleteThenCreate; got != want {
  3898  				t.Errorf("wrong action\ngot:  %s\nwant: %s", got, want)
  3899  			}
  3900  			if got, want := res.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want {
  3901  				t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
  3902  			}
  3903  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3904  				"id":   cty.StringVal("foo"),
  3905  				"vars": cty.StringVal("foo"),
  3906  				"type": cty.StringVal("aws_instance"),
  3907  			}), ric.Before)
  3908  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3909  				"id":   cty.UnknownVal(cty.String),
  3910  				"vars": cty.StringVal("foo"),
  3911  				"type": cty.UnknownVal(cty.String),
  3912  			}), ric.After)
  3913  		default:
  3914  			t.Fatal("unknown instance:", i)
  3915  		}
  3916  	}
  3917  }
  3918  
  3919  // Fails about 50% of the time before the fix for GH-4982, covers the fix.
  3920  func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
  3921  	m := testModule(t, "plan-taint-interpolated-count")
  3922  	p := testProvider("aws")
  3923  	p.PlanResourceChangeFn = testDiffFn
  3924  	state := states.NewState()
  3925  	root := state.EnsureModule(addrs.RootModuleInstance)
  3926  	root.SetResourceInstanceCurrent(
  3927  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  3928  		&states.ResourceInstanceObjectSrc{
  3929  			Status:    states.ObjectTainted,
  3930  			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
  3931  		},
  3932  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3933  	)
  3934  	root.SetResourceInstanceCurrent(
  3935  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  3936  		&states.ResourceInstanceObjectSrc{
  3937  			Status:    states.ObjectReady,
  3938  			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
  3939  		},
  3940  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3941  	)
  3942  	root.SetResourceInstanceCurrent(
  3943  		mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
  3944  		&states.ResourceInstanceObjectSrc{
  3945  			Status:    states.ObjectReady,
  3946  			AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
  3947  		},
  3948  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  3949  	)
  3950  
  3951  	for i := 0; i < 100; i++ {
  3952  		ctx := testContext2(t, &ContextOpts{
  3953  			Providers: map[addrs.Provider]providers.Factory{
  3954  				addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  3955  			},
  3956  		})
  3957  
  3958  		plan, diags := ctx.Plan(m, state.DeepCopy(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  3959  		if diags.HasErrors() {
  3960  			t.Fatalf("unexpected errors: %s", diags.Err())
  3961  		}
  3962  
  3963  		schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  3964  		ty := schema.ImpliedType()
  3965  
  3966  		if len(plan.Changes.Resources) != 3 {
  3967  			t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
  3968  		}
  3969  
  3970  		for _, res := range plan.Changes.Resources {
  3971  			ric, err := res.Decode(ty)
  3972  			if err != nil {
  3973  				t.Fatal(err)
  3974  			}
  3975  
  3976  			switch i := ric.Addr.String(); i {
  3977  			case "aws_instance.foo[0]":
  3978  				if got, want := ric.Action, plans.DeleteThenCreate; got != want {
  3979  					t.Errorf("wrong action\ngot:  %s\nwant: %s", got, want)
  3980  				}
  3981  				if got, want := ric.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want {
  3982  					t.Errorf("wrong action reason\ngot:  %s\nwant: %s", got, want)
  3983  				}
  3984  				checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3985  					"id":   cty.StringVal("bar"),
  3986  					"type": cty.StringVal("aws_instance"),
  3987  				}), ric.Before)
  3988  				checkVals(t, objectVal(t, schema, map[string]cty.Value{
  3989  					"id":   cty.UnknownVal(cty.String),
  3990  					"type": cty.UnknownVal(cty.String),
  3991  				}), ric.After)
  3992  			case "aws_instance.foo[1]", "aws_instance.foo[2]":
  3993  				if res.Action != plans.NoOp {
  3994  					t.Fatalf("resource %s should not be changed", i)
  3995  				}
  3996  			default:
  3997  				t.Fatal("unknown instance:", i)
  3998  			}
  3999  		}
  4000  	}
  4001  }
  4002  
  4003  func TestContext2Plan_targeted(t *testing.T) {
  4004  	m := testModule(t, "plan-targeted")
  4005  	p := testProvider("aws")
  4006  	p.PlanResourceChangeFn = testDiffFn
  4007  	ctx := testContext2(t, &ContextOpts{
  4008  		Providers: map[addrs.Provider]providers.Factory{
  4009  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4010  		},
  4011  	})
  4012  
  4013  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  4014  		Mode: plans.NormalMode,
  4015  		Targets: []addrs.Targetable{
  4016  			addrs.RootModuleInstance.Resource(
  4017  				addrs.ManagedResourceMode, "aws_instance", "foo",
  4018  			),
  4019  		},
  4020  	})
  4021  	if diags.HasErrors() {
  4022  		t.Fatalf("unexpected errors: %s", diags.Err())
  4023  	}
  4024  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  4025  	ty := schema.ImpliedType()
  4026  
  4027  	if len(plan.Changes.Resources) != 1 {
  4028  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  4029  	}
  4030  
  4031  	for _, res := range plan.Changes.Resources {
  4032  		ric, err := res.Decode(ty)
  4033  		if err != nil {
  4034  			t.Fatal(err)
  4035  		}
  4036  
  4037  		switch i := ric.Addr.String(); i {
  4038  		case "aws_instance.foo":
  4039  			if res.Action != plans.Create {
  4040  				t.Fatalf("resource %s should be created", i)
  4041  			}
  4042  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4043  				"id":   cty.UnknownVal(cty.String),
  4044  				"num":  cty.NumberIntVal(2),
  4045  				"type": cty.UnknownVal(cty.String),
  4046  			}), ric.After)
  4047  		default:
  4048  			t.Fatal("unknown instance:", i)
  4049  		}
  4050  	}
  4051  }
  4052  
  4053  // Test that targeting a module properly plans any inputs that depend
  4054  // on another module.
  4055  func TestContext2Plan_targetedCrossModule(t *testing.T) {
  4056  	m := testModule(t, "plan-targeted-cross-module")
  4057  	p := testProvider("aws")
  4058  	p.PlanResourceChangeFn = testDiffFn
  4059  	ctx := testContext2(t, &ContextOpts{
  4060  		Providers: map[addrs.Provider]providers.Factory{
  4061  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4062  		},
  4063  	})
  4064  
  4065  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  4066  		Mode: plans.NormalMode,
  4067  		Targets: []addrs.Targetable{
  4068  			addrs.RootModuleInstance.Child("B", addrs.NoKey),
  4069  		},
  4070  	})
  4071  	if diags.HasErrors() {
  4072  		t.Fatalf("unexpected errors: %s", diags.Err())
  4073  	}
  4074  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  4075  	ty := schema.ImpliedType()
  4076  
  4077  	if len(plan.Changes.Resources) != 2 {
  4078  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  4079  	}
  4080  
  4081  	for _, res := range plan.Changes.Resources {
  4082  		ric, err := res.Decode(ty)
  4083  		if err != nil {
  4084  			t.Fatal(err)
  4085  		}
  4086  		if res.Action != plans.Create {
  4087  			t.Fatalf("resource %s should be created", ric.Addr)
  4088  		}
  4089  		switch i := ric.Addr.String(); i {
  4090  		case "module.A.aws_instance.foo":
  4091  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4092  				"id":   cty.UnknownVal(cty.String),
  4093  				"foo":  cty.StringVal("bar"),
  4094  				"type": cty.UnknownVal(cty.String),
  4095  			}), ric.After)
  4096  		case "module.B.aws_instance.bar":
  4097  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4098  				"id":   cty.UnknownVal(cty.String),
  4099  				"foo":  cty.UnknownVal(cty.String),
  4100  				"type": cty.UnknownVal(cty.String),
  4101  			}), ric.After)
  4102  		default:
  4103  			t.Fatal("unknown instance:", i)
  4104  		}
  4105  	}
  4106  }
  4107  
  4108  func TestContext2Plan_targetedModuleWithProvider(t *testing.T) {
  4109  	m := testModule(t, "plan-targeted-module-with-provider")
  4110  	p := testProvider("null")
  4111  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4112  		Provider: &configschema.Block{
  4113  			Attributes: map[string]*configschema.Attribute{
  4114  				"key": {Type: cty.String, Optional: true},
  4115  			},
  4116  		},
  4117  		ResourceTypes: map[string]*configschema.Block{
  4118  			"null_resource": {
  4119  				Attributes: map[string]*configschema.Attribute{},
  4120  			},
  4121  		},
  4122  	})
  4123  
  4124  	ctx := testContext2(t, &ContextOpts{
  4125  		Providers: map[addrs.Provider]providers.Factory{
  4126  			addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
  4127  		},
  4128  	})
  4129  
  4130  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  4131  		Mode: plans.NormalMode,
  4132  		Targets: []addrs.Targetable{
  4133  			addrs.RootModuleInstance.Child("child2", addrs.NoKey),
  4134  		},
  4135  	})
  4136  	if diags.HasErrors() {
  4137  		t.Fatalf("unexpected errors: %s", diags.Err())
  4138  	}
  4139  
  4140  	schema := p.GetProviderSchemaResponse.ResourceTypes["null_resource"].Block
  4141  	ty := schema.ImpliedType()
  4142  
  4143  	if len(plan.Changes.Resources) != 1 {
  4144  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  4145  	}
  4146  
  4147  	res := plan.Changes.Resources[0]
  4148  	ric, err := res.Decode(ty)
  4149  	if err != nil {
  4150  		t.Fatal(err)
  4151  	}
  4152  
  4153  	if ric.Addr.String() != "module.child2.null_resource.foo" {
  4154  		t.Fatalf("unexpcetd resource: %s", ric.Addr)
  4155  	}
  4156  }
  4157  
  4158  func TestContext2Plan_targetedOrphan(t *testing.T) {
  4159  	m := testModule(t, "plan-targeted-orphan")
  4160  	p := testProvider("aws")
  4161  
  4162  	state := states.NewState()
  4163  	root := state.EnsureModule(addrs.RootModuleInstance)
  4164  	root.SetResourceInstanceCurrent(
  4165  		mustResourceInstanceAddr("aws_instance.orphan").Resource,
  4166  		&states.ResourceInstanceObjectSrc{
  4167  			Status:    states.ObjectReady,
  4168  			AttrsJSON: []byte(`{"id":"i-789xyz"}`),
  4169  		},
  4170  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4171  	)
  4172  	root.SetResourceInstanceCurrent(
  4173  		mustResourceInstanceAddr("aws_instance.nottargeted").Resource,
  4174  		&states.ResourceInstanceObjectSrc{
  4175  			Status:    states.ObjectReady,
  4176  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  4177  		},
  4178  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4179  	)
  4180  
  4181  	ctx := testContext2(t, &ContextOpts{
  4182  		Providers: map[addrs.Provider]providers.Factory{
  4183  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4184  		},
  4185  	})
  4186  
  4187  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4188  		Mode: plans.DestroyMode,
  4189  		Targets: []addrs.Targetable{
  4190  			addrs.RootModuleInstance.Resource(
  4191  				addrs.ManagedResourceMode, "aws_instance", "orphan",
  4192  			),
  4193  		},
  4194  	})
  4195  	if diags.HasErrors() {
  4196  		t.Fatalf("unexpected errors: %s", diags.Err())
  4197  	}
  4198  
  4199  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  4200  	ty := schema.ImpliedType()
  4201  
  4202  	if len(plan.Changes.Resources) != 1 {
  4203  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  4204  	}
  4205  
  4206  	for _, res := range plan.Changes.Resources {
  4207  		ric, err := res.Decode(ty)
  4208  		if err != nil {
  4209  			t.Fatal(err)
  4210  		}
  4211  
  4212  		switch i := ric.Addr.String(); i {
  4213  		case "aws_instance.orphan":
  4214  			if res.Action != plans.Delete {
  4215  				t.Fatalf("resource %s should be destroyed", ric.Addr)
  4216  			}
  4217  		default:
  4218  			t.Fatal("unknown instance:", i)
  4219  		}
  4220  	}
  4221  }
  4222  
  4223  // https://github.com/hashicorp/terraform/issues/2538
  4224  func TestContext2Plan_targetedModuleOrphan(t *testing.T) {
  4225  	m := testModule(t, "plan-targeted-module-orphan")
  4226  	p := testProvider("aws")
  4227  
  4228  	state := states.NewState()
  4229  	child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
  4230  	child.SetResourceInstanceCurrent(
  4231  		mustResourceInstanceAddr("aws_instance.orphan").Resource,
  4232  		&states.ResourceInstanceObjectSrc{
  4233  			Status:    states.ObjectReady,
  4234  			AttrsJSON: []byte(`{"id":"i-789xyz"}`),
  4235  		},
  4236  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4237  	)
  4238  	child.SetResourceInstanceCurrent(
  4239  		mustResourceInstanceAddr("aws_instance.nottargeted").Resource,
  4240  		&states.ResourceInstanceObjectSrc{
  4241  			Status:    states.ObjectReady,
  4242  			AttrsJSON: []byte(`{"id":"i-abc123"}`),
  4243  		},
  4244  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4245  	)
  4246  
  4247  	ctx := testContext2(t, &ContextOpts{
  4248  		Providers: map[addrs.Provider]providers.Factory{
  4249  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4250  		},
  4251  	})
  4252  
  4253  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4254  		Mode: plans.DestroyMode,
  4255  		Targets: []addrs.Targetable{
  4256  			addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
  4257  				addrs.ManagedResourceMode, "aws_instance", "orphan",
  4258  			),
  4259  		},
  4260  	})
  4261  	if diags.HasErrors() {
  4262  		t.Fatalf("unexpected errors: %s", diags.Err())
  4263  	}
  4264  
  4265  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  4266  	ty := schema.ImpliedType()
  4267  
  4268  	if len(plan.Changes.Resources) != 1 {
  4269  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  4270  	}
  4271  
  4272  	res := plan.Changes.Resources[0]
  4273  	ric, err := res.Decode(ty)
  4274  	if err != nil {
  4275  		t.Fatal(err)
  4276  	}
  4277  
  4278  	if ric.Addr.String() != "module.child.aws_instance.orphan" {
  4279  		t.Fatalf("unexpected resource :%s", ric.Addr)
  4280  	}
  4281  	if res.Action != plans.Delete {
  4282  		t.Fatalf("resource %s should be deleted", ric.Addr)
  4283  	}
  4284  }
  4285  
  4286  func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) {
  4287  	m := testModule(t, "plan-targeted-module-untargeted-variable")
  4288  	p := testProvider("aws")
  4289  	p.PlanResourceChangeFn = testDiffFn
  4290  	ctx := testContext2(t, &ContextOpts{
  4291  		Providers: map[addrs.Provider]providers.Factory{
  4292  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4293  		},
  4294  	})
  4295  
  4296  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  4297  		Targets: []addrs.Targetable{
  4298  			addrs.RootModuleInstance.Resource(
  4299  				addrs.ManagedResourceMode, "aws_instance", "blue",
  4300  			),
  4301  			addrs.RootModuleInstance.Child("blue_mod", addrs.NoKey),
  4302  		},
  4303  	})
  4304  	if diags.HasErrors() {
  4305  		t.Fatalf("unexpected errors: %s", diags.Err())
  4306  	}
  4307  
  4308  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  4309  	ty := schema.ImpliedType()
  4310  
  4311  	if len(plan.Changes.Resources) != 2 {
  4312  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  4313  	}
  4314  
  4315  	for _, res := range plan.Changes.Resources {
  4316  		ric, err := res.Decode(ty)
  4317  		if err != nil {
  4318  			t.Fatal(err)
  4319  		}
  4320  		if res.Action != plans.Create {
  4321  			t.Fatalf("resource %s should be created", ric.Addr)
  4322  		}
  4323  		switch i := ric.Addr.String(); i {
  4324  		case "aws_instance.blue":
  4325  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4326  				"id":   cty.UnknownVal(cty.String),
  4327  				"type": cty.UnknownVal(cty.String),
  4328  			}), ric.After)
  4329  		case "module.blue_mod.aws_instance.mod":
  4330  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4331  				"id":    cty.UnknownVal(cty.String),
  4332  				"value": cty.UnknownVal(cty.String),
  4333  				"type":  cty.UnknownVal(cty.String),
  4334  			}), ric.After)
  4335  		default:
  4336  			t.Fatal("unknown instance:", i)
  4337  		}
  4338  	}
  4339  }
  4340  
  4341  // ensure that outputs missing references due to targetting are removed from
  4342  // the graph.
  4343  func TestContext2Plan_outputContainsTargetedResource(t *testing.T) {
  4344  	m := testModule(t, "plan-untargeted-resource-output")
  4345  	p := testProvider("aws")
  4346  	ctx := testContext2(t, &ContextOpts{
  4347  		Providers: map[addrs.Provider]providers.Factory{
  4348  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4349  		},
  4350  	})
  4351  
  4352  	_, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  4353  		Targets: []addrs.Targetable{
  4354  			addrs.RootModuleInstance.Child("mod", addrs.NoKey).Resource(
  4355  				addrs.ManagedResourceMode, "aws_instance", "a",
  4356  			),
  4357  		},
  4358  	})
  4359  	if diags.HasErrors() {
  4360  		t.Fatalf("err: %s", diags)
  4361  	}
  4362  	if len(diags) != 1 {
  4363  		t.Fatalf("got %d diagnostics; want 1", diags)
  4364  	}
  4365  	if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
  4366  		t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
  4367  	}
  4368  	if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want {
  4369  		t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
  4370  	}
  4371  }
  4372  
  4373  // https://github.com/hashicorp/terraform/issues/4515
  4374  func TestContext2Plan_targetedOverTen(t *testing.T) {
  4375  	m := testModule(t, "plan-targeted-over-ten")
  4376  	p := testProvider("aws")
  4377  	p.PlanResourceChangeFn = testDiffFn
  4378  
  4379  	state := states.NewState()
  4380  	root := state.EnsureModule(addrs.RootModuleInstance)
  4381  	for i := 0; i < 13; i++ {
  4382  		key := fmt.Sprintf("aws_instance.foo[%d]", i)
  4383  		id := fmt.Sprintf("i-abc%d", i)
  4384  		attrs := fmt.Sprintf(`{"id":"%s","type":"aws_instance"}`, id)
  4385  
  4386  		root.SetResourceInstanceCurrent(
  4387  			mustResourceInstanceAddr(key).Resource,
  4388  			&states.ResourceInstanceObjectSrc{
  4389  				Status:    states.ObjectReady,
  4390  				AttrsJSON: []byte(attrs),
  4391  			},
  4392  			mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4393  		)
  4394  	}
  4395  
  4396  	ctx := testContext2(t, &ContextOpts{
  4397  		Providers: map[addrs.Provider]providers.Factory{
  4398  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4399  		},
  4400  	})
  4401  
  4402  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4403  		Targets: []addrs.Targetable{
  4404  			addrs.RootModuleInstance.ResourceInstance(
  4405  				addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(1),
  4406  			),
  4407  		},
  4408  	})
  4409  	if diags.HasErrors() {
  4410  		t.Fatalf("unexpected errors: %s", diags.Err())
  4411  	}
  4412  
  4413  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  4414  	ty := schema.ImpliedType()
  4415  
  4416  	for _, res := range plan.Changes.Resources {
  4417  		ric, err := res.Decode(ty)
  4418  		if err != nil {
  4419  			t.Fatal(err)
  4420  		}
  4421  		if res.Action != plans.NoOp {
  4422  			t.Fatalf("unexpected action %s for %s", res.Action, ric.Addr)
  4423  		}
  4424  	}
  4425  }
  4426  
  4427  func TestContext2Plan_provider(t *testing.T) {
  4428  	m := testModule(t, "plan-provider")
  4429  	p := testProvider("aws")
  4430  
  4431  	var value interface{}
  4432  	p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
  4433  		value = req.Config.GetAttr("foo").AsString()
  4434  		return
  4435  	}
  4436  
  4437  	ctx := testContext2(t, &ContextOpts{
  4438  		Providers: map[addrs.Provider]providers.Factory{
  4439  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4440  		},
  4441  	})
  4442  	opts := &PlanOpts{
  4443  		Mode: plans.NormalMode,
  4444  		SetVariables: InputValues{
  4445  			"foo": &InputValue{
  4446  				Value:      cty.StringVal("bar"),
  4447  				SourceType: ValueFromCaller,
  4448  			},
  4449  		},
  4450  	}
  4451  
  4452  	if _, err := ctx.Plan(m, states.NewState(), opts); err != nil {
  4453  		t.Fatalf("err: %s", err)
  4454  	}
  4455  
  4456  	if value != "bar" {
  4457  		t.Fatalf("bad: %#v", value)
  4458  	}
  4459  }
  4460  
  4461  func TestContext2Plan_varListErr(t *testing.T) {
  4462  	m := testModule(t, "plan-var-list-err")
  4463  	p := testProvider("aws")
  4464  	ctx := testContext2(t, &ContextOpts{
  4465  		Providers: map[addrs.Provider]providers.Factory{
  4466  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4467  		},
  4468  	})
  4469  
  4470  	_, err := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4471  
  4472  	if err == nil {
  4473  		t.Fatal("should error")
  4474  	}
  4475  }
  4476  
  4477  func TestContext2Plan_ignoreChanges(t *testing.T) {
  4478  	m := testModule(t, "plan-ignore-changes")
  4479  	p := testProvider("aws")
  4480  	p.PlanResourceChangeFn = testDiffFn
  4481  
  4482  	state := states.NewState()
  4483  	root := state.EnsureModule(addrs.RootModuleInstance)
  4484  	root.SetResourceInstanceCurrent(
  4485  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  4486  		&states.ResourceInstanceObjectSrc{
  4487  			Status:    states.ObjectReady,
  4488  			AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","type":"aws_instance"}`),
  4489  		},
  4490  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4491  	)
  4492  
  4493  	ctx := testContext2(t, &ContextOpts{
  4494  		Providers: map[addrs.Provider]providers.Factory{
  4495  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4496  		},
  4497  	})
  4498  
  4499  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4500  		Mode: plans.NormalMode,
  4501  		SetVariables: InputValues{
  4502  			"foo": &InputValue{
  4503  				Value:      cty.StringVal("ami-1234abcd"),
  4504  				SourceType: ValueFromCaller,
  4505  			},
  4506  		},
  4507  	})
  4508  	if diags.HasErrors() {
  4509  		t.Fatalf("unexpected errors: %s", diags.Err())
  4510  	}
  4511  
  4512  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  4513  	ty := schema.ImpliedType()
  4514  
  4515  	if len(plan.Changes.Resources) != 1 {
  4516  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  4517  	}
  4518  
  4519  	res := plan.Changes.Resources[0]
  4520  	ric, err := res.Decode(ty)
  4521  	if err != nil {
  4522  		t.Fatal(err)
  4523  	}
  4524  
  4525  	if ric.Addr.String() != "aws_instance.foo" {
  4526  		t.Fatalf("unexpected resource: %s", ric.Addr)
  4527  	}
  4528  
  4529  	checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4530  		"id":   cty.StringVal("bar"),
  4531  		"ami":  cty.StringVal("ami-abcd1234"),
  4532  		"type": cty.StringVal("aws_instance"),
  4533  	}), ric.After)
  4534  }
  4535  
  4536  func TestContext2Plan_ignoreChangesWildcard(t *testing.T) {
  4537  	m := testModule(t, "plan-ignore-changes-wildcard")
  4538  	p := testProvider("aws")
  4539  	p.PlanResourceChangeFn = testDiffFn
  4540  
  4541  	state := states.NewState()
  4542  	root := state.EnsureModule(addrs.RootModuleInstance)
  4543  	root.SetResourceInstanceCurrent(
  4544  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  4545  		&states.ResourceInstanceObjectSrc{
  4546  			Status:    states.ObjectReady,
  4547  			AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","instance":"t2.micro","type":"aws_instance"}`),
  4548  		},
  4549  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4550  	)
  4551  
  4552  	ctx := testContext2(t, &ContextOpts{
  4553  		Providers: map[addrs.Provider]providers.Factory{
  4554  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4555  		},
  4556  	})
  4557  
  4558  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4559  		Mode: plans.NormalMode,
  4560  		SetVariables: InputValues{
  4561  			"foo": &InputValue{
  4562  				Value:      cty.StringVal("ami-1234abcd"),
  4563  				SourceType: ValueFromCaller,
  4564  			},
  4565  			"bar": &InputValue{
  4566  				Value:      cty.StringVal("t2.small"),
  4567  				SourceType: ValueFromCaller,
  4568  			},
  4569  		},
  4570  	})
  4571  	if diags.HasErrors() {
  4572  		t.Fatalf("unexpected errors: %s", diags.Err())
  4573  	}
  4574  
  4575  	for _, res := range plan.Changes.Resources {
  4576  		if res.Action != plans.NoOp {
  4577  			t.Fatalf("unexpected resource diffs in root module: %s", spew.Sdump(plan.Changes.Resources))
  4578  		}
  4579  	}
  4580  }
  4581  
  4582  func TestContext2Plan_ignoreChangesInMap(t *testing.T) {
  4583  	p := testProvider("test")
  4584  
  4585  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4586  		ResourceTypes: map[string]*configschema.Block{
  4587  			"test_ignore_changes_map": {
  4588  				Attributes: map[string]*configschema.Attribute{
  4589  					"tags": {Type: cty.Map(cty.String), Optional: true},
  4590  				},
  4591  			},
  4592  		},
  4593  	})
  4594  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  4595  		return providers.PlanResourceChangeResponse{
  4596  			PlannedState: req.ProposedNewState,
  4597  		}
  4598  	}
  4599  
  4600  	s := states.BuildState(func(ss *states.SyncState) {
  4601  		ss.SetResourceInstanceCurrent(
  4602  			addrs.Resource{
  4603  				Mode: addrs.ManagedResourceMode,
  4604  				Type: "test_ignore_changes_map",
  4605  				Name: "foo",
  4606  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  4607  			&states.ResourceInstanceObjectSrc{
  4608  				Status:    states.ObjectReady,
  4609  				AttrsJSON: []byte(`{"id":"foo","tags":{"ignored":"from state","other":"from state"},"type":"aws_instance"}`),
  4610  			},
  4611  			addrs.AbsProviderConfig{
  4612  				Provider: addrs.NewDefaultProvider("test"),
  4613  				Module:   addrs.RootModule,
  4614  			},
  4615  		)
  4616  	})
  4617  	m := testModule(t, "plan-ignore-changes-in-map")
  4618  
  4619  	ctx := testContext2(t, &ContextOpts{
  4620  		Providers: map[addrs.Provider]providers.Factory{
  4621  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  4622  		},
  4623  	})
  4624  
  4625  	plan, diags := ctx.Plan(m, s, DefaultPlanOpts)
  4626  	if diags.HasErrors() {
  4627  		t.Fatalf("unexpected errors: %s", diags.Err())
  4628  	}
  4629  
  4630  	schema := p.GetProviderSchemaResponse.ResourceTypes["test_ignore_changes_map"].Block
  4631  	ty := schema.ImpliedType()
  4632  
  4633  	if got, want := len(plan.Changes.Resources), 1; got != want {
  4634  		t.Fatalf("wrong number of changes %d; want %d", got, want)
  4635  	}
  4636  
  4637  	res := plan.Changes.Resources[0]
  4638  	ric, err := res.Decode(ty)
  4639  	if err != nil {
  4640  		t.Fatal(err)
  4641  	}
  4642  	if res.Action != plans.Update {
  4643  		t.Fatalf("resource %s should be updated, got %s", ric.Addr, res.Action)
  4644  	}
  4645  
  4646  	if got, want := ric.Addr.String(), "test_ignore_changes_map.foo"; got != want {
  4647  		t.Fatalf("unexpected resource address %s; want %s", got, want)
  4648  	}
  4649  
  4650  	checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4651  		"tags": cty.MapVal(map[string]cty.Value{
  4652  			"ignored": cty.StringVal("from state"),
  4653  			"other":   cty.StringVal("from config"),
  4654  		}),
  4655  	}), ric.After)
  4656  }
  4657  
  4658  func TestContext2Plan_ignoreChangesSensitive(t *testing.T) {
  4659  	m := testModule(t, "plan-ignore-changes-sensitive")
  4660  	p := testProvider("aws")
  4661  	p.PlanResourceChangeFn = testDiffFn
  4662  
  4663  	state := states.NewState()
  4664  	root := state.EnsureModule(addrs.RootModuleInstance)
  4665  	root.SetResourceInstanceCurrent(
  4666  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  4667  		&states.ResourceInstanceObjectSrc{
  4668  			Status:    states.ObjectReady,
  4669  			AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","type":"aws_instance"}`),
  4670  		},
  4671  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  4672  	)
  4673  
  4674  	ctx := testContext2(t, &ContextOpts{
  4675  		Providers: map[addrs.Provider]providers.Factory{
  4676  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4677  		},
  4678  	})
  4679  
  4680  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  4681  		Mode: plans.NormalMode,
  4682  		SetVariables: InputValues{
  4683  			"foo": &InputValue{
  4684  				Value:      cty.StringVal("ami-1234abcd"),
  4685  				SourceType: ValueFromCaller,
  4686  			},
  4687  		},
  4688  	})
  4689  	if diags.HasErrors() {
  4690  		t.Fatalf("unexpected errors: %s", diags.Err())
  4691  	}
  4692  
  4693  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  4694  	ty := schema.ImpliedType()
  4695  
  4696  	if len(plan.Changes.Resources) != 1 {
  4697  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  4698  	}
  4699  
  4700  	res := plan.Changes.Resources[0]
  4701  	ric, err := res.Decode(ty)
  4702  	if err != nil {
  4703  		t.Fatal(err)
  4704  	}
  4705  
  4706  	if ric.Addr.String() != "aws_instance.foo" {
  4707  		t.Fatalf("unexpected resource: %s", ric.Addr)
  4708  	}
  4709  
  4710  	checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4711  		"id":   cty.StringVal("bar"),
  4712  		"ami":  cty.StringVal("ami-abcd1234"),
  4713  		"type": cty.StringVal("aws_instance"),
  4714  	}), ric.After)
  4715  }
  4716  
  4717  func TestContext2Plan_moduleMapLiteral(t *testing.T) {
  4718  	m := testModule(t, "plan-module-map-literal")
  4719  	p := testProvider("aws")
  4720  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4721  		ResourceTypes: map[string]*configschema.Block{
  4722  			"aws_instance": {
  4723  				Attributes: map[string]*configschema.Attribute{
  4724  					"meta": {Type: cty.Map(cty.String), Optional: true},
  4725  					"tags": {Type: cty.Map(cty.String), Optional: true},
  4726  				},
  4727  			},
  4728  		},
  4729  	})
  4730  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  4731  		s := req.ProposedNewState.AsValueMap()
  4732  		m := s["tags"].AsValueMap()
  4733  
  4734  		if m["foo"].AsString() != "bar" {
  4735  			t.Fatalf("Bad value in tags attr: %#v", m)
  4736  		}
  4737  
  4738  		meta := s["meta"].AsValueMap()
  4739  		if len(meta) != 0 {
  4740  			t.Fatalf("Meta attr not empty: %#v", meta)
  4741  		}
  4742  		return testDiffFn(req)
  4743  	}
  4744  	ctx := testContext2(t, &ContextOpts{
  4745  		Providers: map[addrs.Provider]providers.Factory{
  4746  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4747  		},
  4748  	})
  4749  
  4750  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4751  	if diags.HasErrors() {
  4752  		t.Fatalf("unexpected errors: %s", diags.Err())
  4753  	}
  4754  }
  4755  
  4756  func TestContext2Plan_computedValueInMap(t *testing.T) {
  4757  	m := testModule(t, "plan-computed-value-in-map")
  4758  	p := testProvider("aws")
  4759  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4760  		ResourceTypes: map[string]*configschema.Block{
  4761  			"aws_instance": {
  4762  				Attributes: map[string]*configschema.Attribute{
  4763  					"looked_up": {Type: cty.String, Optional: true},
  4764  				},
  4765  			},
  4766  			"aws_computed_source": {
  4767  				Attributes: map[string]*configschema.Attribute{
  4768  					"computed_read_only": {Type: cty.String, Computed: true},
  4769  				},
  4770  			},
  4771  		},
  4772  	})
  4773  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  4774  		resp = testDiffFn(req)
  4775  
  4776  		if req.TypeName != "aws_computed_source" {
  4777  			return
  4778  		}
  4779  
  4780  		planned := resp.PlannedState.AsValueMap()
  4781  		planned["computed_read_only"] = cty.UnknownVal(cty.String)
  4782  		resp.PlannedState = cty.ObjectVal(planned)
  4783  		return resp
  4784  	}
  4785  
  4786  	ctx := testContext2(t, &ContextOpts{
  4787  		Providers: map[addrs.Provider]providers.Factory{
  4788  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4789  		},
  4790  	})
  4791  
  4792  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4793  	if diags.HasErrors() {
  4794  		t.Fatalf("unexpected errors: %s", diags.Err())
  4795  	}
  4796  
  4797  	if len(plan.Changes.Resources) != 2 {
  4798  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  4799  	}
  4800  
  4801  	for _, res := range plan.Changes.Resources {
  4802  		schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
  4803  
  4804  		ric, err := res.Decode(schema.ImpliedType())
  4805  		if err != nil {
  4806  			t.Fatal(err)
  4807  		}
  4808  
  4809  		if res.Action != plans.Create {
  4810  			t.Fatalf("resource %s should be created", ric.Addr)
  4811  		}
  4812  
  4813  		switch i := ric.Addr.String(); i {
  4814  		case "aws_computed_source.intermediates":
  4815  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4816  				"computed_read_only": cty.UnknownVal(cty.String),
  4817  			}), ric.After)
  4818  		case "module.test_mod.aws_instance.inner2":
  4819  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4820  				"looked_up": cty.UnknownVal(cty.String),
  4821  			}), ric.After)
  4822  		default:
  4823  			t.Fatal("unknown instance:", i)
  4824  		}
  4825  	}
  4826  }
  4827  
  4828  func TestContext2Plan_moduleVariableFromSplat(t *testing.T) {
  4829  	m := testModule(t, "plan-module-variable-from-splat")
  4830  	p := testProvider("aws")
  4831  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4832  		ResourceTypes: map[string]*configschema.Block{
  4833  			"aws_instance": {
  4834  				Attributes: map[string]*configschema.Attribute{
  4835  					"thing": {Type: cty.String, Optional: true},
  4836  				},
  4837  			},
  4838  		},
  4839  	})
  4840  
  4841  	ctx := testContext2(t, &ContextOpts{
  4842  		Providers: map[addrs.Provider]providers.Factory{
  4843  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4844  		},
  4845  	})
  4846  
  4847  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4848  	if diags.HasErrors() {
  4849  		t.Fatalf("unexpected errors: %s", diags.Err())
  4850  	}
  4851  
  4852  	if len(plan.Changes.Resources) != 4 {
  4853  		t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
  4854  	}
  4855  
  4856  	for _, res := range plan.Changes.Resources {
  4857  		schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
  4858  
  4859  		ric, err := res.Decode(schema.ImpliedType())
  4860  		if err != nil {
  4861  			t.Fatal(err)
  4862  		}
  4863  
  4864  		if res.Action != plans.Create {
  4865  			t.Fatalf("resource %s should be created", ric.Addr)
  4866  		}
  4867  
  4868  		switch i := ric.Addr.String(); i {
  4869  		case "module.mod1.aws_instance.test[0]",
  4870  			"module.mod1.aws_instance.test[1]",
  4871  			"module.mod2.aws_instance.test[0]",
  4872  			"module.mod2.aws_instance.test[1]":
  4873  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4874  				"thing": cty.StringVal("doesnt"),
  4875  			}), ric.After)
  4876  		default:
  4877  			t.Fatal("unknown instance:", i)
  4878  		}
  4879  	}
  4880  }
  4881  
  4882  func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) {
  4883  	m := testModule(t, "plan-cbd-depends-datasource")
  4884  	p := testProvider("aws")
  4885  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4886  		ResourceTypes: map[string]*configschema.Block{
  4887  			"aws_instance": {
  4888  				Attributes: map[string]*configschema.Attribute{
  4889  					"num":      {Type: cty.String, Optional: true},
  4890  					"computed": {Type: cty.String, Optional: true, Computed: true},
  4891  				},
  4892  			},
  4893  		},
  4894  		DataSources: map[string]*configschema.Block{
  4895  			"aws_vpc": {
  4896  				Attributes: map[string]*configschema.Attribute{
  4897  					"id":  {Type: cty.String, Computed: true},
  4898  					"foo": {Type: cty.Number, Optional: true},
  4899  				},
  4900  			},
  4901  		},
  4902  	})
  4903  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  4904  		computedVal := req.ProposedNewState.GetAttr("computed")
  4905  		if computedVal.IsNull() {
  4906  			computedVal = cty.UnknownVal(cty.String)
  4907  		}
  4908  		return providers.PlanResourceChangeResponse{
  4909  			PlannedState: cty.ObjectVal(map[string]cty.Value{
  4910  				"num":      req.ProposedNewState.GetAttr("num"),
  4911  				"computed": computedVal,
  4912  			}),
  4913  		}
  4914  	}
  4915  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
  4916  		cfg := req.Config.AsValueMap()
  4917  		cfg["id"] = cty.StringVal("data_id")
  4918  		return providers.ReadDataSourceResponse{
  4919  			State: cty.ObjectVal(cfg),
  4920  		}
  4921  	}
  4922  
  4923  	ctx := testContext2(t, &ContextOpts{
  4924  		Providers: map[addrs.Provider]providers.Factory{
  4925  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  4926  		},
  4927  	})
  4928  
  4929  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  4930  	if diags.HasErrors() {
  4931  		t.Fatalf("unexpected errors: %s", diags.Err())
  4932  	}
  4933  
  4934  	seenAddrs := make(map[string]struct{})
  4935  	for _, res := range plan.Changes.Resources {
  4936  		var schema *configschema.Block
  4937  		switch res.Addr.Resource.Resource.Mode {
  4938  		case addrs.DataResourceMode:
  4939  			schema = p.GetProviderSchemaResponse.DataSources[res.Addr.Resource.Resource.Type].Block
  4940  		case addrs.ManagedResourceMode:
  4941  			schema = p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
  4942  		}
  4943  
  4944  		ric, err := res.Decode(schema.ImpliedType())
  4945  		if err != nil {
  4946  			t.Fatal(err)
  4947  		}
  4948  
  4949  		seenAddrs[ric.Addr.String()] = struct{}{}
  4950  
  4951  		t.Run(ric.Addr.String(), func(t *testing.T) {
  4952  			switch i := ric.Addr.String(); i {
  4953  			case "aws_instance.foo[0]":
  4954  				if res.Action != plans.Create {
  4955  					t.Fatalf("resource %s should be created, got %s", ric.Addr, ric.Action)
  4956  				}
  4957  				checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4958  					"num":      cty.StringVal("2"),
  4959  					"computed": cty.StringVal("data_id"),
  4960  				}), ric.After)
  4961  			case "aws_instance.foo[1]":
  4962  				if res.Action != plans.Create {
  4963  					t.Fatalf("resource %s should be created, got %s", ric.Addr, ric.Action)
  4964  				}
  4965  				checkVals(t, objectVal(t, schema, map[string]cty.Value{
  4966  					"num":      cty.StringVal("2"),
  4967  					"computed": cty.StringVal("data_id"),
  4968  				}), ric.After)
  4969  			default:
  4970  				t.Fatal("unknown instance:", i)
  4971  			}
  4972  		})
  4973  	}
  4974  
  4975  	wantAddrs := map[string]struct{}{
  4976  		"aws_instance.foo[0]": {},
  4977  		"aws_instance.foo[1]": {},
  4978  	}
  4979  	if !cmp.Equal(seenAddrs, wantAddrs) {
  4980  		t.Errorf("incorrect addresses in changeset:\n%s", cmp.Diff(wantAddrs, seenAddrs))
  4981  	}
  4982  }
  4983  
  4984  // interpolated lists need to be stored in the original order.
  4985  func TestContext2Plan_listOrder(t *testing.T) {
  4986  	m := testModule(t, "plan-list-order")
  4987  	p := testProvider("aws")
  4988  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  4989  		ResourceTypes: map[string]*configschema.Block{
  4990  			"aws_instance": {
  4991  				Attributes: map[string]*configschema.Attribute{
  4992  					"foo": {Type: cty.List(cty.String), Optional: true},
  4993  				},
  4994  			},
  4995  		},
  4996  	})
  4997  	ctx := testContext2(t, &ContextOpts{
  4998  		Providers: map[addrs.Provider]providers.Factory{
  4999  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5000  		},
  5001  	})
  5002  
  5003  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5004  	if diags.HasErrors() {
  5005  		t.Fatalf("unexpected errors: %s", diags.Err())
  5006  	}
  5007  
  5008  	changes := plan.Changes
  5009  	rDiffA := changes.ResourceInstance(addrs.Resource{
  5010  		Mode: addrs.ManagedResourceMode,
  5011  		Type: "aws_instance",
  5012  		Name: "a",
  5013  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
  5014  	rDiffB := changes.ResourceInstance(addrs.Resource{
  5015  		Mode: addrs.ManagedResourceMode,
  5016  		Type: "aws_instance",
  5017  		Name: "b",
  5018  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
  5019  
  5020  	if !cmp.Equal(rDiffA.After, rDiffB.After, valueComparer) {
  5021  		t.Fatal(cmp.Diff(rDiffA.After, rDiffB.After, valueComparer))
  5022  	}
  5023  }
  5024  
  5025  // Make sure ignore-changes doesn't interfere with set/list/map diffs.
  5026  // If a resource was being replaced by a RequiresNew attribute that gets
  5027  // ignored, we need to filter the diff properly to properly update rather than
  5028  // replace.
  5029  func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) {
  5030  	m := testModule(t, "plan-ignore-changes-with-flatmaps")
  5031  	p := testProvider("aws")
  5032  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  5033  		ResourceTypes: map[string]*configschema.Block{
  5034  			"aws_instance": {
  5035  				Attributes: map[string]*configschema.Attribute{
  5036  					"user_data":   {Type: cty.String, Optional: true},
  5037  					"require_new": {Type: cty.String, Optional: true},
  5038  
  5039  					// This test predates the 0.12 work to integrate cty and
  5040  					// HCL, and so it was ported as-is where its expected
  5041  					// test output was clearly expecting a list of maps here
  5042  					// even though it is named "set".
  5043  					"set": {Type: cty.List(cty.Map(cty.String)), Optional: true},
  5044  					"lst": {Type: cty.List(cty.String), Optional: true},
  5045  				},
  5046  			},
  5047  		},
  5048  	})
  5049  
  5050  	state := states.NewState()
  5051  	root := state.EnsureModule(addrs.RootModuleInstance)
  5052  	root.SetResourceInstanceCurrent(
  5053  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  5054  		&states.ResourceInstanceObjectSrc{
  5055  			Status: states.ObjectReady,
  5056  			AttrsJSON: []byte(`{
  5057  				"user_data":"x","require_new":"",
  5058  				"set":[{"a":"1"}],
  5059  				"lst":["j"]
  5060  			}`),
  5061  		},
  5062  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5063  	)
  5064  
  5065  	ctx := testContext2(t, &ContextOpts{
  5066  		Providers: map[addrs.Provider]providers.Factory{
  5067  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5068  		},
  5069  	})
  5070  
  5071  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5072  	if diags.HasErrors() {
  5073  		t.Fatalf("unexpected errors: %s", diags.Err())
  5074  	}
  5075  
  5076  	if len(plan.Changes.Resources) != 1 {
  5077  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  5078  	}
  5079  
  5080  	res := plan.Changes.Resources[0]
  5081  	schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
  5082  
  5083  	ric, err := res.Decode(schema.ImpliedType())
  5084  	if err != nil {
  5085  		t.Fatal(err)
  5086  	}
  5087  
  5088  	if res.Action != plans.Update {
  5089  		t.Fatalf("resource %s should be updated, got %s", ric.Addr, ric.Action)
  5090  	}
  5091  
  5092  	if ric.Addr.String() != "aws_instance.foo" {
  5093  		t.Fatalf("unknown resource: %s", ric.Addr)
  5094  	}
  5095  
  5096  	checkVals(t, objectVal(t, schema, map[string]cty.Value{
  5097  		"lst": cty.ListVal([]cty.Value{
  5098  			cty.StringVal("j"),
  5099  			cty.StringVal("k"),
  5100  		}),
  5101  		"require_new": cty.StringVal(""),
  5102  		"user_data":   cty.StringVal("x"),
  5103  		"set": cty.ListVal([]cty.Value{cty.MapVal(map[string]cty.Value{
  5104  			"a": cty.StringVal("1"),
  5105  			"b": cty.StringVal("2"),
  5106  		})}),
  5107  	}), ric.After)
  5108  }
  5109  
  5110  // TestContext2Plan_resourceNestedCount ensures resource sets that depend on
  5111  // the count of another resource set (ie: count of a data source that depends
  5112  // on another data source's instance count - data.x.foo.*.id) get properly
  5113  // normalized to the indexes they should be. This case comes up when there is
  5114  // an existing state (after an initial apply).
  5115  func TestContext2Plan_resourceNestedCount(t *testing.T) {
  5116  	m := testModule(t, "nested-resource-count-plan")
  5117  	p := testProvider("aws")
  5118  	p.PlanResourceChangeFn = testDiffFn
  5119  	p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
  5120  		return providers.ReadResourceResponse{
  5121  			NewState: req.PriorState,
  5122  		}
  5123  	}
  5124  
  5125  	state := states.NewState()
  5126  	root := state.EnsureModule(addrs.RootModuleInstance)
  5127  	root.SetResourceInstanceCurrent(
  5128  		mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
  5129  		&states.ResourceInstanceObjectSrc{
  5130  			Status:    states.ObjectReady,
  5131  			AttrsJSON: []byte(`{"id":"foo0","type":"aws_instance"}`),
  5132  		},
  5133  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5134  	)
  5135  	root.SetResourceInstanceCurrent(
  5136  		mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
  5137  		&states.ResourceInstanceObjectSrc{
  5138  			Status:    states.ObjectReady,
  5139  			AttrsJSON: []byte(`{"id":"foo1","type":"aws_instance"}`),
  5140  		},
  5141  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5142  	)
  5143  	root.SetResourceInstanceCurrent(
  5144  		mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
  5145  		&states.ResourceInstanceObjectSrc{
  5146  			Status:       states.ObjectReady,
  5147  			AttrsJSON:    []byte(`{"id":"bar0","type":"aws_instance"}`),
  5148  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  5149  		},
  5150  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5151  	)
  5152  	root.SetResourceInstanceCurrent(
  5153  		mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
  5154  		&states.ResourceInstanceObjectSrc{
  5155  			Status:       states.ObjectReady,
  5156  			AttrsJSON:    []byte(`{"id":"bar1","type":"aws_instance"}`),
  5157  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
  5158  		},
  5159  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5160  	)
  5161  	root.SetResourceInstanceCurrent(
  5162  		mustResourceInstanceAddr("aws_instance.baz[0]").Resource,
  5163  		&states.ResourceInstanceObjectSrc{
  5164  			Status:       states.ObjectReady,
  5165  			AttrsJSON:    []byte(`{"id":"baz0","type":"aws_instance"}`),
  5166  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
  5167  		},
  5168  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5169  	)
  5170  	root.SetResourceInstanceCurrent(
  5171  		mustResourceInstanceAddr("aws_instance.baz[1]").Resource,
  5172  		&states.ResourceInstanceObjectSrc{
  5173  			Status:       states.ObjectReady,
  5174  			AttrsJSON:    []byte(`{"id":"baz1","type":"aws_instance"}`),
  5175  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
  5176  		},
  5177  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5178  	)
  5179  	ctx := testContext2(t, &ContextOpts{
  5180  		Providers: map[addrs.Provider]providers.Factory{
  5181  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5182  		},
  5183  	})
  5184  
  5185  	diags := ctx.Validate(m)
  5186  	if diags.HasErrors() {
  5187  		t.Fatalf("validate errors: %s", diags.Err())
  5188  	}
  5189  
  5190  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5191  	if diags.HasErrors() {
  5192  		t.Fatalf("plan errors: %s", diags.Err())
  5193  	}
  5194  
  5195  	for _, res := range plan.Changes.Resources {
  5196  		if res.Action != plans.NoOp {
  5197  			t.Fatalf("resource %s should not change, plan returned %s", res.Addr, res.Action)
  5198  		}
  5199  	}
  5200  }
  5201  
  5202  // Higher level test at TestResource_dataSourceListApplyPanic
  5203  func TestContext2Plan_computedAttrRefTypeMismatch(t *testing.T) {
  5204  	m := testModule(t, "plan-computed-attr-ref-type-mismatch")
  5205  	p := testProvider("aws")
  5206  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
  5207  		var diags tfdiags.Diagnostics
  5208  		if req.TypeName == "aws_instance" {
  5209  			amiVal := req.Config.GetAttr("ami")
  5210  			if amiVal.Type() != cty.String {
  5211  				diags = diags.Append(fmt.Errorf("Expected ami to be cty.String, got %#v", amiVal))
  5212  			}
  5213  		}
  5214  		return providers.ValidateResourceConfigResponse{
  5215  			Diagnostics: diags,
  5216  		}
  5217  	}
  5218  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  5219  		if req.TypeName != "aws_ami_list" {
  5220  			t.Fatalf("Reached apply for unexpected resource type! %s", req.TypeName)
  5221  		}
  5222  		// Pretend like we make a thing and the computed list "ids" is populated
  5223  		s := req.PlannedState.AsValueMap()
  5224  		s["id"] = cty.StringVal("someid")
  5225  		s["ids"] = cty.ListVal([]cty.Value{
  5226  			cty.StringVal("ami-abc123"),
  5227  			cty.StringVal("ami-bcd345"),
  5228  		})
  5229  
  5230  		resp.NewState = cty.ObjectVal(s)
  5231  		return
  5232  	}
  5233  	ctx := testContext2(t, &ContextOpts{
  5234  		Providers: map[addrs.Provider]providers.Factory{
  5235  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5236  		},
  5237  	})
  5238  
  5239  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5240  	if !diags.HasErrors() {
  5241  		t.Fatalf("Succeeded; want type mismatch error for 'ami' argument")
  5242  	}
  5243  
  5244  	expected := `Inappropriate value for attribute "ami"`
  5245  	if errStr := diags.Err().Error(); !strings.Contains(errStr, expected) {
  5246  		t.Fatalf("expected:\n\n%s\n\nto contain:\n\n%s", errStr, expected)
  5247  	}
  5248  }
  5249  
  5250  func TestContext2Plan_selfRef(t *testing.T) {
  5251  	p := testProvider("aws")
  5252  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  5253  		ResourceTypes: map[string]*configschema.Block{
  5254  			"aws_instance": {
  5255  				Attributes: map[string]*configschema.Attribute{
  5256  					"foo": {Type: cty.String, Optional: true},
  5257  				},
  5258  			},
  5259  		},
  5260  	})
  5261  
  5262  	m := testModule(t, "plan-self-ref")
  5263  	c := testContext2(t, &ContextOpts{
  5264  		Providers: map[addrs.Provider]providers.Factory{
  5265  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5266  		},
  5267  	})
  5268  
  5269  	diags := c.Validate(m)
  5270  	if diags.HasErrors() {
  5271  		t.Fatalf("unexpected validation failure: %s", diags.Err())
  5272  	}
  5273  
  5274  	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
  5275  	if !diags.HasErrors() {
  5276  		t.Fatalf("plan succeeded; want error")
  5277  	}
  5278  
  5279  	gotErrStr := diags.Err().Error()
  5280  	wantErrStr := "Self-referential block"
  5281  	if !strings.Contains(gotErrStr, wantErrStr) {
  5282  		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
  5283  	}
  5284  }
  5285  
  5286  func TestContext2Plan_selfRefMulti(t *testing.T) {
  5287  	p := testProvider("aws")
  5288  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  5289  		ResourceTypes: map[string]*configschema.Block{
  5290  			"aws_instance": {
  5291  				Attributes: map[string]*configschema.Attribute{
  5292  					"foo": {Type: cty.String, Optional: true},
  5293  				},
  5294  			},
  5295  		},
  5296  	})
  5297  
  5298  	m := testModule(t, "plan-self-ref-multi")
  5299  	c := testContext2(t, &ContextOpts{
  5300  		Providers: map[addrs.Provider]providers.Factory{
  5301  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5302  		},
  5303  	})
  5304  
  5305  	diags := c.Validate(m)
  5306  	if diags.HasErrors() {
  5307  		t.Fatalf("unexpected validation failure: %s", diags.Err())
  5308  	}
  5309  
  5310  	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
  5311  	if !diags.HasErrors() {
  5312  		t.Fatalf("plan succeeded; want error")
  5313  	}
  5314  
  5315  	gotErrStr := diags.Err().Error()
  5316  	wantErrStr := "Self-referential block"
  5317  	if !strings.Contains(gotErrStr, wantErrStr) {
  5318  		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
  5319  	}
  5320  }
  5321  
  5322  func TestContext2Plan_selfRefMultiAll(t *testing.T) {
  5323  	p := testProvider("aws")
  5324  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  5325  		ResourceTypes: map[string]*configschema.Block{
  5326  			"aws_instance": {
  5327  				Attributes: map[string]*configschema.Attribute{
  5328  					"foo": {Type: cty.List(cty.String), Optional: true},
  5329  				},
  5330  			},
  5331  		},
  5332  	})
  5333  
  5334  	m := testModule(t, "plan-self-ref-multi-all")
  5335  	c := testContext2(t, &ContextOpts{
  5336  		Providers: map[addrs.Provider]providers.Factory{
  5337  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5338  		},
  5339  	})
  5340  
  5341  	diags := c.Validate(m)
  5342  	if diags.HasErrors() {
  5343  		t.Fatalf("unexpected validation failure: %s", diags.Err())
  5344  	}
  5345  
  5346  	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
  5347  	if !diags.HasErrors() {
  5348  		t.Fatalf("plan succeeded; want error")
  5349  	}
  5350  
  5351  	gotErrStr := diags.Err().Error()
  5352  
  5353  	// The graph is checked for cycles before we can walk it, so we don't
  5354  	// encounter the self-reference check.
  5355  	//wantErrStr := "Self-referential block"
  5356  	wantErrStr := "Cycle"
  5357  	if !strings.Contains(gotErrStr, wantErrStr) {
  5358  		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
  5359  	}
  5360  }
  5361  
  5362  func TestContext2Plan_invalidOutput(t *testing.T) {
  5363  	m := testModuleInline(t, map[string]string{
  5364  		"main.tf": `
  5365  data "aws_data_source" "name" {}
  5366  
  5367  output "out" {
  5368    value = data.aws_data_source.name.missing
  5369  }`,
  5370  	})
  5371  
  5372  	p := testProvider("aws")
  5373  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  5374  		State: cty.ObjectVal(map[string]cty.Value{
  5375  			"id":  cty.StringVal("data_id"),
  5376  			"foo": cty.StringVal("foo"),
  5377  		}),
  5378  	}
  5379  
  5380  	ctx := testContext2(t, &ContextOpts{
  5381  		Providers: map[addrs.Provider]providers.Factory{
  5382  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5383  		},
  5384  	})
  5385  
  5386  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5387  	if !diags.HasErrors() {
  5388  		// Should get this error:
  5389  		// Unsupported attribute: This object does not have an attribute named "missing"
  5390  		t.Fatal("succeeded; want errors")
  5391  	}
  5392  
  5393  	gotErrStr := diags.Err().Error()
  5394  	wantErrStr := "Unsupported attribute"
  5395  	if !strings.Contains(gotErrStr, wantErrStr) {
  5396  		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
  5397  	}
  5398  }
  5399  
  5400  func TestContext2Plan_invalidModuleOutput(t *testing.T) {
  5401  	m := testModuleInline(t, map[string]string{
  5402  		"child/main.tf": `
  5403  data "aws_data_source" "name" {}
  5404  
  5405  output "out" {
  5406    value = "${data.aws_data_source.name.missing}"
  5407  }`,
  5408  		"main.tf": `
  5409  module "child" {
  5410    source = "./child"
  5411  }
  5412  
  5413  resource "aws_instance" "foo" {
  5414    foo = "${module.child.out}"
  5415  }`,
  5416  	})
  5417  
  5418  	p := testProvider("aws")
  5419  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  5420  		State: cty.ObjectVal(map[string]cty.Value{
  5421  			"id":  cty.StringVal("data_id"),
  5422  			"foo": cty.StringVal("foo"),
  5423  		}),
  5424  	}
  5425  
  5426  	ctx := testContext2(t, &ContextOpts{
  5427  		Providers: map[addrs.Provider]providers.Factory{
  5428  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5429  		},
  5430  	})
  5431  
  5432  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5433  	if !diags.HasErrors() {
  5434  		// Should get this error:
  5435  		// Unsupported attribute: This object does not have an attribute named "missing"
  5436  		t.Fatal("succeeded; want errors")
  5437  	}
  5438  
  5439  	gotErrStr := diags.Err().Error()
  5440  	wantErrStr := "Unsupported attribute"
  5441  	if !strings.Contains(gotErrStr, wantErrStr) {
  5442  		t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
  5443  	}
  5444  }
  5445  
  5446  func TestContext2Plan_variableValidation(t *testing.T) {
  5447  	m := testModuleInline(t, map[string]string{
  5448  		"main.tf": `
  5449  variable "x" {
  5450    default = "bar"
  5451  }
  5452  
  5453  resource "aws_instance" "foo" {
  5454    foo = var.x
  5455  }`,
  5456  	})
  5457  
  5458  	p := testProvider("aws")
  5459  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
  5460  		foo := req.Config.GetAttr("foo").AsString()
  5461  		if foo == "bar" {
  5462  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo cannot be bar"))
  5463  		}
  5464  		return
  5465  	}
  5466  
  5467  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  5468  		resp.PlannedState = req.ProposedNewState
  5469  		return
  5470  	}
  5471  
  5472  	ctx := testContext2(t, &ContextOpts{
  5473  		Providers: map[addrs.Provider]providers.Factory{
  5474  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5475  		},
  5476  	})
  5477  
  5478  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5479  	if !diags.HasErrors() {
  5480  		// Should get this error:
  5481  		// Unsupported attribute: This object does not have an attribute named "missing"
  5482  		t.Fatal("succeeded; want errors")
  5483  	}
  5484  }
  5485  
  5486  func TestContext2Plan_variableSensitivity(t *testing.T) {
  5487  	m := testModule(t, "plan-variable-sensitivity")
  5488  
  5489  	p := testProvider("aws")
  5490  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  5491  		resp.PlannedState = req.ProposedNewState
  5492  		return
  5493  	}
  5494  
  5495  	ctx := testContext2(t, &ContextOpts{
  5496  		Providers: map[addrs.Provider]providers.Factory{
  5497  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5498  		},
  5499  	})
  5500  
  5501  	plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  5502  	if diags.HasErrors() {
  5503  		t.Fatalf("unexpected errors: %s", diags.Err())
  5504  	}
  5505  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  5506  	ty := schema.ImpliedType()
  5507  
  5508  	if len(plan.Changes.Resources) != 1 {
  5509  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  5510  	}
  5511  
  5512  	for _, res := range plan.Changes.Resources {
  5513  		if res.Action != plans.Create {
  5514  			t.Fatalf("expected resource creation, got %s", res.Action)
  5515  		}
  5516  		ric, err := res.Decode(ty)
  5517  		if err != nil {
  5518  			t.Fatal(err)
  5519  		}
  5520  
  5521  		switch i := ric.Addr.String(); i {
  5522  		case "aws_instance.foo":
  5523  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  5524  				"foo": cty.StringVal("foo").Mark(marks.Sensitive),
  5525  			}), ric.After)
  5526  			if len(res.ChangeSrc.BeforeValMarks) != 0 {
  5527  				t.Errorf("unexpected BeforeValMarks: %#v", res.ChangeSrc.BeforeValMarks)
  5528  			}
  5529  			if len(res.ChangeSrc.AfterValMarks) != 1 {
  5530  				t.Errorf("unexpected AfterValMarks: %#v", res.ChangeSrc.AfterValMarks)
  5531  				continue
  5532  			}
  5533  			pvm := res.ChangeSrc.AfterValMarks[0]
  5534  			if got, want := pvm.Path, cty.GetAttrPath("foo"); !got.Equals(want) {
  5535  				t.Errorf("unexpected path for mark\n got: %#v\nwant: %#v", got, want)
  5536  			}
  5537  			if got, want := pvm.Marks, cty.NewValueMarks(marks.Sensitive); !got.Equal(want) {
  5538  				t.Errorf("unexpected value for mark\n got: %#v\nwant: %#v", got, want)
  5539  			}
  5540  		default:
  5541  			t.Fatal("unknown instance:", i)
  5542  		}
  5543  	}
  5544  }
  5545  
  5546  func TestContext2Plan_variableSensitivityModule(t *testing.T) {
  5547  	m := testModule(t, "plan-variable-sensitivity-module")
  5548  
  5549  	p := testProvider("aws")
  5550  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  5551  		resp.PlannedState = req.ProposedNewState
  5552  		return
  5553  	}
  5554  
  5555  	ctx := testContext2(t, &ContextOpts{
  5556  		Providers: map[addrs.Provider]providers.Factory{
  5557  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5558  		},
  5559  	})
  5560  
  5561  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  5562  		Mode: plans.NormalMode,
  5563  		SetVariables: InputValues{
  5564  			"sensitive_var": {Value: cty.NilVal},
  5565  			"another_var": &InputValue{
  5566  				Value:      cty.StringVal("boop"),
  5567  				SourceType: ValueFromCaller,
  5568  			},
  5569  		},
  5570  	})
  5571  	if diags.HasErrors() {
  5572  		t.Fatalf("unexpected errors: %s", diags.Err())
  5573  	}
  5574  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  5575  	ty := schema.ImpliedType()
  5576  
  5577  	if len(plan.Changes.Resources) != 1 {
  5578  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  5579  	}
  5580  
  5581  	for _, res := range plan.Changes.Resources {
  5582  		if res.Action != plans.Create {
  5583  			t.Fatalf("expected resource creation, got %s", res.Action)
  5584  		}
  5585  		ric, err := res.Decode(ty)
  5586  		if err != nil {
  5587  			t.Fatal(err)
  5588  		}
  5589  
  5590  		switch i := ric.Addr.String(); i {
  5591  		case "module.child.aws_instance.foo":
  5592  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  5593  				"foo":   cty.StringVal("foo").Mark(marks.Sensitive),
  5594  				"value": cty.StringVal("boop").Mark(marks.Sensitive),
  5595  			}), ric.After)
  5596  			if len(res.ChangeSrc.BeforeValMarks) != 0 {
  5597  				t.Errorf("unexpected BeforeValMarks: %#v", res.ChangeSrc.BeforeValMarks)
  5598  			}
  5599  			if len(res.ChangeSrc.AfterValMarks) != 2 {
  5600  				t.Errorf("expected AfterValMarks to contain two elements: %#v", res.ChangeSrc.AfterValMarks)
  5601  				continue
  5602  			}
  5603  			// validate that the after marks have "foo" and "value"
  5604  			contains := func(pvmSlice []cty.PathValueMarks, stepName string) bool {
  5605  				for _, pvm := range pvmSlice {
  5606  					if pvm.Path.Equals(cty.GetAttrPath(stepName)) {
  5607  						if pvm.Marks.Equal(cty.NewValueMarks(marks.Sensitive)) {
  5608  							return true
  5609  						}
  5610  					}
  5611  				}
  5612  				return false
  5613  			}
  5614  			if !contains(res.ChangeSrc.AfterValMarks, "foo") {
  5615  				t.Error("unexpected AfterValMarks to contain \"foo\" with sensitive mark")
  5616  			}
  5617  			if !contains(res.ChangeSrc.AfterValMarks, "value") {
  5618  				t.Error("unexpected AfterValMarks to contain \"value\" with sensitive mark")
  5619  			}
  5620  		default:
  5621  			t.Fatal("unknown instance:", i)
  5622  		}
  5623  	}
  5624  }
  5625  
  5626  func checkVals(t *testing.T, expected, got cty.Value) {
  5627  	t.Helper()
  5628  	// The GoStringer format seems to result in the closest thing to a useful
  5629  	// diff for values with marks.
  5630  	// TODO: if we want to continue using cmp.Diff on cty.Values, we should
  5631  	// make a transformer that creates a more comparable structure.
  5632  	valueTrans := cmp.Transformer("gostring", func(v cty.Value) string {
  5633  		return fmt.Sprintf("%#v\n", v)
  5634  	})
  5635  	if !cmp.Equal(expected, got, valueComparer, typeComparer, equateEmpty) {
  5636  		t.Fatal(cmp.Diff(expected, got, valueTrans, equateEmpty))
  5637  	}
  5638  }
  5639  
  5640  func objectVal(t *testing.T, schema *configschema.Block, m map[string]cty.Value) cty.Value {
  5641  	t.Helper()
  5642  	v, err := schema.CoerceValue(
  5643  		cty.ObjectVal(m),
  5644  	)
  5645  	if err != nil {
  5646  		t.Fatal(err)
  5647  	}
  5648  	return v
  5649  }
  5650  
  5651  func TestContext2Plan_requiredModuleOutput(t *testing.T) {
  5652  	m := testModule(t, "plan-required-output")
  5653  	p := testProvider("test")
  5654  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  5655  		ResourceTypes: map[string]*configschema.Block{
  5656  			"test_resource": {
  5657  				Attributes: map[string]*configschema.Attribute{
  5658  					"id":       {Type: cty.String, Computed: true},
  5659  					"required": {Type: cty.String, Required: true},
  5660  				},
  5661  			},
  5662  		},
  5663  	})
  5664  
  5665  	ctx := testContext2(t, &ContextOpts{
  5666  		Providers: map[addrs.Provider]providers.Factory{
  5667  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  5668  		},
  5669  	})
  5670  
  5671  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5672  	if diags.HasErrors() {
  5673  		t.Fatalf("unexpected errors: %s", diags.Err())
  5674  	}
  5675  
  5676  	schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
  5677  	ty := schema.ImpliedType()
  5678  
  5679  	if len(plan.Changes.Resources) != 2 {
  5680  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  5681  	}
  5682  
  5683  	for _, res := range plan.Changes.Resources {
  5684  		t.Run(fmt.Sprintf("%s %s", res.Action, res.Addr), func(t *testing.T) {
  5685  			if res.Action != plans.Create {
  5686  				t.Fatalf("expected resource creation, got %s", res.Action)
  5687  			}
  5688  			ric, err := res.Decode(ty)
  5689  			if err != nil {
  5690  				t.Fatal(err)
  5691  			}
  5692  
  5693  			var expected cty.Value
  5694  			switch i := ric.Addr.String(); i {
  5695  			case "test_resource.root":
  5696  				expected = objectVal(t, schema, map[string]cty.Value{
  5697  					"id":       cty.UnknownVal(cty.String),
  5698  					"required": cty.UnknownVal(cty.String),
  5699  				})
  5700  			case "module.mod.test_resource.for_output":
  5701  				expected = objectVal(t, schema, map[string]cty.Value{
  5702  					"id":       cty.UnknownVal(cty.String),
  5703  					"required": cty.StringVal("val"),
  5704  				})
  5705  			default:
  5706  				t.Fatal("unknown instance:", i)
  5707  			}
  5708  
  5709  			checkVals(t, expected, ric.After)
  5710  		})
  5711  	}
  5712  }
  5713  
  5714  func TestContext2Plan_requiredModuleObject(t *testing.T) {
  5715  	m := testModule(t, "plan-required-whole-mod")
  5716  	p := testProvider("test")
  5717  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  5718  		ResourceTypes: map[string]*configschema.Block{
  5719  			"test_resource": {
  5720  				Attributes: map[string]*configschema.Attribute{
  5721  					"id":       {Type: cty.String, Computed: true},
  5722  					"required": {Type: cty.String, Required: true},
  5723  				},
  5724  			},
  5725  		},
  5726  	})
  5727  
  5728  	ctx := testContext2(t, &ContextOpts{
  5729  		Providers: map[addrs.Provider]providers.Factory{
  5730  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  5731  		},
  5732  	})
  5733  
  5734  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5735  	if diags.HasErrors() {
  5736  		t.Fatalf("unexpected errors: %s", diags.Err())
  5737  	}
  5738  
  5739  	schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
  5740  	ty := schema.ImpliedType()
  5741  
  5742  	if len(plan.Changes.Resources) != 2 {
  5743  		t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
  5744  	}
  5745  
  5746  	for _, res := range plan.Changes.Resources {
  5747  		t.Run(fmt.Sprintf("%s %s", res.Action, res.Addr), func(t *testing.T) {
  5748  			if res.Action != plans.Create {
  5749  				t.Fatalf("expected resource creation, got %s", res.Action)
  5750  			}
  5751  			ric, err := res.Decode(ty)
  5752  			if err != nil {
  5753  				t.Fatal(err)
  5754  			}
  5755  
  5756  			var expected cty.Value
  5757  			switch i := ric.Addr.String(); i {
  5758  			case "test_resource.root":
  5759  				expected = objectVal(t, schema, map[string]cty.Value{
  5760  					"id":       cty.UnknownVal(cty.String),
  5761  					"required": cty.UnknownVal(cty.String),
  5762  				})
  5763  			case "module.mod.test_resource.for_output":
  5764  				expected = objectVal(t, schema, map[string]cty.Value{
  5765  					"id":       cty.UnknownVal(cty.String),
  5766  					"required": cty.StringVal("val"),
  5767  				})
  5768  			default:
  5769  				t.Fatal("unknown instance:", i)
  5770  			}
  5771  
  5772  			checkVals(t, expected, ric.After)
  5773  		})
  5774  	}
  5775  }
  5776  
  5777  func TestContext2Plan_expandOrphan(t *testing.T) {
  5778  	m := testModuleInline(t, map[string]string{
  5779  		"main.tf": `
  5780  module "mod" {
  5781    count = 1
  5782    source = "./mod"
  5783  }
  5784  `,
  5785  		"mod/main.tf": `
  5786  resource "aws_instance" "foo" {
  5787  }
  5788  `,
  5789  	})
  5790  
  5791  	state := states.NewState()
  5792  	state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.IntKey(0))).SetResourceInstanceCurrent(
  5793  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  5794  		&states.ResourceInstanceObjectSrc{
  5795  			Status:    states.ObjectReady,
  5796  			AttrsJSON: []byte(`{"id":"child","type":"aws_instance"}`),
  5797  		},
  5798  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5799  	)
  5800  	state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.IntKey(1))).SetResourceInstanceCurrent(
  5801  		mustResourceInstanceAddr("aws_instance.foo").Resource,
  5802  		&states.ResourceInstanceObjectSrc{
  5803  			Status:    states.ObjectReady,
  5804  			AttrsJSON: []byte(`{"id":"child","type":"aws_instance"}`),
  5805  		},
  5806  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
  5807  	)
  5808  
  5809  	p := testProvider("aws")
  5810  	p.PlanResourceChangeFn = testDiffFn
  5811  	ctx := testContext2(t, &ContextOpts{
  5812  		Providers: map[addrs.Provider]providers.Factory{
  5813  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5814  		},
  5815  	})
  5816  
  5817  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  5818  	if diags.HasErrors() {
  5819  		t.Fatal(diags.ErrWithWarnings())
  5820  	}
  5821  
  5822  	expected := map[string]plans.Action{
  5823  		`module.mod[1].aws_instance.foo`: plans.Delete,
  5824  		`module.mod[0].aws_instance.foo`: plans.NoOp,
  5825  	}
  5826  
  5827  	for _, res := range plan.Changes.Resources {
  5828  		want := expected[res.Addr.String()]
  5829  		if res.Action != want {
  5830  			t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action)
  5831  		}
  5832  		delete(expected, res.Addr.String())
  5833  	}
  5834  
  5835  	for res, action := range expected {
  5836  		t.Errorf("missing %s change for %s", action, res)
  5837  	}
  5838  }
  5839  
  5840  func TestContext2Plan_indexInVar(t *testing.T) {
  5841  	m := testModuleInline(t, map[string]string{
  5842  		"main.tf": `
  5843  module "a" {
  5844    count = 1
  5845    source = "./mod"
  5846    in = "test"
  5847  }
  5848  
  5849  module "b" {
  5850    count = 1
  5851    source = "./mod"
  5852    in = length(module.a)
  5853  }
  5854  `,
  5855  		"mod/main.tf": `
  5856  resource "aws_instance" "foo" {
  5857    foo = var.in
  5858  }
  5859  
  5860  variable "in" {
  5861  }
  5862  
  5863  output"out" {
  5864    value = aws_instance.foo.id
  5865  }
  5866  `,
  5867  	})
  5868  
  5869  	p := testProvider("aws")
  5870  	ctx := testContext2(t, &ContextOpts{
  5871  		Providers: map[addrs.Provider]providers.Factory{
  5872  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5873  		},
  5874  	})
  5875  
  5876  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  5877  	if diags.HasErrors() {
  5878  		t.Fatal(diags.ErrWithWarnings())
  5879  	}
  5880  }
  5881  
  5882  func TestContext2Plan_targetExpandedAddress(t *testing.T) {
  5883  	m := testModuleInline(t, map[string]string{
  5884  		"main.tf": `
  5885  module "mod" {
  5886    count = 3
  5887    source = "./mod"
  5888  }
  5889  `,
  5890  		"mod/main.tf": `
  5891  resource "aws_instance" "foo" {
  5892    count = 2
  5893  }
  5894  `,
  5895  	})
  5896  
  5897  	p := testProvider("aws")
  5898  
  5899  	targets := []addrs.Targetable{}
  5900  	target, diags := addrs.ParseTargetStr("module.mod[1].aws_instance.foo[0]")
  5901  	if diags.HasErrors() {
  5902  		t.Fatal(diags.ErrWithWarnings())
  5903  	}
  5904  	targets = append(targets, target.Subject)
  5905  
  5906  	target, diags = addrs.ParseTargetStr("module.mod[2]")
  5907  	if diags.HasErrors() {
  5908  		t.Fatal(diags.ErrWithWarnings())
  5909  	}
  5910  	targets = append(targets, target.Subject)
  5911  
  5912  	ctx := testContext2(t, &ContextOpts{
  5913  		Providers: map[addrs.Provider]providers.Factory{
  5914  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5915  		},
  5916  	})
  5917  
  5918  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  5919  		Mode:    plans.NormalMode,
  5920  		Targets: targets,
  5921  	})
  5922  	if diags.HasErrors() {
  5923  		t.Fatal(diags.ErrWithWarnings())
  5924  	}
  5925  
  5926  	expected := map[string]plans.Action{
  5927  		// the single targeted mod[1] instances
  5928  		`module.mod[1].aws_instance.foo[0]`: plans.Create,
  5929  		// the whole mode[2]
  5930  		`module.mod[2].aws_instance.foo[0]`: plans.Create,
  5931  		`module.mod[2].aws_instance.foo[1]`: plans.Create,
  5932  	}
  5933  
  5934  	for _, res := range plan.Changes.Resources {
  5935  		want := expected[res.Addr.String()]
  5936  		if res.Action != want {
  5937  			t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action)
  5938  		}
  5939  		delete(expected, res.Addr.String())
  5940  	}
  5941  
  5942  	for res, action := range expected {
  5943  		t.Errorf("missing %s change for %s", action, res)
  5944  	}
  5945  }
  5946  
  5947  func TestContext2Plan_targetResourceInModuleInstance(t *testing.T) {
  5948  	m := testModuleInline(t, map[string]string{
  5949  		"main.tf": `
  5950  module "mod" {
  5951    count = 3
  5952    source = "./mod"
  5953  }
  5954  `,
  5955  		"mod/main.tf": `
  5956  resource "aws_instance" "foo" {
  5957  }
  5958  `,
  5959  	})
  5960  
  5961  	p := testProvider("aws")
  5962  
  5963  	target, diags := addrs.ParseTargetStr("module.mod[1].aws_instance.foo")
  5964  	if diags.HasErrors() {
  5965  		t.Fatal(diags.ErrWithWarnings())
  5966  	}
  5967  
  5968  	targets := []addrs.Targetable{target.Subject}
  5969  
  5970  	ctx := testContext2(t, &ContextOpts{
  5971  		Providers: map[addrs.Provider]providers.Factory{
  5972  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  5973  		},
  5974  	})
  5975  
  5976  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  5977  		Mode:    plans.NormalMode,
  5978  		Targets: targets,
  5979  	})
  5980  	if diags.HasErrors() {
  5981  		t.Fatal(diags.ErrWithWarnings())
  5982  	}
  5983  
  5984  	expected := map[string]plans.Action{
  5985  		// the single targeted mod[1] instance
  5986  		`module.mod[1].aws_instance.foo`: plans.Create,
  5987  	}
  5988  
  5989  	for _, res := range plan.Changes.Resources {
  5990  		want := expected[res.Addr.String()]
  5991  		if res.Action != want {
  5992  			t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action)
  5993  		}
  5994  		delete(expected, res.Addr.String())
  5995  	}
  5996  
  5997  	for res, action := range expected {
  5998  		t.Errorf("missing %s change for %s", action, res)
  5999  	}
  6000  }
  6001  
  6002  func TestContext2Plan_moduleRefIndex(t *testing.T) {
  6003  	m := testModuleInline(t, map[string]string{
  6004  		"main.tf": `
  6005  module "mod" {
  6006    for_each = {
  6007      a = "thing"
  6008    }
  6009    in = null
  6010    source = "./mod"
  6011  }
  6012  
  6013  module "single" {
  6014    source = "./mod"
  6015    in = module.mod["a"]
  6016  }
  6017  `,
  6018  		"mod/main.tf": `
  6019  variable "in" {
  6020  }
  6021  
  6022  output "out" {
  6023    value = "foo"
  6024  }
  6025  
  6026  resource "aws_instance" "foo" {
  6027  }
  6028  `,
  6029  	})
  6030  
  6031  	p := testProvider("aws")
  6032  
  6033  	ctx := testContext2(t, &ContextOpts{
  6034  		Providers: map[addrs.Provider]providers.Factory{
  6035  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6036  		},
  6037  	})
  6038  
  6039  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6040  	if diags.HasErrors() {
  6041  		t.Fatal(diags.ErrWithWarnings())
  6042  	}
  6043  }
  6044  
  6045  func TestContext2Plan_noChangeDataPlan(t *testing.T) {
  6046  	m := testModuleInline(t, map[string]string{
  6047  		"main.tf": `
  6048  data "test_data_source" "foo" {}
  6049  `,
  6050  	})
  6051  
  6052  	p := new(MockProvider)
  6053  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6054  		DataSources: map[string]*configschema.Block{
  6055  			"test_data_source": {
  6056  				Attributes: map[string]*configschema.Attribute{
  6057  					"id": {
  6058  						Type:     cty.String,
  6059  						Computed: true,
  6060  					},
  6061  					"foo": {
  6062  						Type:     cty.String,
  6063  						Optional: true,
  6064  					},
  6065  				},
  6066  			},
  6067  		},
  6068  	})
  6069  
  6070  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  6071  		State: cty.ObjectVal(map[string]cty.Value{
  6072  			"id":  cty.StringVal("data_id"),
  6073  			"foo": cty.StringVal("foo"),
  6074  		}),
  6075  	}
  6076  
  6077  	state := states.NewState()
  6078  	root := state.EnsureModule(addrs.RootModuleInstance)
  6079  	root.SetResourceInstanceCurrent(
  6080  		mustResourceInstanceAddr("data.test_data_source.foo").Resource,
  6081  		&states.ResourceInstanceObjectSrc{
  6082  			Status:    states.ObjectReady,
  6083  			AttrsJSON: []byte(`{"id":"data_id", "foo":"foo"}`),
  6084  		},
  6085  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
  6086  	)
  6087  
  6088  	ctx := testContext2(t, &ContextOpts{
  6089  		Providers: map[addrs.Provider]providers.Factory{
  6090  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6091  		},
  6092  	})
  6093  
  6094  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6095  	if diags.HasErrors() {
  6096  		t.Fatal(diags.ErrWithWarnings())
  6097  	}
  6098  
  6099  	for _, res := range plan.Changes.Resources {
  6100  		if res.Action != plans.NoOp {
  6101  			t.Fatalf("expected NoOp, got: %q %s", res.Addr, res.Action)
  6102  		}
  6103  	}
  6104  }
  6105  
  6106  // for_each can reference a resource with 0 instances
  6107  func TestContext2Plan_scaleInForEach(t *testing.T) {
  6108  	p := testProvider("test")
  6109  
  6110  	m := testModuleInline(t, map[string]string{
  6111  		"main.tf": `
  6112  locals {
  6113    m = {}
  6114  }
  6115  
  6116  resource "test_instance" "a" {
  6117    for_each = local.m
  6118  }
  6119  
  6120  resource "test_instance" "b" {
  6121    for_each = test_instance.a
  6122  }
  6123  `})
  6124  
  6125  	state := states.NewState()
  6126  	root := state.EnsureModule(addrs.RootModuleInstance)
  6127  	root.SetResourceInstanceCurrent(
  6128  		mustResourceInstanceAddr("test_instance.a[0]").Resource,
  6129  		&states.ResourceInstanceObjectSrc{
  6130  			Status:       states.ObjectReady,
  6131  			AttrsJSON:    []byte(`{"id":"a0"}`),
  6132  			Dependencies: []addrs.ConfigResource{},
  6133  		},
  6134  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
  6135  	)
  6136  	root.SetResourceInstanceCurrent(
  6137  		mustResourceInstanceAddr("test_instance.b").Resource,
  6138  		&states.ResourceInstanceObjectSrc{
  6139  			Status:       states.ObjectReady,
  6140  			AttrsJSON:    []byte(`{"id":"b"}`),
  6141  			Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")},
  6142  		},
  6143  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
  6144  	)
  6145  
  6146  	ctx := testContext2(t, &ContextOpts{
  6147  		Providers: map[addrs.Provider]providers.Factory{
  6148  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6149  		},
  6150  	})
  6151  
  6152  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6153  	assertNoErrors(t, diags)
  6154  
  6155  	t.Run("test_instance.a[0]", func(t *testing.T) {
  6156  		instAddr := mustResourceInstanceAddr("test_instance.a[0]")
  6157  		change := plan.Changes.ResourceInstance(instAddr)
  6158  		if change == nil {
  6159  			t.Fatalf("no planned change for %s", instAddr)
  6160  		}
  6161  		if got, want := change.PrevRunAddr, instAddr; !want.Equal(got) {
  6162  			t.Errorf("wrong previous run address for %s %s; want %s", instAddr, got, want)
  6163  		}
  6164  		if got, want := change.Action, plans.Delete; got != want {
  6165  			t.Errorf("wrong action for %s %s; want %s", instAddr, got, want)
  6166  		}
  6167  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want {
  6168  			t.Errorf("wrong action reason for %s %s; want %s", instAddr, got, want)
  6169  		}
  6170  	})
  6171  	t.Run("test_instance.b", func(t *testing.T) {
  6172  		instAddr := mustResourceInstanceAddr("test_instance.b")
  6173  		change := plan.Changes.ResourceInstance(instAddr)
  6174  		if change == nil {
  6175  			t.Fatalf("no planned change for %s", instAddr)
  6176  		}
  6177  		if got, want := change.PrevRunAddr, instAddr; !want.Equal(got) {
  6178  			t.Errorf("wrong previous run address for %s %s; want %s", instAddr, got, want)
  6179  		}
  6180  		if got, want := change.Action, plans.Delete; got != want {
  6181  			t.Errorf("wrong action for %s %s; want %s", instAddr, got, want)
  6182  		}
  6183  		if got, want := change.ActionReason, plans.ResourceInstanceDeleteBecauseWrongRepetition; got != want {
  6184  			t.Errorf("wrong action reason for %s %s; want %s", instAddr, got, want)
  6185  		}
  6186  	})
  6187  }
  6188  
  6189  func TestContext2Plan_targetedModuleInstance(t *testing.T) {
  6190  	m := testModule(t, "plan-targeted")
  6191  	p := testProvider("aws")
  6192  	p.PlanResourceChangeFn = testDiffFn
  6193  	ctx := testContext2(t, &ContextOpts{
  6194  		Providers: map[addrs.Provider]providers.Factory{
  6195  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  6196  		},
  6197  	})
  6198  
  6199  	plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
  6200  		Mode: plans.NormalMode,
  6201  		Targets: []addrs.Targetable{
  6202  			addrs.RootModuleInstance.Child("mod", addrs.IntKey(0)),
  6203  		},
  6204  	})
  6205  	if diags.HasErrors() {
  6206  		t.Fatalf("unexpected errors: %s", diags.Err())
  6207  	}
  6208  	schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
  6209  	ty := schema.ImpliedType()
  6210  
  6211  	if len(plan.Changes.Resources) != 1 {
  6212  		t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
  6213  	}
  6214  
  6215  	for _, res := range plan.Changes.Resources {
  6216  		ric, err := res.Decode(ty)
  6217  		if err != nil {
  6218  			t.Fatal(err)
  6219  		}
  6220  
  6221  		switch i := ric.Addr.String(); i {
  6222  		case "module.mod[0].aws_instance.foo":
  6223  			if res.Action != plans.Create {
  6224  				t.Fatalf("resource %s should be created", i)
  6225  			}
  6226  			checkVals(t, objectVal(t, schema, map[string]cty.Value{
  6227  				"id":   cty.UnknownVal(cty.String),
  6228  				"num":  cty.NumberIntVal(2),
  6229  				"type": cty.UnknownVal(cty.String),
  6230  			}), ric.After)
  6231  		default:
  6232  			t.Fatal("unknown instance:", i)
  6233  		}
  6234  	}
  6235  }
  6236  
  6237  func TestContext2Plan_dataRefreshedInPlan(t *testing.T) {
  6238  	m := testModuleInline(t, map[string]string{
  6239  		"main.tf": `
  6240  data "test_data_source" "d" {
  6241  }
  6242  `})
  6243  
  6244  	p := testProvider("test")
  6245  	p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
  6246  		State: cty.ObjectVal(map[string]cty.Value{
  6247  			"id":  cty.StringVal("this"),
  6248  			"foo": cty.NullVal(cty.String),
  6249  		}),
  6250  	}
  6251  
  6252  	ctx := testContext2(t, &ContextOpts{
  6253  		Providers: map[addrs.Provider]providers.Factory{
  6254  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6255  		},
  6256  	})
  6257  
  6258  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6259  	if diags.HasErrors() {
  6260  		t.Fatal(diags.ErrWithWarnings())
  6261  	}
  6262  
  6263  	d := plan.PriorState.ResourceInstance(mustResourceInstanceAddr("data.test_data_source.d"))
  6264  	if d == nil || d.Current == nil {
  6265  		t.Fatal("data.test_data_source.d not found in state:", plan.PriorState)
  6266  	}
  6267  
  6268  	if d.Current.Status != states.ObjectReady {
  6269  		t.Fatal("expected data.test_data_source.d to be fully read in refreshed state, got status", d.Current.Status)
  6270  	}
  6271  }
  6272  
  6273  func TestContext2Plan_dataReferencesResourceDirectly(t *testing.T) {
  6274  	// When a data resource refers to a managed resource _directly_, any
  6275  	// pending change for the managed resource will cause the data resource
  6276  	// to be deferred to the apply step.
  6277  	// See also TestContext2Plan_dataReferencesResourceIndirectly for the
  6278  	// other case, where the reference is indirect.
  6279  
  6280  	p := testProvider("test")
  6281  
  6282  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
  6283  		resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source should not be read"))
  6284  		return resp
  6285  	}
  6286  
  6287  	m := testModuleInline(t, map[string]string{
  6288  		"main.tf": `
  6289  locals {
  6290    x = "value"
  6291  }
  6292  
  6293  resource "test_resource" "a" {
  6294    value = local.x
  6295  }
  6296  
  6297  // test_resource.a.value can be resolved during plan, but the reference implies
  6298  // that the data source should wait until the resource is created.
  6299  data "test_data_source" "d" {
  6300    foo = test_resource.a.value
  6301  }
  6302  
  6303  // ensure referencing an indexed instance that has not yet created will also
  6304  // delay reading the data source
  6305  resource "test_resource" "b" {
  6306    count = 2
  6307    value = local.x
  6308  }
  6309  
  6310  data "test_data_source" "e" {
  6311    foo = test_resource.b[0].value
  6312  }
  6313  `})
  6314  
  6315  	ctx := testContext2(t, &ContextOpts{
  6316  		Providers: map[addrs.Provider]providers.Factory{
  6317  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6318  		},
  6319  	})
  6320  
  6321  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6322  	assertNoErrors(t, diags)
  6323  
  6324  	rc := plan.Changes.ResourceInstance(addrs.Resource{
  6325  		Mode: addrs.DataResourceMode,
  6326  		Type: "test_data_source",
  6327  		Name: "d",
  6328  	}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
  6329  	if rc != nil {
  6330  		if got, want := rc.ActionReason, plans.ResourceInstanceReadBecauseDependencyPending; got != want {
  6331  			t.Errorf("wrong ActionReason\ngot:  %s\nwant: %s", got, want)
  6332  		}
  6333  	} else {
  6334  		t.Error("no change for test_data_source.e")
  6335  	}
  6336  }
  6337  
  6338  func TestContext2Plan_dataReferencesResourceIndirectly(t *testing.T) {
  6339  	// When a data resource refers to a managed resource indirectly, pending
  6340  	// changes for the managed resource _do not_ cause the data resource to
  6341  	// be deferred to apply. This is a pragmatic special case added for
  6342  	// backward compatibility with the old situation where we would _always_
  6343  	// eagerly read data resources with known configurations, regardless of
  6344  	// the plans for their dependencies.
  6345  	// This test creates an indirection through a local value, but the same
  6346  	// principle would apply for both input variable and output value
  6347  	// indirection.
  6348  	//
  6349  	// See also TestContext2Plan_dataReferencesResourceDirectly for the
  6350  	// other case, where the reference is direct.
  6351  	// This special exception doesn't apply for a data resource that has
  6352  	// custom conditions; see
  6353  	// TestContext2Plan_dataResourceChecksManagedResourceChange for that
  6354  	// situation.
  6355  
  6356  	p := testProvider("test")
  6357  	var applyCount int64
  6358  	p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
  6359  		atomic.AddInt64(&applyCount, 1)
  6360  		resp.NewState = req.PlannedState
  6361  		return resp
  6362  	}
  6363  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
  6364  		if atomic.LoadInt64(&applyCount) == 0 {
  6365  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source read before managed resource apply"))
  6366  		} else {
  6367  			resp.State = req.Config
  6368  		}
  6369  		return resp
  6370  	}
  6371  
  6372  	m := testModuleInline(t, map[string]string{
  6373  		"main.tf": `
  6374  locals {
  6375  	x = "value"
  6376  }
  6377  
  6378  resource "test_resource" "a" {
  6379  	value = local.x
  6380  }
  6381  
  6382  locals {
  6383  	y = test_resource.a.value
  6384  }
  6385  
  6386  // test_resource.a.value would ideally cause a pending change for
  6387  // test_resource.a to defer this to the apply step, but we intentionally don't
  6388  // do that when it's indirect (through a local value, here) as a concession
  6389  // to backward compatibility.
  6390  data "test_data_source" "d" {
  6391  	foo = local.y
  6392  }
  6393  `})
  6394  
  6395  	ctx := testContext2(t, &ContextOpts{
  6396  		Providers: map[addrs.Provider]providers.Factory{
  6397  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6398  		},
  6399  	})
  6400  
  6401  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6402  	if !diags.HasErrors() {
  6403  		t.Fatalf("successful plan; want an error")
  6404  	}
  6405  
  6406  	if got, want := diags.Err().Error(), "data source read before managed resource apply"; !strings.Contains(got, want) {
  6407  		t.Errorf("Missing expected error message\ngot: %s\nwant substring: %s", got, want)
  6408  	}
  6409  }
  6410  
  6411  func TestContext2Plan_skipRefresh(t *testing.T) {
  6412  	p := testProvider("test")
  6413  	p.PlanResourceChangeFn = testDiffFn
  6414  
  6415  	m := testModuleInline(t, map[string]string{
  6416  		"main.tf": `
  6417  resource "test_instance" "a" {
  6418  }
  6419  `})
  6420  
  6421  	state := states.NewState()
  6422  	root := state.EnsureModule(addrs.RootModuleInstance)
  6423  	root.SetResourceInstanceCurrent(
  6424  		mustResourceInstanceAddr("test_instance.a").Resource,
  6425  		&states.ResourceInstanceObjectSrc{
  6426  			Status:       states.ObjectReady,
  6427  			AttrsJSON:    []byte(`{"id":"a","type":"test_instance"}`),
  6428  			Dependencies: []addrs.ConfigResource{},
  6429  		},
  6430  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
  6431  	)
  6432  
  6433  	ctx := testContext2(t, &ContextOpts{
  6434  		Providers: map[addrs.Provider]providers.Factory{
  6435  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6436  		},
  6437  	})
  6438  
  6439  	plan, diags := ctx.Plan(m, state, &PlanOpts{
  6440  		Mode:        plans.NormalMode,
  6441  		SkipRefresh: true,
  6442  	})
  6443  	assertNoErrors(t, diags)
  6444  
  6445  	if p.ReadResourceCalled {
  6446  		t.Fatal("Resource should not have been refreshed")
  6447  	}
  6448  
  6449  	for _, c := range plan.Changes.Resources {
  6450  		if c.Action != plans.NoOp {
  6451  			t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
  6452  		}
  6453  	}
  6454  }
  6455  
  6456  func TestContext2Plan_dataInModuleDependsOn(t *testing.T) {
  6457  	p := testProvider("test")
  6458  
  6459  	readDataSourceB := false
  6460  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
  6461  		cfg := req.Config.AsValueMap()
  6462  		foo := cfg["foo"].AsString()
  6463  
  6464  		cfg["id"] = cty.StringVal("ID")
  6465  		cfg["foo"] = cty.StringVal("new")
  6466  
  6467  		if foo == "b" {
  6468  			readDataSourceB = true
  6469  		}
  6470  
  6471  		resp.State = cty.ObjectVal(cfg)
  6472  		return resp
  6473  	}
  6474  
  6475  	m := testModuleInline(t, map[string]string{
  6476  		"main.tf": `
  6477  module "a" {
  6478    source = "./mod_a"
  6479  }
  6480  
  6481  module "b" {
  6482    source = "./mod_b"
  6483    depends_on = [module.a]
  6484  }`,
  6485  		"mod_a/main.tf": `
  6486  data "test_data_source" "a" {
  6487    foo = "a"
  6488  }`,
  6489  		"mod_b/main.tf": `
  6490  data "test_data_source" "b" {
  6491    foo = "b"
  6492  }`,
  6493  	})
  6494  
  6495  	ctx := testContext2(t, &ContextOpts{
  6496  		Providers: map[addrs.Provider]providers.Factory{
  6497  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6498  		},
  6499  	})
  6500  
  6501  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6502  	assertNoErrors(t, diags)
  6503  
  6504  	// The change to data source a should not prevent data source b from being
  6505  	// read.
  6506  	if !readDataSourceB {
  6507  		t.Fatal("data source b was not read during plan")
  6508  	}
  6509  }
  6510  
  6511  func TestContext2Plan_rpcDiagnostics(t *testing.T) {
  6512  	m := testModuleInline(t, map[string]string{
  6513  		"main.tf": `
  6514  resource "test_instance" "a" {
  6515  }
  6516  `,
  6517  	})
  6518  
  6519  	p := testProvider("test")
  6520  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
  6521  		resp := testDiffFn(req)
  6522  		resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("don't frobble"))
  6523  		return resp
  6524  	}
  6525  
  6526  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6527  		ResourceTypes: map[string]*configschema.Block{
  6528  			"test_instance": {
  6529  				Attributes: map[string]*configschema.Attribute{
  6530  					"id": {Type: cty.String, Computed: true},
  6531  				},
  6532  			},
  6533  		},
  6534  	})
  6535  
  6536  	ctx := testContext2(t, &ContextOpts{
  6537  		Providers: map[addrs.Provider]providers.Factory{
  6538  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6539  		},
  6540  	})
  6541  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6542  	if diags.HasErrors() {
  6543  		t.Fatal(diags.Err())
  6544  	}
  6545  
  6546  	if len(diags) == 0 {
  6547  		t.Fatal("expected warnings")
  6548  	}
  6549  
  6550  	for _, d := range diags {
  6551  		des := d.Description().Summary
  6552  		if !strings.Contains(des, "frobble") {
  6553  			t.Fatalf(`expected frobble, got %q`, des)
  6554  		}
  6555  	}
  6556  }
  6557  
  6558  // ignore_changes needs to be re-applied to the planned value for provider
  6559  // using the LegacyTypeSystem
  6560  func TestContext2Plan_legacyProviderIgnoreChanges(t *testing.T) {
  6561  	m := testModuleInline(t, map[string]string{
  6562  		"main.tf": `
  6563  resource "test_instance" "a" {
  6564    lifecycle {
  6565      ignore_changes = [data]
  6566    }
  6567  }
  6568  `,
  6569  	})
  6570  
  6571  	p := testProvider("test")
  6572  	p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
  6573  		m := req.ProposedNewState.AsValueMap()
  6574  		// this provider "hashes" the data attribute as bar
  6575  		m["data"] = cty.StringVal("bar")
  6576  
  6577  		resp.PlannedState = cty.ObjectVal(m)
  6578  		resp.LegacyTypeSystem = true
  6579  		return resp
  6580  	}
  6581  
  6582  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6583  		ResourceTypes: map[string]*configschema.Block{
  6584  			"test_instance": {
  6585  				Attributes: map[string]*configschema.Attribute{
  6586  					"id":   {Type: cty.String, Computed: true},
  6587  					"data": {Type: cty.String, Optional: true},
  6588  				},
  6589  			},
  6590  		},
  6591  	})
  6592  
  6593  	state := states.NewState()
  6594  	root := state.EnsureModule(addrs.RootModuleInstance)
  6595  	root.SetResourceInstanceCurrent(
  6596  		mustResourceInstanceAddr("test_instance.a").Resource,
  6597  		&states.ResourceInstanceObjectSrc{
  6598  			Status:       states.ObjectReady,
  6599  			AttrsJSON:    []byte(`{"id":"a","data":"foo"}`),
  6600  			Dependencies: []addrs.ConfigResource{},
  6601  		},
  6602  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
  6603  	)
  6604  
  6605  	ctx := testContext2(t, &ContextOpts{
  6606  		Providers: map[addrs.Provider]providers.Factory{
  6607  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6608  		},
  6609  	})
  6610  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6611  	if diags.HasErrors() {
  6612  		t.Fatal(diags.Err())
  6613  	}
  6614  
  6615  	for _, c := range plan.Changes.Resources {
  6616  		if c.Action != plans.NoOp {
  6617  			t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
  6618  		}
  6619  	}
  6620  }
  6621  
  6622  func TestContext2Plan_validateIgnoreAll(t *testing.T) {
  6623  	m := testModuleInline(t, map[string]string{
  6624  		"main.tf": `
  6625  resource "test_instance" "a" {
  6626    lifecycle {
  6627      ignore_changes = all
  6628    }
  6629  }
  6630  `,
  6631  	})
  6632  
  6633  	p := testProvider("test")
  6634  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  6635  		ResourceTypes: map[string]*configschema.Block{
  6636  			"test_instance": {
  6637  				Attributes: map[string]*configschema.Attribute{
  6638  					"id":   {Type: cty.String, Computed: true},
  6639  					"data": {Type: cty.String, Optional: true},
  6640  				},
  6641  			},
  6642  		},
  6643  	})
  6644  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
  6645  		var diags tfdiags.Diagnostics
  6646  		if req.TypeName == "test_instance" {
  6647  			if !req.Config.GetAttr("id").IsNull() {
  6648  				diags = diags.Append(errors.New("id cannot be set in config"))
  6649  			}
  6650  		}
  6651  		return providers.ValidateResourceConfigResponse{
  6652  			Diagnostics: diags,
  6653  		}
  6654  	}
  6655  
  6656  	state := states.NewState()
  6657  	root := state.EnsureModule(addrs.RootModuleInstance)
  6658  	root.SetResourceInstanceCurrent(
  6659  		mustResourceInstanceAddr("test_instance.a").Resource,
  6660  		&states.ResourceInstanceObjectSrc{
  6661  			Status:       states.ObjectReady,
  6662  			AttrsJSON:    []byte(`{"id":"a","data":"foo"}`),
  6663  			Dependencies: []addrs.ConfigResource{},
  6664  		},
  6665  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
  6666  	)
  6667  
  6668  	ctx := testContext2(t, &ContextOpts{
  6669  		Providers: map[addrs.Provider]providers.Factory{
  6670  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6671  		},
  6672  	})
  6673  	_, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6674  	if diags.HasErrors() {
  6675  		t.Fatal(diags.Err())
  6676  	}
  6677  }
  6678  
  6679  func TestContext2Plan_dataRemovalNoProvider(t *testing.T) {
  6680  	m := testModuleInline(t, map[string]string{
  6681  		"main.tf": `
  6682  resource "test_instance" "a" {
  6683  }
  6684  `,
  6685  	})
  6686  
  6687  	p := testProvider("test")
  6688  
  6689  	state := states.NewState()
  6690  	root := state.EnsureModule(addrs.RootModuleInstance)
  6691  	root.SetResourceInstanceCurrent(
  6692  		mustResourceInstanceAddr("test_instance.a").Resource,
  6693  		&states.ResourceInstanceObjectSrc{
  6694  			Status:       states.ObjectReady,
  6695  			AttrsJSON:    []byte(`{"id":"a","data":"foo"}`),
  6696  			Dependencies: []addrs.ConfigResource{},
  6697  		},
  6698  		mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
  6699  	)
  6700  
  6701  	// the provider for this data source is no longer in the config, but that
  6702  	// should not matter for state removal.
  6703  	root.SetResourceInstanceCurrent(
  6704  		mustResourceInstanceAddr("data.test_data_source.d").Resource,
  6705  		&states.ResourceInstanceObjectSrc{
  6706  			Status:       states.ObjectReady,
  6707  			AttrsJSON:    []byte(`{"id":"d"}`),
  6708  			Dependencies: []addrs.ConfigResource{},
  6709  		},
  6710  		mustProviderConfig(`provider["registry.terraform.io/local/test"]`),
  6711  	)
  6712  
  6713  	ctx := testContext2(t, &ContextOpts{
  6714  		Providers: map[addrs.Provider]providers.Factory{
  6715  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6716  			// We still need to be able to locate the provider to decode the
  6717  			// state, since we do not know during init that this provider is
  6718  			// only used for an orphaned data source.
  6719  			addrs.NewProvider("registry.terraform.io", "local", "test"): testProviderFuncFixed(p),
  6720  		},
  6721  	})
  6722  	_, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6723  	if diags.HasErrors() {
  6724  		t.Fatal(diags.Err())
  6725  	}
  6726  }
  6727  
  6728  func TestContext2Plan_noSensitivityChange(t *testing.T) {
  6729  	m := testModuleInline(t, map[string]string{
  6730  		"main.tf": `
  6731  variable "sensitive_var" {
  6732         default = "hello"
  6733         sensitive = true
  6734  }
  6735  
  6736  resource "test_resource" "foo" {
  6737         value = var.sensitive_var
  6738         sensitive_value = var.sensitive_var
  6739  }`,
  6740  	})
  6741  
  6742  	p := testProvider("test")
  6743  
  6744  	ctx := testContext2(t, &ContextOpts{
  6745  		Providers: map[addrs.Provider]providers.Factory{
  6746  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6747  		},
  6748  	})
  6749  	state := states.BuildState(func(s *states.SyncState) {
  6750  		s.SetResourceInstanceCurrent(
  6751  			addrs.Resource{
  6752  				Mode: addrs.ManagedResourceMode,
  6753  				Type: "test_resource",
  6754  				Name: "foo",
  6755  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
  6756  			&states.ResourceInstanceObjectSrc{
  6757  				Status:    states.ObjectReady,
  6758  				AttrsJSON: []byte(`{"id":"foo", "value":"hello", "sensitive_value":"hello"}`),
  6759  				AttrSensitivePaths: []cty.PathValueMarks{
  6760  					{Path: cty.Path{cty.GetAttrStep{Name: "value"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
  6761  					{Path: cty.Path{cty.GetAttrStep{Name: "sensitive_value"}}, Marks: cty.NewValueMarks(marks.Sensitive)},
  6762  				},
  6763  			},
  6764  			addrs.AbsProviderConfig{
  6765  				Provider: addrs.NewDefaultProvider("test"),
  6766  				Module:   addrs.RootModule,
  6767  			},
  6768  		)
  6769  	})
  6770  	plan, diags := ctx.Plan(m, state, SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
  6771  	if diags.HasErrors() {
  6772  		t.Fatal(diags.Err())
  6773  	}
  6774  
  6775  	for _, c := range plan.Changes.Resources {
  6776  		if c.Action != plans.NoOp {
  6777  			t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
  6778  		}
  6779  	}
  6780  }
  6781  
  6782  func TestContext2Plan_variableCustomValidationsSensitive(t *testing.T) {
  6783  	m := testModule(t, "validate-variable-custom-validations-child-sensitive")
  6784  
  6785  	p := testProvider("test")
  6786  	ctx := testContext2(t, &ContextOpts{
  6787  		Providers: map[addrs.Provider]providers.Factory{
  6788  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  6789  		},
  6790  	})
  6791  
  6792  	_, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6793  	if !diags.HasErrors() {
  6794  		t.Fatal("succeeded; want errors")
  6795  	}
  6796  	if got, want := diags.Err().Error(), `Invalid value for variable: Value must not be "nope".`; !strings.Contains(got, want) {
  6797  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  6798  	}
  6799  }
  6800  
  6801  func TestContext2Plan_nullOutputNoOp(t *testing.T) {
  6802  	// this should always plan a NoOp change for the output
  6803  	m := testModuleInline(t, map[string]string{
  6804  		"main.tf": `
  6805  output "planned" {
  6806    value = false ? 1 : null
  6807  }
  6808  `,
  6809  	})
  6810  
  6811  	ctx := testContext2(t, &ContextOpts{})
  6812  	state := states.BuildState(func(s *states.SyncState) {
  6813  		r := s.Module(addrs.RootModuleInstance)
  6814  		r.SetOutputValue("planned", cty.NullVal(cty.DynamicPseudoType), false)
  6815  	})
  6816  	plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
  6817  	if diags.HasErrors() {
  6818  		t.Fatal(diags.Err())
  6819  	}
  6820  
  6821  	for _, c := range plan.Changes.Outputs {
  6822  		if c.Action != plans.NoOp {
  6823  			t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
  6824  		}
  6825  	}
  6826  }
  6827  
  6828  func TestContext2Plan_createOutput(t *testing.T) {
  6829  	// this should always plan a NoOp change for the output
  6830  	m := testModuleInline(t, map[string]string{
  6831  		"main.tf": `
  6832  output "planned" {
  6833    value = 1
  6834  }
  6835  `,
  6836  	})
  6837  
  6838  	ctx := testContext2(t, &ContextOpts{})
  6839  	plan, diags := ctx.Plan(m, states.NewState(), DefaultPlanOpts)
  6840  	if diags.HasErrors() {
  6841  		t.Fatal(diags.Err())
  6842  	}
  6843  
  6844  	for _, c := range plan.Changes.Outputs {
  6845  		if c.Action != plans.Create {
  6846  			t.Fatalf("expected Create change, got %s for %q", c.Action, c.Addr)
  6847  		}
  6848  	}
  6849  }
  6850  
  6851  ////////////////////////////////////////////////////////////////////////////////
  6852  // NOTE: Due to the size of this file, new tests should be added to
  6853  // context_plan2_test.go.
  6854  ////////////////////////////////////////////////////////////////////////////////