mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-06 02:34:03 +00:00
fake util.clock tick
This commit is contained in:
parent
290d970282
commit
bf097ea233
@ -28,6 +28,7 @@ type Clock interface {
|
|||||||
Since(time.Time) time.Duration
|
Since(time.Time) time.Duration
|
||||||
After(d time.Duration) <-chan time.Time
|
After(d time.Duration) <-chan time.Time
|
||||||
Sleep(d time.Duration)
|
Sleep(d time.Duration)
|
||||||
|
Tick(d time.Duration) <-chan time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -54,6 +55,10 @@ func (RealClock) After(d time.Duration) <-chan time.Time {
|
|||||||
return time.After(d)
|
return time.After(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (RealClock) Tick(d time.Duration) <-chan time.Time {
|
||||||
|
return time.Tick(d)
|
||||||
|
}
|
||||||
|
|
||||||
func (RealClock) Sleep(d time.Duration) {
|
func (RealClock) Sleep(d time.Duration) {
|
||||||
time.Sleep(d)
|
time.Sleep(d)
|
||||||
}
|
}
|
||||||
@ -68,8 +73,10 @@ type FakeClock struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type fakeClockWaiter struct {
|
type fakeClockWaiter struct {
|
||||||
targetTime time.Time
|
targetTime time.Time
|
||||||
destChan chan<- time.Time
|
stepInterval time.Duration
|
||||||
|
skipIfBlocked bool
|
||||||
|
destChan chan<- time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFakeClock(t time.Time) *FakeClock {
|
func NewFakeClock(t time.Time) *FakeClock {
|
||||||
@ -105,7 +112,22 @@ func (f *FakeClock) After(d time.Duration) <-chan time.Time {
|
|||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move clock by Duration, notify anyone that's called After
|
func (f *FakeClock) Tick(d time.Duration) <-chan time.Time {
|
||||||
|
f.lock.Lock()
|
||||||
|
defer f.lock.Unlock()
|
||||||
|
tickTime := f.time.Add(d)
|
||||||
|
ch := make(chan time.Time, 1) // hold one tick
|
||||||
|
f.waiters = append(f.waiters, fakeClockWaiter{
|
||||||
|
targetTime: tickTime,
|
||||||
|
stepInterval: d,
|
||||||
|
skipIfBlocked: true,
|
||||||
|
destChan: ch,
|
||||||
|
})
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move clock by Duration, notify anyone that's called After or Tick
|
||||||
func (f *FakeClock) Step(d time.Duration) {
|
func (f *FakeClock) Step(d time.Duration) {
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
@ -126,7 +148,23 @@ func (f *FakeClock) setTimeLocked(t time.Time) {
|
|||||||
for i := range f.waiters {
|
for i := range f.waiters {
|
||||||
w := &f.waiters[i]
|
w := &f.waiters[i]
|
||||||
if !w.targetTime.After(t) {
|
if !w.targetTime.After(t) {
|
||||||
w.destChan <- t
|
|
||||||
|
if w.skipIfBlocked {
|
||||||
|
select {
|
||||||
|
case w.destChan <- t:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
w.destChan <- t
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.stepInterval > 0 {
|
||||||
|
for !w.targetTime.After(t) {
|
||||||
|
w.targetTime = w.targetTime.Add(w.stepInterval)
|
||||||
|
}
|
||||||
|
newWaiters = append(newWaiters, *w)
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
newWaiters = append(newWaiters, f.waiters[i])
|
newWaiters = append(newWaiters, f.waiters[i])
|
||||||
}
|
}
|
||||||
@ -169,6 +207,12 @@ func (*IntervalClock) After(d time.Duration) <-chan time.Time {
|
|||||||
panic("IntervalClock doesn't implement After")
|
panic("IntervalClock doesn't implement After")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unimplemented, will panic.
|
||||||
|
// TODO: make interval clock use FakeClock so this can be implemented.
|
||||||
|
func (*IntervalClock) Tick(d time.Duration) <-chan time.Time {
|
||||||
|
panic("IntervalClock doesn't implement Tick")
|
||||||
|
}
|
||||||
|
|
||||||
func (*IntervalClock) Sleep(d time.Duration) {
|
func (*IntervalClock) Sleep(d time.Duration) {
|
||||||
panic("IntervalClock doesn't implement Sleep")
|
panic("IntervalClock doesn't implement Sleep")
|
||||||
}
|
}
|
||||||
|
@ -104,3 +104,81 @@ func TestFakeAfter(t *testing.T) {
|
|||||||
t.Errorf("unexpected non-channel read")
|
t.Errorf("unexpected non-channel read")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFakeTick(t *testing.T) {
|
||||||
|
tc := NewFakeClock(time.Now())
|
||||||
|
if tc.HasWaiters() {
|
||||||
|
t.Errorf("unexpected waiter?")
|
||||||
|
}
|
||||||
|
oneSec := tc.Tick(time.Second)
|
||||||
|
if !tc.HasWaiters() {
|
||||||
|
t.Errorf("unexpected lack of waiter?")
|
||||||
|
}
|
||||||
|
|
||||||
|
oneOhOneSec := tc.Tick(time.Second + time.Millisecond)
|
||||||
|
twoSec := tc.Tick(2 * time.Second)
|
||||||
|
select {
|
||||||
|
case <-oneSec:
|
||||||
|
t.Errorf("unexpected channel read")
|
||||||
|
case <-oneOhOneSec:
|
||||||
|
t.Errorf("unexpected channel read")
|
||||||
|
case <-twoSec:
|
||||||
|
t.Errorf("unexpected channel read")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
tc.Step(999 * time.Millisecond) // t=.999
|
||||||
|
select {
|
||||||
|
case <-oneSec:
|
||||||
|
t.Errorf("unexpected channel read")
|
||||||
|
case <-oneOhOneSec:
|
||||||
|
t.Errorf("unexpected channel read")
|
||||||
|
case <-twoSec:
|
||||||
|
t.Errorf("unexpected channel read")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
tc.Step(time.Millisecond) // t=1.000
|
||||||
|
select {
|
||||||
|
case <-oneSec:
|
||||||
|
// Expected!
|
||||||
|
case <-oneOhOneSec:
|
||||||
|
t.Errorf("unexpected channel read")
|
||||||
|
case <-twoSec:
|
||||||
|
t.Errorf("unexpected channel read")
|
||||||
|
default:
|
||||||
|
t.Errorf("unexpected non-channel read")
|
||||||
|
}
|
||||||
|
tc.Step(time.Millisecond) // t=1.001
|
||||||
|
select {
|
||||||
|
case <-oneSec:
|
||||||
|
// should not double-trigger!
|
||||||
|
t.Errorf("unexpected channel read")
|
||||||
|
case <-oneOhOneSec:
|
||||||
|
// Expected!
|
||||||
|
case <-twoSec:
|
||||||
|
t.Errorf("unexpected channel read")
|
||||||
|
default:
|
||||||
|
t.Errorf("unexpected non-channel read")
|
||||||
|
}
|
||||||
|
|
||||||
|
tc.Step(time.Second) // t=2.001
|
||||||
|
tc.Step(time.Second) // t=3.001
|
||||||
|
tc.Step(time.Second) // t=4.001
|
||||||
|
tc.Step(time.Second) // t=5.001
|
||||||
|
|
||||||
|
// The one second ticker should not accumulate ticks
|
||||||
|
accumulatedTicks := 0
|
||||||
|
drained := false
|
||||||
|
for !drained {
|
||||||
|
select {
|
||||||
|
case <-oneSec:
|
||||||
|
accumulatedTicks++
|
||||||
|
default:
|
||||||
|
drained = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if accumulatedTicks != 1 {
|
||||||
|
t.Errorf("unexpected number of accumulated ticks: %d", accumulatedTicks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -41,7 +41,7 @@ func newDelayingQueue(clock util.Clock) DelayingInterface {
|
|||||||
ret := &delayingType{
|
ret := &delayingType{
|
||||||
Interface: New(),
|
Interface: New(),
|
||||||
clock: clock,
|
clock: clock,
|
||||||
heartbeat: time.Tick(maxWait),
|
heartbeat: clock.Tick(maxWait),
|
||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
waitingForAddCh: make(chan waitFor, 1000),
|
waitingForAddCh: make(chan waitFor, 1000),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user