When running Wallaby tests with [async: true] against a LiveView component that hits the database, I end up getting a DBConnection.OwnershipError when LiveView attempts to reconnect.
wallaby_liveview_playground master % mix test
Compiling 1 file (.ex)
14:57:55.508 [info] Already up
...UserListLive PID: #PID<0.612.0>
UserListLive PID: #PID<0.620.0>
14:57:56.753 [error] GenServer #PID<0.620.0> terminating
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.620.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:14: 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}
14:57:56.754 [error] an exception was raised:
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.620.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:14: 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 702318
I think what's going on is there is no equivalent to Phoenix.Ecto.SQL.Sandbox for a socket, so it's unable to check out the ecto sandbox for the test pid.
I've created a test app that recreates the issue: https://github.com/aaronrenner/wallaby_liveview_playground. To recreate this, run the following.
mix deps.getcd assets && npm install && ./node_modules/webpack/bin/webpack.js --mode developmentcd ..mix testIdeally, there would be something similar to Phoenix.Ecto.SQL.Sandbox for Sockets/LiveView that makes LiveView compatible with async browser tests.
@aaronrenner Do you know exactly how the Ecto Sandbox works? I realized in the example FeatureCase it doesn't set the sandbox to shared mode when you are running async tests.
I pulled down your test repo and made it always set the sandbox to shared mode and I'm not seeing the ownership errors anymore.
@mhanberg I was looking at the docs and I believe concurrent tests need to be run in :manual mode.
The advantage of shared mode is that by calling a single function, you will ensure all upcoming processes and operations will use that shared connection, without a need to explicitly allow them. The downside is that tests can no longer run concurrently in shared mode.
Also, the code generated in *_case.ex files seem to support that async tests should me run in manual mode as well.
# test/test_helper.exs
# ...
Ecto.Adapters.SQL.Sandbox.mode(WallabyLiveviewPlayground.Repo, :manual)
# test/support/data_case.exs
# ...
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(WallabyLiveviewPlayground.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(WallabyLiveviewPlayground.Repo, {:shared, self()})
end
:ok
end
If I'm incorrect and can just switch it to shared mode, that will make things a lot easier. 馃槄
I wasn't really sure how it works, but I thought i'd bring it up. The line from the docs looks like it confirms it shouldn't be used. Thanks for the sanity check 馃憤
Just to clarify, the issue is that you can't have concurrent acceptance tests with LiveView. Setting async: false should fix it right now.
Btw, I just included an integration-like testing facility in LiveView master, without using tools like Wallaby. It should bring you greater confidence in tests without bringing such complex tools. I think this would still be a good feature to have, but we don't plan to tackle it directly.
I will close this for now. While we can't have async concurrent tests with wallaby, the new testing facilities reduce considerably the need for using wallaby in the first place. :) If someone wants to provide this functionality, we will gladly accept a PR tho. :)
Most helpful comment
Just to clarify, the issue is that you can't have concurrent acceptance tests with LiveView. Setting
async: falseshould fix it right now.