Files
simslim-mirror/measure_test.go
Interlap 6af86fb728 feat: add simslim top — live fleet monitor with per-daemon drill-down
A top(1) for the simulator fleet: every booted simulator with its OS,
slim state, process count, CPU, RAM, and disk, refreshing live. Enter a
row (or pass a UDID) to drill into that simulator's per-daemon footprint.
Columns sort via n/o/s/p/c/m/d with a version-aware OS comparator; the
name column flexes to the terminal width. --json and piped output emit
one-shot snapshots, keeping the JSON contract for the GUI.

Library side stays dependency-free: MeasureProcesses keeps per-process
footprint+cpu from the shared ps/top snapshot, and FleetSnapshot
composes booted devices, slim status (fanned out per device), and
MeasureMany. The TUI (bubbletea + lipgloss, CLI-only deps) anchors the
cursor by UDID across live re-sorts, keeps the last snapshot on
transient refresh errors, and guards disk sweeps against overlap.

Also adds `simslim list --booted` to filter the listing to booted
simulators.
2026-07-24 11:52:03 +02:00

52 lines
1.4 KiB
Go

package simslim
import "testing"
func TestMeasureTree(t *testing.T) {
snap := psSnapshot{
children: map[int][]int{
10: {11, 12},
11: {13},
13: {10}, // A cycle must not double-count the root.
},
cpu: map[int]float64{10: 1.5, 11: 0.5, 12: 2, 13: 0},
}
footprint := map[int]int64{10: 100, 11: 20, 12: 30, 13: 4}
got := measureTree(10, snap, footprint)
if got.Processes != 4 {
t.Errorf("Processes = %d, want 4", got.Processes)
}
if got.Bytes != 154 {
t.Errorf("Bytes = %d, want 154", got.Bytes)
}
if got.CPU != 4 {
t.Errorf("CPU = %v, want 4", got.CPU)
}
}
func TestParsePS(t *testing.T) {
out := " PID PPID %CPU COMM\n" +
" 10 1 1.5 launchd_sim\n" +
" 11 10 12.0 /usr/libexec/assistantd\n" +
" 12 10 0.0 /System/Library/CoreServices/SpringBoard.app/SpringBoard\n" +
" bad line that should be skipped\n"
snap := parsePS(out)
if got := snap.children[10]; len(got) != 2 {
t.Fatalf("children[10] = %v, want 2 entries", got)
}
if snap.comm[11] != "assistantd" { // basenamed from the full path
t.Errorf("comm[11] = %q, want assistantd", snap.comm[11])
}
if snap.comm[12] != "SpringBoard" {
t.Errorf("comm[12] = %q, want SpringBoard", snap.comm[12])
}
if snap.cpu[11] != 12 {
t.Errorf("cpu[11] = %v, want 12", snap.cpu[11])
}
if _, ok := snap.comm[1]; ok {
t.Errorf("header row was parsed as a process")
}
}