diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-31 19:22:22 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-31 19:22:22 +0300 |
| commit | 63a20d8498bf161d16e8a8c8cc0b096a8355aa6f (patch) | |
| tree | 18aa764dacba2a6ddc3aabc6e36e44db6ea6b5dd /integrationtests/readwrite_test.go | |
| parent | 8a1bf6236f6a525881c647fd881093b393436411 (diff) | |
test(readahead): add end-to-end integration coverage
readahead(2) was traced (KindFd enter fd_event from args[0], UNCLASSIFIED
exit ret_event) but had no integration or ioworkload scenario coverage,
unlike its sibling sync_file_range. Add readwrite-readahead and
readwrite-readahead-ebadf scenarios plus TestReadwriteReadahead /
TestReadwriteReadaheadEbadf, asserting enter_readahead capture with path
attribution, zero attributed bytes (readahead returns 0/-1, not a byte
count, so it is correctly UNCLASSIFIED), and positive end-to-end duration.
No classification change: inspection confirms KindFd / UNCLASSIFIED is
correct per man 2 readahead; bytesFromRet returns 0 for UNCLASSIFIED so
the 0/-1 return is never misattributed as bytes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'integrationtests/readwrite_test.go')
| -rw-r--r-- | integrationtests/readwrite_test.go | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/integrationtests/readwrite_test.go b/integrationtests/readwrite_test.go index 7a479b7..c1efbb4 100644 --- a/integrationtests/readwrite_test.go +++ b/integrationtests/readwrite_test.go @@ -221,6 +221,48 @@ func TestReadwritePwriteInvalid(t *testing.T) { }) } +func TestReadwriteReadahead(t *testing.T) { + // readahead(2) is KindFd / UNCLASSIFIED: despite its ssize_t prototype it + // returns 0/-1 and transfers no bytes to userspace, so the tracer must + // attribute zero bytes (not misread the 0/-1 return as a byte count) while + // still capturing the fd (args[0]) on enter and timing the syscall. + result, _ := runScenarioResult(t, "readwrite-readahead", []ExpectedEvent{ + { + PathContains: "readaheadfile.txt", + Tracepoint: "enter_readahead", + Comm: "ioworkload", + MinCount: 1, + }, + }) + exp := ExpectedEvent{ + PathContains: "readaheadfile.txt", + Tracepoint: "enter_readahead", + Comm: "ioworkload", + } + // UNCLASSIFIED: no byte count is attributed for a successful readahead. + assertEventBytesEqual(t, result, exp, 0) + // Timing is captured end-to-end (enter/exit paired into a duration). + assertEventDurationPositive(t, result, exp) +} + +func TestReadwriteReadaheadEbadf(t *testing.T) { + // readahead on an invalid fd fails with EBADF, but ior still captures the + // enter_readahead tracepoint because arguments are read on syscall entry + // before the kernel returns the error. The UNCLASSIFIED -1 return must not + // be attributed as bytes. + result, _ := runScenarioResult(t, "readwrite-readahead-ebadf", []ExpectedEvent{ + { + Tracepoint: "enter_readahead", + Comm: "ioworkload", + MinCount: 1, + }, + }) + assertEventBytesEqual(t, result, ExpectedEvent{ + Tracepoint: "enter_readahead", + Comm: "ioworkload", + }, 0) +} + func assertEventBytesAtLeast(t *testing.T, result TestResult, exp ExpectedEvent, minBytes uint64) { t.Helper() var matched bool |
