github.com/ergo-services/ergo@v1.999.224/tests/raft_data_test.go (about) 1 //go:build !manual 2 3 package tests 4 5 import ( 6 "fmt" 7 "testing" 8 "time" 9 10 "github.com/ergo-services/ergo/etf" 11 "github.com/ergo-services/ergo/gen" 12 ) 13 14 // F - follower 15 // M - quorum member 16 // L - leader 17 // Q - quorum (all members) 18 // 19 // append cases: 20 // 1. F -> M -> L -> Q ... broadcast 21 // 2. F -> L -> Q ... broadcast 22 // 3. M -> L - Q ... broadcast 23 // 4. L -> Q ... broadcast 24 // 25 26 func TestRaftAppend(t *testing.T) { 27 fmt.Printf("\n=== Test GenRaft - append data\n") 28 server := &testRaft{ 29 n: 6, 30 qstate: gen.RaftQuorumState5, 31 } 32 nodes, rafts, leaderSerial := startRaftCluster("append", server) 33 34 fmt.Printf(" append on a follower (send to the quorum member and forward to the leader: ") 35 for _, raft := range rafts { 36 q := raft.Quorum() 37 // find the follower 38 if q.Member == true { 39 continue 40 } 41 42 // cases 1 and 2 - send to the quorum member. 43 // the follower isn't able to send it to the leader (case 2) 44 // since it has no info about the quorum leader (quorum member forwards it 45 // to the leader under the hood) 46 ref, err := raft.Append("asdfkey", "asdfvalue") 47 if err != nil { 48 t.Fatal(err) 49 } 50 leaderSerial = checkAppend(t, server, ref, rafts, leaderSerial) 51 break 52 } 53 fmt.Println("OK") 54 fmt.Printf(" append on a quorum member (send to the leader): ") 55 for _, raft := range rafts { 56 q := raft.Quorum() 57 // find the quorum member 58 if q.Member == false { 59 continue 60 } 61 62 // case 3 - quorum member sends append to the leader 63 ref, err := raft.Append("asdfkey", "asdfvalue") 64 if err != nil { 65 t.Fatal(err) 66 } 67 leaderSerial = checkAppend(t, server, ref, rafts, leaderSerial) 68 break 69 } 70 fmt.Println("OK") 71 fmt.Printf(" append on a leader: ") 72 for _, raft := range rafts { 73 l := raft.Leader() 74 // finde the quorum leader 75 if l == nil || l.Leader != raft.Self() { 76 continue 77 } 78 79 // case 4 - leader makes append 80 ref, err := raft.Append("asdfkey", "asdfvalue") 81 if err != nil { 82 t.Fatal(err) 83 } 84 leaderSerial = checkAppend(t, server, ref, rafts, leaderSerial) 85 break 86 } 87 fmt.Println("OK") 88 89 for _, node := range nodes { 90 node.Stop() 91 } 92 } 93 94 // get serial case: run through the raft process and get all the data to achieve 95 // the same serial 96 func TestRaftGet(t *testing.T) { 97 fmt.Printf("\n=== Test GenRaft - get data\n") 98 server := &testRaft{ 99 n: 6, 100 qstate: gen.RaftQuorumState5, 101 } 102 nodes, rafts, leaderSerial := startRaftCluster("get", server) 103 for _, raft := range rafts { 104 fmt.Println(" started raft process", raft.Self(), "with serial", raft.Serial()) 105 } 106 107 for _, raft := range rafts { 108 _, err := raft.Get(12341234) 109 if err != gen.ErrRaftNoSerial { 110 t.Fatal("must be ErrRaftNoSerial here") 111 } 112 113 if raft.Serial() == leaderSerial { 114 fmt.Println(" raft process", raft.Self(), "has already latest serial. skip it") 115 continue 116 } 117 118 fmt.Printf(" get serials (%d...%d) on %s to reach the leader's serial: ", raft.Serial()+1, leaderSerial, raft.Self()) 119 serial := raft.Serial() 120 gotFrom := []etf.Pid{} 121 for i := serial; i < leaderSerial; i++ { 122 ref, err := raft.Get(i + 1) 123 if err != nil { 124 t.Fatal(err) 125 } 126 result := waitGetRef(t, server, ref) 127 128 // compare with the original 129 original := data[result.key] 130 if original.serial != result.serial { 131 t.Fatal("wrong serial") 132 } 133 if original.value != result.value { 134 t.Fatal("wrong value") 135 } 136 // check internal data 137 internal := raft.State.(*raftState) 138 if internal.serials[result.serial] != result.key { 139 t.Fatal("serial mismatch the result key") 140 } 141 d, exist := internal.data[result.key] 142 if exist == false { 143 t.Fatal("internal data hasn't been updated") 144 } 145 if d.serial != result.serial { 146 t.Fatal("intenal data serial mismatch") 147 } 148 if d.value != result.value { 149 t.Fatal("intarnal data value mismatch") 150 } 151 gotFrom = append(gotFrom, result.process.Self()) 152 } 153 fmt.Println("OK") 154 fmt.Println(" got from:", gotFrom, ")") 155 } 156 157 //fmt.Println("-----------") 158 //for _, raft := range rafts { 159 // s := raft.State.(*raftState) 160 // fmt.Println(raft.Self(), "INTERNAL", s) 161 //} 162 163 for _, node := range nodes { 164 node.Stop() 165 } 166 } 167 168 func waitGetRef(t *testing.T, server *testRaft, ref etf.Ref) raftResult { 169 var result raftResult 170 select { 171 case result = <-server.s: 172 if result.ref != ref { 173 t.Fatal("wrong ref") 174 } 175 return result 176 case <-time.After(30 * time.Second): 177 t.Fatal("get timeout") 178 } 179 return result 180 } 181 182 func checkAppend(t *testing.T, server *testRaft, ref etf.Ref, rafts []*gen.RaftProcess, serial uint64) uint64 { 183 appends := 0 184 for { 185 select { 186 case result := <-server.a: 187 if result.serial != serial+1 { 188 t.Fatalf("wrong serial %d (must be %d)", result.serial, serial+1) 189 } 190 appends++ 191 //fmt.Println("got append on ", result.process.Self(), "total appends", appends) 192 if appends != len(rafts) { 193 continue 194 } 195 // check serials 196 for _, r := range rafts { 197 s := r.Serial() 198 if s != serial+1 { 199 t.Fatalf("wrong serial %d on %s", s, r.Self()) 200 } 201 } 202 return serial + 1 203 case <-time.After(30 * time.Second): 204 t.Fatal("append timeout") 205 206 } 207 } 208 209 }