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