stopevidence test: wait until fd 3 holds the database by identity before scanning (flaky on arm64 CI)
The namespace holder's fd 3 can be the dynamic loader's libc while unshare or sh starts, so the old wait (any readlink text) scanned too early.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+14
−3
internal/stopevidence/fdholders_alias_linux_test.go+14 −3
CI passed — run details
diff --git a/internal/stopevidence/fdholders_alias_linux_test.go b/internal/stopevidence/fdholders_alias_linux_test.go| index 6c9971286..b0ee488ce 100644 |
| --- a/internal/stopevidence/fdholders_alias_linux_test.go |
| +++ b/internal/stopevidence/fdholders_alias_linux_test.go |
| @@ -132,14 +132,25 @@ func TestFDIdentityFindsAHolderInAnotherMountNamespace(t *testing.T) { |
| t.Cleanup(func() { cmd.Process.Kill(); cmd.Wait() }) |
| pid := cmd.Process.Pid |
| fd3 := filepath.Join("/proc", strconv.Itoa(pid), "fd", "3") |
| + // Until sh has run the mount and exec'd sleep, fd 3 can be some other |
| + // file (the dynamic loader's libc, while unshare or sh starts), so wait |
| + // for fd 3 to be the database itself, by identity: stat through the |
| + // magic link reaches the file the descriptor holds in any namespace. |
| + want, err := os.Stat(db) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| var target string |
| + held := false |
| for deadline := time.Now().Add(5 * time.Second); time.Now().Before(deadline); time.Sleep(20 * time.Millisecond) { |
| - if target, _ = os.Readlink(fd3); target != "" { |
| + if fi, err := os.Stat(fd3); err == nil && os.SameFile(fi, want) { |
| + target, _ = os.Readlink(fd3) |
| + held = true |
| break |
| } |
| } |
| - if target == "" { |
| - t.Skip("the namespace holder never came up (unprivileged user namespaces refused?)") |
| + if !held { |
| + t.Skip("the namespace holder never came up holding the database (unprivileged user namespaces refused?)") |
| } |
| if target != aliased { |
| t.Logf("descriptor text %q (expected the bind path %q)", target, aliased) |