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

     1  package terraform
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"sync"
     7  	"testing"
     8  
     9  	"github.com/zclconf/go-cty/cty"
    10  
    11  	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
    12  	"github.com/hashicorp/terraform-plugin-sdk/internal/configs/configschema"
    13  	"github.com/hashicorp/terraform-plugin-sdk/internal/providers"
    14  	"github.com/hashicorp/terraform-plugin-sdk/internal/states"
    15  )
    16  
    17  func TestContext2Input(t *testing.T) {
    18  	input := new(MockUIInput)
    19  	m := testModule(t, "input-vars")
    20  	p := testProvider("aws")
    21  	p.ApplyFn = testApplyFn
    22  	p.DiffFn = testDiffFn
    23  	ctx := testContext2(t, &ContextOpts{
    24  		Config: m,
    25  		ProviderResolver: providers.ResolverFixed(
    26  			map[string]providers.Factory{
    27  				"aws": testProviderFuncFixed(p),
    28  			},
    29  		),
    30  		Variables: InputValues{
    31  			"amis": &InputValue{
    32  				Value: cty.MapVal(map[string]cty.Value{
    33  					"us-east-1": cty.StringVal("override"),
    34  				}),
    35  				SourceType: ValueFromCaller,
    36  			},
    37  		},
    38  		UIInput: input,
    39  	})
    40  
    41  	input.InputReturnMap = map[string]string{
    42  		"var.foo": "us-east-1",
    43  	}
    44  
    45  	if diags := ctx.Input(InputModeStd | InputModeVarUnset); diags.HasErrors() {
    46  		t.Fatalf("input errors: %s", diags.Err())
    47  	}
    48  
    49  	if _, diags := ctx.Plan(); diags.HasErrors() {
    50  		t.Fatalf("plan errors: %s", diags.Err())
    51  	}
    52  
    53  	state, diags := ctx.Apply()
    54  	if diags.HasErrors() {
    55  		t.Fatalf("apply errors: %s", diags.Err())
    56  	}
    57  
    58  	actual := strings.TrimSpace(state.String())
    59  	expected := strings.TrimSpace(testTerraformInputVarsStr)
    60  	if actual != expected {
    61  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
    62  	}
    63  }
    64  
    65  func TestContext2Input_moduleComputedOutputElement(t *testing.T) {
    66  	m := testModule(t, "input-module-computed-output-element")
    67  	p := testProvider("aws")
    68  	p.ApplyFn = testApplyFn
    69  	p.DiffFn = testDiffFn
    70  	ctx := testContext2(t, &ContextOpts{
    71  		Config: m,
    72  		ProviderResolver: providers.ResolverFixed(
    73  			map[string]providers.Factory{
    74  				"aws": testProviderFuncFixed(p),
    75  			},
    76  		),
    77  	})
    78  
    79  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
    80  		t.Fatalf("input errors: %s", diags.Err())
    81  	}
    82  }
    83  
    84  func TestContext2Input_badVarDefault(t *testing.T) {
    85  	m := testModule(t, "input-bad-var-default")
    86  	p := testProvider("aws")
    87  	p.ApplyFn = testApplyFn
    88  	p.DiffFn = testDiffFn
    89  	ctx := testContext2(t, &ContextOpts{
    90  		Config: m,
    91  		ProviderResolver: providers.ResolverFixed(
    92  			map[string]providers.Factory{
    93  				"aws": testProviderFuncFixed(p),
    94  			},
    95  		),
    96  	})
    97  
    98  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
    99  		t.Fatalf("input errors: %s", diags.Err())
   100  	}
   101  }
   102  
   103  func TestContext2Input_provider(t *testing.T) {
   104  	m := testModule(t, "input-provider")
   105  	p := testProvider("aws")
   106  	p.ApplyFn = testApplyFn
   107  	p.DiffFn = testDiffFn
   108  	p.GetSchemaReturn = &ProviderSchema{
   109  		Provider: &configschema.Block{
   110  			Attributes: map[string]*configschema.Attribute{
   111  				"foo": {
   112  					Type:        cty.String,
   113  					Required:    true,
   114  					Description: "something something",
   115  				},
   116  			},
   117  		},
   118  		ResourceTypes: map[string]*configschema.Block{
   119  			"aws_instance": {},
   120  		},
   121  	}
   122  
   123  	inp := &MockUIInput{
   124  		InputReturnMap: map[string]string{
   125  			"provider.aws.foo": "bar",
   126  		},
   127  	}
   128  
   129  	ctx := testContext2(t, &ContextOpts{
   130  		Config: m,
   131  		ProviderResolver: providers.ResolverFixed(
   132  			map[string]providers.Factory{
   133  				"aws": testProviderFuncFixed(p),
   134  			},
   135  		),
   136  		UIInput: inp,
   137  	})
   138  
   139  	var actual interface{}
   140  	p.ConfigureFn = func(c *ResourceConfig) error {
   141  		actual = c.Config["foo"]
   142  		return nil
   143  	}
   144  	p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
   145  		return nil, c.CheckSet([]string{"foo"})
   146  	}
   147  
   148  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
   149  		t.Fatalf("input errors: %s", diags.Err())
   150  	}
   151  
   152  	if !inp.InputCalled {
   153  		t.Fatal("no input prompt; want prompt for argument \"foo\"")
   154  	}
   155  	if got, want := inp.InputOpts.Description, "something something"; got != want {
   156  		t.Errorf("wrong description\ngot:  %q\nwant: %q", got, want)
   157  	}
   158  
   159  	if _, diags := ctx.Plan(); diags.HasErrors() {
   160  		t.Fatalf("plan errors: %s", diags.Err())
   161  	}
   162  
   163  	if _, diags := ctx.Apply(); diags.HasErrors() {
   164  		t.Fatalf("apply errors: %s", diags.Err())
   165  	}
   166  
   167  	if !reflect.DeepEqual(actual, "bar") {
   168  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", actual, "bar")
   169  	}
   170  }
   171  
   172  func TestContext2Input_providerMulti(t *testing.T) {
   173  	m := testModule(t, "input-provider-multi")
   174  
   175  	p := testProvider("aws")
   176  	p.ApplyFn = testApplyFn
   177  	p.DiffFn = testDiffFn
   178  	p.GetSchemaReturn = &ProviderSchema{
   179  		Provider: &configschema.Block{
   180  			Attributes: map[string]*configschema.Attribute{
   181  				"foo": {
   182  					Type:        cty.String,
   183  					Required:    true,
   184  					Description: "something something",
   185  				},
   186  			},
   187  		},
   188  		ResourceTypes: map[string]*configschema.Block{
   189  			"aws_instance": {},
   190  		},
   191  	}
   192  
   193  	inp := &MockUIInput{
   194  		InputReturnMap: map[string]string{
   195  			"provider.aws.foo":      "bar",
   196  			"provider.aws.east.foo": "bar",
   197  		},
   198  	}
   199  
   200  	ctx := testContext2(t, &ContextOpts{
   201  		Config: m,
   202  		ProviderResolver: providers.ResolverFixed(
   203  			map[string]providers.Factory{
   204  				"aws": testProviderFuncFixed(p),
   205  			},
   206  		),
   207  		UIInput: inp,
   208  	})
   209  
   210  	var actual []interface{}
   211  	var lock sync.Mutex
   212  	p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
   213  		return nil, c.CheckSet([]string{"foo"})
   214  	}
   215  
   216  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
   217  		t.Fatalf("input errors: %s", diags.Err())
   218  	}
   219  
   220  	if _, diags := ctx.Plan(); diags.HasErrors() {
   221  		t.Fatalf("plan errors: %s", diags.Err())
   222  	}
   223  
   224  	p.ConfigureFn = func(c *ResourceConfig) error {
   225  		lock.Lock()
   226  		defer lock.Unlock()
   227  		actual = append(actual, c.Config["foo"])
   228  		return nil
   229  	}
   230  	if _, diags := ctx.Apply(); diags.HasErrors() {
   231  		t.Fatalf("apply errors: %s", diags.Err())
   232  	}
   233  
   234  	expected := []interface{}{"bar", "bar"}
   235  	if !reflect.DeepEqual(actual, expected) {
   236  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", actual, expected)
   237  	}
   238  }
   239  
   240  func TestContext2Input_providerOnce(t *testing.T) {
   241  	m := testModule(t, "input-provider-once")
   242  	p := testProvider("aws")
   243  	p.ApplyFn = testApplyFn
   244  	p.DiffFn = testDiffFn
   245  	ctx := testContext2(t, &ContextOpts{
   246  		Config: m,
   247  		ProviderResolver: providers.ResolverFixed(
   248  			map[string]providers.Factory{
   249  				"aws": testProviderFuncFixed(p),
   250  			},
   251  		),
   252  	})
   253  
   254  	//count := 0
   255  	/*p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   256  		count++
   257  		_, set := c.Config["from_input"]
   258  
   259  		if count == 1 {
   260  			if set {
   261  				return nil, errors.New("from_input should not be set")
   262  			}
   263  			c.Config["from_input"] = "x"
   264  		}
   265  
   266  		if count > 1 && !set {
   267  			return nil, errors.New("from_input should be set")
   268  		}
   269  
   270  		return c, nil
   271  	}*/
   272  
   273  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
   274  		t.Fatalf("input errors: %s", diags.Err())
   275  	}
   276  }
   277  
   278  func TestContext2Input_providerId(t *testing.T) {
   279  	input := new(MockUIInput)
   280  
   281  	m := testModule(t, "input-provider")
   282  
   283  	p := testProvider("aws")
   284  	p.ApplyFn = testApplyFn
   285  	p.DiffFn = testDiffFn
   286  	p.GetSchemaReturn = &ProviderSchema{
   287  		Provider: &configschema.Block{
   288  			Attributes: map[string]*configschema.Attribute{
   289  				"foo": {
   290  					Type:        cty.String,
   291  					Required:    true,
   292  					Description: "something something",
   293  				},
   294  			},
   295  		},
   296  		ResourceTypes: map[string]*configschema.Block{
   297  			"aws_instance": {},
   298  		},
   299  	}
   300  
   301  	ctx := testContext2(t, &ContextOpts{
   302  		Config: m,
   303  		ProviderResolver: providers.ResolverFixed(
   304  			map[string]providers.Factory{
   305  				"aws": testProviderFuncFixed(p),
   306  			},
   307  		),
   308  		UIInput: input,
   309  	})
   310  
   311  	var actual interface{}
   312  	p.ConfigureFn = func(c *ResourceConfig) error {
   313  		actual = c.Config["foo"]
   314  		return nil
   315  	}
   316  
   317  	input.InputReturnMap = map[string]string{
   318  		"provider.aws.foo": "bar",
   319  	}
   320  
   321  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
   322  		t.Fatalf("input errors: %s", diags.Err())
   323  	}
   324  
   325  	if _, diags := ctx.Plan(); diags.HasErrors() {
   326  		t.Fatalf("plan errors: %s", diags.Err())
   327  	}
   328  
   329  	if _, diags := ctx.Apply(); diags.HasErrors() {
   330  		t.Fatalf("apply errors: %s", diags.Err())
   331  	}
   332  
   333  	if !reflect.DeepEqual(actual, "bar") {
   334  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", actual, "bar")
   335  	}
   336  }
   337  
   338  func TestContext2Input_providerOnly(t *testing.T) {
   339  	input := new(MockUIInput)
   340  
   341  	m := testModule(t, "input-provider-vars")
   342  
   343  	p := testProvider("aws")
   344  	p.ApplyFn = testApplyFn
   345  	p.DiffFn = testDiffFn
   346  	p.GetSchemaReturn = &ProviderSchema{
   347  		Provider: &configschema.Block{
   348  			Attributes: map[string]*configschema.Attribute{
   349  				"foo": {
   350  					Type:     cty.String,
   351  					Required: true,
   352  				},
   353  			},
   354  		},
   355  		ResourceTypes: map[string]*configschema.Block{
   356  			"aws_instance": {
   357  				Attributes: map[string]*configschema.Attribute{
   358  					"foo":  {Type: cty.String, Required: true},
   359  					"id":   {Type: cty.String, Computed: true},
   360  					"type": {Type: cty.String, Computed: true},
   361  				},
   362  			},
   363  		},
   364  	}
   365  
   366  	ctx := testContext2(t, &ContextOpts{
   367  		Config: m,
   368  		ProviderResolver: providers.ResolverFixed(
   369  			map[string]providers.Factory{
   370  				"aws": testProviderFuncFixed(p),
   371  			},
   372  		),
   373  		Variables: InputValues{
   374  			"foo": &InputValue{
   375  				Value:      cty.StringVal("us-west-2"),
   376  				SourceType: ValueFromCaller,
   377  			},
   378  		},
   379  		UIInput: input,
   380  	})
   381  
   382  	input.InputReturnMap = map[string]string{
   383  		"provider.aws.foo": "bar",
   384  	}
   385  
   386  	var actual interface{}
   387  	p.ConfigureFn = func(c *ResourceConfig) error {
   388  		actual = c.Config["foo"]
   389  		return nil
   390  	}
   391  
   392  	if err := ctx.Input(InputModeProvider); err != nil {
   393  		t.Fatalf("err: %s", err)
   394  	}
   395  
   396  	if _, diags := ctx.Plan(); diags.HasErrors() {
   397  		t.Fatalf("plan errors: %s", diags.Err())
   398  	}
   399  
   400  	state, err := ctx.Apply()
   401  	if err != nil {
   402  		t.Fatalf("err: %s", err)
   403  	}
   404  
   405  	if !reflect.DeepEqual(actual, "bar") {
   406  		t.Fatalf("wrong result\ngot:  %#v\nwant: %#v", actual, "bar")
   407  	}
   408  
   409  	actualStr := strings.TrimSpace(state.String())
   410  	expectedStr := strings.TrimSpace(testTerraformInputProviderOnlyStr)
   411  	if actualStr != expectedStr {
   412  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actualStr, expectedStr)
   413  	}
   414  }
   415  
   416  func TestContext2Input_providerVars(t *testing.T) {
   417  	input := new(MockUIInput)
   418  	m := testModule(t, "input-provider-with-vars")
   419  	p := testProvider("aws")
   420  	p.ApplyFn = testApplyFn
   421  	p.DiffFn = testDiffFn
   422  	ctx := testContext2(t, &ContextOpts{
   423  		Config: m,
   424  		ProviderResolver: providers.ResolverFixed(
   425  			map[string]providers.Factory{
   426  				"aws": testProviderFuncFixed(p),
   427  			},
   428  		),
   429  		Variables: InputValues{
   430  			"foo": &InputValue{
   431  				Value:      cty.StringVal("bar"),
   432  				SourceType: ValueFromCaller,
   433  			},
   434  		},
   435  		UIInput: input,
   436  	})
   437  
   438  	input.InputReturnMap = map[string]string{
   439  		"var.foo": "bar",
   440  	}
   441  
   442  	var actual interface{}
   443  	/*p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   444  		c.Config["bar"] = "baz"
   445  		return c, nil
   446  	}*/
   447  	p.ConfigureFn = func(c *ResourceConfig) error {
   448  		actual, _ = c.Get("foo")
   449  		return nil
   450  	}
   451  
   452  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
   453  		t.Fatalf("input errors: %s", diags.Err())
   454  	}
   455  
   456  	if _, diags := ctx.Plan(); diags.HasErrors() {
   457  		t.Fatalf("plan errors: %s", diags.Err())
   458  	}
   459  
   460  	if _, diags := ctx.Apply(); diags.HasErrors() {
   461  		t.Fatalf("apply errors: %s", diags.Err())
   462  	}
   463  
   464  	if !reflect.DeepEqual(actual, "bar") {
   465  		t.Fatalf("bad: %#v", actual)
   466  	}
   467  }
   468  
   469  func TestContext2Input_providerVarsModuleInherit(t *testing.T) {
   470  	input := new(MockUIInput)
   471  	m := testModule(t, "input-provider-with-vars-and-module")
   472  	p := testProvider("aws")
   473  	p.ApplyFn = testApplyFn
   474  	p.DiffFn = testDiffFn
   475  	ctx := testContext2(t, &ContextOpts{
   476  		Config: m,
   477  		ProviderResolver: providers.ResolverFixed(
   478  			map[string]providers.Factory{
   479  				"aws": testProviderFuncFixed(p),
   480  			},
   481  		),
   482  		UIInput: input,
   483  	})
   484  
   485  	/*p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   486  		if errs := c.CheckSet([]string{"access_key"}); len(errs) > 0 {
   487  			return c, errs[0]
   488  		}
   489  		return c, nil
   490  	}*/
   491  	p.ConfigureFn = func(c *ResourceConfig) error {
   492  		return nil
   493  	}
   494  
   495  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
   496  		t.Fatalf("input errors: %s", diags.Err())
   497  	}
   498  }
   499  
   500  func TestContext2Input_varOnly(t *testing.T) {
   501  	input := new(MockUIInput)
   502  	m := testModule(t, "input-provider-vars")
   503  	p := testProvider("aws")
   504  	p.ApplyFn = testApplyFn
   505  	p.DiffFn = testDiffFn
   506  	ctx := testContext2(t, &ContextOpts{
   507  		Config: m,
   508  		ProviderResolver: providers.ResolverFixed(
   509  			map[string]providers.Factory{
   510  				"aws": testProviderFuncFixed(p),
   511  			},
   512  		),
   513  		Variables: InputValues{
   514  			"foo": &InputValue{
   515  				Value:      cty.StringVal("us-west-2"),
   516  				SourceType: ValueFromCaller,
   517  			},
   518  		},
   519  		UIInput: input,
   520  	})
   521  
   522  	input.InputReturnMap = map[string]string{
   523  		"var.foo": "us-east-1",
   524  	}
   525  
   526  	var actual interface{}
   527  	/*p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   528  		c.Raw["foo"] = "bar"
   529  		return c, nil
   530  	}*/
   531  	p.ConfigureFn = func(c *ResourceConfig) error {
   532  		actual = c.Raw["foo"]
   533  		return nil
   534  	}
   535  
   536  	if err := ctx.Input(InputModeVar); err != nil {
   537  		t.Fatalf("err: %s", err)
   538  	}
   539  
   540  	if _, diags := ctx.Plan(); diags.HasErrors() {
   541  		t.Fatalf("plan errors: %s", diags.Err())
   542  	}
   543  
   544  	state, err := ctx.Apply()
   545  	if err != nil {
   546  		t.Fatalf("err: %s", err)
   547  	}
   548  
   549  	if reflect.DeepEqual(actual, "bar") {
   550  		t.Fatalf("bad: %#v", actual)
   551  	}
   552  
   553  	actualStr := strings.TrimSpace(state.String())
   554  	expectedStr := strings.TrimSpace(testTerraformInputVarOnlyStr)
   555  	if actualStr != expectedStr {
   556  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actualStr, expectedStr)
   557  	}
   558  }
   559  
   560  func TestContext2Input_varOnlyUnset(t *testing.T) {
   561  	input := new(MockUIInput)
   562  	m := testModule(t, "input-vars-unset")
   563  	p := testProvider("aws")
   564  	p.ApplyFn = testApplyFn
   565  	p.DiffFn = testDiffFn
   566  	ctx := testContext2(t, &ContextOpts{
   567  		Config: m,
   568  		ProviderResolver: providers.ResolverFixed(
   569  			map[string]providers.Factory{
   570  				"aws": testProviderFuncFixed(p),
   571  			},
   572  		),
   573  		Variables: InputValues{
   574  			"foo": &InputValue{
   575  				Value:      cty.StringVal("foovalue"),
   576  				SourceType: ValueFromCaller,
   577  			},
   578  		},
   579  		UIInput: input,
   580  	})
   581  
   582  	input.InputReturnMap = map[string]string{
   583  		"var.foo": "nope",
   584  		"var.bar": "baz",
   585  	}
   586  
   587  	if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil {
   588  		t.Fatalf("err: %s", err)
   589  	}
   590  
   591  	if _, diags := ctx.Plan(); diags.HasErrors() {
   592  		t.Fatalf("plan errors: %s", diags.Err())
   593  	}
   594  
   595  	state, err := ctx.Apply()
   596  	if err != nil {
   597  		t.Fatalf("err: %s", err)
   598  	}
   599  
   600  	actualStr := strings.TrimSpace(state.String())
   601  	expectedStr := strings.TrimSpace(testTerraformInputVarOnlyUnsetStr)
   602  	if actualStr != expectedStr {
   603  		t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actualStr, expectedStr)
   604  	}
   605  }
   606  
   607  func TestContext2Input_varWithDefault(t *testing.T) {
   608  	input := new(MockUIInput)
   609  	m := testModule(t, "input-var-default")
   610  	p := testProvider("aws")
   611  	p.ApplyFn = testApplyFn
   612  	p.DiffFn = testDiffFn
   613  	ctx := testContext2(t, &ContextOpts{
   614  		Config: m,
   615  		ProviderResolver: providers.ResolverFixed(
   616  			map[string]providers.Factory{
   617  				"aws": testProviderFuncFixed(p),
   618  			},
   619  		),
   620  		Variables: InputValues{},
   621  		UIInput:   input,
   622  	})
   623  
   624  	input.InputFn = func(opts *InputOpts) (string, error) {
   625  		t.Fatalf(
   626  			"Input should never be called because variable has a default: %#v", opts)
   627  		return "", nil
   628  	}
   629  
   630  	if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil {
   631  		t.Fatalf("err: %s", err)
   632  	}
   633  
   634  	if _, diags := ctx.Plan(); diags.HasErrors() {
   635  		t.Fatalf("plan errors: %s", diags.Err())
   636  	}
   637  
   638  	state, err := ctx.Apply()
   639  	if err != nil {
   640  		t.Fatalf("err: %s", err)
   641  	}
   642  
   643  	actualStr := strings.TrimSpace(state.String())
   644  	expectedStr := strings.TrimSpace(`
   645  aws_instance.foo:
   646    ID = foo
   647    provider = provider.aws
   648    foo = 123
   649    type = aws_instance
   650  	`)
   651  	if actualStr != expectedStr {
   652  		t.Fatalf("expected: \n%s\ngot: \n%s\n", expectedStr, actualStr)
   653  	}
   654  }
   655  
   656  func TestContext2Input_varPartiallyComputed(t *testing.T) {
   657  	input := new(MockUIInput)
   658  	m := testModule(t, "input-var-partially-computed")
   659  	p := testProvider("aws")
   660  	p.ApplyFn = testApplyFn
   661  	p.DiffFn = testDiffFn
   662  	ctx := testContext2(t, &ContextOpts{
   663  		Config: m,
   664  		ProviderResolver: providers.ResolverFixed(
   665  			map[string]providers.Factory{
   666  				"aws": testProviderFuncFixed(p),
   667  			},
   668  		),
   669  		Variables: InputValues{
   670  			"foo": &InputValue{
   671  				Value:      cty.StringVal("foovalue"),
   672  				SourceType: ValueFromCaller,
   673  			},
   674  		},
   675  		UIInput: input,
   676  		State: states.BuildState(func(s *states.SyncState) {
   677  			s.SetResourceInstanceCurrent(
   678  				addrs.Resource{
   679  					Mode: addrs.ManagedResourceMode,
   680  					Type: "aws_instance",
   681  					Name: "foo",
   682  				}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   683  				&states.ResourceInstanceObjectSrc{
   684  					AttrsFlat: map[string]string{
   685  						"id": "i-abc123",
   686  					},
   687  					Status: states.ObjectReady,
   688  				},
   689  				addrs.ProviderConfig{Type: "aws"}.Absolute(addrs.RootModuleInstance),
   690  			)
   691  			s.SetResourceInstanceCurrent(
   692  				addrs.Resource{
   693  					Mode: addrs.ManagedResourceMode,
   694  					Type: "aws_instance",
   695  					Name: "mode",
   696  				}.Instance(addrs.NoKey).Absolute(addrs.Module{"child"}.UnkeyedInstanceShim()),
   697  				&states.ResourceInstanceObjectSrc{
   698  					AttrsFlat: map[string]string{
   699  						"id":    "i-bcd345",
   700  						"value": "one,i-abc123",
   701  					},
   702  					Status: states.ObjectReady,
   703  				},
   704  				addrs.ProviderConfig{Type: "aws"}.Absolute(addrs.RootModuleInstance),
   705  			)
   706  		}),
   707  	})
   708  
   709  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
   710  		t.Fatalf("input errors: %s", diags.Err())
   711  	}
   712  
   713  	if _, diags := ctx.Plan(); diags.HasErrors() {
   714  		t.Fatalf("plan errors: %s", diags.Err())
   715  	}
   716  }
   717  
   718  // Module variables weren't being interpolated during the Input walk.
   719  // https://github.com/hashicorp/terraform-plugin-sdk/issues/5322
   720  func TestContext2Input_interpolateVar(t *testing.T) {
   721  	input := new(MockUIInput)
   722  
   723  	m := testModule(t, "input-interpolate-var")
   724  	p := testProvider("null")
   725  	p.ApplyFn = testApplyFn
   726  	p.DiffFn = testDiffFn
   727  
   728  	ctx := testContext2(t, &ContextOpts{
   729  		Config: m,
   730  		ProviderResolver: providers.ResolverFixed(
   731  			map[string]providers.Factory{
   732  				"template": testProviderFuncFixed(p),
   733  			},
   734  		),
   735  		UIInput: input,
   736  	})
   737  
   738  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
   739  		t.Fatalf("input errors: %s", diags.Err())
   740  	}
   741  }
   742  
   743  func TestContext2Input_hcl(t *testing.T) {
   744  	input := new(MockUIInput)
   745  	m := testModule(t, "input-hcl")
   746  	p := testProvider("hcl")
   747  	p.ApplyFn = testApplyFn
   748  	p.DiffFn = testDiffFn
   749  	p.GetSchemaReturn = &ProviderSchema{
   750  		ResourceTypes: map[string]*configschema.Block{
   751  			"hcl_instance": {
   752  				Attributes: map[string]*configschema.Attribute{
   753  					"foo":  {Type: cty.List(cty.String), Optional: true},
   754  					"bar":  {Type: cty.Map(cty.String), Optional: true},
   755  					"id":   {Type: cty.String, Computed: true},
   756  					"type": {Type: cty.String, Computed: true},
   757  				},
   758  			},
   759  		},
   760  	}
   761  	ctx := testContext2(t, &ContextOpts{
   762  		Config: m,
   763  		ProviderResolver: providers.ResolverFixed(
   764  			map[string]providers.Factory{
   765  				"hcl": testProviderFuncFixed(p),
   766  			},
   767  		),
   768  		Variables: InputValues{},
   769  		UIInput:   input,
   770  	})
   771  
   772  	input.InputReturnMap = map[string]string{
   773  		"var.listed": `["a", "b"]`,
   774  		"var.mapped": `{x = "y", w = "z"}`,
   775  	}
   776  
   777  	if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil {
   778  		t.Fatalf("err: %s", err)
   779  	}
   780  
   781  	if _, diags := ctx.Plan(); diags.HasErrors() {
   782  		t.Fatalf("plan errors: %s", diags.Err())
   783  	}
   784  
   785  	state, err := ctx.Apply()
   786  	if err != nil {
   787  		t.Fatalf("err: %s", err)
   788  	}
   789  
   790  	actualStr := strings.TrimSpace(state.String())
   791  	expectedStr := strings.TrimSpace(testTerraformInputHCL)
   792  	if actualStr != expectedStr {
   793  		t.Logf("expected: \n%s", expectedStr)
   794  		t.Fatalf("bad: \n%s", actualStr)
   795  	}
   796  }
   797  
   798  // adding a list interpolation in fails to interpolate the count variable
   799  func TestContext2Input_submoduleTriggersInvalidCount(t *testing.T) {
   800  	input := new(MockUIInput)
   801  	m := testModule(t, "input-submodule-count")
   802  	p := testProvider("aws")
   803  	p.ApplyFn = testApplyFn
   804  	p.DiffFn = testDiffFn
   805  	ctx := testContext2(t, &ContextOpts{
   806  		Config: m,
   807  		ProviderResolver: providers.ResolverFixed(
   808  			map[string]providers.Factory{
   809  				"aws": testProviderFuncFixed(p),
   810  			},
   811  		),
   812  		UIInput: input,
   813  	})
   814  
   815  	/*p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   816  		return c, nil
   817  	}*/
   818  	p.ConfigureFn = func(c *ResourceConfig) error {
   819  		return nil
   820  	}
   821  
   822  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
   823  		t.Fatalf("input errors: %s", diags.Err())
   824  	}
   825  }
   826  
   827  // In this case, a module variable can't be resolved from a data source until
   828  // it's refreshed, but it can't be refreshed during Input.
   829  func TestContext2Input_dataSourceRequiresRefresh(t *testing.T) {
   830  	input := new(MockUIInput)
   831  	p := testProvider("null")
   832  	m := testModule(t, "input-module-data-vars")
   833  
   834  	p.GetSchemaReturn = &ProviderSchema{
   835  		DataSources: map[string]*configschema.Block{
   836  			"null_data_source": {
   837  				Attributes: map[string]*configschema.Attribute{
   838  					"foo": {Type: cty.List(cty.String), Optional: true},
   839  				},
   840  			},
   841  		},
   842  	}
   843  	p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
   844  		return providers.ReadDataSourceResponse{
   845  			State: req.Config,
   846  		}
   847  	}
   848  
   849  	state := states.BuildState(func(s *states.SyncState) {
   850  		s.SetResourceInstanceCurrent(
   851  			addrs.Resource{
   852  				Mode: addrs.DataResourceMode,
   853  				Type: "null_data_source",
   854  				Name: "bar",
   855  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   856  			&states.ResourceInstanceObjectSrc{
   857  				AttrsFlat: map[string]string{
   858  					"id":    "-",
   859  					"foo.#": "1",
   860  					"foo.0": "a",
   861  					// foo.1 exists in the data source, but needs to be refreshed.
   862  				},
   863  				Status: states.ObjectReady,
   864  			},
   865  			addrs.ProviderConfig{Type: "null"}.Absolute(addrs.RootModuleInstance),
   866  		)
   867  	})
   868  
   869  	ctx := testContext2(t, &ContextOpts{
   870  		Config: m,
   871  		ProviderResolver: providers.ResolverFixed(
   872  			map[string]providers.Factory{
   873  				"null": testProviderFuncFixed(p),
   874  			},
   875  		),
   876  		State:   state,
   877  		UIInput: input,
   878  	})
   879  
   880  	if diags := ctx.Input(InputModeStd); diags.HasErrors() {
   881  		t.Fatalf("input errors: %s", diags.Err())
   882  	}
   883  
   884  	// ensure that plan works after Refresh
   885  	if _, diags := ctx.Refresh(); diags.HasErrors() {
   886  		t.Fatalf("refresh errors: %s", diags.Err())
   887  	}
   888  	if _, diags := ctx.Plan(); diags.HasErrors() {
   889  		t.Fatalf("plan errors: %s", diags.Err())
   890  	}
   891  }