lib/protocol: Test for Close on blocking send deadlock (ref #5442) (#5732)

This commit is contained in:
Simon Frei 2019-05-23 22:42:02 +02:00 committed by Audrius Butkevicius
parent 224775ca81
commit 5d35b2c540
1 changed files with 50 additions and 3 deletions

View File

@ -11,11 +11,13 @@ import (
"io"
"io/ioutil"
"runtime"
"strings"
"sync"
"testing"
"testing/quick"
"time"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/testutils"
)
var (
@ -43,6 +45,8 @@ func TestPing(t *testing.T) {
}
}
var errManual = errors.New("manual close")
func TestClose(t *testing.T) {
m0 := newTestModel()
m1 := newTestModel()
@ -57,10 +61,10 @@ func TestClose(t *testing.T) {
c0.ClusterConfig(ClusterConfig{})
c1.ClusterConfig(ClusterConfig{})
c0.internalClose(errors.New("manual close"))
c0.internalClose(errManual)
<-c0.closed
if err := m0.closedError(); err == nil || !strings.Contains(err.Error(), "manual close") {
if err := m0.closedError(); err != errManual {
t.Fatal("Connection should be closed")
}
@ -78,6 +82,49 @@ func TestClose(t *testing.T) {
}
}
// TestCloseOnBlockingSend checks that the connection does not deadlock when
// Close is called while the underlying connection is broken (send blocks).
// https://github.com/syncthing/syncthing/pull/5442
func TestCloseOnBlockingSend(t *testing.T) {
m := newTestModel()
c := NewConnection(c0ID, &testutils.BlockingRW{}, &testutils.BlockingRW{}, m, "name", CompressAlways).(wireFormatConnection).Connection.(*rawConnection)
c.Start()
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
c.ClusterConfig(ClusterConfig{})
wg.Done()
}()
wg.Add(1)
go func() {
c.Close(errManual)
wg.Done()
}()
// This simulates an error from ping timeout
wg.Add(1)
go func() {
c.internalClose(ErrTimeout)
wg.Done()
}()
done := make(chan struct{})
go func() {
wg.Wait()
close(done)
}()
select {
case <-done:
case <-time.After(time.Second):
t.Fatal("timed out before all functions returned")
}
}
func TestMarshalIndexMessage(t *testing.T) {
if testing.Short() {
quickCfg.MaxCount = 10