Tired to fight with Ecto.Sandbox errors

I’m just started with Elixir and fall in love with it. I like Phoenix, mix, exUnit and the only thing bothering me are millions mesages during testing like:

[error] Postgrex.Protocol (#PID<0.422.0>) disconnected: ** (DBConnection.ConnectionError) owner #PID<0.1213.0> exited

Client #PID<0.1215.0> is still using a connection from owner at location

or

%DBConnection.OwnershipError{
   message: "cannot find ownership process for #PID<0.1105.0>

My deps:

[
      {:phoenix, "~> 1.7.6"},
      {:phoenix_ecto, "~> 4.4"},
      {:ecto_sql, "~> 3.10"},
      {:postgrex, ">= 0.0.0"},
      {:swoosh, "~> 1.3"},
      {:finch, "~> 0.13"},
      {:telemetry_metrics, "~> 0.6"},
      {:telemetry_poller, "~> 1.0"},
      {:jason, "~> 1.2"},
      {:plug_cowboy, "~> 2.5"},
      {:pbkdf2_elixir, "~> 2.0"},
      {:excoveralls, "~> 0.16", only: :test},
      {:gen_rmq, "~> 4.0"}
    ]

here is test_helper.xs

ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(Chat.Repo, :manual)

here is part of data_case.ex

def setup_sandbox(tags) do
    pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Chat.Repo, shared: not tags[:async])
    on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
  end

I use channels, sockets, rabbitmq, so a lots of things happen in different processes. I tried everything I could fin in internet:

  1. try to add in every test module
setup do
    :ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo)
  end
  1. try do use everythere async: false or delete any mentions about async
  2. explicit add to every test
allow = Process.whereis(EventConsumer)
    Ecto.Adapters.SQL.Sandbox.allow(Repo, self(), allow)
  1. try to add at begining at every module
setup do
    :ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo)
    Ecto.Adapters.SQL.Sandbox.mode(Repo, {:shared, self()})
  end
  1. in config set ownership_timeout: 6000

Nothing helps, tests are all green (sic!) but all console full of errors about ownership

Please help! may be I could somehow said to Ecto -ignore ownership and timings, just test it =)

Do you query the db outside of tests / outside of processes collaborating with test processes?

I would strongly recommend spawning a distinct set of processes for each of your tests and not using global ones like allow = Process.whereis(EventConsumer). That simply cannot ever work with async because the same process would be interacting with every test.

no, only tests or processes from it

ok, delete it

Guys, big step forward -now instead of millions of errors i got 2-3

Done:

  1. remove all explicit allow()
  2. purge test queues for rabbit before tests
  3. add checkout Ecto for test modules where it uses it

But I still have

21:58:16.734 [error] Postgrex.Protocol (#PID<0.380.0>) disconnected: ** (DBConnection.ConnectionError) owner #PID<0.857.0> exited

Client #PID<0.411.0> is still using a connection from owner at location:

and

21:58:16.807 [error] GenServer EventConsumer terminating
** (stop) exited in: DBConnection.Holder.checkout(#PID<0.978.0>, [log: #Function<13.95253921/1 in Ecto.Adapters.SQL.with_log/3>, source: "invite", cast_params: [1380, 1380], repo: Chat.Repo, timeout: 15000, ownership_timeout: 6000, pool: DBConnection.Ownership, pool_size: 10])
    ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started

I need one more step or idea )

Everything works, thanks all! =)

For those who gets here with same troubles:

  1. use checkout Ecto in every test module which using something with db (even if this “something” is very deep)
  2. dont work on same data in different tests, always create new entities at the beginning
  3. wait for processes to stop - sometimes your test asserts and over, but some your logic is still works, for example RabbitMq
  4. if using rabbit -clean queues before tests
1 Like

Yeah this bit is key. How are you starting the processes? start_supervised/2 ExUnit.Callbacks — ExUnit v1.15.4 exists to solve this for you, it waits until the linked process is dead before moving to the next test.

5 Likes