Add a test for read requests waiting when a task is stopped

Ask a view buffer manager to read to the end of its content twice over,
then stop the task before it has served either request, as a re-render
replacing it does. Only the request it had already picked up is answered;
the one still queued behind it is dropped, and its caller waits for a
callback that never comes.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller 2026-09-05 13:24:34 +02:00
parent ef3a4c71cc
commit e148959865

View file

@ -486,3 +486,45 @@ func TestNewCmdTaskRefresh(t *testing.T) {
}
}
}
// A read request is answered by the task that serves it calling the request's Then.
// This checks that requests still waiting when the task is stopped are answered too,
// which is what happens when a re-render replaces the task.
func TestQueuedReadRequestsAreAnsweredWhenTheTaskStops(t *testing.T) {
noop := func() {}
task := gocui.NewFakeTask()
// A pipe the task blocks on, so that the requests are still waiting when it stops.
pipeReader, pipeWriter := io.Pipe()
defer pipeWriter.Close()
manager := NewViewBufferManager(
utils.NewDummyLog(), bytes.NewBuffer(nil), noop, noop, noop, noop, noop, noop,
func() gocui.Task { return task },
func(f func()) error { f(); return nil },
)
stop := make(chan struct{})
fn := manager.NewCmdTask(
func() (Cmd, io.Reader) { return ExecCmd{Cmd: exec.Command("true")}, pipeReader },
"", LinesToRead{Total: 1, InitialRefreshAfter: -1}, noop)
go func() { _, _ = pipeWriter.Write([]byte("first line\n")) }()
go func() { _ = fn(TaskOpts{Stop: stop, InitialContentLoaded: noop}) }()
// Let the task start and read the line it was asked for, so that the requests
// below are handed to a task that is waiting for them.
time.Sleep(50 * time.Millisecond)
answered := atomic.Int32{}
manager.ReadToEnd(func() { answered.Add(1) })
manager.ReadToEnd(func() { answered.Add(1) })
// Let the first request be picked up and block on the pipe, then stop the task.
time.Sleep(50 * time.Millisecond)
close(stop)
time.Sleep(50 * time.Millisecond)
/* EXPECTED:
assert.EqualValues(t, 2, answered.Load())
ACTUAL: */
assert.EqualValues(t, 1, answered.Load())
}