test(configuration): add some additional coverage (#5485)

Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>
pull/5508/head
James Elliott 2023-05-31 20:50:22 +10:00 committed by GitHub
parent 8a24d422c1
commit 4c98da0d29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 384 additions and 25 deletions

View File

@ -634,11 +634,11 @@ func StringToPasswordDigestHookFunc() mapstructure.DecodeHookFuncType {
var result *schema.PasswordDigest var result *schema.PasswordDigest
if dataStr != "" {
if !strings.HasPrefix(dataStr, "$") { if !strings.HasPrefix(dataStr, "$") {
dataStr = fmt.Sprintf(plaintext.EncodingFmt, plaintext.AlgIdentifierPlainText, dataStr) dataStr = fmt.Sprintf(plaintext.EncodingFmt, plaintext.AlgIdentifierPlainText, dataStr)
} }
if dataStr != "" {
if result, err = schema.DecodePasswordDigest(dataStr); err != nil { if result, err = schema.DecodePasswordDigest(dataStr); err != nil {
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParse, dataStr, prefixType, expectedType.String(), err) return nil, fmt.Errorf(errFmtDecodeHookCouldNotParse, dataStr, prefixType, expectedType.String(), err)
} }

View File

@ -4,8 +4,10 @@ import (
"bytes" "bytes"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/rsa" "crypto/rsa"
"crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"fmt"
"math" "math"
"net/mail" "net/mail"
"net/url" "net/url"
@ -786,24 +788,6 @@ func TestStringToRegexpFuncPointers(t *testing.T) {
} }
func TestStringToAddressHookFunc(t *testing.T) { func TestStringToAddressHookFunc(t *testing.T) {
mustParseAddress := func(a string) (addr schema.Address) {
addrs, err := schema.NewAddress(a)
if err != nil {
panic(err)
}
return *addrs
}
mustParseAddressPtr := func(a string) (addr *schema.Address) {
addr, err := schema.NewAddress(a)
if err != nil {
panic(err)
}
return addr
}
testCases := []struct { testCases := []struct {
name string name string
have any have any
@ -814,13 +798,13 @@ func TestStringToAddressHookFunc(t *testing.T) {
{ {
name: "ShouldDecodeNonPtr", name: "ShouldDecodeNonPtr",
have: "tcp://0.0.0.0:2020", have: "tcp://0.0.0.0:2020",
expected: mustParseAddress("tcp://0.0.0.0:2020"), expected: MustParseAddress("tcp://0.0.0.0:2020"),
decode: true, decode: true,
}, },
{ {
name: "ShouldDecodePtr", name: "ShouldDecodePtr",
have: "tcp://0.0.0.0:2020", have: "tcp://0.0.0.0:2020",
expected: mustParseAddressPtr("tcp://0.0.0.0:2020"), expected: MustParseAddressPtr("tcp://0.0.0.0:2020"),
decode: true, decode: true,
}, },
{ {
@ -872,6 +856,90 @@ func TestStringToAddressHookFunc(t *testing.T) {
err: "could not decode 'tcp://&!@^#*&!@#&*@!:2020' to a schema.Address: could not parse string 'tcp://&!@^#*&!@#&*@!:2020' as address: expected format is [<scheme>://]<hostname>[:<port>]: parse \"tcp://&!@^\": invalid character \"^\" in host name", err: "could not decode 'tcp://&!@^#*&!@#&*@!:2020' to a schema.Address: could not parse string 'tcp://&!@^#*&!@#&*@!:2020' as address: expected format is [<scheme>://]<hostname>[:<port>]: parse \"tcp://&!@^\": invalid character \"^\" in host name",
decode: false, decode: false,
}, },
{
name: "ShouldDecodeTCP",
have: "tcp://127.0.0.1",
expected: schema.AddressTCP{Address: MustParseAddress("tcp://127.0.0.1")},
err: "",
decode: true,
},
{
name: "ShouldDecodeTCPPtr",
have: "tcp://127.0.0.1",
expected: &schema.AddressTCP{Address: MustParseAddress("tcp://127.0.0.1")},
err: "",
decode: true,
},
{
name: "ShouldDecodeUDP",
have: "udp://127.0.0.1",
expected: schema.AddressUDP{Address: MustParseAddress("udp://127.0.0.1")},
err: "",
decode: true,
},
{
name: "ShouldDecodeUDPPtr",
have: "udp://127.0.0.1",
expected: &schema.AddressUDP{Address: MustParseAddress("udp://127.0.0.1")},
err: "",
decode: true,
},
{
name: "ShouldDecodeLDAP",
have: "ldap://127.0.0.1",
expected: schema.AddressLDAP{Address: MustParseAddress("ldap://127.0.0.1")},
err: "",
decode: true,
},
{
name: "ShouldDecodeLDAPPtr",
have: "ldap://127.0.0.1",
expected: &schema.AddressLDAP{Address: MustParseAddress("ldap://127.0.0.1")},
err: "",
decode: true,
},
{
name: "ShouldDecodeSMTP",
have: "smtp://127.0.0.1",
expected: schema.AddressSMTP{Address: MustParseAddress("smtp://127.0.0.1")},
err: "",
decode: true,
},
{
name: "ShouldDecodeSMTPPtr",
have: "smtp://127.0.0.1",
expected: &schema.AddressSMTP{Address: MustParseAddress("smtp://127.0.0.1")},
err: "",
decode: true,
},
{
name: "ShouldFailDecodeTCP",
have: "@@@@@@@",
expected: schema.AddressTCP{Address: MustParseAddress("tcp://127.0.0.1")},
err: "could not decode '@@@@@@@' to a schema.AddressTCP: error validating the address: the url 'tcp://%40%40%40%40%40%40@' appears to have user info but this is not valid for addresses",
decode: false,
},
{
name: "ShouldFailDecodeUDP",
have: "@@@@@@@",
expected: schema.AddressUDP{Address: MustParseAddress("udp://127.0.0.1")},
err: "could not decode '@@@@@@@' to a schema.AddressUDP: error validating the address: the url 'udp://%40%40%40%40%40%40@' appears to have user info but this is not valid for addresses",
decode: false,
},
{
name: "ShouldFailDecodeLDAP",
have: "@@@@@@@",
expected: schema.AddressLDAP{Address: MustParseAddress("ldap://127.0.0.1")},
err: "could not decode '@@@@@@@' to a schema.AddressLDAP: error validating the address: the url 'ldaps://%40%40%40%40%40%40@' appears to have user info but this is not valid for addresses",
decode: false,
},
{
name: "ShouldFailDecodeSMTP",
have: "@@@@@@@",
expected: schema.AddressSMTP{Address: MustParseAddress("smtp://127.0.0.1")},
err: "could not decode '@@@@@@@' to a schema.AddressSMTP: error validating the address: the url 'smtp://%40%40%40%40%40%40@' appears to have user info but this is not valid for addresses",
decode: false,
},
} }
hook := configuration.StringToAddressHookFunc() hook := configuration.StringToAddressHookFunc()
@ -1095,6 +1163,160 @@ func TestStringToX509CertificateHookFunc(t *testing.T) {
} }
} }
func TestStringToPasswordDigestHookFunc(t *testing.T) {
var nilvalue *schema.PasswordDigest
testCases := []struct {
name string
have any
expected any
err string
decode bool
}{
{
"ShouldParse",
"$plaintext$example",
MustParsePasswordDigest("$plaintext$example"),
"",
true,
},
{
"ShouldParsePtr",
"$plaintext$example",
MustParsePasswordDigestPtr("$plaintext$example"),
"",
true,
},
{
"ShouldNotParseUnknown",
"$abc$example",
schema.PasswordDigest{},
"could not decode '$abc$example' to a schema.PasswordDigest: provided encoded hash has an invalid identifier: the identifier 'abc' is unknown to the decoder",
false,
},
{
"ShouldNotParseWrongType",
"$abc$example",
schema.TLSVersion{},
"",
false,
},
{
"ShouldNotParseWrongTypePtr",
"$abc$example",
&schema.TLSVersion{},
"",
false,
},
{
"ShouldNotParseEmptyString",
"",
schema.PasswordDigest{},
"could not decode an empty value to a schema.PasswordDigest: must have a non-empty value",
false,
},
{
"ShouldParseEmptyStringPtr",
"",
nilvalue,
"",
true,
},
}
hook := configuration.StringToPasswordDigestHookFunc()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.expected), tc.have)
if tc.err != "" {
assert.EqualError(t, err, tc.err)
if !tc.decode {
assert.Nil(t, actual)
}
} else {
assert.NoError(t, err)
if tc.decode {
assert.Equal(t, tc.expected, actual)
} else {
assert.Equal(t, tc.have, actual)
}
}
})
}
}
func TestStringToTLSVersionHookFunc(t *testing.T) {
testCases := []struct {
name string
have any
expected any
err string
decode bool
}{
{
"ShouldParseTLS1.3",
"TLS1.3",
schema.TLSVersion{Value: tls.VersionTLS13},
"",
true,
},
{
"ShouldParseTLS1.3PTR",
"TLS1.3",
&schema.TLSVersion{Value: tls.VersionTLS13},
"",
true,
},
{
"ShouldParseTLS1.2",
"TLS1.2",
schema.TLSVersion{Value: tls.VersionTLS12},
"",
true,
},
{
"ShouldNotParseInt",
1,
&schema.TLSVersion{},
"",
false,
},
{
"ShouldNotParseNonVersion",
"1",
&schema.TLSVersion{},
"could not decode '1' to a *schema.TLSVersion: supplied tls version isn't supported",
false,
},
}
hook := configuration.StringToTLSVersionHookFunc()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual, err := hook(reflect.TypeOf(tc.have), reflect.TypeOf(tc.expected), tc.have)
if tc.err != "" {
assert.EqualError(t, err, tc.err)
if !tc.decode {
assert.Nil(t, actual)
}
} else {
assert.NoError(t, err)
if tc.decode {
assert.Equal(t, tc.expected, actual)
} else {
assert.Equal(t, tc.have, actual)
}
}
})
}
}
func TestStringToX509CertificateChainHookFunc(t *testing.T) { func TestStringToX509CertificateChainHookFunc(t *testing.T) {
var nilkey *schema.X509CertificateChain var nilkey *schema.X509CertificateChain
@ -1411,3 +1633,42 @@ var (
testZero int32 testZero int32
testString = "" testString = ""
) )
func MustParseAddress(input string) schema.Address {
address, err := schema.NewAddress(input)
if err != nil {
panic(err)
}
fmt.Println(address.String())
addr := *address
return addr
}
func MustParseAddressPtr(input string) *schema.Address {
address, err := schema.NewAddress(input)
if err != nil {
panic(err)
}
return address
}
func MustParsePasswordDigest(input string) schema.PasswordDigest {
digest, err := schema.DecodePasswordDigest(input)
if err != nil {
panic(err)
}
return *digest
}
func MustParsePasswordDigestPtr(input string) *schema.PasswordDigest {
digest, err := schema.DecodePasswordDigest(input)
if err != nil {
panic(err)
}
return digest
}

View File

@ -6,6 +6,7 @@ import (
"runtime" "runtime"
"testing" "testing"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -125,3 +126,85 @@ func TestKoanfSecretCallbackShouldErrorOnFSError(t *testing.T) {
assert.Len(t, val.Warnings(), 0) assert.Len(t, val.Warnings(), 0)
assert.EqualError(t, val.Errors()[0], fmt.Sprintf("secrets: error loading secret path %s into key 'theme': file permission error occurred: open %s: permission denied", secret, secret)) assert.EqualError(t, val.Errors()[0], fmt.Sprintf("secrets: error loading secret path %s into key 'theme': file permission error occurred: open %s: permission denied", secret, secret))
} }
func TestKoanfCommandLineWithMappingCallback(t *testing.T) {
testCases := []struct {
name string
have []string
flagName string
flagValue string
mapped string
valid bool
unchanged bool
expectedName string
expectedValue any
}{
{
"ShouldDecodeStandard",
[]string{"--commands", "abc"},
"commands",
"",
"command.another",
false,
false,
"command.another",
"abc",
},
{
"ShouldSkipUnchangedKey",
[]string{},
"commands",
"abc",
"command.another",
false,
false,
"",
nil,
},
{
"ShouldLookupNormalizedKey",
[]string{"--log.file-path", "abc"},
"log.file-path",
"",
"",
true,
false,
"log.file_path",
"abc",
},
{
"ShouldReturnUnmodified",
[]string{"--commands", "abc"},
"commands",
"",
"",
false,
false,
"",
nil,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
flagset := pflag.NewFlagSet("test", pflag.ContinueOnError)
flagset.String(tc.flagName, tc.flagValue, "")
assert.NoError(t, flagset.Parse(tc.have))
mapper := map[string]string{}
if tc.mapped != "" {
mapper[tc.flagName] = tc.mapped
}
callback := koanfCommandLineWithMappingCallback(mapper, tc.valid, tc.unchanged)
actualName, actualValue := callback(flagset.Lookup(tc.flagName))
assert.Equal(t, tc.expectedName, actualName)
assert.Equal(t, tc.expectedValue, actualValue)
})
}
}

