diff --git a/test/util.go b/test/util.go index 100de7d..61ffc8c 100644 --- a/test/util.go +++ b/test/util.go @@ -53,6 +53,20 @@ func CheckRoutines(t *testing.T) func() { } } +// CheckRoutinesStrict is used to check for leaked go-routines. +// It differs from CheckRoutines in that it won't wait at all +// for lingering goroutines. This is helpful for tests that need +// to ensure clean closure of resources. +func CheckRoutinesStrict(tb testing.TB) func() { + return func() { + routines := getRoutines() + if len(routines) == 0 { + return + } + tb.Fatalf("%s: \n%s", "Unexpected routines on test end", strings.Join(routines, "\n\n")) // nolint + } +} + func getRoutines() []string { buf := make([]byte, 2<<20) buf = buf[:runtime.Stack(buf, true)] diff --git a/test/util_test.go b/test/util_test.go index 2b3d47d..e1ab6d9 100644 --- a/test/util_test.go +++ b/test/util_test.go @@ -4,6 +4,8 @@ package test import ( + "fmt" + "strings" "testing" "time" ) @@ -21,3 +23,37 @@ func TestCheckRoutines(t *testing.T) { time.Sleep(1 * time.Second) }() } + +func TestCheckRoutinesStrict(t *testing.T) { + mock := &tbMock{TB: t} + + // Limit runtime in case of deadlocks + lim := TimeOut(time.Second * 20) + defer lim.Stop() + + // Check for leaking routines + report := CheckRoutinesStrict(mock) + defer func() { + report() + if len(mock.fatalfCalled) == 0 { + t.Error("expected Fatalf to be called") + } + if !strings.Contains(mock.fatalfCalled[0], "Unexpected routines") { + t.Error("expected 'Unexpected routines'") + } + }() + + go func() { + time.Sleep(1 * time.Second) + }() +} + +type tbMock struct { + testing.TB + + fatalfCalled []string +} + +func (m *tbMock) Fatalf(format string, args ...any) { + m.fatalfCalled = append(m.fatalfCalled, fmt.Sprintf(format, args...)) +} diff --git a/utils/xor/xor_old.go b/utils/xor/xor_old.go index bd14d7c..f46f4d9 100644 --- a/utils/xor/xor_old.go +++ b/utils/xor/xor_old.go @@ -15,7 +15,7 @@ import ( ) const ( - wordSize = int(unsafe.Sizeof(uintptr(0))) // nolint:gosec + wordSize = int(unsafe.Sizeof(uintptr(0))) // nolint:gosec supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x" // nolint:gochecknoglobals )