Tempo.Clock.Test (Tempo v0.5.0)

Copy Markdown View Source

A process-local deterministic clock for use in tests.

Configure Tempo to use this clock in config/test.exs:

config :ex_tempo, clock: Tempo.Clock.Test

Then in a test, pin the clock to a known instant before exercising any code that calls Tempo.utc_now/0, Tempo.now/1, Tempo.utc_today/0, or Tempo.today/1:

test "renews a subscription at renewal time" do
  Tempo.Clock.Test.put(~U[2026-06-15 12:00:00Z])
  assert Subscription.should_renew?(subscription) == true
end

Time is stored in the calling process's dictionary. Each test gets its own pin and does not interfere with other tests running concurrently, provided the test uses async: true (which is the default for ExUnit.Case).

If utc_now/0 is called without a prior put/1, it raises so the test fails loudly rather than silently returning the system time.

Summary

Functions

Advance the pinned clock by an integer number of seconds. Raises if no time has been pinned.

Pin the test clock to the given DateTime.t/0 in the calling process.

Clear the pinned time from the calling process.

Functions

advance(seconds)

@spec advance(integer()) :: :ok

Advance the pinned clock by an integer number of seconds. Raises if no time has been pinned.

Useful for tests that exercise elapsed-time logic without re-pinning an absolute instant after each step.

Arguments

  • seconds is a signed integer. Negative values move the clock backwards.

Returns

  • :ok.

Examples

iex> Tempo.Clock.Test.put(~U[2026-06-15 12:00:00Z])
iex> Tempo.Clock.Test.advance(3600)
:ok
iex> Tempo.Clock.Test.utc_now()
~U[2026-06-15 13:00:00Z]

put(date_time)

@spec put(DateTime.t()) :: :ok

Pin the test clock to the given DateTime.t/0 in the calling process.

Arguments

  • date_time is a DateTime.t/0. It may be in any zone; it is converted to Etc/UTC before storage so that downstream Tempo.now/1 sees the same UTC instant regardless of the caller's convenience zone.

Returns

  • :ok.

Examples

iex> Tempo.Clock.Test.put(~U[2026-06-15 12:00:00Z])
:ok

reset()

@spec reset() :: :ok

Clear the pinned time from the calling process.

Subsequent calls to utc_now/0 will raise until a new put/1 is made. Useful in on_exit callbacks to guarantee isolation.

Returns

  • :ok.