wallaby
wallaby copied to clipboard
DBConnection.OwnershipError error in async tests (using LiveView)
Issue
Are async tests using the Repo and connecting to LiveView supposed to work correctly? I keep getting the error mentioned in the issue subject. If I disable async the tests work correctly.
As I understand it, this is a general limitation of running Wallaby tests async. I run those tests synchronously when a background process will be touching the db.
@bartblast can you confirm if you've set up the Ecto sandboxing in your test setup as described here: https://github.com/elixir-wallaby/wallaby#writing-tests
I've seen this issue as well. @bannmoore put together a small repo that illustrates the problem she's been seeing: https://github.com/bannmoore/demo_wallaby_liveview.
@bartblast Is this issue similar to what you've seen?
@byronanderson, @bannmoore I took a look at the repo, but I couldn't find any tests which use Wallaby and hit a LiveView. The only Wallaby spec file is here: /test/demo_wallaby_liveview_web/browser/happy_test.exs, but it goes through a controller.
@mhanberg Yes, I confirm, I went through the docs very thoroughly.
I can recreate the issue with this repo: https://github.com/aaronrenner/wallaby_liveview_playground. If I run mix test
I get the following error after the test exits
wallaby_liveview_playground master % mix test
11:56:54.211 [info] Already up
...11:56:55.504 [error] GenServer #PID<0.610.0> terminating
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.610.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.
See Ecto.Adapters.SQL.Sandbox docs for more information.
(ecto_sql 3.3.4) lib/ecto/adapters/sql.ex:609: Ecto.Adapters.SQL.raise_sql_call_error/1
(ecto_sql 3.3.4) lib/ecto/adapters/sql.ex:545: Ecto.Adapters.SQL.execute/5
(ecto 3.3.4) lib/ecto/repo/queryable.ex:192: Ecto.Repo.Queryable.execute/4
(ecto 3.3.4) lib/ecto/repo/queryable.ex:17: Ecto.Repo.Queryable.all/3
(wallaby_liveview_playground 0.1.0) lib/wallaby_liveview_playground_web/live/user_list_live.ex:13: WallabyLiveviewPlaygroundWeb.UserListLive.mount/3
(phoenix_live_view 0.9.0) lib/phoenix_live_view/utils.ex:225: Phoenix.LiveView.Utils.maybe_call_mount!/3
(phoenix_live_view 0.9.0) lib/phoenix_live_view/channel.ex:597: Phoenix.LiveView.Channel.verified_mount/4
(phoenix_live_view 0.9.0) lib/phoenix_live_view/channel.ex:34: Phoenix.LiveView.Channel.handle_info/2
(stdlib 3.11.2) gen_server.erl:637: :gen_server.try_dispatch/4
(stdlib 3.11.2) gen_server.erl:711: :gen_server.handle_msg/6
(stdlib 3.11.2) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: {:mount, Phoenix.LiveView.Channel}
11:56:55.505 [error] an exception was raised:
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.610.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.
See Ecto.Adapters.SQL.Sandbox docs for more information.
(ecto_sql 3.3.4) lib/ecto/adapters/sql.ex:609: Ecto.Adapters.SQL.raise_sql_call_error/1
(ecto_sql 3.3.4) lib/ecto/adapters/sql.ex:545: Ecto.Adapters.SQL.execute/5
(ecto 3.3.4) lib/ecto/repo/queryable.ex:192: Ecto.Repo.Queryable.execute/4
(ecto 3.3.4) lib/ecto/repo/queryable.ex:17: Ecto.Repo.Queryable.all/3
(wallaby_liveview_playground 0.1.0) lib/wallaby_liveview_playground_web/live/user_list_live.ex:13: WallabyLiveviewPlaygroundWeb.UserListLive.mount/3
(phoenix_live_view 0.9.0) lib/phoenix_live_view/utils.ex:225: Phoenix.LiveView.Utils.maybe_call_mount!/3
(phoenix_live_view 0.9.0) lib/phoenix_live_view/channel.ex:597: Phoenix.LiveView.Channel.verified_mount/4
(phoenix_live_view 0.9.0) lib/phoenix_live_view/channel.ex:34: Phoenix.LiveView.Channel.handle_info/2
(stdlib 3.11.2) gen_server.erl:637: :gen_server.try_dispatch/4
(stdlib 3.11.2) gen_server.erl:711: :gen_server.handle_msg/6
(stdlib 3.11.2) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
..................
Finished in 1.1 seconds
21 tests, 0 failures
Randomized with seed 420379
It's interesting this doesn't actually cause a test failure... I think what's happening is the wallaby session is being shut down after the test process is finished, and during that gap the browser tries to hit the database and rehydrate the LiveView.
I investigated this a little further today and it appears the ownership error occurs when the LiveView process tries to rehydrate the LiveView. I opened this issue on the LiveView repo: https://github.com/phoenixframework/phoenix_live_view/issues/708
I'm not using async tests, but I think I have a related issue with a test which has 2 sessions (with LiveView).
My test passes every time, but on some of the runs I see an error from the LiveView indicating that it failed to find a record in the database. I suspect this is happening because e.g. session 2 causes session 1's LV to re-render, but session 1 no longer has access to the database sandbox? That's just a vague guess, I don't know exactly what's happening but it seems to be something like that.
Hi, Has anybody found a way to resolve this issue. We are facing it too now with latest version of phoenix and wallaby
At the opened issue on LiveView, there is a comment in which José talks about setting the test to be async false, and further a new integration facililty to help test LiveView, so you could use that instead of Wallaby when testing LV
@mhanberg hi, I am wondering if you had the chance to test it...
@jorbs I have not. It seems that code has not yet been released to Hex either.
As mentioned in https://github.com/elixir-wallaby/wallaby/discussions/616 , things might be improved by https://github.com/phoenixframework/phoenix_ecto/commit/1d8d28a82eef1ff496851bd2fd53661398d38b99 e.g. when browser aborts AJAX requests.
Just an update on the state of things (I've landed here from Google multiple times). The previous comment mentioned a change in phoenix_ecto
. The current v4.4.0 now has this included. And using Wallaby async
is also documented in it's docs.
In my case async
can now be enabled without the DB problems.
Yet I can't figure out how to populate the database. Seems that the Sandbox instructions don't work and my insert ends up in a different sandbox than what Chrome has access to. That is another issue though, this issue can be closed.
Oh, I forgot that I was following this issue but I added a note to the Phoenix Ecto docs a few days ago about one "gotcha" setting with Liveviews - https://github.com/phoenixframework/phoenix_ecto/pull/146
Hope this will be useful to anyone who ends up here after googling or who was also following this issue :)
Just a note for those people still seeing this error, here's the issue I was facing. The docs include this step:
live_session :default, on_mount: MyApp.Hooks.AllowEctoSandbox do
# ...
end
but you might have something slightly more complex such as
live_session :redirect_if_user_is_authenticated,
on_mount: [.
{MyAppWeb.UserAuth, :redirect_if_user_is_authenticated},
{MyAppWeb.UserAuth, :mount_current_org}
] do
...
end
In this case, the :allow_ecto_sandbox
must come first on the given list, like:
live_session :redirect_if_user_is_authenticated,
on_mount: [
{MyAppWeb.Hooks.AllowEctoSandbox, :allow_ecto_sandbox},
{MyAppWeb.UserAuth, :redirect_if_user_is_authenticated},
{MyAppWeb.UserAuth, :mount_current_org}
] do
Hope this helps other sleep-deprived devs.