e3.0.0 Added env variable support, improved cli arg, added tests, updated documentation.
This commit is contained in:
225
env_test.go
Normal file
225
env_test.go
Normal file
@ -0,0 +1,225 @@
|
||||
// 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)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user