How to catch a termination in GenServer.cast?

Hello,

I’m trying to test that worker terminates via {:stop, reason, state} after a certain number of retries. My first attempt was to use Process.flag(:trap_exit, true)

test "worker termination after all retries failed", ctx do
  error = ~s<{"just": "because"}>
  {:ok, wrk}    = GenServer.start(Elastic.Worker, nil)

  Process.flag(:trap_exit, true)
  Application.put_env(:tirexs, :uri, endpoint_url(ctx.bypass.port))
  Bypass.expect(ctx.bypass, &Plug.Conn.send_resp(&1, 500, error))

  Elastic.Worker.insert(wrk, ctx.doc, Property)
  assert_receive {:EXIT, ^wrk, ^error}, 1000
end

it failed due to reason described here https://github.com/elixir-lang/elixir/issues/3507 and then I tried to wrap operation in try/catch/rescue block

   {:ok, wrk} = GenServer.start(Elastic.Worker, nil)
      Elastic.Worker.insert(wrk, ctx.doc, Property)
      :timer.sleep(1000)
    rescue
      msg -> IO.inspect "rescued #{msg}"
    catch
      msg -> IO.inspect "catched #{msg}"
    end

No luck as well as with catch_exit and assert_raise:

assert catch_exit((fn ->
  {:ok, wrk} = GenServer.start(Elastic.Worker, nil)
  Elastic.Worker.insert(wrk, ctx.doc, Property)
  :timer.sleep(1000)
end).()) == 1

Error mesasge (and the reason) looks like that:

.12:10:03.513 [error] GenServer #PID<0.530.0> terminating
** (stop) {:error, 500, %{just: "because"}}

If you are trapping exits, you need to make sure the GenServer is linked by starting it with GenServer.start_link.

The test process mailbox now has it

  test "worker termination after all retries failed", ctx do
    error = %{just: "because"}
    wrk   =  ctx.wrk

    Process.flag(:trap_exit, true)
    Application.put_env(:tirexs, :uri, endpoint_url(ctx.bypass.port))
    Bypass.expect(ctx.bypass, &Plug.Conn.send_resp(&1, 500, Poison.encode!(error)))

    Elastic.Worker.insert(ctx.wrk, ctx.doc, Property)
    assert_receive {:EXIT, ^wrk, {:error, 500, ^error}}, 1000
  end

but, probably, due to raise that occurs in the GenServer there is as an error message in the console and test is considered as skipped.

If a test is skipped, it didn’t even start running. So it cannot be due to a GenServer raise inside the test. How are you running your tests?

Dang, sorry for misleading: I chose to run only second test by myself via mix test test/lib/elastic/worker_test.exs:39 , so it was the other test which was skipped :slight_smile:

When I run full file both scenarios are executed, but failure is still there

I see no failure, only a logger report because your GenServer is still failing. If you want to avoid the report from being logged, add @tag :capture_log before your test.

thank you!