test: Add tests for API helper functions
- isRecentlyAutoRegistered: expiry logic, cleanup behavior - clearAutoRegistered: key deletion, empty input handling - normalizeDockerAgentArch: all arch variants, case handling, trimming
This commit is contained in:
parent
80702a51bf
commit
3233c48986
2 changed files with 266 additions and 0 deletions
196
internal/api/config_handlers_auto_reg_test.go
Normal file
196
internal/api/config_handlers_auto_reg_test.go
Normal file
|
|
@ -0,0 +1,196 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsRecentlyAutoRegistered(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
nodeType string
|
||||||
|
nodeName string
|
||||||
|
setup func(*ConfigHandlers)
|
||||||
|
want bool
|
||||||
|
checkGone bool // verify entry was cleaned up
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty nodeType returns false",
|
||||||
|
nodeType: "",
|
||||||
|
nodeName: "node1",
|
||||||
|
setup: nil,
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty nodeName returns false",
|
||||||
|
nodeType: "pve",
|
||||||
|
nodeName: "",
|
||||||
|
setup: nil,
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "key not in map returns false",
|
||||||
|
nodeType: "pve",
|
||||||
|
nodeName: "nonexistent",
|
||||||
|
setup: nil,
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "recent registration returns true",
|
||||||
|
nodeType: "pve",
|
||||||
|
nodeName: "node1",
|
||||||
|
setup: func(h *ConfigHandlers) {
|
||||||
|
h.recentAutoRegistered["pve:node1"] = time.Now()
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "expired registration returns false and cleans up",
|
||||||
|
nodeType: "pve",
|
||||||
|
nodeName: "node1",
|
||||||
|
setup: func(h *ConfigHandlers) {
|
||||||
|
h.recentAutoRegistered["pve:node1"] = time.Now().Add(-3 * time.Minute)
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
checkGone: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "different keys are independent",
|
||||||
|
nodeType: "pbs",
|
||||||
|
nodeName: "node2",
|
||||||
|
setup: func(h *ConfigHandlers) {
|
||||||
|
h.recentAutoRegistered["pve:node1"] = time.Now()
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cfg := &config.Config{
|
||||||
|
DataPath: t.TempDir(),
|
||||||
|
ConfigPath: t.TempDir(),
|
||||||
|
}
|
||||||
|
h := newTestConfigHandlers(t, cfg)
|
||||||
|
|
||||||
|
if tt.setup != nil {
|
||||||
|
tt.setup(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
got := h.isRecentlyAutoRegistered(tt.nodeType, tt.nodeName)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("isRecentlyAutoRegistered(%q, %q) = %v, want %v", tt.nodeType, tt.nodeName, got, tt.want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.checkGone {
|
||||||
|
key := tt.nodeType + ":" + tt.nodeName
|
||||||
|
h.recentAutoRegMutex.Lock()
|
||||||
|
_, exists := h.recentAutoRegistered[key]
|
||||||
|
h.recentAutoRegMutex.Unlock()
|
||||||
|
if exists {
|
||||||
|
t.Errorf("expected key %q to be cleaned up, but it still exists", key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClearAutoRegistered(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
nodeType string
|
||||||
|
nodeName string
|
||||||
|
setup func(*ConfigHandlers)
|
||||||
|
check func(*testing.T, *ConfigHandlers)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty nodeType is safe",
|
||||||
|
nodeType: "",
|
||||||
|
nodeName: "node1",
|
||||||
|
setup: func(h *ConfigHandlers) {
|
||||||
|
h.recentAutoRegistered["pve:node1"] = time.Now()
|
||||||
|
},
|
||||||
|
check: func(t *testing.T, h *ConfigHandlers) {
|
||||||
|
h.recentAutoRegMutex.Lock()
|
||||||
|
defer h.recentAutoRegMutex.Unlock()
|
||||||
|
if _, exists := h.recentAutoRegistered["pve:node1"]; !exists {
|
||||||
|
t.Error("expected pve:node1 to still exist")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty nodeName is safe",
|
||||||
|
nodeType: "pve",
|
||||||
|
nodeName: "",
|
||||||
|
setup: func(h *ConfigHandlers) {
|
||||||
|
h.recentAutoRegistered["pve:node1"] = time.Now()
|
||||||
|
},
|
||||||
|
check: func(t *testing.T, h *ConfigHandlers) {
|
||||||
|
h.recentAutoRegMutex.Lock()
|
||||||
|
defer h.recentAutoRegMutex.Unlock()
|
||||||
|
if _, exists := h.recentAutoRegistered["pve:node1"]; !exists {
|
||||||
|
t.Error("expected pve:node1 to still exist")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "successfully clears existing entry",
|
||||||
|
nodeType: "pve",
|
||||||
|
nodeName: "node1",
|
||||||
|
setup: func(h *ConfigHandlers) {
|
||||||
|
h.recentAutoRegistered["pve:node1"] = time.Now()
|
||||||
|
},
|
||||||
|
check: func(t *testing.T, h *ConfigHandlers) {
|
||||||
|
h.recentAutoRegMutex.Lock()
|
||||||
|
defer h.recentAutoRegMutex.Unlock()
|
||||||
|
if _, exists := h.recentAutoRegistered["pve:node1"]; exists {
|
||||||
|
t.Error("expected pve:node1 to be cleared")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-existent key does not error",
|
||||||
|
nodeType: "pve",
|
||||||
|
nodeName: "nonexistent",
|
||||||
|
setup: nil,
|
||||||
|
check: func(t *testing.T, h *ConfigHandlers) {
|
||||||
|
// Just verify no panic occurred and map is still valid
|
||||||
|
h.recentAutoRegMutex.Lock()
|
||||||
|
defer h.recentAutoRegMutex.Unlock()
|
||||||
|
if h.recentAutoRegistered == nil {
|
||||||
|
t.Error("map should not be nil")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cfg := &config.Config{
|
||||||
|
DataPath: t.TempDir(),
|
||||||
|
ConfigPath: t.TempDir(),
|
||||||
|
}
|
||||||
|
h := newTestConfigHandlers(t, cfg)
|
||||||
|
|
||||||
|
if tt.setup != nil {
|
||||||
|
tt.setup(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.clearAutoRegistered(tt.nodeType, tt.nodeName)
|
||||||
|
|
||||||
|
if tt.check != nil {
|
||||||
|
tt.check(t, h)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
70
internal/api/router_arch_test.go
Normal file
70
internal/api/router_arch_test.go
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestNormalizeDockerAgentArch(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
// Empty string
|
||||||
|
{"empty string", "", ""},
|
||||||
|
|
||||||
|
// amd64 variants
|
||||||
|
{"linux-amd64", "linux-amd64", "linux-amd64"},
|
||||||
|
{"amd64", "amd64", "linux-amd64"},
|
||||||
|
{"x86_64", "x86_64", "linux-amd64"},
|
||||||
|
{"x86-64", "x86-64", "linux-amd64"},
|
||||||
|
|
||||||
|
// arm64 variants
|
||||||
|
{"linux-arm64", "linux-arm64", "linux-arm64"},
|
||||||
|
{"arm64", "arm64", "linux-arm64"},
|
||||||
|
{"aarch64", "aarch64", "linux-arm64"},
|
||||||
|
|
||||||
|
// armv7 variants
|
||||||
|
{"linux-armv7", "linux-armv7", "linux-armv7"},
|
||||||
|
{"armv7", "armv7", "linux-armv7"},
|
||||||
|
{"armv7l", "armv7l", "linux-armv7"},
|
||||||
|
{"armhf", "armhf", "linux-armv7"},
|
||||||
|
|
||||||
|
// armv6 variants
|
||||||
|
{"linux-armv6", "linux-armv6", "linux-armv6"},
|
||||||
|
{"armv6", "armv6", "linux-armv6"},
|
||||||
|
{"armv6l", "armv6l", "linux-armv6"},
|
||||||
|
|
||||||
|
// 386 variants
|
||||||
|
{"linux-386", "linux-386", "linux-386"},
|
||||||
|
{"386", "386", "linux-386"},
|
||||||
|
{"i386", "i386", "linux-386"},
|
||||||
|
{"i686", "i686", "linux-386"},
|
||||||
|
|
||||||
|
// Unknown architecture
|
||||||
|
{"unknown arch", "unknown", ""},
|
||||||
|
{"invalid arch", "powerpc", ""},
|
||||||
|
{"mips", "mips", ""},
|
||||||
|
|
||||||
|
// Case insensitivity
|
||||||
|
{"AMD64 uppercase", "AMD64", "linux-amd64"},
|
||||||
|
{"X86_64 uppercase", "X86_64", "linux-amd64"},
|
||||||
|
{"AARCH64 uppercase", "AARCH64", "linux-arm64"},
|
||||||
|
{"ARMV7 uppercase", "ARMV7", "linux-armv7"},
|
||||||
|
{"mixed case LinuX-AmD64", "LinuX-AmD64", "linux-amd64"},
|
||||||
|
|
||||||
|
// Whitespace trimming
|
||||||
|
{"leading space", " amd64", "linux-amd64"},
|
||||||
|
{"trailing space", "amd64 ", "linux-amd64"},
|
||||||
|
{"both spaces", " amd64 ", "linux-amd64"},
|
||||||
|
{"tabs", "\tamd64\t", "linux-amd64"},
|
||||||
|
{"mixed whitespace", " \t arm64 \t ", "linux-arm64"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result := normalizeDockerAgentArch(tt.input)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("normalizeDockerAgentArch(%q) = %q, want %q", tt.input, result, tt.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue