Assert_raise in a linked process, without knowing the pid

Hello all, I am trying to test a linked process raising an error. I consulted this link Can't figure out how to assert error in linked process with ExUnit and it proved very helpful. However, the solution in that thread requires that the linked process’s pid be known. The code I’m testing does not provide a pid, unfortunately. Here is the source code (GenRetry.Task.async/2 is basically Task.async):

def read({time,{:read, key}}) do
    num_of_nodes = Nodes.all_nodes()
    |> queue_to_list()
    |> length()

    task = GenRetry.Task.async(
      fn -> 
        value = RPC.call(Nodes.next_node(),Server,:read,[time, key]) 
        case value do
          {:badrpc, _reason} -> raise ReadNodesUnresponsive
          value -> value
        end
      end,
      retries: @retries_per_read * num_of_nodes,
      delay: @delay_per_read / num_of_nodes,
      exp_base: 1
    )
    Task.await(task)
  end

And here is the test

test "raises error if only node is unresponsive" do
      Nodes.add_node("a@com")
      
      with_mock(RPC, call: fn _node,_module,_fun,_args -> 
        {:badrpc, :reason}
      end) do
        Process.flag :trap_exit, true
        pid = self()

        catch_exit do
          CommunicationService.read({1,{:read, 1}})          
        end

        assert_received({:EXIT, _, {%ReadNodesUnresponsive{message: _}, _}}) #uses _ instead of pid

      end
    end

I am trying to match against all possible pids to see if an error message is sent. However, I get this test failure:

21:44:37.620 [error] Task #PID<0.304.0> started from #PID<0.296.0> terminating
** (Exceptions.ReadNodesUnresponsive) All the nodes are unresponsive
() lib/nectar_api_web/services/communication_service.ex:58: anonymous fn/2 in .CommunicationService.read/1
(gen_retry) lib/gen_retry/worker.ex:21: GenRetry.Worker.handle_cast/2
(stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:686: :gen_server.handle_msg/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Function: #Function<0.31575502/0 in GenRetry.Task.task_function/2>
Args: []

It seems like the error was never caught! Is there any way to listen to all messages that are sent and see if any of them is an error message? Thank you.

1 Like

Why do you need a separate process if your function is just gonna wait for it to finish every time?

1 Like

The separate process is spawned by GenRetry, which handles catching errors and restarting the process. It is required to get the behavior I want.

GenRetry.Task.async returns the same normal %Task{} struct as Elixir’s Task functions. Have you tried using its pid field?

task = CommunicationService.read({1,{:read, 1}})
# some lines later, use the task's pid.
task.pid

I’d temporarily replace the assert_received with:

receive do
   msg  ->
     IO.inspect(msg)
after
   10_000 ->
     IO.puts("No message")
end

to see if there is any type of message in the test process mailbox.

1 Like