k8s.io/client-go@v0.31.1/tools/leaderelection/healthzadaptor_test.go (about) 1 /* 2 Copyright 2015 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package leaderelection 18 19 import ( 20 "context" 21 "fmt" 22 "testing" 23 "time" 24 25 "net/http" 26 27 rl "k8s.io/client-go/tools/leaderelection/resourcelock" 28 testingclock "k8s.io/utils/clock/testing" 29 ) 30 31 type fakeLock struct { 32 identity string 33 } 34 35 // Get is a dummy to allow us to have a fakeLock for testing. 36 func (fl *fakeLock) Get(ctx context.Context) (ler *rl.LeaderElectionRecord, rawRecord []byte, err error) { 37 return nil, nil, nil 38 } 39 40 // Create is a dummy to allow us to have a fakeLock for testing. 41 func (fl *fakeLock) Create(ctx context.Context, ler rl.LeaderElectionRecord) error { 42 return nil 43 } 44 45 // Update is a dummy to allow us to have a fakeLock for testing. 46 func (fl *fakeLock) Update(ctx context.Context, ler rl.LeaderElectionRecord) error { 47 return nil 48 } 49 50 // RecordEvent is a dummy to allow us to have a fakeLock for testing. 51 func (fl *fakeLock) RecordEvent(string) {} 52 53 // Identity is a dummy to allow us to have a fakeLock for testing. 54 func (fl *fakeLock) Identity() string { 55 return fl.identity 56 } 57 58 // Describe is a dummy to allow us to have a fakeLock for testing. 59 func (fl *fakeLock) Describe() string { 60 return "Dummy implementation of lock for testing" 61 } 62 63 // TestLeaderElectionHealthChecker tests that the healthcheck for leader election handles its edge cases. 64 func TestLeaderElectionHealthChecker(t *testing.T) { 65 current := time.Now() 66 req := &http.Request{} 67 68 tests := []struct { 69 description string 70 expected error 71 adaptorTimeout time.Duration 72 elector *LeaderElector 73 }{ 74 { 75 description: "call check before leader elector initialized", 76 expected: nil, 77 adaptorTimeout: time.Second * 20, 78 elector: nil, 79 }, 80 { 81 description: "call check when the lease is far expired", 82 expected: fmt.Errorf("failed election to renew leadership on lease %s", "foo"), 83 adaptorTimeout: time.Second * 20, 84 elector: &LeaderElector{ 85 config: LeaderElectionConfig{ 86 Lock: &fakeLock{identity: "healthTest"}, 87 LeaseDuration: time.Minute, 88 Name: "foo", 89 }, 90 observedRecord: rl.LeaderElectionRecord{ 91 HolderIdentity: "healthTest", 92 }, 93 observedTime: current, 94 clock: testingclock.NewFakeClock(current.Add(time.Hour)), 95 }, 96 }, 97 { 98 description: "call check when the lease is far expired but held by another server", 99 expected: nil, 100 adaptorTimeout: time.Second * 20, 101 elector: &LeaderElector{ 102 config: LeaderElectionConfig{ 103 Lock: &fakeLock{identity: "healthTest"}, 104 LeaseDuration: time.Minute, 105 Name: "foo", 106 }, 107 observedRecord: rl.LeaderElectionRecord{ 108 HolderIdentity: "otherServer", 109 }, 110 observedTime: current, 111 clock: testingclock.NewFakeClock(current.Add(time.Hour)), 112 }, 113 }, 114 { 115 description: "call check when the lease is not expired", 116 expected: nil, 117 adaptorTimeout: time.Second * 20, 118 elector: &LeaderElector{ 119 config: LeaderElectionConfig{ 120 Lock: &fakeLock{identity: "healthTest"}, 121 LeaseDuration: time.Minute, 122 Name: "foo", 123 }, 124 observedRecord: rl.LeaderElectionRecord{ 125 HolderIdentity: "healthTest", 126 }, 127 observedTime: current, 128 clock: testingclock.NewFakeClock(current), 129 }, 130 }, 131 { 132 description: "call check when the lease is expired but inside the timeout", 133 expected: nil, 134 adaptorTimeout: time.Second * 20, 135 elector: &LeaderElector{ 136 config: LeaderElectionConfig{ 137 Lock: &fakeLock{identity: "healthTest"}, 138 LeaseDuration: time.Minute, 139 Name: "foo", 140 }, 141 observedRecord: rl.LeaderElectionRecord{ 142 HolderIdentity: "healthTest", 143 }, 144 observedTime: current, 145 clock: testingclock.NewFakeClock(current.Add(time.Minute).Add(time.Second)), 146 }, 147 }, 148 } 149 150 for _, test := range tests { 151 adaptor := NewLeaderHealthzAdaptor(test.adaptorTimeout) 152 if adaptor.le != nil { 153 t.Errorf("[%s] leaderChecker started with a LeaderElector %v", test.description, adaptor.le) 154 } 155 if test.elector != nil { 156 test.elector.config.WatchDog = adaptor 157 adaptor.SetLeaderElection(test.elector) 158 if adaptor.le == nil { 159 t.Errorf("[%s] adaptor failed to set the LeaderElector", test.description) 160 } 161 } 162 err := adaptor.Check(req) 163 if test.expected == nil { 164 if err == nil { 165 continue 166 } 167 t.Errorf("[%s] called check, expected no error but received \"%v\"", test.description, err) 168 } else { 169 if err == nil { 170 t.Errorf("[%s] called check and failed to received the expected error \"%v\"", test.description, test.expected) 171 } 172 if err.Error() != test.expected.Error() { 173 t.Errorf("[%s] called check, expected %v, received %v", test.description, test.expected, err) 174 } 175 } 176 } 177 }