2019-04-13 09:23:43 -04:00
|
|
|
package blockchain
|
2019-03-26 09:58:30 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
cmn "github.com/tendermint/tendermint/libs/common"
|
|
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
|
|
"github.com/tendermint/tendermint/p2p"
|
|
|
|
)
|
|
|
|
|
|
|
|
// check if peer timer is running or not (a running timer can be successfully stopped)
|
|
|
|
// Note: it does stop the timer!
|
|
|
|
func checkByStoppingPeerTimer(t *testing.T, peer *bpPeer, running bool) {
|
|
|
|
assert.NotPanics(t, func() {
|
2019-06-02 19:03:51 +02:00
|
|
|
stopped := peer.StopBlockResponseTimer()
|
2019-03-26 09:58:30 +01:00
|
|
|
if running {
|
|
|
|
assert.True(t, stopped)
|
|
|
|
} else {
|
|
|
|
assert.False(t, stopped)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPeerResetMonitor(t *testing.T) {
|
2019-06-02 19:03:51 +02:00
|
|
|
peer := NewBPPeer(
|
|
|
|
p2p.ID(cmn.RandStr(12)), 10,
|
|
|
|
func(err error, _ p2p.ID) {},
|
|
|
|
nil)
|
|
|
|
peer.SetLogger(log.TestingLogger())
|
2019-03-26 09:58:30 +01:00
|
|
|
peer.resetMonitor()
|
|
|
|
assert.NotNil(t, peer.recvMonitor)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPeerTimer(t *testing.T) {
|
2019-06-02 19:03:51 +02:00
|
|
|
var (
|
|
|
|
numErrFuncCalls int // number of calls to the errFunc
|
|
|
|
lastErr error // last generated error
|
|
|
|
peerTestMtx sync.Mutex // modifications of ^^ variables are also done from timer handler goroutine
|
|
|
|
)
|
|
|
|
params := &bpPeerParams{peerTimeout: 2 * time.Millisecond}
|
|
|
|
|
|
|
|
peer := NewBPPeer(
|
|
|
|
p2p.ID(cmn.RandStr(12)), 10,
|
|
|
|
func(err error, _ p2p.ID) {
|
|
|
|
peerTestMtx.Lock()
|
|
|
|
defer peerTestMtx.Unlock()
|
|
|
|
lastErr = err
|
|
|
|
numErrFuncCalls++
|
|
|
|
},
|
|
|
|
params)
|
|
|
|
|
|
|
|
peer.SetLogger(log.TestingLogger())
|
|
|
|
assert.Nil(t, peer.blockResponseTimer)
|
2019-03-26 09:58:30 +01:00
|
|
|
|
|
|
|
// initial reset call with peer having a nil timer
|
|
|
|
peer.resetTimeout()
|
2019-06-02 19:03:51 +02:00
|
|
|
assert.NotNil(t, peer.blockResponseTimer)
|
2019-03-26 09:58:30 +01:00
|
|
|
// make sure timer is running and stop it
|
|
|
|
checkByStoppingPeerTimer(t, peer, true)
|
|
|
|
|
|
|
|
// reset with non nil expired timer
|
|
|
|
peer.resetTimeout()
|
2019-06-02 19:03:51 +02:00
|
|
|
assert.NotNil(t, peer.blockResponseTimer)
|
2019-03-26 09:58:30 +01:00
|
|
|
// make sure timer is running and stop it
|
|
|
|
checkByStoppingPeerTimer(t, peer, true)
|
|
|
|
|
|
|
|
// reset with running timer (started above)
|
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
peer.resetTimeout()
|
2019-06-02 19:03:51 +02:00
|
|
|
assert.NotNil(t, peer.blockResponseTimer)
|
2019-03-26 09:58:30 +01:00
|
|
|
|
|
|
|
// let the timer expire and ...
|
|
|
|
time.Sleep(3 * time.Millisecond)
|
|
|
|
checkByStoppingPeerTimer(t, peer, false)
|
|
|
|
|
2019-04-14 22:53:24 -04:00
|
|
|
peerTestMtx.Lock()
|
2019-03-26 09:58:30 +01:00
|
|
|
// ... check an error has been sent, error is peerNonResponsive
|
|
|
|
assert.Equal(t, 1, numErrFuncCalls)
|
|
|
|
assert.Equal(t, lastErr, errNoPeerResponse)
|
2019-04-14 22:53:24 -04:00
|
|
|
peerTestMtx.Unlock()
|
2019-03-26 09:58:30 +01:00
|
|
|
}
|
|
|
|
|
2019-04-14 22:53:24 -04:00
|
|
|
func TestPeerIncrPending(t *testing.T) {
|
2019-06-02 19:03:51 +02:00
|
|
|
params := &bpPeerParams{peerTimeout: 2 * time.Millisecond}
|
2019-03-26 09:58:30 +01:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
peer := NewBPPeer(
|
|
|
|
p2p.ID(cmn.RandStr(12)), 10,
|
|
|
|
func(err error, _ p2p.ID) {},
|
|
|
|
params)
|
2019-03-26 09:58:30 +01:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
peer.SetLogger(log.TestingLogger())
|
2019-03-26 09:58:30 +01:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
peer.IncrPending()
|
2019-03-26 09:58:30 +01:00
|
|
|
assert.NotNil(t, peer.recvMonitor)
|
2019-06-02 19:03:51 +02:00
|
|
|
assert.NotNil(t, peer.blockResponseTimer)
|
|
|
|
assert.Equal(t, int32(1), peer.GetNumPendingBlockRequests())
|
2019-04-12 22:02:30 -04:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
peer.IncrPending()
|
|
|
|
assert.NotNil(t, peer.recvMonitor)
|
|
|
|
assert.NotNil(t, peer.blockResponseTimer)
|
|
|
|
assert.Equal(t, int32(2), peer.GetNumPendingBlockRequests())
|
2019-03-26 09:58:30 +01:00
|
|
|
}
|
|
|
|
|
2019-04-14 22:53:24 -04:00
|
|
|
func TestPeerDecrPending(t *testing.T) {
|
2019-06-02 19:03:51 +02:00
|
|
|
params := &bpPeerParams{peerTimeout: 2 * time.Millisecond}
|
|
|
|
|
|
|
|
peer := NewBPPeer(
|
|
|
|
p2p.ID(cmn.RandStr(12)), 10,
|
|
|
|
func(err error, _ p2p.ID) {},
|
|
|
|
params)
|
2019-03-26 09:58:30 +01:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
peer.SetLogger(log.TestingLogger())
|
2019-03-26 09:58:30 +01:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
// panic if numPendingBlockRequests is 0 and try to decrement it
|
|
|
|
assert.Panics(t, func() { peer.DecrPending(10) })
|
2019-03-26 09:58:30 +01:00
|
|
|
|
|
|
|
// decrement to zero
|
2019-06-02 19:03:51 +02:00
|
|
|
peer.IncrPending()
|
|
|
|
peer.DecrPending(10)
|
|
|
|
assert.Equal(t, int32(0), peer.GetNumPendingBlockRequests())
|
2019-03-26 09:58:30 +01:00
|
|
|
// make sure timer is not running
|
|
|
|
checkByStoppingPeerTimer(t, peer, false)
|
|
|
|
|
|
|
|
// decrement to non zero
|
2019-06-02 19:03:51 +02:00
|
|
|
peer.IncrPending()
|
|
|
|
peer.IncrPending()
|
|
|
|
peer.DecrPending(10)
|
|
|
|
assert.Equal(t, int32(1), peer.GetNumPendingBlockRequests())
|
2019-03-26 09:58:30 +01:00
|
|
|
// make sure timer is running and stop it
|
|
|
|
checkByStoppingPeerTimer(t, peer, true)
|
|
|
|
}
|
|
|
|
|
2019-04-14 22:53:24 -04:00
|
|
|
func TestPeerCanBeRemovedDueToExpiration(t *testing.T) {
|
2019-03-26 09:58:30 +01:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
params := &bpPeerParams{peerTimeout: 2 * time.Millisecond}
|
|
|
|
var (
|
|
|
|
numErrFuncCalls int // number of calls to the errFunc
|
|
|
|
lastErr error // last generated error
|
|
|
|
peerTestMtx sync.Mutex // modifications of ^^ variables are also done from timer handler goroutine
|
|
|
|
)
|
|
|
|
|
|
|
|
peer := NewBPPeer(
|
|
|
|
p2p.ID(cmn.RandStr(12)), 10,
|
|
|
|
func(err error, _ p2p.ID) {
|
|
|
|
peerTestMtx.Lock()
|
|
|
|
defer peerTestMtx.Unlock()
|
|
|
|
lastErr = err
|
|
|
|
numErrFuncCalls++
|
|
|
|
},
|
|
|
|
params)
|
|
|
|
|
|
|
|
peer.SetLogger(log.TestingLogger())
|
|
|
|
|
|
|
|
peer.IncrPending()
|
|
|
|
time.Sleep(3 * time.Millisecond)
|
2019-03-26 09:58:30 +01:00
|
|
|
// timer expired, should be able to remove peer
|
2019-04-14 22:53:24 -04:00
|
|
|
peerTestMtx.Lock()
|
2019-06-02 19:03:51 +02:00
|
|
|
assert.Equal(t, 1, numErrFuncCalls)
|
2019-04-14 22:53:24 -04:00
|
|
|
assert.Equal(t, errNoPeerResponse, lastErr)
|
|
|
|
peerTestMtx.Unlock()
|
2019-03-26 09:58:30 +01:00
|
|
|
}
|
|
|
|
|
2019-04-14 22:53:24 -04:00
|
|
|
func TestPeerCanBeRemovedDueToLowSpeed(t *testing.T) {
|
2019-06-02 19:03:51 +02:00
|
|
|
params := &bpPeerParams{
|
|
|
|
peerTimeout: time.Second,
|
|
|
|
minRecvRate: int64(100), // 100 bytes/sec exponential moving average
|
|
|
|
}
|
|
|
|
peer := NewBPPeer(
|
|
|
|
p2p.ID(cmn.RandStr(12)), 10,
|
|
|
|
func(err error, _ p2p.ID) {},
|
|
|
|
params)
|
|
|
|
peer.SetLogger(log.TestingLogger())
|
2019-03-26 09:58:30 +01:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
peer.IncrPending()
|
|
|
|
peer.numPendingBlockRequests = 100
|
2019-03-26 09:58:30 +01:00
|
|
|
|
|
|
|
// monitor starts with a higher rEMA (~ 2*minRecvRate), wait for it to go down
|
|
|
|
time.Sleep(900 * time.Millisecond)
|
|
|
|
|
2019-05-15 18:33:12 -04:00
|
|
|
// normal peer - send a bit more than 100 bytes/sec, > 10 bytes/100msec, check peer is not considered slow
|
2019-03-26 09:58:30 +01:00
|
|
|
for i := 0; i < 10; i++ {
|
2019-06-02 19:03:51 +02:00
|
|
|
peer.DecrPending(11)
|
2019-03-26 09:58:30 +01:00
|
|
|
time.Sleep(100 * time.Millisecond)
|
2019-06-02 19:03:51 +02:00
|
|
|
require.Nil(t, peer.IsGood())
|
2019-03-26 09:58:30 +01:00
|
|
|
}
|
|
|
|
|
2019-05-15 18:33:12 -04:00
|
|
|
// slow peer - send a bit less than 10 bytes/100msec
|
2019-03-26 09:58:30 +01:00
|
|
|
for i := 0; i < 10; i++ {
|
2019-06-02 19:03:51 +02:00
|
|
|
peer.DecrPending(9)
|
2019-03-26 09:58:30 +01:00
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
}
|
|
|
|
// check peer is considered slow
|
2019-06-02 19:03:51 +02:00
|
|
|
assert.Equal(t, errSlowPeer, peer.IsGood())
|
2019-03-26 09:58:30 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-04-14 22:53:24 -04:00
|
|
|
func TestPeerCleanup(t *testing.T) {
|
2019-06-02 19:03:51 +02:00
|
|
|
params := &bpPeerParams{peerTimeout: 2 * time.Millisecond}
|
2019-05-15 18:33:12 -04:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
peer := NewBPPeer(
|
|
|
|
p2p.ID(cmn.RandStr(12)), 10,
|
|
|
|
func(err error, _ p2p.ID) {},
|
|
|
|
params)
|
|
|
|
peer.SetLogger(log.TestingLogger())
|
2019-05-15 18:33:12 -04:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
assert.Nil(t, peer.blockResponseTimer)
|
2019-03-26 09:58:30 +01:00
|
|
|
|
|
|
|
// initial reset call with peer having a nil timer
|
|
|
|
peer.resetTimeout()
|
2019-06-02 19:03:51 +02:00
|
|
|
assert.NotNil(t, peer.blockResponseTimer)
|
2019-03-26 09:58:30 +01:00
|
|
|
|
2019-06-02 19:03:51 +02:00
|
|
|
peer.Cleanup()
|
2019-03-26 09:58:30 +01:00
|
|
|
checkByStoppingPeerTimer(t, peer, false)
|
|
|
|
}
|