summaryrefslogtreecommitdiff
path: root/internal/generate/tracepointsgo_test.go
blob: 978633b857aebe5f8f4e6e170f66502c92128298 (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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package generate

import (
	"strings"
	"testing"
)

const sampleGeneratedC = `// Code generated - don't change manually!

/// Ignoring sys_enter_kill sys_exit_kill as possibly not file I/O related

#define SYS_ENTER_READ 844
#define SYS_EXIT_READ 843
#define SYS_ENTER_CLOSE 778
#define SYS_EXIT_CLOSE 777

/// sys_enter_read is a struct fd_event
SEC("tracepoint/syscalls/sys_enter_read")
int handle_sys_enter_read(struct syscall_trace_enter *ctx) {
    return 0;
}

/// sys_exit_read is a struct ret_event (READ_CLASSIFIED)
SEC("tracepoint/syscalls/sys_exit_read")
int handle_sys_exit_read(struct syscall_trace_exit *ctx) {
    return 0;
}

/// sys_enter_close is a struct fd_event
SEC("tracepoint/syscalls/sys_enter_close")
int handle_sys_enter_close(struct syscall_trace_enter *ctx) {
    return 0;
}

/// sys_exit_close is a struct ret_event (UNCLASSIFIED)
SEC("tracepoint/syscalls/sys_exit_close")
int handle_sys_exit_close(struct syscall_trace_exit *ctx) {
    return 0;
}
`

func TestExtractTracepoints(t *testing.T) {
	output, err := ExtractTracepoints(strings.NewReader(sampleGeneratedC))
	if err != nil {
		t.Fatalf("ExtractTracepoints failed: %v", err)
	}

	requireContains(t, output, "package tracepoints")
	requireContains(t, output, `"sys_enter_read",`)
	requireContains(t, output, `"sys_exit_read",`)
	requireContains(t, output, `"sys_enter_close",`)
	requireContains(t, output, `"sys_exit_close",`)
	requireContains(t, output, "var List = []string{")

	// Should NOT contain ignore comments or defines
	if strings.Contains(output, "kill") {
		t.Error("output should not contain ignored tracepoints")
	}
}

func TestExtractTracepointsOrder(t *testing.T) {
	output, err := ExtractTracepoints(strings.NewReader(sampleGeneratedC))
	if err != nil {
		t.Fatal(err)
	}

	enterReadPos := strings.Index(output, `"sys_enter_read"`)
	exitReadPos := strings.Index(output, `"sys_exit_read"`)
	enterClosePos := strings.Index(output, `"sys_enter_close"`)
	if enterReadPos > exitReadPos || exitReadPos > enterClosePos {
		t.Error("tracepoints should maintain source order")
	}
}

func TestExtractTracepointsEmpty(t *testing.T) {
	output, err := ExtractTracepoints(strings.NewReader("// no SEC lines here\n"))
	if err != nil {
		t.Fatal(err)
	}
	requireContains(t, output, "var List = []string{")
	requireContains(t, output, "}")
}

func TestExtractTracepointsPackageHeader(t *testing.T) {
	output, err := ExtractTracepoints(strings.NewReader(sampleGeneratedC))
	if err != nil {
		t.Fatal(err)
	}
	if !strings.HasPrefix(output, "// Code generated - don't change manually!\npackage tracepoints\n") {
		t.Errorf("unexpected header: %s", output[:60])
	}
}

func TestExtractTracepointsMalformedSEC(t *testing.T) {
	input := `SEC("tracepoint/not_matching_pattern")
int handle_something(struct syscall_trace_enter *ctx) {
    return 0;
}
SEC("some/garbage")
`
	output, err := ExtractTracepoints(strings.NewReader(input))
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if strings.Contains(output, `"sys_`) {
		t.Error("malformed SEC lines should not produce tracepoints")
	}
	requireContains(t, output, "var List = []string{")
}

func TestExtractTracepointsNoSECLines(t *testing.T) {
	input := "// just a comment\n/* another comment */\nint foo() { return 0; }\n"
	output, err := ExtractTracepoints(strings.NewReader(input))
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	requireContains(t, output, "var List = []string{")
	if strings.Contains(output, `"sys_`) {
		t.Error("input with no SEC lines should produce empty list")
	}
}