@@ -48,6 +48,12 @@ defmodule Ecto.Adapters.SQL.Sandbox do
4848 :ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo)
4949 end
5050
51+ setup tags do
52+ pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Repo, shared: not tags[:async])
53+ on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
54+ :ok
55+ end
56+
5157 test "create post" do
5258 # Use the repository as usual
5359 assert %Post{} = Repo.insert!(%Post{})
@@ -203,13 +209,36 @@ defmodule Ecto.Adapters.SQL.Sandbox do
203209 test "queries periodically" do
204210 {:ok, pid} = PeriodicServer.start_link()
205211 Ecto.Adapters.SQL.Sandbox.allow(Repo, self(), pid)
206- # more tests
212+ # assertions
207213 end
208214
209215 Because the server is querying the database from time to time, there is
210216 a chance that, when the test exits, the periodic process may be querying
211217 the database, regardless of test success or failure.
212218
219+ To address this, you can tell ExUnit to manage your processes:
220+
221+ test "queries periodically" do
222+ pid = start_supervised!(PeriodicServer)
223+ Ecto.Adapters.SQL.Sandbox.allow(Repo, self(), pid)
224+ # assertions
225+ end
226+
227+ By using `start_supervised!/1`, ExUnit guarantess the process finishes
228+ before your test (the connection owner).
229+
230+ In some situations, however, the dynamic processes are directly started
231+ inside a `DynamicSupervisor` or a `Task.Supervisor`. You can guarantee
232+ proper termination in such scenarios by adding an `on_exit` callback
233+ that waits until all supervised children terminate:
234+
235+ on_exit(fn ->
236+ for {_, pid, _, _} <- DynamicSupervisor.which_children(MyApp.DynamicSupervisor) do
237+ ref = Process.monitor(pid)
238+ assert_receive {:DOWN, ^ref, _, _, _}, :infinity
239+ end
240+ end)
241+
213242 ### "owner timed out because it owned the connection for longer than Nms"
214243
215244 In some situations, you may see error reports similar to the one below:
0 commit comments