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