github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/context_plan_test.go (about)

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