1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
package integrationtests
import (
"strings"
"testing"
)
func TestRenameBasic(t *testing.T) {
runScenario(t, "rename-basic", []ExpectedEvent{
{
PathContains: "newname.txt",
Tracepoint: "enter_rename",
Comm: "ioworkload",
MinCount: 1,
},
})
}
func TestRenameRenameat(t *testing.T) {
runScenario(t, "rename-renameat", []ExpectedEvent{
{
PathContains: "renameat-new.txt",
Tracepoint: "enter_renameat",
Comm: "ioworkload",
MinCount: 1,
},
})
}
func TestRenameRenameat2(t *testing.T) {
runScenario(t, "rename-renameat2", []ExpectedEvent{
{
PathContains: "renameat2-new.txt",
Tracepoint: "enter_renameat2",
Comm: "ioworkload",
MinCount: 1,
},
})
}
func TestRenameEnoent(t *testing.T) {
runScenario(t, "rename-enoent", []ExpectedEvent{
{
PathContains: "rename-enoent-new.txt",
Tracepoint: "enter_rename",
Comm: "ioworkload",
MinCount: 1,
},
})
}
func TestRenameNoreplace(t *testing.T) {
runScenario(t, "rename-noreplace", []ExpectedEvent{
{
PathContains: "noreplace-dst.txt",
Tracepoint: "enter_renameat2",
Comm: "ioworkload",
MinCount: 1,
},
})
}
// TestRenameRenameatOldnameInParquet locks in the oldname capture end-to-end
// for an AT-variant. renameat passes the source path at args[1] (after the
// olddfd dirfd), so this validates the args[1] oldname index: the new `old_file`
// parquet column must carry the source path while `file` carries the new path.
// A wrong-oldname-index regression would surface here as a missing/empty
// old_file, which no prior persisted-output test could detect.
func TestRenameRenameatOldnameInParquet(t *testing.T) {
h := newTestHarness(t)
path, pid, err := h.RunParquetWithIorArgs("rename-renameat", defaultDuration,
[]string{"-trace-syscalls", "renameat"})
if err != nil {
t.Fatalf("run rename-renameat parquet scenario: %v", err)
}
rows := filterRecordsByPID(readParquetRecords(t, path), uint32(pid))
if len(rows) == 0 {
t.Fatalf("expected parquet rows for workload PID %d", pid)
}
var sawRenameat bool
for _, row := range rows {
if row.Syscall != "renameat" {
// old_file is rename/link-only; everything else must leave it empty.
if row.OldFile != "" {
t.Fatalf("%s row has unexpected old_file %q", row.Syscall, row.OldFile)
}
continue
}
sawRenameat = true
// file == newname; old_file == oldname (captured at args[1]).
if !strings.Contains(row.File, "renameat-new.txt") {
t.Fatalf("renameat row file = %q, want it to contain renameat-new.txt", row.File)
}
if !strings.Contains(row.OldFile, "renameat-old.txt") {
t.Fatalf("renameat row old_file = %q, want it to contain renameat-old.txt (args[1] oldname capture)", row.OldFile)
}
}
if !sawRenameat {
t.Fatalf("expected at least one renameat row in parquet output")
}
}
|