package metrics import ( "math" "testing" "time" ) func TestParseProcStat(t *testing.T) { // user nice system idle iowait irq softirq steal c := ParseProcStat("cpu 100 20 30 800 50 5 5 0 0 0\ncpu0 1 2 3 4 5 6 7 8 9 10\n") if c == nil { t.Fatal("nil for valid input") } // Busy = everything except idle(800) and iowait(50) = 160; Total = 1010. if c.Busy != 160 || c.Total != 1010 { t.Fatalf("got busy=%d total=%d, want 160/1010", c.Busy, c.Total) } if ParseProcStat("") != nil || ParseProcStat("cpu x y z") != nil { t.Fatal("garbage must parse to nil") } } func TestCPUFrac(t *testing.T) { prev := &CPUCounters{Busy: 100, Total: 1000} cur := &CPUCounters{Busy: 160, Total: 1100} f := CPUFrac(prev, cur) if f == nil || math.Abs(*f-0.6) > 1e-9 { // 60 busy / 100 total t.Fatalf("got %v, want 0.6", f) } if CPUFrac(nil, cur) != nil || CPUFrac(prev, nil) != nil { t.Fatal("nil input must be nil") } if CPUFrac(cur, prev) != nil { // counters went backwards (reboot) — no guess t.Fatal("backwards counters must be nil") } // Total advances but Busy alone regresses: uint64 subtraction of // cur.Busy-prev.Busy would wrap into a huge garbage value instead of // going negative, so this must be caught explicitly, not just inferred // from the Total check. if got := CPUFrac(&CPUCounters{Busy: 500, Total: 1000}, &CPUCounters{Busy: 100, Total: 1100}); got != nil { t.Fatalf("Busy regressing while Total advances must be nil, got %v", *got) } } func TestParseLoadAvg(t *testing.T) { l1, l5, l15 := ParseLoadAvg("0.52 0.41 0.30 1/234 5678") if l1 == nil || l5 == nil || l15 == nil { t.Fatal("nil for valid input") } if math.Abs(*l1-0.52) > 1e-9 || math.Abs(*l5-0.41) > 1e-9 || math.Abs(*l15-0.30) > 1e-9 { t.Fatalf("got %v/%v/%v, want 0.52/0.41/0.30", *l1, *l5, *l15) } l1, l5, l15 = ParseLoadAvg("garbage") if l1 != nil || l5 != nil || l15 != nil { t.Fatal("garbage must be all-nil") } l1, l5, l15 = ParseLoadAvg("") if l1 != nil || l5 != nil || l15 != nil { t.Fatal("empty must be all-nil") } } func TestParseCgroupCPUUsec(t *testing.T) { v := ParseCgroupCPUUsec("usage_usec 4500000\nuser_usec 3000000\nsystem_usec 1500000\n") if v == nil || *v != 4500000 { t.Fatalf("got %v, want 4500000", v) } if ParseCgroupCPUUsec("") != nil { t.Fatal("empty must be nil") } if ParseCgroupCPUUsec("user_usec 3000000\nsystem_usec 1500000\n") != nil { t.Fatal("missing usage_usec must be nil") } } func TestParseCgroupInt(t *testing.T) { v := ParseCgroupInt("123456\n") if v == nil || *v != 123456 { t.Fatalf("got %v, want 123456", v) } if ParseCgroupInt("max\n") != nil { t.Fatal(`"max" must be nil`) } if ParseCgroupInt("") != nil { t.Fatal("empty must be nil") } if ParseCgroupInt("not-a-number\n") != nil { t.Fatal("garbage must be nil") } } func TestParseCgroupIO(t *testing.T) { r, w := ParseCgroupIO("259:0 rbytes=1000 wbytes=2000 rios=10 wios=20 dbytes=0 dios=0\n259:1 rbytes=500 wbytes=100 rios=1 wios=1 dbytes=0 dios=0\n") if r == nil || w == nil || *r != 1500 || *w != 2100 { t.Fatalf("got r=%v w=%v, want 1500/2100", r, w) } r, w = ParseCgroupIO("") if r != nil || w != nil { t.Fatal("empty must be both-nil") } r, w = ParseCgroupIO("garbage line with no equals signs\n") if r != nil || w != nil { t.Fatal("garbage must be both-nil") } } func TestUnitCPUFrac(t *testing.T) { prev := int64(1_000_000) cur := int64(4_000_000) f := UnitCPUFrac(&prev, &cur, 60*time.Second) if f == nil || math.Abs(*f-0.05) > 1e-9 { t.Fatalf("got %v, want 0.05", f) } if UnitCPUFrac(nil, &cur, 60*time.Second) != nil { t.Fatal("nil prev must be nil") } if UnitCPUFrac(&prev, nil, 60*time.Second) != nil { t.Fatal("nil cur must be nil") } if UnitCPUFrac(&cur, &prev, 60*time.Second) != nil { t.Fatal("backwards counters must be nil") } if UnitCPUFrac(&prev, &cur, 0) != nil { t.Fatal("zero elapsed must be nil") } if UnitCPUFrac(&prev, &cur, -time.Second) != nil { t.Fatal("negative elapsed must be nil") } }