Hi. I am using Ecto.Sandbox for all of my unit tests, so I’ve decided to create new ExUnit.CaseTemplate that will setup this sandbox for each test. Here is that file:
# Helper module for setting up tests that can run DB queries concurrently
# withourh interfearing with each other
# https://hexdocs.pm/ecto/testing-with-ecto.html
defmodule Guard.RepoCase do
use ExUnit.CaseTemplate
using do
quote do
import Guard.RepoCase
end
end
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Guard.Repo)
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Guard.FrontRepo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(Guard.Repo, {:shared, self()})
Ecto.Adapters.SQL.Sandbox.mode(Guard.FrontRepo, {:shared, self()})
end
:ok
end
end
Now this is how one of my Test modules looks, where above mentioned RepoCase with Ecto.Sandbox is used:
defmodule Guard.Store.RbacRole.Test do
use Guard.RepoCase, async: true
@user_id "cb358a11-4185-4b5b-8829-5619805ac1fe"
setup_all do
Support.Factories.RbacUser.insert_user_into_db(@user_id)
{:ok, %{}}
end
Support.Factories.RbacUser.insert_user_into_db is literally just one Ecto.insert call that creates user with the given id, nothing special. This user needs to be in database for each test within this module, and that is why I decided to use setup_all instead of setup.
BUT, whenever I run tests like this, I get this error:
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2623ms. This means requests are coming in and your connection pool cannot serve them fast enough. You can address this by:
1. Ensuring your database is available and that you can connect to it
2. Tracking down slow queries and making sure they are running fast enough
3. Increasing the pool_size (albeit it increases resource consumption)
4. Allowing requests to wait longer by increasing :queue_target and :queue_interval
See DBConnection.start_link/2 for more information
stacktrace:
(db_connection 2.4.0) lib/db_connection/ownership.ex:95: DBConnection.Ownership.ownership_checkout/2
(ecto_sql 3.7.0) lib/ecto/adapters/sql/sandbox.ex:499: Ecto.Adapters.SQL.Sandbox.checkout/2
(guard 0.1.0) test/support/concurrent_repo_case.ex:15: Guard.RepoCase.__ex_unit_setup_0/1
(guard 0.1.0) test/support/concurrent_repo_case.ex:4: Guard.RepoCase.__ex_unit__/2
test/guard/store/rbac_role_test.exs:1: Guard.Store.RbacRole.Test.__ex_unit__/2
The problem is (at least I think) that setup_all from my Test module is called before setup function where Sandbox is initialized, and that creates some sort of problem.
If I change setup_all within my Test module to setup, which looks like this:
setup do
Support.Factories.RbacUser.insert_user_into_db(@user_id)
{:ok, %{}}
end
everything works just fine.
Im not satisfied because now I have to insert this user before each test, which is ~15 db insert queries, instead of just one.
Does anyone have any idea if it is possible to run setup_all method just once, but to ‘delay’ execution of that method for after ecto.Sandbox has been already initialized. Thanks a lot