wallaby icon indicating copy to clipboard operation
wallaby copied to clipboard

DBConnection.OwnershipError error in async tests (using LiveView)

Open bartblast opened this issue 4 years ago • 16 comments

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.

bartblast avatar Nov 26 '19 21:11 bartblast

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.

mhanberg avatar Nov 26 '19 21:11 mhanberg

@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

mhanberg avatar Nov 26 '19 22:11 mhanberg

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?

aaronrenner avatar Nov 29 '19 16:11 aaronrenner

@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.

bartblast avatar Nov 29 '19 17:11 bartblast

@mhanberg Yes, I confirm, I went through the docs very thoroughly.

bartblast avatar Nov 29 '19 17:11 bartblast

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.

aaronrenner avatar Mar 17 '20 18:03 aaronrenner

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

aaronrenner avatar Mar 17 '20 21:03 aaronrenner

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.

jonleighton avatar Jun 04 '20 05:06 jonleighton

Hi, Has anybody found a way to resolve this issue. We are facing it too now with latest version of phoenix and wallaby

Maxim-Filimonov avatar Dec 10 '20 02:12 Maxim-Filimonov

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

theevangelista avatar Jan 21 '21 15:01 theevangelista

I think this should close this issue.

I'll test when I get some time.

mhanberg avatar Feb 11 '21 01:02 mhanberg

@mhanberg hi, I am wondering if you had the chance to test it...

jorbs avatar Jun 16 '21 18:06 jorbs

@jorbs I have not. It seems that code has not yet been released to Hex either.

mhanberg avatar Jun 16 '21 18:06 mhanberg

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.

michallepicki avatar Aug 24 '21 06:08 michallepicki

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.

KristerV avatar Oct 29 '21 09:10 KristerV

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 :)

jcrevits avatar Oct 29 '21 11:10 jcrevits

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.

brecke avatar Feb 01 '24 16:02 brecke