a fake clock for golang

Overview

clockwork

Mentioned in Awesome Go

GitHub Workflow Status Go Report Card Go Version go.dev reference

A simple fake clock for Go.

Usage

Replace uses of the time package with the clockwork.Clock interface instead.

For example, instead of using time.Sleep directly:

func myFunc() {
	time.Sleep(3 * time.Second)
	doSomething()
}

Inject a clock and use its Sleep method instead:

func myFunc(clock clockwork.Clock) {
	clock.Sleep(3 * time.Second)
	doSomething()
}

Now you can easily test myFunc with a FakeClock:

func TestMyFunc(t *testing.T) {
	c := clockwork.NewFakeClock()

	// Start our sleepy function
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		myFunc(c)
		wg.Done()
	}()

	// Ensure we wait until myFunc is sleeping
	c.BlockUntil(1)

	assertState()

	// Advance the FakeClock forward in time
	c.Advance(3 * time.Second)

	// Wait until the function completes
	wg.Wait()

	assertState()
}

and in production builds, simply inject the real clock instead:

myFunc(clockwork.NewRealClock())

See example_test.go for a full example.

Credits

clockwork is inspired by @wickman's threaded fake clock, and the Golang playground

License

Apache License, Version 2.0. Please see License File for more information.

Comments
  • Add support for Timers

    Add support for Timers

    Noticed that #13 appears stale. So I made a new branch locally rebased onto @aviddiviner's work, rebased his work onto master, and addressed the PR comments.

    I feel like this code has made the sleeper struct a little obfuscated and could be cleaned up to better reflect what was done for the Ticker stuff. I'm going to try to decouple it myself, but help/suggestions are welcome.

    resolves #10

    opened by ghost 8
  • make clockwork modules friendly

    make clockwork modules friendly

    Adding go.mod and go.sum is nice, but more important (and simpler) is tagging new version to include "recent" code changes. Without it go take version 0.10 which is quite old.

    opened by mlitvin 4
  • Need help with maintenance?

    Need help with maintenance?

    Hi @jonboulle,

    First of all, thanks for this package, I think it's a quite popular one!

    I noticed there are a couple open issues and PRs and I wonder if you need help with maintenance. Either as a contributor to this repo, or if you don't want to maintain it anymore, as a managed fork somewhere (eg. https://github.com/gofrs).

    Let me know what you think!

    opened by sagikazarmark 3
  • Add support for fake tickers

    Add support for fake tickers

    I spend a little time on extending your library to add support for fake tickers. Currently this requires surrounding the Advance() calls with BlockUntil() to make sure that the ticker can go to sleep before Advance() is called and afterwards wake up before we start consuming ticks. Let me know what you think.

    opened by tflach 3
  • Set NewFakeClock initial time

    Set NewFakeClock initial time

    Using NewFakeClock() to make a Clock at a specific point in time requires a custom implementation (since fakeClock is internal) or calling Advance while depending on the internal detail that the clock starts in 1900. Is this within the desired project scope?

    I previously considered this package for some testing which depended on a specific timestamp for validations.

    opened by dghubble 3
  • Add Timers

    Add Timers

    Since both #13 and #22 look abandoned, this is another attempt at implementing fake timers. This doesn't build of the implementation in either previous attempt; rather I tried to implement fake timers in a manner similar to fake tickers.

    Closes #10

    release-note/new-feature 
    opened by rosstimothy 2
  • BlockUntil blocks forever if there are too many blockers

    BlockUntil blocks forever if there are too many blockers

    Consider the following code:

    func TestFakeClock(t *testing.T) {
    	c := clockwork.NewFakeClock()
    
    	go func(){
    		c.Sleep(time.Second)
    	}()
    	go func(){
    		c.Sleep(time.Second)
    	}()
    
    	c.BlockUntil(1)
    }
    

    Most of the time this code will pass! But non-deterministically (if the goroutines are scheduled at just the right time), the BlockUntil will block forever.

    The problem is that numExpected != numActual (2 != 1), so the BlockUntil call will block forever. I think it should be changed so that it blocks until numExpected <= numActual. Would you accept a PR to change this?

    I could also imagine other fixes, like BlockUntil panic-ing if there are more sleepers than numExpected, rather than blocking forever.

    opened by nicks 2
  • Timers

    Timers

    Hey. Thanks for the excellent repo, I was looking for a time testing tool and this was a great start. Not sure if you're interested, but I've implemented timers on my fork.

    The fake timers are quite closely inspired by the ones from the standard library and it should all work well. Your old After(d Duration) <-chan Time is now just a shortcut for my NewTimer(d).C (as it is in the standard lib), so I got test coverage from all your existing tests on the new timers too.

    Let me know what you think and if you want me to modify anything. Cheers!

    opened by aviddiviner 2
  • feat: Add context helpers to package.

    feat: Add context helpers to package.

    This change adds new methods .AddTo() and .From() to assist with threading clocks through code paths via context. Enables simple fake clock usage in test where needed.

    Closes #32

    opened by connyay 1
  • Fake clock does not handle negative durations to After() correctly

    Fake clock does not handle negative durations to After() correctly

    Description

    fakeClock does not handle negative durations passed to After() correctly.

    This looks very similar to https://github.com/jonboulle/clockwork/issues/19

    Steps to reproduce

    func TestNegativeTimer(t *testing.T) {
    	fakeClock := clockwork.NewFakeClock()
    	timer := time.NewTimer(2 * time.Second)
    	defer timer.Stop()
    	select {
    	case <-fakeClock.After(-1 * time.Second):
    	// Success
    	case <-timer.C:
    		t.Fatalf("Timed out!")
    	}
    }
    

    Output:

    $ go test -v -run TestNegativeTimer
    === RUN   TestNegativeTimer
    --- FAIL: TestNegativeTimer (2.00s)
        negativetimer_test.go:18: Timed out!
    FAIL
    exit status 1
    
    opened by pcman312 1
  • FakeClock sleep blocks on negative duration

    FakeClock sleep blocks on negative duration

    According to the golang documentation for time.Sleep, when passed a zero or negative duration, the function returns immediately.

    FakeClock correctly handles a zero duration, but ends up blocking for negative durations, thus requiring the clock to be advanced by zero to unblock the sleeper (which should never have been blocked to begin with).

    opened by redgoattea 1
  • Make FakeTicker synchronous

    Make FakeTicker synchronous

    I'm trying to use FakeTicker to test production code that uses clockwork.Ticker. I found that my FakeTicker would "race ahead", since it doesn't block on ft.c being available to receive a tick.

    I make it synchronous, and add a test case showing the behavior.

    opened by dbenbenn 0
  • Fake clock advances past intervening timers

    Fake clock advances past intervening timers

    I know that the real clock doesn't guarantee that timers will go off exactly on time, but in practice they go off somewhat close to on schedule.

    I just created a pull request to add AfterFunc. I noticed when testing it that I can advance the clock well past when a timer is supposed to fire. The timer fires, but it thinks the time is well past when it should be.

    So then, the question is: should the clock pause for real time as it advances past timers? I think that for AfterFunc, it should be willing to wait for f() to return or for one real second to pass, whichever comes first.

    I don't think any of the other APIs provide any way to know how long to pause.

    opened by muir 0
  • add AfterFunc

    add AfterFunc

    I didn't see a way to build the equivalent of time.AfterFunc using the public APIs without leaking a goroutine and the callback func.

    With the internal APIs, it's pretty easy.

    opened by muir 0
  • Refactor to avoid channels and goroutines

    Refactor to avoid channels and goroutines

    In terms of features, the addition of AfterFunc is the main benefit here. Otherwise it addresses a number of bugs, mainly around out-of-order or duplicate delivery of events, as exposed by the various tests added by these changes.

    These changes merge the sleeper and the fakeTimer task. Now a fakeTimer object is used to represent any future event on the timeline of a given fake clock. When the time advances to that point, a callback on the fakeTimer gets called. This makes sending to a channel only one of many possible responses on expiry. Not using channels, but instead an internal callback that gets called with the clock's lock held, allows using the timer far more flexible. It is now also the basis of ticker and of the After method. This change in general will do more things while holding the clock's lock, leading to more consistent behavior and less risk of data races.

    Basing After on Timer instead of the other way round also allows clearing the future events when timers get stopped or reset. This in turn helps BlockUntil actually track active blockers, ignoring obsolete ones that used to exist in the past.

    This fixes https://github.com/jonboulle/clockwork/issues/42.

    opened by gagern 1
  • Fake Timer may report the same time twice

    Fake Timer may report the same time twice

    I noticed that there appears to be a race condition in the fake timer implementation. If Reset gets called multiple times then apparently it can schedule multiple channel events. I will upload a commit demonstrating the issue.

    opened by gagern 1
