Files
MrFastwind d55200886b docs: rewrite PLAN.md and update CODEBASE.md, README.md
- Full rewrite of PLAN.md to reflect current architecture (27 REST + 3 WS endpoints,
  embedded frontend, automation, scheduler, health check, GoReleaser CI)
- Added health.go, mods.go, scheduler.go, robfig/cron dep to CODEBASE.md
- Added Gitea Actions CI/CD section to CODEBASE.md
- Added conventional commits to code style section
- Added missing API routes and embed/ to README.md
2026-07-23 20:14:56 +02:00

161 lines
3.6 KiB
Go

package services
import (
"os"
"path/filepath"
"testing"
)
func TestConfigManager_ListEmpty(t *testing.T) {
dir := t.TempDir()
cm := NewConfigManager(dir)
configs, err := cm.List()
if err != nil {
t.Fatalf("List() error = %v", err)
}
if len(configs) != 0 {
t.Errorf("List() returned %d configs, want 0", len(configs))
}
}
func TestConfigManager_CreateAndGet(t *testing.T) {
dir := t.TempDir()
cm := NewConfigManager(dir)
if err := cm.Create("server", "host = 0.0.0.0"); err != nil {
t.Fatalf("Create() error = %v", err)
}
content, err := cm.Get("server")
if err != nil {
t.Fatalf("Get() error = %v", err)
}
if content != "host = 0.0.0.0" {
t.Errorf("Get() = %q, want %q", content, "host = 0.0.0.0")
}
}
func TestConfigManager_CreateDuplicate(t *testing.T) {
dir := t.TempDir()
cm := NewConfigManager(dir)
cm.Create("server", "content")
err := cm.Create("server", "content2")
if err == nil {
t.Error("Create() should fail for existing config")
}
}
func TestConfigManager_Update(t *testing.T) {
dir := t.TempDir()
cm := NewConfigManager(dir)
cm.Create("server", "old")
if err := cm.Update("server", "new"); err != nil {
t.Fatalf("Update() error = %v", err)
}
content, _ := cm.Get("server")
if content != "new" {
t.Errorf("Get() after Update() = %q, want %q", content, "new")
}
}
func TestConfigManager_Delete(t *testing.T) {
dir := t.TempDir()
cm := NewConfigManager(dir)
cm.Create("server", "content")
if err := cm.Delete("server"); err != nil {
t.Fatalf("Delete() error = %v", err)
}
_, err := cm.Get("server")
if err == nil {
t.Error("Get() should fail after Delete()")
}
}
func TestConfigManager_Duplicate(t *testing.T) {
dir := t.TempDir()
cm := NewConfigManager(dir)
cm.Create("server", "host = 0.0.0.0")
if err := cm.Duplicate("server", "backup"); err != nil {
t.Fatalf("Duplicate() error = %v", err)
}
content, _ := cm.Get("backup")
if content != "host = 0.0.0.0" {
t.Errorf("Get(backup) = %q, want %q", content, "host = 0.0.0.0")
}
configs, _ := cm.List()
if len(configs) != 2 {
t.Errorf("List() returned %d configs, want 2", len(configs))
}
}
func TestConfigManager_ListWithMultipleFiles(t *testing.T) {
dir := t.TempDir()
cm := NewConfigManager(dir)
cm.Create("server", "s")
cm.Create("difficulty", "d")
os.WriteFile(filepath.Join(dir, "notacfg.txt"), []byte("txt"), 0644)
configs, err := cm.List()
if err != nil {
t.Fatalf("List() error = %v", err)
}
if len(configs) != 2 {
t.Errorf("List() returned %d configs, want 2 (should exclude non-.cfg)", len(configs))
}
}
func TestConfigManager_GetNotFound(t *testing.T) {
dir := t.TempDir()
cm := NewConfigManager(dir)
_, err := cm.Get("nonexistent")
if err == nil {
t.Error("Get() should fail for nonexistent config")
}
}
func TestConfigManager_CreateWithPathTraversal(t *testing.T) {
dir := t.TempDir()
cm := NewConfigManager(dir)
// Attempt to create with path traversal
err := cm.Create("../../etc/passwd", "content")
if err != nil {
t.Fatalf("Create() error = %v", err)
}
// Verify it was sanitized to just "passwd.cfg" in the cfgDir
path := filepath.Join(dir, "passwd.cfg")
if _, err := os.Stat(path); os.IsNotExist(err) {
t.Error("File should be created with sanitized name in cfgDir")
}
}
func TestSanitizeConfigName(t *testing.T) {
tests := []struct {
input string
want string
}{
{"server", "server"},
{"../etc/passwd", "passwd"},
{"../../secret.cfg", "secret"},
{"server.cfg", "server"},
}
for _, tt := range tests {
got := sanitizeConfigName(tt.input)
if got != tt.want {
t.Errorf("sanitizeConfigName(%q) = %q, want %q", tt.input, got, tt.want)
}
}
}