summaryrefslogtreecommitdiff
path: root/integrationtests
diff options
context:
space:
mode:
Diffstat (limited to 'integrationtests')
-rw-r--r--integrationtests/cmd/ioworkload/scenario_open.go29
-rw-r--r--integrationtests/cmd/ioworkload/scenarios.go1
-rw-r--r--integrationtests/open_test.go34
3 files changed, 63 insertions, 1 deletions
diff --git a/integrationtests/cmd/ioworkload/scenario_open.go b/integrationtests/cmd/ioworkload/scenario_open.go
index 449549c..d86e53b 100644
--- a/integrationtests/cmd/ioworkload/scenario_open.go
+++ b/integrationtests/cmd/ioworkload/scenario_open.go
@@ -6,6 +6,7 @@ import (
"path/filepath"
"runtime"
"syscall"
+ "time"
"unsafe"
)
@@ -226,3 +227,31 @@ func openByHandleAtSyscall(mountFD int, handle []byte, flags int) (int, error) {
}
return int(fd), nil
}
+
+// openDurationGap creates two openat syscalls separated by a deliberate sleep.
+// Integration tests use this to assert durationToPrev captures inter-syscall gaps.
+func openDurationGap() error {
+ dir, cleanup, err := makeTempDir("open-duration-gap")
+ if err != nil {
+ return err
+ }
+ defer cleanup()
+
+ first := filepath.Join(dir, "gap-first.txt")
+ fd1, err := syscall.Open(first, syscall.O_RDWR|syscall.O_CREAT, 0o644)
+ if err != nil {
+ return fmt.Errorf("open first: %w", err)
+ }
+ if err := syscall.Close(fd1); err != nil {
+ return fmt.Errorf("close first: %w", err)
+ }
+
+ time.Sleep(800 * time.Millisecond)
+
+ second := filepath.Join(dir, "gap-second.txt")
+ fd2, err := syscall.Open(second, syscall.O_RDWR|syscall.O_CREAT, 0o644)
+ if err != nil {
+ return fmt.Errorf("open second: %w", err)
+ }
+ return syscall.Close(fd2)
+}
diff --git a/integrationtests/cmd/ioworkload/scenarios.go b/integrationtests/cmd/ioworkload/scenarios.go
index a6e7a5f..6910314 100644
--- a/integrationtests/cmd/ioworkload/scenarios.go
+++ b/integrationtests/cmd/ioworkload/scenarios.go
@@ -11,6 +11,7 @@ var scenarios = map[string]func() error{
"open-basic": openBasic,
"open-creat": openCreat,
"open-by-handle-at": openByHandleAt,
+ "open-duration-gap": openDurationGap,
"open-enoent": openEnoent,
"open-rdonly-write": openRdonlyWrite,
"open-pid-filter": openPidFilter,
diff --git a/integrationtests/open_test.go b/integrationtests/open_test.go
index dae5244..c2a0366 100644
--- a/integrationtests/open_test.go
+++ b/integrationtests/open_test.go
@@ -1,6 +1,9 @@
package integrationtests
-import "testing"
+import (
+ "strings"
+ "testing"
+)
func TestOpenBasic(t *testing.T) {
runScenario(t, "open-basic", []ExpectedEvent{
@@ -93,3 +96,32 @@ func TestOpenPidFilter(t *testing.T) {
},
})
}
+
+func TestOpenDurationGap(t *testing.T) {
+ h := newTestHarness(t)
+ result, pid, err := h.Run("open-duration-gap", defaultDuration)
+ if err != nil {
+ t.Fatalf("run scenario open-duration-gap: %v", err)
+ }
+
+ AssertNoUnexpectedPID(t, result, pid)
+ AssertNoUnexpectedComm(t, result, "ioworkload")
+
+ // We intentionally sleep 800ms between first and second openat.
+ const minGapNs = uint64(500 * 1_000_000)
+
+ for _, rec := range result.Records {
+ if !strings.Contains(rec.TraceID.String(), "enter_openat") {
+ continue
+ }
+ if !strings.Contains(rec.Path, "gap-second.txt") {
+ continue
+ }
+ if rec.Cnt.DurationToPrev < minGapNs {
+ t.Fatalf("durationToPrev for second openat = %d ns, want >= %d ns", rec.Cnt.DurationToPrev, minGapNs)
+ }
+ return
+ }
+
+ t.Fatalf("did not find second openat record for gap-second.txt")
+}