Releases(v0.3.0)
  • v0.3.0(Apr 21, 2022)

    What's Changed

    Exciting New Features 🎉

    • Add Timers by @rosstimothy in https://github.com/jonboulle/clockwork/pull/38

    New Contributors

    • @rosstimothy made their first contribution in https://github.com/jonboulle/clockwork/pull/38

    Full Changelog: https://github.com/jonboulle/clockwork/compare/v0.2.3...v0.3.0

    Source code(tar.gz)
    Source code(zip)
  • v0.2.3(Mar 24, 2022)

    What's Changed

    • Ci updates by @sagikazarmark in https://github.com/jonboulle/clockwork/pull/34
    • feat: Add context helpers to package. by @connyay in https://github.com/jonboulle/clockwork/pull/33
    • fix: fixes a deadlock in BlockUntil by @nicks in https://github.com/jonboulle/clockwork/pull/36
    • Go 1.18 by @sagikazarmark in https://github.com/jonboulle/clockwork/pull/37

    New Contributors

    • @connyay made their first contribution in https://github.com/jonboulle/clockwork/pull/33
    • @nicks made their first contribution in https://github.com/jonboulle/clockwork/pull/36

    Full Changelog: https://github.com/jonboulle/clockwork/compare/v0.2.2...v0.2.3

    Source code(tar.gz)
    Source code(zip)
  • v0.2.2(Sep 29, 2020)

  • v0.2.1(Sep 10, 2020)

  • v0.2.0(Jul 6, 2020)

    This release contains a few minor changes (like adding a go.mod file to the repository). This is only a maintenance release, the next release will contain more changes.

    Source code(tar.gz)
    Source code(zip)
