github.com/ergo-services/ergo@v1.999.224/tests/raft_manual_test.go (about) 1 //go:build manual 2 // +build manual 3 4 // to run this test: 5 // go test -run TestRaft -ergo.norecover -tags manual 6 // 7 // enable debug printing in the gen/raft.go 8 // quorum building debuging: %s/\/\/ QUODBG // 9 // leader election debuging: %s/\/\/ LDRDBG // 10 // heartbeat debuging: %s/\/\/ HRTDBG // 11 12 package tests 13 14 import ( 15 "fmt" 16 "math/rand" 17 "testing" 18 "time" 19 20 "github.com/ergo-services/ergo" 21 "github.com/ergo-services/ergo/etf" 22 "github.com/ergo-services/ergo/gen" 23 "github.com/ergo-services/ergo/node" 24 ) 25 26 type testRaft struct { 27 gen.Raft 28 res chan interface{} 29 } 30 31 func (tr *testRaft) InitRaft(process *gen.RaftProcess, args ...etf.Term) (gen.RaftOptions, error) { 32 var options gen.RaftOptions 33 if len(args) > 0 { 34 options.Peers = args[0].([]gen.ProcessID) 35 options.Serial = uint64(rand.Intn(10)) 36 } 37 38 fmt.Println(process.Self(), process.Name(), " ----------", options.Serial) 39 return options, gen.RaftStatusOK 40 } 41 42 func (tr *testRaft) HandleQuorum(process *gen.RaftProcess, q *gen.RaftQuorum) gen.RaftStatus { 43 if q == nil { 44 fmt.Println("QQQ quorum", process.Name(), "state: NONE") 45 return gen.RaftStatusOK 46 } else { 47 fmt.Println("QQQ quorum", process.Name(), "state:", q.State, q.Member, q.Peers) 48 } 49 if sent, _ := process.State.(int); sent != 1 { 50 process.SendAfter(process.Self(), "ok", 7*time.Second) 51 process.State = 1 52 } 53 //tr.res <- qs 54 return gen.RaftStatusOK 55 } 56 57 func (tr *testRaft) HandleLeader(process *gen.RaftProcess, leader *gen.RaftLeader) gen.RaftStatus { 58 fmt.Println("LLL leader", process.Name(), leader) 59 return gen.RaftStatusOK 60 } 61 62 func (tr *testRaft) HandleAppend(process *gen.RaftProcess, ref etf.Ref, serial uint64, key string, value etf.Term) gen.RaftStatus { 63 fmt.Println("AAA append", ref, serial, value) 64 return gen.RaftStatusOK 65 } 66 67 func (tr *testRaft) HandleGet(process *gen.RaftProcess, serial uint64) (string, etf.Term, gen.RaftStatus) { 68 fmt.Println("GGG get", process.Name(), serial) 69 return "", nil, gen.RaftStatusOK 70 } 71 72 func (tr *testRaft) HandleRaftInfo(process *gen.RaftProcess, message etf.Term) gen.ServerStatus { 73 q := process.Quorum() 74 if q == nil { 75 fmt.Println("III info", process.Name(), "state: NONE", "message:", message) 76 } else { 77 fmt.Println("III info", process.Name(), "Q:", q.State, q.Member, "", process.Leader(), "message:", message) 78 } 79 if l := process.Leader(); l != nil && l.Leader == process.Self() { 80 fmt.Println("III i'm leader. freeze", process.Self()) 81 time.Sleep(35 * time.Second) 82 } 83 process.State = 0 84 return gen.ServerStatusOK 85 } 86 87 func TestRaftLeader(t *testing.T) { 88 fmt.Printf("\n=== Test GenRaft\n") 89 var N int = 4 90 91 fmt.Printf("Starting %d nodes: nodeGenRaftXX@localhost...", N) 92 93 nodes := make([]node.Node, N) 94 for i := range nodes { 95 name := fmt.Sprintf("nodeGenRaft%02d@localhost", i) 96 node, err := ergo.StartNode(name, "cookies", node.Options{}) 97 if err != nil { 98 t.Fatal(err) 99 } 100 nodes[i] = node 101 } 102 103 defer func() { 104 for i := range nodes { 105 nodes[i].Stop() 106 } 107 }() 108 fmt.Println("OK") 109 110 rafts := make([]gen.Process, N) 111 results := make([]chan interface{}, N) 112 var args []etf.Term 113 var peer gen.ProcessID 114 for i := range rafts { 115 name := fmt.Sprintf("raft%02d", i+1) 116 if i == 0 { 117 args = nil 118 } else { 119 peer.Node = nodes[i-1].Name() 120 peer.Name = rafts[i-1].Name() 121 peers := []gen.ProcessID{peer} 122 args = []etf.Term{peers} 123 } 124 tr := &testRaft{ 125 res: make(chan interface{}, 2), 126 } 127 results[i] = tr.res 128 raft, err := nodes[i].Spawn(name, gen.ProcessOptions{}, tr, args...) 129 if err != nil { 130 t.Fatal(err) 131 } 132 rafts[i] = raft 133 //time.Sleep(300 * time.Millisecond) 134 } 135 136 time.Sleep(50 * time.Second) 137 138 }