github.com/mailgun/holster/v4@v4.20.0/clock/clock.go (about)

     1  // Package clock provides the same functions as the system package time. In
     2  // production it forwards all calls to the system time package, but in tests
     3  // the time can be frozen by calling Freeze function and from that point it has
     4  // to be advanced manually with Advance function making all scheduled calls
     5  // deterministic.
     6  //
     7  // The functions provided by the package have the same parameters and return
     8  // values as their system counterparts with a few exceptions. Where either
     9  // *time.Timer or *time.Ticker is returned by a system function, the clock
    10  // package counterpart returns clock.Timer or clock.Ticker interface
    11  // respectively. The interfaces provide API as respective structs except C is
    12  // not a channel, but a function that returns <-chan time.Time.
    13  package clock
    14  
    15  import (
    16  	"time"
    17  )
    18  
    19  var (
    20  	realtime = &systemTime{}
    21  )
    22  
    23  // Freeze after this function is called all time related functions start
    24  // generate deterministic timers that are triggered by Advance function. It is
    25  // supposed to be used in tests only. Returns an Unfreezer so it can be a
    26  // one-liner in tests: defer clock.Freeze(clock.Now()).Unfreeze()
    27  func Freeze(now time.Time) Unfreezer {
    28  	setProvider(&frozenTime{frozenAt: now, now: now})
    29  	return Unfreezer{}
    30  }
    31  
    32  type Unfreezer struct{}
    33  
    34  func (u Unfreezer) Unfreeze() {
    35  	Unfreeze()
    36  }
    37  
    38  // Unfreeze reverses effect of Freeze.
    39  func Unfreeze() {
    40  	setProvider(realtime)
    41  }
    42  
    43  // Realtime returns a clock provider wrapping the SDK's time package. It is
    44  // supposed to be used in tests when time is frozen to schedule test timeouts.
    45  func Realtime() Clock {
    46  	return realtime
    47  }
    48  
    49  // Advance makes the deterministic time move forward by the specified duration,
    50  // firing timers along the way in the natural order. It returns how much time
    51  // has passed since it was frozen. So you can assert on the return value in
    52  // tests to make it explicit where you stand on the deterministic timescale.
    53  func Advance(d time.Duration) time.Duration {
    54  	ft, ok := getProvider().(*frozenTime)
    55  	if !ok {
    56  		panic("Freeze time first!")
    57  	}
    58  	ft.advance(d)
    59  	return Now().Sub(ft.frozenAt)
    60  }
    61  
    62  // Wait4Scheduled blocks until either there are n or more scheduled events, or
    63  // the timeout elapses. It returns true if the wait condition has been met
    64  // before the timeout expired, false otherwise.
    65  func Wait4Scheduled(count int, timeout time.Duration) bool {
    66  	return getProvider().Wait4Scheduled(count, timeout)
    67  }
    68  
    69  // Now see time.Now.
    70  func Now() time.Time {
    71  	return getProvider().Now()
    72  }
    73  
    74  // Sleep see time.Sleep.
    75  func Sleep(d time.Duration) {
    76  	getProvider().Sleep(d)
    77  }
    78  
    79  // After see time.After.
    80  func After(d time.Duration) <-chan time.Time {
    81  	return getProvider().After(d)
    82  }
    83  
    84  // NewTimer see time.NewTimer.
    85  func NewTimer(d time.Duration) Timer {
    86  	return getProvider().NewTimer(d)
    87  }
    88  
    89  // AfterFunc see time.AfterFunc.
    90  func AfterFunc(d time.Duration, f func()) Timer {
    91  	return getProvider().AfterFunc(d, f)
    92  }
    93  
    94  // NewTicker see time.Ticker.
    95  func NewTicker(d time.Duration) Ticker {
    96  	return getProvider().NewTicker(d)
    97  }
    98  
    99  // Tick see time.Tick.
   100  func Tick(d time.Duration) <-chan time.Time {
   101  	return getProvider().Tick(d)
   102  }