@@ -917,3 +917,158 @@ func TestTryAcquireOrRenewEndpointsLeases(t *testing.T) {
917
917
func TestTryAcquireOrRenewConfigMapsLeases (t * testing.T ) {
918
918
testTryAcquireOrRenewMultiLock (t , "configmapsleases" )
919
919
}
920
+
921
+ func testReleaseLease (t * testing.T , objectType string ) {
922
+ tests := []struct {
923
+ name string
924
+ observedRecord rl.LeaderElectionRecord
925
+ observedTime time.Time
926
+ reactors []Reactor
927
+
928
+ expectSuccess bool
929
+ transitionLeader bool
930
+ outHolder string
931
+ }{
932
+ {
933
+ name : "release acquired lock from no object" ,
934
+ reactors : []Reactor {
935
+ {
936
+ verb : "get" ,
937
+ objectType : objectType ,
938
+ reaction : func (action fakeclient.Action ) (handled bool , ret runtime.Object , err error ) {
939
+ return true , nil , errors .NewNotFound (action .(fakeclient.GetAction ).GetResource ().GroupResource (), action .(fakeclient.GetAction ).GetName ())
940
+ },
941
+ },
942
+ {
943
+ verb : "create" ,
944
+ objectType : objectType ,
945
+ reaction : func (action fakeclient.Action ) (handled bool , ret runtime.Object , err error ) {
946
+ return true , action .(fakeclient.CreateAction ).GetObject (), nil
947
+ },
948
+ },
949
+ {
950
+ verb : "update" ,
951
+ objectType : objectType ,
952
+ reaction : func (action fakeclient.Action ) (handled bool , ret runtime.Object , err error ) {
953
+ return true , action .(fakeclient.UpdateAction ).GetObject (), nil
954
+ },
955
+ },
956
+ },
957
+ expectSuccess : true ,
958
+ outHolder : "" ,
959
+ },
960
+ }
961
+
962
+ for i := range tests {
963
+ test := & tests [i ]
964
+ t .Run (test .name , func (t * testing.T ) {
965
+ // OnNewLeader is called async so we have to wait for it.
966
+ var wg sync.WaitGroup
967
+ wg .Add (1 )
968
+ var reportedLeader string
969
+ var lock rl.Interface
970
+
971
+ objectMeta := metav1.ObjectMeta {Namespace : "foo" , Name : "bar" }
972
+ resourceLockConfig := rl.ResourceLockConfig {
973
+ Identity : "baz" ,
974
+ EventRecorder : & record.FakeRecorder {},
975
+ }
976
+ c := & fake.Clientset {}
977
+ for _ , reactor := range test .reactors {
978
+ c .AddReactor (reactor .verb , objectType , reactor .reaction )
979
+ }
980
+ c .AddReactor ("*" , "*" , func (action fakeclient.Action ) (bool , runtime.Object , error ) {
981
+ t .Errorf ("unreachable action. testclient called too many times: %+v" , action )
982
+ return true , nil , fmt .Errorf ("unreachable action" )
983
+ })
984
+
985
+ switch objectType {
986
+ case "endpoints" :
987
+ lock = & rl.EndpointsLock {
988
+ EndpointsMeta : objectMeta ,
989
+ LockConfig : resourceLockConfig ,
990
+ Client : c .CoreV1 (),
991
+ }
992
+ case "configmaps" :
993
+ lock = & rl.ConfigMapLock {
994
+ ConfigMapMeta : objectMeta ,
995
+ LockConfig : resourceLockConfig ,
996
+ Client : c .CoreV1 (),
997
+ }
998
+ case "leases" :
999
+ lock = & rl.LeaseLock {
1000
+ LeaseMeta : objectMeta ,
1001
+ LockConfig : resourceLockConfig ,
1002
+ Client : c .CoordinationV1 (),
1003
+ }
1004
+ }
1005
+
1006
+ lec := LeaderElectionConfig {
1007
+ Lock : lock ,
1008
+ LeaseDuration : 10 * time .Second ,
1009
+ Callbacks : LeaderCallbacks {
1010
+ OnNewLeader : func (l string ) {
1011
+ defer wg .Done ()
1012
+ reportedLeader = l
1013
+ },
1014
+ },
1015
+ }
1016
+ observedRawRecord := GetRawRecordOrDie (t , objectType , test .observedRecord )
1017
+ le := & LeaderElector {
1018
+ config : lec ,
1019
+ observedRecord : test .observedRecord ,
1020
+ observedRawRecord : observedRawRecord ,
1021
+ observedTime : test .observedTime ,
1022
+ clock : clock.RealClock {},
1023
+ }
1024
+ if ! le .tryAcquireOrRenew (context .Background ()) {
1025
+ t .Errorf ("unexpected result of tryAcquireOrRenew: [succeeded=%v]" , true )
1026
+ }
1027
+
1028
+ le .maybeReportTransition ()
1029
+
1030
+ // Wait for a response to the leader transition, and add 1 so that we can track the final transition.
1031
+ wg .Wait ()
1032
+ wg .Add (1 )
1033
+
1034
+ if test .expectSuccess != le .release () {
1035
+ t .Errorf ("unexpected result of release: [succeeded=%v]" , ! test .expectSuccess )
1036
+ }
1037
+
1038
+ le .observedRecord .AcquireTime = metav1.Time {}
1039
+ le .observedRecord .RenewTime = metav1.Time {}
1040
+ if le .observedRecord .HolderIdentity != test .outHolder {
1041
+ t .Errorf ("expected holder:\n \t %+v\n got:\n \t %+v" , test .outHolder , le .observedRecord .HolderIdentity )
1042
+ }
1043
+ if len (test .reactors ) != len (c .Actions ()) {
1044
+ t .Errorf ("wrong number of api interactions" )
1045
+ }
1046
+ if test .transitionLeader && le .observedRecord .LeaderTransitions != 1 {
1047
+ t .Errorf ("leader should have transitioned but did not" )
1048
+ }
1049
+ if ! test .transitionLeader && le .observedRecord .LeaderTransitions != 0 {
1050
+ t .Errorf ("leader should not have transitioned but did" )
1051
+ }
1052
+ le .maybeReportTransition ()
1053
+ wg .Wait ()
1054
+ if reportedLeader != test .outHolder {
1055
+ t .Errorf ("reported leader was not the new leader. expected %q, got %q" , test .outHolder , reportedLeader )
1056
+ }
1057
+ })
1058
+ }
1059
+ }
1060
+
1061
+ // Will test leader election using endpoints as the resource
1062
+ func TestReleaseLeaseEndpoints (t * testing.T ) {
1063
+ testReleaseLease (t , "endpoints" )
1064
+ }
1065
+
1066
+ // Will test leader election using endpoints as the resource
1067
+ func TestReleaseLeaseConfigMaps (t * testing.T ) {
1068
+ testReleaseLease (t , "configmaps" )
1069
+ }
1070
+
1071
+ // Will test leader election using endpoints as the resource
1072
+ func TestReleaseLeaseLeases (t * testing.T ) {
1073
+ testReleaseLease (t , "leases" )
1074
+ }
0 commit comments