Harrygr

Harrygr

Testing a Genserver PubSub subscriber that speaks to the DB

I have a test in my Phoenix app that is testing a Phoenix.PubSub subscriber that uses Genserver. The subscriber does some database work as part of its handle_info/2. It looks like this:

defmodule MyApp.Accounts.Subscriber do
  use GenServer
  require Logger
  alias Phoenix.PubSub

  alias MyApp.ReferralCode

 # genserver stuff...

  def init(_) do
    PubSub.subscribe(MyApp.PubSub, "accounts")
    {:ok, %{}}
  end

  def handle_call(:get, _, state) do
    {:reply, state, state}
  end

  def handle_info({:register, user}, state) do
    Logger.info("user registered: #{user.name}")

    %ReferralCode{user_id: user.id}
    |> ReferralCode.changeset(%{code: ReferralCode.generate_code(user.name)})
    |> MyApp.Repo.insert!()

    {:noreply, state}
  end
end

I start my subscriber in my app’s application.ex

children = [
  # Start the PubSub system
  {Phoenix.PubSub, name: MyApp.PubSub},
  MyApp.Accounts.Subscriber,
  # Start the Ecto repository
  supervisor(MyApp.Repo, []),
  # Start the endpoint when the application starts
  supervisor(MyAppWeb.Endpoint, [])
]

opts = [strategy: :one_for_one, name: MyApp.Supervisor]

Supervisor.start_link(children, opts)

My test looks like this:

test "sending creating a referral code upon user registration" do
  start_supervised(MyApp.Accounts.Subscriber)
  user = insert(:user)

  Phoenix.PubSub.broadcast(MappApp.PubSub, "accounts", {:register, user})

  assert_eventually(Repo.exists?(ReferralCode))

  stop_supervised(MyApp.Accounts.Subscriber)
end

The test runs fine when run by itself but when the whole suite is run I get the following error:

[error] GenServer MyApp.Accounts.Subscriber terminating
** (stop) exited in: DBConnection.Holder.checkout(#PID<0.970.0>, [log: #Function<9.124843621/1 in Ecto.Adapters.SQL.with_log/3>, cache_statement: "ecto_insert_referral_codes", timeout: 15000, pool_size: 10, pool: DBConnection.Ownership])
    ** (EXIT) shutdown: "owner #PID<0.969.0> exited"
    <stacktrace...>

This looks like it’s an issue with the database connection still being open when the process is terminated so it doesn’t die gracefully. But I’m not sure how to deal with this.

As an aside, I tried running the test without the call to start_supervised and stop_supervised and strangely it still passed. This did not solve the error mentioned above though. Is there an explanation for this?

Side question: Is this a valid way to implement a pubsub system to handle side effects based on events?

First Post!

patfranciso

patfranciso

Hello there Sir.
Try using

start_supervised!

(that is with the exclamation mark) in your test in your test at the line

“start_supervised(MyApp.Accounts.Subscriber)”

I hope this helps

Where Next?

Popular in Questions Top

srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
dokuzbir
Hello, I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these buyer = %{ id: ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement