@@ -20,6 +20,7 @@ import (
2020 "github.com/hashicorp/go-hclog"
2121 "github.com/hashicorp/raft"
2222 "github.com/stretchr/testify/assert"
23+ "github.com/stretchr/testify/require"
2324 "google.golang.org/grpc"
2425 "google.golang.org/grpc/credentials/insecure"
2526)
@@ -55,11 +56,13 @@ type portsAdress struct {
5556
5657const (
5758 // raft and the grpc requested by the client use grpc and are received on the same port
58- grpcPort = 50000
59- raftPort = 50000
60-
59+ grpcPort = 50000
60+ raftPort = 50000
6161 redisPort = 63790
6262 dynamoPort = 28000
63+
64+ // followers wait longer before starting elections to give the leader time to bootstrap and share config.
65+ followerElectionTimeout = 10 * time .Second
6366)
6467
6568var mu sync.Mutex
@@ -136,6 +139,7 @@ func createNode(t *testing.T, n int) ([]Node, []string, []string) {
136139 nodes , grpcAdders , redisAdders := setupNodes (t , ctx , n , ports , cfg )
137140
138141 waitForNodeListeners (t , ctx , nodes , waitTimeout , waitInterval )
142+ waitForConfigReplication (t , cfg , nodes , waitTimeout , waitInterval )
139143 waitForRaftReadiness (t , nodes , waitTimeout , waitInterval )
140144
141145 return nodes , grpcAdders , redisAdders
@@ -163,9 +167,6 @@ func waitForNodeListeners(t *testing.T, ctx context.Context, nodes []Node, waitT
163167
164168func waitForRaftReadiness (t * testing.T , nodes []Node , waitTimeout , waitInterval time.Duration ) {
165169 t .Helper ()
166- assert .Eventually (t , func () bool {
167- return nodes [0 ].raft .State () == raft .Leader
168- }, waitTimeout , waitInterval )
169170
170171 expectedLeader := raft .ServerAddress (nodes [0 ].raftAddress )
171172 assert .Eventually (t , func () bool {
@@ -188,6 +189,40 @@ func waitForRaftReadiness(t *testing.T, nodes []Node, waitTimeout, waitInterval
188189 }, waitTimeout , waitInterval )
189190}
190191
192+ func waitForConfigReplication (t * testing.T , cfg raft.Configuration , nodes []Node , waitTimeout , waitInterval time.Duration ) {
193+ t .Helper ()
194+
195+ assert .Eventually (t , func () bool {
196+ for _ , n := range nodes {
197+ future := n .raft .GetConfiguration ()
198+ if future .Error () != nil {
199+ return false
200+ }
201+
202+ current := future .Configuration ().Servers
203+ if len (current ) != len (cfg .Servers ) {
204+ return false
205+ }
206+
207+ for _ , expected := range cfg .Servers {
208+ if ! containsServer (current , expected ) {
209+ return false
210+ }
211+ }
212+ }
213+ return true
214+ }, waitTimeout , waitInterval )
215+ }
216+
217+ func containsServer (servers []raft.Server , expected raft.Server ) bool {
218+ for _ , s := range servers {
219+ if s .ID == expected .ID && s .Address == expected .Address && s .Suffrage == expected .Suffrage {
220+ return true
221+ }
222+ }
223+ return false
224+ }
225+
191226func assignPorts (n int ) []portsAdress {
192227 ports := make ([]portsAdress , n )
193228 for i := 0 ; i < n ; i ++ {
@@ -214,6 +249,8 @@ func buildRaftConfig(n int, ports []portsAdress) raft.Configuration {
214249 return cfg
215250}
216251
252+ const leaderElectionTimeout = 0 * time .Second
253+
217254func setupNodes (t * testing.T , ctx context.Context , n int , ports []portsAdress , cfg raft.Configuration ) ([]Node , []string , []string ) {
218255 t .Helper ()
219256 var grpcAdders []string
@@ -228,7 +265,13 @@ func setupNodes(t *testing.T, ctx context.Context, n int, ports []portsAdress, c
228265
229266 port := ports [i ]
230267
231- r , tm , err := newRaft (strconv .Itoa (i ), port .raftAddress , fsm , i == 0 , cfg )
268+ // リーダーが先に投票を開始させる
269+ electionTimeout := leaderElectionTimeout
270+ if i != 0 {
271+ electionTimeout = followerElectionTimeout
272+ }
273+
274+ r , tm , err := newRaft (strconv .Itoa (i ), port .raftAddress , fsm , i == 0 , cfg , electionTimeout )
232275 assert .NoError (t , err )
233276
234277 s := grpc .NewServer ()
@@ -244,7 +287,7 @@ func setupNodes(t *testing.T, ctx context.Context, n int, ports []portsAdress, c
244287 raftadmin .Register (s , r )
245288
246289 grpcSock , err := lc .Listen (ctx , "tcp" , port .grpcAddress )
247- assert .NoError (t , err )
290+ require .NoError (t , err )
248291
249292 grpcAdders = append (grpcAdders , port .grpcAddress )
250293 redisAdders = append (redisAdders , port .redisAddress )
@@ -253,7 +296,7 @@ func setupNodes(t *testing.T, ctx context.Context, n int, ports []portsAdress, c
253296 }(s , grpcSock )
254297
255298 l , err := lc .Listen (ctx , "tcp" , port .redisAddress )
256- assert .NoError (t , err )
299+ require .NoError (t , err )
257300 rd := NewRedisServer (l , st , coordinator )
258301 go func (server * RedisServer ) {
259302 assert .NoError (t , server .Run ())
@@ -282,10 +325,14 @@ func setupNodes(t *testing.T, ctx context.Context, n int, ports []portsAdress, c
282325 return nodes , grpcAdders , redisAdders
283326}
284327
285- func newRaft (myID string , myAddress string , fsm raft.FSM , bootstrap bool , cfg raft.Configuration ) (* raft.Raft , * transport.Manager , error ) {
328+ func newRaft (myID string , myAddress string , fsm raft.FSM , bootstrap bool , cfg raft.Configuration , electionTimeout time. Duration ) (* raft.Raft , * transport.Manager , error ) {
286329 c := raft .DefaultConfig ()
287330 c .LocalID = raft .ServerID (myID )
288331
332+ if electionTimeout > 0 {
333+ c .ElectionTimeout = electionTimeout
334+ }
335+
289336 // this config is for development
290337 ldb := raft .NewInmemStore ()
291338 sdb := raft .NewInmemStore ()
0 commit comments