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