Ecto_SQL spits a MatchError getting a dynamic repo

Recently I start getting this flaky issue running Ecto tests.

** (MatchError) no match of right hand side value: 
{:error, {:undef, [{MyApp.Repo, :get_dynamic_repo, [], []}, 
{Ecto.Adapters.SQL.Sandbox, :lookup_meta!, 1, [file: ~c"lib/ecto/adapters/sql/sandbox.ex", line: 580]}, 
{Ecto.Adapters.SQL.Sandbox, :checkout, 2, [file: ~c"lib/ecto/adapters/sql/sandbox.ex", line: 494]}, 
{Ecto.Adapters.SQL.Sandbox, :"-start_owner!/2-fun-0-", 3, [file: ~c"lib/ecto/adapters/sql/sandbox.ex", line: 416]}, 
{Agent.Server, :init, 1, [file: ~c"lib/agent/server.ex", line: 8]}, {:gen_server, :init_it, 2, [file: ~c"gen_server.erl", line: 962]}, 
{:gen_server, :init_it, 6, [file: ~c"gen_server.erl", line: 917]}, 
{:proc_lib, :init_p_do_apply, 3, [file: ~c"proc_lib.erl", line: 241]}]}}

I couldn’t find out the root cause of this error. since there’s no major change in the configs of the sandbox.

# lib/my_app/repo.ex
defmodule MyApp.Repo do
  use Ecto.Repo,
    otp_app: :my_app,
    adapter: Ecto.Adapters.Postgres
end

# config/test.exs
config :my_app, MyApp.Repo,
  url: @default_db_url,
  pool: Ecto.Adapters.SQL.Sandbox,
  pool_size: 10,
  ownership_timeout: 360_000

# test/support/data_case.ex
defmodule MyApp.DataCase do
use ExUnit.CaseTemplate

  alias Ecto.Adapters.SQL.Sandbox

  using do
    quote do
      alias MyApp.Repo

      import Ecto
      import Ecto.Changeset
      import Ecto.Query
      import MyApp.DataCase

      import MyApp.Factory
    end
  end

  setup tags do
    MyApp.DataCase.setup_sandbox(tags)
    :ok
  end

  def setup_sandbox(tags) do
    pid = Sandbox.start_owner!(MyApp.Repo, shared: not tags[:async])
    on_exit(fn -> Sandbox.stop_owner(pid) end)
  end

  def errors_on(changeset) do
    Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->
      Regex.replace(~r"%{(\w+)}", message, fn _, key ->
        opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string()
      end)
    end)
  end

can someone give some hands on this issue. I tried to tweak configs left and right, but the only thing get it works is to get rid of sandbox setup (which means get rid of the failing statement) and change it following Ecto documnentation

# test/support/data_case.ex
 setup tags do
    :ok = Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo)

    unless tags[:async] do
      Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()})
    end

    :ok
  end

Any thoughts.

I seem to remember having to call put_dynamic_repo before being able to call get_dynamic_repo?

I’m not calling get_dynamic_repo, it’s ecto_sql inner job. can you elaborate more, where should I call the put_dynamic_repo?

Dunno. I’d just generate a new project and compare the test files and helpers with yours, side by side.

If you have delta then it’s as simple as:

diff -u your_project/test/support/something.ex \
  brand_new_project/test/support/something.ex | delta --side-by-side

Because looking at your OP, nothing jumps to mind. Seems fairly standard.

I was able to reproduce this error message with the code:

iex(1)> {:ok, pid} = Agent.start(fn -> NoSuchModule.wat() end)
** (MatchError) no match of right hand side value: {:error, {:undef, [{NoSuchModule, :wat, [], []}, {Agent.Server, :init, 1, [file: 'lib/agent/server.ex', line: 8]}, {:gen_server, :init_it, 2, [file: 'gen_server.erl', line: 423]}, {:gen_server, :init_it, 6, [file: 'gen_server.erl', line: 390]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 226]}]}}

But that just makes things more confusing, because it means the Agent isn’t seeing MyApp.Repo.get_dynamic_repo/0 - which is defined when a module says use Ecto.Repo :thinking:

Are you using any mocking etc libraries that manipulate modules at runtime?