From 4f44de8ee0ec51ee5c934048405030e362cc197f Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 2 Jun 2026 21:32:47 +0300 Subject: test(integration): add cachestat end-to-end coverage cachestat(2) had no integration coverage. Add a readwrite-cachestat ioworkload scenario and TestReadwriteCachestat mirroring the readahead precedent: open a temp file, write data to populate the page cache, then issue cachestat via a raw syscall (no glibc/unix wrapper) with a whole-file cachestat_range and zeroed cachestat output buffer, flags=0. ENOSYS on kernels < 6.5 is tolerated for portability. The test asserts enter_cachestat is captured with the fd-resolved file path, that the UNCLASSIFIED return attributes zero bytes, and that the syscall duration is positive. golang.org/x/sys is promoted to a direct dependency. Verified PASS under sudo on kernel 7.0.9. Co-Authored-By: Claude Opus 4.8 --- integrationtests/readwrite_test.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'integrationtests/readwrite_test.go') diff --git a/integrationtests/readwrite_test.go b/integrationtests/readwrite_test.go index f4f528a..8bfa539 100644 --- a/integrationtests/readwrite_test.go +++ b/integrationtests/readwrite_test.go @@ -302,6 +302,32 @@ func TestReadwriteReadaheadEbadf(t *testing.T) { }, 0) } +func TestReadwriteCachestat(t *testing.T) { + // cachestat(2) is KindFd / UNCLASSIFIED: it queries page-cache residency for + // a file and returns 0/-1 (no byte count, no I/O bytes to userspace), so the + // tracer must attribute zero bytes while still capturing the fd (args[0]) on + // enter and timing the syscall. cachestat is Linux 6.5+; the enter tracepoint + // fires before the kernel checks availability, so even an ENOSYS kernel would + // still record enter_cachestat, but this dev kernel (7.0.9) supports it fully. + result, _ := runScenarioResult(t, "readwrite-cachestat", []ExpectedEvent{ + { + PathContains: "cachestatfile.txt", + Tracepoint: "enter_cachestat", + Comm: "ioworkload", + MinCount: 1, + }, + }) + exp := ExpectedEvent{ + PathContains: "cachestatfile.txt", + Tracepoint: "enter_cachestat", + Comm: "ioworkload", + } + // UNCLASSIFIED: no byte count is attributed for a successful cachestat. + assertEventBytesEqual(t, result, exp, 0) + // Timing is captured end-to-end (enter/exit paired into a duration). + assertEventDurationPositive(t, result, exp) +} + func assertEventBytesAtLeast(t *testing.T, result TestResult, exp ExpectedEvent, minBytes uint64) { t.Helper() var matched bool -- cgit v1.2.3