...

Source file src/k8s.io/klog/v2/internal/clock/testing/fake_clock.go

Documentation: k8s.io/klog/v2/internal/clock/testing

     1  /*
     2  Copyright 2014 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 testing
    18  
    19  import (
    20  	"sync"
    21  	"time"
    22  
    23  	"k8s.io/klog/v2/internal/clock"
    24  )
    25  
    26  var (
    27  	_ = clock.PassiveClock(&FakePassiveClock{})
    28  	_ = clock.Clock(&IntervalClock{})
    29  )
    30  
    31  // FakePassiveClock implements PassiveClock, but returns an arbitrary time.
    32  type FakePassiveClock struct {
    33  	lock sync.RWMutex
    34  	time time.Time
    35  }
    36  
    37  // FakeClock implements clock.Clock, but returns an arbitrary time.
    38  type FakeClock struct {
    39  	FakePassiveClock
    40  
    41  	// waiters are waiting for the fake time to pass their specified time
    42  	waiters []*fakeClockWaiter
    43  }
    44  
    45  type fakeClockWaiter struct {
    46  	targetTime    time.Time
    47  	stepInterval  time.Duration
    48  	skipIfBlocked bool
    49  	destChan      chan time.Time
    50  	fired         bool
    51  	afterFunc     func()
    52  }
    53  
    54  // NewFakePassiveClock returns a new FakePassiveClock.
    55  func NewFakePassiveClock(t time.Time) *FakePassiveClock {
    56  	return &FakePassiveClock{
    57  		time: t,
    58  	}
    59  }
    60  
    61  // NewFakeClock constructs a fake clock set to the provided time.
    62  func NewFakeClock(t time.Time) *FakeClock {
    63  	return &FakeClock{
    64  		FakePassiveClock: *NewFakePassiveClock(t),
    65  	}
    66  }
    67  
    68  // Now returns f's time.
    69  func (f *FakePassiveClock) Now() time.Time {
    70  	f.lock.RLock()
    71  	defer f.lock.RUnlock()
    72  	return f.time
    73  }
    74  
    75  // Since returns time since the time in f.
    76  func (f *FakePassiveClock) Since(ts time.Time) time.Duration {
    77  	f.lock.RLock()
    78  	defer f.lock.RUnlock()
    79  	return f.time.Sub(ts)
    80  }
    81  
    82  // SetTime sets the time on the FakePassiveClock.
    83  func (f *FakePassiveClock) SetTime(t time.Time) {
    84  	f.lock.Lock()
    85  	defer f.lock.Unlock()
    86  	f.time = t
    87  }
    88  
    89  // After is the fake version of time.After(d).
    90  func (f *FakeClock) After(d time.Duration) <-chan time.Time {
    91  	f.lock.Lock()
    92  	defer f.lock.Unlock()
    93  	stopTime := f.time.Add(d)
    94  	ch := make(chan time.Time, 1) // Don't block!
    95  	f.waiters = append(f.waiters, &fakeClockWaiter{
    96  		targetTime: stopTime,
    97  		destChan:   ch,
    98  	})
    99  	return ch
   100  }
   101  
   102  // NewTimer constructs a fake timer, akin to time.NewTimer(d).
   103  func (f *FakeClock) NewTimer(d time.Duration) clock.Timer {
   104  	f.lock.Lock()
   105  	defer f.lock.Unlock()
   106  	stopTime := f.time.Add(d)
   107  	ch := make(chan time.Time, 1) // Don't block!
   108  	timer := &fakeTimer{
   109  		fakeClock: f,
   110  		waiter: fakeClockWaiter{
   111  			targetTime: stopTime,
   112  			destChan:   ch,
   113  		},
   114  	}
   115  	f.waiters = append(f.waiters, &timer.waiter)
   116  	return timer
   117  }
   118  
   119  // AfterFunc is the Fake version of time.AfterFunc(d, cb).
   120  func (f *FakeClock) AfterFunc(d time.Duration, cb func()) clock.Timer {
   121  	f.lock.Lock()
   122  	defer f.lock.Unlock()
   123  	stopTime := f.time.Add(d)
   124  	ch := make(chan time.Time, 1) // Don't block!
   125  
   126  	timer := &fakeTimer{
   127  		fakeClock: f,
   128  		waiter: fakeClockWaiter{
   129  			targetTime: stopTime,
   130  			destChan:   ch,
   131  			afterFunc:  cb,
   132  		},
   133  	}
   134  	f.waiters = append(f.waiters, &timer.waiter)
   135  	return timer
   136  }
   137  
   138  // Tick constructs a fake ticker, akin to time.Tick
   139  func (f *FakeClock) Tick(d time.Duration) <-chan time.Time {
   140  	if d <= 0 {
   141  		return nil
   142  	}
   143  	f.lock.Lock()
   144  	defer f.lock.Unlock()
   145  	tickTime := f.time.Add(d)
   146  	ch := make(chan time.Time, 1) // hold one tick
   147  	f.waiters = append(f.waiters, &fakeClockWaiter{
   148  		targetTime:    tickTime,
   149  		stepInterval:  d,
   150  		skipIfBlocked: true,
   151  		destChan:      ch,
   152  	})
   153  
   154  	return ch
   155  }
   156  
   157  // NewTicker returns a new Ticker.
   158  func (f *FakeClock) NewTicker(d time.Duration) clock.Ticker {
   159  	f.lock.Lock()
   160  	defer f.lock.Unlock()
   161  	tickTime := f.time.Add(d)
   162  	ch := make(chan time.Time, 1) // hold one tick
   163  	f.waiters = append(f.waiters, &fakeClockWaiter{
   164  		targetTime:    tickTime,
   165  		stepInterval:  d,
   166  		skipIfBlocked: true,
   167  		destChan:      ch,
   168  	})
   169  
   170  	return &fakeTicker{
   171  		c: ch,
   172  	}
   173  }
   174  
   175  // Step moves the clock by Duration and notifies anyone that's called After,
   176  // Tick, or NewTimer.
   177  func (f *FakeClock) Step(d time.Duration) {
   178  	f.lock.Lock()
   179  	defer f.lock.Unlock()
   180  	f.setTimeLocked(f.time.Add(d))
   181  }
   182  
   183  // SetTime sets the time.
   184  func (f *FakeClock) SetTime(t time.Time) {
   185  	f.lock.Lock()
   186  	defer f.lock.Unlock()
   187  	f.setTimeLocked(t)
   188  }
   189  
   190  // Actually changes the time and checks any waiters. f must be write-locked.
   191  func (f *FakeClock) setTimeLocked(t time.Time) {
   192  	f.time = t
   193  	newWaiters := make([]*fakeClockWaiter, 0, len(f.waiters))
   194  	for i := range f.waiters {
   195  		w := f.waiters[i]
   196  		if !w.targetTime.After(t) {
   197  			if w.skipIfBlocked {
   198  				select {
   199  				case w.destChan <- t:
   200  					w.fired = true
   201  				default:
   202  				}
   203  			} else {
   204  				w.destChan <- t
   205  				w.fired = true
   206  			}
   207  
   208  			if w.afterFunc != nil {
   209  				w.afterFunc()
   210  			}
   211  
   212  			if w.stepInterval > 0 {
   213  				for !w.targetTime.After(t) {
   214  					w.targetTime = w.targetTime.Add(w.stepInterval)
   215  				}
   216  				newWaiters = append(newWaiters, w)
   217  			}
   218  
   219  		} else {
   220  			newWaiters = append(newWaiters, f.waiters[i])
   221  		}
   222  	}
   223  	f.waiters = newWaiters
   224  }
   225  
   226  // HasWaiters returns true if After or AfterFunc has been called on f but not yet satisfied (so you can
   227  // write race-free tests).
   228  func (f *FakeClock) HasWaiters() bool {
   229  	f.lock.RLock()
   230  	defer f.lock.RUnlock()
   231  	return len(f.waiters) > 0
   232  }
   233  
   234  // Sleep is akin to time.Sleep
   235  func (f *FakeClock) Sleep(d time.Duration) {
   236  	f.Step(d)
   237  }
   238  
   239  // IntervalClock implements clock.PassiveClock, but each invocation of Now steps the clock forward the specified duration.
   240  // IntervalClock technically implements the other methods of clock.Clock, but each implementation is just a panic.
   241  //
   242  // Deprecated: See SimpleIntervalClock for an alternative that only has the methods of PassiveClock.
   243  type IntervalClock struct {
   244  	Time     time.Time
   245  	Duration time.Duration
   246  }
   247  
   248  // Now returns i's time.
   249  func (i *IntervalClock) Now() time.Time {
   250  	i.Time = i.Time.Add(i.Duration)
   251  	return i.Time
   252  }
   253  
   254  // Since returns time since the time in i.
   255  func (i *IntervalClock) Since(ts time.Time) time.Duration {
   256  	return i.Time.Sub(ts)
   257  }
   258  
   259  // After is unimplemented, will panic.
   260  // TODO: make interval clock use FakeClock so this can be implemented.
   261  func (*IntervalClock) After(time.Duration) <-chan time.Time {
   262  	panic("IntervalClock doesn't implement After")
   263  }
   264  
   265  // NewTimer is unimplemented, will panic.
   266  // TODO: make interval clock use FakeClock so this can be implemented.
   267  func (*IntervalClock) NewTimer(time.Duration) clock.Timer {
   268  	panic("IntervalClock doesn't implement NewTimer")
   269  }
   270  
   271  // AfterFunc is unimplemented, will panic.
   272  // TODO: make interval clock use FakeClock so this can be implemented.
   273  func (*IntervalClock) AfterFunc(time.Duration, func()) clock.Timer {
   274  	panic("IntervalClock doesn't implement AfterFunc")
   275  }
   276  
   277  // NewTicker has no implementation yet and is omitted.
   278  // TODO: make interval clock use FakeClock so this can be implemented.
   279  func (*IntervalClock) NewTicker(time.Duration) clock.Ticker {
   280  	panic("IntervalClock doesn't implement NewTicker")
   281  }
   282  
   283  // Sleep is unimplemented, will panic.
   284  func (*IntervalClock) Sleep(time.Duration) {
   285  	panic("IntervalClock doesn't implement Sleep")
   286  }
   287  
   288  var _ = clock.Timer(&fakeTimer{})
   289  
   290  // fakeTimer implements clock.Timer based on a FakeClock.
   291  type fakeTimer struct {
   292  	fakeClock *FakeClock
   293  	waiter    fakeClockWaiter
   294  }
   295  
   296  // C returns the channel that notifies when this timer has fired.
   297  func (f *fakeTimer) C() <-chan time.Time {
   298  	return f.waiter.destChan
   299  }
   300  
   301  // Stop stops the timer and returns true if the timer has not yet fired, or false otherwise.
   302  func (f *fakeTimer) Stop() bool {
   303  	f.fakeClock.lock.Lock()
   304  	defer f.fakeClock.lock.Unlock()
   305  
   306  	newWaiters := make([]*fakeClockWaiter, 0, len(f.fakeClock.waiters))
   307  	for i := range f.fakeClock.waiters {
   308  		w := f.fakeClock.waiters[i]
   309  		if w != &f.waiter {
   310  			newWaiters = append(newWaiters, w)
   311  		}
   312  	}
   313  
   314  	f.fakeClock.waiters = newWaiters
   315  
   316  	return !f.waiter.fired
   317  }
   318  
   319  // Reset resets the timer to the fake clock's "now" + d. It returns true if the timer has not yet
   320  // fired, or false otherwise.
   321  func (f *fakeTimer) Reset(d time.Duration) bool {
   322  	f.fakeClock.lock.Lock()
   323  	defer f.fakeClock.lock.Unlock()
   324  
   325  	active := !f.waiter.fired
   326  
   327  	f.waiter.fired = false
   328  	f.waiter.targetTime = f.fakeClock.time.Add(d)
   329  
   330  	var isWaiting bool
   331  	for i := range f.fakeClock.waiters {
   332  		w := f.fakeClock.waiters[i]
   333  		if w == &f.waiter {
   334  			isWaiting = true
   335  			break
   336  		}
   337  	}
   338  	if !isWaiting {
   339  		f.fakeClock.waiters = append(f.fakeClock.waiters, &f.waiter)
   340  	}
   341  
   342  	return active
   343  }
   344  
   345  type fakeTicker struct {
   346  	c <-chan time.Time
   347  }
   348  
   349  func (t *fakeTicker) C() <-chan time.Time {
   350  	return t.c
   351  }
   352  
   353  func (t *fakeTicker) Stop() {
   354  }
   355  

View as plain text