jungsoft/uploadex

Make TestStorage safe for async tests

Closed this issue · 2 comments

We can't use Uploadex.TestStorage with async tests because of the following random error:

** (exit) exited in: GenServer.call(Uploadex.TestStorage, {:update, #Function<6.116564614/1 in Uploadex.TestStorage.store/2>}, 5000)
         ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
     stacktrace:
       (elixir 1.12.3) lib/gen_server.ex:1014: GenServer.call/3
       (uploadex 3.0.0-rc.0) lib/storage/test_storage.ex:24: Uploadex.TestStorage.store/2

This probably happens because we use TestStorage.start_link() (which calls Agent.start_link(fn -> initial_value end, name: __MODULE__)) in the test setup, but the Agent process dies when the test is ended, but other tests relies on the same Agent instance, since it has the same name.

We could start only one instance of the Agent in the test_helper.ex, but all tests would use the same storage, causing other random errors, such as files from other tests in the stored state.

We want a completely isolated TestStorage per test. For that we need to have a unique name the Agent process. We could use the test module name, but this probably won't work because the TestStorage.store/2 and TestStorage.delete/2 are functions from behavior and are called from inside Uploadex, so we can't pass this names for this callback functions.
So probably a better approach would be using a name based on the current process pid.

What do you think? There's a better option here?

Haven't looked into it yet, but my suggestion is to see how other libraries are doing this, for example https://github.com/dashbitco/mox. The fact that we can assert how many times each function was called during the test makes me think they also use an Agent/GenServer, and they support async tests.

Update: It seems mox has its own supervision tree: https://github.com/dashbitco/mox/blob/master/lib/mox/application.ex, so it's a global process not associated to any specific test process, and the GenServer keeps track of which processes are using it: https://github.com/dashbitco/mox/blob/be379dfcb256729cdf4ad76d50c937bc2202c5f2/lib/mox/server.ex#L235. That's in line with your first suggestion, but does seem more complicated because we need to handle the multiple asynchronous states in the code.

So if the idea of starting different processes based on the test pid works, that would be nice and simpler. If it doesn't, then we would probably need to follow a similar route from mox.