blob: 65bec2f8fa679a6e47898797796a0b667dc1fa68 [file]
// Copyright 2025 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
// Minimal fake clock for testing, based on
// https://github.com/kubernetes/utils/blob/master/clock/testing/fake_clock.go
import (
"sync"
"time"
)
type fakeClock struct {
lock sync.Mutex
time time.Time
waiters []*fakeClockWaiter
}
type fakeClockWaiter struct {
targetTime time.Time
destChan chan time.Time
}
func newFakeClock() *fakeClock {
return &fakeClock{time: time.Now()}
}
func (f *fakeClock) NewTimer(d time.Duration) Timer {
f.lock.Lock()
defer f.lock.Unlock()
ch := make(chan time.Time, 1)
timer := &fakeTimer{
fakeClock: f,
waiter: fakeClockWaiter{
targetTime: f.time.Add(d),
destChan: ch,
},
}
f.waiters = append(f.waiters, &timer.waiter)
return timer
}
func (f *fakeClock) Advance(d time.Duration) {
f.lock.Lock()
defer f.lock.Unlock()
f.time = f.time.Add(d)
newWaiters := make([]*fakeClockWaiter, 0, len(f.waiters))
for _, w := range f.waiters {
if !w.targetTime.After(f.time) {
w.destChan <- f.time
} else {
newWaiters = append(newWaiters, w)
}
}
f.waiters = newWaiters
}
type fakeTimer struct {
fakeClock *fakeClock
waiter fakeClockWaiter
}
func (t *fakeTimer) Chan() <-chan time.Time {
return t.waiter.destChan
}
func (t *fakeTimer) Stop() bool {
t.fakeClock.lock.Lock()
defer t.fakeClock.lock.Unlock()
active := false
newWaiters := make([]*fakeClockWaiter, 0, len(t.fakeClock.waiters))
for _, w := range t.fakeClock.waiters {
if w != &t.waiter {
newWaiters = append(newWaiters, w)
} else {
active = true
}
}
t.fakeClock.waiters = newWaiters
return active
}
func (t *fakeTimer) Reset(d time.Duration) bool {
t.fakeClock.lock.Lock()
defer t.fakeClock.lock.Unlock()
active := false
t.waiter.targetTime = t.fakeClock.time.Add(d)
for _, w := range t.fakeClock.waiters {
if w == &t.waiter {
// If timer is found, it has not been fired yet.
active = true
break
}
}
if !active {
t.fakeClock.waiters = append(t.fakeClock.waiters, &t.waiter)
}
return active
}