summaryrefslogtreecommitdiff
path: root/internal/tui/dashboard/overview_test.go
blob: cee6cf2cd01a2be5aa89d2b5d23c53675537e11a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package dashboard

import (
	"strings"
	"testing"
	"time"

	"ior/internal/statsengine"
)

func TestRenderOverviewIncludesCoreMetrics(t *testing.T) {
	snap := &statsengine.Snapshot{
		Elapsed:           95 * time.Second,
		TotalSyscalls:     1200,
		SyscallRatePerSec: 12.5,
		TotalBytes:        10 * 1024 * 1024,
		ReadBytesPerSec:   4096,
		WriteBytesPerSec:  8192,
		TotalErrors:       12,
		LatencyMeanNs:     5000,
		LatencyTrend:      statsengine.Trend{Direction: statsengine.TrendRising, DeltaPercent: 12.5},
		GapTrend:          statsengine.Trend{Direction: statsengine.TrendFalling, DeltaPercent: -7.4},
		ThroughputTrend:   statsengine.Trend{Direction: statsengine.TrendStable, DeltaPercent: 0},
	}

	out := renderOverview(snap, 120, 40)
	for _, token := range []string{
		"Elapsed:",
		"Syscalls:",
		"Read/s:",
		"Errors:",
		"Trends:",
		"Latency:",
		"Gap:",
		"Throughput:",
		"Top syscalls:",
		"Top files:",
		"Top processes:",
		"Latency buckets:",
		"Gap buckets:",
	} {
		if !strings.Contains(out, token) {
			t.Fatalf("expected token %q in overview output", token)
		}
	}
}

func TestSummarizeTopSyscalls(t *testing.T) {
	snap := statsengine.NewSnapshot(
		nil, nil, nil,
		[]statsengine.SyscallSnapshot{
			{Name: "read", Count: 50},
			{Name: "write", Count: 20},
			{Name: "openat", Count: 10},
			{Name: "close", Count: 5},
		},
		nil, nil,
		statsengine.HistogramSnapshot{},
		statsengine.HistogramSnapshot{},
	)

	got := summarizeTopSyscalls(&snap)
	if got != "read(50), write(20), openat(10)" {
		t.Fatalf("unexpected top syscall summary: %q", got)
	}
}

func TestRenderOverviewWithoutSnapshot(t *testing.T) {
	out := renderOverview(nil, 80, 24)
	if !strings.Contains(out, "waiting for stats") {
		t.Fatalf("expected waiting placeholder, got %q", out)
	}
}

func TestOverviewSummariesIncludeFilesProcessesAndHistograms(t *testing.T) {
	snap := statsengine.NewSnapshot(
		nil, nil, nil,
		[]statsengine.SyscallSnapshot{{Name: "read", Count: 2}},
		[]statsengine.FileSnapshot{{Path: "/tmp/very/long/path/file.log", Accesses: 4}},
		[]statsengine.ProcessSnapshot{{PID: 12, Comm: "proc", Syscalls: 7}},
		statsengine.NewHistogramSnapshot(3, []statsengine.HistogramBucketSnapshot{
			{Label: "[0,1us)", Count: 2},
			{Label: "[1us,10us)", Count: 1},
		}),
		statsengine.NewHistogramSnapshot(1, []statsengine.HistogramBucketSnapshot{
			{Label: "[10us,100us)", Count: 1},
		}),
	)

	out := renderOverview(&snap, 120, 40)
	for _, token := range []string{"Top files:", "Top processes:", "Latency buckets:", "Gap buckets:"} {
		if !strings.Contains(out, token) {
			t.Fatalf("expected %q in overview output", token)
		}
	}
}