I would like to use the setup_all macro with one of my test modules. In that setup_all I want to create some users and send them to tests. Unfortunately I can’t make it work.
This is a phoenix 1.3 application
here is my setup_all
setup_all do
%{user: fixture(:user)}
end
where fixture(:user) calls my Phoenix context function which essentially does
Repo.insert(user_changeset, returning: true)
and here is the result
3) Qssite.Schema.Mutation.CreateResetTokenTest: failure on setup_all callback, test invalidated
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.397.0>.
When using ownership, you must manage connections in one
of the four ways:
* By explicitly checking out a connection
* By explicitly allowing a spawned process
* By running the pool in shared mode
* By using :caller option with allowed process
The first two options require every new process to explicitly
check a connection out or be allowed by calling checkout or
allow respectively.
The third option requires a {:shared, pid} mode to be set.
If using shared mode in tests, make sure your tests are not
async.
The fourth option requires [caller: pid] to be used when
checking out a connection from the pool. The caller process
should already be allowed on a connection.
If you are reading this error, it means you have not done one
of the steps above or that the owner process has crashed.
stacktrace:
(db_connection) lib/db_connection.ex:926: DBConnection.checkout/2
(db_connection) lib/db_connection.ex:742: DBConnection.run/3
(db_connection) lib/db_connection.ex:790: DBConnection.transaction/3
(qssite) lib/qssite/accounts/accounts.ex:32: Qssite.Accounts.create_user/1
(qssite) test/support/custom_helpers.ex:21: Qssite.Test.CustomHelpers.fixture/2
test/qssite_web/schema/mutation/create_reset_token_test.exs:8: Qssite.Schema.Mutation.CreateResetTokenTest.__ex_unit_setup_all_1/1
test/qssite_web/schema/mutation/create_reset_token_test.exs:1: Qssite.Schema.Mutation.CreateResetTokenTest.__ex_unit__/2
I don’t understand what exactly it wants me to do. I understand setup_all runs in a separate process than this module but I don’t know how to handle this.
Initially I had it in a setup block but there are 3 reasons:
setup runs for every test case and I wan’t to do some tests that involve multiple users. So maybe cut some testing time by not having to create the users every time.
setup_all runs on a separate process. Every time a user is created I get a {:delivered_email, welcome_email} message from Bamboo in the current process. In this module I test only {:delivered_email, password_reset_email}. I wan’t to see if messages related to welcome_email go to the setup_all process. Mostly curiosity than a need to keep the job done. My tests work anyway. Actually this is not a big deal but is directly related with
I wan’t learn how to use setup_all and see how it works.
My use case is when using with Triplex, in every test i need a “tenant” to exist. The default setup where a tenant is created in every test is unacceptably slow (each test takes >1 second).
My solution is to make a new module called TenantCase:
defmodule MyApp.TenantCase do
use ExUnit.CaseTemplate
setup_all tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo)
# we are setting :auto here so that the data persists for all tests,
# normally (with :shared mode) every process runs in a transaction
# and rolls back when it exits. setup_all runs in a distinct process
# from each test so the data doesn't exist for each test.
Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, :auto)
{:ok, tenant} = MyApp.Tenant.create(%{name: "example"})
on_exit fn ->
# this callback needs to checkout its own connection since it
# runs in its own process
:ok = Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo)
Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, :auto)
# we also need to re-fetch the %Tenant struct since Ecto otherwise
# complains it's "stale"
tenant = MyApp.Tenant.get!(tenant.id)
MyApp.Tenant.delete(tenant)
:ok
end
[tenant: tenant]
end
end
Now i can use the tenant in my tests:
defmodule MyApp.MyTest do
use MyApp.ConnCase
use MyApp.TenantCase
test "foo", %{tenant: tenant} do
...
end
end
These lines could have been in the error message! Really simple solution.
Anyway, we can’t be too hard on that subject, elixir error messages are great!