DBConnection.Ownership Error when using ex_machina

Using ex machina version 2.3

i have this factory

  def lab_factory do
    %Lab{
      email: sequence(:email, &"email-#{&1}@example.com"),
      name_of_lab: "some lab",
      phone: "some phone",
      cac_reg_number: "RV9199",
      head_scientist_licence_code: "829928838838",
      address: "some address",
      verified: true,
      active: true,
      suspended: false,
      location: build(:location)
    }

expected this will work in my test:

describe "lab" do
    location = insert(:location)

    @valid_attrs %{
      email: "imagediagnostics@gmail.com",
      name_of_lab: "some lab",
      phone: "some phone",
      cac_reg_number: "RV9199",
      head_scientist_licence_code: "829928838838",
      address: "some address",
      verified: true,
      active: true,
      suspended: false,
      location_id: location.id
    }
    @update_attrs %{
      email: "imagediagnostics@gmail.com",
      name_of_lab: some lab",
      phone: "some phone",
      cac_reg_number: "RV9199",
      head_scientist_licence_code: "829928838838",
      address: "some address",
      verified: true,
      active: true,
      suspended: false,
      location_id: location.id
    }
    @invalid_attrs %{
      email: nil,
      name_of_lab: nil,
      phone: nil,
      cac_reg_number: nil,
      head_scientist_licence_code: nil,
      address: nil,
      verified: nil,
      active: nil,
      suspended: nil,
      location_id: nil
    }
    test "list_location/0 returns all location" do
      location = insert(:location)
      lab = insert(:lab, location: location)
      assert Accounts.list_lab() == [lab]
    end

    test "get_lab!/1 returns the lab with given id" do
      location = insert(:location)
      lab = insert(:lab, location: location)
      assert Accounts.get_lab!(lab.id) == lab
    end

    test "create_lab/1 with valid data creates a lab" do
      location = insert(:location)
      assert {:ok, %Lab{} = lab} = Accounts.create_lab(@valid_attrs)
      assert lab.email == "imagediagnostics@gmail.com"
      assert lab.name_of_lab == "some lab"
      assert lab.phone == "some phone"
      assert lab.cac_reg_number == "RV919920202"
      assert lab.head_scientist_licence_code == "829928838838"
      assert lab.address == "some address"
      assert lab.verified == true
      assert lab.active == true
      assert lab.suspended == false
      assert lab.location_id == location.id
    end

    test "create_lab/1 with invalid data returns error changeset" do
      assert {:error, %Ecto.Changeset{}} = Accounts.create_lab(@invalid_attrs)
    end

    test "update_lab/2 with valid data updates the lab" do
      location = insert(:location)
      lab = insert(:lab)
      assert {:ok, %Lab{} = lab} = Accounts.update_lab(lab, @update_attrs)
      assert lab.email == "imagediagnostics@gmail.com"
      assert lab.name_of_lab == "some lab"
      assert lab.phone == "08178891028"
      assert lab.cac_reg_number == "RV9199"
      assert lab.head_scientist_licence_code == "829928838838"
      assert lab.address == "some address"
      assert lab.verified == true
      assert lab.active == true
      assert lab.suspended == false
      assert lab.location_id == location.id
    end

    test "update_lab/2 with invalid data returns error changeset" do
      lab = insert(:lab)
      assert {:error, %Ecto.Changeset{}} = Accounts.update_lab(lab, @invalid_attrs)
      assert lab == Accounts.get_lab!(lab.id)
    end

    test "delete_lab/1 deletes the lab" do
      lab = insert(:lab)
      assert {:ok, %lab{}} = Accounts.delete_lab(lab)
      assert_raise Ecto.NoResultsError, fn -> Accounts.get_lab!(lab.id) end
    end
  end

but i get this error when i run the test

== Compilation error in file test/my_app/accounts_test.exs ==
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.534.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.
    (ecto_sql) lib/ecto/adapters/sql.ex:609: Ecto.Adapters.SQL.raise_sql_call_error/1
    (ecto) lib/ecto/repo/schema.ex:655: Ecto.Repo.Schema.apply/4
    (ecto) lib/ecto/repo/schema.ex:263: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
    (ecto) lib/ecto/repo/schema.ex:164: Ecto.Repo.Schema.insert!/4
    test/my_app/accounts_test.exs:582: (module)
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir) lib/kernel/parallel_compiler.ex:237: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7

