package generate import ( "strings" "testing" ) func classifyFromData(t *testing.T, data string) ClassificationResult { t.Helper() f := mustParseOne(t, data) return ClassifyFormat(&f) } func TestClassifyFdRead(t *testing.T) { r := classifyFromData(t, FormatRead) if r.Kind != KindFd { t.Errorf("read: got kind %d, want KindFd", r.Kind) } } func TestClassifyFdClose(t *testing.T) { r := classifyFromData(t, FormatClose) if r.Kind != KindFd { t.Errorf("close: got kind %d, want KindFd", r.Kind) } } func TestClassifyFdPread64(t *testing.T) { r := classifyFromData(t, FormatPread64) if r.Kind != KindFd { t.Errorf("pread64: got kind %d, want KindFd", r.Kind) } } func TestClassifyFdWrite(t *testing.T) { r := classifyFromData(t, FormatWrite) if r.Kind != KindFd { t.Errorf("write: got kind %d, want KindFd", r.Kind) } } func TestClassifyFdPidfdGetfd(t *testing.T) { r := classifyFromData(t, FormatPidfdGetfd) if r.Kind != KindFd { t.Errorf("pidfd_getfd: got kind %d, want KindFd", r.Kind) } } func TestClassifyOpenOpenat(t *testing.T) { r := classifyFromData(t, FormatOpenat) if r.Kind != KindOpen { t.Errorf("openat: got kind %d, want KindOpen", r.Kind) } } func TestClassifyOpenOpen(t *testing.T) { r := classifyFromData(t, FormatOpen) if r.Kind != KindOpen { t.Errorf("open: got kind %d, want KindOpen", r.Kind) } } func TestClassifyOpenOpenat2(t *testing.T) { r := classifyFromData(t, FormatOpenat2) if r.Kind != KindOpen { t.Errorf("openat2: got kind %d, want KindOpen", r.Kind) } } func TestClassifyPathnameCreat(t *testing.T) { r := classifyFromData(t, FormatCreat) if r.Kind != KindPathname { t.Errorf("creat: got kind %d, want KindPathname", r.Kind) } if r.PathnameField != "pathname" { t.Errorf("creat: PathnameField = %q, want pathname", r.PathnameField) } } func TestClassifyPathnameUnlink(t *testing.T) { r := classifyFromData(t, FormatUnlink) if r.Kind != KindPathname { t.Errorf("unlink: got kind %d, want KindPathname", r.Kind) } if r.PathnameField != "pathname" { t.Errorf("unlink: PathnameField = %q, want pathname", r.PathnameField) } } func TestClassifyNameRename(t *testing.T) { r := classifyFromData(t, FormatRename) if r.Kind != KindName { t.Errorf("rename: got kind %d, want KindName", r.Kind) } } func TestClassifyNameLinkat(t *testing.T) { r := classifyFromData(t, FormatLinkat) if r.Kind != KindName { t.Errorf("linkat: got kind %d, want KindName", r.Kind) } } func TestClassifyNameSymlink(t *testing.T) { r := classifyFromData(t, FormatSymlink) if r.Kind != KindName { t.Errorf("symlink: got kind %d, want KindName", r.Kind) } } func TestClassifyFcntl(t *testing.T) { r := classifyFromData(t, FormatFcntl) if r.Kind != KindFcntl { t.Errorf("fcntl: got kind %d, want KindFcntl", r.Kind) } } func TestClassifyDup(t *testing.T) { r := classifyFromData(t, FormatDup) if r.Kind != KindFd { t.Errorf("dup: got kind %d, want KindFd", r.Kind) } } func TestClassifyDup2(t *testing.T) { r := classifyFromData(t, FormatDup2) if r.Kind != KindFd { t.Errorf("dup2: got kind %d, want KindFd", r.Kind) } } func TestClassifyDup3(t *testing.T) { r := classifyFromData(t, FormatDup3) if r.Kind != KindDup3 { t.Errorf("dup3: got kind %d, want KindDup3", r.Kind) } } func TestClassifyOpenByHandleAt(t *testing.T) { r := classifyFromData(t, FormatOpenByHandleAt) if r.Kind != KindOpenByHandleAt { t.Errorf("open_by_handle_at: got kind %d, want KindOpenByHandleAt", r.Kind) } } func TestClassifyNameToHandleAt(t *testing.T) { r := classifyFromData(t, FormatNameToHandleAt) if r.Kind != KindPathname { t.Errorf("name_to_handle_at: got kind %d, want KindPathname", r.Kind) } if r.PathnameField != "name" { t.Errorf("name_to_handle_at: PathnameField = %q, want name", r.PathnameField) } } func TestClassifyNullSync(t *testing.T) { r := classifyFromData(t, FormatSync) if r.Kind != KindNull { t.Errorf("sync: got kind %d, want KindNull", r.Kind) } } func TestClassifyNullSyslog(t *testing.T) { r := classifyFromData(t, FormatSyslog) if r.Kind != KindNull { t.Errorf("syslog: got kind %d, want KindNull", r.Kind) } } func TestClassifyNullGetcwd(t *testing.T) { r := classifyFromData(t, FormatGetcwd) if r.Kind != KindNull { t.Errorf("getcwd: got kind %d, want KindNull", r.Kind) } } func TestClassifyNullIoUring(t *testing.T) { r := classifyFromData(t, FormatIoUringEnter) if r.Kind != KindFd { t.Errorf("io_uring_enter: got kind %d, want KindFd", r.Kind) } } func TestClassifyIoUringRegister(t *testing.T) { r := classifyFromData(t, FormatIoUringRegister) if r.Kind != KindFd { t.Errorf("io_uring_register: got kind %d, want KindFd", r.Kind) } } func TestClassifyRetExitRead(t *testing.T) { r := classifyFromData(t, FormatExitRead) if r.Kind != KindRet { t.Errorf("exit_read: got kind %d, want KindRet", r.Kind) } } func TestClassifyRetExitWrite(t *testing.T) { r := classifyFromData(t, FormatExitWrite) if r.Kind != KindRet { t.Errorf("exit_write: got kind %d, want KindRet", r.Kind) } } func TestClassifyRetExitOpenat(t *testing.T) { r := classifyFromData(t, FormatExitOpenat) if r.Kind != KindRet { t.Errorf("exit_openat: got kind %d, want KindRet", r.Kind) } } func TestClassifyRetExitPread64(t *testing.T) { r := classifyFromData(t, FormatExitPread64) if r.Kind != KindRet { t.Errorf("exit_pread64: got kind %d, want KindRet", r.Kind) } } func TestClassifyRetExitSymlink(t *testing.T) { r := classifyFromData(t, FormatExitSymlink) if r.Kind != KindRet { t.Errorf("exit_symlink: got kind %d, want KindRet", r.Kind) } } // --- Ignore tests --- func TestIgnoreMknod(t *testing.T) { r := classifyFromData(t, FormatMknod) if r.Kind != KindNone { t.Errorf("mknod: got kind %d, want KindNone (ignored)", r.Kind) } } func TestIgnoreExecve(t *testing.T) { r := classifyFromData(t, FormatExecve) if r.Kind != KindNone { t.Errorf("execve: got kind %d, want KindNone (ignored)", r.Kind) } } func TestIgnoreAccept(t *testing.T) { r := classifyFromData(t, FormatAccept) if r.Kind != KindNone { t.Errorf("accept: got kind %d, want KindNone (ignored)", r.Kind) } } func TestIgnoreSocket(t *testing.T) { r := classifyFromData(t, FormatSocket) if r.Kind != KindNone { t.Errorf("socket: got kind %d, want KindNone (ignored)", r.Kind) } } func TestIgnoreKill(t *testing.T) { r := classifyFromData(t, FormatKill) if r.Kind != KindNone { t.Errorf("kill: got kind %d, want KindNone (no matching type)", r.Kind) } } func TestShouldIgnorePatterns(t *testing.T) { ignoreNames := []string{ "sys_enter_mknod", "sys_enter_mknodat", "sys_enter_execve", "sys_enter_execveat", "sys_enter_accept", "sys_enter_accept4", "sys_enter_listen", "sys_enter_epoll_ctl", "sys_enter_epoll_pwait", "sys_enter_recvfrom", "sys_enter_recvmsg", "sys_enter_recvmmsg", "sys_enter_sendto", "sys_enter_sendmsg", "sys_enter_sendmmsg", "sys_enter_socket", "sys_enter_socketpair", "sys_enter_getsockname", "sys_enter_inotify_init", "sys_enter_inotify_add_watch", "sys_enter_bind", "sys_enter_setns", "sys_enter_shutdown", "sys_enter_connect", "sys_enter_fanotify_init", "sys_enter_getpeername", } for _, name := range ignoreNames { if !shouldIgnore(name) { t.Errorf("shouldIgnore(%q) = false, want true", name) } } } func TestShouldNotIgnore(t *testing.T) { noIgnore := []string{ "sys_enter_read", "sys_enter_write", "sys_enter_openat", "sys_enter_close", "sys_enter_rename", "sys_enter_unlink", "sys_enter_copy_file_range", "sys_enter_msync", "sys_enter_pidfd_getfd", "sys_exit_read", "sys_exit_openat", } for _, name := range noIgnore { if shouldIgnore(name) { t.Errorf("shouldIgnore(%q) = true, want false", name) } } } // --- End-to-end classification with enter+exit pairs --- func TestClassifySyscallPairAccepted(t *testing.T) { tests := []struct { name string enter string exit string enterKind TracepointKind }{ {"read", FormatRead, FormatExitRead, KindFd}, {"openat", FormatOpenat, FormatExitOpenat, KindOpen}, {"rename", FormatRename, FormatExitRename, KindName}, {"close", FormatClose, FormatExitClose, KindFd}, {"dup3", FormatDup3, FormatExitDup3, KindDup3}, {"fcntl", FormatFcntl, FormatExitFcntl, KindFcntl}, {"sync", FormatSync, FormatExitSync, KindNull}, {"msync", FormatMsync, FormatExitMsync, KindNull}, {"getcwd", FormatGetcwd, FormatExitGetcwd, KindNull}, {"pidfd_getfd", FormatPidfdGetfd, FormatExitPidfdGetfd, KindFd}, {"copy_file_range", FormatCopyFileRange, FormatExitCopyFileRange, KindFd}, {"syslog", FormatSyslog, FormatExitSyslog, KindNull}, {"open_by_handle_at", FormatOpenByHandleAt, FormatExitOpenByHandleAt, KindOpenByHandleAt}, {"name_to_handle_at", FormatNameToHandleAt, FormatExitNameToHandleAt, KindPathname}, {"io_uring_enter", FormatIoUringEnter, FormatExitIoUringEnter, KindFd}, {"io_uring_register", FormatIoUringRegister, FormatExitIoUringRegister, KindFd}, {"pread64", FormatPread64, FormatExitPread64, KindFd}, {"symlink", FormatSymlink, FormatExitSymlink, KindName}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { input := tt.enter + "\n" + tt.exit output := GenerateTracepointsC(mustParseAll(t, input)) if strings.Contains(output, "Ignoring") { t.Errorf("syscall %s was ignored, expected accepted", tt.name) } }) } } func TestClassifySyscallPairIgnored(t *testing.T) { tests := []struct { name string enter string exit string }{ {"mknod", FormatMknod, FormatExitMknod}, {"execve", FormatExecve, FormatExitExecve}, {"accept", FormatAccept, FormatExitAccept}, {"socket", FormatSocket, FormatExitSocket}, {"kill", FormatKill, FormatExitKill}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { input := tt.enter + "\n" + tt.exit output := GenerateTracepointsC(mustParseAll(t, input)) if !strings.Contains(output, "Ignoring") { t.Errorf("syscall %s was accepted, expected ignored", tt.name) } }) } } func TestClassifyFormatNoExternalFields(t *testing.T) { f := &Format{ Name: "sys_enter_test", ID: 999, ExternalFields: nil, } r := ClassifyFormat(f) if r.Kind != KindNone { t.Errorf("ClassifyFormat with empty ExternalFields: got kind %d, want KindNone", r.Kind) } } func TestIsFdTypeNonMatch(t *testing.T) { nonFdTypes := []string{ "const char *", "long", "size_t", "pid_t", "umode_t", "char *", "void *", } for _, typ := range nonFdTypes { if isFdType(typ) { t.Errorf("isFdType(%q) = true, want false", typ) } } } func mustParseAll(t *testing.T, data string) []Format { t.Helper() formats, err := ParseFormats(strings.NewReader(data)) if err != nil { t.Fatalf("ParseFormats failed: %v", err) } return formats }