219 lines
5.8 KiB
Go
219 lines
5.8 KiB
Go
// File: lixenwraith/config/source_test.go
|
|
package config_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/lixenwraith/config"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestMultiSourceConfiguration(t *testing.T) {
|
|
t.Run("Source Precedence", func(t *testing.T) {
|
|
cfg := config.New()
|
|
cfg.Register("test.value", "default")
|
|
|
|
// Set values in different sources
|
|
cfg.SetSource("test.value", config.SourceFile, "from-file")
|
|
cfg.SetSource("test.value", config.SourceEnv, "from-env")
|
|
cfg.SetSource("test.value", config.SourceCLI, "from-cli")
|
|
|
|
// Default precedence: CLI > Env > File > Default
|
|
val, _ := cfg.String("test.value")
|
|
assert.Equal(t, "from-cli", val)
|
|
|
|
// Change precedence
|
|
opts := config.LoadOptions{
|
|
Sources: []config.Source{
|
|
config.SourceEnv,
|
|
config.SourceCLI,
|
|
config.SourceFile,
|
|
config.SourceDefault,
|
|
},
|
|
}
|
|
cfg.SetLoadOptions(opts)
|
|
|
|
// Now env should win
|
|
val, _ = cfg.String("test.value")
|
|
assert.Equal(t, "from-env", val)
|
|
})
|
|
|
|
t.Run("Source Tracking", func(t *testing.T) {
|
|
cfg := config.New()
|
|
cfg.Register("server.port", 8080)
|
|
|
|
// Set from multiple sources
|
|
cfg.SetSource("server.port", config.SourceFile, 9090)
|
|
cfg.SetSource("server.port", config.SourceEnv, 7070)
|
|
|
|
// Get all sources
|
|
sources := cfg.GetSources("server.port")
|
|
|
|
// Should have 2 sources
|
|
assert.Len(t, sources, 2)
|
|
assert.Equal(t, 9090, sources[config.SourceFile])
|
|
assert.Equal(t, 7070, sources[config.SourceEnv])
|
|
})
|
|
|
|
t.Run("GetSource", func(t *testing.T) {
|
|
cfg := config.New()
|
|
cfg.Register("api.key", "default-key")
|
|
|
|
cfg.SetSource("api.key", config.SourceEnv, "env-key")
|
|
|
|
// Get from specific source
|
|
envVal, exists := cfg.GetSource("api.key", config.SourceEnv)
|
|
assert.True(t, exists)
|
|
assert.Equal(t, "env-key", envVal)
|
|
|
|
// Get from missing source
|
|
_, exists = cfg.GetSource("api.key", config.SourceFile)
|
|
assert.False(t, exists)
|
|
})
|
|
|
|
t.Run("Reset Sources", func(t *testing.T) {
|
|
cfg := config.New()
|
|
cfg.Register("test1", "default1")
|
|
cfg.Register("test2", "default2")
|
|
|
|
// Set values
|
|
cfg.SetSource("test1", config.SourceFile, "file1")
|
|
cfg.SetSource("test1", config.SourceEnv, "env1")
|
|
cfg.SetSource("test2", config.SourceCLI, "cli2")
|
|
|
|
// Reset specific source
|
|
cfg.ResetSource(config.SourceEnv)
|
|
|
|
// Env value should be gone
|
|
_, exists := cfg.GetSource("test1", config.SourceEnv)
|
|
assert.False(t, exists)
|
|
|
|
// Other sources remain
|
|
fileVal, _ := cfg.GetSource("test1", config.SourceFile)
|
|
assert.Equal(t, "file1", fileVal)
|
|
|
|
// Reset all
|
|
cfg.Reset()
|
|
|
|
// All values should be defaults
|
|
val1, _ := cfg.String("test1")
|
|
val2, _ := cfg.String("test2")
|
|
assert.Equal(t, "default1", val1)
|
|
assert.Equal(t, "default2", val2)
|
|
})
|
|
|
|
t.Run("LoadWithOptions Integration", func(t *testing.T) {
|
|
// Create temp config file
|
|
tmpdir := t.TempDir()
|
|
configFile := filepath.Join(tmpdir, "test.toml")
|
|
|
|
configContent := `
|
|
[server]
|
|
host = "file-host"
|
|
port = 8080
|
|
|
|
[feature]
|
|
enabled = true
|
|
`
|
|
require.NoError(t, os.WriteFile(configFile, []byte(configContent), 0644))
|
|
|
|
// Set environment
|
|
os.Setenv("TEST_SERVER_PORT", "9090")
|
|
os.Setenv("TEST_FEATURE_ENABLED", "false")
|
|
t.Cleanup(func() {
|
|
os.Unsetenv("TEST_SERVER_PORT")
|
|
os.Unsetenv("TEST_FEATURE_ENABLED")
|
|
})
|
|
|
|
cfg := config.New()
|
|
cfg.Register("server.host", "default-host")
|
|
cfg.Register("server.port", 7070)
|
|
cfg.Register("feature.enabled", false)
|
|
|
|
// Load with custom precedence (File highest)
|
|
opts := config.LoadOptions{
|
|
Sources: []config.Source{
|
|
config.SourceFile,
|
|
config.SourceEnv,
|
|
config.SourceCLI,
|
|
config.SourceDefault,
|
|
},
|
|
EnvPrefix: "TEST_",
|
|
}
|
|
|
|
err := cfg.LoadWithOptions(configFile, []string{"--server.host=cli-host"}, opts)
|
|
require.NoError(t, err)
|
|
|
|
// File should win for all values
|
|
host, _ := cfg.String("server.host")
|
|
assert.Equal(t, "file-host", host)
|
|
|
|
port, _ := cfg.Int64("server.port")
|
|
assert.Equal(t, int64(8080), port)
|
|
|
|
enabled, _ := cfg.Bool("feature.enabled")
|
|
assert.True(t, enabled)
|
|
})
|
|
|
|
t.Run("ScanSource", func(t *testing.T) {
|
|
type ServerConfig struct {
|
|
Host string `toml:"host"`
|
|
Port int `toml:"port"`
|
|
}
|
|
|
|
cfg := config.New()
|
|
cfg.Register("server.host", "default")
|
|
cfg.Register("server.port", 8080)
|
|
|
|
// Set different values in different sources
|
|
cfg.SetSource("server.host", config.SourceFile, "file-host")
|
|
cfg.SetSource("server.port", config.SourceFile, 8080)
|
|
cfg.SetSource("server.host", config.SourceEnv, "env-host")
|
|
cfg.SetSource("server.port", config.SourceEnv, 9090)
|
|
|
|
// Scan from specific source
|
|
var fileConfig ServerConfig
|
|
err := cfg.ScanSource("server", config.SourceFile, &fileConfig)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "file-host", fileConfig.Host)
|
|
assert.Equal(t, 8080, fileConfig.Port)
|
|
|
|
var envConfig ServerConfig
|
|
err = cfg.ScanSource("server", config.SourceEnv, &envConfig)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "env-host", envConfig.Host)
|
|
assert.Equal(t, 9090, envConfig.Port)
|
|
})
|
|
|
|
t.Run("SaveSource", 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 values in different sources
|
|
cfg.SetSource("app.name", config.SourceFile, "fileapp")
|
|
cfg.SetSource("app.version", config.SourceEnv, "2.0.0")
|
|
cfg.SetSource("server.port", config.SourceCLI, 9090)
|
|
|
|
// Save only env source
|
|
tmpfile := filepath.Join(t.TempDir(), "config-source.toml")
|
|
err := cfg.SaveSource(tmpfile, config.SourceEnv)
|
|
require.NoError(t, err)
|
|
|
|
// Load saved file and verify
|
|
newCfg := config.New()
|
|
newCfg.Register("app.version", "")
|
|
newCfg.LoadFile(tmpfile)
|
|
|
|
version, _ := newCfg.String("app.version")
|
|
assert.Equal(t, "2.0.0", version)
|
|
|
|
// Should not have other source values
|
|
name, _ := newCfg.String("app.name")
|
|
assert.Empty(t, name)
|
|
})
|
|
} |