...

Source file src/k8s.io/utils/clock/testing/fake_clock.go

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

View as plain text