mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 06:42:16 +00:00
* close peer's connection to avoid fd leak Fixes #2967 * rename peer#Addr to RemoteAddr * fix test * fixes after Ethan's review * bring back the check * changelog entry * write a test for switch#acceptRoutine * increase timeouts? :( * remove extra assertNPeersWithTimeout * simplify test * assert number of peers (just to be safe) * Cleanup in OnStop * run tests with verbose flag on CircleCI * spawn a reading routine to prevent connection from closing * get port from the listener random port is faster, but often results in ``` panic: listen tcp 127.0.0.1:44068: bind: address already in use [recovered] panic: listen tcp 127.0.0.1:44068: bind: address already in use goroutine 79 [running]: testing.tRunner.func1(0xc0001bd600) /usr/local/go/src/testing/testing.go:792 +0x387 panic(0x974d20, 0xc0001b0500) /usr/local/go/src/runtime/panic.go:513 +0x1b9 github.com/tendermint/tendermint/p2p.MakeSwitch(0xc0000f42a0, 0x0, 0x9fb9cc, 0x9, 0x9fc346, 0xb, 0xb42128, 0x0, 0x0, 0x0, ...) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:182 +0xa28 github.com/tendermint/tendermint/p2p.MakeConnectedSwitches(0xc0000f42a0, 0x2, 0xb42128, 0xb41eb8, 0x4f1205, 0xc0001bed80, 0x4f16ed) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:75 +0xf9 github.com/tendermint/tendermint/p2p.MakeSwitchPair(0xbb8d20, 0xc0001bd600, 0xb42128, 0x2f7, 0x4f16c0) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:94 +0x4c github.com/tendermint/tendermint/p2p.TestSwitches(0xc0001bd600) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:117 +0x58 testing.tRunner(0xc0001bd600, 0xb42038) /usr/local/go/src/testing/testing.go:827 +0xbf created by testing.(*T).Run /usr/local/go/src/testing/testing.go:878 +0x353 exit status 2 FAIL github.com/tendermint/tendermint/p2p 0.350s ```
191 lines
5.3 KiB
Go
191 lines
5.3 KiB
Go
package p2p
|
|
|
|
import (
|
|
"net"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
|
cmn "github.com/tendermint/tendermint/libs/common"
|
|
)
|
|
|
|
// mockPeer for testing the PeerSet
|
|
type mockPeer struct {
|
|
cmn.BaseService
|
|
ip net.IP
|
|
id ID
|
|
}
|
|
|
|
func (mp *mockPeer) FlushStop() { mp.Stop() }
|
|
func (mp *mockPeer) TrySend(chID byte, msgBytes []byte) bool { return true }
|
|
func (mp *mockPeer) Send(chID byte, msgBytes []byte) bool { return true }
|
|
func (mp *mockPeer) NodeInfo() NodeInfo { return DefaultNodeInfo{} }
|
|
func (mp *mockPeer) Status() ConnectionStatus { return ConnectionStatus{} }
|
|
func (mp *mockPeer) ID() ID { return mp.id }
|
|
func (mp *mockPeer) IsOutbound() bool { return false }
|
|
func (mp *mockPeer) IsPersistent() bool { return true }
|
|
func (mp *mockPeer) Get(s string) interface{} { return s }
|
|
func (mp *mockPeer) Set(string, interface{}) {}
|
|
func (mp *mockPeer) RemoteIP() net.IP { return mp.ip }
|
|
func (mp *mockPeer) OriginalAddr() *NetAddress { return nil }
|
|
func (mp *mockPeer) RemoteAddr() net.Addr { return &net.TCPAddr{IP: mp.ip, Port: 8800} }
|
|
func (mp *mockPeer) CloseConn() error { return nil }
|
|
|
|
// Returns a mock peer
|
|
func newMockPeer(ip net.IP) *mockPeer {
|
|
if ip == nil {
|
|
ip = net.IP{127, 0, 0, 1}
|
|
}
|
|
nodeKey := NodeKey{PrivKey: ed25519.GenPrivKey()}
|
|
return &mockPeer{
|
|
ip: ip,
|
|
id: nodeKey.ID(),
|
|
}
|
|
}
|
|
|
|
func TestPeerSetAddRemoveOne(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
peerSet := NewPeerSet()
|
|
|
|
var peerList []Peer
|
|
for i := 0; i < 5; i++ {
|
|
p := newMockPeer(net.IP{127, 0, 0, byte(i)})
|
|
if err := peerSet.Add(p); err != nil {
|
|
t.Error(err)
|
|
}
|
|
peerList = append(peerList, p)
|
|
}
|
|
|
|
n := len(peerList)
|
|
// 1. Test removing from the front
|
|
for i, peerAtFront := range peerList {
|
|
removed := peerSet.Remove(peerAtFront)
|
|
assert.True(t, removed)
|
|
wantSize := n - i - 1
|
|
for j := 0; j < 2; j++ {
|
|
assert.Equal(t, false, peerSet.Has(peerAtFront.ID()), "#%d Run #%d: failed to remove peer", i, j)
|
|
assert.Equal(t, wantSize, peerSet.Size(), "#%d Run #%d: failed to remove peer and decrement size", i, j)
|
|
// Test the route of removing the now non-existent element
|
|
removed := peerSet.Remove(peerAtFront)
|
|
assert.False(t, removed)
|
|
}
|
|
}
|
|
|
|
// 2. Next we are testing removing the peer at the end
|
|
// a) Replenish the peerSet
|
|
for _, peer := range peerList {
|
|
if err := peerSet.Add(peer); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// b) In reverse, remove each element
|
|
for i := n - 1; i >= 0; i-- {
|
|
peerAtEnd := peerList[i]
|
|
removed := peerSet.Remove(peerAtEnd)
|
|
assert.True(t, removed)
|
|
assert.Equal(t, false, peerSet.Has(peerAtEnd.ID()), "#%d: failed to remove item at end", i)
|
|
assert.Equal(t, i, peerSet.Size(), "#%d: differing sizes after peerSet.Remove(atEndPeer)", i)
|
|
}
|
|
}
|
|
|
|
func TestPeerSetAddRemoveMany(t *testing.T) {
|
|
t.Parallel()
|
|
peerSet := NewPeerSet()
|
|
|
|
peers := []Peer{}
|
|
N := 100
|
|
for i := 0; i < N; i++ {
|
|
peer := newMockPeer(net.IP{127, 0, 0, byte(i)})
|
|
if err := peerSet.Add(peer); err != nil {
|
|
t.Errorf("Failed to add new peer")
|
|
}
|
|
if peerSet.Size() != i+1 {
|
|
t.Errorf("Failed to add new peer and increment size")
|
|
}
|
|
peers = append(peers, peer)
|
|
}
|
|
|
|
for i, peer := range peers {
|
|
removed := peerSet.Remove(peer)
|
|
assert.True(t, removed)
|
|
if peerSet.Has(peer.ID()) {
|
|
t.Errorf("Failed to remove peer")
|
|
}
|
|
if peerSet.Size() != len(peers)-i-1 {
|
|
t.Errorf("Failed to remove peer and decrement size")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPeerSetAddDuplicate(t *testing.T) {
|
|
t.Parallel()
|
|
peerSet := NewPeerSet()
|
|
peer := newMockPeer(nil)
|
|
|
|
n := 20
|
|
errsChan := make(chan error)
|
|
// Add the same asynchronously to test the
|
|
// concurrent guarantees of our APIs, and
|
|
// our expectation in the end is that only
|
|
// one addition succeeded, but the rest are
|
|
// instances of ErrSwitchDuplicatePeer.
|
|
for i := 0; i < n; i++ {
|
|
go func() {
|
|
errsChan <- peerSet.Add(peer)
|
|
}()
|
|
}
|
|
|
|
// Now collect and tally the results
|
|
errsTally := make(map[string]int)
|
|
for i := 0; i < n; i++ {
|
|
err := <-errsChan
|
|
|
|
switch err.(type) {
|
|
case ErrSwitchDuplicatePeerID:
|
|
errsTally["duplicateID"]++
|
|
default:
|
|
errsTally["other"]++
|
|
}
|
|
}
|
|
|
|
// Our next procedure is to ensure that only one addition
|
|
// succeeded and that the rest are each ErrSwitchDuplicatePeer.
|
|
wantErrCount, gotErrCount := n-1, errsTally["duplicateID"]
|
|
assert.Equal(t, wantErrCount, gotErrCount, "invalid ErrSwitchDuplicatePeer count")
|
|
|
|
wantNilErrCount, gotNilErrCount := 1, errsTally["other"]
|
|
assert.Equal(t, wantNilErrCount, gotNilErrCount, "invalid nil errCount")
|
|
}
|
|
|
|
func TestPeerSetGet(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
peerSet = NewPeerSet()
|
|
peer = newMockPeer(nil)
|
|
)
|
|
|
|
assert.Nil(t, peerSet.Get(peer.ID()), "expecting a nil lookup, before .Add")
|
|
|
|
if err := peerSet.Add(peer); err != nil {
|
|
t.Fatalf("Failed to add new peer: %v", err)
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < 10; i++ {
|
|
// Add them asynchronously to test the
|
|
// concurrent guarantees of our APIs.
|
|
wg.Add(1)
|
|
go func(i int) {
|
|
defer wg.Done()
|
|
have, want := peerSet.Get(peer.ID()), peer
|
|
assert.Equal(t, have, want, "%d: have %v, want %v", i, have, want)
|
|
}(i)
|
|
}
|
|
wg.Wait()
|
|
}
|