mirror of
https://github.com/lukaszraczylo/lolcathost.git
synced 2026-06-05 23:29:18 +00:00
29263dc8a2
* gosec govulncheck runs
* Fix flaky TestRateLimiter_Matrix test
The test was failing due to two issues:
1. Test name generation used invalid character conversion (string(rune('0'+limit)))
which produced non-printable characters for limits >= 10
2. Using 10ms windows with 100 requests caused race conditions - early requests
would expire before all 100 were made, allowing the 101st request
Changed to use struct-based test cases with proper fmt.Sprintf naming and
a consistent 1-second window that won't expire during rapid test execution.
522 lines
13 KiB
Go
522 lines
13 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestConfig_GetAllHosts(t *testing.T) {
|
|
cfg := &Config{
|
|
Groups: []Group{
|
|
{
|
|
Name: "dev",
|
|
Hosts: []Host{
|
|
{Domain: "a.com", IP: "127.0.0.1", Alias: "a", Enabled: true},
|
|
{Domain: "b.com", IP: "127.0.0.1", Alias: "b", Enabled: false},
|
|
},
|
|
},
|
|
{
|
|
Name: "staging",
|
|
Hosts: []Host{
|
|
{Domain: "c.com", IP: "192.168.1.1", Alias: "c", Enabled: true},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
hosts := cfg.GetAllHosts()
|
|
assert.Len(t, hosts, 3)
|
|
assert.Equal(t, "a.com", hosts[0].Domain)
|
|
assert.Equal(t, "b.com", hosts[1].Domain)
|
|
assert.Equal(t, "c.com", hosts[2].Domain)
|
|
}
|
|
|
|
func TestConfig_FindHostByAlias(t *testing.T) {
|
|
cfg := &Config{
|
|
Groups: []Group{
|
|
{
|
|
Name: "dev",
|
|
Hosts: []Host{
|
|
{Domain: "example.com", IP: "127.0.0.1", Alias: "example", Enabled: true},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
t.Run("found", func(t *testing.T) {
|
|
host, group := cfg.FindHostByAlias("example")
|
|
require.NotNil(t, host)
|
|
require.NotNil(t, group)
|
|
assert.Equal(t, "example.com", host.Domain)
|
|
assert.Equal(t, "dev", group.Name)
|
|
})
|
|
|
|
t.Run("not found", func(t *testing.T) {
|
|
host, group := cfg.FindHostByAlias("nonexistent")
|
|
assert.Nil(t, host)
|
|
assert.Nil(t, group)
|
|
})
|
|
}
|
|
|
|
func TestConfig_FindPreset(t *testing.T) {
|
|
cfg := &Config{
|
|
Presets: []Preset{
|
|
{Name: "local", Enable: []string{"a"}, Disable: []string{"b"}},
|
|
{Name: "staging", Enable: []string{"b"}, Disable: []string{"a"}},
|
|
},
|
|
}
|
|
|
|
t.Run("found", func(t *testing.T) {
|
|
preset := cfg.FindPreset("local")
|
|
require.NotNil(t, preset)
|
|
assert.Equal(t, "local", preset.Name)
|
|
assert.Equal(t, []string{"a"}, preset.Enable)
|
|
})
|
|
|
|
t.Run("not found", func(t *testing.T) {
|
|
preset := cfg.FindPreset("nonexistent")
|
|
assert.Nil(t, preset)
|
|
})
|
|
}
|
|
|
|
func TestConfig_SetHostEnabled(t *testing.T) {
|
|
cfg := &Config{
|
|
Groups: []Group{
|
|
{
|
|
Name: "dev",
|
|
Hosts: []Host{
|
|
{Domain: "example.com", IP: "127.0.0.1", Alias: "example", Enabled: false},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
t.Run("enable existing", func(t *testing.T) {
|
|
result := cfg.SetHostEnabled("example", true)
|
|
assert.True(t, result)
|
|
assert.True(t, cfg.Groups[0].Hosts[0].Enabled)
|
|
})
|
|
|
|
t.Run("disable existing", func(t *testing.T) {
|
|
result := cfg.SetHostEnabled("example", false)
|
|
assert.True(t, result)
|
|
assert.False(t, cfg.Groups[0].Hosts[0].Enabled)
|
|
})
|
|
|
|
t.Run("nonexistent alias", func(t *testing.T) {
|
|
result := cfg.SetHostEnabled("nonexistent", true)
|
|
assert.False(t, result)
|
|
})
|
|
}
|
|
|
|
func TestConfig_ApplyPreset(t *testing.T) {
|
|
cfg := &Config{
|
|
Groups: []Group{
|
|
{
|
|
Name: "dev",
|
|
Hosts: []Host{
|
|
{Domain: "a.com", IP: "127.0.0.1", Alias: "a", Enabled: false},
|
|
{Domain: "b.com", IP: "127.0.0.1", Alias: "b", Enabled: true},
|
|
},
|
|
},
|
|
},
|
|
Presets: []Preset{
|
|
{Name: "swap", Enable: []string{"a"}, Disable: []string{"b"}},
|
|
},
|
|
}
|
|
|
|
t.Run("valid preset", func(t *testing.T) {
|
|
err := cfg.ApplyPreset("swap")
|
|
require.NoError(t, err)
|
|
assert.True(t, cfg.Groups[0].Hosts[0].Enabled)
|
|
assert.False(t, cfg.Groups[0].Hosts[1].Enabled)
|
|
})
|
|
|
|
t.Run("nonexistent preset", func(t *testing.T) {
|
|
err := cfg.ApplyPreset("nonexistent")
|
|
assert.Error(t, err)
|
|
})
|
|
}
|
|
|
|
func TestManager_LoadAndGet(t *testing.T) {
|
|
// Create temp config file
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, "config.yaml")
|
|
|
|
configContent := `
|
|
settings:
|
|
autoApply: true
|
|
flushMethod: auto
|
|
groups:
|
|
- name: development
|
|
hosts:
|
|
- domain: example.com
|
|
ip: 127.0.0.1
|
|
alias: example-local
|
|
enabled: true
|
|
presets:
|
|
- name: local
|
|
enable: [example-local]
|
|
disable: []
|
|
`
|
|
err := os.WriteFile(configPath, []byte(configContent), 0644)
|
|
require.NoError(t, err)
|
|
|
|
manager := NewManager(configPath)
|
|
err = manager.Load()
|
|
require.NoError(t, err)
|
|
|
|
cfg := manager.Get()
|
|
require.NotNil(t, cfg)
|
|
|
|
assert.True(t, cfg.Settings.AutoApply)
|
|
assert.Equal(t, FlushMethodAuto, cfg.Settings.FlushMethod)
|
|
assert.Len(t, cfg.Groups, 1)
|
|
assert.Equal(t, "development", cfg.Groups[0].Name)
|
|
assert.Len(t, cfg.Groups[0].Hosts, 1)
|
|
assert.Equal(t, "example.com", cfg.Groups[0].Hosts[0].Domain)
|
|
}
|
|
|
|
func TestManager_Save(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, "config.yaml")
|
|
|
|
// Create initial config
|
|
err := CreateDefault(configPath)
|
|
require.NoError(t, err)
|
|
|
|
// Load and modify
|
|
manager := NewManager(configPath)
|
|
err = manager.Load()
|
|
require.NoError(t, err)
|
|
|
|
cfg := manager.Get()
|
|
cfg.Groups[0].Hosts[0].Enabled = true
|
|
|
|
// Save
|
|
err = manager.Save()
|
|
require.NoError(t, err)
|
|
|
|
// Reload and verify
|
|
manager2 := NewManager(configPath)
|
|
err = manager2.Load()
|
|
require.NoError(t, err)
|
|
|
|
cfg2 := manager2.Get()
|
|
assert.True(t, cfg2.Groups[0].Hosts[0].Enabled)
|
|
}
|
|
|
|
func TestCreateDefault(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, "subdir", "config.yaml")
|
|
|
|
err := CreateDefault(configPath)
|
|
require.NoError(t, err)
|
|
|
|
// Verify file exists
|
|
_, err = os.Stat(configPath)
|
|
require.NoError(t, err)
|
|
|
|
// Verify content is valid
|
|
manager := NewManager(configPath)
|
|
err = manager.Load()
|
|
require.NoError(t, err)
|
|
|
|
cfg := manager.Get()
|
|
require.NotNil(t, cfg)
|
|
assert.True(t, cfg.Settings.AutoApply)
|
|
assert.Len(t, cfg.Groups, 1)
|
|
assert.Len(t, cfg.Presets, 2)
|
|
}
|
|
|
|
func TestManager_Load_InvalidYAML(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, "config.yaml")
|
|
|
|
err := os.WriteFile(configPath, []byte("invalid: yaml: content:"), 0644)
|
|
require.NoError(t, err)
|
|
|
|
manager := NewManager(configPath)
|
|
err = manager.Load()
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestManager_Load_FileNotFound(t *testing.T) {
|
|
manager := NewManager("/nonexistent/path/config.yaml")
|
|
err := manager.Load()
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
func TestFlushMethod(t *testing.T) {
|
|
methods := []FlushMethod{
|
|
FlushMethodAuto,
|
|
FlushMethodDscacheutil,
|
|
FlushMethodKillall,
|
|
FlushMethodBoth,
|
|
}
|
|
|
|
for _, m := range methods {
|
|
t.Run(string(m), func(t *testing.T) {
|
|
assert.NotEmpty(t, string(m))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDefaultConfigDir(t *testing.T) {
|
|
dir := DefaultConfigDir()
|
|
assert.NotEmpty(t, dir)
|
|
assert.Contains(t, dir, ".config/lolcathost")
|
|
}
|
|
|
|
func TestDefaultConfigPath(t *testing.T) {
|
|
path := DefaultConfigPath()
|
|
assert.NotEmpty(t, path)
|
|
assert.Contains(t, path, "config.yaml")
|
|
}
|
|
|
|
func TestConfig_GenerateAlias(t *testing.T) {
|
|
cfg := &Config{
|
|
Groups: []Group{
|
|
{
|
|
Name: "dev",
|
|
Hosts: []Host{
|
|
{Domain: "existing.com", IP: "127.0.0.1", Alias: "existing-com", Enabled: true},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
t.Run("simple domain", func(t *testing.T) {
|
|
alias := cfg.GenerateAlias("newdomain.com")
|
|
assert.Equal(t, "newdomain-com", alias)
|
|
})
|
|
|
|
t.Run("domain with underscore", func(t *testing.T) {
|
|
alias := cfg.GenerateAlias("my_app.test")
|
|
assert.Equal(t, "my-app-test", alias)
|
|
})
|
|
|
|
t.Run("duplicate generates numbered alias", func(t *testing.T) {
|
|
alias := cfg.GenerateAlias("existing.com")
|
|
assert.Equal(t, "existing-com-2", alias)
|
|
})
|
|
}
|
|
|
|
func TestConfig_AddHost(t *testing.T) {
|
|
t.Run("add to existing group", func(t *testing.T) {
|
|
cfg := &Config{
|
|
Groups: []Group{
|
|
{Name: "dev", Hosts: []Host{}},
|
|
},
|
|
}
|
|
err := cfg.AddHost("test.local", "127.0.0.1", "test-local", "dev", true)
|
|
require.NoError(t, err)
|
|
assert.Len(t, cfg.Groups[0].Hosts, 1)
|
|
assert.Equal(t, "test.local", cfg.Groups[0].Hosts[0].Domain)
|
|
})
|
|
|
|
t.Run("add to new group", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{}}
|
|
err := cfg.AddHost("test.local", "127.0.0.1", "test-local", "newgroup", true)
|
|
require.NoError(t, err)
|
|
assert.Len(t, cfg.Groups, 1)
|
|
assert.Equal(t, "newgroup", cfg.Groups[0].Name)
|
|
})
|
|
|
|
t.Run("auto-generate alias", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{}}
|
|
err := cfg.AddHost("auto.test", "127.0.0.1", "", "dev", true)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "auto-test", cfg.Groups[0].Hosts[0].Alias)
|
|
})
|
|
|
|
t.Run("duplicate alias error", func(t *testing.T) {
|
|
cfg := &Config{
|
|
Groups: []Group{
|
|
{Name: "dev", Hosts: []Host{{Domain: "a.com", IP: "127.0.0.1", Alias: "existing"}}},
|
|
},
|
|
}
|
|
err := cfg.AddHost("b.com", "127.0.0.1", "existing", "dev", true)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "alias already exists")
|
|
})
|
|
}
|
|
|
|
func TestConfig_AddGroup(t *testing.T) {
|
|
t.Run("add new group", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{}}
|
|
err := cfg.AddGroup("newgroup")
|
|
require.NoError(t, err)
|
|
assert.Len(t, cfg.Groups, 1)
|
|
assert.Equal(t, "newgroup", cfg.Groups[0].Name)
|
|
})
|
|
|
|
t.Run("duplicate group error", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{{Name: "existing"}}}
|
|
err := cfg.AddGroup("existing")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "group already exists")
|
|
})
|
|
}
|
|
|
|
func TestConfig_DeleteGroup(t *testing.T) {
|
|
t.Run("delete existing group", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{{Name: "todelete"}, {Name: "keep"}}}
|
|
err := cfg.DeleteGroup("todelete")
|
|
require.NoError(t, err)
|
|
assert.Len(t, cfg.Groups, 1)
|
|
assert.Equal(t, "keep", cfg.Groups[0].Name)
|
|
})
|
|
|
|
t.Run("delete nonexistent group", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{}}
|
|
err := cfg.DeleteGroup("nonexistent")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "group not found")
|
|
})
|
|
}
|
|
|
|
func TestConfig_RenameGroup(t *testing.T) {
|
|
t.Run("rename existing group", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{{Name: "oldname"}}}
|
|
err := cfg.RenameGroup("oldname", "newname")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "newname", cfg.Groups[0].Name)
|
|
})
|
|
|
|
t.Run("rename to existing name error", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{{Name: "a"}, {Name: "b"}}}
|
|
err := cfg.RenameGroup("a", "b")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "group already exists")
|
|
})
|
|
|
|
t.Run("rename nonexistent group", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{}}
|
|
err := cfg.RenameGroup("nonexistent", "newname")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "group not found")
|
|
})
|
|
}
|
|
|
|
func TestConfig_GetGroups(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{{Name: "a"}, {Name: "b"}, {Name: "c"}}}
|
|
groups := cfg.GetGroups()
|
|
assert.Equal(t, []string{"a", "b", "c"}, groups)
|
|
}
|
|
|
|
func TestConfig_DeleteHost(t *testing.T) {
|
|
t.Run("delete existing host", func(t *testing.T) {
|
|
cfg := &Config{
|
|
Groups: []Group{
|
|
{Name: "dev", Hosts: []Host{
|
|
{Domain: "a.com", Alias: "a"},
|
|
{Domain: "b.com", Alias: "b"},
|
|
}},
|
|
},
|
|
}
|
|
result := cfg.DeleteHost("a")
|
|
assert.True(t, result)
|
|
assert.Len(t, cfg.Groups[0].Hosts, 1)
|
|
assert.Equal(t, "b", cfg.Groups[0].Hosts[0].Alias)
|
|
})
|
|
|
|
t.Run("delete nonexistent host", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{}}
|
|
result := cfg.DeleteHost("nonexistent")
|
|
assert.False(t, result)
|
|
})
|
|
}
|
|
|
|
func TestConfig_AddPreset(t *testing.T) {
|
|
t.Run("add new preset", func(t *testing.T) {
|
|
cfg := &Config{Presets: []Preset{}}
|
|
err := cfg.AddPreset("newpreset", []string{"a"}, []string{"b"})
|
|
require.NoError(t, err)
|
|
assert.Len(t, cfg.Presets, 1)
|
|
assert.Equal(t, "newpreset", cfg.Presets[0].Name)
|
|
})
|
|
|
|
t.Run("duplicate preset error", func(t *testing.T) {
|
|
cfg := &Config{Presets: []Preset{{Name: "existing"}}}
|
|
err := cfg.AddPreset("existing", nil, nil)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "preset already exists")
|
|
})
|
|
}
|
|
|
|
func TestConfig_DeletePreset(t *testing.T) {
|
|
t.Run("delete existing preset", func(t *testing.T) {
|
|
cfg := &Config{Presets: []Preset{{Name: "todelete"}, {Name: "keep"}}}
|
|
err := cfg.DeletePreset("todelete")
|
|
require.NoError(t, err)
|
|
assert.Len(t, cfg.Presets, 1)
|
|
assert.Equal(t, "keep", cfg.Presets[0].Name)
|
|
})
|
|
|
|
t.Run("delete nonexistent preset", func(t *testing.T) {
|
|
cfg := &Config{Presets: []Preset{}}
|
|
err := cfg.DeletePreset("nonexistent")
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "preset not found")
|
|
})
|
|
}
|
|
|
|
func TestConfig_GetPresets(t *testing.T) {
|
|
cfg := &Config{Presets: []Preset{{Name: "a"}, {Name: "b"}}}
|
|
presets := cfg.GetPresets()
|
|
assert.Len(t, presets, 2)
|
|
}
|
|
|
|
func TestConfig_EnsureDefaultGroup(t *testing.T) {
|
|
t.Run("creates default when empty", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{}}
|
|
cfg.EnsureDefaultGroup()
|
|
assert.Len(t, cfg.Groups, 1)
|
|
assert.Equal(t, "default", cfg.Groups[0].Name)
|
|
})
|
|
|
|
t.Run("does nothing when groups exist", func(t *testing.T) {
|
|
cfg := &Config{Groups: []Group{{Name: "existing"}}}
|
|
cfg.EnsureDefaultGroup()
|
|
assert.Len(t, cfg.Groups, 1)
|
|
assert.Equal(t, "existing", cfg.Groups[0].Name)
|
|
})
|
|
}
|
|
|
|
func TestManager_Watch(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, "config.yaml")
|
|
|
|
err := CreateDefault(configPath)
|
|
require.NoError(t, err)
|
|
|
|
manager := NewManager(configPath)
|
|
err = manager.Load()
|
|
require.NoError(t, err)
|
|
|
|
changeCh := make(chan *Config, 1)
|
|
err = manager.Watch(func(cfg *Config) {
|
|
changeCh <- cfg
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Stop the watcher
|
|
manager.Stop()
|
|
}
|
|
|
|
func TestManager_Save_NoConfig(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
configPath := filepath.Join(tmpDir, "config.yaml")
|
|
|
|
manager := NewManager(configPath)
|
|
// Don't load, so config is nil
|
|
err := manager.Save()
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "no config loaded")
|
|
}
|