Owner
Jonathan Boulle
Jonathan Boulle
goCron: A Golang Job Scheduling Package.

goCron: A Golang Job Scheduling Package.

辣椒面 3.1k Sep 25, 2022
golang job dispatcher

go-gearman The shardingkey is hashed to the same queue, each of which is bound to a worker.

fengyun.rui 17 Apr 4, 2022
Lightweight, fast and dependency-free Cron expression parser (due checker) for Golang (tested on v1.13 and above)

adhocore/gronx gronx is Golang cron expression parser ported from adhocore/cron-expr. Zero dependency. Very fast because it bails early in case a segm

Jitendra Adhikari 212 Sep 19, 2022
A lightweight job scheduler based on priority queue with timeout, retry, replica, context cancellation and easy semantics for job chaining. Build for golang web apps.

Table of Contents Introduction What is RIO? Concern An asynchronous job processor Easy management of these goroutines and chaining them Introduction W

Supratim Samanta 49 May 3, 2022
Simple, efficient background processing for Golang backed by RabbitMQ and Redis

Table of Contents How to Use Motivation Requirements Features Examples Setup Config Client/Server Task Worker/Task Hander Register The Handlers Send t

Hasan 38 Aug 30, 2022
cpuworker - A Customized Goroutine Scheduler over Golang Runtime

cpuworker Status Working in process. Run the Demo Make sure the GOMAXPROCS is bigger than 1 and there is at least GOMAXPROCS physical OS threads avail

Sen Han 139 Sep 23, 2022
YTask is an asynchronous task queue for handling distributed jobs in golang

YTask is an asynchronous task queue for handling distributed jobs in golang

gojuukaze 220 Sep 19, 2022
goInterLock is golang job/task scheduler with distributed locking mechanism (by Using Redis🔒).

goInterLock is golang job/task scheduler with distributed locking mechanism. In distributed system locking is preventing task been executed in every instant that has the scheduler,

Jay Ehsaniara 26 Sep 19, 2022
a self terminating concurrent job queue for indeterminate workloads in golang

jobtracker - a self terminating concurrent job queue for indeterminate workloads in golang This library is primarily useful for technically-recursive

maia tillie arson crimew 9 Sep 6, 2022
go-sche is a golang library that lets you schedule your task to be executed later.

go-sche is a golang library that lets you schedule your task to be executed later.

cza 2 Jul 4, 2022
Scheduler CRUD For Golang

scheduler-CRUD 從dbdiagram.io建立table與create語法 在mysql建立table 以sqlc建CRUD function與Transaction 加入viper讀環境變量 以gin開發REST API 加入Dockerfile docker build -t th

null 0 Feb 10, 2022
Scheduler: the scheduler of distbuild written in Golang

scheduler Introduction scheduler is the scheduler of distbuild written in Go. Pr

distbuild 0 Feb 9, 2022
Delay-tasks - A delayed tasks implementation for golang

delay-tasks An implementation of delayed tasks. Usage $ git clone https://github

null 2 Jan 14, 2022
Tasks - Golang CLI, Task manager

Tasks Golang CLI, Task manager Prerequisites Golang Setup environment variables

Santiago Bedoya 0 Jan 30, 2022
Clock is a small library for mocking time in Go.

clock Clock is a small library for mocking time in Go. It provides an interface around the standard library's time package so that the application can

Ben Johnson 581 Sep 25, 2022
GoVector is a vector clock logging library written in Go.

GoVector is a vector clock logging library written in Go. The vector clock algorithm is used to order events in distributed systems in the absence of a centralized clock. GoVector implements the vector clock algorithm and provides feature-rich logging and encoding infrastructure.

Distributed clocks 164 Aug 13, 2022
CPU usage percentage is the ratio of the total time the CPU was active, to the elapsed time of the clock on your wall.

Docker-Kubernetes-Container-CPU-Utilization Implementing CPU Load goroutine requires the user to call the goroutine from the main file. go CPULoadCalc

Ishank Jain 1 Dec 15, 2021
Simple text-line analog clock

anaclock anaclock prints a simple analog clock as a line of text. Demo $ anaclock 23 . : .| 00 anaclock is easy to use in CLI prompts or anywhere

null 0 Dec 31, 2021
Raspberry Pi alarm clock for childs, to let them know whether they can wake up or stay in bed

Miveil Raspberry Pi alarm clock for childs, to let them know whether they can wake up or stay in bed. The idea was to have a simple device that let my

Pierre 0 Apr 14, 2022
A simple digital clock written in go to show time in hh : mm : ss format in console

Go console clock a simple digital clock written in go to show time in "hh : mm :

Mojtaba Khodami 0 Feb 3, 2022