defmodule ExshomeTest.TestRegistry do
@moduledoc """
Registry for async tests.
"""
@spec child_spec(opts :: any()) :: Supervisor.child_spec()
def child_spec(_opts) do
Registry.child_spec(keys: :unique, name: __MODULE__)
end
@spec started?() :: boolean()
def started?, do: !!Process.whereis(__MODULE__)
@spec allow(parent :: pid(), allow :: pid()) :: :ok
def allow(parent, allow) when is_pid(parent) and is_pid(allow) do
{:ok, _} = Registry.register(__MODULE__, {:parent, allow}, parent)
:ok
end
@spec put(key :: any(), value :: any()) :: :ok
def put(key, value) do
parent = get_parent()
{:ok, _} = Registry.register(__MODULE__, {:value, parent, key}, value)
:ok
end
@spec get!(key :: any()) :: any()
def get!(key) do
case get(key) do
{:ok, value} -> value
{:error, error} -> raise error
end
end
def get(key) do
lookup({:value, get_parent(), key})
end
@spec start_dependency(module :: module(), opts :: map()) :: :ok
def start_dependency(module, opts \\ %{}) do
opts = prepare_child_opts(opts)
pid = ExUnit.Callbacks.start_supervised!({module, opts})
put({:dependency, module}, pid)
end
def prepare_child_opts(opts) do
current_pid = self()
opts
|> Map.put(
:custom_init_hook,
fn -> allow(current_pid, self()) end
)
|> Map.put_new(:name, nil)
end
@spec get_dependency_pid(module()) :: pid() | nil
def get_dependency_pid(module) do
case get({:dependency, module}) do
{:ok, value} -> value
_ -> nil
end
end
@spec get_parent() :: pid()
def get_parent do
get_parent(self())
end
@spec get_parent(pid()) :: pid()
def get_parent(pid) do
{:ok, parent} = lookup({:parent, pid})
parent
end
defp lookup(key) do
case Registry.lookup(__MODULE__, key) do
[{_, value}] -> {:ok, value}
_ -> {:error, "Unable to find a value for a key #{inspect(key)}"}
end
end
end