mirror of https://github.com/hashicorp/terraform
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
841 lines
18 KiB
841 lines
18 KiB
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package s3
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/aws/arn"
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
func TestValidateKMSKey(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
in string
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"kms key id": {
|
|
in: "57ff7a43-341d-46b6-aee3-a450c9de6dc8",
|
|
},
|
|
"kms key arn": {
|
|
in: "arn:aws:kms:us-west-2:111122223333:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8",
|
|
},
|
|
"kms multi-region key id": {
|
|
in: "mrk-f827515944fb43f9b902a09d2c8b554f",
|
|
},
|
|
"kms multi-region key arn": {
|
|
in: "arn:aws:kms:us-west-2:111122223333:key/mrk-a835af0b39c94b86a21a8fc9535df681",
|
|
},
|
|
"kms key alias": {
|
|
in: "alias/arbitrary-key",
|
|
},
|
|
"kms key alias arn": {
|
|
in: "arn:aws:kms:us-west-2:111122223333:alias/arbitrary-key",
|
|
},
|
|
"invalid key": {
|
|
in: "$%wrongkey",
|
|
expected: tfdiags.Diagnostics{
|
|
tfdiags.AttributeValue(
|
|
tfdiags.Error,
|
|
"Invalid KMS Key ID",
|
|
`Value must be a valid KMS Key ID, got "$%wrongkey"`,
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
"non-kms arn": {
|
|
in: "arn:aws:lamda:foo:bar:key/xyz",
|
|
expected: tfdiags.Diagnostics{
|
|
tfdiags.AttributeValue(
|
|
tfdiags.Error,
|
|
"Invalid KMS Key ARN",
|
|
`Value must be a valid KMS Key ARN, got "arn:aws:lamda:foo:bar:key/xyz"`,
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
diags := validateKMSKey(path, testcase.in)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateKeyARN(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
in string
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"kms key id": {
|
|
in: "arn:aws:kms:us-west-2:123456789012:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8",
|
|
},
|
|
"kms mrk key id": {
|
|
in: "arn:aws:kms:us-west-2:111122223333:key/mrk-a835af0b39c94b86a21a8fc9535df681",
|
|
},
|
|
"kms non-key id": {
|
|
in: "arn:aws:kms:us-west-2:123456789012:something/else",
|
|
expected: tfdiags.Diagnostics{
|
|
tfdiags.AttributeValue(
|
|
tfdiags.Error,
|
|
"Invalid KMS Key ARN",
|
|
`Value must be a valid KMS Key ARN, got "arn:aws:kms:us-west-2:123456789012:something/else"`,
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
"non-kms arn": {
|
|
in: "arn:aws:iam::123456789012:user/David",
|
|
expected: tfdiags.Diagnostics{
|
|
tfdiags.AttributeValue(
|
|
tfdiags.Error,
|
|
"Invalid KMS Key ARN",
|
|
`Value must be a valid KMS Key ARN, got "arn:aws:iam::123456789012:user/David"`,
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
"not an arn": {
|
|
in: "not an arn",
|
|
expected: tfdiags.Diagnostics{
|
|
tfdiags.AttributeValue(
|
|
tfdiags.Error,
|
|
"Invalid KMS Key ARN",
|
|
`Value must be a valid KMS Key ARN, got "not an arn"`,
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
diags := validateKMSKeyARN(path, testcase.in)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateStringLenBetween(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const min, max = 2, 5
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
val string
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"valid": {
|
|
val: "valid",
|
|
},
|
|
|
|
"too short": {
|
|
val: "x",
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid Value Length",
|
|
fmt.Sprintf("Length must be between %d and %d, had %d", min, max, 1),
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
|
|
"too long": {
|
|
val: "a very long string",
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid Value Length",
|
|
fmt.Sprintf("Length must be between %d and %d, had %d", min, max, 18),
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var diags tfdiags.Diagnostics
|
|
validateStringLenBetween(min, max)(testcase.val, path, &diags)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateStringMatches(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
val string
|
|
re *regexp.Regexp
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"valid": {
|
|
val: "ok",
|
|
re: regexp.MustCompile(`^o[j-l]?$`),
|
|
},
|
|
|
|
"invalid": {
|
|
val: "not ok",
|
|
re: regexp.MustCompile(`^o[j-l]?$`),
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid Value",
|
|
"Value must be like ok",
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var diags tfdiags.Diagnostics
|
|
validateStringMatches(testcase.re, "Value must be like ok")(testcase.val, path, &diags)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateARN(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
val string
|
|
validator arnValidator
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"valid": {
|
|
val: "arn:aws:kms:us-west-2:111122223333:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8",
|
|
},
|
|
|
|
"invalid": {
|
|
val: "not an ARN",
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid ARN",
|
|
fmt.Sprintf("The value %q cannot be parsed as an ARN: %s", "not an ARN", arnParseError("not an ARN")),
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
|
|
"fails validator": {
|
|
val: "arn:aws:kms:us-west-2:111122223333:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8",
|
|
validator: func(val arn.ARN, path cty.Path, diags *tfdiags.Diagnostics) {
|
|
*diags = diags.Append(attributeErrDiag(
|
|
"Test",
|
|
"Test",
|
|
path,
|
|
))
|
|
},
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Test",
|
|
"Test",
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var validators []arnValidator
|
|
if testcase.validator != nil {
|
|
validators = []arnValidator{
|
|
testcase.validator,
|
|
}
|
|
}
|
|
|
|
var diags tfdiags.Diagnostics
|
|
validateARN(validators...)(testcase.val, path, &diags)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func arnParseError(s string) error {
|
|
_, err := arn.Parse(s)
|
|
return err
|
|
}
|
|
|
|
func TestValidateIAMPolicyDocument(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
val string
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"empty object": {
|
|
val: `{}`,
|
|
// Valid JSON, not valid IAM policy (but passes provider's test)
|
|
},
|
|
"array": {
|
|
val: `{"abc":["1","2"]}`,
|
|
// Valid JSON, not valid IAM policy (but passes provider's test)
|
|
},
|
|
"invalid key": {
|
|
val: `{0:"1"}`,
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid JSON Document",
|
|
"The JSON document contains an error: invalid character '0' looking for beginning of object key string, at byte offset 2",
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
"leading whitespace": {
|
|
val: ` {"xyz": "foo"}`,
|
|
// Valid, must be trimmed before passing to AWS
|
|
},
|
|
"is a string": {
|
|
val: `"blub"`,
|
|
// Valid JSON, not valid IAM policy
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid IAM Policy Document",
|
|
`Expected a JSON object describing the policy, had a JSON-encoded string.`,
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
"contains filename": {
|
|
val: `"../some-filename.json"`,
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid IAM Policy Document",
|
|
`Expected a JSON object describing the policy, had a JSON-encoded string.
|
|
|
|
The string "../some-filename.json" looks like a filename, please pass the contents of the file instead of the filename.`,
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
"double encoded": {
|
|
val: `"{\"Version\":\"...\"}"`,
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid IAM Policy Document",
|
|
`Expected a JSON object describing the policy, had a JSON-encoded string.
|
|
|
|
The string content was valid JSON, your policy document may have been double-encoded.`,
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var diags tfdiags.Diagnostics
|
|
validateIAMPolicyDocument(testcase.val, path, &diags)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateSetStringElements(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
val cty.Value
|
|
validator stringValidator
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"valid": {
|
|
val: cty.SetVal([]cty.Value{
|
|
cty.StringVal("valid"),
|
|
cty.StringVal("also valid"),
|
|
}),
|
|
},
|
|
|
|
"fails validator": {
|
|
val: cty.SetVal([]cty.Value{
|
|
cty.StringVal("valid"),
|
|
cty.StringVal("invalid"),
|
|
}),
|
|
validator: func(val string, path cty.Path, diags *tfdiags.Diagnostics) {
|
|
if val == "invalid" {
|
|
*diags = diags.Append(attributeErrDiag(
|
|
"Test",
|
|
"Test",
|
|
path,
|
|
))
|
|
}
|
|
},
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Test",
|
|
"Test",
|
|
path.Index(cty.StringVal("invalid")),
|
|
),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var validators []stringValidator
|
|
if testcase.validator != nil {
|
|
validators = []stringValidator{
|
|
testcase.validator,
|
|
}
|
|
}
|
|
|
|
var diags tfdiags.Diagnostics
|
|
validateSetStringElements(validators...)(testcase.val, path, &diags)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// func TestValidateStringSetValues(t *testing.T) {
|
|
// t.Parallel()
|
|
|
|
// path := cty.GetAttrPath("field")
|
|
|
|
// testcases := map[string]struct {
|
|
// val []string
|
|
// validator stringValidator
|
|
// expected tfdiags.Diagnostics
|
|
// }{
|
|
// "valid": {
|
|
// val: []string{
|
|
// "valid",
|
|
// "also valid",
|
|
// },
|
|
// },
|
|
|
|
// "fails validator": {
|
|
// val: []string{
|
|
// "valid",
|
|
// "invalid",
|
|
// },
|
|
// validator: func(val string, path cty.Path, diags *tfdiags.Diagnostics) {
|
|
// if val == "invalid" {
|
|
// *diags = diags.Append(attributeErrDiag(
|
|
// "Test",
|
|
// "Test",
|
|
// path,
|
|
// ))
|
|
// }
|
|
// },
|
|
// expected: tfdiags.Diagnostics{
|
|
// attributeErrDiag(
|
|
// "Test",
|
|
// "Test",
|
|
// path.Index(cty.StringVal("invalid")),
|
|
// ),
|
|
// },
|
|
// },
|
|
// }
|
|
|
|
// for name, testcase := range testcases {
|
|
// testcase := testcase
|
|
// t.Run(name, func(t *testing.T) {
|
|
// t.Parallel()
|
|
|
|
// var validators []stringValidator
|
|
// if testcase.validator != nil {
|
|
// validators = []stringValidator{
|
|
// testcase.validator,
|
|
// }
|
|
// }
|
|
|
|
// var diags tfdiags.Diagnostics
|
|
// validateStringSetValues(validators...)(testcase.val, path, &diags)
|
|
|
|
// if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
// t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
// }
|
|
// })
|
|
// }
|
|
// }
|
|
|
|
func TestValidateDuration(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
val string
|
|
validator durationValidator
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"valid": {
|
|
val: "1h",
|
|
},
|
|
|
|
"invalid": {
|
|
val: "one hour",
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid Duration",
|
|
fmt.Sprintf("The value %q cannot be parsed as a duration: %s", "one hour", durationParseError("one hour")),
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
|
|
"fails validator": {
|
|
val: "1h",
|
|
validator: func(val time.Duration, path cty.Path, diags *tfdiags.Diagnostics) {
|
|
*diags = diags.Append(attributeErrDiag(
|
|
"Test",
|
|
"Test",
|
|
path,
|
|
))
|
|
},
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Test",
|
|
"Test",
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var validators []durationValidator
|
|
if testcase.validator != nil {
|
|
validators = []durationValidator{
|
|
testcase.validator,
|
|
}
|
|
}
|
|
|
|
var diags tfdiags.Diagnostics
|
|
validateDuration(validators...)(testcase.val, path, &diags)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func durationParseError(s string) error {
|
|
_, err := time.ParseDuration(s)
|
|
return err
|
|
}
|
|
|
|
func TestValidateDurationBetween(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const min, max = 15 * time.Minute, 12 * time.Hour
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
val time.Duration
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"valid": {
|
|
val: 1 * time.Hour,
|
|
},
|
|
|
|
"too short": {
|
|
val: 1 * time.Minute,
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid Duration",
|
|
fmt.Sprintf("Duration must be between %s and %s, had %s", min, max, 1*time.Minute),
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
|
|
"too long": {
|
|
val: 24 * time.Hour,
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid Duration",
|
|
fmt.Sprintf("Duration must be between %s and %s, had %s", min, max, 24*time.Hour),
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var diags tfdiags.Diagnostics
|
|
validateDurationBetween(min, max)(testcase.val, path, &diags)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateStringLegacyURL(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
val string
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"no trailing slash": {
|
|
val: "https://domain.test",
|
|
},
|
|
|
|
"no path": {
|
|
val: "https://domain.test/",
|
|
},
|
|
|
|
"with path": {
|
|
val: "https://domain.test/path",
|
|
},
|
|
|
|
"with port no trailing slash": {
|
|
val: "https://domain.test:1234",
|
|
},
|
|
|
|
"with port no path": {
|
|
val: "https://domain.test:1234/",
|
|
},
|
|
|
|
"with port with path": {
|
|
val: "https://domain.test:1234/path",
|
|
},
|
|
|
|
"no scheme no trailing slash": {
|
|
val: "domain.test",
|
|
expected: tfdiags.Diagnostics{
|
|
legacyIncompleteURLDiag("domain.test", path),
|
|
},
|
|
},
|
|
|
|
"no scheme no path": {
|
|
val: "domain.test/",
|
|
expected: tfdiags.Diagnostics{
|
|
legacyIncompleteURLDiag("domain.test/", path),
|
|
},
|
|
},
|
|
|
|
"no scheme with path": {
|
|
val: "domain.test/path",
|
|
expected: tfdiags.Diagnostics{
|
|
legacyIncompleteURLDiag("domain.test/path", path),
|
|
},
|
|
},
|
|
|
|
"no scheme with port": {
|
|
val: "domain.test:1234",
|
|
expected: tfdiags.Diagnostics{
|
|
legacyIncompleteURLDiag("domain.test:1234", path),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var diags tfdiags.Diagnostics
|
|
validateStringLegacyURL(testcase.val, path, &diags)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateStringValidURL(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
val string
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"no trailing slash": {
|
|
val: "https://domain.test",
|
|
},
|
|
|
|
"no path": {
|
|
val: "https://domain.test/",
|
|
},
|
|
|
|
"with path": {
|
|
val: "https://domain.test/path",
|
|
},
|
|
|
|
"with port no trailing slash": {
|
|
val: "https://domain.test:1234",
|
|
},
|
|
|
|
"with port no path": {
|
|
val: "https://domain.test:1234/",
|
|
},
|
|
|
|
"with port with path": {
|
|
val: "https://domain.test:1234/path",
|
|
},
|
|
|
|
"no scheme no trailing slash": {
|
|
val: "domain.test",
|
|
expected: tfdiags.Diagnostics{
|
|
invalidURLDiag("domain.test", path),
|
|
},
|
|
},
|
|
|
|
"no scheme no path": {
|
|
val: "domain.test/",
|
|
expected: tfdiags.Diagnostics{
|
|
invalidURLDiag("domain.test/", path),
|
|
},
|
|
},
|
|
|
|
"no scheme with path": {
|
|
val: "domain.test/path",
|
|
expected: tfdiags.Diagnostics{
|
|
invalidURLDiag("domain.test/path", path),
|
|
},
|
|
},
|
|
|
|
"no scheme with port": {
|
|
val: "domain.test:1234",
|
|
expected: tfdiags.Diagnostics{
|
|
invalidURLDiag("domain.test:1234", path),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var diags tfdiags.Diagnostics
|
|
validateStringValidURL(testcase.val, path, &diags)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_validateStringDoesNotContain(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := cty.GetAttrPath("field")
|
|
|
|
testcases := map[string]struct {
|
|
val string
|
|
s string
|
|
expected tfdiags.Diagnostics
|
|
}{
|
|
"valid": {
|
|
val: "foo",
|
|
s: "bar",
|
|
},
|
|
|
|
"invalid": {
|
|
val: "foobarbaz",
|
|
s: "bar",
|
|
expected: tfdiags.Diagnostics{
|
|
attributeErrDiag(
|
|
"Invalid Value",
|
|
`Value must not contain "bar"`,
|
|
path,
|
|
),
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, testcase := range testcases {
|
|
testcase := testcase
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var diags tfdiags.Diagnostics
|
|
validateStringDoesNotContain(testcase.s)(testcase.val, path, &diags)
|
|
|
|
if diff := cmp.Diff(diags, testcase.expected, tfdiags.DiagnosticComparer); diff != "" {
|
|
t.Errorf("unexpected diagnostics difference: %s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|