Files
parrhesia/test/support/integration_case.ex

85 lines
2.2 KiB
Elixir

defmodule Parrhesia.IntegrationCase do
@moduledoc false
use ExUnit.CaseTemplate
alias Ecto.Adapters.SQL.Sandbox
alias ExUnit.Case
alias Parrhesia.Repo
alias Parrhesia.TestSupport.Runtime
using opts do
quote bind_quoted: [opts: opts] do
use Case, async: Keyword.get(opts, :async, false)
alias Ecto.Adapters.SQL.Sandbox
alias Parrhesia.Repo
@moduletag parrhesia_sandbox: Keyword.get(opts, :sandbox, false)
end
end
setup tags do
Runtime.ensure_started!()
case tags[:parrhesia_sandbox] do
false ->
:ok
true ->
:ok = Sandbox.checkout(Repo)
:shared ->
# Delegate sandbox ownership to a dedicated process that outlives
# the test process. ExUnit terminates start_supervised! children
# (in reverse start order) before running on_exit callbacks. With
# the test process as sandbox owner, the connection dies the
# moment the test process exits — supervised children that make
# DB calls during their shutdown sequence would hit a dead
# connection. The separate owner stays alive through the entire
# supervised-child shutdown, and is only stopped in on_exit
# (which runs afterwards).
test_pid = self()
owner =
spawn(fn ->
:ok = Sandbox.checkout(Repo)
send(test_pid, {:sandbox_ready, self()})
receive do
:stop ->
Sandbox.checkin(Repo)
# Allow the pool to process the checkin before this process
# exits, so Postgrex does not see a dead client and log a
# spurious disconnect error.
Process.sleep(50)
end
end)
receive do
{:sandbox_ready, ^owner} -> :ok
after
5_000 -> raise "Sandbox owner checkout timed out"
end
Sandbox.mode(Repo, {:shared, owner})
on_exit(fn ->
ref = Process.monitor(owner)
send(owner, :stop)
receive do
{:DOWN, ^ref, :process, ^owner, _reason} -> :ok
after
5_000 -> :ok
end
Sandbox.mode(Repo, :manual)
end)
end
:ok
end
end