style: Apply gofmt to 37 files

Standardize code formatting across test files and monitor.go.
No functional changes.
This commit is contained in:
rcourtman 2025-12-02 17:21:48 +00:00
parent ec6133afd8
commit 72af7bed5e
37 changed files with 251 additions and 253 deletions

View file

@ -45,8 +45,8 @@ other_key: value`,
expected: []string{"node1", "node2", "node3"},
},
{
name: "list format single item",
input: `- single-node`,
name: "list format single item",
input: `- single-node`,
expected: []string{"single-node"},
},
@ -94,8 +94,8 @@ allowed_nodes:
expected: []string{"node1", "node2"},
},
{
name: "map format allowed_nodes not a list",
input: `allowed_nodes: not-a-list`,
name: "map format allowed_nodes not a list",
input: `allowed_nodes: not-a-list`,
expected: nil,
},

View file

@ -8399,7 +8399,7 @@ func TestCleanup(t *testing.T) {
m.mu.Lock()
m.alertRateLimit["rate-limited"] = []time.Time{
time.Now().Add(-2 * time.Hour), // Old, should be removed
time.Now().Add(-2 * time.Hour), // Old, should be removed
time.Now().Add(-30 * time.Minute), // Recent, should remain
}
m.mu.Unlock()
@ -14443,9 +14443,9 @@ func TestCheckPMGQuarantineBacklog(t *testing.T) {
}
thresholds := PMGThresholdConfig{
QuarantineSpamWarn: 2000,
QuarantineSpamCritical: 5000,
QuarantineVirusWarn: 2000,
QuarantineSpamWarn: 2000,
QuarantineSpamCritical: 5000,
QuarantineVirusWarn: 2000,
QuarantineVirusCritical: 5000,
}
@ -14482,9 +14482,9 @@ func TestCheckPMGQuarantineBacklog(t *testing.T) {
}
thresholds := PMGThresholdConfig{
QuarantineSpamWarn: 2000,
QuarantineSpamCritical: 5000,
QuarantineVirusWarn: 2000,
QuarantineSpamWarn: 2000,
QuarantineSpamCritical: 5000,
QuarantineVirusWarn: 2000,
QuarantineVirusCritical: 5000,
}

View file

@ -11,17 +11,17 @@ func TestEvaluateVMCondition(t *testing.T) {
m := NewManager()
testVM := models.VM{
ID: "test-vm-1",
VMID: 100,
Name: "test-vm",
Node: "node1",
Status: "running",
CPU: 0.50, // 50%
Memory: models.Memory{Usage: 75.0},
Disk: models.Disk{Usage: 60.0},
DiskRead: 100 * 1024 * 1024, // 100 MB/s in bytes
DiskWrite: 50 * 1024 * 1024, // 50 MB/s in bytes
NetworkIn: 200 * 1024 * 1024, // 200 MB/s in bytes
ID: "test-vm-1",
VMID: 100,
Name: "test-vm",
Node: "node1",
Status: "running",
CPU: 0.50, // 50%
Memory: models.Memory{Usage: 75.0},
Disk: models.Disk{Usage: 60.0},
DiskRead: 100 * 1024 * 1024, // 100 MB/s in bytes
DiskWrite: 50 * 1024 * 1024, // 50 MB/s in bytes
NetworkIn: 200 * 1024 * 1024, // 200 MB/s in bytes
NetworkOut: 150 * 1024 * 1024, // 150 MB/s in bytes
}
@ -958,12 +958,12 @@ func TestMetricOperators(t *testing.T) {
}
tests := []struct {
name string
field string
operator string
value float64
vmValue float64 // expected processed value
want bool
name string
field string
operator string
value float64
vmValue float64 // expected processed value
want bool
}{
// Greater than
{"GT true", "cpu", ">", 40.0, 50.0, true},

View file

@ -311,8 +311,8 @@ func TestCleanOldEntries(t *testing.T) {
now := time.Now()
hm.history = []HistoryEntry{
{Alert: Alert{ID: "old1"}, Timestamp: now.AddDate(0, 0, -40)}, // 40 days old - should be removed
{Alert: Alert{ID: "old2"}, Timestamp: now.AddDate(0, 0, -35)}, // 35 days old - should be removed
{Alert: Alert{ID: "old1"}, Timestamp: now.AddDate(0, 0, -40)}, // 40 days old - should be removed
{Alert: Alert{ID: "old2"}, Timestamp: now.AddDate(0, 0, -35)}, // 35 days old - should be removed
{Alert: Alert{ID: "recent1"}, Timestamp: now.AddDate(0, 0, -25)}, // 25 days old - should stay
{Alert: Alert{ID: "recent2"}, Timestamp: now.AddDate(0, 0, -1)}, // 1 day old - should stay
}

View file

@ -1636,7 +1636,7 @@ func TestEnsureValidHysteresis(t *testing.T) {
threshold: &HysteresisThreshold{Trigger: 0, Clear: 0},
metricName: "disabled",
wantTrigger: 0,
wantClear: 0, // 0 - 5 = -5, clamped to 0 (same value, but fix attempted)
wantClear: 0, // 0 - 5 = -5, clamped to 0 (same value, but fix attempted)
expectChange: false, // Result same as input, even though fix was attempted
},
{

View file

@ -104,10 +104,10 @@ func TestDetectProxy(t *testing.T) {
func TestIsConnectionSecure(t *testing.T) {
tests := []struct {
name string
useTLS bool
headers map[string]string
want bool
name string
useTLS bool
headers map[string]string
want bool
}{
{
name: "plain HTTP no headers",
@ -158,7 +158,7 @@ func TestIsConnectionSecure(t *testing.T) {
want: true,
},
{
name: "both X-Forwarded-Proto and Forwarded present",
name: "both X-Forwarded-Proto and Forwarded present",
useTLS: false,
headers: map[string]string{
"X-Forwarded-Proto": "https",

View file

@ -106,9 +106,9 @@ func TestExtractHostAndPort(t *testing.T) {
wantPort: "8006",
},
{
name: "IPv6 with brackets no port returns error",
hostStr: "[2001:db8::1]",
wantErr: true, // net.SplitHostPort fails on bracketed IPv6 without port
name: "IPv6 with brackets no port returns error",
hostStr: "[2001:db8::1]",
wantErr: true, // net.SplitHostPort fails on bracketed IPv6 without port
},
{
name: "IPv6 with scheme brackets and port",
@ -171,14 +171,14 @@ func TestExtractHostAndPort(t *testing.T) {
// Error cases
{
name: "malformed brackets",
hostStr: "[2001:db8::1:8006",
wantErr: true,
name: "malformed brackets",
hostStr: "[2001:db8::1:8006",
wantErr: true,
},
{
name: "brackets without closing with port attempt",
hostStr: "[invalid:8006",
wantErr: true,
name: "brackets without closing with port attempt",
hostStr: "[invalid:8006",
wantErr: true,
},
}
@ -307,8 +307,8 @@ func TestDefaultPortForNodeType(t *testing.T) {
{"docker node returns empty", "docker", ""},
{"unknown type returns empty", "unknown", ""},
{"empty type returns empty", "", ""},
{"uppercase PVE returns empty", "PVE", ""}, // case sensitive
{"mixed case returns empty", "Pve", ""}, // case sensitive
{"uppercase PVE returns empty", "PVE", ""}, // case sensitive
{"mixed case returns empty", "Pve", ""}, // case sensitive
{"similar but wrong returns empty", "pvee", ""}, // exact match only
}

View file

@ -145,10 +145,10 @@ func TestNormalizePVEUser(t *testing.T) {
func TestShouldSkipClusterAutoDetection(t *testing.T) {
tests := []struct {
name string
host string
name string
host string
vmName string
want bool
want bool
}{
// Empty host cases
{

View file

@ -418,10 +418,10 @@ func TestMatchInstanceNameByHost(t *testing.T) {
t.Parallel()
tests := []struct {
name string
cfg *config.Config
host string
expected string
name string
cfg *config.Config
host string
expected string
}{
{
name: "nil config",

View file

@ -315,11 +315,11 @@ func TestGetRateLimiterForEndpoint_PriorityOrder(t *testing.T) {
InitializeRateLimiters()
tests := []struct {
name string
path string
method string
wantLimiterNm string
reason string
name string
path string
method string
wantLimiterNm string
reason string
}{
{
name: "recovery takes priority over security status",

View file

@ -912,12 +912,12 @@ func TestResolvePublicURL_ConfiguredPublicURL(t *testing.T) {
func TestResolvePublicURL_FromRequest(t *testing.T) {
tests := []struct {
name string
host string
useTLS bool
xForwardProto string
frontendPort int
want string
name string
host string
useTLS bool
xForwardProto string
frontendPort int
want string
}{
{
name: "HTTP request with host header",

View file

@ -7,11 +7,11 @@ import (
func TestGetClientIP(t *testing.T) {
tests := []struct {
name string
xff string // X-Forwarded-For header
xri string // X-Real-IP header
remoteAddr string // Request.RemoteAddr
expectedIP string
name string
xff string // X-Forwarded-For header
xri string // X-Real-IP header
remoteAddr string // Request.RemoteAddr
expectedIP string
}{
// X-Forwarded-For takes priority
{

View file

@ -82,16 +82,16 @@ func TestCreateProxmoxConfigFromFields(t *testing.T) {
t.Parallel()
tests := []struct {
name string
host string
user string
password string
tokenName string
tokenValue string
fingerprint string
verifySSL bool
expectedUser string
expectedHost string
name string
host string
user string
password string
tokenName string
tokenValue string
fingerprint string
verifySSL bool
expectedUser string
expectedHost string
}{
{
name: "user without realm gets @pam appended (password auth)",

View file

@ -187,8 +187,8 @@ func TestCalculateCPUPercent(t *testing.T) {
stats: containertypes.StatsResponse{
CPUStats: containertypes.CPUStats{
CPUUsage: containertypes.CPUUsage{
TotalUsage: 200000000,
PercpuUsage: []uint64{1, 2, 3, 4}, // 4 CPUs
TotalUsage: 200000000,
PercpuUsage: []uint64{1, 2, 3, 4}, // 4 CPUs
},
SystemUsage: 2000000000,
OnlineCPUs: 0,
@ -1018,10 +1018,10 @@ func TestDetermineSelfUpdateArch(t *testing.T) {
// Should be one of the known values or empty (if architecture unknown)
validArches := map[string]bool{
"": true,
"linux-amd64": true,
"linux-arm64": true,
"linux-armv7": true,
"": true,
"linux-amd64": true,
"linux-arm64": true,
"linux-armv7": true,
}
if !validArches[got] {

View file

@ -71,4 +71,3 @@ func TestNormalisePlatform(t *testing.T) {
})
}
}

View file

@ -72,8 +72,8 @@ func TestUpsertDockerHost(t *testing.T) {
// Test PendingUninstall flag preservation
state.SetDockerHostPendingUninstall("host-1", true)
host1Reset2 := DockerHost{
ID: "host-1",
Hostname: "docker-host-1",
ID: "host-1",
Hostname: "docker-host-1",
PendingUninstall: false,
}
state.UpsertDockerHost(host1Reset2)

View file

@ -278,7 +278,7 @@ func TestParseContainerConfigNetworks(t *testing.T) {
{
name: "no net keys",
input: map[string]interface{}{
"cores": 2,
"cores": 2,
"memory": 2048,
},
want: nil,

View file

@ -782,14 +782,14 @@ func TestResolveDockerHostIdentifier(t *testing.T) {
t.Parallel()
tests := []struct {
name string
report agentsdocker.Report
tokenRecord *config.APITokenRecord
hosts []models.DockerHost
expectMatch bool
expectFallbacks int
expectedID string
checkIDFormat bool
name string
report agentsdocker.Report
tokenRecord *config.APITokenRecord
hosts []models.DockerHost
expectMatch bool
expectFallbacks int
expectedID string
checkIDFormat bool
}{
{
name: "existing host match",

View file

@ -816,7 +816,7 @@ func TestTryReserveGuestMetadataFetch(t *testing.T) {
t.Parallel()
m := &Monitor{
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataHoldDuration: 15 * time.Second,
}
now := time.Now()
@ -885,7 +885,7 @@ func TestTryReserveGuestMetadataFetch(t *testing.T) {
t.Parallel()
m := &Monitor{
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataHoldDuration: 0, // zero triggers default
}
now := time.Now()
@ -905,7 +905,7 @@ func TestTryReserveGuestMetadataFetch(t *testing.T) {
t.Parallel()
m := &Monitor{
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataHoldDuration: -5 * time.Second, // negative triggers default
}
now := time.Now()
@ -1016,10 +1016,10 @@ func TestScheduleNextGuestMetadataFetch(t *testing.T) {
rng := newDeterministicRng(42)
m := &Monitor{
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataMinRefresh: 1 * time.Minute,
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataMinRefresh: 1 * time.Minute,
guestMetadataRefreshJitter: 30 * time.Second,
rng: rng,
rng: rng,
}
now := time.Now()
@ -1038,10 +1038,10 @@ func TestScheduleNextGuestMetadataFetch(t *testing.T) {
t.Parallel()
m := &Monitor{
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataMinRefresh: 1 * time.Minute,
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataMinRefresh: 1 * time.Minute,
guestMetadataRefreshJitter: 30 * time.Second, // jitter configured but rng is nil
rng: nil,
rng: nil,
}
now := time.Now()
@ -1060,10 +1060,10 @@ func TestScheduleNextGuestMetadataFetch(t *testing.T) {
rng := newDeterministicRng(42)
m := &Monitor{
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataMinRefresh: 1 * time.Minute,
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataMinRefresh: 1 * time.Minute,
guestMetadataRefreshJitter: 0, // zero jitter
rng: rng,
rng: rng,
}
now := time.Now()
@ -1082,10 +1082,10 @@ func TestScheduleNextGuestMetadataFetch(t *testing.T) {
rng := newDeterministicRng(42)
m := &Monitor{
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataMinRefresh: 1 * time.Minute,
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataMinRefresh: 1 * time.Minute,
guestMetadataRefreshJitter: -10 * time.Second, // negative jitter
rng: rng,
rng: rng,
}
now := time.Now()
@ -1135,7 +1135,7 @@ func TestDeferGuestMetadataRetry(t *testing.T) {
t.Parallel()
m := &Monitor{
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataRetryBackoff: 0, // zero triggers default
}
now := time.Now()
@ -1157,7 +1157,7 @@ func TestDeferGuestMetadataRetry(t *testing.T) {
t.Parallel()
m := &Monitor{
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataRetryBackoff: -10 * time.Second, // negative triggers default
}
now := time.Now()
@ -1175,7 +1175,7 @@ func TestDeferGuestMetadataRetry(t *testing.T) {
t.Parallel()
m := &Monitor{
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataLimiter: make(map[string]time.Time),
guestMetadataRetryBackoff: 45 * time.Second,
}
now := time.Now()

View file

@ -27,21 +27,21 @@ func TestMergeNVMeTempsIntoDisks(t *testing.T) {
expected: []models.PhysicalDisk{{Node: "node1", DevPath: "/dev/sda", Temperature: 0}},
},
{
name: "nil temperature returns disks unchanged",
disks: []models.PhysicalDisk{{Node: "node1", DevPath: "/dev/sda", Temperature: 0}},
nodes: []models.Node{{Name: "node1", Temperature: nil}},
name: "nil temperature returns disks unchanged",
disks: []models.PhysicalDisk{{Node: "node1", DevPath: "/dev/sda", Temperature: 0}},
nodes: []models.Node{{Name: "node1", Temperature: nil}},
expected: []models.PhysicalDisk{{Node: "node1", DevPath: "/dev/sda", Temperature: 0}},
},
{
name: "temperature available false returns disks unchanged",
disks: []models.PhysicalDisk{{Node: "node1", DevPath: "/dev/sda", Temperature: 0}},
nodes: []models.Node{{Name: "node1", Temperature: &models.Temperature{Available: false}}},
name: "temperature available false returns disks unchanged",
disks: []models.PhysicalDisk{{Node: "node1", DevPath: "/dev/sda", Temperature: 0}},
nodes: []models.Node{{Name: "node1", Temperature: &models.Temperature{Available: false}}},
expected: []models.PhysicalDisk{{Node: "node1", DevPath: "/dev/sda", Temperature: 0}},
},
{
name: "no SMART or NVMe temps returns disks unchanged",
disks: []models.PhysicalDisk{{Node: "node1", DevPath: "/dev/sda", Temperature: 0}},
nodes: []models.Node{{Name: "node1", Temperature: &models.Temperature{Available: true, SMART: nil, NVMe: nil}}},
name: "no SMART or NVMe temps returns disks unchanged",
disks: []models.PhysicalDisk{{Node: "node1", DevPath: "/dev/sda", Temperature: 0}},
nodes: []models.Node{{Name: "node1", Temperature: &models.Temperature{Available: true, SMART: nil, NVMe: nil}}},
expected: []models.PhysicalDisk{{Node: "node1", DevPath: "/dev/sda", Temperature: 0}},
},
{

View file

@ -113,7 +113,7 @@ func TestAppendMetric(t *testing.T) {
maxDataPoints: 100,
retentionTime: 30 * time.Minute,
existing: []MetricPoint{
{Value: 10.0, Timestamp: now.Add(-2 * time.Hour)}, // beyond retention
{Value: 10.0, Timestamp: now.Add(-2 * time.Hour)}, // beyond retention
{Value: 20.0, Timestamp: now.Add(-90 * time.Minute)}, // beyond retention
{Value: 30.0, Timestamp: now.Add(-20 * time.Minute)}, // within retention
},
@ -1111,12 +1111,12 @@ func TestRetentionTimeEnforced(t *testing.T) {
mh := NewMetricsHistory(100, retentionTime)
// Add points at various times
mh.AddGuestMetric("vm-100", "cpu", 10.0, now.Add(-2*time.Hour)) // beyond retention
mh.AddGuestMetric("vm-100", "cpu", 20.0, now.Add(-1*time.Hour)) // beyond retention
mh.AddGuestMetric("vm-100", "cpu", 10.0, now.Add(-2*time.Hour)) // beyond retention
mh.AddGuestMetric("vm-100", "cpu", 20.0, now.Add(-1*time.Hour)) // beyond retention
mh.AddGuestMetric("vm-100", "cpu", 30.0, now.Add(-45*time.Minute)) // beyond retention
mh.AddGuestMetric("vm-100", "cpu", 40.0, now.Add(-20*time.Minute)) // within retention
mh.AddGuestMetric("vm-100", "cpu", 50.0, now.Add(-10*time.Minute)) // within retention
mh.AddGuestMetric("vm-100", "cpu", 60.0, now) // within retention
mh.AddGuestMetric("vm-100", "cpu", 60.0, now) // within retention
// appendMetric removes old points on each add
result := mh.GetGuestMetrics("vm-100", "cpu", time.Hour)

View file

@ -792,8 +792,8 @@ func TestRecordResult_LabelsSanitized(t *testing.T) {
pm := newFullTestPollMetrics(t)
pm.RecordResult(PollResult{
InstanceType: "", // Should become "unknown"
InstanceName: " ", // Should become "unknown"
InstanceType: "", // Should become "unknown"
InstanceName: " ", // Should become "unknown"
StartTime: time.Now().Add(-time.Second),
EndTime: time.Now(),
Success: true,

View file

@ -875,8 +875,8 @@ const (
hostMinimumHealthWindow = 30 * time.Second
hostMaximumHealthWindow = 10 * time.Minute
nodeOfflineGracePeriod = 60 * time.Second // Grace period before marking Proxmox nodes offline
nodeRRDCacheTTL = 30 * time.Second
nodeRRDRequestTimeout = 2 * time.Second
nodeRRDCacheTTL = 30 * time.Second
nodeRRDRequestTimeout = 2 * time.Second
)
type taskOutcome struct {

View file

@ -96,8 +96,8 @@ func TestShouldRunBackupPoll(t *testing.T) {
name: "cycle-based: pollCounter=1 returns true",
monitor: &Monitor{
config: &config.Config{
EnableBackupPolling: true,
BackupPollingCycles: 10,
EnableBackupPolling: true,
BackupPollingCycles: 10,
BackupPollingInterval: 0,
},
pollCounter: 1,
@ -112,8 +112,8 @@ func TestShouldRunBackupPoll(t *testing.T) {
name: "cycle-based: pollCounter divisible by cycles returns true",
monitor: &Monitor{
config: &config.Config{
EnableBackupPolling: true,
BackupPollingCycles: 5,
EnableBackupPolling: true,
BackupPollingCycles: 5,
BackupPollingInterval: 0,
},
pollCounter: 15, // 15 % 5 == 0
@ -128,8 +128,8 @@ func TestShouldRunBackupPoll(t *testing.T) {
name: "cycle-based: pollCounter not divisible returns false",
monitor: &Monitor{
config: &config.Config{
EnableBackupPolling: true,
BackupPollingCycles: 5,
EnableBackupPolling: true,
BackupPollingCycles: 5,
BackupPollingInterval: 0,
},
pollCounter: 7, // 7 % 5 == 2, remaining = 3
@ -144,8 +144,8 @@ func TestShouldRunBackupPoll(t *testing.T) {
name: "default cycles (10) when BackupPollingCycles is 0",
monitor: &Monitor{
config: &config.Config{
EnableBackupPolling: true,
BackupPollingCycles: 0, // should default to 10
EnableBackupPolling: true,
BackupPollingCycles: 0, // should default to 10
BackupPollingInterval: 0,
},
pollCounter: 10, // 10 % 10 == 0
@ -160,8 +160,8 @@ func TestShouldRunBackupPoll(t *testing.T) {
name: "default cycles (10) when BackupPollingCycles is negative",
monitor: &Monitor{
config: &config.Config{
EnableBackupPolling: true,
BackupPollingCycles: -5, // should default to 10
EnableBackupPolling: true,
BackupPollingCycles: -5, // should default to 10
BackupPollingInterval: 0,
},
pollCounter: 20, // 20 % 10 == 0
@ -176,8 +176,8 @@ func TestShouldRunBackupPoll(t *testing.T) {
name: "default cycles (10) not divisible returns false with correct remaining",
monitor: &Monitor{
config: &config.Config{
EnableBackupPolling: true,
BackupPollingCycles: 0, // defaults to 10
EnableBackupPolling: true,
BackupPollingCycles: 0, // defaults to 10
BackupPollingInterval: 0,
},
pollCounter: 3, // 3 % 10 == 3, remaining = 7

View file

@ -96,9 +96,9 @@ func TestRecordTaskResult_NilMonitor(t *testing.T) {
func TestRecordTaskResult_Success(t *testing.T) {
m := &Monitor{
pollStatusMap: make(map[string]*pollStatus),
failureCounts: make(map[string]int),
lastOutcome: make(map[string]taskOutcome),
pollStatusMap: make(map[string]*pollStatus),
failureCounts: make(map[string]int),
lastOutcome: make(map[string]taskOutcome),
circuitBreakers: make(map[string]*circuitBreaker),
}
@ -133,9 +133,9 @@ func TestRecordTaskResult_Success(t *testing.T) {
func TestRecordTaskResult_Failure(t *testing.T) {
m := &Monitor{
pollStatusMap: make(map[string]*pollStatus),
failureCounts: make(map[string]int),
lastOutcome: make(map[string]taskOutcome),
pollStatusMap: make(map[string]*pollStatus),
failureCounts: make(map[string]int),
lastOutcome: make(map[string]taskOutcome),
circuitBreakers: make(map[string]*circuitBreaker),
}
@ -178,9 +178,9 @@ func TestRecordTaskResult_Failure(t *testing.T) {
func TestRecordTaskResult_ConsecutiveFailures(t *testing.T) {
m := &Monitor{
pollStatusMap: make(map[string]*pollStatus),
failureCounts: make(map[string]int),
lastOutcome: make(map[string]taskOutcome),
pollStatusMap: make(map[string]*pollStatus),
failureCounts: make(map[string]int),
lastOutcome: make(map[string]taskOutcome),
circuitBreakers: make(map[string]*circuitBreaker),
}
@ -207,9 +207,9 @@ func TestRecordTaskResult_ConsecutiveFailures(t *testing.T) {
func TestRecordTaskResult_SuccessResetsFailures(t *testing.T) {
m := &Monitor{
pollStatusMap: make(map[string]*pollStatus),
failureCounts: make(map[string]int),
lastOutcome: make(map[string]taskOutcome),
pollStatusMap: make(map[string]*pollStatus),
failureCounts: make(map[string]int),
lastOutcome: make(map[string]taskOutcome),
circuitBreakers: make(map[string]*circuitBreaker),
}
@ -242,9 +242,9 @@ func TestRecordTaskResult_SuccessResetsFailures(t *testing.T) {
func TestRecordTaskResult_NilMaps(t *testing.T) {
// Monitor with nil internal maps - should not panic
m := &Monitor{
pollStatusMap: make(map[string]*pollStatus),
failureCounts: nil, // nil
lastOutcome: nil, // nil
pollStatusMap: make(map[string]*pollStatus),
failureCounts: nil, // nil
lastOutcome: nil, // nil
circuitBreakers: make(map[string]*circuitBreaker),
}
@ -711,10 +711,10 @@ func TestRescheduleTask_PMGInstance(t *testing.T) {
func TestRescheduleTask_AdaptivePollingMaxIntervalLimit(t *testing.T) {
cfg := &config.Config{
PVEPollingInterval: 30 * time.Second,
AdaptivePollingEnabled: true,
AdaptivePollingMaxInterval: 10 * time.Second, // <= 15s enables capping
AdaptivePollingBaseInterval: 5 * time.Second,
PVEPollingInterval: 30 * time.Second,
AdaptivePollingEnabled: true,
AdaptivePollingMaxInterval: 10 * time.Second, // <= 15s enables capping
AdaptivePollingBaseInterval: 5 * time.Second,
}
m := &Monitor{

View file

@ -2289,23 +2289,23 @@ func TestEnsureBreaker(t *testing.T) {
wantExisting bool
}{
{
name: "nil circuitBreakers map gets initialized",
circuitBreakers: nil,
key: "test-key",
wantRetryInterval: 5 * time.Second,
wantMaxDelay: 5 * time.Minute,
wantHalfOpenWindow: 30 * time.Second,
wantExisting: false,
name: "nil circuitBreakers map gets initialized",
circuitBreakers: nil,
key: "test-key",
wantRetryInterval: 5 * time.Second,
wantMaxDelay: 5 * time.Minute,
wantHalfOpenWindow: 30 * time.Second,
wantExisting: false,
},
{
name: "existing breaker for key is returned",
circuitBreakers: map[string]*circuitBreaker{},
existingBreaker: newCircuitBreaker(3, 10*time.Second, 10*time.Minute, 60*time.Second),
key: "existing-key",
wantRetryInterval: 10 * time.Second,
wantMaxDelay: 10 * time.Minute,
wantHalfOpenWindow: 60 * time.Second,
wantExisting: true,
name: "existing breaker for key is returned",
circuitBreakers: map[string]*circuitBreaker{},
existingBreaker: newCircuitBreaker(3, 10*time.Second, 10*time.Minute, 60*time.Second),
key: "existing-key",
wantRetryInterval: 10 * time.Second,
wantMaxDelay: 10 * time.Minute,
wantHalfOpenWindow: 60 * time.Second,
wantExisting: true,
},
{
name: "new breaker with default values (all config fields zero)",

View file

@ -142,7 +142,7 @@ func TestConvertPBSSnapshots(t *testing.T) {
Files: []interface{}{
map[string]interface{}{"filename": "valid.raw"},
map[string]interface{}{"name": "invalid.raw"}, // Wrong field name
map[string]interface{}{}, // Empty object
map[string]interface{}{}, // Empty object
},
},
}

View file

@ -464,10 +464,10 @@ func TestCalculateRates_DoesNotUpdatePreviousOnStaleData(t *testing.T) {
// Second call with stale data (same values, different timestamp)
metrics2 := types.IOMetrics{
DiskRead: 1000, // same
DiskWrite: 2000, // same
NetworkIn: 3000, // same
NetworkOut: 4000, // same
DiskRead: 1000, // same
DiskWrite: 2000, // same
NetworkIn: 3000, // same
NetworkOut: 4000, // same
Timestamp: baseTime.Add(10 * time.Second), // different time
}
rt.CalculateRates("vm-100", metrics2)

View file

@ -849,8 +849,8 @@ func TestAdaptiveIntervalSelector_JitterDeterministic(t *testing.T) {
name: "jitter within bounds",
seed: 12345,
score: 0.5,
wantMin: 19 * time.Second, // slightly below min due to jitter
wantMax: 41 * time.Second, // slightly above base due to jitter
wantMin: 19 * time.Second, // slightly below min due to jitter
wantMax: 41 * time.Second, // slightly above base due to jitter
iterations: 50,
},
{
@ -905,11 +905,11 @@ func TestAdaptiveIntervalSelector_JitterDeterministic(t *testing.T) {
// TestAdaptiveIntervalSelector_BoundaryConditions tests edge cases
func TestAdaptiveIntervalSelector_BoundaryConditions(t *testing.T) {
tests := []struct {
name string
cfg SchedulerConfig
req IntervalRequest
wantMin time.Duration
wantMax time.Duration
name string
cfg SchedulerConfig
req IntervalRequest
wantMin time.Duration
wantMax time.Duration
}{
{
name: "zero intervals default to min",
@ -1696,7 +1696,7 @@ func TestAdaptiveIntervalSelector_TargetBelowMinClamp(t *testing.T) {
// This hits the code path but with corrected values
req := IntervalRequest{
BaseInterval: cfg.BaseInterval,
MinInterval: -5 * time.Second, // negative min
MinInterval: -5 * time.Second, // negative min
MaxInterval: -10 * time.Second, // negative max < negative min
StalenessScore: 0.5,
InstanceKey: "test-target-below-min",

View file

@ -452,7 +452,6 @@ func TestParseRPiTemperature(t *testing.T) {
}
}
func TestParseSensorsJSON_PiPartialSensors(t *testing.T) {
collector := &TemperatureCollector{}
@ -1096,19 +1095,19 @@ func TestExtractCoreNumber(t *testing.T) {
{"Core 10", 10},
{"Core 99", 99},
{"Core 127", 127},
{"Core", 0}, // missing number
{"Core ", 0}, // trailing space, no number
{"core 5", 5}, // lowercase
{"CORE 7", 7}, // uppercase
{"Core 12", 12}, // extra space (Fields handles this)
{"", 0}, // empty string
{" ", 0}, // whitespace only
{"Core abc", 0}, // non-numeric
{"Package id 0", 0}, // last part is "0"
{"temp1", 0}, // no spaces
{"Core 1000", 1000}, // large core number
{"Prefix Core 5", 5}, // core not at start
{"Core 0 extra", 0}, // text after number - "extra" is last field
{"Core", 0}, // missing number
{"Core ", 0}, // trailing space, no number
{"core 5", 5}, // lowercase
{"CORE 7", 7}, // uppercase
{"Core 12", 12}, // extra space (Fields handles this)
{"", 0}, // empty string
{" ", 0}, // whitespace only
{"Core abc", 0}, // non-numeric
{"Package id 0", 0}, // last part is "0"
{"temp1", 0}, // no spaces
{"Core 1000", 1000}, // large core number
{"Prefix Core 5", 5}, // core not at start
{"Core 0 extra", 0}, // text after number - "extra" is last field
}
for _, tt := range tests {

View file

@ -322,10 +322,10 @@ func TestSendEmailOnce_BuildsMultipartMessage(t *testing.T) {
func TestTestConnection_TLSRouting(t *testing.T) {
tests := []struct {
name string
tls bool
port int
wantTLS bool
name string
tls bool
port int
wantTLS bool
}{
{"TLS true uses TLS dial", true, 587, true},
{"Port 465 uses TLS dial", false, 465, true},

View file

@ -312,9 +312,9 @@ func TestResolvedTimeFromAlerts(t *testing.T) {
fixedTimeStr := fixedTime.Format(time.RFC3339)
tests := []struct {
name string
alerts []*alerts.Alert
checkFn func(*testing.T, time.Time)
name string
alerts []*alerts.Alert
checkFn func(*testing.T, time.Time)
}{
{
name: "nil slice - returns current time",
@ -679,9 +679,9 @@ func TestCopyWebhookConfigs(t *testing.T) {
name: "multiple webhooks with all fields",
webhooks: []WebhookConfig{
{
Enabled: true,
URL: "https://discord.com/api/webhooks/123",
Headers: map[string]string{"X-Custom": "value"},
Enabled: true,
URL: "https://discord.com/api/webhooks/123",
Headers: map[string]string{"X-Custom": "value"},
CustomFields: map[string]string{"key": "val"},
},
{

View file

@ -373,13 +373,13 @@ func TestVersionPatternValidation(t *testing.T) {
{"master", false},
{"main", false},
{"HEAD", false},
{"1.0.0-", false}, // trailing dash
{"1.0.0+", false}, // trailing plus
{"-1.0.0", false}, // leading dash
{"v-1.0.0", false}, // invalid prefix
{"V1.0.0", false}, // uppercase V not allowed
{"1.0.0--alpha", true}, // double dash allowed (not a security risk)
{"1.0.0++build", false}, // double plus
{"1.0.0-", false}, // trailing dash
{"1.0.0+", false}, // trailing plus
{"-1.0.0", false}, // leading dash
{"v-1.0.0", false}, // invalid prefix
{"V1.0.0", false}, // uppercase V not allowed
{"1.0.0--alpha", true}, // double dash allowed (not a security risk)
{"1.0.0++build", false}, // double plus
{"1.0.0-alpha_1", false}, // underscore not allowed in prerelease
{"1.0.0+build_1", false}, // underscore not allowed in build metadata
}

View file

@ -77,9 +77,9 @@ func TestParseVersion(t *testing.T) {
wantMajor: 4, wantMinor: 24, wantPatch: 0,
},
{
name: "with prerelease",
input: "4.24.0-rc.3",
wantMajor: 4, wantMinor: 24, wantPatch: 0,
name: "with prerelease",
input: "4.24.0-rc.3",
wantMajor: 4, wantMinor: 24, wantPatch: 0,
wantPrerel: "rc.3",
},
{
@ -89,9 +89,9 @@ func TestParseVersion(t *testing.T) {
wantBuild: "build.123",
},
{
name: "with prerelease and build",
input: "4.24.0-rc.3+build.123",
wantMajor: 4, wantMinor: 24, wantPatch: 0,
name: "with prerelease and build",
input: "4.24.0-rc.3+build.123",
wantMajor: 4, wantMinor: 24, wantPatch: 0,
wantPrerel: "rc.3",
wantBuild: "build.123",
},

View file

@ -440,12 +440,12 @@ func TestFlexibleTypes_InStruct(t *testing.T) {
func TestFlexibleTypes_PMGResponsePatterns(t *testing.T) {
// Simulates real PMG API response patterns observed in production
type MailStats struct {
Count flexibleFloat `json:"count"`
CountIn flexibleFloat `json:"count_in"`
SpamCount flexibleFloat `json:"spamcount_in"`
BouncesIn flexibleFloat `json:"bounces_in"`
BytesIn flexibleFloat `json:"bytes_in"`
AvgTime flexibleFloat `json:"avptime"`
Count flexibleFloat `json:"count"`
CountIn flexibleFloat `json:"count_in"`
SpamCount flexibleFloat `json:"spamcount_in"`
BouncesIn flexibleFloat `json:"bounces_in"`
BytesIn flexibleFloat `json:"bytes_in"`
AvgTime flexibleFloat `json:"avptime"`
}
input := `{

View file

@ -145,10 +145,10 @@ func TestExtractStatusCode(t *testing.T) {
func TestIsTransientRateLimitError(t *testing.T) {
tests := []struct {
name string
err error
name string
err error
wantTransient bool
wantCode int
wantCode int
}{
{"nil error", nil, false, 0},
{"generic error", errors.New("connection refused"), false, 0},

View file

@ -359,10 +359,10 @@ func TestParseReplicationTime(t *testing.T) {
func TestParseDurationSeconds(t *testing.T) {
tests := []struct {
name string
input interface{}
wantSecs int
wantHuman string
name string
input interface{}
wantSecs int
wantHuman string
}{
// nil
{"nil", nil, 0, ""},
@ -526,17 +526,17 @@ func TestCopyFloat(t *testing.T) {
func TestParseReplicationJob(t *testing.T) {
entry := map[string]json.RawMessage{
"id": json.RawMessage(`"100-0"`),
"guest": json.RawMessage(`100`),
"source": json.RawMessage(`"node1"`),
"target": json.RawMessage(`"node2"`),
"schedule": json.RawMessage(`"*/15"`),
"type": json.RawMessage(`"local"`),
"state": json.RawMessage(`"ok"`),
"enabled": json.RawMessage(`1`),
"last_sync": json.RawMessage(`1736936400`),
"fail_count": json.RawMessage(`0`),
"rate": json.RawMessage(`10.5`),
"id": json.RawMessage(`"100-0"`),
"guest": json.RawMessage(`100`),
"source": json.RawMessage(`"node1"`),
"target": json.RawMessage(`"node2"`),
"schedule": json.RawMessage(`"*/15"`),
"type": json.RawMessage(`"local"`),
"state": json.RawMessage(`"ok"`),
"enabled": json.RawMessage(`1`),
"last_sync": json.RawMessage(`1736936400`),
"fail_count": json.RawMessage(`0`),
"rate": json.RawMessage(`10.5`),
}
job := parseReplicationJob(entry)