From 656a4324e896da8a3d0b1c0de6b91a2ffe1e99cd Mon Sep 17 00:00:00 2001 From: Ophestra Date: Wed, 7 Oct 2026 03:37:39 +0900 Subject: internal/testsuite: handle intermittent EACCES The test suite is now fast enough that the tester can also suffer from the same vfs race. This change works around such intermittent failures. Signed-off-by: Ophestra --- cmd/hakurei/testsuite/sandbox/tester/main.go | 12 ++++++++++-- internal/testsuite/testsuite.go | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/cmd/hakurei/testsuite/sandbox/tester/main.go b/cmd/hakurei/testsuite/sandbox/tester/main.go index 452712d9..6ccad5be 100644 --- a/cmd/hakurei/testsuite/sandbox/tester/main.go +++ b/cmd/hakurei/testsuite/sandbox/tester/main.go @@ -15,6 +15,7 @@ import ( "syscall" "hakurei.app/cmd/hakurei/testsuite/sandbox/testdata" + "hakurei.app/internal/testsuite" "hakurei.app/internal/testsuite/mountinfo" ) @@ -29,6 +30,13 @@ func mustAbs(s string) string { return s } +// dial is [net.Dial] retrying intermittent EACCES. +func dial(network, address string) (net.Conn, error) { + return testsuite.RetryExp(func() (net.Conn, error) { + return net.Dial(network, address) + }, syscall.EACCES) +} + func main() { log.SetFlags(0) log.SetPrefix("tester: ") @@ -165,8 +173,8 @@ func main() { if want.TrySocket != "" { retry: - abstractConn, abstractErr := net.Dial("unix", "@"+want.TrySocket) - pathnameConn, pathnameErr := net.Dial("unix", want.TrySocket) + abstractConn, abstractErr := dial("unix", "@"+want.TrySocket) + pathnameConn, pathnameErr := dial("unix", want.TrySocket) ok := true if abstractErr == nil { diff --git a/internal/testsuite/testsuite.go b/internal/testsuite/testsuite.go index 6e48eca1..a1e39720 100644 --- a/internal/testsuite/testsuite.go +++ b/internal/testsuite/testsuite.go @@ -28,6 +28,32 @@ func ReceiveSignals() { log.Fatalf("terminating on signal %s", <-s) } +// RetryExp retries f if the resulting error is equivalent to e according to +// [errors.Is], up to 8 times. +func RetryExp[T any](f func() (T, error), e error) (v T, err error) { + const statRetry = 8 // 64 ms + var n int + d := 256 * time.Microsecond + +retry: + v, err = f() + if err != nil { + if !errors.Is(err, e) { + return + } + + n++ + if n == statRetry { + return + } + + time.Sleep(d) + d *= 2 + goto retry + } + return +} + var ( // users caches [user.LookupId] calls. users = make(map[string]*user.User) -- cgit v1.3.1