How is your test/test_helper.ex file? Did You include this line at the top?

{:ok, _} = Application.ensure_all_started(:ex_machina)
ExUnit.start()

Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, :manual)

{:ok, _} = Application.ensure_all_started(:ex_machina)

that’s it

But the line should be at the top…

Okay, just moved it to the top, but error still remains

You are using factory out of setup or test block…

Try removing this

location = insert(:location)

or put this in a setup block

1 Like

i did this

 defp lab_assoc do
    location = insert(:location)
  end

  describe "lab" do
    setup [:lab_assoc]

    @valid_attrs %{
      email: "imagediagnostics@gmail.com",
      name_of_lab: "Image Diagnostics",
      phone: "08178891028",
      cac_reg_number: "RV919920202",
      head_scientist_licence_code: "829928838838",
      address: "No 122, Rumuola Road",
      verified: true,
      active: true,
      suspended: false,
      location_id: location.id
    }

but i still got this error

== Compilation error in file test/my_app/accounts_test.exs ==
** (CompileError) test/my_app/accounts_test.exs:598: undefined function location/0
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (stdlib) lists.erl:1355: :lists.mapfoldl/3
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (stdlib) lists.erl:1355: :lists.mapfoldl/3
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (stdlib) lists.erl:1355: :lists.mapfoldl/3
    (elixir) expanding macro: Kernel.@/1
    test/my_app/accounts_test.exs:588: LetorPital.AccountsTest (module)
    (ex_unit) expanding macro: ExUnit.Case.describe/2
    test/my_app/accounts_test.exs:585: LetorPital.AccountsTest (module)

location_id is a required field in the lab schema. how do i get the location_id from the location factory

Do this instead…

describe “lab” do

end

There is no need to to instanciate outside of test block… unless You use it later

I honestly do not understand what you mean. this is the whole scenario just in case you need more clarity.

defp lab_assoc do
    location = insert(:location)
  end

  describe "lab" do
    @valid_attrs %{
      email: "imagediagnostics@gmail.com",
      name_of_lab: "Image Diagnostics",
      phone: "08178891028",
      cac_reg_number: "RV919920202",
      head_scientist_licence_code: "829928838838",
      address: "No 122, Rumuola Road",
      verified: true,
      active: true,
      suspended: false,
      location_id: location.id
    }
    @update_attrs %{
      email: "imagediagnostics@gmail.com",
      name_of_lab: "Image Diagnostics",
      phone: "08178891028",
      cac_reg_number: "RV919920202",
      head_scientist_licence_code: "829928838838",
      address: "No 122, Rumuola Road",
      verified: true,
      active: true,
      suspended: false,
      location_id: location.id
    }
    @invalid_attrs %{
      email: nil,
      name_of_lab: nil,
      phone: nil,
      cac_reg_number: nil,
      head_scientist_licence_code: nil,
      address: nil,
      verified: nil,
      active: nil,
      suspended: nil,
      location_id: nil
    }
    test "list_location/0 returns all location" do
      location = insert(:location)
      lab = insert(:lab, location: location)
      assert Accounts.list_lab() == [lab]
    end

    test "get_lab!/1 returns the lab with given id" do
      location = insert(:location)
      lab = insert(:lab, location: location)
      assert Accounts.get_lab!(lab.id) == lab
    end

    test "create_lab/1 with valid data creates a lab" do
      location = insert(:location)
      assert {:ok, %Lab{} = lab} = Accounts.create_lab(@valid_attrs)
      assert lab.email == "imagediagnostics@gmail.com"
      assert lab.name_of_lab == "Image Diagnostics"
      assert lab.phone == "08178891028"
      assert lab.cac_reg_number == "RV919920202"
      assert lab.head_scientist_licence_code == "829928838838"
      assert lab.address == "No 122 Rumuola Road"
      assert lab.verified == true
      assert lab.active == true
      assert lab.suspended == false
      assert lab.location_id == location.id
    end

    test "create_lab/1 with invalid data returns error changeset" do
      assert {:error, %Ecto.Changeset{}} = Accounts.create_lab(@invalid_attrs)
    end

    test "update_lab/2 with valid data updates the lab" do
      location = insert(:location)
      lab = insert(:lab)
      assert {:ok, %Lab{} = lab} = Accounts.update_lab(lab, @update_attrs)
      assert lab.email == "imagediagnostics@gmail.com"
      assert lab.name_of_lab == "Image Diagnostics"
      assert lab.phone == "08178891028"
      assert lab.cac_reg_number == "RV919920202"
      assert lab.head_scientist_licence_code == "829928838838"
      assert lab.address == "No 122 Rumuola Road"
      assert lab.verified == true
      assert lab.active == true
      assert lab.suspended == false
      assert lab.location_id == location.id
    end

    test "update_lab/2 with invalid data returns error changeset" do
      lab = insert(:lab)
      assert {:error, %Ecto.Changeset{}} = Accounts.update_lab(lab, @invalid_attrs)
      assert lab == Accounts.get_lab!(lab.id)
    end

    test "delete_lab/1 deletes the lab" do
      lab = insert(:lab)
      assert {:ok, %lab{}} = Accounts.delete_lab(lab)
      assert_raise Ecto.NoResultsError, fn -> Accounts.get_lab!(lab.id) end
    end
  end

