summaryrefslogtreecommitdiff
path: root/integrationtests/cmd
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-21 21:35:09 +0200
committerPaul Buetow <paul@buetow.org>2026-02-21 21:35:09 +0200
commit065389bac04c71a5dd5f44b2cfe5fe801bafabab (patch)
tree2be4be6ab3970ffc329d31ad9be44c25a4e15deb /integrationtests/cmd
parentc36cb85503ce96a589a2dd38c1279b31c87164f2 (diff)
Add negative integration tests for stat syscalls (task 348)
Add three negative test scenarios for stat-family syscalls: - stat-enoent: SYS_STAT on nonexistent file (ENOENT) - stat-access-enoent: SYS_ACCESS on nonexistent file (ENOENT, since tests run as root and EACCES is bypassed) - stat-fstat-ebadf: SYS_FSTAT on invalid fd 99999 (EBADF) Each scenario verifies that ior captures the tracepoint on syscall entry even when the syscall fails. Amp-Thread-ID: https://ampcode.com/threads/T-019c81af-d01d-75db-8a92-37951fb1503c Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'integrationtests/cmd')
-rw-r--r--integrationtests/cmd/ioworkload/scenarios.go66
1 files changed, 66 insertions, 0 deletions
diff --git a/integrationtests/cmd/ioworkload/scenarios.go b/integrationtests/cmd/ioworkload/scenarios.go
index 5eb8acb..3f5ee4c 100644
--- a/integrationtests/cmd/ioworkload/scenarios.go
+++ b/integrationtests/cmd/ioworkload/scenarios.go
@@ -76,6 +76,9 @@ var scenarios = map[string]func() error{
"stat-statx": statStatx,
"stat-access": statAccess,
"stat-faccessat": statFaccessat,
+ "stat-enoent": statEnoent,
+ "stat-access-enoent": statAccessEnoent,
+ "stat-fstat-ebadf": statFstatEbadf,
"sync-basic": syncBasic,
"sync-fdatasync": syncFdatasync,
"sync-sync": syncSync,
@@ -2009,6 +2012,69 @@ func statFaccessat() error {
return nil
}
+// statEnoent attempts to stat a nonexistent file via raw SYS_STAT.
+// The syscall fails with ENOENT, but ior captures the enter_newstat
+// tracepoint because the filename is read on entry.
+func statEnoent() error {
+ dir, cleanup, err := makeTempDir("stat-enoent")
+ if err != nil {
+ return err
+ }
+ defer cleanup()
+
+ path := filepath.Join(dir, "stat-enoent-missing.txt")
+ pathBytes, err := syscall.BytePtrFromString(path)
+ if err != nil {
+ return fmt.Errorf("path bytes: %w", err)
+ }
+ var stat syscall.Stat_t
+ _, _, errno := syscall.Syscall(syscall.SYS_STAT, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(&stat)), 0)
+ runtime.KeepAlive(pathBytes)
+ runtime.KeepAlive(&stat)
+ if errno == 0 {
+ return fmt.Errorf("expected ENOENT, but stat succeeded")
+ }
+ return nil
+}
+
+// statAccessEnoent attempts to check access on a nonexistent file via raw
+// SYS_ACCESS. The syscall fails with ENOENT, but ior captures the
+// enter_access tracepoint because the path is read on entry.
+// We use ENOENT instead of EACCES because integration tests run as root,
+// which bypasses DAC permission checks.
+func statAccessEnoent() error {
+ dir, cleanup, err := makeTempDir("stat-access-enoent")
+ if err != nil {
+ return err
+ }
+ defer cleanup()
+
+ path := filepath.Join(dir, "access-enoent-missing.txt")
+ pathBytes, err := syscall.BytePtrFromString(path)
+ if err != nil {
+ return fmt.Errorf("path bytes: %w", err)
+ }
+ _, _, errno := syscall.Syscall(syscall.SYS_ACCESS, uintptr(unsafe.Pointer(pathBytes)), rOK, 0)
+ runtime.KeepAlive(pathBytes)
+ if errno == 0 {
+ return fmt.Errorf("expected ENOENT, but access succeeded")
+ }
+ return nil
+}
+
+// statFstatEbadf calls raw SYS_FSTAT on an invalid fd (99999).
+// The syscall fails with EBADF, but ior captures the enter_newfstat
+// tracepoint because it is recorded on syscall entry.
+func statFstatEbadf() error {
+ var stat syscall.Stat_t
+ _, _, errno := syscall.Syscall(syscall.SYS_FSTAT, 99999, uintptr(unsafe.Pointer(&stat)), 0)
+ runtime.KeepAlive(&stat)
+ if errno == 0 {
+ return fmt.Errorf("expected EBADF, but fstat succeeded")
+ }
+ return nil
+}
+
// syncBasic opens a file, writes data, and fsyncs it.
func syncBasic() error {
dir, cleanup, err := makeTempDir("sync-basic")