mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-27 09:21:14 -06:00
0e963db2c5
Since the validation of connection blocks is delegated to the communicator selected by "type", we were not previously doing any validation of the attribute names in these blocks until running provisioners during apply. Proper validation here requires us to already have the instance state, since the final connection info is a merge of values provided in config with values assigned automatically by the resource. However, we can do some basic name validation to catch typos during the validation pass, even though semantic validation and checking for missing attributes will still wait until the provisioner is instantiated. This fixes #6582 as much as we reasonably can.
295 lines
7.1 KiB
Go
295 lines
7.1 KiB
Go
package terraform
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/terraform/config"
|
|
)
|
|
|
|
func TestEvalValidateResource_managedResource(t *testing.T) {
|
|
mp := testProvider("aws")
|
|
mp.ValidateResourceFn = func(rt string, c *ResourceConfig) (ws []string, es []error) {
|
|
expected := "aws_instance"
|
|
if rt != expected {
|
|
t.Fatalf("expected: %s, got: %s", expected, rt)
|
|
}
|
|
expected = "bar"
|
|
val, _ := c.Get("foo")
|
|
if val != expected {
|
|
t.Fatalf("expected: %s, got: %s", expected, val)
|
|
}
|
|
return
|
|
}
|
|
|
|
p := ResourceProvider(mp)
|
|
rc := testResourceConfig(t, map[string]interface{}{"foo": "bar"})
|
|
node := &EvalValidateResource{
|
|
Provider: &p,
|
|
Config: &rc,
|
|
ResourceName: "foo",
|
|
ResourceType: "aws_instance",
|
|
ResourceMode: config.ManagedResourceMode,
|
|
}
|
|
|
|
_, err := node.Eval(&MockEvalContext{})
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !mp.ValidateResourceCalled {
|
|
t.Fatal("Expected ValidateResource to be called, but it was not!")
|
|
}
|
|
}
|
|
|
|
func TestEvalValidateResource_dataSource(t *testing.T) {
|
|
mp := testProvider("aws")
|
|
mp.ValidateDataSourceFn = func(rt string, c *ResourceConfig) (ws []string, es []error) {
|
|
expected := "aws_ami"
|
|
if rt != expected {
|
|
t.Fatalf("expected: %s, got: %s", expected, rt)
|
|
}
|
|
expected = "bar"
|
|
val, _ := c.Get("foo")
|
|
if val != expected {
|
|
t.Fatalf("expected: %s, got: %s", expected, val)
|
|
}
|
|
return
|
|
}
|
|
|
|
p := ResourceProvider(mp)
|
|
rc := testResourceConfig(t, map[string]interface{}{"foo": "bar"})
|
|
node := &EvalValidateResource{
|
|
Provider: &p,
|
|
Config: &rc,
|
|
ResourceName: "foo",
|
|
ResourceType: "aws_ami",
|
|
ResourceMode: config.DataResourceMode,
|
|
}
|
|
|
|
_, err := node.Eval(&MockEvalContext{})
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !mp.ValidateDataSourceCalled {
|
|
t.Fatal("Expected ValidateDataSource to be called, but it was not!")
|
|
}
|
|
}
|
|
|
|
func TestEvalValidateResource_validReturnsNilError(t *testing.T) {
|
|
mp := testProvider("aws")
|
|
mp.ValidateResourceFn = func(rt string, c *ResourceConfig) (ws []string, es []error) {
|
|
return
|
|
}
|
|
|
|
p := ResourceProvider(mp)
|
|
rc := &ResourceConfig{}
|
|
node := &EvalValidateResource{
|
|
Provider: &p,
|
|
Config: &rc,
|
|
ResourceName: "foo",
|
|
ResourceType: "aws_instance",
|
|
ResourceMode: config.ManagedResourceMode,
|
|
}
|
|
|
|
_, err := node.Eval(&MockEvalContext{})
|
|
if err != nil {
|
|
t.Fatalf("Expected nil error, got: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestEvalValidateResource_warningsAndErrorsPassedThrough(t *testing.T) {
|
|
mp := testProvider("aws")
|
|
mp.ValidateResourceFn = func(rt string, c *ResourceConfig) (ws []string, es []error) {
|
|
ws = append(ws, "warn")
|
|
es = append(es, errors.New("err"))
|
|
return
|
|
}
|
|
|
|
p := ResourceProvider(mp)
|
|
rc := &ResourceConfig{}
|
|
node := &EvalValidateResource{
|
|
Provider: &p,
|
|
Config: &rc,
|
|
ResourceName: "foo",
|
|
ResourceType: "aws_instance",
|
|
ResourceMode: config.ManagedResourceMode,
|
|
}
|
|
|
|
_, err := node.Eval(&MockEvalContext{})
|
|
if err == nil {
|
|
t.Fatal("Expected an error, got none!")
|
|
}
|
|
|
|
verr := err.(*EvalValidateError)
|
|
if len(verr.Warnings) != 1 || verr.Warnings[0] != "warn" {
|
|
t.Fatalf("Expected 1 warning 'warn', got: %#v", verr.Warnings)
|
|
}
|
|
if len(verr.Errors) != 1 || verr.Errors[0].Error() != "err" {
|
|
t.Fatalf("Expected 1 error 'err', got: %#v", verr.Errors)
|
|
}
|
|
}
|
|
|
|
func TestEvalValidateResource_checksResourceName(t *testing.T) {
|
|
mp := testProvider("aws")
|
|
p := ResourceProvider(mp)
|
|
rc := &ResourceConfig{}
|
|
node := &EvalValidateResource{
|
|
Provider: &p,
|
|
Config: &rc,
|
|
ResourceName: "bad*name",
|
|
ResourceType: "aws_instance",
|
|
ResourceMode: config.ManagedResourceMode,
|
|
}
|
|
|
|
_, err := node.Eval(&MockEvalContext{})
|
|
if err == nil {
|
|
t.Fatal("Expected an error, got none!")
|
|
}
|
|
expectErr := "resource name can only contain"
|
|
if !strings.Contains(err.Error(), expectErr) {
|
|
t.Fatalf("Expected err: %s to contain %s", err, expectErr)
|
|
}
|
|
}
|
|
|
|
func TestEvalValidateResource_ignoreWarnings(t *testing.T) {
|
|
mp := testProvider("aws")
|
|
mp.ValidateResourceFn = func(rt string, c *ResourceConfig) (ws []string, es []error) {
|
|
ws = append(ws, "warn")
|
|
return
|
|
}
|
|
|
|
p := ResourceProvider(mp)
|
|
rc := &ResourceConfig{}
|
|
node := &EvalValidateResource{
|
|
Provider: &p,
|
|
Config: &rc,
|
|
ResourceName: "foo",
|
|
ResourceType: "aws_instance",
|
|
ResourceMode: config.ManagedResourceMode,
|
|
|
|
IgnoreWarnings: true,
|
|
}
|
|
|
|
_, err := node.Eval(&MockEvalContext{})
|
|
if err != nil {
|
|
t.Fatalf("Expected no error, got: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestEvalValidateProvisioner_valid(t *testing.T) {
|
|
mp := &MockResourceProvisioner{}
|
|
var p ResourceProvisioner = mp
|
|
ctx := &MockEvalContext{}
|
|
|
|
cfg := &ResourceConfig{}
|
|
connInfo, err := config.NewRawConfig(map[string]interface{}{})
|
|
if err != nil {
|
|
t.Fatalf("failed to make connInfo: %s", err)
|
|
}
|
|
connConfig := NewResourceConfig(connInfo)
|
|
|
|
node := &EvalValidateProvisioner{
|
|
Provisioner: &p,
|
|
Config: &cfg,
|
|
ConnConfig: &connConfig,
|
|
}
|
|
|
|
result, err := node.Eval(ctx)
|
|
if err != nil {
|
|
t.Fatalf("node.Eval failed: %s", err)
|
|
}
|
|
if result != nil {
|
|
t.Errorf("node.Eval returned non-nil result")
|
|
}
|
|
|
|
if !mp.ValidateCalled {
|
|
t.Fatalf("p.Config not called")
|
|
}
|
|
if mp.ValidateConfig != cfg {
|
|
t.Errorf("p.Config called with wrong config")
|
|
}
|
|
}
|
|
|
|
func TestEvalValidateProvisioner_warning(t *testing.T) {
|
|
mp := &MockResourceProvisioner{}
|
|
var p ResourceProvisioner = mp
|
|
ctx := &MockEvalContext{}
|
|
|
|
cfg := &ResourceConfig{}
|
|
connInfo, err := config.NewRawConfig(map[string]interface{}{})
|
|
if err != nil {
|
|
t.Fatalf("failed to make connInfo: %s", err)
|
|
}
|
|
connConfig := NewResourceConfig(connInfo)
|
|
|
|
node := &EvalValidateProvisioner{
|
|
Provisioner: &p,
|
|
Config: &cfg,
|
|
ConnConfig: &connConfig,
|
|
}
|
|
|
|
mp.ValidateReturnWarns = []string{"foo is deprecated"}
|
|
|
|
_, err = node.Eval(ctx)
|
|
if err == nil {
|
|
t.Fatalf("node.Eval succeeded; want error")
|
|
}
|
|
|
|
valErr, ok := err.(*EvalValidateError)
|
|
if !ok {
|
|
t.Fatalf("node.Eval error is %#v; want *EvalValidateError", valErr)
|
|
}
|
|
|
|
warns := valErr.Warnings
|
|
if warns == nil || len(warns) != 1 {
|
|
t.Fatalf("wrong number of warnings in %#v; want one warning", warns)
|
|
}
|
|
if warns[0] != mp.ValidateReturnWarns[0] {
|
|
t.Fatalf("wrong warning %q; want %q", warns[0], mp.ValidateReturnWarns[0])
|
|
}
|
|
}
|
|
|
|
func TestEvalValidateProvisioner_connectionInvalid(t *testing.T) {
|
|
var p ResourceProvisioner = &MockResourceProvisioner{}
|
|
ctx := &MockEvalContext{}
|
|
|
|
cfg := &ResourceConfig{}
|
|
connInfo, err := config.NewRawConfig(map[string]interface{}{
|
|
"bananananananana": "foo",
|
|
"bazaz": "bar",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to make connInfo: %s", err)
|
|
}
|
|
connConfig := NewResourceConfig(connInfo)
|
|
|
|
node := &EvalValidateProvisioner{
|
|
Provisioner: &p,
|
|
Config: &cfg,
|
|
ConnConfig: &connConfig,
|
|
}
|
|
|
|
_, err = node.Eval(ctx)
|
|
if err == nil {
|
|
t.Fatalf("node.Eval succeeded; want error")
|
|
}
|
|
|
|
valErr, ok := err.(*EvalValidateError)
|
|
if !ok {
|
|
t.Fatalf("node.Eval error is %#v; want *EvalValidateError", valErr)
|
|
}
|
|
|
|
errs := valErr.Errors
|
|
if errs == nil || len(errs) != 2 {
|
|
t.Fatalf("wrong number of errors in %#v; want two errors", errs)
|
|
}
|
|
|
|
errStr := errs[0].Error()
|
|
if !(strings.Contains(errStr, "bananananananana") || strings.Contains(errStr, "bazaz")) {
|
|
t.Fatalf("wrong first error %q; want something about our invalid connInfo keys", errStr)
|
|
}
|
|
}
|