In order to update a last_seen field when a User leaves their UserChannel, I am starting a GenServer, on join, that monitors the User's UserChannel process, and makes the db call on reception of :DOWN signal.
I’m trying to test this.
test "joins succesfully", %{user_a: user} do
assert {:ok, _, _socket} =
UserSocket
|> socket("user_socket:#{user.id}", %{user_id: user.id})
|> subscribe_and_join(UserChannel, "user:#{user.id}")
end
Currently getting this error
[error] GenServer #PID<0.629.0> terminating
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.629.0>.
The module that tracks the user channel
defmodule ChataWeb.UserTracker.Process do
use GenServer, restart: :transient
alias Chata.Accounts
def start_link(%{user_id: user_id, user_channel_pid: user_channel_pid}, opts \\ []) do
init_args = %{user_id: user_id, user_channel_pid: user_channel_pid}
GenServer.start_link(__MODULE__, init_args, opts)
end
def init(init_args) do
Process.monitor(init_args.user_channel_pid)
{:ok, init_args}
end
def handle_info({:DOWN, _ref, :process, _pid, _}, state) do
%{user_id: user_id} = state
Accounts.update_last_seen(user_id)
{:stop, :normal, state}
end
end
I suppose this is happening because the test process completes before the db call does.
So I came back to this few days ago and have been at it since, and still can’t figure it out.
I now put @chrismccord’s method into practice, which consists of a global GenServer that monitors channel processes when they join, and persists last_seen for that user when the channel goes {:DOWN.
This LastSeenTracker GenServer is started in Application.ex children on boot.
Here is the test
describe "user joins own channel" do
test "successfully", %{user_1: me, device_info: device_info} do
token =
ChataWeb.Token.sign(%{user_id: me.id, device_unique_id: device_info.device_unique_id})
assert {:ok, _reply, socket} =
UserSocket
|> socket("user_socket:#{me.id}", %{
user: me,
phone_number: me.phone_number,
user_id: me.id
})
|> subscribe_and_join(UserChannel, "user:#{me.id}")
end
end
I have tried various permutations of manually a) leaving the channel b) closing the socket c) monitoring the channel + assert_receive its down signal, and a few other solutions but each one of these ended up making the test actually fail.
Any ideas on how to test a db write made asynchronously by another process?
You might need to trap exits in the test processes to prevent the test process from dying when the channel goes down. From there you can assert that the channel has indeed died and then you can check in the DB for the update.