225 lines
5.5 KiB
Go
225 lines
5.5 KiB
Go
// File: lixenwraith/config/env_test.go
|
|
package config_test
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/lixenwraith/config"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestEnvironmentVariables(t *testing.T) {
|
|
t.Run("Basic Environment Loading", func(t *testing.T) {
|
|
// Set up environment
|
|
envVars := map[string]string{
|
|
"TEST_SERVER_HOST": "env-host",
|
|
"TEST_SERVER_PORT": "9999",
|
|
"TEST_DEBUG": "true",
|
|
}
|
|
for k, v := range envVars {
|
|
os.Setenv(k, v)
|
|
defer os.Unsetenv(k)
|
|
}
|
|
|
|
cfg := config.New()
|
|
cfg.Register("server.host", "default-host")
|
|
cfg.Register("server.port", 8080)
|
|
cfg.Register("debug", false)
|
|
|
|
// Load environment variables
|
|
err := cfg.LoadEnv("TEST_")
|
|
require.NoError(t, err)
|
|
|
|
// Verify values
|
|
host, _ := cfg.String("server.host")
|
|
assert.Equal(t, "env-host", host)
|
|
|
|
port, _ := cfg.Int64("server.port")
|
|
assert.Equal(t, int64(9999), port)
|
|
|
|
debug, _ := cfg.Bool("debug")
|
|
assert.True(t, debug)
|
|
})
|
|
|
|
t.Run("Custom Environment Transform", func(t *testing.T) {
|
|
os.Setenv("PORT", "3000")
|
|
os.Setenv("DATABASE_URL", "postgres://localhost/test")
|
|
defer func() {
|
|
os.Unsetenv("PORT")
|
|
os.Unsetenv("DATABASE_URL")
|
|
}()
|
|
|
|
cfg := config.New()
|
|
cfg.Register("server.port", 8080)
|
|
cfg.Register("database.url", "sqlite://memory")
|
|
|
|
opts := config.LoadOptions{
|
|
Sources: []config.Source{config.SourceEnv, config.SourceDefault},
|
|
EnvTransform: func(path string) string {
|
|
mapping := map[string]string{
|
|
"server.port": "PORT",
|
|
"database.url": "DATABASE_URL",
|
|
}
|
|
return mapping[path]
|
|
},
|
|
}
|
|
|
|
err := cfg.LoadWithOptions("", nil, opts)
|
|
require.NoError(t, err)
|
|
|
|
port, _ := cfg.Int64("server.port")
|
|
assert.Equal(t, int64(3000), port)
|
|
|
|
dbURL, _ := cfg.String("database.url")
|
|
assert.Equal(t, "postgres://localhost/test", dbURL)
|
|
})
|
|
|
|
t.Run("Environment Discovery", func(t *testing.T) {
|
|
// Set up various env vars
|
|
envVars := map[string]string{
|
|
"APP_SERVER_HOST": "discovered",
|
|
"APP_SERVER_PORT": "4444",
|
|
"APP_UNREGISTERED": "ignored",
|
|
}
|
|
for k, v := range envVars {
|
|
os.Setenv(k, v)
|
|
defer os.Unsetenv(k)
|
|
}
|
|
|
|
cfg := config.New()
|
|
cfg.Register("server.host", "default")
|
|
cfg.Register("server.port", 8080)
|
|
cfg.Register("server.timeout", 30)
|
|
|
|
// Discover which registered paths have env vars
|
|
discovered := cfg.DiscoverEnv("APP_")
|
|
|
|
// Should find 2 env vars
|
|
assert.Len(t, discovered, 2)
|
|
assert.Equal(t, "APP_SERVER_HOST", discovered["server.host"])
|
|
assert.Equal(t, "APP_SERVER_PORT", discovered["server.port"])
|
|
assert.NotContains(t, discovered, "unregistered")
|
|
})
|
|
|
|
t.Run("Environment Whitelist", func(t *testing.T) {
|
|
envVars := map[string]string{
|
|
"SECRET_API_KEY": "secret-value",
|
|
"SECRET_DATABASE_PASSWORD": "db-pass",
|
|
"SECRET_SERVER_PORT": "5555",
|
|
}
|
|
for k, v := range envVars {
|
|
os.Setenv(k, v)
|
|
defer os.Unsetenv(k)
|
|
}
|
|
|
|
cfg := config.New()
|
|
cfg.Register("api.key", "")
|
|
cfg.Register("database.password", "")
|
|
cfg.Register("server.port", 8080)
|
|
|
|
opts := config.LoadOptions{
|
|
Sources: []config.Source{config.SourceEnv, config.SourceDefault},
|
|
EnvPrefix: "SECRET_",
|
|
EnvWhitelist: map[string]bool{
|
|
"api.key": true,
|
|
"database.password": true,
|
|
// server.port is NOT whitelisted
|
|
},
|
|
}
|
|
|
|
cfg.LoadWithOptions("", nil, opts)
|
|
|
|
// Whitelisted values should load
|
|
apiKey, _ := cfg.String("api.key")
|
|
assert.Equal(t, "secret-value", apiKey)
|
|
|
|
dbPass, _ := cfg.String("database.password")
|
|
assert.Equal(t, "db-pass", dbPass)
|
|
|
|
// Non-whitelisted should use default
|
|
port, _ := cfg.Int64("server.port")
|
|
assert.Equal(t, int64(8080), port)
|
|
})
|
|
|
|
t.Run("RegisterWithEnv", func(t *testing.T) {
|
|
os.Setenv("CUSTOM_PORT", "6666")
|
|
defer os.Unsetenv("CUSTOM_PORT")
|
|
|
|
cfg := config.New()
|
|
|
|
// Register with explicit env mapping
|
|
err := cfg.RegisterWithEnv("server.port", 8080, "CUSTOM_PORT")
|
|
require.NoError(t, err)
|
|
|
|
// Should immediately have env value
|
|
port, _ := cfg.Int64("server.port")
|
|
assert.Equal(t, int64(6666), port)
|
|
})
|
|
|
|
t.Run("Export Environment", func(t *testing.T) {
|
|
cfg := config.New()
|
|
cfg.Register("app.name", "myapp")
|
|
cfg.Register("app.version", "1.0.0")
|
|
cfg.Register("server.port", 8080)
|
|
|
|
// Set some non-default values
|
|
cfg.Set("app.version", "2.0.0")
|
|
cfg.Set("server.port", 9090)
|
|
|
|
// Export as env vars
|
|
exports := cfg.ExportEnv("EXPORT_")
|
|
|
|
// Should export non-default values
|
|
assert.Equal(t, "2.0.0", exports["EXPORT_APP_VERSION"])
|
|
assert.Equal(t, "9090", exports["EXPORT_SERVER_PORT"])
|
|
|
|
// Should not export defaults
|
|
assert.NotContains(t, exports, "EXPORT_APP_NAME")
|
|
})
|
|
|
|
t.Run("Type Parsing from Environment", func(t *testing.T) {
|
|
envVars := map[string]string{
|
|
"TYPES_STRING": "hello world",
|
|
"TYPES_INT": "42",
|
|
"TYPES_FLOAT": "3.14159",
|
|
"TYPES_BOOL_TRUE": "true",
|
|
"TYPES_BOOL_FALSE": "false",
|
|
"TYPES_QUOTED": `"quoted string"`,
|
|
}
|
|
for k, v := range envVars {
|
|
os.Setenv(k, v)
|
|
defer os.Unsetenv(k)
|
|
}
|
|
|
|
cfg := config.New()
|
|
cfg.Register("string", "")
|
|
cfg.Register("int", 0)
|
|
cfg.Register("float", 0.0)
|
|
cfg.Register("bool.true", false)
|
|
cfg.Register("bool.false", true)
|
|
cfg.Register("quoted", "")
|
|
|
|
cfg.LoadEnv("TYPES_")
|
|
|
|
// Verify type conversions
|
|
s, _ := cfg.String("string")
|
|
assert.Equal(t, "hello world", s)
|
|
|
|
i, _ := cfg.Int64("int")
|
|
assert.Equal(t, int64(42), i)
|
|
|
|
f, _ := cfg.Float64("float")
|
|
assert.Equal(t, 3.14159, f)
|
|
|
|
bt, _ := cfg.Bool("bool.true")
|
|
assert.True(t, bt)
|
|
|
|
bf, _ := cfg.Bool("bool.false")
|
|
assert.False(t, bf)
|
|
|
|
q, _ := cfg.String("quoted")
|
|
assert.Equal(t, "quoted string", q)
|
|
})
|
|
} |