elvish/edit/async_reader_test.go

110 lines
1.9 KiB
Go

package edit
import (
"fmt"
"math/rand"
"os"
"testing"
"time"
"github.com/elves/elvish/sys"
)
// Pretty arbitrary numbers. May not reveal deadlocks on all machines.
var (
DeadlockNWrite = 1024
DeadlockRun = 64
DeadlockTimeout = 500 * time.Millisecond
DeadlockMaxJitter = time.Millisecond
)
func jitter() {
time.Sleep(time.Duration(float64(DeadlockMaxJitter) * rand.Float64()))
}
func f(done chan struct{}) {
r, w, err := os.Pipe()
if err != nil {
panic(err)
}
defer r.Close()
defer w.Close()
ar := NewAsyncReader(r)
defer ar.Close()
fmt.Fprintf(w, "%*s", DeadlockNWrite, "")
go func() {
jitter()
ar.Run()
}()
jitter()
ar.Quit()
done <- struct{}{}
}
func TestAsyncReaderDeadlock(t *testing.T) {
done := make(chan struct{})
isatty := sys.IsATTY(1)
rand.Seed(time.Now().UTC().UnixNano())
timer := time.NewTimer(DeadlockTimeout)
for i := 0; i < DeadlockRun; i++ {
if isatty {
fmt.Printf("\r%d/%d ", i+1, DeadlockRun)
}
go f(done)
select {
case <-done:
// no deadlock trigerred
case <-timer.C:
// deadlock
t.Errorf("%s", sys.DumpStack())
t.Fatalf("AsyncReader deadlock trigerred on run %d/%d, stack trace:\n%s", i, DeadlockRun, sys.DumpStack())
}
timer.Reset(DeadlockTimeout)
}
if isatty {
fmt.Print("\r \r")
}
}
var ReadTimeout = time.Second
func TestAsyncReader(t *testing.T) {
r, w, err := os.Pipe()
if err != nil {
panic(err)
}
defer r.Close()
defer w.Close()
ar := NewAsyncReader(r)
defer ar.Close()
go ar.Run()
go func() {
var i rune
for i = 0; i <= 1280; i += 10 {
w.WriteString(string(i))
}
}()
var i rune
timer := time.NewTimer(ReadTimeout)
for i = 0; i <= 1280; i += 10 {
select {
case r := <-ar.Chan():
if r != i {
t.Fatalf("expect %q, got %q\n", i, r)
}
case <-timer.C:
t.Fatalf("read timeout (i = %d)", i)
}
timer.Reset(ReadTimeout)
}
ar.Quit()
}