Sandbox does not flush records after each mix test

Im doing integration tests in my test database if my logic saves the correct records. Although im running pool: Ecto.Adapters.SQL.Sandbox the records are not flushed after each mix test

Hello, You don’t give a lot of details, so it’s hard to give You an answer…

What do You have in the file test/test_helper.exs?

Is that some legacy project?

Hey there
No its not a legacy project.

test "if compatibility fails, make a record with status: :not_available" do
      VinWorker.request_data_clearance("WBY2Z2205EX7GB012", "O00O010O184TA")
      details = Bmw.get_clearance_by_cid("11111111-1111-1111-1111-111111111111")
      assert "not_available" == details.status
    end
    
    test "if compatibility succeeds, make a record with :pending" do
      VinWorker.request_data_clearance("WBAVB71470VOTP000", "S00I000M001OK")
      details = Bmw.get_clearance_by_cid("11111111-1111-1111-1111-111111111112")
      assert "pending" == details.status
    end

These two records persist in the test database.

My test helper file is just ExUnit.start(exclude: [:pending])

This is mine…

ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(Caissa.Repo, :manual)

BTW if I create a new project…

$ mix phx.new koko
$ cat koko/test/test_helper.exs 
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(Koko.Repo, :manual)

hey,
If i add the line Ecto.Adapters.SQL.Sandbox.mode(DB.Repo, :manual)
I get this error:
6) Logic.VinWorkerTest: failure on setup_all callback, all tests have been invalidated
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.597.0>.

 When using ownership, you must manage connections in one
 of the four ways:

 * By explicitly checking out a connection
 * By explicitly allowing a spawned process
 * By running the pool in shared mode
 * By using :caller option with allowed process

 The first two options require every new process to explicitly
 check a connection out or be allowed by calling checkout or
 allow respectively.

 The third option requires a {:shared, pid} mode to be set.
 If using shared mode in tests, make sure your tests are not
 async.

 The fourth option requires [caller: pid] to be used when
 checking out a connection from the pool. The caller process
 should already be allowed on a connection.

 If you are reading this error, it means you have not done one
 of the steps above or that the owner process has crashed.

 See Ecto.Adapters.SQL.Sandbox docs for more information.

Also important is this file

test/support/data_case.ex

It would be helpful to know

  • What Phoenix version?
  • Did You edit test config yourself?
  • What happens on a new project?

Hey, i found the solution, I had to Explicitly get a connection before each test , so i did setup do
# Explicitly get a connection before each test
:ok = Ecto.Adapters.SQL.Sandbox.checkout(DB.Repo) end

Thank you for your help!

This is normally set in data_case.ex

  setup tags do
    :ok = Ecto.Adapters.SQL.Sandbox.checkout(YourDB.Repo)

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

    :ok
  end

But it’s nice You find a solution :slight_smile:

ok, can you show me your data_case.ex file

This is a standard data_case file (I did not edit after project creation)

defmodule Rbax.DataCase do
  @moduledoc """
  This module defines the setup for tests requiring
  access to the application's data layer.

  You may define functions here to be used as helpers in
  your tests.

  Finally, if the test case interacts with the database,
  it cannot be async. For this reason, every test runs
  inside a transaction which is reset at the beginning
  of the test unless the test case is marked as async.
  """

  use ExUnit.CaseTemplate

  using do
    quote do
      alias Rbax.Repo

      import Ecto
      import Ecto.Changeset
      import Ecto.Query
      import Rbax.DataCase
    end
  end

  setup tags do
    :ok = Ecto.Adapters.SQL.Sandbox.checkout(Rbax.Repo)

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

    :ok
  end

  @doc """
  A helper that transforms changeset errors into a map of messages.

      assert {:error, changeset} = Accounts.create_user(%{password: "short"})
      assert "password is too short" in errors_on(changeset).password
      assert %{password: ["password is too short"]} = errors_on(changeset)

  """
  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
end

What is your approach for umbrella project? Because if I do like this for one or two projects, the first one works but the another projects have many errors. Especially when your Ecto is in a project under umbrella.

2 Likes