test: Add tests for normalizeEndpointHost, taskExecutionTimeout, decrementPending
- normalizeEndpointHost: 89%→94.4% (19 cases covering schemes, ports, paths, edge cases) - taskExecutionTimeout: 83%→100% (4 cases covering defaults and custom timeouts) - decrementPending: 88%→100% (5 cases covering decrement logic and no-op scenarios)
This commit is contained in:
parent
6183727368
commit
acb7f4cf3a
3 changed files with 184 additions and 7 deletions
|
|
@ -17,20 +17,49 @@ func TestNormalizeEndpointHost(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
{"", ""},
|
||||
{" node.local ", "node.local"},
|
||||
{"https://node.local:8006/", "node.local"},
|
||||
{"node.local:8006", "node.local"},
|
||||
{"node.local/path", "node.local"},
|
||||
{"https://[2001:db8::1]:8006", "2001:db8::1"},
|
||||
// Empty and whitespace
|
||||
{"empty string", "", ""},
|
||||
{"whitespace only", " ", ""},
|
||||
{"whitespace with tabs", " \t ", ""},
|
||||
|
||||
// Full URLs with scheme
|
||||
{"https URL with port and path", "https://example.com:8006/api", "example.com"},
|
||||
{"http URL with path", "http://host/path", "host"},
|
||||
{"https URL with trailing slash", "https://node.local:8006/", "node.local"},
|
||||
|
||||
// URLs without scheme
|
||||
{"host with port", "example.com:8006", "example.com"},
|
||||
{"host with port no scheme", "node.local:8006", "node.local"},
|
||||
|
||||
// Hostname only
|
||||
{"hostname only", "example.com", "example.com"},
|
||||
{"simple hostname", "node.local", "node.local"},
|
||||
|
||||
// IP addresses
|
||||
{"IPv4 with port", "192.168.1.1:8006", "192.168.1.1"},
|
||||
{"IPv4 only", "192.168.1.100", "192.168.1.100"},
|
||||
{"IPv6 bracketed with port", "https://[2001:db8::1]:8006", "2001:db8::1"},
|
||||
|
||||
// Host with path (no scheme)
|
||||
{"host with path no scheme", "node.local/path", "node.local"},
|
||||
{"host with deep path", "server.example.com/api/v1/resource", "server.example.com"},
|
||||
|
||||
// Edge cases with just scheme prefix
|
||||
{"just https prefix", "https://", ""},
|
||||
{"just http prefix", "http://", ""},
|
||||
|
||||
// Whitespace trimming
|
||||
{"whitespace around hostname", " node.local ", "node.local"},
|
||||
{"whitespace around URL", " https://example.com:8006 ", "example.com"},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.input, func(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := normalizeEndpointHost(tc.input); got != tc.want {
|
||||
t.Fatalf("normalizeEndpointHost(%q) = %q, want %q", tc.input, got, tc.want)
|
||||
|
|
|
|||
|
|
@ -1094,3 +1094,104 @@ func TestDecInFlight_DecrementsGauge(t *testing.T) {
|
|||
t.Errorf("inflight{pve} = %v, want 0 after full decrement", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecrementPending_NilPollMetrics(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var pm *PollMetrics
|
||||
// Should not panic
|
||||
pm.decrementPending()
|
||||
}
|
||||
|
||||
func TestDecrementPending_DecrementsWhenPositive(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pm := newFullTestPollMetrics(t)
|
||||
|
||||
// Set initial pending count
|
||||
pm.ResetQueueDepth(5)
|
||||
|
||||
pm.decrementPending()
|
||||
|
||||
pm.mu.RLock()
|
||||
gotPending := pm.pending
|
||||
pm.mu.RUnlock()
|
||||
|
||||
if gotPending != 4 {
|
||||
t.Errorf("pending = %v, want 4 after decrement from 5", gotPending)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecrementPending_DoesNotGoBelowZero(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pm := newFullTestPollMetrics(t)
|
||||
|
||||
// Start at 0 (default)
|
||||
pm.decrementPending()
|
||||
|
||||
pm.mu.RLock()
|
||||
gotPending := pm.pending
|
||||
pm.mu.RUnlock()
|
||||
|
||||
if gotPending != 0 {
|
||||
t.Errorf("pending = %v, want 0 (should not go negative)", gotPending)
|
||||
}
|
||||
|
||||
// Also verify the gauge is 0
|
||||
gotQueueDepth := getGaugeValue(pm.queueDepth)
|
||||
if gotQueueDepth != 0 {
|
||||
t.Errorf("queueDepth gauge = %v, want 0", gotQueueDepth)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecrementPending_UpdatesQueueDepthGauge(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pm := newFullTestPollMetrics(t)
|
||||
|
||||
pm.ResetQueueDepth(10)
|
||||
pm.decrementPending()
|
||||
|
||||
gotQueueDepth := getGaugeValue(pm.queueDepth)
|
||||
if gotQueueDepth != 9 {
|
||||
t.Errorf("queueDepth gauge = %v, want 9", gotQueueDepth)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecrementPending_MultipleDecrements(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pm := newFullTestPollMetrics(t)
|
||||
|
||||
pm.ResetQueueDepth(5)
|
||||
|
||||
// Decrement 5 times
|
||||
for i := 0; i < 5; i++ {
|
||||
pm.decrementPending()
|
||||
}
|
||||
|
||||
pm.mu.RLock()
|
||||
gotPending := pm.pending
|
||||
pm.mu.RUnlock()
|
||||
|
||||
if gotPending != 0 {
|
||||
t.Errorf("pending = %v, want 0 after 5 decrements from 5", gotPending)
|
||||
}
|
||||
|
||||
gotQueueDepth := getGaugeValue(pm.queueDepth)
|
||||
if gotQueueDepth != 0 {
|
||||
t.Errorf("queueDepth gauge = %v, want 0", gotQueueDepth)
|
||||
}
|
||||
|
||||
// Decrement one more time - should stay at 0
|
||||
pm.decrementPending()
|
||||
|
||||
pm.mu.RLock()
|
||||
gotPending = pm.pending
|
||||
pm.mu.RUnlock()
|
||||
|
||||
if gotPending != 0 {
|
||||
t.Errorf("pending = %v, want 0 after extra decrement", gotPending)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,4 +65,51 @@ func TestTaskExecutionTimeout(t *testing.T) {
|
|||
t.Fatalf("taskExecutionTimeout() = %v, want %v", got, defaultTaskTimeout)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("nil Monitor returns defaultTaskTimeout", func(t *testing.T) {
|
||||
var m *Monitor
|
||||
got := m.taskExecutionTimeout(InstanceTypePVE)
|
||||
if got != defaultTaskTimeout {
|
||||
t.Fatalf("taskExecutionTimeout() = %v, want %v", got, defaultTaskTimeout)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("zero pollTimeout returns defaultTaskTimeout", func(t *testing.T) {
|
||||
m := &Monitor{pollTimeout: 0}
|
||||
got := m.taskExecutionTimeout(InstanceTypePVE)
|
||||
if got != defaultTaskTimeout {
|
||||
t.Fatalf("taskExecutionTimeout() = %v, want %v", got, defaultTaskTimeout)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("negative pollTimeout returns defaultTaskTimeout", func(t *testing.T) {
|
||||
m := &Monitor{pollTimeout: -5 * time.Second}
|
||||
got := m.taskExecutionTimeout(InstanceTypePVE)
|
||||
if got != defaultTaskTimeout {
|
||||
t.Fatalf("taskExecutionTimeout() = %v, want %v", got, defaultTaskTimeout)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("InstanceType parameter is ignored", func(t *testing.T) {
|
||||
m := &Monitor{pollTimeout: 60 * time.Second}
|
||||
// All instance types should return the same value
|
||||
gotPVE := m.taskExecutionTimeout(InstanceTypePVE)
|
||||
gotPBS := m.taskExecutionTimeout(InstanceTypePBS)
|
||||
gotPMG := m.taskExecutionTimeout(InstanceTypePMG)
|
||||
gotUnknown := m.taskExecutionTimeout(InstanceType("unknown"))
|
||||
|
||||
expected := 60 * time.Second
|
||||
if gotPVE != expected {
|
||||
t.Errorf("taskExecutionTimeout(PVE) = %v, want %v", gotPVE, expected)
|
||||
}
|
||||
if gotPBS != expected {
|
||||
t.Errorf("taskExecutionTimeout(PBS) = %v, want %v", gotPBS, expected)
|
||||
}
|
||||
if gotPMG != expected {
|
||||
t.Errorf("taskExecutionTimeout(PMG) = %v, want %v", gotPMG, expected)
|
||||
}
|
||||
if gotUnknown != expected {
|
||||
t.Errorf("taskExecutionTimeout(unknown) = %v, want %v", gotUnknown, expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue