opentofu/terraform/context_validate_test.go
James Bardin e3f64af8ac Temporarily move 2 validate tests to plan
We can't catch invalid attributes in validate at the moment, because the
lack of count information causes the references to return unknown. Make
sure they fail in plan, and mark the validate tests to fix later.
2018-10-16 19:14:11 -07:00

1186 lines
28 KiB
Go

package terraform
import (
"errors"
"fmt"
"strings"
"testing"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/providers"
"github.com/hashicorp/terraform/provisioners"
"github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/tfdiags"
)
func TestContext2Validate_badCount(t *testing.T) {
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{},
},
},
}
m := testModule(t, "validate-bad-count")
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_badVar(t *testing.T) {
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
"num": {Type: cty.String, Optional: true},
},
},
},
}
m := testModule(t, "validate-bad-var")
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_varMapOverrideOld(t *testing.T) {
m := testModule(t, "validate-module-pc-vars")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
Variables: InputValues{
"foo.foo": &InputValue{
Value: cty.StringVal("bar"),
SourceType: ValueFromCaller,
},
},
})
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_varNoDefaultExplicitType(t *testing.T) {
m := testModule(t, "validate-var-no-default-explicit-type")
c := testContext2(t, &ContextOpts{
Config: m,
})
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_computedVar(t *testing.T) {
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"value": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{},
},
},
}
pt := testProvider("test")
pt.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"test_instance": {
Attributes: map[string]*configschema.Attribute{
"value": {Type: cty.String, Optional: true},
},
},
},
}
m := testModule(t, "validate-computed-var")
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
"test": testProviderFuncFixed(pt),
},
),
})
p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
if !c.IsComputed("value") {
return nil, []error{fmt.Errorf("value isn't computed")}
}
return nil, c.CheckSet([]string{"value"})
}
p.ConfigureFn = func(c *ResourceConfig) error {
return fmt.Errorf("Configure should not be called for provider")
}
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
// Test that validate allows through computed counts. We do this and allow
// them to fail during "plan" since we can't know if the computed values
// can be realized during a plan.
func TestContext2Validate_countComputed(t *testing.T) {
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{},
},
},
DataSources: map[string]*configschema.Block{
"aws_data_source": {
Attributes: map[string]*configschema.Attribute{
"compute": {Type: cty.String, Optional: true},
"value": {Type: cty.String, Computed: true},
},
},
},
}
m := testModule(t, "validate-count-computed")
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_countNegative(t *testing.T) {
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{},
},
},
}
m := testModule(t, "validate-count-negative")
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_countVariable(t *testing.T) {
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
m := testModule(t, "apply-count-variable")
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_countVariableNoDefault(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "validate-count-variable")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_moduleBadOutput(t *testing.T) {
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
m := testModule(t, "validate-bad-module-output")
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_moduleGood(t *testing.T) {
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
m := testModule(t, "validate-good-module")
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_moduleBadResource(t *testing.T) {
m := testModule(t, "validate-module-bad-rc")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
p.ValidateResourceTypeConfigResponse = providers.ValidateResourceTypeConfigResponse{
Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
}
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_moduleDepsShouldNotCycle(t *testing.T) {
m := testModule(t, "validate-module-deps-cycle")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Optional: true},
},
},
},
}
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := ctx.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_moduleProviderVar(t *testing.T) {
m := testModule(t, "validate-module-pc-vars")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
Variables: InputValues{
"provider_var": &InputValue{
Value: cty.StringVal("bar"),
SourceType: ValueFromCaller,
},
},
})
p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
return nil, c.CheckSet([]string{"foo"})
}
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_moduleProviderInheritUnused(t *testing.T) {
m := testModule(t, "validate-module-pc-inherit-unused")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
return nil, c.CheckSet([]string{"foo"})
}
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_orphans(t *testing.T) {
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
"num": {Type: cty.String, Optional: true},
},
},
},
}
m := testModule(t, "validate-good")
state := mustShimLegacyState(&State{
Modules: []*ModuleState{
&ModuleState{
Path: rootModulePath,
Resources: map[string]*ResourceState{
"aws_instance.web": &ResourceState{
Type: "aws_instance",
Primary: &InstanceState{
ID: "bar",
},
},
},
},
},
})
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
State: state,
})
p.ValidateResourceTypeConfigFn = func(req providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse {
var diags tfdiags.Diagnostics
if req.Config.GetAttr("foo").IsNull() {
diags.Append(errors.New("foo is not set"))
}
return providers.ValidateResourceTypeConfigResponse{
Diagnostics: diags,
}
}
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_providerConfig_bad(t *testing.T) {
m := testModule(t, "validate-bad-pc")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
p.ValidateProviderConfigResponse = providers.ValidateProviderConfigResponse{
Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
}
diags := c.Validate()
if len(diags) != 1 {
t.Fatalf("wrong number of diagnostics %d; want %d", len(diags), 1)
}
if !strings.Contains(diags.Err().Error(), "bad") {
t.Fatalf("bad: %s", diags.Err().Error())
}
}
func TestContext2Validate_providerConfig_badEmpty(t *testing.T) {
m := testModule(t, "validate-bad-pc-empty")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
p.ValidateProviderConfigResponse = providers.ValidateProviderConfigResponse{
Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
}
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_providerConfig_good(t *testing.T) {
m := testModule(t, "validate-bad-pc")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_provisionerConfig_bad(t *testing.T) {
m := testModule(t, "validate-bad-prov-conf")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
pr := simpleMockProvisioner()
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
Provisioners: map[string]ProvisionerFactory{
"shell": testProvisionerFuncFixed(pr),
},
})
p.ValidateProviderConfigResponse = providers.ValidateProviderConfigResponse{
Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
}
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_provisionerConfig_good(t *testing.T) {
m := testModule(t, "validate-bad-prov-conf")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
pr := simpleMockProvisioner()
pr.ValidateProvisionerConfigFn = func(req provisioners.ValidateProvisionerConfigRequest) provisioners.ValidateProvisionerConfigResponse {
var diags tfdiags.Diagnostics
if req.Config.GetAttr("test_string").IsNull() {
diags.Append(errors.New("test_string is not set"))
}
return provisioners.ValidateProvisionerConfigResponse{
Diagnostics: diags,
}
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
Provisioners: map[string]ProvisionerFactory{
"shell": testProvisionerFuncFixed(pr),
},
})
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_requiredVar(t *testing.T) {
m := testModule(t, "validate-required-var")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"ami": {Type: cty.String, Optional: true},
},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_resourceConfig_bad(t *testing.T) {
m := testModule(t, "validate-bad-rc")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
p.ValidateResourceTypeConfigResponse = providers.ValidateResourceTypeConfigResponse{
Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("bad")),
}
diags := c.Validate()
if !diags.HasErrors() {
t.Fatalf("succeeded; want error")
}
}
func TestContext2Validate_resourceConfig_good(t *testing.T) {
m := testModule(t, "validate-bad-rc")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_tainted(t *testing.T) {
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
"num": {Type: cty.String, Optional: true},
},
},
},
}
m := testModule(t, "validate-good")
state := mustShimLegacyState(&State{
Modules: []*ModuleState{
&ModuleState{
Path: rootModulePath,
Resources: map[string]*ResourceState{
"aws_instance.foo": &ResourceState{
Type: "aws_instance",
Primary: &InstanceState{
ID: "bar",
Tainted: true,
},
},
},
},
},
})
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
State: state,
})
p.ValidateResourceTypeConfigFn = func(req providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse {
var diags tfdiags.Diagnostics
if req.Config.GetAttr("foo").IsNull() {
diags.Append(errors.New("foo is not set"))
}
return providers.ValidateResourceTypeConfigResponse{
Diagnostics: diags,
}
}
diags := c.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_targetedDestroy(t *testing.T) {
m := testModule(t, "validate-targeted")
p := testProvider("aws")
pr := simpleMockProvisioner()
p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
"num": {Type: cty.String, Optional: true},
},
},
},
}
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
Provisioners: map[string]ProvisionerFactory{
"shell": testProvisionerFuncFixed(pr),
},
State: mustShimLegacyState(&State{
Modules: []*ModuleState{
&ModuleState{
Path: rootModulePath,
Resources: map[string]*ResourceState{
"aws_instance.foo": resourceState("aws_instance", "i-bcd345"),
"aws_instance.bar": resourceState("aws_instance", "i-abc123"),
},
},
},
}),
Targets: []addrs.Targetable{
addrs.RootModuleInstance.Resource(
addrs.ManagedResourceMode, "aws_instance", "foo",
),
},
Destroy: true,
})
diags := ctx.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
func TestContext2Validate_varRefFilled(t *testing.T) {
m := testModule(t, "validate-variable-ref")
p := testProvider("aws")
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
},
}
c := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
Variables: InputValues{
"foo": &InputValue{
Value: cty.StringVal("bar"),
SourceType: ValueFromCaller,
},
},
})
var value cty.Value
p.ValidateResourceTypeConfigFn = func(req providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse {
value = req.Config.GetAttr("foo")
return providers.ValidateResourceTypeConfigResponse{}
}
c.Validate()
if !value.RawEquals(cty.StringVal("bar")) {
t.Fatalf("bad: %#v", value)
}
}
// Module variables weren't being interpolated during Validate phase.
// related to https://github.com/hashicorp/terraform/issues/5322
func TestContext2Validate_interpolateVar(t *testing.T) {
input := new(MockUIInput)
m := testModule(t, "input-interpolate-var")
p := testProvider("null")
p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"template_file": {
Attributes: map[string]*configschema.Attribute{
"template": {Type: cty.String, Optional: true},
},
},
},
}
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"template": testProviderFuncFixed(p),
},
),
UIInput: input,
})
diags := ctx.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
// When module vars reference something that is actually computed, this
// shouldn't cause validation to fail.
func TestContext2Validate_interpolateComputedModuleVarDef(t *testing.T) {
input := new(MockUIInput)
m := testModule(t, "validate-computed-module-var-ref")
p := testProvider("aws")
p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn
p.GetSchemaReturn = &ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"attr": {Type: cty.String, Optional: true},
},
},
},
}
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
UIInput: input,
})
diags := ctx.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
// Computed values are lost when a map is output from a module
func TestContext2Validate_interpolateMap(t *testing.T) {
input := new(MockUIInput)
m := testModule(t, "issue-9549")
p := testProvider("template")
p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"template": testProviderFuncFixed(p),
},
),
UIInput: input,
})
diags := ctx.Validate()
if diags.HasErrors() {
t.Fatalf("unexpected error: %s", diags.Err())
}
}
// Manually validate using the new PlanGraphBuilder
func TestContext2Validate_PlanGraphBuilder(t *testing.T) {
fixture := contextFixtureApplyVars(t)
opts := fixture.ContextOpts()
opts.Variables = InputValues{
"foo": &InputValue{
Value: cty.StringVal("us-east-1"),
SourceType: ValueFromCaller,
},
"test_list": &InputValue{
Value: cty.ListVal([]cty.Value{
cty.StringVal("Hello"),
cty.StringVal("World"),
}),
SourceType: ValueFromCaller,
},
"test_map": &InputValue{
Value: cty.MapVal(map[string]cty.Value{
"Hello": cty.StringVal("World"),
"Foo": cty.StringVal("Bar"),
"Baz": cty.StringVal("Foo"),
}),
SourceType: ValueFromCaller,
},
"amis": &InputValue{
Value: cty.MapVal(map[string]cty.Value{
"us-east-1": cty.StringVal("override"),
}),
SourceType: ValueFromCaller,
},
}
c := testContext2(t, opts)
graph, diags := (&PlanGraphBuilder{
Config: c.config,
State: states.NewState(),
Components: c.components,
Schemas: c.schemas,
Targets: c.targets,
}).Build(addrs.RootModuleInstance)
if diags.HasErrors() {
t.Fatalf("errors from PlanGraphBuilder: %s", diags.Err())
}
defer c.acquireRun("validate-test")()
walker, diags := c.walk(graph, walkValidate)
if diags.HasErrors() {
t.Fatal(diags.Err())
}
if len(walker.NonFatalDiagnostics) > 0 {
t.Fatal(walker.NonFatalDiagnostics.Err())
}
}
// FIXME: these 2 tests should be caught in validation.
// Since the evaluator can't determine if the resource contains a count during
// validation, any refereces are currently returned as unknown. We need a
// static validation of a reference to determine if it's possible within a
// particular schema.
/*
func TestContext2Validate_invalidOutput(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
data "aws_data_source" "name" {}
output "out" {
value = "${data.aws_data_source.name.missing}"
}`,
})
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := ctx.Validate()
if !diags.HasErrors() {
// Should get this error:
// Unsupported attribute: This object does not have an attribute named "missing"
t.Fatal("succeeded; want errors")
}
}
func TestContext2Validate_invalidModuleOutput(t *testing.T) {
m := testModuleInline(t, map[string]string{
"child/main.tf": `
data "aws_data_source" "name" {}
output "out" {
value = "${data.aws_data_source.name.missing}"
}`,
"main.tf": `
module "child" {
source = "./child"
}
resource "aws_instance" "foo" {
foo = "${module.child.out}"
}`,
})
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[string]providers.Factory{
"aws": testProviderFuncFixed(p),
},
),
})
diags := ctx.Validate()
if !diags.HasErrors() {
// Should get this error:
// Unsupported attribute: This object does not have an attribute named "missing"
t.Fatal("succeeded; want errors")
}
}
*/