github.com/kubernetes/utils@v0.0.0-20190308190857-21c4ce38f2a7/clock/testing/fake_clock.go (about)

     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.Clock(&FakeClock{})
    28  	_ = clock.Clock(&IntervalClock{})
    29  )
    30  
    31  // FakeClock implements clock.Clock, but returns an arbitrary time.
    32  type FakeClock struct {
    33  	lock sync.RWMutex
    34  	time time.Time
    35  
    36  	// waiters are waiting for the fake time to pass their specified time
    37  	waiters []*fakeClockWaiter
    38  }
    39  
    40  type fakeClockWaiter struct {
    41  	targetTime    time.Time
    42  	stepInterval  time.Duration
    43  	skipIfBlocked bool
    44  	destChan      chan time.Time
    45  	fired         bool
    46  }
    47  
    48  // NewFakeClock constructs a fake clock set to the provided time.
    49  func NewFakeClock(t time.Time) *FakeClock {
    50  	return &FakeClock{
    51  		time: t,
    52  	}
    53  }
    54  
    55  // Now returns f's time.
    56  func (f *FakeClock) Now() time.Time {
    57  	f.lock.RLock()
    58  	defer f.lock.RUnlock()
    59  	return f.time
    60  }
    61  
    62  // Since returns time since the time in f.
    63  func (f *FakeClock) Since(ts time.Time) time.Duration {
    64  	f.lock.RLock()
    65  	defer f.lock.RUnlock()
    66  	return f.time.Sub(ts)
    67  }
    68  
    69  // After is the fake version of time.After(d).
    70  func (f *FakeClock) After(d time.Duration) <-chan time.Time {
    71  	f.lock.Lock()
    72  	defer f.lock.Unlock()
    73  	stopTime := f.time.Add(d)
    74  	ch := make(chan time.Time, 1) // Don't block!
    75  	f.waiters = append(f.waiters, &fakeClockWaiter{
    76  		targetTime: stopTime,
    77  		destChan:   ch,
    78  	})
    79  	return ch
    80  }
    81  
    82  // NewTimer constructs a fake timer, akin to time.NewTimer(d).
    83  func (f *FakeClock) NewTimer(d time.Duration) clock.Timer {
    84  	f.lock.Lock()
    85  	defer f.lock.Unlock()
    86  	stopTime := f.time.Add(d)
    87  	ch := make(chan time.Time, 1) // Don't block!
    88  	timer := &fakeTimer{
    89  		fakeClock: f,
    90  		waiter: fakeClockWaiter{
    91  			targetTime: stopTime,
    92  			destChan:   ch,
    93  		},
    94  	}
    95  	f.waiters = append(f.waiters, &timer.waiter)
    96  	return timer
    97  }
    98  
    99  // Tick constructs a fake ticker, akin to time.Tick
   100  func (f *FakeClock) Tick(d time.Duration) <-chan time.Time {
   101  	if d <= 0 {
   102  		return nil
   103  	}
   104  	f.lock.Lock()
   105  	defer f.lock.Unlock()
   106  	tickTime := f.time.Add(d)
   107  	ch := make(chan time.Time, 1) // hold one tick
   108  	f.waiters = append(f.waiters, &fakeClockWaiter{
   109  		targetTime:    tickTime,
   110  		stepInterval:  d,
   111  		skipIfBlocked: true,
   112  		destChan:      ch,
   113  	})
   114  
   115  	return ch
   116  }
   117  
   118  // Step moves the clock by Duration and notifies anyone that's called After,
   119  // Tick, or NewTimer.
   120  func (f *FakeClock) Step(d time.Duration) {
   121  	f.lock.Lock()
   122  	defer f.lock.Unlock()
   123  	f.setTimeLocked(f.time.Add(d))
   124  }
   125  
   126  // SetTime sets the time.
   127  func (f *FakeClock) SetTime(t time.Time) {
   128  	f.lock.Lock()
   129  	defer f.lock.Unlock()
   130  	f.setTimeLocked(t)
   131  }
   132  
   133  // Actually changes the time and checks any waiters. f must be write-locked.
   134  func (f *FakeClock) setTimeLocked(t time.Time) {
   135  	f.time = t
   136  	newWaiters := make([]*fakeClockWaiter, 0, len(f.waiters))
   137  	for i := range f.waiters {
   138  		w := f.waiters[i]
   139  		if !w.targetTime.After(t) {
   140  
   141  			if w.skipIfBlocked {
   142  				select {
   143  				case w.destChan <- t:
   144  					w.fired = true
   145  				default:
   146  				}
   147  			} else {
   148  				w.destChan <- t
   149  				w.fired = true
   150  			}
   151  
   152  			if w.stepInterval > 0 {
   153  				for !w.targetTime.After(t) {
   154  					w.targetTime = w.targetTime.Add(w.stepInterval)
   155  				}
   156  				newWaiters = append(newWaiters, w)
   157  			}
   158  
   159  		} else {
   160  			newWaiters = append(newWaiters, f.waiters[i])
   161  		}
   162  	}
   163  	f.waiters = newWaiters
   164  }
   165  
   166  // HasWaiters returns true if After has been called on f but not yet satisfied (so you can
   167  // write race-free tests).
   168  func (f *FakeClock) HasWaiters() bool {
   169  	f.lock.RLock()
   170  	defer f.lock.RUnlock()
   171  	return len(f.waiters) > 0
   172  }
   173  
   174  // Sleep is akin to time.Sleep
   175  func (f *FakeClock) Sleep(d time.Duration) {
   176  	f.Step(d)
   177  }
   178  
   179  // IntervalClock implements clock.Clock, but each invocation of Now steps the clock forward the specified duration
   180  type IntervalClock struct {
   181  	Time     time.Time
   182  	Duration time.Duration
   183  }
   184  
   185  // Now returns i's time.
   186  func (i *IntervalClock) Now() time.Time {
   187  	i.Time = i.Time.Add(i.Duration)
   188  	return i.Time
   189  }
   190  
   191  // Since returns time since the time in i.
   192  func (i *IntervalClock) Since(ts time.Time) time.Duration {
   193  	return i.Time.Sub(ts)
   194  }
   195  
   196  // After is unimplemented, will panic.
   197  // TODO: make interval clock use FakeClock so this can be implemented.
   198  func (*IntervalClock) After(d time.Duration) <-chan time.Time {
   199  	panic("IntervalClock doesn't implement After")
   200  }
   201  
   202  // NewTimer is unimplemented, will panic.
   203  // TODO: make interval clock use FakeClock so this can be implemented.
   204  func (*IntervalClock) NewTimer(d time.Duration) clock.Timer {
   205  	panic("IntervalClock doesn't implement NewTimer")
   206  }
   207  
   208  // Tick is unimplemented, will panic.
   209  // TODO: make interval clock use FakeClock so this can be implemented.
   210  func (*IntervalClock) Tick(d time.Duration) <-chan time.Time {
   211  	panic("IntervalClock doesn't implement Tick")
   212  }
   213  
   214  // Sleep is unimplemented, will panic.
   215  func (*IntervalClock) Sleep(d time.Duration) {
   216  	panic("IntervalClock doesn't implement Sleep")
   217  }
   218  
   219  var _ = clock.Timer(&fakeTimer{})
   220  
   221  // fakeTimer implements clock.Timer based on a FakeClock.
   222  type fakeTimer struct {
   223  	fakeClock *FakeClock
   224  	waiter    fakeClockWaiter
   225  }
   226  
   227  // C returns the channel that notifies when this timer has fired.
   228  func (f *fakeTimer) C() <-chan time.Time {
   229  	return f.waiter.destChan
   230  }
   231  
   232  // Stop stops the timer and returns true if the timer has not yet fired, or false otherwise.
   233  func (f *fakeTimer) Stop() bool {
   234  	f.fakeClock.lock.Lock()
   235  	defer f.fakeClock.lock.Unlock()
   236  
   237  	newWaiters := make([]*fakeClockWaiter, 0, len(f.fakeClock.waiters))
   238  	for i := range f.fakeClock.waiters {
   239  		w := f.fakeClock.waiters[i]
   240  		if w != &f.waiter {
   241  			newWaiters = append(newWaiters, w)
   242  		}
   243  	}
   244  
   245  	f.fakeClock.waiters = newWaiters
   246  
   247  	return !f.waiter.fired
   248  }
   249  
   250  // Reset resets the timer to the fake clock's "now" + d. It returns true if the timer has not yet
   251  // fired, or false otherwise.
   252  func (f *fakeTimer) Reset(d time.Duration) bool {
   253  	f.fakeClock.lock.Lock()
   254  	defer f.fakeClock.lock.Unlock()
   255  
   256  	active := !f.waiter.fired
   257  
   258  	f.waiter.fired = false
   259  	f.waiter.targetTime = f.fakeClock.time.Add(d)
   260  
   261  	var isWaiting bool
   262  	for i := range f.fakeClock.waiters {
   263  		w := f.fakeClock.waiters[i]
   264  		if w == &f.waiter {
   265  			isWaiting = true
   266  			break
   267  		}
   268  	}
   269  	if !isWaiting {
   270  		f.fakeClock.waiters = append(f.fakeClock.waiters, &f.waiter)
   271  	}
   272  
   273  	return active
   274  }