blob: c6ff96525fe2c20ae45f71e8ca640e7b8c75ac6b [file] [log] [blame] [edit]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package server
import (
"fmt"
"reflect"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func TestLoadConfigFile(t *testing.T) {
testLoadConfigFile(t)
}
func TestLoadConfigFile_json(t *testing.T) {
testLoadConfigFile_json(t)
}
func TestLoadConfigFileIntegerAndBooleanValues(t *testing.T) {
testLoadConfigFileIntegerAndBooleanValues(t)
}
func TestLoadConfigFileIntegerAndBooleanValuesJson(t *testing.T) {
testLoadConfigFileIntegerAndBooleanValuesJson(t)
}
func TestLoadConfigFileWithLeaseMetricTelemetry(t *testing.T) {
testLoadConfigFileLeaseMetrics(t)
}
func TestLoadConfigDir(t *testing.T) {
testLoadConfigDir(t)
}
func TestConfig_Sanitized(t *testing.T) {
testConfig_Sanitized(t)
}
func TestParseListeners(t *testing.T) {
testParseListeners(t)
}
func TestParseUserLockouts(t *testing.T) {
testParseUserLockouts(t)
}
func TestParseSockaddrTemplate(t *testing.T) {
testParseSockaddrTemplate(t)
}
func TestConfigRaftRetryJoin(t *testing.T) {
testConfigRaftRetryJoin(t)
}
func TestParseSeals(t *testing.T) {
testParseSeals(t)
}
func TestParseStorage(t *testing.T) {
testParseStorageTemplate(t)
}
// TestConfigWithAdministrativeNamespace tests that .hcl and .json configurations are correctly parsed when the administrative_namespace_path is present.
func TestConfigWithAdministrativeNamespace(t *testing.T) {
testConfigWithAdministrativeNamespaceHcl(t)
testConfigWithAdministrativeNamespaceJson(t)
}
func TestUnknownFieldValidation(t *testing.T) {
testUnknownFieldValidation(t)
}
func TestUnknownFieldValidationJson(t *testing.T) {
testUnknownFieldValidationJson(t)
}
func TestUnknownFieldValidationHcl(t *testing.T) {
testUnknownFieldValidationHcl(t)
}
func TestUnknownFieldValidationListenerAndStorage(t *testing.T) {
testUnknownFieldValidationStorageAndListener(t)
}
func TestExperimentsConfigParsing(t *testing.T) {
const envKey = "VAULT_EXPERIMENTS"
originalValue := validExperiments
validExperiments = []string{"foo", "bar", "baz"}
t.Cleanup(func() {
validExperiments = originalValue
})
for name, tc := range map[string]struct {
fromConfig []string
fromEnv []string
fromCLI []string
expected []string
expectedError string
}{
// Multiple sources.
"duplication": {[]string{"foo"}, []string{"foo"}, []string{"foo"}, []string{"foo"}, ""},
"disjoint set": {[]string{"foo"}, []string{"bar"}, []string{"baz"}, []string{"foo", "bar", "baz"}, ""},
// Single source.
"config only": {[]string{"foo"}, nil, nil, []string{"foo"}, ""},
"env only": {nil, []string{"foo"}, nil, []string{"foo"}, ""},
"CLI only": {nil, nil, []string{"foo"}, []string{"foo"}, ""},
// Validation errors.
"config invalid": {[]string{"invalid"}, nil, nil, nil, "from config"},
"env invalid": {nil, []string{"invalid"}, nil, nil, "from environment variable"},
"CLI invalid": {nil, nil, []string{"invalid"}, nil, "from command line flag"},
} {
t.Run(name, func(t *testing.T) {
var configString string
t.Setenv(envKey, strings.Join(tc.fromEnv, ","))
if len(tc.fromConfig) != 0 {
configString = fmt.Sprintf("experiments = [\"%s\"]", strings.Join(tc.fromConfig, "\", \""))
}
config, err := ParseConfig(configString, "")
if err == nil {
err = ExperimentsFromEnvAndCLI(config, envKey, tc.fromCLI)
}
switch tc.expectedError {
case "":
if err != nil {
t.Fatal(err)
}
default:
if err == nil || !strings.Contains(err.Error(), tc.expectedError) {
t.Fatalf("Expected error to contain %q, but got: %s", tc.expectedError, err)
}
}
})
}
}
func TestValidate(t *testing.T) {
originalValue := validExperiments
for name, tc := range map[string]struct {
validSet []string
input []string
expectError bool
}{
// Valid cases
"minimal valid": {[]string{"foo"}, []string{"foo"}, false},
"valid subset": {[]string{"foo", "bar"}, []string{"bar"}, false},
"repeated": {[]string{"foo"}, []string{"foo", "foo"}, false},
// Error cases
"partially valid": {[]string{"foo", "bar"}, []string{"foo", "baz"}, true},
"empty": {[]string{"foo"}, []string{""}, true},
"no valid experiments": {[]string{}, []string{"foo"}, true},
} {
t.Run(name, func(t *testing.T) {
t.Cleanup(func() {
validExperiments = originalValue
})
validExperiments = tc.validSet
err := validateExperiments(tc.input)
if tc.expectError && err == nil {
t.Fatal("Expected error but got none")
}
if !tc.expectError && err != nil {
t.Fatal("Did not expect error but got", err)
}
})
}
}
func TestMerge(t *testing.T) {
for name, tc := range map[string]struct {
left []string
right []string
expected []string
}{
"disjoint": {[]string{"foo"}, []string{"bar"}, []string{"foo", "bar"}},
"empty left": {[]string{}, []string{"foo"}, []string{"foo"}},
"empty right": {[]string{"foo"}, []string{}, []string{"foo"}},
"overlapping": {[]string{"foo", "bar"}, []string{"foo", "baz"}, []string{"foo", "bar", "baz"}},
} {
t.Run(name, func(t *testing.T) {
result := mergeExperiments(tc.left, tc.right)
if !reflect.DeepEqual(tc.expected, result) {
t.Fatalf("Expected %v but got %v", tc.expected, result)
}
})
}
}
// Test_parseDevTLSConfig verifies that both Windows and Unix directories are correctly escaped when creating a dev TLS
// configuration in HCL
func Test_parseDevTLSConfig(t *testing.T) {
tests := []struct {
name string
certDirectory string
}{
{
name: "windows path",
certDirectory: `C:\Users\ADMINI~1\AppData\Local\Temp\2\vault-tls4169358130`,
},
{
name: "unix path",
certDirectory: "/tmp/vault-tls4169358130",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg, err := parseDevTLSConfig("file", tt.certDirectory)
require.NoError(t, err)
require.Equal(t, fmt.Sprintf("%s/%s", tt.certDirectory, VaultDevCertFilename), cfg.Listeners[0].TLSCertFile)
require.Equal(t, fmt.Sprintf("%s/%s", tt.certDirectory, VaultDevKeyFilename), cfg.Listeners[0].TLSKeyFile)
})
}
}