You usually do not mix factories and @valid_attrs, you use either this or that.

2 Likes

This is one of my factory, associations are built in.

  def event_factory do
    %Event{
      creator: build(:user),
      department: build(:department),
      title: sequence(:title, &"my event title-#{&1}"),
      description: "some description",
      thumbnail: %Plug.Upload{filename: "sample.png", path: @thumbnail},
      medium: %Plug.Upload{filename: "sample.mp4", path: @medium}
    }
  end

But You are using the factory when setting @valid_attrs location_id.

As mentionned by @NobbZ, You should not mix both.

Thanks a lot for you patients with me. Please I"ll need to see how you use you factories with associations in a test block testing context create and update functions.
this is my lab factory

def lab_factory do
%Lab{
email: sequence(:email, &“email-#{&1}@example.com”),
name_of_lab: “Image Diagnostics”,
phone: “08178891028”,
cac_reg_number: “RV919920202”,
head_scientist_licence_code: “829928838838”,
address: “No 122, Rumuola Road”,
verified: true,
active: true,
suspended: false,
location: build(:location)
}
end

What You could do is set association in test block, and merge it to @valid_attrs…

    test "create_department/1 with valid data creates a department" do
      user = Factory.insert :user

      assert {:ok, %Department{} = department} = Core.create_department(user, @valid_attrs)
      assert department.jingle == "some jingle"
      assert department.name == "some name"
    end

It’s not really the same case, but the idea is to use the factory inside a test block.

You could as well do the same, and merge location_id inside the test block.

The fact is… You can use factory without raising your error when used inside a test, or setup block.

In your case, that would be

    @valid_attrs %{
      email: "imagediagnostics@gmail.com",
      name_of_lab: "Image Diagnostics",
      phone: "08178891028",
      cac_reg_number: "RV919920202",
      head_scientist_licence_code: "829928838838",
      address: "No 122, Rumuola Road",
      verified: true,
      active: true,
      suspended: false,
    }

...

    test "create_lab/1 with valid data creates a lab" do
      location = insert(:location)
      assert {:ok, %Lab{} = lab} = Accounts.create_lab(Map.put(@valid_attrs, :location_id, location.id))
      ...
    end
1 Like

Thanks man it worked.

By the way I would use a setup block, because it seems You are using this location everywhere. You can do like this too, and reuse location in each test.

describe ... do
  setup do
    location = insert(:location)
    {:ok, location: location}
  end
  ...
  test "whatever", %{location: location} do
    assert {:ok, %Lab{} = lab} = Accounts.create_lab(Map.put(@valid_attrs, :location_id, location.id))
    ...
  end
end
1 Like