mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 01:41:48 -06:00
e0ecd2ebb3
Signed-off-by: RLRabinowitz <rlrabinowitz2@gmail.com>
153 lines
4.3 KiB
Go
153 lines
4.3 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package tofu
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/hcl/v2/hclsyntax"
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
"github.com/opentofu/opentofu/internal/addrs"
|
|
"github.com/opentofu/opentofu/internal/configs/configschema"
|
|
"github.com/opentofu/opentofu/internal/lang"
|
|
"github.com/opentofu/opentofu/internal/providers"
|
|
)
|
|
|
|
func TestStaticValidateReferences(t *testing.T) {
|
|
tests := []struct {
|
|
Ref string
|
|
Src addrs.Referenceable
|
|
WantErr string
|
|
}{
|
|
{
|
|
Ref: "aws_instance.no_count",
|
|
WantErr: ``,
|
|
},
|
|
{
|
|
Ref: "aws_instance.count",
|
|
WantErr: ``,
|
|
},
|
|
{
|
|
Ref: "aws_instance.count[0]",
|
|
WantErr: ``,
|
|
},
|
|
{
|
|
Ref: "aws_instance.nonexist",
|
|
WantErr: `Reference to undeclared resource: A managed resource "aws_instance" "nonexist" has not been declared in the root module.`,
|
|
},
|
|
{
|
|
Ref: "beep.boop",
|
|
WantErr: `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?`,
|
|
},
|
|
{
|
|
Ref: "aws_instance.no_count[0]",
|
|
WantErr: `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.`,
|
|
},
|
|
{
|
|
Ref: "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.
|
|
WantErr: `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".`,
|
|
},
|
|
{
|
|
Ref: "boop_instance.yep",
|
|
WantErr: ``,
|
|
},
|
|
{
|
|
Ref: "boop_whatever.nope",
|
|
WantErr: `Invalid resource type: A managed resource type "boop_whatever" is not supported by provider "registry.opentofu.org/foobar/beep".`,
|
|
},
|
|
{
|
|
Ref: "data.boop_data.boop_nested",
|
|
WantErr: `Reference to scoped resource: The referenced data resource "boop_data" "boop_nested" is not available from this context.`,
|
|
},
|
|
{
|
|
Ref: "data.boop_data.boop_nested",
|
|
WantErr: ``,
|
|
Src: addrs.Check{Name: "foo"},
|
|
},
|
|
}
|
|
|
|
cfg := testModule(t, "static-validate-refs")
|
|
evaluator := &Evaluator{
|
|
Config: cfg,
|
|
Plugins: schemaOnlyProvidersForTesting(map[addrs.Provider]providers.ProviderSchema{
|
|
addrs.NewDefaultProvider("aws"): {
|
|
ResourceTypes: map[string]providers.Schema{
|
|
"aws_instance": {
|
|
Block: &configschema.Block{},
|
|
},
|
|
},
|
|
},
|
|
addrs.MustParseProviderSourceString("foobar/beep"): {
|
|
ResourceTypes: map[string]providers.Schema{
|
|
// intentional mismatch between resource type prefix and provider type
|
|
"boop_instance": {
|
|
Block: &configschema.Block{},
|
|
},
|
|
},
|
|
DataSources: map[string]providers.Schema{
|
|
"boop_data": {
|
|
Block: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"id": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
}
|
|
|
|
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(addrs.ParseRef, []hcl.Traversal{traversal})
|
|
if diags.HasErrors() {
|
|
t.Fatal(diags.Err())
|
|
}
|
|
|
|
data := &evaluationStateData{
|
|
Evaluator: evaluator,
|
|
}
|
|
|
|
diags = data.StaticValidateReferences(refs, nil, test.Src)
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|