Files
redis-go/cluster/topo_test.go
finley 74421ba3f2 Merge branch 'feat/raft'
# Conflicts:
#	cluster/cluster.go
#	cluster/router.go
#	config/config.go
#	database/database.go
#	database/server.go
2023-06-11 13:25:41 +08:00

153 lines
3.8 KiB
Go

package cluster
import (
"github.com/hdt3213/godis/config"
database2 "github.com/hdt3213/godis/database"
"github.com/hdt3213/godis/datastruct/dict"
"github.com/hdt3213/godis/lib/idgenerator"
"github.com/hdt3213/godis/lib/utils"
"github.com/hdt3213/godis/redis/connection"
"github.com/hdt3213/godis/redis/protocol/asserts"
"path"
"strconv"
"testing"
"time"
)
func makeTestRaft(addresses []string, timeoutFlags []bool, persistFilenames []string) ([]*Cluster, error) {
nodes := make([]*Cluster, len(addresses))
factory := &testClientFactory{
nodes: nodes,
timeoutFlags: timeoutFlags,
}
for i, addr := range addresses {
addr := addr
nodes[i] = &Cluster{
self: addr,
addr: addr,
db: database2.NewStandaloneServer(),
transactions: dict.MakeSimple(),
idGenerator: idgenerator.MakeGenerator(config.Properties.Self),
clientFactory: factory,
slots: make(map[uint32]*hostSlot),
}
topologyPersistFile := persistFilenames[i]
nodes[i].topology = newRaft(nodes[i], topologyPersistFile)
}
err := nodes[0].startAsSeed(addresses[0])
if err != nil {
return nil, err
}
err = nodes[1].Join(addresses[0])
if err != nil {
return nil, err
}
err = nodes[2].Join(addresses[0])
if err != nil {
return nil, err
}
return nodes, nil
}
func TestRaftStart(t *testing.T) {
addresses := []string{"127.0.0.1:6399", "127.0.0.1:7379", "127.0.0.1:7369"}
timeoutFlags := []bool{false, false, false}
persistFilenames := []string{"", "", ""}
nodes, err := makeTestRaft(addresses, timeoutFlags, persistFilenames)
if err != nil {
t.Error(err)
return
}
if nodes[0].asRaft().state != leader {
t.Error("expect leader")
return
}
if nodes[1].asRaft().state != follower {
t.Error("expect follower")
return
}
if nodes[2].asRaft().state != follower {
t.Error("expect follower")
return
}
size := 100
conn := connection.NewFakeConn()
for i := 0; i < size; i++ {
str := strconv.Itoa(i)
result := nodes[0].Exec(conn, utils.ToCmdLine("SET", str, str))
asserts.AssertNotError(t, result)
}
for i := 0; i < size; i++ {
str := strconv.Itoa(i)
result := nodes[0].Exec(conn, utils.ToCmdLine("Get", str))
asserts.AssertBulkReply(t, result, str)
}
for _, node := range nodes {
_ = node.asRaft().Close()
}
}
func TestRaftElection(t *testing.T) {
addresses := []string{"127.0.0.1:6399", "127.0.0.1:7379", "127.0.0.1:7369"}
timeoutFlags := []bool{false, false, false}
persistFilenames := []string{"", "", ""}
nodes, err := makeTestRaft(addresses, timeoutFlags, persistFilenames)
if err != nil {
t.Error(err)
return
}
nodes[0].asRaft().Close()
time.Sleep(3 * electionTimeoutMaxMs * time.Millisecond) // wait for leader timeout
//<-make(chan struct{}) // wait for leader timeout
for i := 0; i < 10; i++ {
leaderCount := 0
for _, node := range nodes {
if node.asRaft().closed {
continue
}
switch node.asRaft().state {
case leader:
leaderCount++
}
}
if leaderCount == 1 {
break
} else if leaderCount > 1 {
t.Errorf("get %d leaders, split brain", leaderCount)
break
}
time.Sleep(time.Second)
}
}
func TestRaftPersist(t *testing.T) {
addresses := []string{"127.0.0.1:6399", "127.0.0.1:7379", "127.0.0.1:7369"}
timeoutFlags := []bool{false, false, false}
persistFilenames := []string{
path.Join(config.Properties.Dir, "test6399.conf"),
path.Join(config.Properties.Dir, "test7379.conf"),
path.Join(config.Properties.Dir, "test7369.conf"),
}
nodes, err := makeTestRaft(addresses, timeoutFlags, persistFilenames)
if err != nil {
t.Error(err)
return
}
node1 := nodes[0].asRaft()
err = node1.persist()
if err != nil {
t.Error(err)
return
}
for _, node := range nodes {
_ = node.asRaft().Close()
}
err = node1.LoadConfigFile()
if err != nil {
t.Error(err)
return
}
}