From 6d0d7814c052f5540746456c8e3c47cc1657bf61 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sun, 31 May 2026 10:36:10 +0300 Subject: test(retbytes): assert read byte counts for pread64/preadv/preadv2 The retbytes integration coverage exercised read/write/sendto/etc but the positional read p-variants only had presence assertions (pread64) or no coverage at all (preadv/preadv2), so their READ_CLASSIFIED byte accounting was validated only by unit tests, not end-to-end. Add a positive byte-count assertion to TestReadwritePread and new readwrite-preadv / readwrite-preadv2 workload scenarios plus integration tests that read a known payload and assert the attributed byte count, mirroring the existing pwrite64 assertion. preadv2 lacks a Go syscall.SYS_PREADV2 constant, so its number is provided per-GOARCH (amd64=327, arm64=286) following the securitySyscallNumbers pattern. Addresses the read side of b20. Co-Authored-By: Claude Opus 4.8 --- integrationtests/readwrite_test.go | 50 +++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) (limited to 'integrationtests/readwrite_test.go') diff --git a/integrationtests/readwrite_test.go b/integrationtests/readwrite_test.go index 69f60ea..7a479b7 100644 --- a/integrationtests/readwrite_test.go +++ b/integrationtests/readwrite_test.go @@ -31,7 +31,11 @@ func TestReadwriteBasic(t *testing.T) { } func TestReadwritePread(t *testing.T) { - runScenario(t, "readwrite-pread", []ExpectedEvent{ + // pread64 returns the number of bytes read (READ_CLASSIFIED), so a + // successful positional read must attribute the payload byte count + // end-to-end, mirroring the pwrite64 byte-count assertion below. + const payloadLen = uint64(len("pread test data")) + result, _ := runScenarioResult(t, "readwrite-pread", []ExpectedEvent{ { PathContains: "preadfile.txt", Tracepoint: "enter_pread64", @@ -39,6 +43,11 @@ func TestReadwritePread(t *testing.T) { MinCount: 1, }, }) + assertEventBytesAtLeast(t, result, ExpectedEvent{ + PathContains: "preadfile.txt", + Tracepoint: "enter_pread64", + Comm: "ioworkload", + }, payloadLen) } func TestReadwritePwrite(t *testing.T) { @@ -57,6 +66,45 @@ func TestReadwritePwrite(t *testing.T) { }, 1) } +func TestReadwritePreadv(t *testing.T) { + // preadv is the positional vectored read sibling of pread64/readv and is + // READ_CLASSIFIED, so a successful read must attribute the payload bytes + // end-to-end. + const payloadLen = uint64(len("preadv test data")) + result, _ := runScenarioResult(t, "readwrite-preadv", []ExpectedEvent{ + { + PathContains: "preadvfile.txt", + Tracepoint: "enter_preadv", + Comm: "ioworkload", + MinCount: 1, + }, + }) + assertEventBytesAtLeast(t, result, ExpectedEvent{ + PathContains: "preadvfile.txt", + Tracepoint: "enter_preadv", + Comm: "ioworkload", + }, payloadLen) +} + +func TestReadwritePreadv2(t *testing.T) { + // preadv2 is the positional vectored read variant with flags; like preadv + // it is READ_CLASSIFIED and must attribute the payload bytes end-to-end. + const payloadLen = uint64(len("preadv2 test data")) + result, _ := runScenarioResult(t, "readwrite-preadv2", []ExpectedEvent{ + { + PathContains: "preadv2file.txt", + Tracepoint: "enter_preadv2", + Comm: "ioworkload", + MinCount: 1, + }, + }) + assertEventBytesAtLeast(t, result, ExpectedEvent{ + PathContains: "preadv2file.txt", + Tracepoint: "enter_preadv2", + Comm: "ioworkload", + }, payloadLen) +} + func TestReadwriteReadv(t *testing.T) { result, _ := runScenarioResult(t, "readwrite-readv", []ExpectedEvent{ { -- cgit v1.2.3