diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-23 23:19:04 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-23 23:19:04 +0200 |
| commit | a8a4f82675ed2df538e9fbf95504d5674a732c52 (patch) | |
| tree | 6668ad03881c5bb7d5041462deba8683cff45705 /internal/statsengine/process_test.go | |
| parent | 08449a591bc9ffb67dde33353fb72403683dcb2f (diff) | |
task 303: add per-process accumulator with pid-reuse guard
Diffstat (limited to 'internal/statsengine/process_test.go')
| -rw-r--r-- | internal/statsengine/process_test.go | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/internal/statsengine/process_test.go b/internal/statsengine/process_test.go new file mode 100644 index 0000000..add5ae1 --- /dev/null +++ b/internal/statsengine/process_test.go @@ -0,0 +1,125 @@ +package statsengine + +import ( + "ior/internal/event" + "ior/internal/types" + "math" + "testing" + "time" +) + +func TestProcessAccumulatorBasicStats(t *testing.T) { + acc := newProcessAccumulator() + + acc.Add(newProcessPair(2000, "proc-a", 10, 100)) + acc.Add(newProcessPair(2000, "proc-a", 30, 50)) + acc.Add(newProcessPair(3000, "proc-b", 20, 25)) + + snap := acc.Snapshot(2 * time.Second) + if len(snap) != 2 { + t.Fatalf("expected 2 process snapshots, got %d", len(snap)) + } + + p0 := snap[0] + if p0.PID != 2000 { + t.Fatalf("expected pid 2000 first, got %d", p0.PID) + } + if p0.Comm != "proc-a" { + t.Fatalf("unexpected comm: got %q", p0.Comm) + } + if p0.Syscalls != 2 || p0.Bytes != 150 { + t.Fatalf("unexpected count/bytes: %+v", p0) + } + if p0.AvgLatencyNs != 20 { + t.Fatalf("unexpected avg latency: got %v", p0.AvgLatencyNs) + } + if math.Abs(p0.RatePerSec-1.0) > 1e-9 { + t.Fatalf("unexpected rate: got %v", p0.RatePerSec) + } + + p1 := snap[1] + if p1.PID != 3000 || p1.Comm != "proc-b" || p1.Syscalls != 1 { + t.Fatalf("unexpected second row: %+v", p1) + } +} + +func TestProcessAccumulatorSortsBySyscallsBytesPid(t *testing.T) { + acc := newProcessAccumulator() + + acc.Add(newProcessPair(20, "b", 10, 2)) + acc.Add(newProcessPair(10, "a", 10, 3)) + acc.Add(newProcessPair(10, "a", 10, 3)) + acc.Add(newProcessPair(20, "b", 10, 2)) + + snap := acc.Snapshot(1 * time.Second) + if len(snap) != 2 { + t.Fatalf("expected 2 process snapshots, got %d", len(snap)) + } + + if snap[0].PID != 10 { + t.Fatalf("expected pid 10 first by bytes tie-breaker, got %d", snap[0].PID) + } + if snap[1].PID != 20 { + t.Fatalf("expected pid 20 second, got %d", snap[1].PID) + } +} + +func TestProcessAccumulatorCommUpdateAndZeroRate(t *testing.T) { + acc := newProcessAccumulator() + + acc.Add(newProcessPair(7, "", 10, 1)) + acc.Add(newProcessPair(7, "worker", 20, 2)) + snap := acc.Snapshot(0) + + if len(snap) != 1 { + t.Fatalf("expected 1 snapshot row, got %d", len(snap)) + } + if snap[0].Comm != "worker" { + t.Fatalf("expected comm to be updated, got %q", snap[0].Comm) + } + if snap[0].RatePerSec != 0 { + t.Fatalf("expected zero rate on zero elapsed, got %v", snap[0].RatePerSec) + } +} + +func TestProcessAccumulatorResetsOnCommChangeForSamePID(t *testing.T) { + acc := newProcessAccumulator() + + acc.Add(newProcessPair(42, "old", 100, 10)) + acc.Add(newProcessPair(42, "new", 200, 20)) + + snap := acc.Snapshot(time.Second) + if len(snap) != 1 { + t.Fatalf("expected 1 snapshot row, got %d", len(snap)) + } + if snap[0].Comm != "new" { + t.Fatalf("expected new comm after reset, got %q", snap[0].Comm) + } + if snap[0].Syscalls != 1 || snap[0].Bytes != 20 || snap[0].AvgLatencyNs != 200 { + t.Fatalf("expected counters to reset on comm change, got %+v", snap[0]) + } +} + +func TestProcessAccumulatorNilInputs(t *testing.T) { + var acc *processAccumulator + acc.Add(nil) + if got := acc.Snapshot(time.Second); got != nil { + t.Fatalf("expected nil snapshot from nil accumulator, got %#v", got) + } + + acc = newProcessAccumulator() + acc.Add(nil) + acc.Add(&event.Pair{}) + if got := acc.Snapshot(time.Second); len(got) != 0 { + t.Fatalf("expected empty snapshot, got %#v", got) + } +} + +func newProcessPair(pid uint32, comm string, duration uint64, bytes uint64) *event.Pair { + return &event.Pair{ + EnterEv: &types.RetEvent{Pid: pid}, + Comm: comm, + Duration: duration, + Bytes: bytes, + } +} |
