diff --git a/pkg/ioutils/bytespipe_test.go b/pkg/ioutils/bytespipe_test.go index 74644e4a95..8b2c4444d3 100644 --- a/pkg/ioutils/bytespipe_test.go +++ b/pkg/ioutils/bytespipe_test.go @@ -60,6 +60,65 @@ func TestBytesPipeWrite(t *testing.T) { } } +// Regression test for #41941. +func TestBytesPipeDeadlock(t *testing.T) { + bp := NewBytesPipe() + bp.buf = []*fixedBuffer{getBuffer(blockThreshold)} + + rd := make(chan error) + go func() { + n, err := bp.Read(make([]byte, 1)) + t.Logf("Read n=%d, err=%v", n, err) + if n != 1 { + t.Errorf("short read: got %d, want 1", n) + } + rd <- err + }() + + wr := make(chan error) + go func() { + const writeLen int = blockThreshold + 1 + time.Sleep(time.Millisecond) + n, err := bp.Write(make([]byte, writeLen)) + t.Logf("Write n=%d, err=%v", n, err) + if n != writeLen { + t.Errorf("short write: got %d, want %d", n, writeLen) + } + wr <- err + }() + + timer := time.NewTimer(time.Second) + defer timer.Stop() + select { + case <-timer.C: + t.Fatal("deadlock! Neither Read() nor Write() returned.") + case rerr := <-rd: + if rerr != nil { + t.Fatal(rerr) + } + select { + case <-timer.C: + t.Fatal("deadlock! Write() did not return.") + case werr := <-wr: + if werr != nil { + t.Fatal(werr) + } + } + case werr := <-wr: + if werr != nil { + t.Fatal(werr) + } + select { + case <-timer.C: + t.Fatal("deadlock! Read() did not return.") + case rerr := <-rd: + if rerr != nil { + t.Fatal(rerr) + } + } + } +} + // Write and read in different speeds/chunk sizes and check valid data is read. func TestBytesPipeWriteRandomChunks(t *testing.T) { cases := []struct{ iterations, writesPerLoop, readsPerLoop int }{