github.com/hugorut/terraform@v1.1.3/src/terraform/context_validate_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/zclconf/go-cty/cty"
    10  
    11  	"github.com/hugorut/terraform/src/addrs"
    12  	"github.com/hugorut/terraform/src/configs/configschema"
    13  	"github.com/hugorut/terraform/src/providers"
    14  	"github.com/hugorut/terraform/src/provisioners"
    15  	"github.com/hugorut/terraform/src/states"
    16  	"github.com/hugorut/terraform/src/tfdiags"
    17  )
    18  
    19  func TestContext2Validate_badCount(t *testing.T) {
    20  	p := testProvider("aws")
    21  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
    22  		ResourceTypes: map[string]*configschema.Block{
    23  			"aws_instance": {
    24  				Attributes: map[string]*configschema.Attribute{},
    25  			},
    26  		},
    27  	})
    28  
    29  	m := testModule(t, "validate-bad-count")
    30  	c := testContext2(t, &ContextOpts{
    31  		Providers: map[addrs.Provider]providers.Factory{
    32  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
    33  		},
    34  	})
    35  
    36  	diags := c.Validate(m)
    37  	if !diags.HasErrors() {
    38  		t.Fatalf("succeeded; want error")
    39  	}
    40  }
    41  
    42  func TestContext2Validate_badResource_reference(t *testing.T) {
    43  	p := testProvider("aws")
    44  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
    45  		ResourceTypes: map[string]*configschema.Block{
    46  			"aws_instance": {
    47  				Attributes: map[string]*configschema.Attribute{},
    48  			},
    49  		},
    50  	})
    51  
    52  	m := testModule(t, "validate-bad-resource-count")
    53  	c := testContext2(t, &ContextOpts{
    54  		Providers: map[addrs.Provider]providers.Factory{
    55  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
    56  		},
    57  	})
    58  
    59  	diags := c.Validate(m)
    60  	if !diags.HasErrors() {
    61  		t.Fatalf("succeeded; want error")
    62  	}
    63  }
    64  
    65  func TestContext2Validate_badVar(t *testing.T) {
    66  	p := testProvider("aws")
    67  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
    68  		ResourceTypes: map[string]*configschema.Block{
    69  			"aws_instance": {
    70  				Attributes: map[string]*configschema.Attribute{
    71  					"foo": {Type: cty.String, Optional: true},
    72  					"num": {Type: cty.String, Optional: true},
    73  				},
    74  			},
    75  		},
    76  	})
    77  
    78  	m := testModule(t, "validate-bad-var")
    79  	c := testContext2(t, &ContextOpts{
    80  		Providers: map[addrs.Provider]providers.Factory{
    81  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
    82  		},
    83  	})
    84  
    85  	diags := c.Validate(m)
    86  	if !diags.HasErrors() {
    87  		t.Fatalf("succeeded; want error")
    88  	}
    89  }
    90  
    91  func TestContext2Validate_varNoDefaultExplicitType(t *testing.T) {
    92  	m := testModule(t, "validate-var-no-default-explicit-type")
    93  	c, diags := NewContext(&ContextOpts{})
    94  	if diags.HasErrors() {
    95  		t.Fatalf("unexpected NewContext errors: %s", diags.Err())
    96  	}
    97  
    98  	// NOTE: This test has grown idiosyncratic because originally Terraform
    99  	// would (optionally) check variables during validation, and then in
   100  	// Terraform v0.12 we switched to checking variables during NewContext,
   101  	// and now most recently we've switched to checking variables only during
   102  	// planning because root variables are a plan option. Therefore this has
   103  	// grown into a plan test rather than a validate test, but it lives on
   104  	// here in order to make it easier to navigate through that history in
   105  	// version control.
   106  	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
   107  	if !diags.HasErrors() {
   108  		// Error should be: The input variable "maybe_a_map" has not been assigned a value.
   109  		t.Fatalf("succeeded; want error")
   110  	}
   111  }
   112  
   113  func TestContext2Validate_computedVar(t *testing.T) {
   114  	p := testProvider("aws")
   115  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   116  		Provider: providers.Schema{
   117  			Block: &configschema.Block{
   118  				Attributes: map[string]*configschema.Attribute{
   119  					"value": {Type: cty.String, Optional: true},
   120  				},
   121  			},
   122  		},
   123  		ResourceTypes: map[string]providers.Schema{
   124  			"aws_instance": {
   125  				Block: &configschema.Block{
   126  					Attributes: map[string]*configschema.Attribute{},
   127  				},
   128  			},
   129  		},
   130  	}
   131  	pt := testProvider("test")
   132  	pt.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   133  		ResourceTypes: map[string]providers.Schema{
   134  			"test_instance": {
   135  				Block: &configschema.Block{
   136  					Attributes: map[string]*configschema.Attribute{
   137  						"id":    {Type: cty.String, Computed: true},
   138  						"value": {Type: cty.String, Optional: true},
   139  					},
   140  				},
   141  			},
   142  		},
   143  	}
   144  
   145  	m := testModule(t, "validate-computed-var")
   146  	c := testContext2(t, &ContextOpts{
   147  		Providers: map[addrs.Provider]providers.Factory{
   148  			addrs.NewDefaultProvider("aws"):  testProviderFuncFixed(p),
   149  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(pt),
   150  		},
   151  	})
   152  
   153  	p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
   154  		val := req.Config.GetAttr("value")
   155  		if val.IsKnown() {
   156  			resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("value isn't computed"))
   157  		}
   158  
   159  		return
   160  	}
   161  
   162  	diags := c.Validate(m)
   163  	if diags.HasErrors() {
   164  		t.Fatalf("unexpected error: %s", diags.Err())
   165  	}
   166  	if p.ConfigureProviderCalled {
   167  		t.Fatal("Configure should not be called for provider")
   168  	}
   169  }
   170  
   171  func TestContext2Validate_computedInFunction(t *testing.T) {
   172  	p := testProvider("aws")
   173  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   174  		ResourceTypes: map[string]providers.Schema{
   175  			"aws_instance": {
   176  				Block: &configschema.Block{
   177  					Attributes: map[string]*configschema.Attribute{
   178  						"attr": {Type: cty.Number, Optional: true},
   179  					},
   180  				},
   181  			},
   182  		},
   183  		DataSources: map[string]providers.Schema{
   184  			"aws_data_source": {
   185  				Block: &configschema.Block{
   186  					Attributes: map[string]*configschema.Attribute{
   187  						"optional_attr": {Type: cty.String, Optional: true},
   188  						"computed":      {Type: cty.String, Computed: true},
   189  					},
   190  				},
   191  			},
   192  		},
   193  	}
   194  
   195  	m := testModule(t, "validate-computed-in-function")
   196  	c := testContext2(t, &ContextOpts{
   197  		Providers: map[addrs.Provider]providers.Factory{
   198  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   199  		},
   200  	})
   201  
   202  	diags := c.Validate(m)
   203  	if diags.HasErrors() {
   204  		t.Fatalf("unexpected error: %s", diags.Err())
   205  	}
   206  }
   207  
   208  // Test that validate allows through computed counts. We do this and allow
   209  // them to fail during "plan" since we can't know if the computed values
   210  // can be realized during a plan.
   211  func TestContext2Validate_countComputed(t *testing.T) {
   212  	p := testProvider("aws")
   213  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   214  		ResourceTypes: map[string]providers.Schema{
   215  			"aws_instance": {
   216  				Block: &configschema.Block{
   217  					Attributes: map[string]*configschema.Attribute{},
   218  				},
   219  			},
   220  		},
   221  		DataSources: map[string]providers.Schema{
   222  			"aws_data_source": {
   223  				Block: &configschema.Block{
   224  					Attributes: map[string]*configschema.Attribute{
   225  						"compute": {Type: cty.String, Optional: true},
   226  						"value":   {Type: cty.String, Computed: true},
   227  					},
   228  				},
   229  			},
   230  		},
   231  	}
   232  
   233  	m := testModule(t, "validate-count-computed")
   234  	c := testContext2(t, &ContextOpts{
   235  		Providers: map[addrs.Provider]providers.Factory{
   236  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   237  		},
   238  	})
   239  
   240  	diags := c.Validate(m)
   241  	if diags.HasErrors() {
   242  		t.Fatalf("unexpected error: %s", diags.Err())
   243  	}
   244  }
   245  
   246  func TestContext2Validate_countNegative(t *testing.T) {
   247  	p := testProvider("aws")
   248  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   249  		ResourceTypes: map[string]providers.Schema{
   250  			"aws_instance": {
   251  				Block: &configschema.Block{
   252  					Attributes: map[string]*configschema.Attribute{},
   253  				},
   254  			},
   255  		},
   256  	}
   257  	m := testModule(t, "validate-count-negative")
   258  	c := testContext2(t, &ContextOpts{
   259  		Providers: map[addrs.Provider]providers.Factory{
   260  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   261  		},
   262  	})
   263  
   264  	diags := c.Validate(m)
   265  	if !diags.HasErrors() {
   266  		t.Fatalf("succeeded; want error")
   267  	}
   268  }
   269  
   270  func TestContext2Validate_countVariable(t *testing.T) {
   271  	p := testProvider("aws")
   272  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   273  		ResourceTypes: map[string]providers.Schema{
   274  			"aws_instance": {
   275  				Block: &configschema.Block{
   276  					Attributes: map[string]*configschema.Attribute{
   277  						"foo": {Type: cty.String, Optional: true},
   278  					},
   279  				},
   280  			},
   281  		},
   282  	}
   283  	m := testModule(t, "apply-count-variable")
   284  	c := testContext2(t, &ContextOpts{
   285  		Providers: map[addrs.Provider]providers.Factory{
   286  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   287  		},
   288  	})
   289  
   290  	diags := c.Validate(m)
   291  	if diags.HasErrors() {
   292  		t.Fatalf("unexpected error: %s", diags.Err())
   293  	}
   294  }
   295  
   296  func TestContext2Validate_countVariableNoDefault(t *testing.T) {
   297  	p := testProvider("aws")
   298  	m := testModule(t, "validate-count-variable")
   299  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   300  		ResourceTypes: map[string]providers.Schema{
   301  			"aws_instance": {
   302  				Block: &configschema.Block{
   303  					Attributes: map[string]*configschema.Attribute{
   304  						"foo": {Type: cty.String, Optional: true},
   305  					},
   306  				},
   307  			},
   308  		},
   309  	}
   310  	c, diags := NewContext(&ContextOpts{
   311  		Providers: map[addrs.Provider]providers.Factory{
   312  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   313  		},
   314  	})
   315  	assertNoDiagnostics(t, diags)
   316  
   317  	_, diags = c.Plan(m, nil, &PlanOpts{})
   318  	if !diags.HasErrors() {
   319  		// Error should be: The input variable "foo" has not been assigned a value.
   320  		t.Fatalf("succeeded; want error")
   321  	}
   322  }
   323  
   324  func TestContext2Validate_moduleBadOutput(t *testing.T) {
   325  	p := testProvider("aws")
   326  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   327  		ResourceTypes: map[string]providers.Schema{
   328  			"aws_instance": {
   329  				Block: &configschema.Block{
   330  					Attributes: map[string]*configschema.Attribute{
   331  						"foo": {Type: cty.String, Optional: true},
   332  					},
   333  				},
   334  			},
   335  		},
   336  	}
   337  	m := testModule(t, "validate-bad-module-output")
   338  	c := testContext2(t, &ContextOpts{
   339  		Providers: map[addrs.Provider]providers.Factory{
   340  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   341  		},
   342  	})
   343  
   344  	diags := c.Validate(m)
   345  	if !diags.HasErrors() {
   346  		t.Fatalf("succeeded; want error")
   347  	}
   348  }
   349  
   350  func TestContext2Validate_moduleGood(t *testing.T) {
   351  	p := testProvider("aws")
   352  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   353  		ResourceTypes: map[string]providers.Schema{
   354  			"aws_instance": {
   355  				Block: &configschema.Block{
   356  					Attributes: map[string]*configschema.Attribute{
   357  						"foo": {Type: cty.String, Optional: true},
   358  					},
   359  				},
   360  			},
   361  		},
   362  	}
   363  	m := testModule(t, "validate-good-module")
   364  	c := testContext2(t, &ContextOpts{
   365  		Providers: map[addrs.Provider]providers.Factory{
   366  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   367  		},
   368  	})
   369  
   370  	diags := c.Validate(m)
   371  	if diags.HasErrors() {
   372  		t.Fatalf("unexpected error: %s", diags.Err())
   373  	}
   374  }
   375  
   376  func TestContext2Validate_moduleBadResource(t *testing.T) {
   377  	m := testModule(t, "validate-module-bad-rc")
   378  	p := testProvider("aws")
   379  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   380  		ResourceTypes: map[string]providers.Schema{
   381  			"aws_instance": {
   382  				Block: &configschema.Block{
   383  					Attributes: map[string]*configschema.Attribute{},
   384  				},
   385  			},
   386  		},
   387  	}
   388  
   389  	c := testContext2(t, &ContextOpts{
   390  		Providers: map[addrs.Provider]providers.Factory{
   391  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   392  		},
   393  	})
   394  
   395  	p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{
   396  		Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
   397  	}
   398  
   399  	diags := c.Validate(m)
   400  	if !diags.HasErrors() {
   401  		t.Fatalf("succeeded; want error")
   402  	}
   403  }
   404  
   405  func TestContext2Validate_moduleDepsShouldNotCycle(t *testing.T) {
   406  	m := testModule(t, "validate-module-deps-cycle")
   407  	p := testProvider("aws")
   408  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   409  		ResourceTypes: map[string]providers.Schema{
   410  			"aws_instance": {
   411  				Block: &configschema.Block{
   412  					Attributes: map[string]*configschema.Attribute{
   413  						"id": {Type: cty.String, Optional: true},
   414  					},
   415  				},
   416  			},
   417  		},
   418  	}
   419  
   420  	ctx := testContext2(t, &ContextOpts{
   421  		Providers: map[addrs.Provider]providers.Factory{
   422  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   423  		},
   424  	})
   425  
   426  	diags := ctx.Validate(m)
   427  	if diags.HasErrors() {
   428  		t.Fatalf("unexpected error: %s", diags.Err())
   429  	}
   430  }
   431  
   432  func TestContext2Validate_moduleProviderVar(t *testing.T) {
   433  	m := testModule(t, "validate-module-pc-vars")
   434  	p := testProvider("aws")
   435  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   436  		Provider: providers.Schema{
   437  			Block: &configschema.Block{
   438  				Attributes: map[string]*configschema.Attribute{
   439  					"foo": {Type: cty.String, Optional: true},
   440  				},
   441  			},
   442  		},
   443  		ResourceTypes: map[string]providers.Schema{
   444  			"aws_instance": {
   445  				Block: &configschema.Block{
   446  					Attributes: map[string]*configschema.Attribute{
   447  						"foo": {Type: cty.String, Optional: true},
   448  					},
   449  				},
   450  			},
   451  		},
   452  	}
   453  
   454  	c := testContext2(t, &ContextOpts{
   455  		Providers: map[addrs.Provider]providers.Factory{
   456  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   457  		},
   458  	})
   459  
   460  	p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
   461  		if req.Config.GetAttr("foo").IsNull() {
   462  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo is null"))
   463  		}
   464  		return
   465  	}
   466  
   467  	diags := c.Validate(m)
   468  	if diags.HasErrors() {
   469  		t.Fatalf("unexpected error: %s", diags.Err())
   470  	}
   471  }
   472  
   473  func TestContext2Validate_moduleProviderInheritUnused(t *testing.T) {
   474  	m := testModule(t, "validate-module-pc-inherit-unused")
   475  	p := testProvider("aws")
   476  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   477  		Provider: providers.Schema{
   478  			Block: &configschema.Block{
   479  				Attributes: map[string]*configschema.Attribute{
   480  					"foo": {Type: cty.String, Optional: true},
   481  				},
   482  			},
   483  		},
   484  		ResourceTypes: map[string]providers.Schema{
   485  			"aws_instance": {
   486  				Block: &configschema.Block{
   487  					Attributes: map[string]*configschema.Attribute{
   488  						"foo": {Type: cty.String, Optional: true},
   489  					},
   490  				},
   491  			},
   492  		},
   493  	}
   494  
   495  	c := testContext2(t, &ContextOpts{
   496  		Providers: map[addrs.Provider]providers.Factory{
   497  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   498  		},
   499  	})
   500  
   501  	p.ValidateProviderConfigFn = func(req providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) {
   502  		if req.Config.GetAttr("foo").IsNull() {
   503  			resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo is null"))
   504  		}
   505  		return
   506  	}
   507  
   508  	diags := c.Validate(m)
   509  	if diags.HasErrors() {
   510  		t.Fatalf("unexpected error: %s", diags.Err())
   511  	}
   512  }
   513  
   514  func TestContext2Validate_orphans(t *testing.T) {
   515  	p := testProvider("aws")
   516  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   517  		ResourceTypes: map[string]providers.Schema{
   518  			"aws_instance": {
   519  				Block: &configschema.Block{
   520  					Attributes: map[string]*configschema.Attribute{
   521  						"foo": {Type: cty.String, Optional: true},
   522  						"num": {Type: cty.String, Optional: true},
   523  					},
   524  				},
   525  			},
   526  		},
   527  	}
   528  
   529  	m := testModule(t, "validate-good")
   530  
   531  	c := testContext2(t, &ContextOpts{
   532  		Providers: map[addrs.Provider]providers.Factory{
   533  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   534  		},
   535  	})
   536  
   537  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
   538  		var diags tfdiags.Diagnostics
   539  		if req.Config.GetAttr("foo").IsNull() {
   540  			diags = diags.Append(errors.New("foo is not set"))
   541  		}
   542  		return providers.ValidateResourceConfigResponse{
   543  			Diagnostics: diags,
   544  		}
   545  	}
   546  
   547  	diags := c.Validate(m)
   548  	if diags.HasErrors() {
   549  		t.Fatalf("unexpected error: %s", diags.Err())
   550  	}
   551  }
   552  
   553  func TestContext2Validate_providerConfig_bad(t *testing.T) {
   554  	m := testModule(t, "validate-bad-pc")
   555  	p := testProvider("aws")
   556  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   557  		Provider: providers.Schema{
   558  			Block: &configschema.Block{
   559  				Attributes: map[string]*configschema.Attribute{
   560  					"foo": {Type: cty.String, Optional: true},
   561  				},
   562  			},
   563  		},
   564  		ResourceTypes: map[string]providers.Schema{
   565  			"aws_instance": {
   566  				Block: &configschema.Block{
   567  					Attributes: map[string]*configschema.Attribute{},
   568  				},
   569  			},
   570  		},
   571  	}
   572  
   573  	c := testContext2(t, &ContextOpts{
   574  		Providers: map[addrs.Provider]providers.Factory{
   575  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   576  		},
   577  	})
   578  
   579  	p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{
   580  		Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
   581  	}
   582  
   583  	diags := c.Validate(m)
   584  	if len(diags) != 1 {
   585  		t.Fatalf("wrong number of diagnostics %d; want %d", len(diags), 1)
   586  	}
   587  	if !strings.Contains(diags.Err().Error(), "bad") {
   588  		t.Fatalf("bad: %s", diags.Err().Error())
   589  	}
   590  }
   591  
   592  func TestContext2Validate_providerConfig_skippedEmpty(t *testing.T) {
   593  	m := testModule(t, "validate-skipped-pc-empty")
   594  	p := testProvider("aws")
   595  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   596  		Provider: providers.Schema{
   597  			Block: &configschema.Block{
   598  				Attributes: map[string]*configschema.Attribute{
   599  					"foo": {Type: cty.String, Optional: true},
   600  				},
   601  			},
   602  		},
   603  		ResourceTypes: map[string]providers.Schema{
   604  			"aws_instance": {
   605  				Block: &configschema.Block{
   606  					Attributes: map[string]*configschema.Attribute{},
   607  				},
   608  			},
   609  		},
   610  	}
   611  
   612  	c := testContext2(t, &ContextOpts{
   613  		Providers: map[addrs.Provider]providers.Factory{
   614  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   615  		},
   616  	})
   617  
   618  	p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{
   619  		Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("should not be called")),
   620  	}
   621  
   622  	diags := c.Validate(m)
   623  	if diags.HasErrors() {
   624  		t.Fatalf("unexpected error: %s", diags.Err())
   625  	}
   626  }
   627  
   628  func TestContext2Validate_providerConfig_good(t *testing.T) {
   629  	m := testModule(t, "validate-bad-pc")
   630  	p := testProvider("aws")
   631  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   632  		Provider: providers.Schema{
   633  			Block: &configschema.Block{
   634  				Attributes: map[string]*configschema.Attribute{
   635  					"foo": {Type: cty.String, Optional: true},
   636  				},
   637  			},
   638  		},
   639  		ResourceTypes: map[string]providers.Schema{
   640  			"aws_instance": {
   641  				Block: &configschema.Block{
   642  					Attributes: map[string]*configschema.Attribute{},
   643  				},
   644  			},
   645  		},
   646  	}
   647  
   648  	c := testContext2(t, &ContextOpts{
   649  		Providers: map[addrs.Provider]providers.Factory{
   650  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   651  		},
   652  	})
   653  
   654  	diags := c.Validate(m)
   655  	if diags.HasErrors() {
   656  		t.Fatalf("unexpected error: %s", diags.Err())
   657  	}
   658  }
   659  
   660  // In this test there is a mismatch between the provider's fqn (hashicorp/test)
   661  // and it's local name set in required_providers (arbitrary).
   662  func TestContext2Validate_requiredProviderConfig(t *testing.T) {
   663  	m := testModule(t, "validate-required-provider-config")
   664  	p := testProvider("aws")
   665  
   666  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   667  		Provider: providers.Schema{
   668  			Block: &configschema.Block{
   669  				Attributes: map[string]*configschema.Attribute{
   670  					"required_attribute": {Type: cty.String, Required: true},
   671  				},
   672  			},
   673  		},
   674  		ResourceTypes: map[string]providers.Schema{
   675  			"aws_instance": {
   676  				Block: &configschema.Block{
   677  					Attributes: map[string]*configschema.Attribute{},
   678  				},
   679  			},
   680  		},
   681  	}
   682  
   683  	c := testContext2(t, &ContextOpts{
   684  		Providers: map[addrs.Provider]providers.Factory{
   685  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   686  		},
   687  	})
   688  
   689  	diags := c.Validate(m)
   690  	if diags.HasErrors() {
   691  		t.Fatalf("unexpected error: %s", diags.Err())
   692  	}
   693  }
   694  
   695  func TestContext2Validate_provisionerConfig_bad(t *testing.T) {
   696  	m := testModule(t, "validate-bad-prov-conf")
   697  	p := testProvider("aws")
   698  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   699  		ResourceTypes: map[string]providers.Schema{
   700  			"aws_instance": {
   701  				Block: &configschema.Block{
   702  					Attributes: map[string]*configschema.Attribute{
   703  						"foo": {Type: cty.String, Optional: true},
   704  					},
   705  				},
   706  			},
   707  		},
   708  	}
   709  
   710  	pr := simpleMockProvisioner()
   711  
   712  	c := testContext2(t, &ContextOpts{
   713  		Providers: map[addrs.Provider]providers.Factory{
   714  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   715  		},
   716  		Provisioners: map[string]provisioners.Factory{
   717  			"shell": testProvisionerFuncFixed(pr),
   718  		},
   719  	})
   720  
   721  	p.ValidateProviderConfigResponse = &providers.ValidateProviderConfigResponse{
   722  		Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
   723  	}
   724  
   725  	diags := c.Validate(m)
   726  	if !diags.HasErrors() {
   727  		t.Fatalf("succeeded; want error")
   728  	}
   729  }
   730  
   731  func TestContext2Validate_badResourceConnection(t *testing.T) {
   732  	m := testModule(t, "validate-bad-resource-connection")
   733  	p := testProvider("aws")
   734  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   735  		ResourceTypes: map[string]providers.Schema{
   736  			"aws_instance": {
   737  				Block: &configschema.Block{
   738  					Attributes: map[string]*configschema.Attribute{
   739  						"foo": {Type: cty.String, Optional: true},
   740  					},
   741  				},
   742  			},
   743  		},
   744  	}
   745  
   746  	pr := simpleMockProvisioner()
   747  
   748  	c := testContext2(t, &ContextOpts{
   749  		Providers: map[addrs.Provider]providers.Factory{
   750  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   751  		},
   752  		Provisioners: map[string]provisioners.Factory{
   753  			"shell": testProvisionerFuncFixed(pr),
   754  		},
   755  	})
   756  
   757  	diags := c.Validate(m)
   758  	t.Log(diags.Err())
   759  	if !diags.HasErrors() {
   760  		t.Fatalf("succeeded; want error")
   761  	}
   762  }
   763  
   764  func TestContext2Validate_badProvisionerConnection(t *testing.T) {
   765  	m := testModule(t, "validate-bad-prov-connection")
   766  	p := testProvider("aws")
   767  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   768  		ResourceTypes: map[string]providers.Schema{
   769  			"aws_instance": {
   770  				Block: &configschema.Block{
   771  					Attributes: map[string]*configschema.Attribute{
   772  						"foo": {Type: cty.String, Optional: true},
   773  					},
   774  				},
   775  			},
   776  		},
   777  	}
   778  
   779  	pr := simpleMockProvisioner()
   780  
   781  	c := testContext2(t, &ContextOpts{
   782  		Providers: map[addrs.Provider]providers.Factory{
   783  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   784  		},
   785  		Provisioners: map[string]provisioners.Factory{
   786  			"shell": testProvisionerFuncFixed(pr),
   787  		},
   788  	})
   789  
   790  	diags := c.Validate(m)
   791  	t.Log(diags.Err())
   792  	if !diags.HasErrors() {
   793  		t.Fatalf("succeeded; want error")
   794  	}
   795  }
   796  
   797  func TestContext2Validate_provisionerConfig_good(t *testing.T) {
   798  	m := testModule(t, "validate-bad-prov-conf")
   799  	p := testProvider("aws")
   800  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   801  		Provider: providers.Schema{
   802  			Block: &configschema.Block{
   803  				Attributes: map[string]*configschema.Attribute{
   804  					"foo": {Type: cty.String, Optional: true},
   805  				},
   806  			},
   807  		},
   808  		ResourceTypes: map[string]providers.Schema{
   809  			"aws_instance": {
   810  				Block: &configschema.Block{
   811  					Attributes: map[string]*configschema.Attribute{
   812  						"foo": {Type: cty.String, Optional: true},
   813  					},
   814  				},
   815  			},
   816  		},
   817  	}
   818  
   819  	pr := simpleMockProvisioner()
   820  	pr.ValidateProvisionerConfigFn = func(req provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse {
   821  		var diags tfdiags.Diagnostics
   822  		if req.Config.GetAttr("test_string").IsNull() {
   823  			diags = diags.Append(errors.New("test_string is not set"))
   824  		}
   825  		return provisioners.ValidateProvisionerConfigResponse{
   826  			Diagnostics: diags,
   827  		}
   828  	}
   829  
   830  	c := testContext2(t, &ContextOpts{
   831  		Providers: map[addrs.Provider]providers.Factory{
   832  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   833  		},
   834  		Provisioners: map[string]provisioners.Factory{
   835  			"shell": testProvisionerFuncFixed(pr),
   836  		},
   837  	})
   838  
   839  	diags := c.Validate(m)
   840  	if diags.HasErrors() {
   841  		t.Fatalf("unexpected error: %s", diags.Err())
   842  	}
   843  }
   844  
   845  func TestContext2Validate_requiredVar(t *testing.T) {
   846  	m := testModule(t, "validate-required-var")
   847  	p := testProvider("aws")
   848  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   849  		ResourceTypes: map[string]providers.Schema{
   850  			"aws_instance": {
   851  				Block: &configschema.Block{
   852  					Attributes: map[string]*configschema.Attribute{
   853  						"ami": {Type: cty.String, Optional: true},
   854  					},
   855  				},
   856  			},
   857  		},
   858  	}
   859  	c, diags := NewContext(&ContextOpts{
   860  		Providers: map[addrs.Provider]providers.Factory{
   861  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   862  		},
   863  	})
   864  	assertNoDiagnostics(t, diags)
   865  
   866  	// NOTE: This test has grown idiosyncratic because originally Terraform
   867  	// would (optionally) check variables during validation, and then in
   868  	// Terraform v0.12 we switched to checking variables during NewContext,
   869  	// and now most recently we've switched to checking variables only during
   870  	// planning because root variables are a plan option. Therefore this has
   871  	// grown into a plan test rather than a validate test, but it lives on
   872  	// here in order to make it easier to navigate through that history in
   873  	// version control.
   874  	_, diags = c.Plan(m, states.NewState(), DefaultPlanOpts)
   875  	if !diags.HasErrors() {
   876  		// Error should be: The input variable "foo" has not been assigned a value.
   877  		t.Fatalf("succeeded; want error")
   878  	}
   879  }
   880  
   881  func TestContext2Validate_resourceConfig_bad(t *testing.T) {
   882  	m := testModule(t, "validate-bad-rc")
   883  	p := testProvider("aws")
   884  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   885  		ResourceTypes: map[string]providers.Schema{
   886  			"aws_instance": {
   887  				Block: &configschema.Block{
   888  					Attributes: map[string]*configschema.Attribute{
   889  						"foo": {Type: cty.String, Optional: true},
   890  					},
   891  				},
   892  			},
   893  		},
   894  	}
   895  	c := testContext2(t, &ContextOpts{
   896  		Providers: map[addrs.Provider]providers.Factory{
   897  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   898  		},
   899  	})
   900  
   901  	p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{
   902  		Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
   903  	}
   904  
   905  	diags := c.Validate(m)
   906  	if !diags.HasErrors() {
   907  		t.Fatalf("succeeded; want error")
   908  	}
   909  }
   910  
   911  func TestContext2Validate_resourceConfig_good(t *testing.T) {
   912  	m := testModule(t, "validate-bad-rc")
   913  	p := testProvider("aws")
   914  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   915  		ResourceTypes: map[string]providers.Schema{
   916  			"aws_instance": {
   917  				Block: &configschema.Block{
   918  					Attributes: map[string]*configschema.Attribute{
   919  						"foo": {Type: cty.String, Optional: true},
   920  					},
   921  				},
   922  			},
   923  		},
   924  	}
   925  	c := testContext2(t, &ContextOpts{
   926  		Providers: map[addrs.Provider]providers.Factory{
   927  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   928  		},
   929  	})
   930  
   931  	diags := c.Validate(m)
   932  	if diags.HasErrors() {
   933  		t.Fatalf("unexpected error: %s", diags.Err())
   934  	}
   935  }
   936  
   937  func TestContext2Validate_tainted(t *testing.T) {
   938  	p := testProvider("aws")
   939  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   940  		ResourceTypes: map[string]providers.Schema{
   941  			"aws_instance": {
   942  				Block: &configschema.Block{
   943  					Attributes: map[string]*configschema.Attribute{
   944  						"foo": {Type: cty.String, Optional: true},
   945  						"num": {Type: cty.String, Optional: true},
   946  					},
   947  				},
   948  			},
   949  		},
   950  	}
   951  
   952  	m := testModule(t, "validate-good")
   953  	c := testContext2(t, &ContextOpts{
   954  		Providers: map[addrs.Provider]providers.Factory{
   955  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
   956  		},
   957  	})
   958  
   959  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
   960  		var diags tfdiags.Diagnostics
   961  		if req.Config.GetAttr("foo").IsNull() {
   962  			diags = diags.Append(errors.New("foo is not set"))
   963  		}
   964  		return providers.ValidateResourceConfigResponse{
   965  			Diagnostics: diags,
   966  		}
   967  	}
   968  
   969  	diags := c.Validate(m)
   970  	if diags.HasErrors() {
   971  		t.Fatalf("unexpected error: %s", diags.Err())
   972  	}
   973  }
   974  
   975  func TestContext2Validate_targetedDestroy(t *testing.T) {
   976  	m := testModule(t, "validate-targeted")
   977  	p := testProvider("aws")
   978  	pr := simpleMockProvisioner()
   979  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
   980  		ResourceTypes: map[string]providers.Schema{
   981  			"aws_instance": {
   982  				Block: &configschema.Block{
   983  					Attributes: map[string]*configschema.Attribute{
   984  						"foo": {Type: cty.String, Optional: true},
   985  						"num": {Type: cty.String, Optional: true},
   986  					},
   987  				},
   988  			},
   989  		},
   990  	}
   991  
   992  	state := states.NewState()
   993  	root := state.EnsureModule(addrs.RootModuleInstance)
   994  	testSetResourceInstanceCurrent(root, "aws_instance.foo", `{"id":"i-bcd345"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   995  	testSetResourceInstanceCurrent(root, "aws_instance.bar", `{"id":"i-abc123"}`, `provider["registry.terraform.io/hashicorp/aws"]`)
   996  
   997  	ctx := testContext2(t, &ContextOpts{
   998  		Providers: map[addrs.Provider]providers.Factory{
   999  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1000  		},
  1001  		Provisioners: map[string]provisioners.Factory{
  1002  			"shell": testProvisionerFuncFixed(pr),
  1003  		},
  1004  	})
  1005  
  1006  	diags := ctx.Validate(m)
  1007  	if diags.HasErrors() {
  1008  		t.Fatalf("unexpected error: %s", diags.Err())
  1009  	}
  1010  }
  1011  
  1012  func TestContext2Validate_varRefUnknown(t *testing.T) {
  1013  	m := testModule(t, "validate-variable-ref")
  1014  	p := testProvider("aws")
  1015  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1016  		ResourceTypes: map[string]providers.Schema{
  1017  			"aws_instance": {
  1018  				Block: &configschema.Block{
  1019  					Attributes: map[string]*configschema.Attribute{
  1020  						"foo": {Type: cty.String, Optional: true},
  1021  					},
  1022  				},
  1023  			},
  1024  		},
  1025  	}
  1026  	c := testContext2(t, &ContextOpts{
  1027  		Providers: map[addrs.Provider]providers.Factory{
  1028  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1029  		},
  1030  	})
  1031  
  1032  	var value cty.Value
  1033  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
  1034  		value = req.Config.GetAttr("foo")
  1035  		return providers.ValidateResourceConfigResponse{}
  1036  	}
  1037  
  1038  	c.Validate(m)
  1039  
  1040  	// Input variables are always unknown during the validate walk, because
  1041  	// we're checking for validity of all possible input values. Validity
  1042  	// against specific input values is checked during the plan walk.
  1043  	if !value.RawEquals(cty.UnknownVal(cty.String)) {
  1044  		t.Fatalf("bad: %#v", value)
  1045  	}
  1046  }
  1047  
  1048  // Module variables weren't being interpolated during Validate phase.
  1049  // related to https://github.com/hugorut/terraform/issues/5322
  1050  func TestContext2Validate_interpolateVar(t *testing.T) {
  1051  	input := new(MockUIInput)
  1052  
  1053  	m := testModule(t, "input-interpolate-var")
  1054  	p := testProvider("null")
  1055  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1056  		ResourceTypes: map[string]providers.Schema{
  1057  			"template_file": {
  1058  				Block: &configschema.Block{
  1059  					Attributes: map[string]*configschema.Attribute{
  1060  						"template": {Type: cty.String, Optional: true},
  1061  					},
  1062  				},
  1063  			},
  1064  		},
  1065  	}
  1066  
  1067  	ctx := testContext2(t, &ContextOpts{
  1068  		Providers: map[addrs.Provider]providers.Factory{
  1069  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  1070  		},
  1071  		UIInput: input,
  1072  	})
  1073  
  1074  	diags := ctx.Validate(m)
  1075  	if diags.HasErrors() {
  1076  		t.Fatalf("unexpected error: %s", diags.Err())
  1077  	}
  1078  }
  1079  
  1080  // When module vars reference something that is actually computed, this
  1081  // shouldn't cause validation to fail.
  1082  func TestContext2Validate_interpolateComputedModuleVarDef(t *testing.T) {
  1083  	input := new(MockUIInput)
  1084  
  1085  	m := testModule(t, "validate-computed-module-var-ref")
  1086  	p := testProvider("aws")
  1087  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1088  		ResourceTypes: map[string]providers.Schema{
  1089  			"aws_instance": {
  1090  				Block: &configschema.Block{
  1091  					Attributes: map[string]*configschema.Attribute{
  1092  						"attr": {Type: cty.String, Optional: true},
  1093  					},
  1094  				},
  1095  			},
  1096  		},
  1097  	}
  1098  
  1099  	ctx := testContext2(t, &ContextOpts{
  1100  		Providers: map[addrs.Provider]providers.Factory{
  1101  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1102  		},
  1103  		UIInput: input,
  1104  	})
  1105  
  1106  	diags := ctx.Validate(m)
  1107  	if diags.HasErrors() {
  1108  		t.Fatalf("unexpected error: %s", diags.Err())
  1109  	}
  1110  }
  1111  
  1112  // Computed values are lost when a map is output from a module
  1113  func TestContext2Validate_interpolateMap(t *testing.T) {
  1114  	input := new(MockUIInput)
  1115  
  1116  	m := testModule(t, "issue-9549")
  1117  	p := testProvider("template")
  1118  
  1119  	ctx := testContext2(t, &ContextOpts{
  1120  		Providers: map[addrs.Provider]providers.Factory{
  1121  			addrs.NewDefaultProvider("template"): testProviderFuncFixed(p),
  1122  		},
  1123  		UIInput: input,
  1124  	})
  1125  
  1126  	diags := ctx.Validate(m)
  1127  	if diags.HasErrors() {
  1128  		t.Fatalf("unexpected error: %s", diags.Err())
  1129  	}
  1130  }
  1131  
  1132  func TestContext2Validate_varSensitive(t *testing.T) {
  1133  	// Smoke test through validate where a variable has sensitive applied
  1134  	m := testModuleInline(t, map[string]string{
  1135  		"main.tf": `
  1136  variable "foo" {
  1137    default = "xyz"
  1138    sensitive = true
  1139  }
  1140  
  1141  variable "bar" {
  1142    sensitive = true
  1143  }
  1144  
  1145  data "aws_data_source" "bar" {
  1146    foo = var.bar
  1147  }
  1148  
  1149  resource "aws_instance" "foo" {
  1150    foo = var.foo
  1151  }
  1152  `,
  1153  	})
  1154  
  1155  	p := testProvider("aws")
  1156  	p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
  1157  		// Providers receive unmarked values
  1158  		if got, want := req.Config.GetAttr("foo"), cty.UnknownVal(cty.String); !got.RawEquals(want) {
  1159  			t.Fatalf("wrong value for foo\ngot:  %#v\nwant: %#v", got, want)
  1160  		}
  1161  		return providers.ValidateResourceConfigResponse{}
  1162  	}
  1163  	p.ValidateDataResourceConfigFn = func(req providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) {
  1164  		if got, want := req.Config.GetAttr("foo"), cty.UnknownVal(cty.String); !got.RawEquals(want) {
  1165  			t.Fatalf("wrong value for foo\ngot:  %#v\nwant: %#v", got, want)
  1166  		}
  1167  		return providers.ValidateDataResourceConfigResponse{}
  1168  	}
  1169  
  1170  	ctx := testContext2(t, &ContextOpts{
  1171  		Providers: map[addrs.Provider]providers.Factory{
  1172  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1173  		},
  1174  	})
  1175  
  1176  	diags := ctx.Validate(m)
  1177  	if diags.HasErrors() {
  1178  		t.Fatal(diags.Err())
  1179  	}
  1180  
  1181  	if !p.ValidateResourceConfigCalled {
  1182  		t.Fatal("expected ValidateResourceConfigFn to be called")
  1183  	}
  1184  
  1185  	if !p.ValidateDataResourceConfigCalled {
  1186  		t.Fatal("expected ValidateDataSourceConfigFn to be called")
  1187  	}
  1188  }
  1189  
  1190  // Manually validate using the new PlanGraphBuilder
  1191  func TestContext2Validate_PlanGraphBuilder(t *testing.T) {
  1192  	fixture := contextFixtureApplyVars(t)
  1193  	opts := fixture.ContextOpts()
  1194  	c := testContext2(t, opts)
  1195  
  1196  	graph, diags := ValidateGraphBuilder(&PlanGraphBuilder{
  1197  		Config:  fixture.Config,
  1198  		State:   states.NewState(),
  1199  		Plugins: c.plugins,
  1200  	}).Build(addrs.RootModuleInstance)
  1201  	if diags.HasErrors() {
  1202  		t.Fatalf("errors from PlanGraphBuilder: %s", diags.Err())
  1203  	}
  1204  	defer c.acquireRun("validate-test")()
  1205  	walker, diags := c.walk(graph, walkValidate, &graphWalkOpts{
  1206  		Config: fixture.Config,
  1207  	})
  1208  	if diags.HasErrors() {
  1209  		t.Fatal(diags.Err())
  1210  	}
  1211  	if len(walker.NonFatalDiagnostics) > 0 {
  1212  		t.Fatal(walker.NonFatalDiagnostics.Err())
  1213  	}
  1214  }
  1215  
  1216  func TestContext2Validate_invalidOutput(t *testing.T) {
  1217  	m := testModuleInline(t, map[string]string{
  1218  		"main.tf": `
  1219  data "aws_data_source" "name" {}
  1220  
  1221  output "out" {
  1222    value = "${data.aws_data_source.name.missing}"
  1223  }`,
  1224  	})
  1225  
  1226  	p := testProvider("aws")
  1227  	ctx := testContext2(t, &ContextOpts{
  1228  		Providers: map[addrs.Provider]providers.Factory{
  1229  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1230  		},
  1231  	})
  1232  
  1233  	diags := ctx.Validate(m)
  1234  	if !diags.HasErrors() {
  1235  		t.Fatal("succeeded; want errors")
  1236  	}
  1237  	// Should get this error:
  1238  	// Unsupported attribute: This object does not have an attribute named "missing"
  1239  	if got, want := diags.Err().Error(), "Unsupported attribute"; !strings.Contains(got, want) {
  1240  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  1241  	}
  1242  }
  1243  
  1244  func TestContext2Validate_invalidModuleOutput(t *testing.T) {
  1245  	m := testModuleInline(t, map[string]string{
  1246  		"child/main.tf": `
  1247  data "aws_data_source" "name" {}
  1248  
  1249  output "out" {
  1250    value = "${data.aws_data_source.name.missing}"
  1251  }`,
  1252  		"main.tf": `
  1253  module "child" {
  1254    source = "./child"
  1255  }
  1256  
  1257  resource "aws_instance" "foo" {
  1258    foo = "${module.child.out}"
  1259  }`,
  1260  	})
  1261  
  1262  	p := testProvider("aws")
  1263  	ctx := testContext2(t, &ContextOpts{
  1264  		Providers: map[addrs.Provider]providers.Factory{
  1265  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1266  		},
  1267  	})
  1268  
  1269  	diags := ctx.Validate(m)
  1270  	if !diags.HasErrors() {
  1271  		t.Fatal("succeeded; want errors")
  1272  	}
  1273  	// Should get this error:
  1274  	// Unsupported attribute: This object does not have an attribute named "missing"
  1275  	if got, want := diags.Err().Error(), "Unsupported attribute"; !strings.Contains(got, want) {
  1276  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  1277  	}
  1278  }
  1279  
  1280  func TestContext2Validate_sensitiveRootModuleOutput(t *testing.T) {
  1281  	m := testModuleInline(t, map[string]string{
  1282  		"child/main.tf": `
  1283  variable "foo" {
  1284    default = "xyz"
  1285    sensitive = true
  1286  }
  1287  
  1288  output "out" {
  1289    value = var.foo
  1290  }`,
  1291  		"main.tf": `
  1292  module "child" {
  1293    source = "./child"
  1294  }
  1295  
  1296  output "root" {
  1297    value = module.child.out
  1298    sensitive = true
  1299  }`,
  1300  	})
  1301  
  1302  	ctx := testContext2(t, &ContextOpts{})
  1303  
  1304  	diags := ctx.Validate(m)
  1305  	if diags.HasErrors() {
  1306  		t.Fatal(diags.Err())
  1307  	}
  1308  }
  1309  
  1310  func TestContext2Validate_legacyResourceCount(t *testing.T) {
  1311  	m := testModuleInline(t, map[string]string{
  1312  		"main.tf": `
  1313  resource "aws_instance" "test" {}
  1314  
  1315  output "out" {
  1316    value = aws_instance.test.count
  1317  }`,
  1318  	})
  1319  
  1320  	p := testProvider("aws")
  1321  	ctx := testContext2(t, &ContextOpts{
  1322  		Providers: map[addrs.Provider]providers.Factory{
  1323  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1324  		},
  1325  	})
  1326  
  1327  	diags := ctx.Validate(m)
  1328  	if !diags.HasErrors() {
  1329  		t.Fatal("succeeded; want errors")
  1330  	}
  1331  	// Should get this error:
  1332  	// Invalid resource count attribute: The special "count" attribute is no longer supported after Terraform v0.12. Instead, use length(aws_instance.test) to count resource instances.
  1333  	if got, want := diags.Err().Error(), "Invalid resource count attribute:"; !strings.Contains(got, want) {
  1334  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  1335  	}
  1336  }
  1337  
  1338  func TestContext2Validate_invalidModuleRef(t *testing.T) {
  1339  	// This test is verifying that we properly validate and report on references
  1340  	// to modules that are not declared, since we were missing some validation
  1341  	// here in early 0.12.0 alphas that led to a panic.
  1342  	m := testModuleInline(t, map[string]string{
  1343  		"main.tf": `
  1344  output "out" {
  1345    # Intentionally referencing undeclared module to ensure error
  1346    value = module.foo
  1347  }`,
  1348  	})
  1349  
  1350  	p := testProvider("aws")
  1351  	ctx := testContext2(t, &ContextOpts{
  1352  		Providers: map[addrs.Provider]providers.Factory{
  1353  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1354  		},
  1355  	})
  1356  
  1357  	diags := ctx.Validate(m)
  1358  	if !diags.HasErrors() {
  1359  		t.Fatal("succeeded; want errors")
  1360  	}
  1361  	// Should get this error:
  1362  	// Reference to undeclared module: No module call named "foo" is declared in the root module.
  1363  	if got, want := diags.Err().Error(), "Reference to undeclared module:"; !strings.Contains(got, want) {
  1364  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  1365  	}
  1366  }
  1367  
  1368  func TestContext2Validate_invalidModuleOutputRef(t *testing.T) {
  1369  	// This test is verifying that we properly validate and report on references
  1370  	// to modules that are not declared, since we were missing some validation
  1371  	// here in early 0.12.0 alphas that led to a panic.
  1372  	m := testModuleInline(t, map[string]string{
  1373  		"main.tf": `
  1374  output "out" {
  1375    # Intentionally referencing undeclared module to ensure error
  1376    value = module.foo.bar
  1377  }`,
  1378  	})
  1379  
  1380  	p := testProvider("aws")
  1381  	ctx := testContext2(t, &ContextOpts{
  1382  		Providers: map[addrs.Provider]providers.Factory{
  1383  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1384  		},
  1385  	})
  1386  
  1387  	diags := ctx.Validate(m)
  1388  	if !diags.HasErrors() {
  1389  		t.Fatal("succeeded; want errors")
  1390  	}
  1391  	// Should get this error:
  1392  	// Reference to undeclared module: No module call named "foo" is declared in the root module.
  1393  	if got, want := diags.Err().Error(), "Reference to undeclared module:"; !strings.Contains(got, want) {
  1394  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  1395  	}
  1396  }
  1397  
  1398  func TestContext2Validate_invalidDependsOnResourceRef(t *testing.T) {
  1399  	// This test is verifying that we raise an error if depends_on
  1400  	// refers to something that doesn't exist in configuration.
  1401  	m := testModuleInline(t, map[string]string{
  1402  		"main.tf": `
  1403  resource "test_instance" "bar" {
  1404    depends_on = [test_resource.nonexistant]
  1405  }
  1406  `,
  1407  	})
  1408  
  1409  	p := testProvider("test")
  1410  	ctx := testContext2(t, &ContextOpts{
  1411  		Providers: map[addrs.Provider]providers.Factory{
  1412  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1413  		},
  1414  	})
  1415  
  1416  	diags := ctx.Validate(m)
  1417  	if !diags.HasErrors() {
  1418  		t.Fatal("succeeded; want errors")
  1419  	}
  1420  	// Should get this error:
  1421  	// Reference to undeclared module: No module call named "foo" is declared in the root module.
  1422  	if got, want := diags.Err().Error(), "Reference to undeclared resource:"; !strings.Contains(got, want) {
  1423  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  1424  	}
  1425  }
  1426  
  1427  func TestContext2Validate_invalidResourceIgnoreChanges(t *testing.T) {
  1428  	// This test is verifying that we raise an error if ignore_changes
  1429  	// refers to something that can be statically detected as not conforming
  1430  	// to the resource type schema.
  1431  	m := testModuleInline(t, map[string]string{
  1432  		"main.tf": `
  1433  resource "test_instance" "bar" {
  1434    lifecycle {
  1435      ignore_changes = [does_not_exist_in_schema]
  1436    }
  1437  }
  1438  `,
  1439  	})
  1440  
  1441  	p := testProvider("test")
  1442  	ctx := testContext2(t, &ContextOpts{
  1443  		Providers: map[addrs.Provider]providers.Factory{
  1444  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1445  		},
  1446  	})
  1447  
  1448  	diags := ctx.Validate(m)
  1449  	if !diags.HasErrors() {
  1450  		t.Fatal("succeeded; want errors")
  1451  	}
  1452  	// Should get this error:
  1453  	// Reference to undeclared module: No module call named "foo" is declared in the root module.
  1454  	if got, want := diags.Err().Error(), `no argument, nested block, or exported attribute named "does_not_exist_in_schema"`; !strings.Contains(got, want) {
  1455  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  1456  	}
  1457  }
  1458  
  1459  func TestContext2Validate_variableCustomValidationsFail(t *testing.T) {
  1460  	// This test is for custom validation rules associated with root module
  1461  	// variables, and specifically that we handle the situation where the
  1462  	// given value is invalid in a child module.
  1463  	m := testModule(t, "validate-variable-custom-validations-child")
  1464  
  1465  	p := testProvider("test")
  1466  	ctx := testContext2(t, &ContextOpts{
  1467  		Providers: map[addrs.Provider]providers.Factory{
  1468  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1469  		},
  1470  	})
  1471  
  1472  	diags := ctx.Validate(m)
  1473  	if !diags.HasErrors() {
  1474  		t.Fatal("succeeded; want errors")
  1475  	}
  1476  	if got, want := diags.Err().Error(), `Invalid value for variable: Value must not be "nope".`; !strings.Contains(got, want) {
  1477  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  1478  	}
  1479  }
  1480  
  1481  func TestContext2Validate_variableCustomValidationsRoot(t *testing.T) {
  1482  	// This test is for custom validation rules associated with root module
  1483  	// variables, and specifically that we handle the situation where their
  1484  	// values are unknown during validation, skipping the validation check
  1485  	// altogether. (Root module variables are never known during validation.)
  1486  	m := testModuleInline(t, map[string]string{
  1487  		"main.tf": `
  1488  variable "test" {
  1489    type = string
  1490  
  1491    validation {
  1492  	condition     = var.test != "nope"
  1493  	error_message = "Value must not be \"nope\"."
  1494    }
  1495  }
  1496  `,
  1497  	})
  1498  
  1499  	p := testProvider("test")
  1500  	ctx := testContext2(t, &ContextOpts{
  1501  		Providers: map[addrs.Provider]providers.Factory{
  1502  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1503  		},
  1504  	})
  1505  
  1506  	diags := ctx.Validate(m)
  1507  	if diags.HasErrors() {
  1508  		t.Fatalf("unexpected error\ngot: %s", diags.Err().Error())
  1509  	}
  1510  }
  1511  
  1512  func TestContext2Validate_expandModules(t *testing.T) {
  1513  	m := testModuleInline(t, map[string]string{
  1514  		"main.tf": `
  1515  module "mod1" {
  1516    for_each = toset(["a", "b"])
  1517    source = "./mod"
  1518  }
  1519  
  1520  module "mod2" {
  1521    for_each = module.mod1
  1522    source = "./mod"
  1523    input = module.mod1["a"].out
  1524  }
  1525  
  1526  module "mod3" {
  1527    count = length(module.mod2)
  1528    source = "./mod"
  1529  }
  1530  `,
  1531  		"mod/main.tf": `
  1532  resource "aws_instance" "foo" {
  1533  }
  1534  
  1535  output "out" {
  1536    value = 1
  1537  }
  1538  
  1539  variable "input" {
  1540    type = number
  1541    default = 0
  1542  }
  1543  
  1544  module "nested" {
  1545    count = 2
  1546    source = "./nested"
  1547    input = count.index
  1548  }
  1549  `,
  1550  		"mod/nested/main.tf": `
  1551  variable "input" {
  1552  }
  1553  
  1554  resource "aws_instance" "foo" {
  1555    count = var.input
  1556  }
  1557  `,
  1558  	})
  1559  
  1560  	p := testProvider("aws")
  1561  	ctx := testContext2(t, &ContextOpts{
  1562  		Providers: map[addrs.Provider]providers.Factory{
  1563  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1564  		},
  1565  	})
  1566  
  1567  	diags := ctx.Validate(m)
  1568  	if diags.HasErrors() {
  1569  		t.Fatal(diags.ErrWithWarnings())
  1570  	}
  1571  }
  1572  
  1573  func TestContext2Validate_expandModulesInvalidCount(t *testing.T) {
  1574  	m := testModuleInline(t, map[string]string{
  1575  		"main.tf": `
  1576  module "mod1" {
  1577    count = -1
  1578    source = "./mod"
  1579  }
  1580  `,
  1581  		"mod/main.tf": `
  1582  resource "aws_instance" "foo" {
  1583  }
  1584  `,
  1585  	})
  1586  
  1587  	p := testProvider("aws")
  1588  	ctx := testContext2(t, &ContextOpts{
  1589  		Providers: map[addrs.Provider]providers.Factory{
  1590  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1591  		},
  1592  	})
  1593  
  1594  	diags := ctx.Validate(m)
  1595  	if !diags.HasErrors() {
  1596  		t.Fatal("succeeded; want errors")
  1597  	}
  1598  	if got, want := diags.Err().Error(), `Invalid count argument`; !strings.Contains(got, want) {
  1599  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  1600  	}
  1601  }
  1602  
  1603  func TestContext2Validate_expandModulesInvalidForEach(t *testing.T) {
  1604  	m := testModuleInline(t, map[string]string{
  1605  		"main.tf": `
  1606  module "mod1" {
  1607    for_each = ["a", "b"]
  1608    source = "./mod"
  1609  }
  1610  `,
  1611  		"mod/main.tf": `
  1612  resource "aws_instance" "foo" {
  1613  }
  1614  `,
  1615  	})
  1616  
  1617  	p := testProvider("aws")
  1618  	ctx := testContext2(t, &ContextOpts{
  1619  		Providers: map[addrs.Provider]providers.Factory{
  1620  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1621  		},
  1622  	})
  1623  
  1624  	diags := ctx.Validate(m)
  1625  	if !diags.HasErrors() {
  1626  		t.Fatal("succeeded; want errors")
  1627  	}
  1628  	if got, want := diags.Err().Error(), `Invalid for_each argument`; !strings.Contains(got, want) {
  1629  		t.Fatalf("wrong error:\ngot:  %s\nwant: message containing %q", got, want)
  1630  	}
  1631  }
  1632  
  1633  func TestContext2Validate_expandMultipleNestedModules(t *testing.T) {
  1634  	m := testModuleInline(t, map[string]string{
  1635  		"main.tf": `
  1636  module "modA" {
  1637    for_each = {
  1638      first = "m"
  1639  	second = "n"
  1640    }
  1641    source = "./modA"
  1642  }
  1643  `,
  1644  		"modA/main.tf": `
  1645  locals {
  1646    m = {
  1647      first = "m"
  1648  	second = "n"
  1649    }
  1650  }
  1651  
  1652  module "modB" {
  1653    for_each = local.m
  1654    source = "./modB"
  1655    y = each.value
  1656  }
  1657  
  1658  module "modC" {
  1659    for_each = local.m
  1660    source = "./modC"
  1661    x = module.modB[each.key].out
  1662    y = module.modB[each.key].out
  1663  }
  1664  
  1665  `,
  1666  		"modA/modB/main.tf": `
  1667  variable "y" {
  1668    type = string
  1669  }
  1670  
  1671  resource "aws_instance" "foo" {
  1672    foo = var.y
  1673  }
  1674  
  1675  output "out" {
  1676    value = aws_instance.foo.id
  1677  }
  1678  `,
  1679  		"modA/modC/main.tf": `
  1680  variable "x" {
  1681    type = string
  1682  }
  1683  
  1684  variable "y" {
  1685    type = string
  1686  }
  1687  
  1688  resource "aws_instance" "foo" {
  1689    foo = var.x
  1690  }
  1691  
  1692  output "out" {
  1693    value = var.y
  1694  }
  1695  `,
  1696  	})
  1697  
  1698  	p := testProvider("aws")
  1699  	ctx := testContext2(t, &ContextOpts{
  1700  		Providers: map[addrs.Provider]providers.Factory{
  1701  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1702  		},
  1703  	})
  1704  
  1705  	diags := ctx.Validate(m)
  1706  	if diags.HasErrors() {
  1707  		t.Fatal(diags.ErrWithWarnings())
  1708  	}
  1709  }
  1710  
  1711  func TestContext2Validate_invalidModuleDependsOn(t *testing.T) {
  1712  	// validate module and output depends_on
  1713  	m := testModuleInline(t, map[string]string{
  1714  		"main.tf": `
  1715  module "mod1" {
  1716    source = "./mod"
  1717    depends_on = [resource_foo.bar.baz]
  1718  }
  1719  
  1720  module "mod2" {
  1721    source = "./mod"
  1722    depends_on = [resource_foo.bar.baz]
  1723  }
  1724  `,
  1725  		"mod/main.tf": `
  1726  output "out" {
  1727    value = "foo"
  1728  }
  1729  `,
  1730  	})
  1731  
  1732  	diags := testContext2(t, &ContextOpts{}).Validate(m)
  1733  	if !diags.HasErrors() {
  1734  		t.Fatal("succeeded; want errors")
  1735  	}
  1736  
  1737  	if len(diags) != 2 {
  1738  		t.Fatalf("wanted 2 diagnostic errors, got %q", diags)
  1739  	}
  1740  
  1741  	for _, d := range diags {
  1742  		des := d.Description().Summary
  1743  		if !strings.Contains(des, "Invalid depends_on reference") {
  1744  			t.Fatalf(`expected "Invalid depends_on reference", got %q`, des)
  1745  		}
  1746  	}
  1747  }
  1748  
  1749  func TestContext2Validate_invalidOutputDependsOn(t *testing.T) {
  1750  	// validate module and output depends_on
  1751  	m := testModuleInline(t, map[string]string{
  1752  		"main.tf": `
  1753  module "mod1" {
  1754    source = "./mod"
  1755  }
  1756  
  1757  output "out" {
  1758    value = "bar"
  1759    depends_on = [resource_foo.bar.baz]
  1760  }
  1761  `,
  1762  		"mod/main.tf": `
  1763  output "out" {
  1764    value = "bar"
  1765    depends_on = [resource_foo.bar.baz]
  1766  }
  1767  `,
  1768  	})
  1769  
  1770  	diags := testContext2(t, &ContextOpts{}).Validate(m)
  1771  	if !diags.HasErrors() {
  1772  		t.Fatal("succeeded; want errors")
  1773  	}
  1774  
  1775  	if len(diags) != 2 {
  1776  		t.Fatalf("wanted 2 diagnostic errors, got %q", diags)
  1777  	}
  1778  
  1779  	for _, d := range diags {
  1780  		des := d.Description().Summary
  1781  		if !strings.Contains(des, "Invalid depends_on reference") {
  1782  			t.Fatalf(`expected "Invalid depends_on reference", got %q`, des)
  1783  		}
  1784  	}
  1785  }
  1786  
  1787  func TestContext2Validate_rpcDiagnostics(t *testing.T) {
  1788  	// validate module and output depends_on
  1789  	m := testModuleInline(t, map[string]string{
  1790  		"main.tf": `
  1791  resource "test_instance" "a" {
  1792  }
  1793  `,
  1794  	})
  1795  
  1796  	p := testProvider("test")
  1797  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1798  		ResourceTypes: map[string]providers.Schema{
  1799  			"test_instance": {
  1800  				Block: &configschema.Block{
  1801  					Attributes: map[string]*configschema.Attribute{
  1802  						"id": {Type: cty.String, Computed: true},
  1803  					},
  1804  				},
  1805  			},
  1806  		},
  1807  	}
  1808  
  1809  	p.ValidateResourceConfigResponse = &providers.ValidateResourceConfigResponse{
  1810  		Diagnostics: tfdiags.Diagnostics(nil).Append(tfdiags.SimpleWarning("don't frobble")),
  1811  	}
  1812  
  1813  	ctx := testContext2(t, &ContextOpts{
  1814  		Providers: map[addrs.Provider]providers.Factory{
  1815  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1816  		},
  1817  	})
  1818  	diags := ctx.Validate(m)
  1819  	if diags.HasErrors() {
  1820  		t.Fatal(diags.Err())
  1821  	}
  1822  
  1823  	if len(diags) == 0 {
  1824  		t.Fatal("expected warnings")
  1825  	}
  1826  
  1827  	for _, d := range diags {
  1828  		des := d.Description().Summary
  1829  		if !strings.Contains(des, "frobble") {
  1830  			t.Fatalf(`expected frobble, got %q`, des)
  1831  		}
  1832  	}
  1833  }
  1834  
  1835  func TestContext2Validate_sensitiveProvisionerConfig(t *testing.T) {
  1836  	m := testModule(t, "validate-sensitive-provisioner-config")
  1837  	p := testProvider("aws")
  1838  	p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
  1839  		ResourceTypes: map[string]providers.Schema{
  1840  			"aws_instance": {
  1841  				Block: &configschema.Block{
  1842  					Attributes: map[string]*configschema.Attribute{
  1843  						"foo": {Type: cty.String, Optional: true},
  1844  					},
  1845  				},
  1846  			},
  1847  		},
  1848  	}
  1849  
  1850  	pr := simpleMockProvisioner()
  1851  
  1852  	c := testContext2(t, &ContextOpts{
  1853  		Providers: map[addrs.Provider]providers.Factory{
  1854  			addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
  1855  		},
  1856  		Provisioners: map[string]provisioners.Factory{
  1857  			"test": testProvisionerFuncFixed(pr),
  1858  		},
  1859  	})
  1860  
  1861  	pr.ValidateProvisionerConfigFn = func(r provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse {
  1862  		if r.Config.ContainsMarked() {
  1863  			t.Errorf("provisioner config contains marked values")
  1864  		}
  1865  		return pr.ValidateProvisionerConfigResponse
  1866  	}
  1867  
  1868  	diags := c.Validate(m)
  1869  	if diags.HasErrors() {
  1870  		t.Fatalf("unexpected error: %s", diags.Err())
  1871  	}
  1872  	if !pr.ValidateProvisionerConfigCalled {
  1873  		t.Fatal("ValidateProvisionerConfig not called")
  1874  	}
  1875  }
  1876  
  1877  func TestContext2Plan_validateMinMaxDynamicBlock(t *testing.T) {
  1878  	p := new(MockProvider)
  1879  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  1880  		ResourceTypes: map[string]*configschema.Block{
  1881  			"test_instance": {
  1882  				Attributes: map[string]*configschema.Attribute{
  1883  					"id": {
  1884  						Type:     cty.String,
  1885  						Computed: true,
  1886  					},
  1887  					"things": {
  1888  						Type:     cty.List(cty.String),
  1889  						Computed: true,
  1890  					},
  1891  				},
  1892  				BlockTypes: map[string]*configschema.NestedBlock{
  1893  					"foo": {
  1894  						Block: configschema.Block{
  1895  							Attributes: map[string]*configschema.Attribute{
  1896  								"bar": {Type: cty.String, Optional: true},
  1897  							},
  1898  						},
  1899  						Nesting:  configschema.NestingList,
  1900  						MinItems: 2,
  1901  						MaxItems: 3,
  1902  					},
  1903  				},
  1904  			},
  1905  		},
  1906  	})
  1907  
  1908  	m := testModuleInline(t, map[string]string{
  1909  		"main.tf": `
  1910  resource "test_instance" "a" {
  1911    // MinItems 2
  1912    foo {
  1913      bar = "a"
  1914    }
  1915    foo {
  1916      bar = "b"
  1917    }
  1918  }
  1919  
  1920  resource "test_instance" "b" {
  1921    // one dymamic block can satisfy MinItems of 2
  1922    dynamic "foo" {
  1923  	for_each = test_instance.a.things
  1924  	content {
  1925  	  bar = foo.value
  1926  	}
  1927    }
  1928  }
  1929  
  1930  resource "test_instance" "c" {
  1931    // we may have more than MaxItems dynamic blocks when they are unknown
  1932    foo {
  1933      bar = "b"
  1934    }
  1935    dynamic "foo" {
  1936      for_each = test_instance.a.things
  1937      content {
  1938        bar = foo.value
  1939      }
  1940    }
  1941    dynamic "foo" {
  1942      for_each = test_instance.a.things
  1943      content {
  1944        bar = "${foo.value}-2"
  1945      }
  1946    }
  1947    dynamic "foo" {
  1948      for_each = test_instance.b.things
  1949      content {
  1950        bar = foo.value
  1951      }
  1952    }
  1953  }
  1954  `})
  1955  
  1956  	ctx := testContext2(t, &ContextOpts{
  1957  		Providers: map[addrs.Provider]providers.Factory{
  1958  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  1959  		},
  1960  	})
  1961  
  1962  	diags := ctx.Validate(m)
  1963  	if diags.HasErrors() {
  1964  		t.Fatal(diags.ErrWithWarnings())
  1965  	}
  1966  }
  1967  
  1968  func TestContext2Validate_passInheritedProvider(t *testing.T) {
  1969  	m := testModuleInline(t, map[string]string{
  1970  		"main.tf": `
  1971  terraform {
  1972    required_providers {
  1973  	test = {
  1974  	  source = "hashicorp/test"
  1975  	}
  1976    }
  1977  }
  1978  
  1979  module "first" {
  1980    source = "./first"
  1981    providers = {
  1982      test = test
  1983    }
  1984  }
  1985  `,
  1986  
  1987  		// This module does not define a config for the test provider, but we
  1988  		// should be able to pass whatever the implied config is to a child
  1989  		// module.
  1990  		"first/main.tf": `
  1991  terraform {
  1992    required_providers {
  1993      test = {
  1994  	  source = "hashicorp/test"
  1995      }
  1996    }
  1997  }
  1998  
  1999  module "second" {
  2000    source = "./second"
  2001    providers = {
  2002  	test.alias = test
  2003    }
  2004  }`,
  2005  
  2006  		"first/second/main.tf": `
  2007  terraform {
  2008    required_providers {
  2009      test = {
  2010  	  source = "hashicorp/test"
  2011        configuration_aliases = [test.alias]
  2012      }
  2013    }
  2014  }
  2015  
  2016  resource "test_object" "t" {
  2017    provider = test.alias
  2018  }
  2019  `,
  2020  	})
  2021  
  2022  	p := simpleMockProvider()
  2023  	ctx := testContext2(t, &ContextOpts{
  2024  		Providers: map[addrs.Provider]providers.Factory{
  2025  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  2026  		},
  2027  	})
  2028  
  2029  	diags := ctx.Validate(m)
  2030  	if diags.HasErrors() {
  2031  		t.Fatal(diags.ErrWithWarnings())
  2032  	}
  2033  }
  2034  
  2035  func TestContext2Plan_lookupMismatchedObjectTypes(t *testing.T) {
  2036  	p := new(MockProvider)
  2037  	p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
  2038  		ResourceTypes: map[string]*configschema.Block{
  2039  			"test_instance": {
  2040  				Attributes: map[string]*configschema.Attribute{
  2041  					"id": {
  2042  						Type:     cty.String,
  2043  						Computed: true,
  2044  					},
  2045  					"things": {
  2046  						Type:     cty.List(cty.String),
  2047  						Optional: true,
  2048  					},
  2049  				},
  2050  			},
  2051  		},
  2052  	})
  2053  
  2054  	m := testModuleInline(t, map[string]string{
  2055  		"main.tf": `
  2056  variable "items" {
  2057    type = list(string)
  2058    default = []
  2059  }
  2060  
  2061  resource "test_instance" "a" {
  2062    for_each = length(var.items) > 0 ? { default = {} } : {}
  2063  }
  2064  
  2065  output "out" {
  2066    // Strictly speaking, this expression is incorrect because the map element
  2067    // type is a different type from the default value, and the lookup
  2068    // implementation expects to be able to convert the default to match the
  2069    // element type.
  2070    // There are two reasons this works which we need to maintain for
  2071    // compatibility. First during validation the 'test_instance.a' expression
  2072    // only returns a dynamic value, preventing any type comparison. Later during
  2073    // plan and apply 'test_instance.a' is an object and not a map, and the
  2074    // lookup implementation skips the type comparison when the keys are known
  2075    // statically.
  2076    value = lookup(test_instance.a, "default", { id = null })["id"]
  2077  }
  2078  `})
  2079  
  2080  	ctx := testContext2(t, &ContextOpts{
  2081  		Providers: map[addrs.Provider]providers.Factory{
  2082  			addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
  2083  		},
  2084  	})
  2085  
  2086  	diags := ctx.Validate(m)
  2087  	if diags.HasErrors() {
  2088  		t.Fatal(diags.ErrWithWarnings())
  2089  	}
  2090  }