github.com/DFWallet/tendermint-cosmos@v0.0.2/blockchain/v1/peer_test.go (about) 1 package v1 2 3 import ( 4 "sync" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/DFWallet/tendermint-cosmos/libs/log" 12 tmrand "github.com/DFWallet/tendermint-cosmos/libs/rand" 13 "github.com/DFWallet/tendermint-cosmos/p2p" 14 "github.com/DFWallet/tendermint-cosmos/types" 15 ) 16 17 func TestPeerMonitor(t *testing.T) { 18 peer := NewBpPeer( 19 p2p.ID(tmrand.Str(12)), 0, 10, 20 func(err error, _ p2p.ID) {}, 21 nil) 22 peer.SetLogger(log.TestingLogger()) 23 peer.startMonitor() 24 assert.NotNil(t, peer.recvMonitor) 25 peer.stopMonitor() 26 assert.Nil(t, peer.recvMonitor) 27 } 28 29 func TestPeerResetBlockResponseTimer(t *testing.T) { 30 var ( 31 numErrFuncCalls int // number of calls to the errFunc 32 lastErr error // last generated error 33 peerTestMtx sync.Mutex // modifications of ^^ variables are also done from timer handler goroutine 34 ) 35 params := &BpPeerParams{timeout: 20 * time.Millisecond} 36 37 peer := NewBpPeer( 38 p2p.ID(tmrand.Str(12)), 0, 10, 39 func(err error, _ p2p.ID) { 40 peerTestMtx.Lock() 41 defer peerTestMtx.Unlock() 42 lastErr = err 43 numErrFuncCalls++ 44 }, 45 params) 46 47 peer.SetLogger(log.TestingLogger()) 48 checkByStoppingPeerTimer(t, peer, false) 49 50 // initial reset call with peer having a nil timer 51 peer.resetBlockResponseTimer() 52 assert.NotNil(t, peer.blockResponseTimer) 53 // make sure timer is running and stop it 54 checkByStoppingPeerTimer(t, peer, true) 55 56 // reset with running timer 57 peer.resetBlockResponseTimer() 58 time.Sleep(5 * time.Millisecond) 59 peer.resetBlockResponseTimer() 60 assert.NotNil(t, peer.blockResponseTimer) 61 62 // let the timer expire and ... 63 time.Sleep(50 * time.Millisecond) 64 // ... check timer is not running 65 checkByStoppingPeerTimer(t, peer, false) 66 67 peerTestMtx.Lock() 68 // ... check errNoPeerResponse has been sent 69 assert.Equal(t, 1, numErrFuncCalls) 70 assert.Equal(t, lastErr, errNoPeerResponse) 71 peerTestMtx.Unlock() 72 } 73 74 func TestPeerRequestSent(t *testing.T) { 75 params := &BpPeerParams{timeout: 2 * time.Millisecond} 76 77 peer := NewBpPeer( 78 p2p.ID(tmrand.Str(12)), 0, 10, 79 func(err error, _ p2p.ID) {}, 80 params) 81 82 peer.SetLogger(log.TestingLogger()) 83 84 peer.RequestSent(1) 85 assert.NotNil(t, peer.recvMonitor) 86 assert.NotNil(t, peer.blockResponseTimer) 87 assert.Equal(t, 1, peer.NumPendingBlockRequests) 88 89 peer.RequestSent(1) 90 assert.NotNil(t, peer.recvMonitor) 91 assert.NotNil(t, peer.blockResponseTimer) 92 assert.Equal(t, 2, peer.NumPendingBlockRequests) 93 } 94 95 func TestPeerGetAndRemoveBlock(t *testing.T) { 96 peer := NewBpPeer( 97 p2p.ID(tmrand.Str(12)), 0, 100, 98 func(err error, _ p2p.ID) {}, 99 nil) 100 101 // Change peer height 102 peer.Height = int64(10) 103 assert.Equal(t, int64(10), peer.Height) 104 105 // request some blocks and receive few of them 106 for i := 1; i <= 10; i++ { 107 peer.RequestSent(int64(i)) 108 if i > 5 { 109 // only receive blocks 1..5 110 continue 111 } 112 _ = peer.AddBlock(makeSmallBlock(i), 10) 113 } 114 115 tests := []struct { 116 name string 117 height int64 118 wantErr error 119 blockPresent bool 120 }{ 121 {"no request", 100, errMissingBlock, false}, 122 {"no block", 6, errMissingBlock, false}, 123 {"block 1 present", 1, nil, true}, 124 {"block max present", 5, nil, true}, 125 } 126 127 for _, tt := range tests { 128 tt := tt 129 t.Run(tt.name, func(t *testing.T) { 130 // try to get the block 131 b, err := peer.BlockAtHeight(tt.height) 132 assert.Equal(t, tt.wantErr, err) 133 assert.Equal(t, tt.blockPresent, b != nil) 134 135 // remove the block 136 peer.RemoveBlock(tt.height) 137 _, err = peer.BlockAtHeight(tt.height) 138 assert.Equal(t, errMissingBlock, err) 139 }) 140 } 141 } 142 143 func TestPeerAddBlock(t *testing.T) { 144 peer := NewBpPeer( 145 p2p.ID(tmrand.Str(12)), 0, 100, 146 func(err error, _ p2p.ID) {}, 147 nil) 148 149 // request some blocks, receive one 150 for i := 1; i <= 10; i++ { 151 peer.RequestSent(int64(i)) 152 if i == 5 { 153 // receive block 5 154 _ = peer.AddBlock(makeSmallBlock(i), 10) 155 } 156 } 157 158 tests := []struct { 159 name string 160 height int64 161 wantErr error 162 blockPresent bool 163 }{ 164 {"no request", 50, errMissingBlock, false}, 165 {"duplicate block", 5, errDuplicateBlock, true}, 166 {"block 1 successfully received", 1, nil, true}, 167 {"block max successfully received", 10, nil, true}, 168 } 169 170 for _, tt := range tests { 171 tt := tt 172 t.Run(tt.name, func(t *testing.T) { 173 // try to get the block 174 err := peer.AddBlock(makeSmallBlock(int(tt.height)), 10) 175 assert.Equal(t, tt.wantErr, err) 176 _, err = peer.BlockAtHeight(tt.height) 177 assert.Equal(t, tt.blockPresent, err == nil) 178 }) 179 } 180 } 181 182 func TestPeerOnErrFuncCalledDueToExpiration(t *testing.T) { 183 184 params := &BpPeerParams{timeout: 10 * time.Millisecond} 185 var ( 186 numErrFuncCalls int // number of calls to the onErr function 187 lastErr error // last generated error 188 peerTestMtx sync.Mutex // modifications of ^^ variables are also done from timer handler goroutine 189 ) 190 191 peer := NewBpPeer( 192 p2p.ID(tmrand.Str(12)), 0, 10, 193 func(err error, _ p2p.ID) { 194 peerTestMtx.Lock() 195 defer peerTestMtx.Unlock() 196 lastErr = err 197 numErrFuncCalls++ 198 }, 199 params) 200 201 peer.SetLogger(log.TestingLogger()) 202 203 peer.RequestSent(1) 204 time.Sleep(50 * time.Millisecond) 205 // timer should have expired by now, check that the on error function was called 206 peerTestMtx.Lock() 207 assert.Equal(t, 1, numErrFuncCalls) 208 assert.Equal(t, errNoPeerResponse, lastErr) 209 peerTestMtx.Unlock() 210 } 211 212 func TestPeerCheckRate(t *testing.T) { 213 params := &BpPeerParams{ 214 timeout: time.Second, 215 minRecvRate: int64(100), // 100 bytes/sec exponential moving average 216 } 217 peer := NewBpPeer( 218 p2p.ID(tmrand.Str(12)), 0, 10, 219 func(err error, _ p2p.ID) {}, 220 params) 221 peer.SetLogger(log.TestingLogger()) 222 223 require.Nil(t, peer.CheckRate()) 224 225 for i := 0; i < 40; i++ { 226 peer.RequestSent(int64(i)) 227 } 228 229 // monitor starts with a higher rEMA (~ 2*minRecvRate), wait for it to go down 230 time.Sleep(900 * time.Millisecond) 231 232 // normal peer - send a bit more than 100 bytes/sec, > 10 bytes/100msec, check peer is not considered slow 233 for i := 0; i < 10; i++ { 234 _ = peer.AddBlock(makeSmallBlock(i), 11) 235 time.Sleep(100 * time.Millisecond) 236 require.Nil(t, peer.CheckRate()) 237 } 238 239 // slow peer - send a bit less than 10 bytes/100msec 240 for i := 10; i < 20; i++ { 241 _ = peer.AddBlock(makeSmallBlock(i), 9) 242 time.Sleep(100 * time.Millisecond) 243 } 244 // check peer is considered slow 245 assert.Equal(t, errSlowPeer, peer.CheckRate()) 246 } 247 248 func TestPeerCleanup(t *testing.T) { 249 params := &BpPeerParams{timeout: 2 * time.Millisecond} 250 251 peer := NewBpPeer( 252 p2p.ID(tmrand.Str(12)), 0, 10, 253 func(err error, _ p2p.ID) {}, 254 params) 255 peer.SetLogger(log.TestingLogger()) 256 257 assert.Nil(t, peer.blockResponseTimer) 258 peer.RequestSent(1) 259 assert.NotNil(t, peer.blockResponseTimer) 260 261 peer.Cleanup() 262 checkByStoppingPeerTimer(t, peer, false) 263 } 264 265 // Check if peer timer is running or not (a running timer can be successfully stopped). 266 // Note: stops the timer. 267 func checkByStoppingPeerTimer(t *testing.T, peer *BpPeer, running bool) { 268 assert.NotPanics(t, func() { 269 stopped := peer.stopBlockResponseTimer() 270 if running { 271 assert.True(t, stopped) 272 } else { 273 assert.False(t, stopped) 274 } 275 }) 276 } 277 278 func makeSmallBlock(height int) *types.Block { 279 return types.MakeBlock(int64(height), []types.Tx{types.Tx("foo")}, nil, nil) 280 }