summaryrefslogtreecommitdiff
path: root/integrationtests/xattr_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-01 23:07:06 +0300
committerPaul Buetow <paul@buetow.org>2026-06-01 23:07:06 +0300
commit8251307ac3187b346ed12e9a54d9bf6d7cba7e53 (patch)
tree44d9f7f8485c906e19cd4ad0471d5c013c685b1c /integrationtests/xattr_test.go
parent1fa1cc46a0e34a25b1926837ba663b2446b8dc7c (diff)
test(xattr): add path-based setxattr end-to-end integration coverage
The xattr integration tests previously only asserted on getxattrat/ listxattrat (path/dirfd READ-classified variants). The path-based setxattr(2) was traced by the existing xattr-getxattrat scenario (workload calls syscall.Setxattr; xattrTraceArgs includes setxattr) but never asserted. Add TestXattrSetxattr to verify end-to-end that: - enter_setxattr captures the filesystem PATH at args[0] (kind=pathname), never the xattr NAME at args[1]; - exit_setxattr is UNCLASSIFIED: setxattr returns a 0/-1 status, not a byte count (the size arg is the INPUT value length), so accounted bytes must be exactly zero. This guards against the msgsnd-style bug of treating a status return as bytes written, and contrasts with getxattr/listxattr which DO return byte counts (READ-classified). This is the PATH-based set complement to filed task 8i0 (fd-based fsetxattr/fgetxattr/flistxattr/fremovexattr); it does not duplicate it. Classification (FamilyFS, KindPathname enter, UNCLASSIFIED ret) is verified by inspection per task guidance, not by a unit test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'integrationtests/xattr_test.go')
-rw-r--r--integrationtests/xattr_test.go38
1 files changed, 38 insertions, 0 deletions
diff --git a/integrationtests/xattr_test.go b/integrationtests/xattr_test.go
index 2ba30ac..16efb4a 100644
--- a/integrationtests/xattr_test.go
+++ b/integrationtests/xattr_test.go
@@ -40,6 +40,44 @@ func TestXattrGetxattrat(t *testing.T) {
assertEventDurationPositive(t, result, exp)
}
+// TestXattrSetxattr verifies ior traces the PATH-based setxattr(2) end-to-end.
+// setxattr(const char *path, const char *name, const void *value, size_t size,
+// int flags) takes a real filesystem PATH at args[0] (kind=pathname) and the
+// xattr NAME at args[1]; only the path must be captured on entry, so
+// enter_setxattr must carry the file path "xattrfile.txt" and never the xattr
+// name "user.ior". Crucially, setxattr returns 0 on success / -1 on error — its
+// `size` argument is the INPUT value length, NOT a byte count returned by the
+// call. The exit is therefore UNCLASSIFIED (contrast getxattr/listxattr, which
+// DO return byte counts and are READ-classified), so the recorded byte total
+// must be exactly zero. This reuses the xattr-getxattrat scenario, whose
+// workload performs syscall.Setxattr(path, "user.ior", ...) and is traced via
+// xattrTraceArgs ("getxattrat,setxattr,openat").
+func TestXattrSetxattr(t *testing.T) {
+ result, _ := runScenarioResultWithIorArgs(t, "xattr-getxattrat", []ExpectedEvent{
+ {
+ PathContains: "xattrfile.txt",
+ Tracepoint: "enter_setxattr",
+ Comm: "ioworkload",
+ MinCount: 1,
+ },
+ }, xattrTraceArgs)
+
+ // The captured path must be the filesystem path, never the xattr name.
+ for _, rec := range result.Records {
+ if rec.TraceID.String() == "enter_setxattr" && rec.Path == "user.ior" {
+ t.Errorf("setxattr captured xattr name %q as path instead of file path", rec.Path)
+ }
+ }
+
+ // setxattr is UNCLASSIFIED: its return is a 0/-1 status, never a byte count
+ // (the `size` arg is the input value length). The accounted bytes for the
+ // setxattr events must therefore be exactly zero — guarding against the
+ // msgsnd-style bug of treating a status return as bytes written.
+ exp := ExpectedEvent{Tracepoint: "enter_setxattr", Comm: "ioworkload"}
+ assertEventBytesEqual(t, result, exp, 0)
+ assertEventDurationPositive(t, result, exp)
+}
+
// TestXattrListxattrat verifies ior traces listxattrat(2) (Linux 6.13+)
// end-to-end. listxattrat takes a dirfd plus a real filesystem path at args[1]
// (NOT args[0]=dfd); only the path must be captured. The path is read on