View File

@ -268,6 +268,21 @@ func TestX509CertificateChain(t *testing.T) {
assert.Regexp(t, regexp.MustCompile(`^certificate #1 in chain is invalid before 13569465600 but the time is \d+$`), err.Error()) assert.Regexp(t, regexp.MustCompile(`^certificate #1 in chain is invalid before 13569465600 but the time is \d+$`), err.Error())
} }
func TestPasswordDigest_IsPlainText(t *testing.T) {
digest, err := DecodePasswordDigest("$plaintext$exam")
assert.NoError(t, err)
assert.True(t, digest.IsPlainText())
digest = &PasswordDigest{}
assert.False(t, digest.IsPlainText())
digest, err = DecodePasswordDigest("$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng")
assert.NoError(t, err)
assert.False(t, digest.IsPlainText())
}
func MustParseX509CertificateChain(data string) *X509CertificateChain { func MustParseX509CertificateChain(data string) *X509CertificateChain {
chain, err := NewX509CertificateChain(data) chain, err := NewX509CertificateChain(data)
if err != nil { if err != nil {

View File

@ -21,7 +21,7 @@ type FileSource struct {
filters []FileFilter filters []FileFilter
} }
// EnvironmentSource is a configuration configuration.Source which loads values from the environment. // EnvironmentSource is a configuration.Source which loads values from the environment.
type EnvironmentSource struct { type EnvironmentSource struct {
koanf *koanf.Koanf koanf *koanf.Koanf
prefix string prefix string