mirror of
https://github.com/octoleo/syncthing.git
synced 2024-09-11 01:19:00 +00:00
lib/model, lib/testutils: Test closing a connection on folder restart (#5707)
This commit is contained in:
parent
5ffbb7668d
commit
1b2b970f32
@ -13,6 +13,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/connections"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/scanner"
|
||||
)
|
||||
@ -23,6 +24,7 @@ type downloadProgressMessage struct {
|
||||
}
|
||||
|
||||
type fakeConnection struct {
|
||||
fakeUnderlyingConn
|
||||
id protocol.DeviceID
|
||||
downloadProgressMessages []downloadProgressMessage
|
||||
closed bool
|
||||
@ -58,10 +60,6 @@ func (f *fakeConnection) Name() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (f *fakeConnection) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (f *fakeConnection) Option(string) string {
|
||||
return ""
|
||||
}
|
||||
@ -111,26 +109,6 @@ func (f *fakeConnection) Statistics() protocol.Statistics {
|
||||
return protocol.Statistics{}
|
||||
}
|
||||
|
||||
func (f *fakeConnection) RemoteAddr() net.Addr {
|
||||
return &fakeAddr{}
|
||||
}
|
||||
|
||||
func (f *fakeConnection) Type() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (f *fakeConnection) Crypto() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (f *fakeConnection) Transport() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (f *fakeConnection) Priority() int {
|
||||
return 9000
|
||||
}
|
||||
|
||||
func (f *fakeConnection) DownloadProgress(folder string, updates []protocol.FileDownloadProgressUpdate) {
|
||||
f.downloadProgressMessages = append(f.downloadProgressMessages, downloadProgressMessage{
|
||||
folder: folder,
|
||||
@ -235,6 +213,43 @@ func addFakeConn(m *model, dev protocol.DeviceID) *fakeConnection {
|
||||
return fc
|
||||
}
|
||||
|
||||
type fakeProtoConn struct {
|
||||
protocol.Connection
|
||||
fakeUnderlyingConn
|
||||
}
|
||||
|
||||
func newFakeProtoConn(protoConn protocol.Connection) connections.Connection {
|
||||
return &fakeProtoConn{Connection: protoConn}
|
||||
}
|
||||
|
||||
// fakeUnderlyingConn implements the methods of connections.Connection that are
|
||||
// not implemented by protocol.Connection
|
||||
type fakeUnderlyingConn struct{}
|
||||
|
||||
func (f *fakeUnderlyingConn) RemoteAddr() net.Addr {
|
||||
return &fakeAddr{}
|
||||
}
|
||||
|
||||
func (f *fakeUnderlyingConn) Type() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (f *fakeUnderlyingConn) Crypto() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (f *fakeUnderlyingConn) Transport() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (f *fakeUnderlyingConn) Priority() int {
|
||||
return 9000
|
||||
}
|
||||
|
||||
func (f *fakeUnderlyingConn) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type fakeAddr struct{}
|
||||
|
||||
func (fakeAddr) Network() string {
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
srand "github.com/syncthing/syncthing/lib/rand"
|
||||
"github.com/syncthing/syncthing/lib/testutils"
|
||||
"github.com/syncthing/syncthing/lib/versioner"
|
||||
)
|
||||
|
||||
@ -3381,3 +3382,38 @@ func TestSanitizePath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestConnCloseOnRestart checks that there is no deadlock when calling Close
|
||||
// on a protocol connection that has a blocking reader (blocking writer can't
|
||||
// be done as the test requires clusterconfigs to go through).
|
||||
func TestConnCloseOnRestart(t *testing.T) {
|
||||
w, fcfg := tmpDefaultWrapper()
|
||||
m := setupModel(w)
|
||||
defer func() {
|
||||
m.Stop()
|
||||
m.db.Close()
|
||||
os.RemoveAll(fcfg.Filesystem().URI())
|
||||
os.Remove(w.ConfigPath())
|
||||
}()
|
||||
|
||||
br := &testutils.BlockingRW{}
|
||||
nw := &testutils.NoopRW{}
|
||||
m.AddConnection(newFakeProtoConn(protocol.NewConnection(device1, br, nw, m, "testConn", protocol.CompressNever)), protocol.HelloResult{})
|
||||
|
||||
newFcfg := fcfg.Copy()
|
||||
newFcfg.Paused = true
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
m.RestartFolder(fcfg, newFcfg)
|
||||
close(done)
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("Timed out before folder restart returned")
|
||||
}
|
||||
m.pmut.RLock()
|
||||
if len(m.conn) != 0 {
|
||||
t.Errorf("Conn wasn't removed on restart (len(m.conn) == %v)", len(m.conn))
|
||||
}
|
||||
}
|
||||
|
31
lib/testutils/testutils.go
Normal file
31
lib/testutils/testutils.go
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2019 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package testutils
|
||||
|
||||
// BlockingRW implements io.Reader and Writer but never returns when called
|
||||
type BlockingRW struct{ nilChan chan struct{} }
|
||||
|
||||
func (rw *BlockingRW) Read(p []byte) (n int, err error) {
|
||||
<-rw.nilChan
|
||||
return
|
||||
}
|
||||
|
||||
func (rw *BlockingRW) Write(p []byte) (n int, err error) {
|
||||
<-rw.nilChan
|
||||
return
|
||||
}
|
||||
|
||||
// NoopRW implements io.Reader and Writer but never returns when called
|
||||
type NoopRW struct{}
|
||||
|
||||
func (rw *NoopRW) Read(p []byte) (n int, err error) {
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (rw *NoopRW) Write(p []byte) (n int, err error) {
|
||||
return len(p), nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user