Stuck testing a genserver that accesses a database

I’m stuck.

I’m writing an integration test for a GenServer that fetches data from a DB with Ecto. I created reset API (sync call) on the GenServer for my tests that rebuilds the GenServer state by fetching all the users from the database to build its initial state.

I have one test in the file and a setup block. In the setup, I create some user data, run IO.inspect length(Accounts.list_users), label: "user count1" call Server.reset(), then call a second IO.inspect with a different label. I also have code in the GenSerrver that runs the Exact same IO.inspect (copy and paste with modified label) inside the reset flow.

The inspect statement inside the test module who 2 users as expected. However, the print 0 users from the GenServer process. The inspect output is printed in the expected order so there appears to be nothing out of order.

Does anyone know what might cause this. I’ve been stuck on it for a number of hours, even slept on it (didn’t dream a solution), and can’t figure out for the live of me what might be going on. I’ve tried mix clean with no help. I’m specifying the test file (no line number) when running the test with mix. I’m using MySQL and have some non standard code code locations based on a plugin library I’ve written.

1 Like

You should set the Ecto mode to shared:

setup do
  :ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo)
  Ecto.Adapters.SQL.Sandbox.mode(Repo, {:shared, self()})
end

More info.

2 Likes

@mudasobwa Thanks!, but that’s not it. It was already set up in my DataCase support module and I verified that it was run (no async tag). But thanks for the docs reference. I’ll keep reading…

1 Like

I’m wondering if it has to do with the GenServer being started as part of the application (before the connection is checked out in the test). I’m going to try starting the GenServer manually in the tests. That’s probably a better way to test anyway.

1 Like

That was the problem. Because I was using a named server that was started with the application, it was not using the shared database connection. BTW, I made an error in the original question. I’m using Postgress, not MySQL.

I refactored the APIs on the server to accept an optional pid as will as the start_link API to accept a name: option that can be set to false, to start it from my tests without a name.

I modified my tests to start a unnamed server in the setup block. Everything works fine now. This also means that I don’t need a reset API since a new server will be started for each test that needs it.

I did not need to modify my application code either. The unnamed process just runs in parallel with the named version. I just need to extend any APIs I’ll use for integration test to include a the server pid for testing.

6 Likes