Files
pranshuparmar--witr/internal/proc/process_list_parity_linux_test.go
wehub-resource-sync 36b3af2e3d
PR Check / Code Quality: Format (push) Failing after 1s
PR Check / Code Quality: Lint (darwin) (push) Failing after 0s
PR Check / Code Quality: Lint (freebsd) (push) Failing after 1s
PR Check / Code Quality: Lint (windows) (push) Failing after 1s
PR Check / Code Quality: Lint (linux) (push) Failing after 1s
PR Check / Security: Vulnerability Scan (push) Failing after 0s
Update Documentation / update-docs (push) Failing after 2s
PR Check / Code Quality: Vendor (push) Failing after 1s
PR Check / Code Quality: Coverage (push) Failing after 0s
PR Check / Tests: Unit (macos-latest) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04-arm) (push) Has been cancelled
PR Check / Tests: Unit (windows-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:22:06 +08:00

76 lines
2.2 KiB
Go

//go:build linux
package proc
import (
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"testing"
"github.com/pranshuparmar/witr/pkg/model"
)
func findListedPID(procs []model.Process, pid int) *model.Process {
for i := range procs {
if procs[i].PID == pid {
return &procs[i]
}
}
return nil
}
// TestListProcessesSelf checks the /proc-based ListProcesses (which replaced the
// `ps -axo` fork) produces self with plausible columns, and that the values it
// computes from /proc track what ps reports.
func TestListProcessesSelf(t *testing.T) {
procs, err := ListProcesses()
if err != nil {
t.Fatalf("ListProcesses: %v", err)
}
me := findListedPID(procs, os.Getpid())
if me == nil {
t.Fatalf("ListProcesses did not include self (pid %d)", os.Getpid())
}
if me.MemoryRSS == 0 {
t.Error("self RSS should be > 0")
}
if me.Command == "" {
t.Error("self Command should be non-empty")
}
if me.User == "" {
t.Error("self User should be non-empty")
}
if me.PPID == 0 {
t.Error("self PPID should be non-zero")
}
if me.CPUPercent < 0 || me.CPUPercent > float64(runtime.NumCPU())*100+1 {
t.Errorf("self CPU%% = %v is implausible", me.CPUPercent)
}
// RSS parity with ps (50% tolerance — resident memory drifts between the two reads).
if out, err := exec.Command("ps", "-p", strconv.Itoa(os.Getpid()), "-o", "rss=").Output(); err == nil {
if psKB, perr := strconv.ParseFloat(strings.TrimSpace(string(out)), 64); perr == nil && psKB > 0 {
psRSS := psKB * 1024
if ratio := float64(me.MemoryRSS) / psRSS; ratio < 0.5 || ratio > 2.0 {
t.Errorf("RSS parity off: witr=%d bytes, ps=%.0f bytes (ratio %.2f)", me.MemoryRSS, psRSS, ratio)
}
}
}
// PID 1 is long-lived, so its lifetime-average CPU% should closely track ps's
// (same formula, same /proc source) — a gross formula error would blow past 1%.
if p1 := findListedPID(procs, 1); p1 != nil {
if out, err := exec.Command("ps", "-p", "1", "-o", "%cpu=").Output(); err == nil {
if psCPU, perr := strconv.ParseFloat(strings.TrimSpace(string(out)), 64); perr == nil {
if diff := p1.CPUPercent - psCPU; diff > 1.0 || diff < -1.0 {
t.Errorf("PID 1 CPU%% parity: witr=%.3f, ps=%.3f", p1.CPUPercent, psCPU)
}
}
}
}
}