From f601dc90fcef3f270c55a9612c5f0326dbd0f391 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 9 Jun 2026 22:24:30 +0300 Subject: feat(parquet): export rename/link oldname + assert oldname capture end-to-end rename-family (rename/renameat/renameat2) and link-family (link/linkat/ symlink/symlinkat) capture BOTH paths in BPF (name_event.oldname at args[1] for the AT-variants, after a dirfd, plus newname), but only newname reached any persisted output. event.Pair.FileName() resolves to oldnameNewnameFile.Name() == Newname, so the parquet `file` column, CSV, and flamegraph Path all carried newname; the captured oldname survived only in the TUI stream String() repr ("old:... ->new:..."). The oldname capture (and its args[1] index for the AT-variants) was therefore never validated end-to-end, and a wrong-oldname-index regression would surface in no persisted output or test. Surface oldname as one additive, backward-compatible column, mirroring the dedicated optional-column convention (address_space_bytes, requested_sleep_ns, epoll_*): - old_file (String): source/old path for rename/link syscalls; empty for every other syscall. The existing `file` column keeps its semantics (newname for rename/link). Data flows name_event.oldname -> event.Pair.Oldname (populated in handleNameExit alongside the existing File) -> streamrow.Row.OldName -> parquet.Record.OldFile. Docs (docs/parquet-querying.md) and the Magefile parquetValidate column list updated in lockstep. The new TestRenameRenameatOldnameInParquet integration test exercises the renameat AT-variant (oldname at args[1] after the olddfd dirfd) and asserts the parquet old_file column carries renameat-old.txt while file carries renameat-new.txt, and that old_file stays empty for non-rename/ link rows -- locking in the args[1] oldname capture end-to-end. Co-Authored-By: Claude Opus 4.8 --- integrationtests/rename_test.go | 48 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'integrationtests') diff --git a/integrationtests/rename_test.go b/integrationtests/rename_test.go index b64ea56..31012f2 100644 --- a/integrationtests/rename_test.go +++ b/integrationtests/rename_test.go @@ -1,6 +1,9 @@ package integrationtests -import "testing" +import ( + "strings" + "testing" +) func TestRenameBasic(t *testing.T) { runScenario(t, "rename-basic", []ExpectedEvent{ @@ -56,3 +59,46 @@ func TestRenameNoreplace(t *testing.T) { }, }) } + +// 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") + } +} -- cgit v1.2.3