A few tests are failing since the latest change due to the test setups using dummy User ids which are invalid for the foreign key constraint of PlayerGameSessionSummary. These tests will now need to create User records in the database during setup. Some of these modules also need to add the line use Minotaur.DataCase which will check out a database connection during setup. I apply these changes and most of the tests are passing.

The last tests that are still failing are the cluster tests which spawn multiple process nodes of the application. In these tests the cluster nodes are not seeing the User records exist in the database which are created by the test setup helpers on the test runner process. This is because the test runner process is using a separate connection pool than the spawned nodes and the test runner connections run in sandbox mode which wrap all queries in a transaction that is rolled back at the end of the test. I have to disable sandbox mode for cluster tests to support multi-node database interactions.

I update the Minotaur.DataCase test helper module to make an exception for test modules tagged with :cluster_case so they do not use the sandbox mode. I also need to handle database record cleanup after each test ends since I’m using connections outside of the sandbox which means all database queries will be committed.

defmodule Minotaur.DataCase do
  use ExUnit.CaseTemplate

  alias Ecto.Adapters.SQL.Sandbox
  alias Minotaur.Repo

  @schemas [
    Minotaur.GameEngine.GameSessionSummary,
    Minotaur.Accounts.User,
    Minotaur.Accounts.UserToken
  ]

  def setup_sandbox(tags) do
    if tags[:cluster_test] do
      Sandbox.checkout(Repo, sandbox: false)

      on_exit(fn ->
        Sandbox.checkout(Repo, sandbox: false)
        Enum.each(@schemas, &Repo.delete_all/1)
      end)
    else
      pid = Sandbox.start_owner!(Repo, shared: not tags[:async])
      on_exit(fn -> Sandbox.stop_owner(pid) end)
    end
  end

  # …
end

I don’t need to explicitly delete PlayerGameSessionSummary records since they will automatically be deleted when their associated GameSessionSummary record is deleted. I need to checkout a new connection again in the on_exit callback since it will run in a process separate from the calling process. The last tests are now passing and I have a much better understanding of Ecto sandbox features after all this.