Files
dockertop/dockertop_test.go
Andy Dixon 25dd8505a0 dockertop 1.0.0
htop-style view of Docker containers and the processes inside them.
2026-10-07 13:08:54 +01:00

88 lines
2.6 KiB
Go

package main
import (
"strings"
"testing"
"time"
)
func TestParseStat(t *testing.T) {
// comm with spaces and a ')' must not shift the fields
in := "42 (my (odd) proc) S 1 42 42 0 -1 4194560 100 0 0 0 250 50 0 0 20 0 3 0 1000 123456789 1500 18446744073709551615"
p, ok := parseStat([]byte(in))
if !ok || p.Comm != "my (odd) proc" || p.State != 'S' || p.PPID != 1 || p.Ticks != 300 ||
p.Pri != 20 || p.Nice != 0 || p.Threads != 3 || p.Virt != 123456789 {
t.Fatalf("bad parse: %+v", p)
}
if cpuTime(300) != "0:03.00" || cpuTime(100*3725) != "1h02:05" {
t.Fatalf("cpuTime: %s %s", cpuTime(300), cpuTime(100*3725))
}
}
func TestDemux(t *testing.T) {
frame := func(stream byte, s string) string {
n := len(s)
return string([]byte{stream, 0, 0, 0, byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)}) + s
}
in := frame(1, "out line\n") + frame(2, "err line\n")
if got := string(demux([]byte(in))); got != "out line\nerr line\n" {
t.Fatalf("demux: %q", got)
}
if got := ansi.ReplaceAllString("\x1b[31mred\x1b[0m", ""); got != "red" {
t.Fatalf("ansi: %q", got)
}
}
func TestStatsRates(t *testing.T) {
t0 := time.Unix(1000, 0)
var s stats
s.Read = t0
s.CPU.Usage.Total = 1e9
s.Mem.Usage, s.Mem.Limit = 300, 1000
s.Mem.Stats = map[string]uint64{"inactive_file": 100}
var prev Container
applyStats(&prev, s, Container{})
if prev.HasRate || prev.Mem != 200 {
t.Fatalf("first sample: %+v", prev)
}
s.Read = t0.Add(2 * time.Second)
s.CPU.Usage.Total = 2e9 // 1 CPU-second over 2s = 50%
var c Container
applyStats(&c, s, prev)
if !c.HasRate || c.CPU != 50 || c.MemPct() != 20 {
t.Fatalf("rates: %+v", c)
}
if rate(5, 10, 1) != 0 {
t.Fatal("counter reset must give 0")
}
}
func TestGroupRows(t *testing.T) {
cs := []Container{
{ID: "a", Name: "web-1", Project: "web", CPU: 30, State: "running"},
{ID: "b", Name: "solo", CPU: 20, State: "running"},
{ID: "c", Name: "web-db", Project: "web", CPU: 5, State: "exited"},
}
byCPU := func(x, y Container) bool { return x.CPU > y.CPU }
r := groupRows(cs, byCPU)
var got []string
for _, c := range r {
got = append(got, c.Tree+c.Name)
}
if strings.Join(got, ",") != "web,├─ web-1,└─ web-db,solo" || r[0].CPU != 35 || r[0].Status != "1/2 running" {
t.Fatalf("bad grouping: %q %+v", got, r[0])
}
}
func TestConfig(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
c := defaults
c.Sort, c.ProcSort, c.Tree, c.All, c.Refresh = "MEM", "TIME", true, false, 0.5
if err := c.save(); err != nil {
t.Fatal(err)
}
if got := loadConfig(); got != c {
t.Fatalf("round trip: %+v != %+v", got, c)
}
}