AssertNoLeakFrom and the search Query race test passed vacuously when every symlink swap failed or every read errored. Both now count successful symlink swaps and reads that returned the inside note and fail if either is zero; the Query race reader no longer swallows Query's error. Verified by flipping: a swapper whose os.Symlink always fails turns notes, wiki and search race tests red; Query on a missing brain dir turns the search race test red. Closes #177 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
2.2 KiB
Go
80 lines
2.2 KiB
Go
package brainfstest
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// recordingTB stands in for the test under AssertNoLeakFrom so a fatal
|
|
// there can be observed instead of failing this test. Fatalf ends the
|
|
// calling goroutine the way testing.T does.
|
|
type recordingTB struct {
|
|
testing.TB
|
|
failed bool
|
|
msg string
|
|
}
|
|
|
|
func (r *recordingTB) Fatalf(format string, args ...any) {
|
|
r.failed, r.msg = true, fmt.Sprintf(format, args...)
|
|
runtime.Goexit()
|
|
}
|
|
|
|
func runAssert(t *testing.T, path, target string, read func() string) *recordingTB {
|
|
t.Helper()
|
|
r := &recordingTB{TB: t}
|
|
done := make(chan struct{})
|
|
go func() {
|
|
defer close(done)
|
|
AssertNoLeakFrom(r, path, "inside", target, 200*time.Millisecond, read)
|
|
}()
|
|
<-done
|
|
return r
|
|
}
|
|
|
|
// hyperguild#177: with every swap failing, no leak can occur, so the leak
|
|
// assertion passed without testing anything.
|
|
func TestAssertNoLeakFromFailsWhenNoSymlinkSwapSucceeds(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "missing-dir", "r.md")
|
|
r := runAssert(t, path, Outside(t), func() string { return "inside" })
|
|
if !r.failed {
|
|
t.Fatal("AssertNoLeakFrom passed with zero successful symlink swaps")
|
|
}
|
|
}
|
|
|
|
// hyperguild#177: a reader that always errors returns nothing, so it never
|
|
// leaks either.
|
|
func TestAssertNoLeakFromFailsWhenNoReadReturnsTheInsideNote(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "r.md")
|
|
r := runAssert(t, path, Outside(t), func() string { return "" })
|
|
if !r.failed {
|
|
t.Fatal("AssertNoLeakFrom passed with zero reads returning the inside note")
|
|
}
|
|
}
|
|
|
|
// Positive control: a reader that refuses symlinks and reads regular files
|
|
// passes, so the floors do not fail a working reader.
|
|
func TestAssertNoLeakFromPassesAReaderThatRefusesSymlinks(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "r.md")
|
|
read := func() string {
|
|
f, err := os.OpenFile(path, os.O_RDONLY|noFollow, 0)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
defer func() { _ = f.Close() }()
|
|
b := make([]byte, 64)
|
|
n, _ := f.Read(b)
|
|
return string(b[:n])
|
|
}
|
|
r := runAssert(t, path, Outside(t), read)
|
|
if r.failed {
|
|
t.Fatalf("a symlink-refusing reader failed: %s", r.msg)
|
|
}
|
|
}
|
|
|
|
const noFollow = syscall.O_NOFOLLOW
|