blob: cfdfdea1f5e1e7371cb5181370a0c6a4b4e8568e [file] [log] [blame]
package terraform
import (
"testing"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs/configschema"
"github.com/hashicorp/terraform/internal/lang"
)
func TestStaticValidateReferences(t *testing.T) {
tests := []struct {
Ref string
WantErr string
}{
{
"aws_instance.no_count",
``,
},
{
"aws_instance.count",
``,
},
{
"aws_instance.count[0]",
``,
},
{
"aws_instance.nonexist",
`Reference to undeclared resource: A managed resource "aws_instance" "nonexist" has not been declared in the root module.`,
},
{
"beep.boop",
`Reference to undeclared resource: A managed resource "beep" "boop" has not been declared in the root module.
Did you mean the data resource data.beep.boop?`,
},
{
"aws_instance.no_count[0]",
`Unexpected resource instance key: Because aws_instance.no_count does not have "count" or "for_each" set, references to it must not include an index key. Remove the bracketed index to refer to the single instance of this resource.`,
},
{
"aws_instance.count.foo",
// In this case we return two errors that are somewhat redundant with
// one another, but we'll accept that because they both report the
// problem from different perspectives and so give the user more
// opportunity to understand what's going on here.
`2 problems:
- Missing resource instance key: Because aws_instance.count has "count" set, its attributes must be accessed on specific instances.
For example, to correlate with indices of a referring resource, use:
aws_instance.count[count.index]
- Unsupported attribute: This object has no argument, nested block, or exported attribute named "foo".`,
},
{
"boop_instance.yep",
``,
},
{
"boop_whatever.nope",
`Invalid resource type: A managed resource type "boop_whatever" is not supported by provider "registry.terraform.io/foobar/beep".`,
},
}
cfg := testModule(t, "static-validate-refs")
evaluator := &Evaluator{
Config: cfg,
Plugins: schemaOnlyProvidersForTesting(map[addrs.Provider]*ProviderSchema{
addrs.NewDefaultProvider("aws"): {
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {},
},
},
addrs.MustParseProviderSourceString("foobar/beep"): {
ResourceTypes: map[string]*configschema.Block{
// intentional mismatch between resource type prefix and provider type
"boop_instance": {},
},
},
}),
}
for _, test := range tests {
t.Run(test.Ref, func(t *testing.T) {
traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(test.Ref), "", hcl.Pos{Line: 1, Column: 1})
if hclDiags.HasErrors() {
t.Fatal(hclDiags.Error())
}
refs, diags := lang.References([]hcl.Traversal{traversal})
if diags.HasErrors() {
t.Fatal(diags.Err())
}
data := &evaluationStateData{
Evaluator: evaluator,
}
diags = data.StaticValidateReferences(refs, nil)
if diags.HasErrors() {
if test.WantErr == "" {
t.Fatalf("Unexpected diagnostics: %s", diags.Err())
}
gotErr := diags.Err().Error()
if gotErr != test.WantErr {
t.Fatalf("Wrong diagnostics\ngot: %s\nwant: %s", gotErr, test.WantErr)
}
return
}
if test.WantErr != "" {
t.Fatalf("Expected diagnostics, but got none\nwant: %s", test.WantErr)
}
})
}
}