mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-04-28 03:20:11 +00:00
Add memory regression tests for agent and scheduler
This commit is contained in:
parent
502766b9b7
commit
049a3e424c
2 changed files with 187 additions and 0 deletions
122
internal/hostmetrics/collector_memory_regression_test.go
Normal file
122
internal/hostmetrics/collector_memory_regression_test.go
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
package hostmetrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
godisk "github.com/shirou/gopsutil/v4/disk"
|
||||
goload "github.com/shirou/gopsutil/v4/load"
|
||||
gomem "github.com/shirou/gopsutil/v4/mem"
|
||||
gonet "github.com/shirou/gopsutil/v4/net"
|
||||
)
|
||||
|
||||
func TestCollectMemoryStability(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping memory regression in short mode")
|
||||
}
|
||||
|
||||
origCPUCounts := cpuCounts
|
||||
origCPUPercent := cpuPercent
|
||||
origLoadAvg := loadAvg
|
||||
origVirtualMemory := virtualMemory
|
||||
origDiskPartitions := diskPartitions
|
||||
origDiskUsage := diskUsage
|
||||
origDiskIOCounters := diskIOCounters
|
||||
origNetInterfaces := netInterfaces
|
||||
origNetIOCounters := netIOCounters
|
||||
|
||||
cpuCounts = func(ctx context.Context, logical bool) (int, error) { return 4, nil }
|
||||
cpuPercent = func(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) {
|
||||
return []float64{5.0}, nil
|
||||
}
|
||||
loadAvg = func(ctx context.Context) (*goload.AvgStat, error) {
|
||||
return &goload.AvgStat{Load1: 0.1, Load5: 0.2, Load15: 0.3}, nil
|
||||
}
|
||||
virtualMemory = func(ctx context.Context) (*gomem.VirtualMemoryStat, error) {
|
||||
return &gomem.VirtualMemoryStat{
|
||||
Total: 8 * 1024 * 1024 * 1024,
|
||||
Used: 4 * 1024 * 1024 * 1024,
|
||||
Free: 4 * 1024 * 1024 * 1024,
|
||||
UsedPercent: 50,
|
||||
SwapTotal: 1024 * 1024 * 1024,
|
||||
SwapFree: 512 * 1024 * 1024,
|
||||
}, nil
|
||||
}
|
||||
diskPartitions = func(ctx context.Context, all bool) ([]godisk.PartitionStat, error) {
|
||||
return []godisk.PartitionStat{{Device: "/dev/sda", Mountpoint: "/", Fstype: "ext4"}}, nil
|
||||
}
|
||||
diskUsage = func(ctx context.Context, path string) (*godisk.UsageStat, error) {
|
||||
return &godisk.UsageStat{Total: 100, Used: 50, Free: 50, UsedPercent: 50}, nil
|
||||
}
|
||||
diskIOCounters = func(ctx context.Context, names ...string) (map[string]godisk.IOCountersStat, error) {
|
||||
return map[string]godisk.IOCountersStat{
|
||||
"sda": {
|
||||
ReadBytes: 1,
|
||||
WriteBytes: 2,
|
||||
ReadCount: 1,
|
||||
WriteCount: 2,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
netInterfaces = func(ctx context.Context) (gonet.InterfaceStatList, error) {
|
||||
return gonet.InterfaceStatList{
|
||||
{
|
||||
Name: "eth0",
|
||||
HardwareAddr: "00:11:22:33:44:55",
|
||||
Flags: []string{"up"},
|
||||
Addrs: []gonet.InterfaceAddr{{Addr: "192.168.1.10/24"}},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
netIOCounters = func(ctx context.Context, pernic bool) ([]gonet.IOCountersStat, error) {
|
||||
return []gonet.IOCountersStat{{Name: "eth0", BytesRecv: 1, BytesSent: 2}}, nil
|
||||
}
|
||||
|
||||
t.Cleanup(func() {
|
||||
cpuCounts = origCPUCounts
|
||||
cpuPercent = origCPUPercent
|
||||
loadAvg = origLoadAvg
|
||||
virtualMemory = origVirtualMemory
|
||||
diskPartitions = origDiskPartitions
|
||||
diskUsage = origDiskUsage
|
||||
diskIOCounters = origDiskIOCounters
|
||||
netInterfaces = origNetInterfaces
|
||||
netIOCounters = origNetIOCounters
|
||||
})
|
||||
|
||||
warmupIterations := 50
|
||||
measureIterations := 200
|
||||
|
||||
for i := 0; i < warmupIterations; i++ {
|
||||
if _, err := Collect(context.Background(), nil); err != nil {
|
||||
t.Fatalf("warmup collect: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
var baseline runtime.MemStats
|
||||
runtime.ReadMemStats(&baseline)
|
||||
|
||||
for i := 0; i < measureIterations; i++ {
|
||||
if _, err := Collect(context.Background(), nil); err != nil {
|
||||
t.Fatalf("collect: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
var after runtime.MemStats
|
||||
runtime.ReadMemStats(&after)
|
||||
|
||||
if baseline.HeapAlloc > 0 {
|
||||
allowed := baseline.HeapAlloc + 5*1024*1024
|
||||
growthRatio := float64(after.HeapAlloc) / float64(baseline.HeapAlloc)
|
||||
if after.HeapAlloc > allowed && growthRatio > 1.25 {
|
||||
t.Fatalf("heap allocation grew too much: baseline=%d final=%d ratio=%.2f", baseline.HeapAlloc, after.HeapAlloc, growthRatio)
|
||||
}
|
||||
}
|
||||
}
|
||||
65
internal/monitoring/task_queue_memory_regression_test.go
Normal file
65
internal/monitoring/task_queue_memory_regression_test.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package monitoring
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestTaskQueueMemoryStability(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping memory regression in short mode")
|
||||
}
|
||||
|
||||
queue := NewTaskQueue()
|
||||
taskCount := 250
|
||||
warmupCycles := 10
|
||||
measureCycles := 50
|
||||
|
||||
makeTask := func(i int) ScheduledTask {
|
||||
return ScheduledTask{
|
||||
InstanceName: fmt.Sprintf("node-%03d", i),
|
||||
InstanceType: InstanceTypePVE,
|
||||
NextRun: time.Now().Add(time.Duration(i) * time.Second),
|
||||
Interval: 10 * time.Second,
|
||||
Priority: 1,
|
||||
}
|
||||
}
|
||||
|
||||
cycle := func() {
|
||||
for i := 0; i < taskCount; i++ {
|
||||
queue.Upsert(makeTask(i))
|
||||
}
|
||||
for i := 0; i < taskCount; i++ {
|
||||
queue.Remove(InstanceTypePVE, fmt.Sprintf("node-%03d", i))
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < warmupCycles; i++ {
|
||||
cycle()
|
||||
}
|
||||
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
var baseline runtime.MemStats
|
||||
runtime.ReadMemStats(&baseline)
|
||||
|
||||
for i := 0; i < measureCycles; i++ {
|
||||
cycle()
|
||||
}
|
||||
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
var after runtime.MemStats
|
||||
runtime.ReadMemStats(&after)
|
||||
|
||||
if baseline.HeapAlloc > 0 {
|
||||
allowed := baseline.HeapAlloc + 5*1024*1024
|
||||
growthRatio := float64(after.HeapAlloc) / float64(baseline.HeapAlloc)
|
||||
if after.HeapAlloc > allowed && growthRatio > 1.25 {
|
||||
t.Fatalf("heap allocation grew too much: baseline=%d final=%d ratio=%.2f", baseline.HeapAlloc, after.HeapAlloc, growthRatio)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue