timextest

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 3, 2020 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Mocked

func Mocked(now time.Time, f func(mocked *TestImplementation))

Mocked mocks the current time and passes it to the provided function Afterwards, it restores the default implementation

Types

type AfterCall

type AfterCall struct {
	Mock     *MockedTimer
	Duration time.Duration
}

AfterCall is a call to a mocked After It relies on a MockedTimer which will never be stopped

type AfterFuncCall

type AfterFuncCall struct {
	// Mock provides the underlying timer. Calling Trigger() on it will execute the function provided
	// in the calling goroutine
	Mock     *MockedTimer
	Duration time.Duration
	// Function is the function provided, probably useless
	Function func()
}

AfterFuncCall represents a call made to timex.AfterFunc

type MockedTicker

type MockedTicker struct {
	// contains filtered or unexported fields
}

MockedTicker implements a timex.Ticker and provides functions to control its behavior

func (*MockedTicker) C

func (mt *MockedTicker) C() <-chan time.Time

C implements timex.Ticker

func (*MockedTicker) Stop

func (mt *MockedTicker) Stop()

Stop implements timex.Ticker, and it will close the channel provided by StoppedChan

func (*MockedTicker) StoppedChan

func (mt *MockedTicker) StoppedChan() chan struct{}

StoppedChan will be closed once Stop is called

func (*MockedTicker) Tick

func (mt *MockedTicker) Tick(t time.Time)

Tick will send the provided time through ticker.C()

type MockedTimer

type MockedTimer struct {
	// contains filtered or unexported fields
}

MockedTimer implements a timex.Timer and provides functions to control its behavior

func (*MockedTimer) C

func (mt *MockedTimer) C() <-chan time.Time

C implements timex.Timer

func (*MockedTimer) Stop

func (mt *MockedTimer) Stop() bool

Stop implements the timex.Timer, stop will not return until the value is set by StopValue()

func (*MockedTimer) StopValue

func (mt *MockedTimer) StopValue(v bool)

StopValue sets the value to be returned by Stop(), it has to be called to allow that method to return It can be only called once

func (*MockedTimer) StoppedChan

func (mt *MockedTimer) StoppedChan() chan struct{}

StoppedChan provides the channel that is closed when Stop() is called

func (*MockedTimer) Trigger

func (mt *MockedTimer) Trigger(t time.Time)

Trigger for a usual Timer will send the provided time through timer.C(), If this was a AfterFunc call, then trigger will ignore the time provided and will call the scheduled function in the caller's goroutine

type NewTickerCall

type NewTickerCall struct {
	Mock     *MockedTicker
	Duration time.Duration
}

NewTickerCall is a call to a mocked NewTicker

type NewTimerCall

type NewTimerCall struct {
	Mock     *MockedTimer
	Duration time.Duration
}

NewTimerCall is a call to a mocked NewTimer

type SleepCall

type SleepCall struct {
	// WakeUp allows calling goroutine to continue execution
	WakeUp   func()
	Duration time.Duration
}

SleepCall represents a call made to timex.Sleep

type TestImplementation

type TestImplementation struct {
	SleepCalls     chan SleepCall
	AfterCalls     chan AfterCall
	AfterFuncCalls chan AfterFuncCall
	NewTickerCalls chan NewTickerCall
	NewTimerCalls  chan NewTimerCall

	sync.RWMutex
	// contains filtered or unexported fields
}

TestImplementation implements timex.Implementation for tests

func Mock

func Mock(now time.Time) *TestImplementation

Mock mocks/stubs the timex functions so they return constant known values Also mocks the timex.AfterFunc, returning the calls made to it through a channel. It mocks Sleep too: the delayed function will just unlock the caller of Sleep.

func (*TestImplementation) After

func (ti *TestImplementation) After(d time.Duration) <-chan time.Time

After returns a mocked timer

Example
package main

import (
	"fmt"
	"sync"
	"time"

	"github.com/cabify/timex"
	"github.com/cabify/timex/timextest"
)

var now = time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)

func main() {
	timextest.Mocked(now, func(mockedtimex *timextest.TestImplementation) {
		var value bool

		wg := sync.WaitGroup{}
		wg.Add(1)
		go func() {
			defer wg.Done()
			<-timex.After(time.Minute)
			value = false
		}()

		// Note that the race detector would usually complain about this read because it would be
		// racy with the test
		value = true

		(<-mockedtimex.AfterCalls).Mock.Trigger(time.Time{})
		wg.Wait()

		fmt.Println(value)

	})
}
Output:

false

func (*TestImplementation) AfterFunc

func (ti *TestImplementation) AfterFunc(d time.Duration, f func()) timex.Timer

AfterFunc allows the AfterFunc mocking by pushing calls into ti.AfterFuncCalls

Example
package main

import (
	"fmt"
	"time"

	"github.com/cabify/timex"
	"github.com/cabify/timex/timextest"
)

var now = time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)

func main() {
	timextest.Mocked(now, func(mockedtimex *timextest.TestImplementation) {
		go func() {
			timex.AfterFunc(time.Second, func() { fmt.Println("This happens a second later") })
			timex.AfterFunc(time.Hour, func() { fmt.Println("This happens an hour later") })
		}()

		firstCall := <-mockedtimex.AfterFuncCalls
		fmt.Printf("First function is scheduled for %s\n", firstCall.Duration)

		secondCall := <-mockedtimex.AfterFuncCalls
		fmt.Printf("Second function is scheduled for %s\n", secondCall.Duration)

		firstCall.Mock.Trigger(now)
		secondCall.Mock.Trigger(now)

	})
}
Output:

First function is scheduled for 1s
Second function is scheduled for 1h0m0s
This happens a second later
This happens an hour later

func (*TestImplementation) NewTicker

func (ti *TestImplementation) NewTicker(d time.Duration) timex.Ticker

NewTicker returns a mocked ticker

Example
package main

import (
	"fmt"
	"time"

	"github.com/cabify/timex"
	"github.com/cabify/timex/timextest"
)

var now = time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)

func main() {
	timextest.Mocked(now, func(mockedtimex *timextest.TestImplementation) {
		go func() {
			ticker := timex.NewTicker(time.Hour)
			for t := range ticker.C() {
				fmt.Printf("%s\n", t)
			}
		}()

		tickerCall := <-mockedtimex.NewTickerCalls
		tickerCall.Mock.Tick(now.Add(time.Second))
		tickerCall.Mock.Tick(now.Add(2 * time.Second))

	})
}
Output:

2009-11-10 23:00:01 +0000 UTC
2009-11-10 23:00:02 +0000 UTC

func (*TestImplementation) NewTimer

func (ti *TestImplementation) NewTimer(d time.Duration) timex.Timer

NewTimer returns a mocked timer

Example
package main

import (
	"fmt"
	"sync"
	"time"

	"github.com/cabify/timex"
	"github.com/cabify/timex/timextest"
)

var now = time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)

func main() {
	timextest.Mocked(now, func(mockedtimex *timextest.TestImplementation) {
		wg := sync.WaitGroup{}
		wg.Add(1)
		go func(d time.Duration) {
			defer wg.Done()
			ticker := timex.NewTimer(d)
			t := <-ticker.C()
			fmt.Println(t)
		}(time.Minute)

		timer := <-mockedtimex.NewTimerCalls
		timer.Mock.Trigger(now.Add(timer.Duration))
		wg.Wait()

	})
}
Output:

2009-11-10 23:01:00 +0000 UTC

func (*TestImplementation) Now

func (ti *TestImplementation) Now() time.Time

Now returns always the same now

Example
package main

import (
	"fmt"
	"time"

	"github.com/cabify/timex"
	"github.com/cabify/timex/timextest"
)

var now = time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)

func main() {
	timextest.Mocked(now, func(mockedtimex *timextest.TestImplementation) {
		fmt.Println(timex.Now())

	})
}
Output:

2009-11-10 23:00:00 +0000 UTC

func (*TestImplementation) RestoreDefaultImplementation

func (ti *TestImplementation) RestoreDefaultImplementation()

RestoreDefaultImplementation restores timex default implementation

func (*TestImplementation) SetNow

func (ti *TestImplementation) SetNow(now time.Time)

SetNow updates Now() value to a newer one

Example
package main

import (
	"fmt"
	"time"

	"github.com/cabify/timex"
	"github.com/cabify/timex/timextest"
)

var now = time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)

func main() {
	timextest.Mocked(now, func(mockedtimex *timextest.TestImplementation) {
		mockedtimex.SetNow(time.Unix(1, 0).UTC())
		fmt.Println(timex.Now())

	})
}
Output:

1970-01-01 00:00:01 +0000 UTC

func (*TestImplementation) Since

func (ti *TestImplementation) Since(t time.Time) time.Duration

Since returns the duration elapsed since mocked `now`

Example
package main

import (
	"fmt"
	"time"

	"github.com/cabify/timex"
	"github.com/cabify/timex/timextest"
)

var now = time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)

func main() {
	timextest.Mocked(now, func(mockedtimex *timextest.TestImplementation) {
		fmt.Println(timex.Since(now.Add(-time.Hour)))

	})
}
Output:

1h0m0s

func (*TestImplementation) Sleep

func (ti *TestImplementation) Sleep(d time.Duration)

Sleep sleeps until WakeUp is called

Example

ExampleTestImplementation_Sleep observes the execution of a tempSwitch that uses timex.Sleep To change the state of the program just temporarily This way the assertions are deterministic and we don't have to wait the real amount of time

package main

import (
	"fmt"
	"sync/atomic"
	"time"

	"github.com/cabify/timex"
	"github.com/cabify/timex/timextest"
)

var now = time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)

func main() {
	timextest.Mocked(now, func(mockedtimex *timextest.TestImplementation) {
		sw := tempSwitch{new(int64)}
		done := make(chan struct{})

		// Check it's turned off
		fmt.Printf("First state of switch is %t\n", sw.IsTurnedOn())

		go func() {
			sw.TurnOn()
			close(done)
		}()

		// Wait until the program is sleeping
		sleepCall := <-mockedtimex.SleepCalls

		// Check it's turned on
		fmt.Printf("Then it's temporarily %t\n", sw.IsTurnedOn())

		// Let it wake up and wait until TurnOn call finishes execution
		sleepCall.WakeUp()
		<-done

		// Check it's turned off again
		fmt.Printf("And then it's %t again\n", sw.IsTurnedOn())

	})
}

type tempSwitch struct{ val *int64 }

func (ts tempSwitch) TurnOn() {
	atomic.AddInt64(ts.val, 1)
	timex.Sleep(time.Hour)
	atomic.AddInt64(ts.val, -1)
}

func (ts tempSwitch) IsTurnedOn() bool {
	return atomic.LoadInt64(ts.val) == 1
}
Output:

First state of switch is false
Then it's temporarily true
And then it's false again

func (*TestImplementation) TearDown

func (ti *TestImplementation) TearDown()

TearDown closes all the channels on the test implementation. Useful to terminate goroutines watching those channels.

func (*TestImplementation) Until

func (ti *TestImplementation) Until(t time.Time) time.Duration

Until returns the duration until mocked `now`

Example
package main

import (
	"fmt"
	"time"

	"github.com/cabify/timex"
	"github.com/cabify/timex/timextest"
)

var now = time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)

func main() {
	timextest.Mocked(now, func(mockedtimex *timextest.TestImplementation) {
		fmt.Println(timex.Until(now.Add(time.Minute)))

	})
}
Output:

1m0s

Jump to

Keyboard shortcuts

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