test(tunnel): pin the raced read, the walk error and the _index.md skip (#174)
Review round 1 on PR #186: - The swap test's static note had the same title as the raced note, so the harness's "inside was read" floor passed without reading r.md (skipping r.md stayed green). The static note now has its own title. - An unreadable directory under wiki/ reaches the walk-error path, and swallowing that error stayed green. New test asserts the error. - The FIFO test now runs with and without a writer held open. - _index.md skip had no test; new test. - index.go: the double blank line left by removing readTitleAndCreated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,25 +19,37 @@ import (
|
|||||||
// every note with a blocking os.Open, so a FIFO named *.md anywhere under
|
// every note with a blocking os.Open, so a FIFO named *.md anywhere under
|
||||||
// wiki/ hung every brain_write and brain_update (wikiUpkeep -> AutoTunnel),
|
// wiki/ hung every brain_write and brain_update (wikiUpkeep -> AutoTunnel),
|
||||||
// and a symlinked note's title became a tunnel candidate.
|
// and a symlinked note's title became a tunnel candidate.
|
||||||
func TestDetectTunnelsReturnsPromptlyWithAFIFOUnderWiki(t *testing.T) {
|
func TestDetectTunnelsReturnsPromptlyWithAFIFOUnderWikiWithAndWithoutAWriter(t *testing.T) {
|
||||||
b := t.TempDir()
|
for _, withWriter := range []bool{false, true} {
|
||||||
facts := filepath.Join(b, "wiki", "w", "facts")
|
t.Run(fmt.Sprintf("writer=%v", withWriter), func(t *testing.T) {
|
||||||
require.NoError(t, os.MkdirAll(facts, 0o755))
|
b := t.TempDir()
|
||||||
require.NoError(t, os.WriteFile(filepath.Join(facts, "ok.md"), []byte("---\ntitle: Zqinside Phrase\n---\n"), 0o644))
|
facts := filepath.Join(b, "wiki", "w", "facts")
|
||||||
require.NoError(t, syscall.Mkfifo(filepath.Join(facts, "f.md"), 0o644))
|
require.NoError(t, os.MkdirAll(facts, 0o755))
|
||||||
done := make(chan []brain.TunnelCandidate, 1)
|
require.NoError(t, os.WriteFile(filepath.Join(facts, "ok.md"), []byte("---\ntitle: Zqinside Phrase\n---\n"), 0o644))
|
||||||
go func() {
|
fifo := filepath.Join(facts, "f.md")
|
||||||
cs, _ := brain.DetectTunnels(b, "text mentioning zqinside phrase here")
|
require.NoError(t, syscall.Mkfifo(fifo, 0o644))
|
||||||
done <- cs
|
if withWriter {
|
||||||
}()
|
// A writer held open: a reader that opens the FIFO gets no
|
||||||
select {
|
// EOF and parks, unless the FIFO is never opened.
|
||||||
case cs := <-done:
|
w, err := os.OpenFile(fifo, os.O_RDWR, 0)
|
||||||
assert.Contains(t, fmt.Sprintf("%+v", cs), "Zqinside Phrase", "positive control")
|
require.NoError(t, err)
|
||||||
case <-time.After(3 * time.Second):
|
t.Cleanup(func() { _ = w.Close() })
|
||||||
if r, err := os.OpenFile(filepath.Join(facts, "f.md"), os.O_WRONLY|syscall.O_NONBLOCK, 0); err == nil {
|
}
|
||||||
_ = r.Close()
|
done := make(chan []brain.TunnelCandidate, 1)
|
||||||
}
|
go func() {
|
||||||
t.Fatal("DetectTunnels blocked on a FIFO")
|
cs, _ := brain.DetectTunnels(b, "text mentioning zqinside phrase here")
|
||||||
|
done <- cs
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case cs := <-done:
|
||||||
|
assert.Contains(t, fmt.Sprintf("%+v", cs), "Zqinside Phrase", "positive control")
|
||||||
|
case <-time.After(3 * time.Second):
|
||||||
|
if r, err := os.OpenFile(fifo, os.O_WRONLY|syscall.O_NONBLOCK, 0); err == nil {
|
||||||
|
_ = r.Close()
|
||||||
|
}
|
||||||
|
t.Fatal("DetectTunnels blocked on a FIFO")
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,16 +57,18 @@ func TestDetectTunnelsRefusesSymlinkedNotesAndSurvivesSwapRaces(t *testing.T) {
|
|||||||
b := t.TempDir()
|
b := t.TempDir()
|
||||||
facts := filepath.Join(b, "wiki", "w", "facts")
|
facts := filepath.Join(b, "wiki", "w", "facts")
|
||||||
require.NoError(t, os.MkdirAll(facts, 0o755))
|
require.NoError(t, os.MkdirAll(facts, 0o755))
|
||||||
require.NoError(t, os.WriteFile(filepath.Join(facts, "ok.md"), []byte("---\ntitle: Zqinside Phrase\n---\n"), 0o644))
|
// The static note's title differs from the raced note's, so the
|
||||||
|
// harness's "inside was read" floor can only be met by reading r.md.
|
||||||
|
require.NoError(t, os.WriteFile(filepath.Join(facts, "ok.md"), []byte("---\ntitle: Zqstatic Words\n---\n"), 0o644))
|
||||||
require.NoError(t, os.Symlink(brainfstest.Outside(t), filepath.Join(facts, "out.md")))
|
require.NoError(t, os.Symlink(brainfstest.Outside(t), filepath.Join(facts, "out.md")))
|
||||||
inBrain := brainfstest.WriteSentinelAt(t, filepath.Join(b, "raw", "s.md"))
|
inBrain := brainfstest.WriteSentinelAt(t, filepath.Join(b, "raw", "s.md"))
|
||||||
require.NoError(t, os.Symlink(filepath.Join("..", "..", "..", "raw", "s.md"), filepath.Join(facts, "in.md")))
|
require.NoError(t, os.Symlink(filepath.Join("..", "..", "..", "raw", "s.md"), filepath.Join(facts, "in.md")))
|
||||||
content := "zqinside phrase and " + brainfstest.Sentinel
|
content := "zqstatic words, zqinside phrase and " + brainfstest.Sentinel
|
||||||
|
|
||||||
cs, err := brain.DetectTunnels(b, content)
|
cs, err := brain.DetectTunnels(b, content)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
got := fmt.Sprintf("%+v", cs)
|
got := fmt.Sprintf("%+v", cs)
|
||||||
assert.Contains(t, got, "Zqinside Phrase", "positive control")
|
assert.Contains(t, got, "Zqstatic Words", "positive control")
|
||||||
assert.NotContains(t, got, brainfstest.Sentinel)
|
assert.NotContains(t, got, brainfstest.Sentinel)
|
||||||
|
|
||||||
p := filepath.Join(facts, "r.md")
|
p := filepath.Join(facts, "r.md")
|
||||||
@@ -77,3 +91,35 @@ func TestDetectTunnelsSkipsAWikiThatIsNotARealDirectory(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Empty(t, cs)
|
assert.Empty(t, cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An unreadable directory under wiki/ is a walk error and DetectTunnels
|
||||||
|
// reports it, as filepath.WalkDir did; it is not silently dropped.
|
||||||
|
func TestDetectTunnelsReportsAnUnreadableDirectoryUnderWiki(t *testing.T) {
|
||||||
|
if os.Geteuid() == 0 {
|
||||||
|
t.Skip("root ignores directory permissions")
|
||||||
|
}
|
||||||
|
b := t.TempDir()
|
||||||
|
require.NoError(t, os.MkdirAll(filepath.Join(b, "wiki", "w", "facts"), 0o755))
|
||||||
|
require.NoError(t, os.WriteFile(filepath.Join(b, "wiki", "w", "facts", "ok.md"), []byte("---\ntitle: Zqinside Phrase\n---\n"), 0o644))
|
||||||
|
locked := filepath.Join(b, "wiki", "other", "locked")
|
||||||
|
require.NoError(t, os.MkdirAll(locked, 0o755))
|
||||||
|
require.NoError(t, os.Chmod(locked, 0o000))
|
||||||
|
t.Cleanup(func() { _ = os.Chmod(locked, 0o755) })
|
||||||
|
_, err := brain.DetectTunnels(b, "zqinside phrase")
|
||||||
|
assert.ErrorIs(t, err, os.ErrPermission)
|
||||||
|
}
|
||||||
|
|
||||||
|
// _index.md files are generated, not notes: their title never becomes a
|
||||||
|
// candidate.
|
||||||
|
func TestDetectTunnelsSkipsIndexFiles(t *testing.T) {
|
||||||
|
b := t.TempDir()
|
||||||
|
w := filepath.Join(b, "wiki", "w")
|
||||||
|
require.NoError(t, os.MkdirAll(filepath.Join(w, "facts"), 0o755))
|
||||||
|
require.NoError(t, os.WriteFile(filepath.Join(w, "_index.md"), []byte("---\ntitle: Zqindex Words\n---\n"), 0o644))
|
||||||
|
require.NoError(t, os.WriteFile(filepath.Join(w, "facts", "ok.md"), []byte("---\ntitle: Zqinside Phrase\n---\n"), 0o644))
|
||||||
|
cs, err := brain.DetectTunnels(b, "zqindex words and zqinside phrase")
|
||||||
|
require.NoError(t, err)
|
||||||
|
got := fmt.Sprintf("%+v", cs)
|
||||||
|
assert.Contains(t, got, "Zqinside Phrase", "positive control")
|
||||||
|
assert.NotContains(t, got, "Zqindex")
|
||||||
|
}
|
||||||
|
|||||||
@@ -116,7 +116,6 @@ func collectWingEntries(bfs *brainfs.Brain, wingRel string) ([]noteEntry, error)
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// readTitleAndCreatedIn is readTitleAndCreated through the brain root,
|
// readTitleAndCreatedIn is readTitleAndCreated through the brain root,
|
||||||
// regular files only (hyperguild#157).
|
// regular files only (hyperguild#157).
|
||||||
func readTitleAndCreatedIn(bfs *brainfs.Brain, rel, slug string) (string, string) {
|
func readTitleAndCreatedIn(bfs *brainfs.Brain, rel, slug string) (string, string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user