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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
package integrationtests
import (
"strings"
"testing"
"ior/internal/flamegraph"
)
// ExpectedEvent describes an I/O event that should appear in the test output.
type ExpectedEvent struct {
PathContains string // substring match on file path
Tracepoint string // tracepoint name substring, e.g. "openat"
Comm string // expected comm name, e.g. "ioworkload"
MinCount uint64 // minimum total occurrences across all matching records
}
// AssertEventsPresent verifies that each expected event is found in the test result.
// Counts are summed across all matching records before comparing to MinCount.
func AssertEventsPresent(t *testing.T, result TestResult, expected []ExpectedEvent) {
t.Helper()
for _, exp := range expected {
var totalCount uint64
var matched bool
for _, rec := range result.Records {
if matchesExpectation(rec, exp) {
matched = true
totalCount += rec.Cnt.Count
}
}
if !matched {
t.Errorf("expected event not found: %+v", exp)
continue
}
if exp.MinCount > 0 && totalCount < exp.MinCount {
t.Errorf("event matching %+v has total count %d, want >= %d",
exp, totalCount, exp.MinCount)
}
}
}
// AssertNoUnexpectedComm verifies all records have the expected comm name.
// Records with empty comm are skipped because BPF may capture events before
// the process name is set in the task struct.
func AssertNoUnexpectedComm(t *testing.T, result TestResult, expectedComm string) {
t.Helper()
var count int
for _, rec := range result.Records {
if rec.Comm == "" {
continue
}
if rec.Comm != expectedComm {
count++
if count <= 5 {
t.Logf("unexpected comm %q (pid=%d tracepoint=%s path=%q)",
rec.Comm, rec.Pid, rec.TraceID.String(), rec.Path)
}
}
}
if count > 0 {
t.Fatalf("found %d records with unexpected comm (want %q)", count, expectedComm)
}
}
// AssertNoUnexpectedPID verifies all records belong to the expected PID.
// Accepts int to match os.Getpid() return type.
func AssertNoUnexpectedPID(t *testing.T, result TestResult, expectedPID int) {
t.Helper()
pid := uint32(expectedPID)
var count int
for _, rec := range result.Records {
if rec.Pid != pid {
count++
if count <= 5 {
t.Logf("unexpected PID %d (tracepoint=%s path=%q comm=%q)",
rec.Pid, rec.TraceID.String(), rec.Path, rec.Comm)
}
}
}
if count > 0 {
t.Fatalf("found %d records with unexpected PID (want %d)", count, expectedPID)
}
}
// AssertEventsAbsent verifies that none of the specified events appear in the test result.
// Each ExpectedEvent must have at least one filter field set to avoid accidentally
// matching all records.
func AssertEventsAbsent(t *testing.T, result TestResult, absent []ExpectedEvent) {
t.Helper()
for _, exp := range absent {
if exp.PathContains == "" && exp.Tracepoint == "" && exp.Comm == "" {
t.Errorf("AssertEventsAbsent: ExpectedEvent must have at least one filter field set: %+v", exp)
continue
}
for _, rec := range result.Records {
if matchesExpectation(rec, exp) {
t.Errorf("event should be absent but was found: %+v (path=%q tracepoint=%s comm=%q)",
exp, rec.Path, rec.TraceID.String(), rec.Comm)
break
}
}
}
}
func matchesExpectation(rec flamegraph.IterRecord, exp ExpectedEvent) bool {
if exp.PathContains != "" && !strings.Contains(rec.Path, exp.PathContains) {
return false
}
if exp.Tracepoint != "" && !strings.Contains(rec.TraceID.String(), exp.Tracepoint) {
return false
}
if exp.Comm != "" && rec.Comm != exp.Comm {
return false
}
return true
}
|