@@ -21,6 +21,7 @@ import (
21
21
"io"
22
22
"net"
23
23
"sync"
24
+ "sync/atomic"
24
25
"testing"
25
26
"time"
26
27
@@ -42,6 +43,7 @@ type dummyCommModule struct {
42
43
lock * sync.RWMutex
43
44
incMsgs chan * proto.GossipMessage
44
45
lastSeqs map [string ]uint64
46
+ shouldGossip bool
45
47
}
46
48
47
49
type gossipMsg struct {
@@ -55,8 +57,9 @@ func (m *gossipMsg) GetGossipMessage() *proto.GossipMessage {
55
57
type gossipInstance struct {
56
58
comm * dummyCommModule
57
59
Discovery
58
- gRGCserv * grpc.Server
59
- lsnr net.Listener
60
+ gRGCserv * grpc.Server
61
+ lsnr net.Listener
62
+ shouldGossip bool
60
63
}
61
64
62
65
func (comm * dummyCommModule ) ValidateAliveMsg (am * proto.AliveMessage ) bool {
@@ -68,6 +71,9 @@ func (comm *dummyCommModule) SignMessage(am *proto.AliveMessage) *proto.AliveMes
68
71
}
69
72
70
73
func (comm * dummyCommModule ) Gossip (msg * proto.GossipMessage ) {
74
+ if ! comm .shouldGossip {
75
+ return
76
+ }
71
77
comm .lock .Lock ()
72
78
defer comm .lock .Unlock ()
73
79
for _ , conn := range comm .streams {
@@ -203,6 +209,14 @@ func (g *gossipInstance) Ping(context.Context, *proto.Empty) (*proto.Empty, erro
203
209
}
204
210
205
211
func createDiscoveryInstance (port int , id string , bootstrapPeers []string ) * gossipInstance {
212
+ return createDiscoveryInstanceThatGossips (port , id , bootstrapPeers , true )
213
+ }
214
+
215
+ func createDiscoveryInstanceWithNoGossip (port int , id string , bootstrapPeers []string ) * gossipInstance {
216
+ return createDiscoveryInstanceThatGossips (port , id , bootstrapPeers , false )
217
+ }
218
+
219
+ func createDiscoveryInstanceThatGossips (port int , id string , bootstrapPeers []string , shouldGossip bool ) * gossipInstance {
206
220
comm := & dummyCommModule {
207
221
conns : make (map [string ]* grpc.ClientConn ),
208
222
streams : make (map [string ]proto.Gossip_GossipStreamClient ),
@@ -212,6 +226,7 @@ func createDiscoveryInstance(port int, id string, bootstrapPeers []string) *goss
212
226
detectedDead : make (chan string , 10000 ),
213
227
lock : & sync.RWMutex {},
214
228
lastSeqs : make (map [string ]uint64 ),
229
+ shouldGossip : shouldGossip ,
215
230
}
216
231
217
232
endpoint := fmt .Sprintf ("localhost:%d" , port )
@@ -230,7 +245,7 @@ func createDiscoveryInstance(port int, id string, bootstrapPeers []string) *goss
230
245
231
246
discSvc := NewDiscoveryService (bootstrapPeers , self , comm , comm )
232
247
discSvc .(* gossipDiscoveryImpl ).logger .SetLevel (logging .WARNING )
233
- gossInst := & gossipInstance {comm : comm , gRGCserv : s , Discovery : discSvc , lsnr : ll }
248
+ gossInst := & gossipInstance {comm : comm , gRGCserv : s , Discovery : discSvc , lsnr : ll , shouldGossip : shouldGossip }
234
249
235
250
proto .RegisterGossipServer (s , gossInst )
236
251
go s .Serve (ll )
@@ -287,19 +302,34 @@ func TestUpdate(t *testing.T) {
287
302
return true
288
303
}
289
304
290
-
291
305
waitUntilOrFail (t , checkMembership )
306
+ stopInstances (t , instances )
307
+ }
292
308
293
- stopAction := & sync.WaitGroup {}
294
- for _ , inst := range instances {
295
- stopAction .Add (1 )
296
- go func (inst * gossipInstance ) {
297
- defer stopAction .Done ()
298
- inst .Stop ()
299
- }(inst )
300
- }
309
+ func TestInitiateSync (t * testing.T ) {
310
+ nodeNum := 10
311
+ bootPeers := []string {bootPeer (3611 ), bootPeer (3612 )}
312
+ instances := []* gossipInstance {}
301
313
302
- waitUntilOrFailBlocking (t , stopAction .Wait )
314
+ toDie := int32 (0 )
315
+ for i := 1 ; i <= nodeNum ; i ++ {
316
+ id := fmt .Sprintf ("d%d" , i )
317
+ inst := createDiscoveryInstanceWithNoGossip (3610 + i , id , bootPeers )
318
+ instances = append (instances , inst )
319
+ go func () {
320
+ for {
321
+ if atomic .LoadInt32 (& toDie ) == int32 (1 ) {
322
+ return
323
+ }
324
+ time .Sleep (aliveExpirationTimeout / 3 )
325
+ inst .InitiateSync (9 )
326
+ }
327
+ }()
328
+ }
329
+ time .Sleep (aliveExpirationTimeout * 4 )
330
+ assertMembership (t , instances , nodeNum - 1 )
331
+ atomic .StoreInt32 (& toDie , int32 (1 ))
332
+ stopInstances (t , instances )
303
333
}
304
334
305
335
func TestExpiration (t * testing.T ) {
@@ -319,21 +349,12 @@ func TestExpiration(t *testing.T) {
319
349
instances = append (instances , inst )
320
350
}
321
351
322
- fullMembership := func () bool {
323
- return nodeNum - 1 == len (instances [nodeNum - 1 ].GetMembership ())
324
- }
325
-
326
- waitUntilOrFail (t , fullMembership )
352
+ assertMembership (t , instances , nodeNum - 1 )
327
353
328
354
waitUntilOrFailBlocking (t , instances [nodeNum - 1 ].Stop )
329
355
waitUntilOrFailBlocking (t , instances [nodeNum - 2 ].Stop )
330
356
331
- time .Sleep (time .Duration (2 ) * time .Second )
332
- membershipReduced := func () bool {
333
- return nodeNum - 3 == len (instances [0 ].GetMembership ())
334
- }
335
-
336
- waitUntilOrFail (t , membershipReduced )
357
+ assertMembership (t , instances , nodeNum - 3 )
337
358
338
359
stopAction := & sync.WaitGroup {}
339
360
for i , inst := range instances {
@@ -367,21 +388,8 @@ func TestGetFullMembership(t *testing.T) {
367
388
instances = append (instances , inst )
368
389
}
369
390
370
- fullMembership := func () bool {
371
- return nodeNum - 1 == len (instances [nodeNum - 1 ].GetMembership ())
372
- }
373
- waitUntilOrFail (t , fullMembership )
374
-
375
- stopAction := & sync.WaitGroup {}
376
- for _ , inst := range instances {
377
- stopAction .Add (1 )
378
- go func (inst * gossipInstance ) {
379
- defer stopAction .Done ()
380
- inst .Stop ()
381
- }(inst )
382
- }
383
-
384
- waitUntilOrFailBlocking (t , stopAction .Wait )
391
+ assertMembership (t , instances , nodeNum - 1 )
392
+ stopInstances (t , instances )
385
393
}
386
394
387
395
func TestGossipDiscoveryStopping (t * testing.T ) {
@@ -391,6 +399,38 @@ func TestGossipDiscoveryStopping(t *testing.T) {
391
399
392
400
}
393
401
402
+ func TestConvergence (t * testing.T ) {
403
+ // scenario:
404
+ // {boot peer: [peer list]}
405
+ // {d1: d2, d3, d4}
406
+ // {d5: d6, d7, d8}
407
+ // {d9: d10, d11, d12}
408
+ // connect all boot peers with d13
409
+ // take down d13
410
+ // ensure still full membership
411
+ instances := []* gossipInstance {}
412
+ for _ , i := range []int {1 , 5 , 9 } {
413
+ bootPort := 4610 + i
414
+ id := fmt .Sprintf ("d%d" , i )
415
+ leader := createDiscoveryInstance (bootPort , id , []string {})
416
+ instances = append (instances , leader )
417
+ for minionIndex := 1 ; minionIndex <= 3 ; minionIndex ++ {
418
+ id := fmt .Sprintf ("d%d" , i + minionIndex )
419
+ minion := createDiscoveryInstance (4610 + minionIndex + i , id , []string {bootPeer (bootPort )})
420
+ instances = append (instances , minion )
421
+ }
422
+ }
423
+
424
+ assertMembership (t , instances , 3 )
425
+ connector := createDiscoveryInstance (4623 , fmt .Sprintf ("d13" ), []string {bootPeer (4611 ), bootPeer (4615 ), bootPeer (4619 )})
426
+ instances = append (instances , connector )
427
+ assertMembership (t , instances , 12 )
428
+ connector .Stop ()
429
+ instances = instances [:len (instances )- 1 ]
430
+ assertMembership (t , instances , 11 )
431
+ stopInstances (t , instances )
432
+ }
433
+
394
434
func waitUntilOrFail (t * testing.T , pred func () bool ) {
395
435
start := time .Now ()
396
436
limit := start .UnixNano () + timeout .Nanoseconds ()
@@ -417,3 +457,28 @@ func waitUntilOrFailBlocking(t *testing.T, f func()) {
417
457
}
418
458
assert .Fail (t , "Timeout expired!" )
419
459
}
460
+
461
+ func stopInstances (t * testing.T , instances []* gossipInstance ) {
462
+ stopAction := & sync.WaitGroup {}
463
+ for _ , inst := range instances {
464
+ stopAction .Add (1 )
465
+ go func (inst * gossipInstance ) {
466
+ defer stopAction .Done ()
467
+ inst .Stop ()
468
+ }(inst )
469
+ }
470
+
471
+ waitUntilOrFailBlocking (t , stopAction .Wait )
472
+ }
473
+
474
+ func assertMembership (t * testing.T , instances []* gossipInstance , expectedNum int ) {
475
+ fullMembership := func () bool {
476
+ for _ , inst := range instances {
477
+ if len (inst .GetMembership ()) == expectedNum {
478
+ return true
479
+ }
480
+ }
481
+ return false
482
+ }
483
+ waitUntilOrFail (t , fullMembership )
484
+ }
0 commit comments