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