shad-go/gossip/gossip_test.go

187 lines
3.8 KiB
Go
Raw Permalink Normal View History

2023-04-22 08:58:14 +00:00
package gossip_test
import (
"fmt"
"math/rand"
"net"
"testing"
"time"
"github.com/stretchr/testify/require"
"gitlab.com/slon/shad-go/gossip"
"gitlab.com/slon/shad-go/gossip/meshpb"
2023-04-22 08:58:14 +00:00
"go.uber.org/goleak"
"google.golang.org/grpc"
)
const (
2023-04-22 09:18:36 +00:00
pingPeriod = time.Millisecond * 50
waitPeriod = pingPeriod * 10
2023-04-22 08:58:14 +00:00
)
type env struct {
newPeer func() (*gossip.Peer, func())
}
func newEnv(t *testing.T) *env {
t.Cleanup(func() {
goleak.VerifyNone(t)
})
return &env{
newPeer: func() (*gossip.Peer, func()) {
lsn, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err)
peer := gossip.NewPeer(gossip.PeerConfig{
SelfEndpoint: lsn.Addr().String(),
PingPeriod: pingPeriod,
})
server := grpc.NewServer()
meshpb.RegisterGossipServiceServer(server, peer)
go func() { _ = server.Serve(lsn) }()
go peer.Run()
stop := func() {
server.Stop()
peer.Stop()
}
t.Cleanup(stop)
return peer, stop
},
}
}
func TestGossip_SinglePeer(t *testing.T) {
env := newEnv(t)
peer0, _ := env.newPeer()
members := peer0.GetMembers()
require.Contains(t, members, peer0.Addr())
peer0.UpdateMeta(&meshpb.PeerMeta{Name: "peer0"})
members = peer0.GetMembers()
require.Contains(t, members, peer0.Addr())
require.Equal(t, "peer0", members[peer0.Addr()].Name)
deadPeer, stopDeadPeer := env.newPeer()
stopDeadPeer()
peer0.AddSeed(deadPeer.Addr())
time.Sleep(waitPeriod)
require.Len(t, peer0.GetMembers(), 1)
}
func TestGossip_TwoPeers(t *testing.T) {
env := newEnv(t)
peer0, _ := env.newPeer()
peer1, stop1 := env.newPeer()
peer0.AddSeed(peer1.Addr())
time.Sleep(waitPeriod)
members0 := peer0.GetMembers()
require.Contains(t, members0, peer0.Addr())
require.Contains(t, members0, peer1.Addr())
members1 := peer1.GetMembers()
require.Contains(t, members1, peer0.Addr())
require.Contains(t, members1, peer1.Addr())
2023-05-03 08:00:35 +00:00
peer1.UpdateMeta(&meshpb.PeerMeta{Name: "bob"})
2023-04-22 08:58:14 +00:00
time.Sleep(waitPeriod)
2023-05-03 08:00:35 +00:00
require.Equal(t, "bob", peer0.GetMembers()[peer1.Addr()].Name)
2023-04-22 08:58:14 +00:00
peer1.UpdateMeta(&meshpb.PeerMeta{Name: "sam"})
time.Sleep(waitPeriod)
require.Equal(t, "sam", peer0.GetMembers()[peer1.Addr()].Name)
2023-05-03 08:00:35 +00:00
peer0.UpdateMeta(&meshpb.PeerMeta{Name: "alice"})
time.Sleep(waitPeriod)
require.Equal(t, "alice", peer1.GetMembers()[peer0.Addr()].Name)
2023-04-22 08:58:14 +00:00
stop1()
time.Sleep(waitPeriod)
members0 = peer0.GetMembers()
require.NotContains(t, members0, peer1.Addr())
}
func TestGossip_ManyPeers(t *testing.T) {
env := newEnv(t)
seed, stopSeed := env.newPeer()
var peers []*gossip.Peer
names := map[string]string{}
for i := 0; i < 10; i++ {
peer, _ := env.newPeer()
peer.AddSeed(seed.Addr())
peer.UpdateMeta(&meshpb.PeerMeta{Name: fmt.Sprint(i)})
names[peer.Addr()] = fmt.Sprint(i)
peers = append(peers, peer)
}
time.Sleep(waitPeriod)
stopSeed()
time.Sleep(waitPeriod)
for _, peer := range peers {
members := peer.GetMembers()
require.NotContains(t, members, seed.Addr())
for addr, name := range names {
require.Contains(t, members, addr)
require.Equal(t, members[addr].Name, name)
}
}
peers[0].UpdateMeta(&meshpb.PeerMeta{Name: "leader"})
time.Sleep(waitPeriod)
for _, peer := range peers {
members := peer.GetMembers()
require.Contains(t, members, peers[0].Addr())
require.Equal(t, members[peers[0].Addr()].Name, "leader")
}
}
func TestGossip_Groups(t *testing.T) {
env := newEnv(t)
aSize, bSize := 1, 1
seedA, _ := env.newPeer()
seedB, _ := env.newPeer()
for i := 0; i < 10; i++ {
peer, _ := env.newPeer()
if rand.Int()%2 == 0 {
peer.AddSeed(seedA.Addr())
aSize++
} else {
peer.AddSeed(seedB.Addr())
bSize++
}
}
time.Sleep(waitPeriod)
require.Len(t, seedA.GetMembers(), aSize)
require.Len(t, seedB.GetMembers(), bSize)
seedA.AddSeed(seedB.Addr())
time.Sleep(waitPeriod)
require.Len(t, seedA.GetMembers(), aSize+bSize)
require.Len(t, seedB.GetMembers(), aSize+bSize)
}