From ade74696f89dc98b3472bbacd9f36860ca83e3c5 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 6 Jun 2026 09:08:39 +0300 Subject: test(retbytes): assert readlinkat READ_CLASSIFIED byte count end-to-end readlink/readlinkat are READ_CLASSIFIED (exit ctx->ret = link-target byte count), but the integration suite only asserted the enter_readlinkat pathname tracepoint via MinCount in link_test.go. The exit byte classification and positive duration were never validated end-to-end, unlike sibling READ-classified syscalls (read/recvfrom/getxattrat/ getdents64) in retbytes_test.go. Add retbytesReadlinkat to the phase-A workload: it creates a symlink with a known non-empty absolute target, opens the parent O_DIRECTORY, and re-issues SYS_READLINKAT in a short spaced window (mirroring the getdents64 driver) so ior can attach and capture an enter/exit pair under parallel load. Each call re-resolves the same link, so ctx->ret stays equal to the target length and is strictly positive. Add readlinkat (and symlink, used to build the link without mixing tracepoints) to retbytesTraceArgs, assert enter_readlinkat presence (MinCount) plus bytes>=1 via assertEventBytesAtLeast and a positive duration. bytes>=1 (not an exact target length) because the resolved path varies across temp dirs; >=1 is the safest invariant. Coverage hardening only; classify.go readlink/readlinkat=ReadClassified and the BPF arg capture (args[1]=pathname for readlinkat) are correct. Co-Authored-By: Claude Opus 4.8 --- integrationtests/retbytes_test.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'integrationtests/retbytes_test.go') diff --git a/integrationtests/retbytes_test.go b/integrationtests/retbytes_test.go index 37eb45b..a7cb45a 100644 --- a/integrationtests/retbytes_test.go +++ b/integrationtests/retbytes_test.go @@ -2,7 +2,7 @@ package integrationtests import "testing" -var retbytesTraceArgs = []string{"-trace-syscalls", "sendto,recvfrom,sendmsg,recvmsg,sendmmsg,recvmmsg,sendfile64,splice,tee,process_vm_writev,process_vm_readv,socketpair,pipe2,openat,write,read,close,lseek,fcntl,unlinkat,mkdirat,getdents64"} +var retbytesTraceArgs = []string{"-trace-syscalls", "sendto,recvfrom,sendmsg,recvmsg,sendmmsg,recvmmsg,sendfile64,splice,tee,process_vm_writev,process_vm_readv,socketpair,pipe2,openat,write,read,close,lseek,fcntl,unlinkat,mkdirat,getdents64,readlinkat,symlink"} func TestRetbytesPhaseA(t *testing.T) { const payloadLen = uint64(18) @@ -20,6 +20,7 @@ func TestRetbytesPhaseA(t *testing.T) { {Tracepoint: "enter_process_vm_writev", Comm: "ioworkload", MinCount: 1}, {Tracepoint: "enter_process_vm_readv", Comm: "ioworkload", MinCount: 1}, {Tracepoint: "enter_getdents64", Comm: "ioworkload", MinCount: 1}, + {Tracepoint: "enter_readlinkat", Comm: "ioworkload", MinCount: 1}, }, retbytesTraceArgs) for _, tracepoint := range []string{ @@ -51,4 +52,14 @@ func TestRetbytesPhaseA(t *testing.T) { getdentsExp := ExpectedEvent{Tracepoint: "enter_getdents64", Comm: "ioworkload"} assertEventBytesAtLeast(t, result, getdentsExp, 1) assertEventDurationPositive(t, result, getdentsExp) + + // readlinkat is READ_CLASSIFIED: a successful call reports ctx->ret > 0, + // the byte length of the resolved link target written into the caller's + // buffer. The retbytes driver points the symlink at a known non-empty + // target, so the exit byte count is strictly positive. Assert a + // conservative bytes>=1 minimum (the exact target length is deterministic + // but path-dependent across temp dirs, so >=1 is the safest invariant). + readlinkatExp := ExpectedEvent{Tracepoint: "enter_readlinkat", Comm: "ioworkload"} + assertEventBytesAtLeast(t, result, readlinkatExp, 1) + assertEventDurationPositive(t, result, readlinkatExp) } -- cgit v1.2.3