Fl4m3Ph03n1x

Fl4m3Ph03n1x

Make ExUnit test pass when process fails to start

Background

I have a process that tries to establish a connection to a server and I am testing it. On the happy path, I check that the process does it’s job once it connects.

But its the sad path that is interesting. Should the process fail to connect to the server, I want it to be gracefully terminated and to stop initialization. How do I test this without making the test fail? (the expected behaviour is to have the process die after all)

Code

Worker:

def init(state) do
  Process.flag(:trap_exit, true)
  {:ok, state, {:continue, :establish_conn}}
end

def handle_continue(:establish_conn, state) do
   
    conn_deps = [
      open_fn:      state.deps.http.open,
      await_fn:     state.deps.http.await_up,
      dump_error:   state.deps.dumper.save_failed_request
    ]

    base_url = state.opts.base_url

    with  {:ok, conn_pid} <- Logic.establish_connection(base_url, conn_deps)
    do
      new_state = %{state | conn_pid: conn_pid}
      {:noreply, new_state}
    else
      {:error, reason} -> {:stop, reason, state}
    end
  end

  def terminate(_reason, state) do
    Logic.close_connection(state.conn_pid, [close_fn: state.deps.http.close])
  end

Because connections take a long time to establish, I use handle_continue. However, since in this case the process will fail to connect, handle_continue will return {:stop, reason, state} and prevent the process from continuing, which is expected.

The process then suicides itself and executes the terminate function.

Question

How do I test this without making the tests fail?

Marked As Solved

peerreynders

peerreynders

Anything wrong with the terminate_wait approach?

So for example you could just stick a monitor on the process and wait for the :DOWN message with a blocking receive with a timeout.

Also Liked

Fl4m3Ph03n1x

Fl4m3Ph03n1x

Actually, simply using the format:


    test "closes connection if it cannot establish it" do
      Process.flag :trap_exit, true

      args = %{a: 1, b: 2}

      Worker.start_link(args)

      assert_receive {:EXIT, _, :my_awesome_termination_reason_here_in_this_place}
      Process.flag :trap_exit, false
    end

Does the trick. No supervisor needed

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
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
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
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
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1140 51847 244
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
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
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New

We're in Beta

About us Mission Statement