clock

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 18, 2021 License: MIT Imports: 5 Imported by: 32

README

clock GoDoc Go Report Card

A Go (golang) library for mocking standard time, optionally also with context.Context.

Basic Usage

// Use clock.Realtime() in production
mock := clock.NewMock(time.Date(2018, 1, 1, 10, 0, 0, 0, time.UTC))
fmt.Println("Time is now", mock.Now())
timer := mock.NewTimer(15 * time.Second)
mock.Add(25 * time.Second)
fmt.Println("Time is now", mock.Now())
fmt.Println("Timeout was", <-timer.C)
// Output:
// Time is now 2018-01-01 10:00:00 +0000 UTC
// Time is now 2018-01-01 10:00:25 +0000 UTC
// Timeout was 2018-01-01 10:00:15 +0000 UTC

Context Usage

start := time.Date(2018, 1, 1, 10, 0, 0, 0, time.UTC)
mock := clock.NewMock(start)
fmt.Println("now:", mock.Now())
ctx, cfn := mock.DeadlineContext(context.Background(), start.Add(time.Hour))
defer cfn()
fmt.Println("err:", ctx.Err())
dl, _ := ctx.Deadline()
mock.Set(dl)
fmt.Println("now:", clock.Now(ctx))
<-ctx.Done()
fmt.Println("err:", ctx.Err())
// Output:
// now: 2018-01-01 10:00:00 +0000 UTC
// err: <nil>
// now: 2018-01-01 11:00:00 +0000 UTC
// err: context deadline exceeded

Documentation

Overview

Package clock implements a library for mocking time.

Usage

Include a Clock variable on your application and initialize it with a Realtime() by default. Then use the Clock for all time-related API calls. So instead of time.NewTimer(), say myClock.NewTimer().

On a test setup, override or inject the variable with a Mock instance and use it to control how the time behaves during each test phase.

To mock context.WithTimeout and context.WithDeadline, use the included Context, TimeoutContext and DeadlineContext methods.

The Context method is also useful in cases where you need to pass a Clock via an 'func(ctx Context, ..)' API you can't change yourself. The FromContext method will then return the associated Clock instance. Alternatively, use the context'ed methods like Sleep(ctx) directly.

All methods are safe for concurrent use.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func After

func After(ctx context.Context, d time.Duration) <-chan time.Time

After is a convenience wrapper for FromContext(ctx).After.

func Context

func Context(parent context.Context, c Clock) context.Context

Context returns a copy of parent in which the Clock is associated with.

func DeadlineContext

func DeadlineContext(ctx context.Context, d time.Time) (context.Context, context.CancelFunc)

DeadlineContext is a convenience wrapper for FromContext(ctx).DeadlineContext.

func Now

func Now(ctx context.Context) time.Time

Now is a convenience wrapper for FromContext(ctx).Now.

func Since

func Since(ctx context.Context, t time.Time) time.Duration

Since is a convenience wrapper for FromContext(ctx).Since.

func Sleep

func Sleep(ctx context.Context, d time.Duration)

Sleep is a convenience wrapper for FromContext(ctx).Sleep.

func Tick

func Tick(ctx context.Context, d time.Duration) <-chan time.Time

Tick is a convenience wrapper for FromContext(ctx).Tick.

func TimeoutContext

func TimeoutContext(ctx context.Context, timeout time.Duration) (context.Context, context.CancelFunc)

TimeoutContext is a convenience wrapper for FromContext(ctx).TimeoutContext.

func Until

func Until(ctx context.Context, t time.Time) time.Duration

Until is a convenience wrapper for FromContext(ctx).Until.

Types

type Clock

type Clock interface {
	After(d time.Duration) <-chan time.Time
	AfterFunc(d time.Duration, f func()) *Timer
	NewTicker(d time.Duration) *Ticker
	NewTimer(d time.Duration) *Timer
	Now() time.Time
	Since(t time.Time) time.Duration
	Sleep(d time.Duration)
	Tick(d time.Duration) <-chan time.Time
	Until(t time.Time) time.Duration

	// DeadlineContext returns a copy of the parent context with the associated
	// Clock deadline adjusted to be no later than d.
	DeadlineContext(parent context.Context, d time.Time) (context.Context, context.CancelFunc)

	// TimeoutContext returns DeadlineContext(parent, Now(parent).Add(timeout)).
	TimeoutContext(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc)
}

Clock represents an interface to the functions in the standard time and context packages.

func FromContext

func FromContext(ctx context.Context) Clock

FromContext returns the Clock associated with the context, or Realtime().

func Realtime

func Realtime() Clock

Realtime returns the standard real-time Clock.

type Mock

type Mock struct {
	sync.Mutex
	// contains filtered or unexported fields
}

Mock implements a Clock that only moves with Add, AddNext and Set.

The clock can be suspended with Lock and resumed with Unlock. While suspended, all attempts to use the API will block.

To increase predictability, all Mock methods acquire and release the Mutex only once during their execution.

func NewMock

func NewMock(now time.Time) *Mock

NewMock returns a new Mock with current time set to now.

Use Realtime to get the real-time Clock.

Example
package main

import (
	"fmt"
	"time"

	"github.com/tilinna/clock"
)

func main() {
	// Use clock.Realtime() in production
	mock := clock.NewMock(time.Date(2018, 1, 1, 10, 0, 0, 0, time.UTC))
	fmt.Println("Time is now", mock.Now())
	timer := mock.NewTimer(15 * time.Second)
	mock.Add(25 * time.Second)
	fmt.Println("Time is now", mock.Now())
	fmt.Println("Timeout was", <-timer.C)
}
Output:

Time is now 2018-01-01 10:00:00 +0000 UTC
Time is now 2018-01-01 10:00:25 +0000 UTC
Timeout was 2018-01-01 10:00:15 +0000 UTC

func (*Mock) Add

func (m *Mock) Add(d time.Duration) time.Time

Add advances the current time by duration d and fires all expired timers.

Returns the new current time. To increase predictability and speed, Tickers are ticked only once per call.

func (*Mock) AddNext

func (m *Mock) AddNext() (time.Time, time.Duration)

AddNext advances the current time to the next available timer deadline and fires all expired timers.

Returns the new current time and the advanced duration.

Example
package main

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/tilinna/clock"
)

func main() {
	start := time.Now()
	mock := clock.NewMock(start)
	mock.Tick(1 * time.Second)
	fizz := mock.Tick(3 * time.Second)
	buzz := mock.Tick(5 * time.Second)
	var items []string
	for i := 0; i < 20; i++ {
		mock.AddNext()
		var item string
		select {
		case <-fizz:
			select {
			case <-buzz:
				item = "FizzBuzz"
			default:
				item = "Fizz"
			}
		default:
			select {
			case <-buzz:
				item = "Buzz"
			default:
				item = strconv.Itoa(int(mock.Since(start) / time.Second))
			}
		}
		items = append(items, item)
	}
	fmt.Println(strings.Join(items, " "))
}
Output:

1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz

func (*Mock) After

func (m *Mock) After(d time.Duration) <-chan time.Time

After waits for the duration to elapse and then sends the current time on the returned channel.

A negative or zero duration fires the underlying timer immediately.

func (*Mock) AfterFunc

func (m *Mock) AfterFunc(d time.Duration, f func()) *Timer

AfterFunc waits for the duration to elapse and then calls f in its own goroutine. It returns a Timer that can be used to cancel the call using its Stop method.

A negative or zero duration fires the timer immediately.

func (*Mock) DeadlineContext

func (m *Mock) DeadlineContext(parent context.Context, d time.Time) (context.Context, context.CancelFunc)

DeadlineContext implements Clock.

Example
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/tilinna/clock"
)

func main() {
	start := time.Date(2018, 1, 1, 10, 0, 0, 0, time.UTC)
	mock := clock.NewMock(start)
	fmt.Println("now:", mock.Now())
	ctx, cfn := mock.DeadlineContext(context.Background(), start.Add(time.Hour))
	defer cfn()
	fmt.Println("err:", ctx.Err())
	dl, _ := ctx.Deadline()
	mock.Set(dl)
	fmt.Println("now:", clock.Now(ctx))
	<-ctx.Done()
	fmt.Println("err:", ctx.Err())
}
Output:

now: 2018-01-01 10:00:00 +0000 UTC
err: <nil>
now: 2018-01-01 11:00:00 +0000 UTC
err: context deadline exceeded

func (*Mock) Len added in v1.1.0

func (m *Mock) Len() int

Len returns the number of active timers.

func (*Mock) NewTicker

func (m *Mock) NewTicker(d time.Duration) *Ticker

NewTicker returns a new Ticker containing a channel that will send the current time with a period specified by the duration d.

func (*Mock) NewTimer

func (m *Mock) NewTimer(d time.Duration) *Timer

NewTimer creates a new Timer that will send the current time on its channel after at least duration d.

A negative or zero duration fires the timer immediately.

func (*Mock) Now

func (m *Mock) Now() time.Time

Now returns the current mocked time.

func (*Mock) Set

func (m *Mock) Set(t time.Time) time.Duration

Set advances the current time to t and fires all expired timers.

Returns the advanced duration. To increase predictability and speed, Tickers are ticked only once per call.

func (*Mock) Since

func (m *Mock) Since(t time.Time) time.Duration

Since returns the time elapsed since t.

func (*Mock) Sleep

func (m *Mock) Sleep(d time.Duration)

Sleep pauses the current goroutine for at least the duration d.

A negative or zero duration causes Sleep to return immediately.

func (*Mock) Tick

func (m *Mock) Tick(d time.Duration) <-chan time.Time

Tick is a convenience wrapper for NewTicker providing access to the ticking channel only.

func (*Mock) TimeoutContext

func (m *Mock) TimeoutContext(parent context.Context, timeout time.Duration) (context.Context, context.CancelFunc)

TimeoutContext implements Clock.

func (*Mock) Until

func (m *Mock) Until(t time.Time) time.Duration

Until returns the duration until t.

type Ticker

type Ticker struct {
	C <-chan time.Time
	// contains filtered or unexported fields
}

Ticker represents a time.Ticker.

func NewTicker

func NewTicker(ctx context.Context, d time.Duration) *Ticker

NewTicker is a convenience wrapper for FromContext(ctx).NewTicker.

func (*Ticker) Stop

func (t *Ticker) Stop()

Stop turns off a ticker. After Stop, no more ticks will be sent.

type Timer

type Timer struct {
	C <-chan time.Time
	// contains filtered or unexported fields
}

Timer represents a time.Timer.

func AfterFunc

func AfterFunc(ctx context.Context, d time.Duration, f func()) *Timer

AfterFunc is a convenience wrapper for FromContext(ctx).AfterFunc.

func NewTimer

func NewTimer(ctx context.Context, d time.Duration) *Timer

NewTimer is a convenience wrapper for FromContext(ctx).NewTimer.

func (*Timer) Reset

func (t *Timer) Reset(d time.Duration) bool

Reset changes the timer to expire after duration d. It returns true if the timer had been active, false if the timer had expired or been stopped.

A negative or zero duration fires the timer immediately.

func (*Timer) Stop

func (t *Timer) Stop() bool

Stop prevents the Timer from firing. It returns true if the call stops the timer, false if the timer has already expired or been stopped.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL