Commanded and non-commanded part of the system: how to organize databases and testing

Just come to this thread after a Google search. I can share some practice with resetting the read store.

The recommended testing approach by Commanded community conflicts with Phoenix’s sandbox one.

I believe sandbox is the better way because of concurrent testing, so I also spent some time trying to make the read store repo run in sandbox mode. It turns out that it’s easier than I thought since it already is. What I did was to remove the manual resetting (truncates).

Here’s what testing support files look like:

# file: test/support/storage.ex
defmodule MyAp.Storage do
  @moduledoc """
  Clear the event store and read store databases
  """

  alias EventStore.Storage.Initializer

  def reset! do
    reset_eventstore()

    # For read store, it is expected to be automatically
    # rolled back by the transactional tests, as we are
    # using sandbox mode of the pool.
  end

  defp reset_eventstore do
    config = Investracker.EventStore.config()

    {:ok, conn} = Postgrex.start_link(config)

    Initializer.reset!(conn, config)
  end
end

# file: test/support/data_case.ex
defmodule MyApp.DataCase do
  @moduledoc """
  Test case template with data cleaning up.
  """

  ...

  using do
    quote do
      import Ecto
      import Ecto.Changeset
      import Ecto.Query
      import Commanded.Assertions.EventAssertions
      import unquote(__MODULE__)
    end
  end

  setup tags do
    {:ok, _} = Application.ensure_all_started(:my_app)

    setup_sandbox(tags)

    :ok
  end

  @doc """
  Sets up the sandbox based on the test tags.
  """
  def setup_sandbox(tags) do
    pid =
      Ecto.Adapters.SQL.Sandbox.start_owner!(
        Investracker.Repo,
        shared: not tags[:async]
      )

    on_exit(fn ->
      :ok = Application.stop(:my_app)

      # clean event store
      MyApp.Storage.reset!()

      # clean read store with the help of sandbox rollback
      Ecto.Adapters.SQL.Sandbox.stop_owner(pid)
    end)
  end
end

Ideally we can also employ sandbox to reset event store, too, but I haven’t run into any issue yet, so I leave it as it is.

After a reset of the read store with MIX_ENV=test mix ecto.reset, everything seems working now.