@@ -25,6 +25,7 @@ import (
25
25
"time"
26
26
27
27
"github.com/google/go-cmp/cmp"
28
+ "github.com/stretchr/testify/assert"
28
29
coordinationv1 "k8s.io/api/coordination/v1"
29
30
corev1 "k8s.io/api/core/v1"
30
31
"k8s.io/apimachinery/pkg/api/equality"
@@ -37,8 +38,6 @@ import (
37
38
rl "k8s.io/client-go/tools/leaderelection/resourcelock"
38
39
"k8s.io/client-go/tools/record"
39
40
"k8s.io/utils/clock"
40
-
41
- "github.com/stretchr/testify/assert"
42
41
)
43
42
44
43
func createLockObject (t * testing.T , objectType , namespace , name string , record * rl.LeaderElectionRecord ) (obj runtime.Object ) {
@@ -353,6 +352,147 @@ func testTryAcquireOrRenew(t *testing.T, objectType string) {
353
352
}
354
353
}
355
354
355
+ func TestTryCoordinatedRenew (t * testing.T ) {
356
+ objectType := "leases"
357
+ clock := clock.RealClock {}
358
+ future := clock .Now ().Add (1000 * time .Hour )
359
+
360
+ tests := []struct {
361
+ name string
362
+ observedRecord rl.LeaderElectionRecord
363
+ observedTime time.Time
364
+ retryAfter time.Duration
365
+ reactors []Reactor
366
+ expectedEvents []string
367
+
368
+ expectSuccess bool
369
+ transitionLeader bool
370
+ outHolder string
371
+ }{
372
+ {
373
+ name : "don't acquire from led, acked object" ,
374
+ reactors : []Reactor {
375
+ {
376
+ verb : "get" ,
377
+ reaction : func (action fakeclient.Action ) (handled bool , ret runtime.Object , err error ) {
378
+ return true , createLockObject (t , objectType , action .GetNamespace (), action .(fakeclient.GetAction ).GetName (), & rl.LeaderElectionRecord {HolderIdentity : "bing" }), nil
379
+ },
380
+ },
381
+ },
382
+ observedTime : future ,
383
+
384
+ expectSuccess : false ,
385
+ outHolder : "bing" ,
386
+ },
387
+ {
388
+ name : "renew already acquired object" ,
389
+ reactors : []Reactor {
390
+ {
391
+ verb : "get" ,
392
+ reaction : func (action fakeclient.Action ) (handled bool , ret runtime.Object , err error ) {
393
+ return true , createLockObject (t , objectType , action .GetNamespace (), action .(fakeclient.GetAction ).GetName (), & rl.LeaderElectionRecord {HolderIdentity : "baz" }), nil
394
+ },
395
+ },
396
+ {
397
+ verb : "update" ,
398
+ reaction : func (action fakeclient.Action ) (handled bool , ret runtime.Object , err error ) {
399
+ return true , action .(fakeclient.CreateAction ).GetObject (), nil
400
+ },
401
+ },
402
+ },
403
+ observedTime : future ,
404
+ observedRecord : rl.LeaderElectionRecord {HolderIdentity : "baz" },
405
+
406
+ expectSuccess : true ,
407
+ outHolder : "baz" ,
408
+ },
409
+ }
410
+
411
+ for i := range tests {
412
+ test := & tests [i ]
413
+ t .Run (test .name , func (t * testing.T ) {
414
+ // OnNewLeader is called async so we have to wait for it.
415
+ var wg sync.WaitGroup
416
+ wg .Add (1 )
417
+ var reportedLeader string
418
+ var lock rl.Interface
419
+
420
+ objectMeta := metav1.ObjectMeta {Namespace : "foo" , Name : "bar" }
421
+ recorder := record .NewFakeRecorder (100 )
422
+ resourceLockConfig := rl.ResourceLockConfig {
423
+ Identity : "baz" ,
424
+ EventRecorder : recorder ,
425
+ }
426
+ c := & fake.Clientset {}
427
+ for _ , reactor := range test .reactors {
428
+ c .AddReactor (reactor .verb , objectType , reactor .reaction )
429
+ }
430
+ c .AddReactor ("*" , "*" , func (action fakeclient.Action ) (bool , runtime.Object , error ) {
431
+ t .Errorf ("unreachable action. testclient called too many times: %+v" , action )
432
+ return true , nil , fmt .Errorf ("unreachable action" )
433
+ })
434
+
435
+ lock = & rl.LeaseLock {
436
+ LeaseMeta : objectMeta ,
437
+ LockConfig : resourceLockConfig ,
438
+ Client : c .CoordinationV1 (),
439
+ }
440
+ lec := LeaderElectionConfig {
441
+ Lock : lock ,
442
+ LeaseDuration : 10 * time .Second ,
443
+ Callbacks : LeaderCallbacks {
444
+ OnNewLeader : func (l string ) {
445
+ defer wg .Done ()
446
+ reportedLeader = l
447
+ },
448
+ },
449
+ Coordinated : true ,
450
+ }
451
+ observedRawRecord := GetRawRecordOrDie (t , objectType , test .observedRecord )
452
+ le := & LeaderElector {
453
+ config : lec ,
454
+ observedRecord : test .observedRecord ,
455
+ observedRawRecord : observedRawRecord ,
456
+ observedTime : test .observedTime ,
457
+ clock : clock ,
458
+ metrics : globalMetricsFactory .newLeaderMetrics (),
459
+ }
460
+ if test .expectSuccess != le .tryCoordinatedRenew (context .Background ()) {
461
+ if test .retryAfter != 0 {
462
+ time .Sleep (test .retryAfter )
463
+ if test .expectSuccess != le .tryCoordinatedRenew (context .Background ()) {
464
+ t .Errorf ("unexpected result of tryCoordinatedRenew: [succeeded=%v]" , ! test .expectSuccess )
465
+ }
466
+ } else {
467
+ t .Errorf ("unexpected result of gryCoordinatedRenew: [succeeded=%v]" , ! test .expectSuccess )
468
+ }
469
+ }
470
+
471
+ le .observedRecord .AcquireTime = metav1.Time {}
472
+ le .observedRecord .RenewTime = metav1.Time {}
473
+ if le .observedRecord .HolderIdentity != test .outHolder {
474
+ t .Errorf ("expected holder:\n \t %+v\n got:\n \t %+v" , test .outHolder , le .observedRecord .HolderIdentity )
475
+ }
476
+ if len (test .reactors ) != len (c .Actions ()) {
477
+ t .Errorf ("wrong number of api interactions" )
478
+ }
479
+ if test .transitionLeader && le .observedRecord .LeaderTransitions != 1 {
480
+ t .Errorf ("leader should have transitioned but did not" )
481
+ }
482
+ if ! test .transitionLeader && le .observedRecord .LeaderTransitions != 0 {
483
+ t .Errorf ("leader should not have transitioned but did" )
484
+ }
485
+
486
+ le .maybeReportTransition ()
487
+ wg .Wait ()
488
+ if reportedLeader != test .outHolder {
489
+ t .Errorf ("reported leader was not the new leader. expected %q, got %q" , test .outHolder , reportedLeader )
490
+ }
491
+ assertEqualEvents (t , test .expectedEvents , recorder .Events )
492
+ })
493
+ }
494
+ }
495
+
356
496
// Will test leader election using lease as the resource
357
497
func TestTryAcquireOrRenewLeases (t * testing.T ) {
358
498
testTryAcquireOrRenew (t , "leases" )
0 commit comments