You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

160 lines
4.5 KiB

package p2p_test
import (
"errors"
"testing"
"github.com/fortytw2/leaktest"
gogotypes "github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tm-db"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p"
)
type TestMessage = gogotypes.StringValue
func generateNode() (p2p.NodeInfo, crypto.PrivKey) {
privKey := ed25519.GenPrivKey()
nodeID := p2p.NodeIDFromPubKey(privKey.PubKey())
nodeInfo := p2p.NodeInfo{
NodeID: nodeID,
// FIXME: We have to fake a ListenAddr for now.
ListenAddr: "127.0.0.1:1234",
Moniker: "foo",
}
return nodeInfo, privKey
}
func echoReactor(channel *p2p.Channel) {
for {
select {
case envelope := <-channel.In():
channel.Out() <- p2p.Envelope{
To: envelope.From,
Message: &TestMessage{Value: envelope.Message.(*TestMessage).Value},
}
case <-channel.Done():
return
}
}
}
func TestRouter(t *testing.T) {
defer leaktest.Check(t)()
logger := log.TestingLogger()
network := p2p.NewMemoryNetwork(logger)
nodeInfo, privKey := generateNode()
transport := network.CreateTransport(nodeInfo.NodeID)
defer transport.Close()
chID := p2p.ChannelID(1)
// Start some other in-memory network nodes to communicate with, running
// a simple echo reactor that returns received messages.
peers := []p2p.NodeAddress{}
for i := 0; i < 3; i++ {
peerManager, err := p2p.NewPeerManager(dbm.NewMemDB(), p2p.PeerManagerOptions{})
require.NoError(t, err)
peerInfo, peerKey := generateNode()
peerTransport := network.CreateTransport(peerInfo.NodeID)
defer peerTransport.Close()
peerRouter, err := p2p.NewRouter(
logger.With("peerID", i),
peerInfo,
peerKey,
peerManager,
[]p2p.Transport{peerTransport},
p2p.RouterOptions{},
)
require.NoError(t, err)
peers = append(peers, peerTransport.Endpoints()[0].NodeAddress(peerInfo.NodeID))
channel, err := peerRouter.OpenChannel(chID, &TestMessage{})
require.NoError(t, err)
defer channel.Close()
go echoReactor(channel)
err = peerRouter.Start()
require.NoError(t, err)
defer func() { require.NoError(t, peerRouter.Stop()) }()
}
// Start the main router and connect it to the peers above.
peerManager, err := p2p.NewPeerManager(dbm.NewMemDB(), p2p.PeerManagerOptions{})
require.NoError(t, err)
defer peerManager.Close()
for _, address := range peers {
err := peerManager.Add(address)
require.NoError(t, err)
}
peerUpdates := peerManager.Subscribe()
defer peerUpdates.Close()
router, err := p2p.NewRouter(logger, nodeInfo, privKey, peerManager, []p2p.Transport{transport}, p2p.RouterOptions{})
require.NoError(t, err)
channel, err := router.OpenChannel(chID, &TestMessage{})
require.NoError(t, err)
defer channel.Close()
err = router.Start()
require.NoError(t, err)
defer func() {
// Since earlier defers are closed after this, and we have to make sure
// we close channels and subscriptions before the router, we explicitly
// close them here to.
peerUpdates.Close()
channel.Close()
require.NoError(t, router.Stop())
}()
// Wait for peers to come online, and ping them as they do.
for i := 0; i < len(peers); i++ {
peerUpdate := <-peerUpdates.Updates()
peerID := peerUpdate.PeerID
require.Equal(t, p2p.PeerUpdate{
PeerID: peerID,
Status: p2p.PeerStatusUp,
}, peerUpdate)
channel.Out() <- p2p.Envelope{To: peerID, Message: &TestMessage{Value: "hi!"}}
assert.Equal(t, p2p.Envelope{
From: peerID,
Message: &TestMessage{Value: "hi!"},
}, (<-channel.In()).Strip())
}
// We now send a broadcast, which we should return back from all peers.
channel.Out() <- p2p.Envelope{
Broadcast: true,
Message: &TestMessage{Value: "broadcast"},
}
for i := 0; i < len(peers); i++ {
envelope := <-channel.In()
require.Equal(t, &TestMessage{Value: "broadcast"}, envelope.Message)
}
// We then submit an error for a peer, and watch it get disconnected.
channel.Error() <- p2p.PeerError{
PeerID: peers[0].NodeID,
Err: errors.New("test error"),
Severity: p2p.PeerErrorSeverityCritical,
}
peerUpdate := <-peerUpdates.Updates()
require.Equal(t, p2p.PeerUpdate{
PeerID: peers[0].NodeID,
Status: p2p.PeerStatusDown,
}, peerUpdate)
// The peer manager will automatically reconnect the peer, so we wait
// for that to happen.
peerUpdate = <-peerUpdates.Updates()
require.Equal(t, p2p.PeerUpdate{
PeerID: peers[0].NodeID,
Status: p2p.PeerStatusUp,
}, peerUpdate)
}