Current section

Files

Jump to
parent lib periodic test.ex
Raw

lib/periodic/test.ex

defmodule Periodic.Test do
@moduledoc """
Helpers for testing a periodic job.
See the "Testing" section in `Periodic` documentation for details.
"""
public_telemetry_events = ~w/started finished skipped stopped_previous/a
@telemetry_events if Mix.env() != :test,
do: public_telemetry_events,
else: [:next_tick | public_telemetry_events]
@doc "Sends a tick signal to the given scheduler."
@spec tick(GenServer.name()) :: :ok
def tick(pid_or_name), do: GenServer.call(pid_or_name, :tick)
@doc "Subscribes to telemetry events of the given scheduler."
@spec observe(any) :: :ok
def observe(telemetry_id),
do: Enum.each(@telemetry_events, &attach_telemetry_handler(telemetry_id, &1))
@doc "Waits for the given telemetry event."
defmacro assert_periodic_event(
telemetry_id,
event,
metadata \\ quote(do: _),
measurements \\ quote(do: _)
) do
quote do
assert_receive {
unquote(__MODULE__),
unquote(telemetry_id),
unquote(event),
unquote(metadata),
unquote(measurements)
},
100
end
end
@doc "Asserts that the given telemetry event won't be emitted."
defmacro refute_periodic_event(
telemetry_id,
event,
metadata \\ quote(do: _),
measurements \\ quote(do: _)
) do
quote do
refute_receive {
unquote(__MODULE__),
unquote(telemetry_id),
unquote(event),
unquote(metadata),
unquote(measurements)
},
100
end
end
defp attach_telemetry_handler(telemetry_id, event) do
handler_id = make_ref()
event_name = [Periodic, telemetry_id, event]
:telemetry.attach(handler_id, event_name, telemetry_handler(event_name), nil)
ExUnit.Callbacks.on_exit(fn -> :telemetry.detach(handler_id) end)
end
defp telemetry_handler(event_name) do
test_pid = self()
fn [Periodic, telemetry_id, event] = ^event_name, measurements, metadata, nil ->
send(test_pid, {__MODULE__, telemetry_id, event, metadata, measurements})
end
end
end