clock

A small Go interface that swaps the real-time clock for a fully controllable mock, making timer- and deadline-dependent code deterministic to test.

Library
Go
vv1.3.5
690stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
39/100Needs Attention
Development Activity0
Maintenance20
Community56
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
67/100Good
Architecture78
Code Quality74
Innovation65
Learning Curve50

Clock is a lightweight Go library that wraps the standard library’s time package behind a single Clock interface, letting applications use the real-time clock in production while tests substitute a fully controllable Mock clock. Instead of sleeping in tests or relying on wall-clock timing, code that depends on Now(), After(), Sleep(), Tick(), Ticker(), and Timer() can be driven deterministically by advancing the mock clock programmatically with Add or Set.

The library also ships context.WithDeadline and context.WithTimeout implementations that respect the injected clock, so context-based timeout logic can be tested the same way as timers — advancing the mock clock triggers deadline expiration without waiting on real wall-clock time. The project’s README notes it is no longer actively maintained, but its small, stable interface has made it a long-standing dependency across the Go ecosystem for time-mocking in tests.

What You Get

  • A drop-in Clock interface matching the time package’s After, AfterFunc, Now, Since, Until, Sleep, Tick, Ticker, and Timer semantics
  • A real Clock implementation (New()) that simply delegates to the standard library’s time package for production use
  • A Mock clock (NewMock()) starting at the Unix epoch, with Add/Set/WaitForAllTimers for deterministic, programmatic time control in tests
  • Mock-aware context.WithDeadline and context.WithTimeout implementations, so context-based timeouts can be tested without waiting on real time

Common Use Cases

  • Testing HTTP client and server request timeouts without real wall-clock delays
  • Verifying retry and exponential-backoff scheduling logic deterministically
  • Asserting periodic, ticker-driven job behavior in unit tests
  • Testing context-based cancellation and deadline logic tied to the injected clock

Under The Hood

Architecture The library is a single flat package with two files: one defines the Clock interface and its two implementations — a thin struct wrapping the standard library’s time package for the real clock, and a mutex-guarded Mock struct holding a slice of internal timer/ticker wrappers. Time advancement is driven by Add and Set, which repeatedly sort the pending timers and fire the earliest-due one before moving the current time forward — a straightforward, easy-to-follow scheduling loop rather than a heap-based priority queue. Context support is layered on top in a second file, implementing a context.Context whose deadline cancellation is scheduled through the same Clock interface, with cancellation propagated from any parent context via a background goroutine. The Clock interface is the architecture’s only real seam — anything consuming it swaps implementations transparently between production and tests, but a change to that interface would ripple through every consumer at once.

Tech Stack The module has zero external dependencies, importing only the standard library (context, fmt, sort, sync, time). There is no build tooling beyond go build/go test, no database, and no framework — it is a leaf utility library meant to be pulled into other Go modules with no transitive dependency weight of its own.

Code Quality Test coverage is thorough for the package’s size, exercising the real clock, the mock clock, timers, tickers, and context deadlines with explicit, table-free test functions built on the standard testing package rather than a third-party assertion library — a common, low-dependency style in the Go ecosystem. Error handling is minimal by necessity, since most of the API cannot fail; the one meaningful error path, context cancellation, correctly uses the standard context.Canceled and context.DeadlineExceeded values. Naming is idiomatic Go, types stay simple and concrete, and a compile-time interface-satisfaction check keeps the Mock type honest against the Clock interface.

API Design The public surface is intentionally minimal: one interface and two constructors. A consumer only needs to accept a Clock value instead of calling time.Now() directly, then swap in NewMock() for tests — about as low a barrier to entry as a time-mocking library can offer. The Add/Set/WaitForAllTimers trio gives both fine-grained and coarse-grained control over simulated time without needing a scheduling DSL. The overall approach — abstracting time behind an interface for testability — is a well-established pattern rather than a novel one, but it is executed cleanly with little boilerplate required to adopt.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search