package p2p
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"io"
|
|
"testing"
|
|
"time"
|
|
|
|
. "github.com/tendermint/tendermint/binary"
|
|
)
|
|
|
|
type String string
|
|
|
|
func (s String) WriteTo(w io.Writer) (n int64, err error) {
|
|
WriteString(w, string(s), &n, &err)
|
|
return
|
|
}
|
|
|
|
// convenience method for creating two switches connected to each other.
|
|
func makeSwitchPair(t testing.TB, numChannels int, sendQueueCapacity int, recvBufferSize int, recvQueueCapacity int) (*Switch, *Switch, []*ChannelDescriptor) {
|
|
|
|
// Make numChannels channels starting at byte(0x00)
|
|
chIds := []byte{}
|
|
for i := 0; i < numChannels; i++ {
|
|
chIds = append(chIds, byte(i))
|
|
}
|
|
|
|
// Make some channel descriptors.
|
|
chDescs := []*ChannelDescriptor{}
|
|
for _, chId := range chIds {
|
|
chDescs = append(chDescs, &ChannelDescriptor{
|
|
Id: chId,
|
|
SendQueueCapacity: sendQueueCapacity,
|
|
RecvBufferSize: recvBufferSize,
|
|
RecvQueueCapacity: recvQueueCapacity,
|
|
DefaultPriority: 1,
|
|
})
|
|
}
|
|
|
|
// Create two switches that will be interconnected.
|
|
s1 := NewSwitch(chDescs)
|
|
s2 := NewSwitch(chDescs)
|
|
|
|
// Create a listener for s1
|
|
l := NewDefaultListener("tcp", ":8001")
|
|
|
|
// Dial the listener & add the connection to s2.
|
|
lAddr := l.ExternalAddress()
|
|
connOut, err := lAddr.Dial()
|
|
if err != nil {
|
|
t.Fatalf("Could not connect to listener address %v", lAddr)
|
|
} else {
|
|
t.Logf("Created a connection to listener address %v", lAddr)
|
|
}
|
|
connIn, ok := <-l.Connections()
|
|
if !ok {
|
|
t.Fatalf("Could not get inbound connection from listener")
|
|
}
|
|
|
|
s1.AddPeerWithConnection(connIn, false)
|
|
s2.AddPeerWithConnection(connOut, true)
|
|
|
|
// Wait for things to happen, peers to get added...
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Close the server, no longer needed.
|
|
l.Stop()
|
|
|
|
return s1, s2, chDescs
|
|
}
|
|
|
|
func TestSwitches(t *testing.T) {
|
|
s1, s2, _ := makeSwitchPair(t, 10, 10, 1024, 10)
|
|
defer s1.Stop()
|
|
defer s2.Stop()
|
|
|
|
// Lets send a message from s1 to s2.
|
|
if s1.Peers().Size() != 1 {
|
|
t.Errorf("Expected exactly 1 peer in s1, got %v", s1.Peers().Size())
|
|
}
|
|
if s2.Peers().Size() != 1 {
|
|
t.Errorf("Expected exactly 1 peer in s2, got %v", s2.Peers().Size())
|
|
}
|
|
|
|
// Broadcast a message on ch0
|
|
s1.Broadcast(byte(0x00), String("channel zero"))
|
|
// Broadcast a message on ch1
|
|
s1.Broadcast(byte(0x01), String("channel one"))
|
|
// Broadcast a message on ch2
|
|
s1.Broadcast(byte(0x02), String("channel two"))
|
|
|
|
// Wait for things to settle...
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Receive message from channel 1 and check
|
|
inMsg, ok := s2.Receive(byte(0x01))
|
|
var n int64
|
|
var err error
|
|
if !ok {
|
|
t.Errorf("Failed to receive from channel one")
|
|
}
|
|
if ReadString(bytes.NewBuffer(inMsg.Bytes), &n, &err) != "channel one" {
|
|
t.Errorf("Unexpected received message bytes:\n%v", hex.Dump(inMsg.Bytes))
|
|
}
|
|
|
|
// Receive message from channel 0 and check
|
|
inMsg, ok = s2.Receive(byte(0x00))
|
|
if !ok {
|
|
t.Errorf("Failed to receive from channel zero")
|
|
}
|
|
if ReadString(bytes.NewBuffer(inMsg.Bytes), &n, &err) != "channel zero" {
|
|
t.Errorf("Unexpected received message bytes:\n%v", hex.Dump(inMsg.Bytes))
|
|
}
|
|
}
|
|
|
|
func BenchmarkSwitches(b *testing.B) {
|
|
|
|
b.StopTimer()
|
|
|
|
s1, s2, chDescs := makeSwitchPair(b, 10, 10, 1024, 10)
|
|
defer s1.Stop()
|
|
defer s2.Stop()
|
|
|
|
// Create a sink on either channel to just pop off messages.
|
|
recvRoutine := func(c *Switch, chId byte) {
|
|
for {
|
|
_, ok := c.Receive(chId)
|
|
if !ok {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create routines to consume from recvQueues.
|
|
for _, chDesc := range chDescs {
|
|
go recvRoutine(s1, chDesc.Id)
|
|
go recvRoutine(s2, chDesc.Id)
|
|
}
|
|
|
|
// Allow time for goroutines to boot up
|
|
time.Sleep(1000 * time.Millisecond)
|
|
b.StartTimer()
|
|
|
|
numSuccess, numFailure := 0, 0
|
|
|
|
// Send random message from one channel to another
|
|
for i := 0; i < b.N; i++ {
|
|
chId := chDescs[i%len(chDescs)].Id
|
|
nS, nF := s1.Broadcast(chId, String("test data"))
|
|
numSuccess += nS
|
|
numFailure += nF
|
|
}
|
|
|
|
log.Warning("success: %v, failure: %v", numSuccess, numFailure)
|
|
|
|
// Allow everything to flush before stopping switches & closing connections.
|
|
b.StopTimer()
|
|
time.Sleep(1000 * time.Millisecond)
|
|
|
|
}
|