VirtualTimeGenServer (GenServerVirtualTime v0.1.0)

View Source

A behavior module for GenServers with virtual time support.

This module wraps GenServer and provides a send_after/3 function that can work with either real time (production) or virtual time (testing).

Example

defmodule MyTimedServer do
  use VirtualTimeGenServer

  def start_link(opts) do
    VirtualTimeGenServer.start_link(__MODULE__, :ok, opts)
  end

  @impl true
  def init(:ok) do
    # Schedule a tick every 1000ms
    schedule_tick()
    {:ok, %{count: 0}}
  end

  @impl true
  def handle_info(:tick, state) do
    new_count = state.count + 1
    schedule_tick()
    {:noreply, %{state | count: new_count}}
  end

  defp schedule_tick do
    VirtualTimeGenServer.send_after(self(), :tick, 1000)
  end
end

Testing with Virtual Time

test "server ticks correctly" do
  {:ok, clock} = VirtualClock.start_link()
  VirtualTimeGenServer.set_virtual_clock(clock)

  {:ok, server} = MyTimedServer.start_link([])

  # Advance virtual time by 5 seconds
  VirtualClock.advance(clock, 5000)

  # Server will have ticked 5 times
  assert get_count(server) == 5
end

Summary

Functions

Cancels a timer created with send_after/3.

Gets the current time backend.

Sends a message after a delay using the configured time backend.

Sets the virtual clock for the current process. All child processes will inherit this setting.

Uses real time (default behavior).

Functions

call(server, request, timeout \\ 5000)

See GenServer.call/3.

cancel_timer(ref)

Cancels a timer created with send_after/3.

cast(server, request)

See GenServer.cast/2.

get_time_backend()

Gets the current time backend.

send_after(dest, message, delay)

Sends a message after a delay using the configured time backend.

set_virtual_clock(clock)

Sets the virtual clock for the current process. All child processes will inherit this setting.

Example

iex> {:ok, clock} = VirtualClock.start_link()
iex> VirtualTimeGenServer.set_virtual_clock(clock)
VirtualTimeBackend
iex> VirtualTimeGenServer.get_time_backend()
VirtualTimeBackend

start(module, init_arg, opts \\ [])

start_link(module, init_arg, opts \\ [])

stop(server, reason \\ :normal, timeout \\ :infinity)

See GenServer.stop/3.

use_real_time()

Uses real time (default behavior).